首页
/ OpenCode 泰语(th)翻译词汇表:LLM 驱动国际化流水线中的术语治理规范

OpenCode 泰语(th)翻译词汇表:LLM 驱动国际化流水线中的术语治理规范

2026-09-05 21:08:54作者:贡沫苏Truman

本文以 OpenCode 仓库中的泰语 locale 词汇表 th.md 为主体,解读其中"不可翻译项、优先术语、风格指引"三类规则的具体含义,并结合仓库中的翻译脚本 translate-app.ts 与提示词模板 translate-app.md 说明这些规则如何被自动注入到 AI 翻译流水线中生效。读完后,你将理解 OpenCode 如何用一个轻量 Markdown 文件约束 LLM 翻译的一致性,以及如何在为其他 locale 贡献术语表时复用同一套机制。

一、词汇表在整个国际化体系中的定位

OpenCode 的产品界面(app、ui、desktop 三个包)通过 i18n 字典实现多语言:每个语言对应一个 dict 字典文件,如泰语的 th.ts,英文 en.ts 是唯一只读的事实来源。而 th.md 属于另一层体系——locale 词汇表(locale glossary),其定位在 glossary/README.md 中有明确说明:

  • 该目录存放"locale 级别的翻译指导",是对全局翻译规则的补充;
  • 全局不可翻译术语(命令、代码、路径、产品名等)以全局规则为准,locale 文件只记录社区沉淀出来的措辞与术语偏好
  • 每个 locale 一个文件,文件名用小写 slug,语言级指引用语言码(如 fr.md),地区变体对齐文档 locale 命名(如 zh-cn.mdzh-tw.md)。

