react-i18next 测试实战指南基于 Jest 与 Testing Library 的 example/test-jest 全解【免费下载链接】react-i18nextInternationalization for react done right. Using the i18next i18n ecosystem.项目地址: https://gitcode.com/gh_mirrors/re/react-i18next导读本文以 example/test-jest 示例项目为主体系统讲解在 React i18next 生态中如何用 Jest 与testing-library/react编写可靠的国际化i18n测试包括如何通过src/__mocks__/react-i18next.js自动 mockt、Trans等翻译 API如何在setupTests.js中注册 jest-dom 匹配器或选择真初始化而非打桩以及jest.config.js/babel.config.js的完整配置。读完本文你将掌握一套可直接复制的 react-i18next 组件测试方案并理解每一条 mock 分支背后的源码级动机。示例项目定位与整体结构example/test-jest是 react-i18next 官方仓库中的独立可运行示例其定位非常明确展示在不引入真实 i18next 实例的情况下如何用最轻量的方式测试使用 i18n 的组件。项目同时以 Vite 作为开发/构建工具以 Jest 作为测试运行器兼顾了能跑起来与能测起来两个场景。example/test-jest/ ├── babel.config.js # Jest 使用的 Babel 配置 ├── jest.config.js # Jest 配置roots、setup、moduleNameMapper、transform ├── src/ │ ├── __mocks__/react-i18next.js # 核心react-i18next 的自动 mock │ ├── setupTests.js # jest-dom 注册 真初始化替代方案示例 │ ├── test-utils/fileMock.js # css/svg 静态资源 stub │ ├── i18n.js # 真实应用入口中的 i18next 初始化仅作对照 │ ├── App.jsx / App.test.jsx # 基础渲染测试 │ ├── UseTranslation.jsx/.test.jsx # useTranslation Hook 测试 │ ├── Trans.jsx/.test.jsx # Trans 组件测试 │ ├── Translation.jsx/.test.jsx # Translation 渲染 prop 测试 │ ├── WithTranslation.jsx/.test.jsx# withTranslation HOC 测试 │ └── UseTranslationWithInterpolation.jsx/.test.jsx其中package.json的依赖组合为reactreact-i18nexti18next运行时jest、jest-environment-jsdom、babel-jest、testing-library/react、testing-library/jest-dom测试时见 example/test-jest/package.json。核心思路用自动 Mock 隔离翻译层README 的第一条核心指引是./src/__mocks__contains the react-i18next mock (mocks translate and Trans; mock other components as needed!!!)这正是本示例的灵魂将react-i18next包整体替换为一个返回 key 本身的桩实现。这样测试既不依赖真实语言资源文件也不依赖 i18next 初始化时机组件只要收到t函数即可完成渲染断言。Jest 自动 mock 的触发机制Jest 规定只要在__mocks__目录下存在与包名同名的文件src/mocks/react-i18next.js那么当测试代码import { useTranslation } from react-i18next时Jest 会自动优先使用该 mock无需显式jest.mock()调用。关键前提在于 jest.config.js 中的一行export default { testEnvironment: jsdom, // roots must include src so src/__mocks__/react-i18next.js auto-mocks the package roots: [rootDir/src], setupFilesAfterEnv: [rootDir/src/setupTests.js], moduleNameMapper: { \\.(css|svg)$: rootDir/src/test-utils/fileMock.js, }, transform: { ^.\\.[jt]sx?$: babel-jest, }, };roots必须包含src否则src/__mocks__不会被 Jest 识别为自动 mock 目录——注释里特别强调了这一点。同时testEnvironment: jsdom提供 DOM 环境配合 Testing Library 的render。setupFilesAfterEnv在测试文件执行前加载setupTests.js。moduleNameMapper把.css/.svg导入映射到 src/test-utils/fileMock.js内容为module.exports test-file-stub避免 Jest 解析不了样式与图片资源。transform所有[jt]sx?文件交给babel-jest其 Babel 预设见 babel.config.jsbabel/preset-envtargets: { node: current }与babel/preset-reactruntime: automatic即自动 JSX runtime无需显式import React也能用 JSX不过示例代码仍保留了import React。mock 逐项拆解src/mocks/react-i18next.js 的完整内容值得逐行研读const React require(react); const reactI18next require(react-i18next); const hasChildren node node (node.children || (node.props node.props.children)); const getChildren node node node.children ? node.children : node.props node.props.children; const renderNodes reactNodes { if (typeof reactNodes string) { return reactNodes; } return Object.keys(reactNodes).map((key, i) { const child reactNodes[key]; const isElement React.isValidElement(child); if (typeof child string) { return child; } if (hasChildren(child)) { const inner renderNodes(getChildren(child)); return React.cloneElement(child, { ...child.props, key: i }, inner); } if (typeof child object !isElement) { return Object.keys(child).reduce((str, childKey) ${str}${child[childKey]}, ); } return child; }); }; const useMock [k k, { changeLanguage: () new Promise(() {}) }]; useMock.t k k; useMock.i18n { changeLanguage: () new Promise(() {}) }; module.exports { // this mock makes sure any components using the translate HoC receive the t function as a prop withTranslation: () Component props Component t{k k} {...props} /, Trans: ({ children, i18nKey }) !children ? i18nKey : Array.isArray(children) ? renderNodes(children) : renderNodes([children]), Translation: ({ children }) children(k k, { i18n: {} }), useTranslation: () useMock, // mock if needed I18nextProvider: reactI18next.I18nextProvider, initReactI18next: reactI18next.initReactI18next, setDefaults: reactI18next.setDefaults, getDefaults: reactI18next.getDefaults, setI18n: reactI18next.setI18n, getI18n: reactI18next.getI18n, };各 API 的 mock 策略如下react-i18next APImock 行为设计意图useTranslation()返回[k k, { changeLanguage }]并附加t k k、i18n.changeLanguageHook 返回的t原样返回 key便于断言渲染了哪个 keywithTranslation()返回高阶组件向被包裹组件注入t{k k}保证 HOC 用法下组件能收到tpropTrans无children时渲染i18nKey有children时递归渲染子节点兼容Trans i18nKey...default text/Trans两种形态Translation调用children(k k, { i18n: {} })渲染 prop 模式直接拿到tI18nextProvider/initReactI18next等直接透传真实实现需要时再替换其余保持真实导出注意useMock的实现技巧把t和i18n直接挂到数组对象上这样无论使用者按数组解构const [t] useTranslation()还是按const { t, i18n } useTranslation()都能取到值。Trans 的 children 递归渲染原理renderNodes是本 mock 中最重的逻辑它的作用是在没有真实 i18next 解析器的情况下把Trans的 JSX children 摊平成可渲染的 React 节点。它处理了四类情况字符串节点直接返回字符串子元素直接返回带 children 的元素递归摊平后通过React.cloneElement重挂key普通对象如翻译资源中的嵌套对象把对象值拼接为字符串。对应到真实实现Trans的 children 摊平逻辑在源码 src/Trans.js 与 src/TransWithoutContext.js 中由nodesToString/renderNodes完成见 test/trans.render.spec.jsx 对真实渲染行为的覆盖mock 版刻意保持只保留结构、不解析插值的最小行为让测试聚焦在 DOM 结构而非翻译结果上。setupTests.jsjest-dom 与真初始化两条路线README 的第二条指引./src/setupTests.jsregisters thetesting-library/jest-dommatchers (and shows how to init i18next instead of stubbing)src/setupTests.js 做了两件事import testing-library/jest-dom; // without stubbing do this: // import i18n from i18next; // import { initReactI18next } from react-i18next; // i18n.use(initReactI18next).init({ // lng: en, // fallbackLng: en, // ns: [translations], // defaultNS: translations, // interpolation: { // escapeValue: false, // not needed for react!! // }, // resources: { en: { translations: {} } }, // });第一行注册testing-library/jest-dom的增强匹配器例如测试中使用的toHaveTextContentexpect(container.querySelector(div)).toHaveTextContent(description.part2);见 src/UseTranslation.test.jsx 与 src/Trans.test.jsx。注释掉的段落则展示了第二条路线不 mock直接真初始化 i18next。这在需要验证插值、复数、命名空间等真实翻译行为时很有用。它的初始化参数与真实应用入口 src/i18n.js 几乎一致i18n .use(Backend) // i18next-http-backend .use(LanguageDetector) // i18next-browser-languagedetector .use(initReactI18next) .init({ fallbackLng: en, ns: [translations], defaultNS: translations, debug: true, interpolation: { escapeValue: false, // not needed for react!! }, });两处都使用了interpolation.escapeValue: false——因为 React 本身会对 JSX 文本做转义i18next 无需再转义一次这是 react-i18next 初始化配置的惯例。区别仅在于测试版用resources内联翻译资源应用版用 HTTP Backend 语言探测器从public/locales异步加载。测试文件体系覆盖 react-i18next 的全部用法README 提到./src/App.test.jsxbasic render test./src/*.test.jsxtests usingtesting-library/react示例中的每个测试文件都对应 react-i18next 的一种典型用法形成一个完整的覆盖矩阵1. 基础渲染冒烟测试App.test.jsxsrc/App.test.jsx 使用react-dom/client的createRoot直接在测试中挂载/卸载整个App /验证不崩溃这一最低门槛。真实 src/App.jsx 中同时用到了withTranslationHOC、Trans、useTranslation以及Suspensefallback对应 i18next 异步加载时的挂起态一个测试即可覆盖多条代码路径。2. useTranslation HookUseTranslation.test.jsx被测组件 src/UseTranslation.jsxconst { t } useTranslation(); return div{t(description.part2)}/div;由于 mock 中useTranslation返回的t是k k因此测试断言渲染文本等于 key 本身expect(container.querySelector(div)).toHaveTextContent(description.part2);这种断言 key的写法使得翻译文案修改如把description.part2改为别的 key会直接导致测试失败从而把 key 名当作稳定的契约来守护。3. Trans 组件Trans.test.jsx示例中还提供了带内联元素的Trans用例strong包裹的description.bold测试用toHaveTextContent在strong元素上断言验证 mock 版Trans的renderNodes能正确保留嵌套元素结构。4. 其余覆盖仓库中还有Translation渲染 prop、WithTranslationHOC、UseTranslationWithInterpolation插值场景三组组件与测试共同保证 react-i18next 的每种 API 形态在测试环境下都有对应验证路径见 example/test-jest/src 目录下的Translation.jsx、WithTranslation.jsx、UseTranslationWithInterpolation.jsx及其同名.test.jsx文件。运行方式测试与开发/构建命令README 给出了完整命令对应 example/test-jest/package.json 的 scripts命令作用npm test运行 Jest配置来自jest.config.js/babel.config.js执行全部*.test.jsxnpm start或npm run dev启动 Vite 开发服务器默认地址http://localhost:5173npm run buildVite 生产构建产物输出到dist/npm run preview本地预览构建产物整个测试链路无需启动任何后端jsdom 环境 自动 mock 使测试在毫秒级内完成与 Vite 的开发/构建链路完全解耦。小结何时用 Mock何时真初始化从本示例可以提炼出两条可落地的测试策略默认策略——自动 mock只要关心组件是否正确渲染、是否正确使用翻译 key就用src/__mocks__/react-i18next.js这套桩实现。它速度快、不依赖资源文件且能通过断言 key 文本把翻译 key 变成可回归的契约。进阶策略——真初始化当需要验证插值格式、复数规则、命名空间回退等真实翻译行为时参考 src/setupTests.js 中注释的i18n.init方案用resources内联小规模翻译资源即可无需引入网络后端。两种策略共享同一套 Jest 基建roots指向src以启用自动 mock、setupFilesAfterEnv加载 jest-dom、moduleNameMapper处理静态资源、babel-jest负责 JSX 编译。这套配置可以直接迁移到任何 Vite React react-i18next 项目中作为团队国际化测试的起步模板。【免费下载链接】react-i18nextInternationalization for react done right. Using the i18next i18n ecosystem.项目地址: https://gitcode.com/gh_mirrors/re/react-i18next创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
Agent Substrate 路线图深度解读:从核心架构决策到高密度 Agent 运行时演进方向 人工智能AI AgentAgent 沙箱云原生容器运行时零信任 【免费下载链接】substrate Agent Substrate: the core system 项目地址: https://gitcode.com/GitHub_Trending/substrate7/substrate 点击查看 免费下载 Agent Substrate 是一个面向大规模 Agent 部署的高性能… · 2026/9/24 14:33:41
Hive Aden 工具集 Razorpay 支付集成实战:6 个 MCP 工具完成收款、开票与退款管理 人工智能AI Agent多智能体MCP 服务工具调用浏览器控制 【免费下载链接】hive Multi-Agent Harness for Production AI 项目地址: https://gitcode.com/gh_mirrors/hive48/hive 点击查看 免费下载 本文以 Hive 开源仓库 tools 目录下的 Razorpay 支付工具为对象&… · 2026/9/24 14:33:15
Win11无法识别HC05蓝牙模块的根源与原生解决方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 15:12:51
2026年9月阿里企业邮箱如何购买,中小企业邮箱搭建指南 企业邮箱是中小企业数字化办公的基础设施之一。阿里云企业邮箱依托云原生分布式架构,支持公有云与专有云部署,并与钉钉深度集成。本文围绕2026年9月阿里企业邮箱的购买思路与中小企业邮箱搭建流程展开,从产品定位、功能模块、版本选择、部署方… · 2026/9/24 15:12:45
EMQX HOCON 0.46.3 升级:数组型配置项敏感值脱敏与校验错误日志安全加固解析 后端物联网消息队列通信 【免费下载链接】emqx The most scalable and reliable MQTT broker for AI, IoT, IIoT and connected vehicles 项目地址: https://gitcode.com/gh_mirrors/em/emqx 点击查看 免费下载 导读
本文围绕 EMQX 仓库中 changelog 条目 fix-183… · 2026/9/24 15:12:27
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程 简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13
1D-CNN时间序列建模实战:从Conv1d原理到工业落地 简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26
柔软的L:汉语语流中被忽视的舌肌张力控制 1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44