主题
国际化支持
本文引用的源码文件
本文引用的文件
目录
- 引言
- 项目结构与 i18n 定位
- 双端 i18n 架构总览
- 扩展端:Chrome 消息系统与运行时语言切换
- Agent 端:本地化文件与请求级语言解析
- 多语言消息管理机制
- 运行时语言切换流程
- 翻译文件维护指南
- 使用示例:JavaScript 与 HTML 模板
- i18n 工具函数说明
- 依赖关系分析
- 性能与可维护性考量
- 常见问题与排错
- 最佳实践与工作流建议
- 结论
引言
本文件面向开发者与维护者,系统性说明 AI Helper 的双端国际化方案。项目采用“扩展端 + Agent 端”双进程架构:扩展端基于 Chrome Manifest V3 Service Worker,使用 _locales 与 shared/i18n.js;Agent 端为 Node.js 服务,使用 agent/src/i18n.js 与 agent/src/locales/*.json。文档重点覆盖:
- 双端 i18n 架构差异与协作方式
- 消息键命名、参数插值与回退策略
- 运行时语言检测、持久化与界面刷新
- 新增语言、翻译质量保证与同步机制
- JavaScript 调用与 HTML 模板嵌入方式
- 工具函数、注意事项与常见故障排查
项目结构与 i18n 定位
仓库中与国际化直接相关的资源分布在以下位置:
- 扩展端 Chrome 标准消息:
_locales/{locale}/messages.json - 扩展端运行时 i18n 模块:
src/shared/i18n.js - 扩展端运行时语言包:
src/shared/locales/{en,zh}.js - Agent 端 i18n 模块:
agent/src/i18n.js - Agent 端系统语言检测:
agent/src/sys-lang.js - Agent 端语言包:
agent/src/locales/{en,zh}.json - Agent 服务端入口:
agent/src/server.js - 扩展清单:
manifest.json
graph TB subgraph "扩展端" M["manifest.json<br/>Chrome 消息占位"] L1["_locales/en/messages.json"] L2["_locales/zh_CN/messages.json"] I18N["src/shared/i18n.js"] ENJS["src/shared/locales/en.js"] ZHJS["src/shared/locales/zh.js"] end subgraph "Agent 端" AI18N["agent/src/i18n.js"] SLANG["agent/src/sys-lang.js"] AEN["agent/src/locales/en.json"] AZH["agent/src/locales/zh.json"] SRV["agent/src/server.js"] end M --> L1 M --> L2 I18N --> ENJS I18N --> ZHJS AI18N --> AEN AI18N --> AZH AI18N --> SLANG SRV --> AI18N
图表来源
- manifest.json#L1-L76
- _locales/en/messages.json#L1-L12
- _locales/zh_CN/messages.json#L1-L12
- src/shared/i18n.js#L1-L251
- src/shared/locales/en.js#L1-L800
- src/shared/locales/zh.js#L1-L800
- agent/src/i18n.js#L1-L100
- agent/src/sys-lang.js#L1-L30
- agent/src/locales/en.json#L1-L368
- agent/src/locales/zh.json#L1-L368
- agent/src/server.js#L1-L60
章节来源
双端 i18n 架构总览
本项目存在两套相对独立但语义对齐的国际化体系:
| 维度 | 扩展端 | Agent 端 |
|---|---|---|
| 主要用途 | 浏览器侧 UI、命令描述、设置页、内容脚本提示等 | HTTP/WebSocket API 返回的错误、状态、日志、RAG、Skill、MCP 等后端文案 |
| 核心模块 | src/shared/i18n.js | agent/src/i18n.js |
| 语言包格式 | JS 对象导出(en.js / zh.js) | JSON 文件(en.json / zh.json) |
| Chrome 标准消息 | _locales/*/messages.json,由 manifest.json 引用 | 不适用 |
| 默认语言 | zh | en,可通过环境变量或系统语言检测 |
| 运行时切换 | 通过 setLanguage + chrome.storage.local 跨环境同步 | 按请求 Accept-Language 解析,或由 CLI/env 固定 |
| 参数插值 | {name} 形式 | {name} 形式 |
| 回退策略 | 当前语言 → 英文 → key 本身 | 指定语言 → 默认语言 → key 本身 |
关键设计要点:
- 扩展端适合“用户可见界面”,强调运行时动态切换和 DOM 自动填充。
- Agent 端适合“服务端输出”,强调请求级语言选择、错误信息本地化和日志可读性。
- 两端都使用点分 key 与
{param}插值,便于统一理解,但实现细节不同。
章节来源
扩展端:Chrome 消息系统与运行时语言切换
Chrome 标准消息
manifest.json 中声明了扩展名、描述和命令描述,这些字符串通过 __MSG_*__ 占位符引用 _locales 下的 messages.json。例如:
name使用__MSG_extName__description使用__MSG_extDescription__- 命令描述使用
__MSG_commandToggleSidepanel__
这意味着 Chrome 商店展示、快捷键提示、扩展名称等由 Chrome 自身根据 default_locale 和用户语言加载对应 messages.json。
运行时 i18n 模块
src/shared/i18n.js 提供扩展端运行时翻译能力:
- 内置支持语言:
zh、en - 默认语言:
zh - 支持点分 key 查找
- 支持
{name}参数插值 - 支持运行时语言切换
- 支持订阅语言变更并刷新界面
- 支持从
chrome.storage.local读取/写入语言偏好 - 支持
data-i18n*属性自动填充文本、placeholder、title、aria-label
flowchart TD
Start(["页面或服务 Worker 启动"]) --> InitI18n["调用 initI18n()"]
InitI18n --> CheckStorage{"chrome.storage.local 中有 language?"}
CheckStorage --> |是| UseStored["使用已保存语言"]
CheckStorage --> |否| DetectBrowser["detectBrowserLanguage()"]
DetectBrowser --> PersistAuto["持久化自动检测结果"]
UseStored --> Subscribe["注册 storage.onChanged 监听"]
PersistAuto --> Subscribe
Subscribe --> Ready(["t() 可用"])
图表来源
章节来源
- manifest.json#L3-L6
- manifest.json#L54-L61
- _locales/en/messages.json#L1-L12
- _locales/zh_CN/messages.json#L1-L12
- src/shared/i18n.js#L17-L38
- src/shared/i18n.js#L168-L207
Agent 端:本地化文件与请求级语言解析
Agent 端的 i18n 模块负责:
- 在进程启动时加载
agent/src/locales/en.json与agent/src/locales/zh.json - 确定默认语言:CLI 参数或
AI_HELPER_LANG环境变量优先,否则调用sys-lang.js检测系统语言 - 解析 HTTP 请求的
Accept-Language头,匹配最合适的语言 - 提供
t(lang, key, params)和getRequestI18n(req)
sequenceDiagram
participant Client as "HTTP 客户端"
participant Server as "agent/src/server.js"
participant I18N as "agent/src/i18n.js"
participant SysLang as "agent/src/sys-lang.js"
participant Locales as "agent/src/locales/*.json"
Client->>Server : HTTP 请求
Server->>I18N : getRequestI18n(req)
I18N->>I18N : parseAcceptLanguage(Accept-Language)
I18N->>SysLang : detectSystemLang()
SysLang-->>I18N : zh 或 en
I18N->>Locales : 加载 zh.json / en.json
I18N-->>Server : { lang, t }
Server->>I18N : t(key, params)
I18N-->>Server : 本地化消息
Server-->>Client : 响应
图表来源
- agent/src/i18n.js#L18-L56
- agent/src/i18n.js#L65-L99
- agent/src/sys-lang.js#L14-L29
- agent/src/server.js#L56-L60
章节来源
多语言消息管理机制
消息键命名规范
- 扩展端与 Agent 端均使用点分 key,例如
common.confirm、error.fileNotFound、server.httpStarted。 - 推荐按功能域分组:
- 通用文案:
common.* - 对话框与交互:
dialog.*、chat.*、input.* - 设置页:
settings.*、react.*、toolbar.* - 工具相关:
tool.*、toolCategory.* - Agent 错误:
error.*、security.*、exec.* - Agent 业务:
rag.*、memory.*、skill.*、mcp.*、server.*
- 通用文案:
参数插值
- 扩展端与 Agent 端均使用
{name}占位符。 - 若参数缺失,扩展端会保留原占位符或 key;Agent 端也会保留未提供的参数名。
- 建议始终传入必要参数,避免显示原始
{name}。
复数形式处理
- 当前实现未提供复数规则引擎。
- 对于数量相关文案,建议在 key 层面区分或使用自然语言表达,例如:
- 使用带数量的文案 key,如
foundResults,并在参数中传入具体数字。 - 在翻译层用自然语言描述数量,而不是依赖复数规则。
- 使用带数量的文案 key,如
回退策略
- 扩展端:当前语言 → 英文 → key 本身。
- Agent 端:指定语言 → 默认语言 → key 本身。
章节来源
运行时语言切换流程
扩展端的语言切换由 setLanguage 驱动,核心流程如下:
flowchart TD
Change(["调用 setLanguage(lang)"]) --> Validate{"lang 是否有效且不同于当前语言?"}
Validate --> |否| Ignore["忽略变更"]
Validate --> |是| UpdateState["更新 currentLang"]
UpdateState --> Persist{"是否允许持久化?"}
Persist --> |是| SaveStorage["写入 chrome.storage.local.language"]
Persist --> |否| SkipPersist["跳过持久化"]
SaveStorage --> Notify["通知所有订阅者"]
SkipPersist --> Notify
Notify --> RefreshUI["UI 组件重新渲染"]
图表来源
关键点:
- 语言变更后,会通过订阅者回调通知 UI 层。
- 语言偏好会写入
chrome.storage.local,其他页面(background、side panel、options、content script)可通过storage.onChanged同步。 applyI18n用于批量刷新带data-i18n*属性的 DOM 元素。
章节来源
翻译文件维护指南
新增语言的步骤
当前仓库仅维护中文与英文。若需新增语言,应同时考虑扩展端与 Agent 端:
扩展端
- 在
src/shared/locales/下新增语言文件,例如xx.js。 - 在
src/shared/i18n.js中导入新语言包,并加入SUPPORTED_LANGUAGES。 - 在
initI18n的语言字典中注册新语言。 - 如需 Chrome 标准消息,可在
_locales/xx/下新增messages.json。
- 在
Agent 端
- 在
agent/src/locales/下新增xx.json。 - 在
agent/src/i18n.js中加载新语言文件。 - 确保
parseAcceptLanguage能识别新语言代码。
- 在
验证
- 运行构建脚本验证无语法错误。
- 检查扩展端 UI 是否能切换到新语言。
- 检查 Agent 端 API 返回文案是否按预期本地化。
翻译质量保证
- 保持 key 一致:新增 key 必须同时在所有语言文件中出现。
- 保持参数一致:如果某个 key 使用
{name},所有语言版本都应保留相同占位符。 - 避免硬编码:不要在业务逻辑中直接写死文案,统一走
t()。 - 审查长文案:中文、英文长度差异较大,注意 UI 布局与换行。
- 测试边界情况:空值、null、超长文本、特殊字符。
同步机制
- 扩展端语言包以 JS 对象为主,适合模块化按需引入。
- Agent 端语言包以 JSON 为主,适合静态加载与快速解析。
- 建议在代码审查中检查新增 key 是否遗漏翻译。
章节来源
- src/shared/i18n.js#L17-L21
- src/shared/i18n.js#L142-L157
- agent/src/i18n.js#L12-L24
- agent/src/i18n.js#L32-L56
使用示例:JavaScript 与 HTML 模板
JavaScript 中调用翻译函数
扩展端推荐使用 src/shared/i18n.js 导出的 t:
- 基本用法:
t('common.confirm') - 参数插值:
t('dialog.remainingTime', { time: '1:30' }) - 获取当前语言:
getLanguage() - 设置语言:
setLanguage('en') - 订阅语言变化:
subscribe((lang) => { ... }) - 初始化语言:
await initI18n() - 注册额外翻译:
registerTranslations(lang, dict)
Agent 端推荐使用 agent/src/i18n.js:
- 基础用法:
t(lang, 'error.fileNotFound', { path: '/foo' }) - 请求级 i18n:
const { lang, t } = getRequestI18n(req)
HTML 模板中嵌入动态文本
扩展端支持通过 data-i18n* 属性配合 applyI18n 自动填充:
data-i18n="common.confirm":设置元素文本data-i18n-placeholder="ui.inputPlaceholder":设置 placeholderdata-i18n-title="ui.tip":设置 titledata-i18n-aria-label="ui.accessibleLabel":设置 aria-label
注意:
- 动态内容(如版本号、计数、格式化结果)不应只依赖
data-i18n,应在 JS 中调用t()后插入。 - 语言切换后应再次调用
applyI18n刷新 DOM。
章节来源
- src/shared/i18n.js#L4-L12
- src/shared/i18n.js#L86-L96
- src/shared/i18n.js#L214-L238
- agent/src/i18n.js#L65-L99
i18n 工具函数说明
扩展端工具函数
| 函数 | 作用 | 返回值 | 备注 |
|---|---|---|---|
t(key, params?) | 根据当前语言查找翻译并插值 | string | 找不到时返回 key |
getLanguage() | 获取当前语言代码 | string | 默认 zh |
setLanguage(lang, persist?) | 设置语言并可选持久化 | void | 触发订阅者 |
subscribe(callback) | 订阅语言变更 | function | 返回取消订阅函数 |
registerTranslations(lang, dict) | 合并某语言翻译字典 | void | 深度合并 |
initI18n() | 初始化语言并从存储恢复 | Promise<string> | 注册 storage 监听 |
applyI18n(root?) | 刷新 DOM 中的 data-i18n* 元素 | void | 需要 root 为 DOM 节点 |
Agent 端工具函数
| 函数 | 作用 | 返回值 | 备注 |
|---|---|---|---|
parseAcceptLanguage(header?) | 解析 Accept-Language | string | 返回 zh 或 en |
t(lang, key, params?) | 根据指定语言查找翻译并插值 | string | 找不到时返回 key |
getRequestI18n(req) | 从请求中提取语言并返回 t | object | 包含 lang 和 t |
格式化、日期处理和数字转换
当前 i18n 模块未内置日期格式化、数字格式化或复数规则引擎。建议:
- 在业务层使用
Intl.DateTimeFormat、Intl.NumberFormat进行格式化。 - 将格式化后的结果作为参数传给
t()。 - 对需要区域化显示的数值、时间、货币,优先使用浏览器或 Node.js 原生 Intl API。
章节来源
依赖关系分析
扩展端 i18n 依赖:
src/shared/locales/en.jssrc/shared/locales/zh.js- Chrome API:
chrome.i18n、chrome.storage
Agent 端 i18n 依赖:
agent/src/locales/en.jsonagent/src/locales/zh.jsonagent/src/sys-lang.js- Node.js:
fs、path、process.env、Intl
graph LR SharedI18N["src/shared/i18n.js"] --> EnJS["src/shared/locales/en.js"] SharedI18N --> ZhJS["src/shared/locales/zh.js"] AgentI18N["agent/src/i18n.js"] --> EnJSON["agent/src/locales/en.json"] AgentI18N --> ZhJSON["agent/src/locales/zh.json"] AgentI18N --> SysLang["agent/src/sys-lang.js"] Server["agent/src/server.js"] --> AgentI18N
图表来源
章节来源
性能与可维护性考量
- 扩展端语言包为 JS 模块,编译期可被打包器优化;运行时查表复杂度近似 O(1)。
- Agent 端语言包为 JSON,进程启动时一次性加载,适合服务端高频调用。
applyI18n会遍历 DOM,频繁调用可能带来性能开销,建议仅在语言切换或页面初始化时调用。registerTranslations使用深度合并,适合模块分散注册翻译,但应避免重复覆盖。- 语言切换通过订阅者模式解耦 UI 刷新,降低耦合度。
[本节为通用性能讨论,不直接分析具体代码片段]
常见问题与排错
问题:语言切换后部分文案未更新
可能原因:
- 动态生成的 DOM 没有
data-i18n*属性。 - 语言切换后未调用
applyI18n。 - 文案是通过 JS 直接赋值而非
t()。
解决建议:
- 对静态文案使用
data-i18n*。 - 对动态文案在 JS 中调用
t()。 - 语言切换后调用
applyI18n(document)。
章节来源
问题:Agent 端返回英文而非中文
可能原因:
- 请求未携带正确的
Accept-Language。 - 环境变量
AI_HELPER_LANG设置为en。 - 系统语言检测结果为
en。
解决建议:
- 检查请求头
Accept-Language。 - 检查
AI_HELPER_LANG环境变量。 - 检查系统语言环境变量或
Intl.DateTimeFormat().resolvedOptions().locale。
章节来源
问题:Chrome 扩展名或命令描述未本地化
可能原因:
_locales下缺少对应语言的messages.json。manifest.json中使用了错误的消息 key。- 浏览器语言与
_locales目录名不匹配。
解决建议:
- 确保
_locales/en与_locales/zh_CN中存在完整messages.json。 - 核对
manifest.json中的__MSG_*__key。 - 确认 Chrome 语言设置与
_locales目录匹配。
章节来源
- manifest.json#L3-L6
- manifest.json#L54-L61
- _locales/en/messages.json#L1-L12
- _locales/zh_CN/messages.json#L1-L12
最佳实践与工作流建议
- 新增功能时先定义 key,再补充中英文翻译。
- 避免在业务逻辑中硬编码文案。
- 对含参数的文案,统一使用
{name}插值。 - 对 UI 文案优先使用
data-i18n*+applyI18n。 - 对动态内容使用
t()后插入 DOM。 - 对 Agent 端错误信息,使用
getRequestI18n(req)获取请求级 t。 - 新增语言时同步扩展端与 Agent 端。
- 在代码审查中检查 key 是否遗漏翻译。
- 对长文案进行 UI 适配测试。
- 对日期、数字、货币使用 Intl API 格式化后再传给
t()。
[本节为通用工作流建议,不直接分析具体代码片段]
结论
AI Helper 的国际化方案围绕“扩展端运行时 i18n”和“Agent 端请求级 i18n”两条主线展开。扩展端侧重用户界面体验,支持运行时语言切换、DOM 自动填充和跨环境同步;Agent 端侧重服务端输出,支持 Accept-Language 解析、系统语言检测和 JSON 语言包。两者均采用点分 key 与 {name} 插值,具备清晰的回退策略。通过本文档的架构说明、使用示例、维护指南和排错建议,开发者可以更系统地扩展、维护和调试项目的国际化能力。
[本节为总结性内容,不直接分析具体代码片段]