翻译脚本中的 glossaryFile() 函数确认了这套命名映射的实现逻辑:

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`
}

也就是说,当流水线处理 th locale 时,它按约定直接定位到 .opencode/glossary/th.md 并将其全文读入——这就是词汇表与翻译流水线的绑定方式。

二、th 词汇表的内容逐节解读

2.1 Sources:规则出处溯源

词汇表开头列出了两条来源:

  • PR #10809:标准化了泰语在各 locale 语言列表中的写法;
  • PR #11496:确立"语言选择器中的语言名保持原生写法、不随当前 locale 翻译"的原则。

glossary/README.md 的贡献规范强调"每条新规则都要更新 Sources 段落,优先采用有 PR 支撑的指引,而非臆造的术语映射"。这种"规则必须可溯源到具体 PR/讨论"的设计,使词汇表更像一份可审计的术语决策日志,而不是随意堆砌的对照表。

2.2 Do Not Translate (Locale Additions):不可翻译项

这是泰语词汇表的核心清单,逐条含义如下:

条目 规则
OpenCode 正文中保留原始大小写;只有在命令、包名、路径或代码中才写成小写 opencode
OpenCode CLI 产品组件名,不翻译
CLITUIMCPOAuth 开发者社区通用缩写,保持英文
命令、flag、文件路径、代码字面量 一字不改地原样保留

前几条与全局规则(命令、代码、路径、产品名不翻译)有重叠,但后两条是泰语特有的补充:把 TUIMCPOAuth 明确列为泰语场景下的豁免项。这与 translate-app.md 提示词中"开发者术语优先使用目标语言开发者社区已认可的词,而非词典直译"的要求一脉相承。

2.3 Preferred Terms:优先术语表

英文 / 上下文 推荐写法 说明
语言列表中的"泰语"标签 ไทย PR #10809 已将其在各 locale 间统一
语言选择器中的语言名 原生名称(静态) PR #11496:EnglishDeutschไทย 等在各 locale 下保持一致

第二条规则有直接的字典级证据:英文源字典 en.ts"language.th": "ไทย",泰语字典 th.ts 中同样是 "language.th": "ไทย"——即"泰语"的显示名在所有 locale 下都静态显示为 ไทย,而不是在德语界面里显示成 "Thailändisch"。这正是"Preferred 且可能演进"(README 中要求把此类条目标注为可演进)的典型规则。

2.4 Guidance 与 Avoid:风格指引与反模式

  • Guidance:泰语追求自然表达而非逐词直译;按钮和标签保持简短清晰的语气;命令、flag、代码、URL、模型 ID、文件路径等技术工件一律原样保留;语言选择器中语言名保持原生/静态。
  • Avoid:不要在语言列表中按当前 locale 给语言名做不同翻译;除非产品标准变更,不要更改 ไทย 的显示形式。

这两节给 LLM 划定了"边界":不是禁止翻译,而是禁止两类最容易破坏一致性的行为——语言名单元化漂移,以及技术工件被"顺手翻译"。

三、词汇表如何被翻译流水线消费(源码级机制)

理解这份 Markdown 的价值,需要看它的消费方 script/translate-app.ts。整个流水线的工作方式如下:

  1. 漂移检测inspect() 对每个目标文件(packages/app/src/i18n/th.tspackages/ui/src/i18n/th.ts,以及 desktop 包中存在的泰语字典)逐一对比英文源字典,findDrift() 计算出三类差异:缺失 key(missing)、多余 key(extra)、占位符不匹配(placeholders)。占位符比较通过 tokens() 提取 {{token}} 并排序后比对,确保 {{count}} 等插值 token 与英文完全一致。
  2. 词汇表注入translate() 中读取词汇表并直接拼进发给模型的请求体:
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,
    })),
  }, null, 2),
)

词汇表以 { file, content } 结构进入 translate-app.md 模板中的 $ARGUMENTS 位置。提示词末尾明确要求"Apply the locale glossary included in the request"——即词汇表不是可选参考,而是被执行的约束。若某个 locale 没有词汇表文件,glossary 字段为 undefined,流水线仍能运行,说明词汇表是增量增强而非硬依赖。 3. 隔离执行。子进程以 --pure 模式运行 opencode run,通过环境变量 OPENCODE_CONFIG_CONTENT 注入一个专用 agent:read/glob/grep/webfetch/websearch 允许,edit 仅允许三个目标字典文件,其余权限全部 deny。这保证 LLM 只能修改本 locale 的字典,不能"顺手"改英文源或其他 locale。 4. 验证收口。翻译完成后,脚本重新执行 --check 漂移检测,并比对 git diff 工作区快照(unexpectedChanges()),确认没有目标文件之外的变更;同时通过 opencode export <sessionID> --sanitize 导出会话,校验 assistant 消息实际使用的模型与请求的 --model/--variant 一致。任何一项不满足即退出码非零。

因此,th.md 里的每一条规则——保留 OpenCode 大小写、ไทย 静态显示、语言名单元化不翻译——最终都会成为一次真实翻译会话中模型必须遵守的指令,并由后续的漂移检查兜底验证结果。

四、实操:查看、运行与贡献

4.1 查看泰语翻译现状

4.2 运行漂移检查

仓库根 package.json 注册了脚本 "translate:app": "bun run script/translate-app.ts",帮助文档给出的用法:

# 仅报告泰语字典与英文源的漂移(缺失/多余/占位符不匹配),不执行翻译
bun run translate:app -- th --dry-run

# 存在漂移时以非零退出码结束,适合放进 CI
bun run translate:app -- th --check

# 完整执行泰语翻译(会调用 opencode 并写入三个目标字典)
bun run translate:app -- th

--model(默认 opencode/gpt-5.5)与 --variant(默认 xhigh)可在执行前解析校验,translate-app.ts 中的 resolveModelVariant() 会调用 opencode models <provider> --verbose 确认该 variant 真实存在,避免请求到未配置的推理档位。

4.3 为泰语词汇表贡献新规则

按照 glossary/README.md 的模板与贡献规范,新增规则时应:

  1. 沿用 SourcesDo Not TranslatePreferred TermsGuidanceAvoid 的骨架;
  2. 规则要满足"跨多个界面/文档重复出现、易于一致执行、有社区贡献或评审讨论支撑"三条标准之一;
  3. 每新增一条规则就同步追加 Sources 段落;
  4. 可能演进的条目标注为 preferred,避免把临时偏好固化为硬规则。

五、小结

th.md 看似只有不到 40 行,实则是 OpenCode 国际化体系里"术语治理"的最小完整单元:它用 PR 溯源的规则表约束 LLM 翻译的一致性,再由 script/translate-app.ts 自动注入提示词、以最小权限执行、以漂移检查收口验证。对贡献者而言,它的价值在于给出了一个可复制的模式——任何 locale 都可以用同一套词汇表模板沉淀本语言的术语决策,从而让"机器翻译 + 自动校验"的流水线在数百个 key 的规模下依然保持术语稳定。

登录后查看全文
热门项目推荐
相关项目推荐