
Bitwarden 客户端多应用 i18n 国际化规范从 I18nPipe / I18nService 到 messages.json 的完整实践指南【免费下载链接】clientsBitwarden client apps (web, browser extension, desktop, and cli).项目地址: https://gitcode.com/GitHub_Trending/cl/clients导读本文基于 Bitwarden 客户端仓库clients的.claude/rules/i18n.md规则文档系统讲解该 monorepo 中 Web、浏览器扩展、桌面端与 CLI 四个应用共享一套国际化Localization / i18n体系时的硬性规范所有用户可见字符串必须通过模板中的I18nPipe或 TypeScript 中的I18nService.t()进行本地化新增翻译 key 时只允许编辑enlocale其余语言统一由 Crowdin 托管并且共享库字符串必须在每个使用它的应用的messages.json中同步添加。文章将结合 I18nPipe 实现、TranslationService 底层与四份 locale 文件给出可直接落地的操作步骤、参数化占位符原理与多应用同步清单。适用范围与规则边界i18n.md规则适用于仓库中所有涉及用户可见文本的代码路径paths: - apps/**/*.html - apps/**/*.ts - libs/**/*.html - libs/**/*.ts也就是说四个客户端应用apps/browser、apps/web、apps/desktop、apps/cli以及所有共享库libs/**中的模板与 TypeScript 源码都属于国际化审查范围。用户可见字符串包括但不限于模板文本templatesToast 提示toasts对话框dialogsARIA 无障碍标签ARIA labels表单校验消息validation messages从源码证据看校验消息确实是经I18nService.t()输出的典型案例libs/common/src/platform/services/validation.service.ts中showError()直接调用this.i18nService.t(unexpectedError)构造默认错误文案再通过this.i18nService.t(errorOccurred)作为 Toast 标题。两条唯一出口I18nPipe 与 I18nService.t()规则明确模板中必须用I18nPipeTypeScript 中必须用I18nService.t()不允许硬编码用户可见字符串。模板侧I18nPipe管道的真实实现在 libs/ui/common/src/i18n.pipe.tsPipe({ name: i18n, }) export class I18nPipe implements PipeTransform { constructor(private i18nService: I18nService) {} transform(id: string, p1?: string | number, p2?: string | number, p3?: string | number): string { return this.i18nService.t(id, p1, p2, p3); } }管道名称为i18n支持最多三个位置参数。在模板中的典型用法{{ name | i18n }} {{ characterMaximum | i18n: 100 }} {{ accessingUsingProvider | i18n: organization.providerName }}以上示例均取自仓库真实模板apps/web/src/app/admin-console/organizations/manage/group-add-edit.component.html中name | i18n与characterMaximum | i18n: 100apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html中accessingUsingProvider | i18n: organization.providerName。TypeScript 侧I18nService.t()规则要求服务端/逻辑层字符串使用this.i18nService.t(key)。其抽象接口定义于 libs/common/src/platform/abstractions/i18n.service.tsexport abstract class I18nService extends TranslationService { abstract userSetLocale$: Observablestring | undefined; abstract locale$: Observablestring; abstract setLocale(locale: string | null): Promisevoid; abstract init(): Promisevoid; }具体实现在 libs/common/src/platform/services/i18n.service.ts它通过GlobalStateProvider注册了TRANSLATION_DISK上的localekey将用户手动选择的语言持久化并暴露userSetLocale$与locale$两个 RxJS 流供界面响应语言切换。底层翻译管线TranslationServicet()的核心逻辑位于父类 libs/common/src/platform/services/translation.service.ts加载顺序init()时优先加载当前语言localeMessages若当前语言不是默认en还会额外加载默认英文defaultMessages形成当前语言缺失时回退英文的兜底机制。查找顺序translate()先在localeMessages中查 key未命中再查defaultMessages两者都未命中返回空字符串。语言回退若当前 locale 不在supportedTranslationLocales中先截断为两位语言码如pt-BR→pt再匹配仍不匹配则回退defaultLocale en。排序支持初始化时创建Intl.Collator(translationLocale, { numeric: true, sensitivity: base })供列表按目标语言规则排序使用。新增 key 的核心流程只改 en交给 Crowdin规则给出两个硬性要求Only edit theenlocale —— 只编辑英文语言文件其余语言由 Crowdin 平台自动翻译与同步手工改动其他语言文件会与 Crowdin 冲突Add it to every app that uses it —— 共享库中使用的字符串必须在每个消费该库的应用的messages.json中同步添加 key。四个应用的 en locale 文件位置应用en locale 文件browserapps/browser/src/_locales/en/messages.jsonwebapps/web/src/locales/en/messages.jsondesktopapps/desktop/src/locales/en/messages.jsoncliapps/cli/src/locales/en/messages.json规则依据清晰浏览器扩展遵循 Chrome/WebExtension 的_locales/locale/messages.json目录约定apps/browser/src/_locales/下共 63 个 locale 目录而 web、desktop、cli 则使用apps/app/src/locales/locale/messages.json布局web/desktop 各 66 个语言文件cli 1 个。文件内格式示例apps/browser/src/_locales/en/messages.json的开头示例{ appName: { message: Bitwarden }, appLogoLabel: { message: Bitwarden logo }, extName: { message: Bitwarden Password Manager, description: Extension name, MUST be less than 40 characters (Safari restriction) }, loginOrCreateNewAccount: { message: Log in or create a new account to access your secure vault. } }apps/web/src/locales/en/messages.json则形如{ allApplications: { message: All applications }, activity: { message: Activity } }参数化占位符$1 / $2 / $3 与 placeholders 映射模板传参 →__$N__替换I18nPipe将位置参数透传给t(id, p1, p2, p3)translate()在拿到译文后执行替换if (p1 ! null) { result result.split(__$1__).join(p1.toString()); } if (p2 ! null) { result result.split(__$2__).join(p2.toString()); } if (p3 ! null) { result result.split(__$3__).join(p3.toString()); }即在 messages.json 中位置参数以__$1__、__$2__、__$3__形式嵌入message文本由I18nPipe/t()传入的值按序替换。placeholders 命名占位符的转换loadMessages()还支持 Chrome 风格的命名占位符读取每个条目的placeholders字段将$PLACEHOLDERNAME$如$SCORE$替换为placeholders[prop].content指向的位置参数标记。若content为$1/$2/$3则转换为__$N__交由上述替换逻辑处理。apps/browser/src/_locales/en/messages.json中的真实案例passwordStrengthScore: { message: Password strength score $SCORE$, placeholders: { score: { content: $1 } } }以及带默认内容的示例masterPassHintText: { message: If you forget your password, the password hint can be sent to your email. $CURRENT$/$MAXIMUM$ character maximum., placeholders: { current: { content: $1 }, maximum: { content: 50 } } }这种设计允许同一个 key 在 web 与浏览器扩展Chrome i18n 体系间保持兼容——浏览器扩展可直接使用$SCORE$风格占位符Angular 侧则通过i18n: 参数完成同样的注入。实战操作清单按规则落地一个新字符串 key完整步骤为确认字符串属于用户可见文本模板文本、Toast、对话框、ARIA 标签、校验消息不得硬编码模板中使用{{ yourKey | i18n }}带参时写{{ yourKey | i18n: value1: value2 }}TypeScript 中使用this.i18nService.t(yourKey, value1, value2)只编辑en的 messages.json添加形如yourKey: { message: ... }的条目参数用__$1__/__$2__或$NAME$placeholders表达同步到所有使用该 key 的应用浏览器扩展编辑apps/browser/src/_locales/en/messages.jsonWeb 编辑apps/web/src/locales/en/messages.json桌面端编辑apps/desktop/src/locales/en/messages.jsonCLI 编辑apps/cli/src/locales/en/messages.json若共享库使用则四个文件通常都要添加其余语言交给 Crowdin仓库根目录存在apps/browser/crowdin.yml、apps/desktop/crowdin.yml、apps/web/crowdin.yml等同步配置不要在非 en locale 中手工添加或修改 key提交前自检所有四个应用若都消费该字符串的 en 文件 key 一致模板/TS 引用与 key 拼写完全匹配。常见误区与注意事项不要手工改非 en localeCrowdin 会全量接管非英文语言文件的同步手工修改会被覆盖或产生冲突共享库 key 不是只加在共享库libs/**的组件在 web、desktop、browser 等多处被消费运行时每个应用只加载自己的 messages.json因此必须逐应用添加这正是规则强调 Add it to every app that uses it 的原因参数顺序敏感i18n管道与t()仅支持 3 个位置参数p1/p2/p3需要更多参数时应拆分句子或改写文案结构而不是扩展参数个数未命中 key 返回空字符串translate()在当前语言与英文兜底都未命中时返回因此 key 拼写错误不会抛异常但会静默显示空白——务必在四个 en 文件中核对 key 是否存在占位符大小写敏感命名占位符$SCORE$会按placeholders的 key 名score转换为$SCORE$进行正则替换书写不一致会导致替换失效。小结Bitwarden clients monorepo 的 i18n 体系以只改 en Crowdin 托管多语言 每应用同步 key为核心配合统一的I18nPipe模板与I18nService.t()TypeScript出口以及TranslationService提供的语言回退、参数替换与命名占位符机制保证了 web、browser、desktop、cli 四个客户端与全部共享库在 60 语言间的行为一致。遵循上述规则新增字符串即可在不接触非英文语言文件的前提下让新文案自动进入完整的本地化流水线。【免费下载链接】clientsBitwarden client apps (web, browser extension, desktop, and cli).项目地址: https://gitcode.com/GitHub_Trending/cl/clients创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考