ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

ScriptCat 国际化(i18n)方案解析:基于 i18next 的动态语言切换与多语言文件组织实践

ScriptCat 国际化(i18n)方案解析:基于 i18next 的动态语言切换与多语言文件组织实践 前端开发者工具插件系统【免费下载链接】scriptcatScriptCat, a browser extension that can execute userscript; 脚本猫一个可以执行用户脚本的浏览器扩展项目地址https://gitcode.com/gh_mirrors/sc/scriptcat点击查看免费下载本文深入解析 ScriptCat 浏览器扩展的国际化实现方案为何选择 i18next 而非chrome.i18n、语言文件如何按页面命名空间组织并最终合并导出、关键字冲突如何通过page.key约定解决以及语言切换、质量检查与翻译贡献工作流背后的源码级细节。读完本文你将掌握 ScriptCat 多语言体系10 个 locale的完整运行机制并能依循既有约定新增语言或修改翻译同时理解scripts/check-i18n.mjs机械检查的真实边界。一、方案选型为什么是 i18next 而不是 chrome.i18nScriptCat 的 i18n 实现使用 i18next配合 react-i18next 的 React 绑定核心原因是chrome.i18n不支持动态切换语言。从运行机制看chrome.i18n的语言资源由浏览器根据扩展语言设置静态加载chrome.i18n.getMessage()只能读取当前已加载的messages.json运行时无法在zh-CN与en-US之间即时切换i18next 把全部语言资源作为 JavaScript 对象一次性注册进内存见下文resources配置i18n.changeLanguage(lng)可在任意时刻完成切换且通过languageChanged事件通知所有订阅者。但为了满足某些扩展市场如 Chrome Web Store 等的上架要求项目仍保留了chrome.i18n格式的语言文件位于 src/assets/_locales 目录下包含en、zh_CN、zh_TW、ja、de、ko、pt_BR、ru、tr、vi等子目录每个子目录内是messages.json。也就是说ScriptCat 同时维护了两套语言资源用途目录格式驱动方界面动态多语言主方案src/locales按命名空间拆分的*.jsoni18next扩展市场上架所需兼容src/assets/_localesmessages.jsonchrome.i18n两套资源并非随意维护scripts/check-i18n.mjs会强制校验src/locales/下的每一个 locale 都必须存在对应的_locales目录缺失即检查失败详见下文「机械检查」一节。二、语言文件的组织方式按页面划分的命名空间语言文件位于src/locales目录按照页面命名空间划分每个页面对应一个语言文件。以 src/locales/zh-CN 为例目录下包含 12 个命名空间文件common.json—— 通用文案默认命名空间如save、delete、loading等高频词popup.json—— 扩展弹窗页面文案script.json—— 脚本管理相关文案editor.json—— 代码编辑器相关文案settings.json—— 设置页文案install.json—— 脚本安装页文案agent.json—— Agent 功能文案logs.json、guide.json、tools.json、permission.json、external_access.json—— 分别对应日志、引导、工具、权限、外部访问等页面每个 locale 目录下还有一个 index.ts以export { default as popup } from ./popup.json;的形式显式导出全部命名空间。以common为默认命名空间defaultNS: common代码中引用非common命名空间的 key 时需带ns:前缀例如t(script:tags)表示读取script.json中的tagskey。从 src/locales/locales.ts 的源码可见运行时注册了 10 个语言地区与目录一一对应Locale语言目录en-USEnglish (US)src/locales/en-USzh-CN简体中文src/locales/zh-CNzh-TW繁體中文src/locales/zh-TWja-JP日本語src/locales/ja-JPde-DEDeutschsrc/locales/de-DEvi-VNTiếng Việtsrc/locales/vi-VNru-RUРусскийsrc/locales/ru-RUtr-TRTürkçesrc/locales/tr-TRpt-BRPortuguês (Brasil)src/locales/pt-BRko-KR한국어src/locales/ko-KR其中en-US是运行时回退语言fallbackLng: en-US同时是新增语言的翻译模板。三、合并导出与运行时初始化locales.ts 全流程所有语言文件最终通过 src/locales/locales.ts 合并导出。其核心流程可分为三个步骤1. 初始化 i18next 并注册全部资源initLanguage(lng)调用i18n.use(initReactI18next).init(...)关键配置i18n.use(initReactI18next).init({ fallbackLng: en-US, lng: lng, ns: [...NS], // 12 个命名空间的名称数组 defaultNS: common, interpolation: { escapeValue: false }, // React 场景关闭转义 resources: { en-US: { title: English, ...enUS }, zh-CN: { title: 简体中文, ...zhCN }, // ... 其余 8 个 locale }, });NS数组common、popup、script、editor、settings、install、agent、logs、guide、tools、permission、external_access与en-US/下的命名空间文件集合必须完全一致——这正是机械检查的第一道校验。2. 结合系统配置确定默认语言initLocales(systemConfig)负责读取用户语言偏好const uiLanguage chrome.i18n.getUILanguage(); const defaultLanguage globalThis.localStorage ? localStorage[language] || uiLanguage : uiLanguage;即优先读取localStorage[language]其次回退到浏览器界面语言chrome.i18n.getUILanguage()。随后从SystemConfig即设置存储见 src/pkg/config/config.ts异步读取用户配置的语言并通过systemConfig.addListener(language, changeLanguageCallback)监听语言设置变化——用户修改语言设置后扩展会实时切换界面语言无需刷新页面。3. 语言切换回调与相关工具函数changeLanguageCallback除了调用i18n.changeLanguage(lng)还会同步维护一个模块级变量localePath非中文不以zh-开头时置为/en中文时置为。该变量供文档/帮助中心链接使用。locales.ts还导出了若干实用函数它们也被 src/locales/locales.test.ts 覆盖测试changeLanguage(lng, callback)—— 切换 i18next 语言并同步调用changeRelativeTimeLanguage更新相对时间文案watchLanguageChange(callback)—— 订阅languageChanged事件立即执行一次回调并返回取消订阅函数i18nName(script)—— 根据当前语言读取脚本元数据中的name:zh-CN这类多语言名称先完全匹配name:lang再尝试name:langPrefix如zh-TW回退到zh前缀匹配最后回退到脚本默认namei18nDescription(script)—— 同样的匹配逻辑读取description:langisChineseUser()—— 判断当前用户是否为中文用户zh-前缀matchLanguage()—— 遍历chrome.i18n.getAcceptLanguages()返回的浏览器可接受语言返回第一个已注册资源包的语言找不到完全匹配时再按语言前缀如zh匹配。4. 相对时间文案的本地化界面中的「x 分钟前」「3 天前」等相对时间由 src/locales/relative-date.ts 实现changeRelativeTimeLanguage会将zh-cn、zh-hans归一化为zh-CNzh-tw、zh-hant归一化为zh-TWIntl.getCanonicalLocales兜底semTime(time)依据 Day.js 风格阈值45 秒/45 分钟/22 小时/26 天/320 天计算时间差最终由Intl.RelativeTimeFormat生成对应语言的文案。这保证了「切换语言」不仅影响界面文本还覆盖时间表达。四、关键字冲突page.key约定不同页面中可能出现关键字相同但翻译不同的情况。此时可以使用page.key的方式区分——将 page页面/命名空间作为前缀与 key 用点号连接。原文档给出的示例中文版{ list: { confirm_delete: 确定要删除吗请注意这个操作无法恢复, confirm_update: 确定要更新吗请注意这个操作无法恢复 } }即list页面下的confirm_delete、confirm_update两个 key 属于list这一层级最终通过点号路径list.confirm_delete在命名空间内唯一化。翻译时必须保证同一页面内 key 唯一、且整个命名空间的 key 集合与其他语言完全对齐这也是机械检查的第二道校验。需要区分两个不同的「前缀」概念page.key本文讨论的约定解决命名空间内部、同 key 不同译文的问题ns:keyi18next 语法解决跨命名空间引用的问题如t(script:tags)。两种写法不要混用——i18n-usage.test.ts中专门警示过「误用popup.点号代替popup:冒号会导致 UI 直接显示原始 key 而非译文」。五、代码中使用 i18n 的规范与自动化用法检查src/locales/i18n-usage.test.ts 提供了一道静态扫描防线它遍历src/pages与src/app/service/service_worker下所有非测试*.tsx?文件用正则匹配t(xxx)、i18n.t(xxx)、i18next.t(xxx)调用并按其解析规则在zh-CN资源中查找对应 key空 key、含${或{{的动态/插值 key被跳过带defaultValue兜底文案的调用被跳过不会显示原始 keykey 中的冒号被解析为命名空间前缀如script:tags冒号前的部分不在已注册命名空间列表时跳过如 URL 中的冒号剩余所有调用都必须在zh-CN的对应命名空间中解析到具体的字符串/数字值否则测试失败并列出文件:行号 t(key)。需要注意的是该测试只能证明代码引用的 key 在zh-CN中存在、命名空间前缀正确不能证明其他 locale 的 key 完整性、译文措辞准确性或术语符合对应terminology-locale.md——不要把「测试通过」当成「翻译已核对」的证据后者仍需人工或专项核对。六、机械检查scripts/check-i18n.mjs 的检查面与边界scripts/check-i18n.mjs通过pnpm run check:i18n运行并在每次pnpm lint/pnpm lint:ci时自动执行对翻译 PR 做 fail-closed 式的机械检查覆盖六个检查面src/locales/locales.ts注册完整性src/locales/下的每个 locale 目录必须被import * as X from ./locale导入并在resources中以自己的 locale code 展开注册resources[locale]展开的标识符必须与导入绑定一致顶层NS数组必须与en-US/下的命名空间文件集合完全一致命名空间文件 key 对齐每个 locale 的*.json与en-US模板的 key 集合一一对应缺失或多余的 key 都会报错flattenKeys把嵌套对象压平为点号路径后做差集比较index.ts导出完整性每个 locale 的index.ts必须真实包含export ... from ./ns.json语句通过 TypeScript 编译器解析 AST而非字符串匹配覆盖en-US导出的全部命名空间chrome.i18n文件对齐src/assets/_locales/chrome-locale/messages.json与en/messages.json的 key 必须一致src/locales/下的每个 locale 都必须有对应的_locales目录目录名通过扫描磁盘实际存在的_locales子目录解析兼容ko、zh_CN、pt_BR等不同命名风格术语规范文件存在每个 locale 必须有对应的docs/references/terminology- .md如 terminology-zh-CN.md缺失即失败——不允许新增或修改某个 locale 却不提交其术语规范Monaco 编辑器语言数据对齐src/pkg/utils/monaco-editor/langs/拆分布局中的editorLangs编辑器悬浮提示、脚本头字段提示每个 locale 条目与en-US的 key 集合一致缺失条目或 key 不一致都会报错。该脚本采用 fail-closed 设计任何无法静态解析的结构spread、计算属性、satisfies、语法错误、循环引用等都会报错而不会被静默放行——它只保证「不会有 key、注册项或术语规范文件被整段遗漏」无法判断译文措辞是否准确、是否符合术语规范那部分仍需人工审阅。另一个实用细节git commit触发的.husky/pre-commit校验的是Git 暂存区git add之后的内容而手动运行pnpm lint/pnpm run check:i18n校验的是工作区当前文件——两者检查对象不同提交前若修改了翻译文件务必先git add。七、翻译与贡献工作流指引本 README 只覆盖 i18n 实现机制翻译工作流、术语规则与逐语言检查清单统一维护在 docs/translation.md。核心约定包括改进已有翻译直接编辑对应语言目录下相应命名空间的*.json文件新增语言在src/locales/下新建语言代码目录如fr-FR复制en-US/下的各命名空间*.json与index.ts作为模板翻译并在src/locales/locales.ts中注册同时需要补充_locales目录、terminology-locale.md术语规范与editorLangs条目否则机械检查失败术语规范新增或修改某个 locale 的内容前必须先检查并遵循对应的docs/references/terminology-locale.mden-US是回退语言与翻译模板措辞应被刻意校准提交前检查清单确认目标 locale 与术语规范 → 使用目标语言自然表达并保留 i18next 插值、程序标识符、HTML/React 标记 → 运行pnpm run check:i18n或pnpm lint已内含此检查确认没有遗漏或多余的翻译 key。通过上述「i18next 动态切换 命名空间拆分 page.key消歧 机械检查兜底」的组合ScriptCat 得以在 10 个语言地区之间实现无刷新切换的完整多语言体验同时满足浏览器扩展市场对chrome.i18n格式的兼容要求。赞分享前端开发者工具插件系统【免费下载链接】scriptcatScriptCat, a browser extension that can execute userscript; 脚本猫一个可以执行用户脚本的浏览器扩展项目地址https://gitcode.com/gh_mirrors/sc/scriptcat点击查看免费下载相关推荐BottomBar国际化实践多语言资源组织与动态切换BottomBar国际化实践多语言资源组织与动态切换 在移动应用开发中面向全球用户的产品需要解决多语言适配问题。BottomBar作为Material DeUI组件移动开发QuickLook国际化架构多语言资源文件组织与动态切换QuickLook国际化架构多语言资源文件组织与动态切换 QuickLook作为一款高效的文件预览工具其国际化架构设计确保了全球用户能够获得本地化的使用体验桌面应用插件系统从论文到实践LongCat-AudioDiT研究成果的技术实现路径从论文到实践LongCat AudioDiT研究成果的技术实现路径 LongCat AudioDiT 是一款基于扩散模型的文本转语音TTS模型代表了当前上一篇Readest安全审计现代开源电子书阅读器的全方位安全保障措施解析下一篇django-mongoengine高级技巧查询优化与性能提升的5个方法创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表