跳到主要内容

前端多语言采用策展目录(vue-i18n),拒绝运行时机器翻译

背景

两个 Vue 3 SPA(frontends/userfrontends/admin)此前完全没有 i18n:页面骨架硬编码英文,而共享错误信息目录(src/services/messages/zh-CN.ts)硬编码中文且 DEFAULT_LOCALE = 'zh-CN'——渲染出的界面本身是混语言的。文档站已运行双语言约定(Docusaurus defaultLocale: 'en' + zh-CN 镜像树,同 PR 双写)。在对全部 27 个视图做文案抽取之前,我们评估了自动翻译组件(主要是 translate.js,xnx3/translate)与策展消息目录两条路线。

关于 translate.js(v4,MIT,活跃维护)的关键事实:它在页面加载后遍历 DOM,把页面文本发送到作者私有云(api.translate.zvo.cn 等)做机器翻译;免费通道有每日字数上限;翻译发生在首绘之后(天然 FOUC);Vue 适配有未决 issue(#54、#94);且它会改写 input 的 value 属性——对凭据表单是 UX 隐患。

决策

采用 vue-i18n v11 策展消息目录(Composition API,legacy: falseglobalInjection: true)作为两个前端唯一的 i18n 机制。语言集:现在为 en(默认)+ zh-CN,后续可扩展二级集合(zh-TWjadeesfrpt-BRru)。运行时机翻组件(machine-translation widget)对产品 UI 被明确拒绝

理由:fulla 是安全敏感的身份提供方——consent/scope/authorization 术语必须人工策展、页面内容不得外发第三方翻译云、自托管/离线部署(IdP 常态)必须可用、渲染文本必须确定性且可在 PR 中评审。translate.js 是 MIT 许可、技术上可以嵌入,但其数据流本身就足以否决。vue-i18n 是 Vue 事实标准(MIT,约 390 万周下载),在当前目录规模下无需额外构建插件(运行时约 10–14 KB brotli),且与错误目录既有的 per-locale 资源文件设计同构。

后果与现状

  • 每个应用一个语言切换器同时驱动页面骨架与新产生的错误信息:getErrorMessage(code) 在错误触发时按当前 UI locale 解析。已渲染的消息是一次性快照——切换语言不会重译屏上已有文本(该行为由 e2e 锁定;存错误码、渲染时重解析的完全响应式改造列为受跟踪的后续选项)。DEFAULT_LOCALE 变为回退表(en)。
  • 语言检测顺序:localStorage['fulla-locale'](沿用 fulla-theme 模式)→ navigator.languagesen,在 mount 前同步生效(无语言闪烁),并同步 <html lang>index.html 内联脚本在首绘前预同步 lang。
  • 服务层(errorAdapter + messages/,两应用镜像文件)保持零依赖:当前语言经 services/locale.ts 纯模块传递,由 i18n 引导层推送——node 环境单测因此不受影响。
  • 目录双写(en + zh-CN)同 PR 完成,由 key-parity 与调用点 key 存在性单测(i18nKeys.test.ts)强制;镜像服务与 components/ui 字节同步门禁保持两应用一致。
  • 机器翻译仅允许用于翻译工作流(新增语言时预翻译 + 人工评审),绝不允许进入运行时。
  • 一次性成本:27 个视图的文案抽取(user 188 键 + admin 306 键);固定中文错误文案的 e2e 断言迁移到英文目录(默认语言),中文路径由每应用专属 i18n.spec.ts 覆盖。