LobeHub 国际化实战:基于 react-i18next 的扁平 Key 命名与自动化翻译流水线
LobeHub 是一套面向 7×24 小时 Agent 运营平台的多语言体系,采用 react-i18next 作为框架,默认语言为英语(en-US)。本文基于仓库中的 i18n 技能文档 完整展开,并结合 .i18nrc.js、scripts/i18nWorkflow/ 与 auto-i18n.yml 等真实实现,讲清 Key 命名规范、组件用法、新增文案的五步工作流,以及“默认 locale 生成 + LLM 自动翻译 + 每日定时 PR”的完整流水线,读完即可在 LobeHub 中规范地添加、维护与发布国际化文案。
一、目录职责:单一事实源与生成产物分离
LobeHub 的 i18n 目录结构有一条铁律:只能编辑 packages/locales/src/default/ 下的文件,绝不要直接修改 locales/ 下的 JSON 文件(手工维护的 en-US/zh-CN 预览文案除外)。这一约束在 SKILL.md 中被明确标注,其工程含义是:
packages/locales/src/default/{namespace}.ts:中文默认 locale(源语言),开发者手写,是所有文案的单一事实源(source of truth);locales/{locale}/{namespace}.json:由lobe-i18n翻译工具生成(或每日自动工作流更新),属于生成产物,直接手改会被下次翻译覆盖;locales/en-US/与locales/zh-CN/允许手工写入,用作开发阶段的即时预览。
从 packages/locales/src/default/index.ts 可以看到,每个 namespace 都是一个独立的 TS 模块(import chat from './chat'),最终聚合为 resources 常量导出。当前仓库实际注册了 50 余个 namespace,包括 agent、agentGroup、auth、chat、color、common、components、desktop-onboarding、device、discover、editor、electron、error、eval、file、home、hotkey、image、knowledgeBase、labs、marketAuth、memory、messenger、metadata、migration、modelProvider、modelRuntime、models、notification、oauth、onboarding、opStatusTray、openInApp、pageShare、plugin、portal、project、providers、ragEval、selfLearning、setting、spend、subscription、suggestQuestions、thread、tool、topic、ui、verify、video、welcome 等——可以看到命名上允许连字符(desktop-onboarding)与驼峰(knowledgeBase)两种风格,导出时以字符串键对齐('desktop-onboarding': desktopOnboarding)。
框架依赖方面,根 package.json 中声明了 react-i18next ^16.6.6、i18next ^25.10.10、i18next-browser-languagedetector、i18next-resources-to-backend,翻译 CLI 为 @lobehub/i18n-cli ^1.27.0。
二、Key 命名规范:扁平点号键而非嵌套对象
LobeHub 的文案 Key 统一采用扁平的点号命名(flat keys with dot notation),而不是嵌套对象结构:
// ✅ 正确:扁平 key
export default {
'alert.cloud.action': '立即体验',
'sync.actions.sync': '立即同步',
'sync.status.ready': '已连接',
};
// ❌ 避免:嵌套对象
export default {
alert: { cloud: { action: '...' } },
};
命名模式为 {feature}.{context}.{action|status},即「功能.上下文.动作/状态」三段式,例如 alert.cloud.action 表示「alert 功能下 cloud 上下文中的操作按钮」。扁平结构的工程收益是:Key 即字符串路径,可被脚本按行扫描、按前缀分组统计(scripts/i18nWorkflow/ 中的 flattenLocaleKeys.ts、analyzeUnusedKeys.ts 等工具正是基于这种可扁平化的结构做未使用 Key 分析),也便于 i18next 按命名空间字符串精确寻址。
插值参数使用 {{variableName}} 语法:
'alert.cloud.desc': '我们提供 {{credit}} 额度积分',
避免 Key 冲突
扁平键还有一个必须遵守的约束:不要让一个 Key 恰好成为另一个 Key 的前缀,否则在工具按前缀聚合、或按段拆分时会产生歧义冲突:
// ❌ 冲突:solve 与 solve.backup.title 前缀重叠
'clientDB.solve': '自助解决',
'clientDB.solve.backup.title': '数据备份',
// ✅ 解法:给短 Key 补一层语义(action)
'clientDB.solve.action': '自助解决',
'clientDB.solve.backup.title': '数据备份',
规则可以概括为:当一个 Key 需要“拥有子 Key”时,必须给它换一个不与子路径重合的名字,通常补 .action、.label、.title 之类的末端语义段。
三、组件中使用:useTranslation、命名空间与插值
组件层的调用方式完全遵循 react-i18next 的标准 API:
import { useTranslation } from 'react-i18next';
const { t } = useTranslation('common');
t('newFeature.title');
t('alert.cloud.desc', { credit: '1000' });
// 多命名空间
const { t } = useTranslation(['common', 'chat']);
t('common:save');
要点:
useTranslation('common')传入单个命名空间后,t('newFeature.title')直接以 Key 寻址;- 插值以第二个参数对象传入,
{{credit}}被替换为1000; - 需要跨命名空间时传入数组
['common', 'chat'],此时必须用命名空间:Key前缀语法(t('common:save'))显式指定来源。
使用频率最高的三个命名空间是 common(共享 UI 文案)、chat(聊天功能)与 setting(设置页),绝大多数通用按钮、加载态、错误提示都应优先放入 common,避免在业务 namespace 中重复定义。
四、新增文案的五步工作流
向 LobeHub 添加一条新文案的完整流程(对应 SKILL.md 的 Workflow 章节):
- 添加 Key:在
packages/locales/src/default/{namespace}.ts中新增条目,遵循扁平命名与插值规范; - 导出命名空间:如果是新建的 namespace 文件,必须在 packages/locales/src/default/index.ts 中 import 并加入
resources对象(注意连字符命名要用字符串键,参考'desktop-onboarding': desktopOnboarding的写法); - 开发预览:手工翻译
locales/zh-CN/{namespace}.json与locales/en-US/{namespace}.json,保证本地开发时两种语言可见; - 其余语言交给自动化:由 .github/workflows/auto-i18n.yml 每日定时翻译并自动开 PR,开发者无需手工处理其他 15 种语言;
- 立即需要时才手动跑:
bun run i18n仅在分支必须立即拿到全量翻译时使用——该命令执行缓慢,且依赖OPENAI_API_KEY。
第 5 步背后的实现,可以从 package.json 的 scripts 拆解出来:
"i18n": "npm run workflow:i18n && lobe-i18n && prettier -c --write \"locales/**\"",
"workflow:i18n": "tsx ./scripts/i18nWorkflow/index.ts",
"i18n:unused": "tsx ./scripts/i18nWorkflow/analyzeUnusedKeys.ts",
"i18n:unused-clean": "tsx ./scripts/i18nWorkflow/cleanUnusedKeys.ts",
"docs:i18n": "lobe-i18n md && npm run lint:mdx"
即 bun run i18n 实际是三段流水线:本地预处理脚本 → lobe-i18n LLM 翻译 → prettier 格式化 locales 产物。预处理入口 scripts/i18nWorkflow/index.ts 依次执行 genDiff()(DIFF ANALYSIS,对比当前 locale 与默认 locale 的差异,确定需要翻译的增量 Key)和 genDefaultLocale()(GENERATE DEFAULT LOCALE,把 packages/locales/src/default/ 的 TS 源同步为默认 locale 基准文件),同目录还有 flattenLocaleKeys.ts、protectedPatterns.ts、i18nConfig.ts 等配套模块,其中 i18nConfig.ts 负责加载根目录的 .i18nrc 配置。
五、翻译配置解析:.i18nrc.js 中的语言矩阵与 LLM 参数
翻译行为由 .i18nrc.js 定义,这是 @lobehub/i18n-cli 的入口配置,核心参数如下:
| 参数 | 取值 | 含义 |
|---|---|---|
entry / entryLocale |
locales/en-US / en-US |
翻译基准入口与基准语言 |
output |
locales |
生成产物输出目录 |
outputLocales |
ar、bg-BG、zh-CN、zh-TW、ru-RU、ja-JP、ko-KR、fr-FR、tr-TR、es-ES、pt-BR、de-DE、it-IT、nl-NL、pl-PL、vi-VN、fa-IR |
共 17 个目标语言,与仓库根 locales/ 下的目录一一对应 |
modelName |
gpt-4o |
翻译所用的 LLM 模型 |
temperature |
0 |
零温度采样,保证翻译输出稳定可复现 |
saveImmediately |
true |
每完成即落盘,避免长任务中断丢失进度 |
experimental.jsonMode |
true |
以 JSON 模式约束模型输出,防止格式污染 locale 文件 |
配置中还有一个独立的 markdown 段,负责文档与 README 的翻译(对应 docs:i18n 脚本):
entry覆盖./README.md与./docs/**/*.md、./docs/**/*.mdx,基准语言 en-US,目标语言仅zh-CN;reference注入 docs/glossary.mdx 作为术语表,并要求“保持 mdx 组件格式、输出不包裹代码块”,保证专有名词与组件标记在翻译中一致;exclude排除已有的README.zh-CN.md与*.zh-CN.mdx产物,防止自我翻译;outputExtensions自定义产物后缀:mdx 文件翻译为.{locale}.mdx(如start.zh-CN.mdx),普通 md 翻译为.{locale}.md——这正是 docs/changelog/ 中成对出现*.mdx/*.zh-CN.mdx的由来。
六、每日自动翻译工作流:auto-i18n.yml
.github/workflows/auto-i18n.yml 是整套体系的“兜底引擎”,其关键设定:
- 触发:
cron: '0 0 * * *'每日 0 点定时执行,另支持workflow_dispatch手动触发; - 执行:
bun run i18n,注入OPENAI_API_KEY与OPENAI_PROXY_URL两个 secrets,任务超时 30 分钟; - 产物:通过
peter-evans/create-pull-request@v7仅提交locales/**/*.json的变更,自动创建style/auto-i18n分支 PR,标题为🤖 style: update i18n,打上i18n/automated/style标签并在合并后删除分支; - 可追溯:PR 描述内嵌
i18n_update.log执行日志,便于审阅本次翻译覆盖了哪些 Key。
这也解释了 SKILL 文档中“Leave all other locales to the daily workflow”这句话的完整语义:开发者只需要维护默认 locale,其余 17 种语言的 JSON 由该工作流每日增量翻译并以独立 PR 合入,把翻译成本从“每次发版阻塞项”变成了“异步流水线”。
七、未使用 Key 的治理闭环
扁平 Key 带来的可扫描性还支撑了文案瘦身。package.json 提供两个配套命令:
i18n:unused:运行 scripts/i18nWorkflow/analyzeUnusedKeys.ts,扫描代码中实际t()调用与 locale 中已定义 Key 的差集,报告未被引用的废弃文案;i18n:unused-clean:运行 scripts/i18nWorkflow/cleanUnusedKeys.ts,按分析结果清理无引用 Key。
对一个 50+ 命名空间、每种语言 50+ 个 JSON 文件的仓库而言,这套“分析—清理”闭环能有效控制翻译体量(翻译费用与文件体积都与 Key 数量线性相关),与 protectedPatterns.ts 等防护配置共同避免误删动态拼接 Key。
八、实践要点总结
- 只写默认 locale:新文案一律加到
packages/locales/src/default/{namespace}.ts,新 namespace 必须同步登记到 packages/locales/src/default/index.ts 的resources; - 扁平点号 Key:遵循
{feature}.{context}.{action|status},插值用{{var}},子 Key 前缀冲突时给短 Key 补语义段; - 组件内用
useTranslation:单命名空间直接寻址,多命名空间用'common:save'前缀语法; - 翻译走流水线:日常开发只手工补
locales/zh-CN与locales/en-US两个预览文件;合入 main 后由每日auto-i18n.yml自动开翻译 PR;仅在紧急场景手动bun run i18n(需OPENAI_API_KEY,耗时较长); - 文档翻译独立成线:README 与 docs 通过
docs:i18n(lobe-i18n md)翻译,术语以 docs/glossary.mdx 为参照,产物带.zh-CN后缀与源文件成对存在; - 定期瘦身:用
i18n:unused分析、i18n:unused-clean清理废弃 Key,维持 17 种语言 × 50+ 命名空间的维护成本可控。
按以上规范操作,即可在 LobeHub 的多语言体系中完成从“写一条 Key”到“全语言自动上线”的完整闭环。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00