OpenCode 多语言翻译治理:Locale Glossary 目录规范与 translate:app 流水线详解
OpenCode 仓库中的 .opencode/glossary/ 目录定义了一套"按语言维护翻译术语与措辞偏好"的轻量治理机制。本篇基于该目录的 README 规范,结合 script/translate-app.ts 与 .opencode/command/translate.md 的真实实现,讲清 Locale Glossary 的文件命名规则、内容结构、标准模板、贡献规范,以及术语表如何被翻译流水线实际消费——读完你可以为自己的项目建立一套可被 Agent 直接使用的多语言术语治理体系。
1. 定位:局部术语表,补充全局翻译指南
.opencode/glossary/README.md 开宗明义:
- 该目录用于存放面向具体语言区域(locale)的翻译指引,是对全局翻译指南
.opencode/agent/translator.md的补充; - 全局术语表(
translator.md)仍然是共享"不可翻译"条目(命令、代码、路径、产品名等)的唯一事实来源(source of truth); - 各语言文件则沉淀社区在措辞与术语偏好上积累的经验(community learnings)。
文档同时说明了它引用的全局术语表位于 .opencode/agent/ 目录下;在当前仓库检出中,.opencode/agent/ 实际可见的是 triage.md 与 duplicate-pr.md 等 Agent 定义,而术语表的直接消费者是仓库中的翻译脚本与命令,后文第 5 节会用源码逐条印证。
这种"全局一份不可翻译清单 + 每语言一份偏好表"的分层设计,避免了把 60 多个语言的术语映射堆进同一个文件,也让每个语言的规则可以由熟悉该语言的社区成员独立演进。
2. 文件命名规范:一个 locale 一个文件
README 的 File Naming 章节给出了四条硬性约定,这些约定并非纸面文档,而是被 script/translate-app.ts 的 glossaryFile() 函数直接执行:
| 规则 | 说明 | 示例 |
|---|---|---|
| 一个语言区域一个文件 | 目录内不混放多种语言 | fr.md |
| 使用小写 locale slug,尽量与文档站的 locale 对齐 | 区分地区变体 | zh-cn.md、zh-tw.md |
| 只有语言级(无地区区分)的指引时,直接用语言代码 | 不需要地区后缀 | fr.md |
| 允许非 BCP47 的别名 slug 以保持仓库一致性 | 需在文件内说明 | br(巴西葡语,即 pt-BR) |
第 4 条是理解本目录的关键。script/translate-app.ts 中的映射逻辑精确对应了这些规则:
export function glossaryFile(locale: Locale) {
if (locale === "zh") return ".opencode/glossary/zh-cn.md"
if (locale === "zht") return ".opencode/glossary/zh-tw.md"
return `.opencode/glossary/${locale}.md`
}
即:简中 locale 代码 zh 实际读取 zh-cn.md,繁中 zht 读取 zh-tw.md,其余 locale(包括别名 br)一律按 ${locale}.md 定位。同文件中 L15-L77 的 languages 映射表列出了全部受支持语言,其中 "br": "Brazilian Portuguese" 正是 README 所说"别名 slug"的落地形态。
对照实际目录,.opencode/glossary/ 当前包含 16 个语言文件:ar、br、bs、da、de、es、fr、ja、ko、no、pl、ru、th、tr、zh-cn、zh-tw。
3. 一个 Locale 文件里应该写什么
README 的 What To Put In A Locale File 章节定义了五类内容,其中 Avoid 为可选项:
- Sources:催生该指引的 PR / issue / 讨论;
- Do Not Translate (Locale Additions):该语言特有的不可翻译词或大小写决策;
- Preferred Terms:反复出现的 UI/文档词汇及其推荐译法;
- Guidance:语气、风格与一致性说明;若该语言使用别名 slug,必须在 Guidance 中记录这个别名(例如正文可写
pt-BR,而配置/示例用br); - Avoid(可选):应避免的字面直译或措辞。
3.1 实例一:成熟语言 zh-cn.md
简体中文术语表展示了完整的成熟形态:
- Sources:
PR #13942(该 PR 的讨论直接催生了表内规则); - Do Not Translate (Locale Additions):
OpenCode(正文中保持大写;仅当opencode出现在命令、包名、路径或代码中时保留小写)、OpenCode Zen、OpenCode CLI、CLI/TUI/MCP/OAuth,以及首次引入MCP时优先给出英文全称Model Context Protocol; - Preferred Terms(PR 支撑、可演进):
| English | Preferred | Notes |
|---|---|---|
| prompt | 提示词 | flag/代码中保持 --prompt 不变 |
| session | 会话 | |
| provider | 提供商 | |
| share link / shared URL | 分享链接 | 面向用户的分享动作优先用 分享 |
| headless (server) | 无界面 | 文档措辞 |
| authentication | 认证 | auth/OAuth 语境优先 |
| cache | 缓存 | |
| keybind / shortcut | 快捷键 | 面向用户的文档措辞 |
| workflow | 工作流 | 例如 GitHub Actions workflow |
- Guidance:自然简洁优于逐字直译;语气直接且友好(PR #13942 持续朝这个方向修正措辞);命令、flag、代码、行内代码、URL、文件路径、模型 ID 等技术产物原样保留;枚举式字面量(如
default、json)保持英文;术语一旦选定,跨页面保持一致; - Avoid:正文指代产品名时避免用小写
opencode(应用OpenCode);避免在已有推荐译法的概念上混用多个译名。
3.2 实例二:别名语言 br.md
巴西葡语术语表是"别名 slug"规则的示范:仓库代码与配置中该语言的 locale 代码是 br,而标准 BCP47 写法是 pt-BR。该文件在 Preferred Terms 中明确记录了三条映射关系——正文语言名用 pt-BR、仓库 slug 用 br、浏览器 locale 检测时 pt / pt-br / pt-BR 一律归一到 br——并在 Guidance 与 Avoid 中反复强调:代码片段、路径、配置示例中不得把 br 改成 pt-br,也不得混用不同葡语变体。
3.3 实例三:起步阶段 fr.md
法语术语表展示了"还没有 PR 级术语修正"时的合法状态:其 Preferred Terms 一节直接写明"No PR-backed term mappings yet"(暂无 PR 支撑的术语映射),仅保留 Guidance 与 Avoid 两条通用指引。这正对应 README 贡献规范中"若无术语级修正,先用通用指引起步"的要求,说明术语表允许渐进积累,但每条规则最终都要有出处。
4. 标准模板
README 给出了新语言文件的完整模板(此处将模板示例中的外部 PR 链接省略为"对应 PR 链接"占位,实际填写时附上具体 PR):
# <locale> Glossary
## Sources
- PR #12345(附对应 PR 链接)
## Do Not Translate (Locale Additions)
- `OpenCode` (preserve casing)
## Preferred Terms
| English | Preferred | Notes |
| ------- | --------- | --------- |
| prompt | ... | preferred |
| session | ... | preferred |
## Guidance
- Prefer natural phrasing over literal translation
## Avoid
- Avoid ... when ...
结构上就是第 3 节五类内容的一一落地:Sources 必须非空且随规则同步更新;Preferred Terms 用三列表格(英文原词 / 推荐译法 / 备注)承载可演进的映射;Guidance 与 Avoid 承载风格与负面清单。
5. 入库标准:什么样的指引才值得写
README 给出三条筛选标准,用于控制术语表的信息质量:
- Repeated:该用法在多个文档/屏幕中反复出现,而非一次性偶发;
- Easy to apply consistently:规则能被一致地、机械地执行;
- Backed by a community contribution or review discussion:有社区贡献或评审讨论作为依据。
对应的 Contribution Notes 进一步规定:
- 可能演进的条目要标注为 "preferred"(推荐,而非强制);
- 示例保持简短;
- 每次新增规则必须同步更新
Sources一节; - 优先收录 PR 支撑的指引,而不是凭空发明的术语映射;没有术语级修正时,先写通用指引。
这四条实际上把术语表当作"活文档"管理:规则有出处、有状态(preferred/fixed)、可演进,与 zh-cn.md 中"These are preferred terms ... and may evolve"的声明相互印证。
6. 源码印证:glossary 如何被翻译流水线消费
README 只定义了"文件长什么样",而"文件怎么被用"要看 script/translate-app.ts 与 script/translate-app.md。这条流水线把英文字典视为只读事实来源,把各语言字典与英文对齐,术语表在其中是注入给翻译 Agent 的上下文。
6.1 翻译请求的组装
translate() 函数(script/translate-app.ts)对每个待翻译 locale 执行:
const glossary = glossaryFile(plan.locale)
const glossaryContent = (await Bun.file(path.join(root, glossary)).exists())
? await Bun.file(path.join(root, glossary)).text()
: undefined
const prompt = template.replaceAll("$1", plan.locale).replaceAll(
"$ARGUMENTS",
JSON.stringify({
locale: plan.locale,
language: plan.language,
glossary: glossaryContent ? { file: glossary, content: glossaryContent } : undefined,
domains: plan.domains.map((domain) => ({
source: domain.source,
target: domain.target,
...domain.drift, // missing / extra / placeholders
})),
}, null, 2),
)
要点有三:
- 术语表文件整体以
{ file, content }形式内嵌进翻译请求的 JSON;文件不存在时该字段直接省略,流水线可继续运行——这就是"每个 locale 一个文件、按需存在"命名规范的价值; - 请求同时携带三个
domains的漂移清单(missing / extra / placeholders)。每个 domain 的源与目标字典由 targetFiles() 确定:packages/app/src/i18n/<locale>.ts、packages/ui/src/i18n/<locale>.ts,desktop 原生语言还包含packages/desktop/src/renderer/i18n/<locale>.ts,源文件一律是对应的en.ts; - 模板文本来自 script/translate-app.md,其中明确要求 "Apply the locale glossary included in the request"(第 21 行),并要求对 session、prompt、agent、model、provider、fork、shell、terminal、workspace、worktree、context、permission、tool、server 等高频概念做一致的上下文化翻译,而不是逐词翻译。
文档站与 UI 文案的另一条翻译入口 .opencode/command/translate.md 也在 Requirements 中写明:"Also apply locale-specific guidance from .opencode/glossary/<locale>.md when available (for example, zh-cn.md)"(第 13 行)。两条入口共享同一套术语表。
6.2 权限收敛:术语表之外的护栏
translationConfig()(script/translate-app.ts)为翻译 Agent 生成的内联配置把权限压到最小:默认 deny,仅放开 read、glob、grep、webfetch、websearch,而 edit 只允许作用于本次请求列出的目标文件。这与 script/translate-app.md 中 "Edit only the target files listed in the request" 的文字约束形成双重保障——术语表提供"怎么译",权限配置保证"只能改该改的文件"。
6.3 漂移检测与验证
findDrift()(script/translate-app.ts)按 key 逐一对比英文源字典与目标字典,产出三类漂移:
missing:英文有而目标语言缺失的 key(含按 locale 复数类别展开的变体);extra:目标语言多出的 key;placeholders:同一 key 下{{token}}占位符集合不一致的条目(例如{{count}}丢失)。
bun run translate:app -- <locale|all> 支持 --dry-run(仅报告漂移)与 --check(存在漂移时以非零码退出,可接入 CI);翻译完成后还会用 worktreeSnapshot() 做前后快照比对,确认没有目标文件之外的任何改动被写入。此外 packages/app/AGENTS.md 对 Agent 补充了使用姿势:"A glossary hit is evidence, not permission to translate word-by-word"——命中术语表是证据,不是逐词翻译的许可,整句要在产品语境中翻译。
7. 实践要点小结
- 分层:共享的不可翻译清单放全局指南,语言特有的大小写决策、推荐译法、语气规范放
.opencode/glossary/<locale>.md,两者互补、职责不重叠; - 命名即接口:slug 规则被
glossaryFile()硬编码执行,新增语言文件前先看 script/translate-app.ts 的映射;别名 slug(如br)必须在文件 Guidance 中显式声明; - 结构固定:Sources / Do Not Translate / Preferred Terms / Guidance / Avoid 五段式模板保证任何语言的文件都可被流水线与读者一致地解读;
- 规则要可追溯:每条 Preferred Term 都标注 preferred(可演进)状态,每次加规则必更新 Sources,宁缺毋造;
- 与流水线闭环:术语表内容会被原样注入翻译请求,配合漂移检测(missing/extra/placeholders)与最小化编辑权限,构成"规范 → 上下文注入 → 自动验证"的完整治理回路。
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 StartedRust0624
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