给上游项目补一套简体中文翻译:从 45 个 po 到上游 PR
给一个从没做过简体中文的开源项目补翻译,看起来是「把英文换成中文」的体力活。实际做下来,难的是术语一致性、格式校验和 PR 的可审查性——764 条词条,翻错一条可能只是一个词,但术语不统一会让整个配置界面读起来像三个人分别翻的。
这篇以 Wayfire(基于 wlroots 的 Wayland 合成器)为例,记一遍完整流程。它原本只有罗马尼亚语一种翻译,45 个 .po、764 条词条(去重 721 条)。
一、先摸清规模与构建方式
动手前先回答三个问题:
- 词条总量与分布:
find . -name '*.po' | wc -l、msgattrib --translated或直接统计msgid。Wayfire 是 45 个文件、764 条,分散在 core 与每个插件里; - 翻译怎么被构建:看
locale/meson.build。多数项目会自动find所有语言目录,新增zh_CN不需要改构建脚本——这一步确认了能省掉一个 PR 改动; - 上游有没有术语表或风格指南:没有就自己定一份,写进 PR 描述里。
二、术语表要先定,而且要看代码语义
同一个英文词在不同上下文里的中文可能不同。Wayfire 里先定了几组:
| 原文 | 译法 | 说明 |
|---|---|---|
| view | 窗口 | 不是「视图」 |
| output | 输出 | 显示器/输出设备 |
| workspace | 工作区 | |
| activator | 激活器 | 热区/手势触发 |
Scale 插件 |
窗口概览 | 与 Zoom 区分 |
Zoom 插件 |
桌面缩放 | 直译会和 Scale 撞名 |
Kawase / XWayland / GTK Shell |
保留原文 | 专有名词 |
Scale 与 Zoom 是典型陷阱:两个插件都直译成「缩放」,配置界面里会出现两个同名条目,用户根本分不清。凡是「功能名」而不是「普通名词」的,要按实际行为命名。
三、生成 po 文件:格式比内容更容易出错
最省事的做法是从模板批量生成,但生成脚本很容易在注释、msgid、msgstr 之间插入空行。msgfmt 仍然能过,但 diff 会变得很难看,上游 review 时会先扣格式分。
几个硬性要求:
- 文件头不要写不实的生成器标注。模板里如果带
X-Generator: Poedit 3.7而实际不是 Poedit 生成的,删掉——这是对工具和审查者的误导; - 每个文件的
Language:、Plural-Forms:要正确; msgid一个字符都不能改,包括末尾空格与转义;- 按文件原顺序输出,别重新排序,否则 diff 全红。
生成完先做一次机械校验:
1 | find locale/zh_CN -name '*.po' -exec msgfmt -c -o /dev/null {} \; |
-c 会检查格式错误(占位符不匹配、msgstr 缺失、复数形式不对)。这一步过了,再谈翻译质量。
四、翻译阶段的三个判断
- 短词看上下文,不要按词典:
Open可能是「打开」也可能是「开放」,去.c/.cpp里看它出现在按钮还是状态里; - 占位符原样保留:
%s、%d、{0}的顺序和数量都不能动。msgfmt -c能抓出一部分,但顺序错位它不一定报; - 不要翻译配置键、路径、命令:这些是运行时匹配的字符串,翻了就失效。这个坑在别处已经踩过一次(见「汉化把运行时匹配串一起翻了」那类问题),这里的原则是:只翻给人看的文案。
五、提交 PR:只放翻译文件
上游 PR 的审查成本要尽量低:
- 一个 PR 只做一件事:45 个
.po、+3988 行,只包含翻译文件;顺手加的AGENTS.md、构建脚本改动全部不提交; - 分支名明确:
i18n/zh-cn; - PR 描述写清三件事:覆盖的语言、词条总数与完成率、术语表的几个关键决定(比如为什么
Scale不译成「缩放」); - 提交信息用英文:
locale: add Simplified Chinese translation; - 等 checks:如果仓库没有为该分支配置 CI,PR 页面会显示
no checks reported,这不是失败,但要在描述里说明本地已跑过msgfmt -c。
六、翻译之外:顺手把打包也做了
这个项目当时还没有 deb/rpm 包,翻译合进去也只是源码。所以同一个分支里另外加了一个 packages.yml:deb 与 rpm 两个 job,把目标发行版仓库里没有的 wlroots 0.20.2、wf-config 0.12.0、wf-utils 一起打进包。
打包细节(debian:testing 基线、brp-compress 与 man page、gh release upload 的目录问题)在「跨平台打包与 CI」那篇里展开,这里只记一条:翻译 PR 和打包 PR 要分开,否则审查者要在 4000 行翻译里找构建脚本。
总结
给上游补翻译,交付物不是「一份中文」,而是一套能被维护的本地化:
- 术语表先定,功能名按行为译,专有名词保留;
msgfmt -c机械校验必须过,格式问题比错译更影响 review;- 只翻给人看的文案,运行时键、路径、命令一律不动;
- PR 只放翻译文件,描述里写清术语决定;
- 翻译和打包分成两个 PR。
最后一句:词条数不是工作量,术语一致性才是。764 条翻完可能两天,但把「窗口/视图」「概览/缩放」这些词统一,决定了这套翻译能不能被上游长期维护。