这个多语言项目最开始的目标其实很简单:
翻译 A Tour of Go。
最初需要解决的问题,也基本都围绕 Tour 展开。
例如,怎样让 AI 翻译完整页面,而不是一句一句割裂地处理;怎样保护 Go 代码、内联代码和链接;怎样避免代码注释在翻译过程中破坏程序结构;怎样在生成之后增加独立审核;怎样只修订真正有问题的 TranslationUnit,而不是整批重新翻译;以及最后怎样把审核通过的内容稳定地发布到网站。
围绕这些问题,项目逐渐形成了一套比较完整的流程。
从 Generation、机器校验、Independent Review,到 revision、re-QC、promotion、Surface Review,再到最终的 Production,A Tour of Go 的多语言翻译已经不再只是“把英文交给 AI,然后保存中文结果”。
这套体系在 Tour 阶段已经能够比较稳定地工作。
但项目继续往前以后,一个问题开始越来越明显:
如果以后想翻译的不只是 A Tour of Go 呢?
这也是 v2 真正开始的地方。
Tour 已经不再是项目的全部边界
Go 官方网站中,适合本地化的内容当然远远不只有 A Tour of Go。
除了 Tour,还有网站本身的 Site shell,也就是导航、页面入口和一些公共界面内容;还有 Learn;还有大量 Docs。
如果以后项目继续扩展,还可能增加更多 content package。
这时候,如果仍然把整个系统理解成:
“A Tour of Go 翻译项目,再额外支持几个页面。”
很多设计就会开始变得别扭。
Tour 有自己的内容结构。
Learn 和 Docs 大量使用 Markdown,其中还可能包含标题、列表、链接、inline code、代码块、教学代码注释以及各种必须保护的结构。
Site shell 又不是普通文章,它更接近网站级的界面内容。
再往上,还有 navigation、Homepage、local coverage、canonical、sitemap、404、Surface,以及最终真正呈现在用户面前的 Production。
所以后来我越来越确定:
这已经不是简单地“再增加几十个翻译页面”了。
如果继续围绕 Tour 的旧边界不断往外打补丁,后面的维护成本只会越来越高。
因此这次我决定做一次更完整的架构调整。
这就是现在所说的 v2。
v2 不是“第二版翻译”
这里的 v2,和“把原来的中文重新翻译一遍”没有什么关系。
它更像是一次项目边界的重新定义。
项目正在从:
A Tour of Go 多语言翻译
逐渐走向:
Go Learning & Documentation 多语言本地化。
Tour 仍然非常重要,但它不再是整个架构唯一需要围绕的内容类型。
新的架构需要同时考虑:
Site shell、Tour、Learn、Docs,以及以后可能出现的其他 content package。
真正的问题因此变成了:
这些内容之间,哪些东西应该彼此独立,哪些东西又应该共享?
这个问题后来影响了 v2 中很多重要设计。
不是给 Learn 和 Docs 再复制一套 Tour
最简单的实现方式,其实很好想到。
既然 Tour 已经有一套翻译流程,那么 Learn 再复制一套,Docs 再复制一套就好了。
短期来看,这样甚至可能是最快的。
但如果真的这样做,很快就会出现另外一批问题。
Tour 有一套 glossary。
Learn 有一套 glossary。
Docs 再来一套 glossary。
Tour 有自己的审核状态。
Learn 和 Docs 又建立另外的审核状态。
以后增加新的 content package,再复制一遍。
这样做的问题不在于“不能运行”,而在于同一种能力会不断分叉。
同一个 Go 术语,可能需要在不同 package 中分别决定一次。
同一种质量规则,可能存在几套略有不同的实现。
一种工作流改进,也需要在多个地方重复修改。
项目越做越大,重复的东西也越来越多。
所以 v2 最重要的方向并不是:
给 Learn / Docs 再造一套 Tour。
而是反过来重新思考:
Tour、Learn、Docs 本来就应该共享什么?
Locale 才应该是更稳定的边界
一个很明显的答案,是语言本身。
无论内容来自 Tour、Learn 还是 Docs,只要它们属于同一个 locale,就应该使用一致的语言标准。
例如简体中文中的同一个 Go 概念,不应该因为它出现在 Tour 中就采用一种译法,出现在 Docs 中又重新决定另外一种。
因此 v2 中一个很重要的变化,就是进一步把 glossary 提升到了 locale 级别。
一个 locale 只维护一份正式 glossary。
不同的 content package 可以不断扩大 terminology discovery 的范围,但最终的术语治理不应该随着 package 数量一起复制。
这件事情表面上只是“少维护几个文件”,实际上影响非常大。
因为当 glossary 成为整个 locale 的公共基础以后,另外一个问题马上就出现了:
如果术语表发生了变化,是不是所有已经完成的翻译都要重新做?
显然不应该。
如果只修改了一个只出现在少数页面中的术语,就没有理由让整个 locale 的所有 TranslationUnit 全部失效。
因此后来又进一步发展出了 semantic compatibility、affected scope,以及如何判断哪些已有内容可以继续复用的问题。
这部分本身就值得单独写一篇。
TranslationUnit 也需要重新理解
Learn 和 Docs 的加入,还带来了另外一个很实际的问题:
到底应该把什么当成一个正式翻译单位?
Markdown 非常容易拆。
标题可以单独拆出来。
一个段落可以是一条记录。
列表中的每一项也可以单独处理。
甚至代码里的某一条教学注释,也可以单独成为一条字符串。
从程序处理的角度来看,拆得越细,似乎越容易。
每条内容都短,重试方便,差异也容易比较。
但真正进入语言质量以后,问题就没有这么简单了。
如果一个完整页面被拆成几十个彼此独立的小片段,Generation 能看到的上下文会减少,Reviewer 能看到的上下文也会减少。
前后指代可能断掉。
相邻段落的表达风格可能不一致。
有些句子单独看没有问题,放回整页之后却显得非常生硬。
甚至一些原本需要根据中文自然语序调整的位置,因为切分太细,反而无法合理处理。
因此 v2 后来逐渐明确了一条原则:
机器内部可以拆分,但正式语言治理不能跟着内部结构一起被拆碎。
一个实际存在的 Page,仍然应该是一个正式 TranslationUnit。
内部当然可以存在 slot、protected token、link binding,以及各种 parser 为了保护和重建内容而使用的结构。
但这些属于实现细节。
它们不是新的正式翻译单位。
这个区别后来直接影响了 Generation、validation、QC 和 revision 的设计。
v2 开始处理的,已经不只是翻译问题
当这些东西逐渐组合到一起以后,我发现 v2 实际上已经变成了一个更完整的内容系统。
一个英文页面进入系统之后,不再只是:
English
↓
AI Translation
↓
Chinese而更接近:
Canonical source
↓
TranslationUnit
↓
Generation
↓
Machine validation
↓
Candidate Snapshot
↓
Independent QC
↓
Exact revision
↓
re-QC
↓
Package
↓
Integrated Surface
↓
Preview
↓
Production这条链路越长,状态之间的关系就越重要。
例如:
术语发生变化以后,哪些 TranslationUnit 真的受到了影响?
某个页面没有变化,之前已经完成的审核结果能不能继续复用?
某个 package 的内容发生变化,之前的 Surface Review 还是否有效?
一个英文页面目前没有本地翻译,网站应该链接本地 URL,还是继续链接 go.dev?
如果一个本地 route 根本不存在,应该自动跳回英文,还是应该返回真正的 404?
这些问题已经很难再归类为:
“这一句话应该怎么翻?”
它们更多是在解决:
一个长期运行的本地化系统,应该怎样管理内容、状态、依赖和可信结果。
历史也开始变成架构的一部分
随着系统不断发展,历史成果越来越多。
以前已经完成的翻译、QC、revision 和 promotion,显然不能因为 v2 出现就全部丢掉。
如果 source 没变、相关术语没变、内容也没有受到其他变化影响,那么已经高质量完成的翻译应该尽量继续复用。
这也是保留历史最大的价值之一:
避免把已经做对的事情重新做一遍。
但这次 v2 的开发过程也让我逐渐发现,历史本身同样需要边界。
如果为了继续当前的工作,需要不断向前追溯 Snapshot、predecessor、旧 promotion 和更早的 evidence,甚至为了恢复一个旧状态又必须继续恢复它之前的状态,那么历史就可能从“帮助复用成果”,慢慢变成“拖住当前工作的前置条件”。
这也是这次 v2 中比较重要的一次架构调整。
历史应该保留。
已有成果也应该尽可能复用。
但是系统真正的目标,始终不是无限还原过去。
这些问题后面我也准备分别写,因为它们实际上是两个不同的主题:
一个是为什么历史值得保留;
另一个则是为什么历史又不能无限参与当前工作流。
根本目标其实没有变
v2 做到现在,系统中出现了越来越多的概念。
Glossary。
TranslationUnit。
Snapshot。
Quality Check。
Package。
Closure。
Surface。
Identity。
各种 evidence。
如果只看这些东西,很容易产生一种错觉:
好像项目的目标已经变成了建立一套越来越复杂的流程。
但其实并不是。
这些东西都只是手段。
项目真正的目标一直很简单:
尽可能快速,同时尽可能高质量地完成 Go 学习与文档内容的多语言翻译。
需要 glossary,是为了减少术语漂移。
需要机器校验,是为了让能够自动发现的问题尽量不要进入人工审核。
需要 Independent Reviewer,是为了降低 Generation 自己审核自己的风险。
需要历史,是为了复用已经完成的高质量成果,而不是重复劳动。
需要 Surface Review,是因为单个页面全部正确,并不自动代表整个网站组合起来也一定正确。
如果某一种工程机制开始让这个根本目标变得越来越难实现,那么真正应该重新检查的,可能不是翻译,而是架构本身。
这也是 v2 开发过程中我越来越明显的一种感受。
为什么还没有正式上线,就开始写这个系列
我原本的计划,是等简体中文 v2 正式上线以后,再集中整理这一轮开发过程。
但真正做到后面,我觉得这样并不太合适。
因为这次 v2 中出现的很多问题,本身就已经足够单独写成一篇文章。
如果最后全部塞进一篇“v2 上线总结”,最终很可能只是:
术语表讲几段。
TranslationUnit 讲几段。
parser 讲几段。
性能问题讲几段。
历史恢复讲几段。
Surface 再讲几段。
每个问题都提到了,但每个问题都没有真正讲清楚。
所以我决定不再等到最后一次性整理。
已经相对收敛的问题,可以先逐篇记录下来。
至于最终上线到底用了多少时间,最后阶段又发现了哪些新的问题,则留到 Production 真正完成以后再做完整复盘。
因此这篇文章并不是:
“v2 已经完成以后,我来总结一下。”
它只是先回答整个系列最基础的一个问题:
为什么这个项目需要 v2?
答案现在已经比较清楚了。
因为项目需要解决的,已经不再只是 A Tour of Go 的翻译。
它正在逐渐变成一套能够同时承载 Site shell、Tour、Learn、Docs,以及未来更多内容的多语言本地化系统。
而接下来真正值得记录的,也不只是最终增加了多少个中文页面。
更值得记录的是:
为什么一些设计最后保留了下来,又为什么另外一些设计做到一半以后必须重新调整。
这可能也是这次 v2 最有价值的部分。
Go 学习与文档多语言本地化项目
本系列完整记录 Go 学习与文档多语言本地化项目从 A Tour of Go 起步,逐步扩展到站点首页、项目说明页、学习内容、文档以及未来内容包的实际开发过程,包括架构设计、统一术语治理、整页翻译、结构保护、自动校验、独立质量审核、生产发布与长期维护。
项目源码:
✅ GitHub:shuijingwan/go-tour-i18n
语言版本:
当前跨项目目标语言池共包含 66 个语言版本。Go 项目本身目前提供 65 个社区 Production 语言版本,下面每一门 Go 语言版本都直接链接到其当前公开站点。语言列表沿用项目首页现有的展示顺序。
英语(美国)仅作为跨项目目标语言纳入列表,并不是单独的 Go Production 语言版本。当前 Go 的英文源内容仍为官方 generic English,因此英语(美国)链接到 Go 官方站点,而不是不存在的本地社区部署。
- 阿姆哈拉语
- 阿拉伯语
- 孟加拉语
- 葡萄牙语(巴西)
- 保加利亚语
- 加泰罗尼亚语
- 克罗地亚语
- 捷克语
- 丹麦语
- 荷兰语
- 英语(美国)(Go 官方英文站点)
- 英语(澳大利亚)
- 英语(加拿大)
- 英语(印度)
- 英语(新加坡)
- 英语(南非)
- 英语(英国)
- 爱沙尼亚语
- 菲律宾语
- 芬兰语
- 法语(法国)
- 法语(加拿大)
- 德语(德国)
- 德语(奥地利)
- 德语(瑞士)
- 希腊语
- 古吉拉特语
- 希伯来语
- 印地语
- 匈牙利语
- 印度尼西亚语
- 意大利语
- 日语
- 卡纳达语
- 哈萨克语
- 韩语
- 西班牙语(拉丁美洲)
- 拉脱维亚语
- 立陶宛语
- 马来语
- 马拉雅拉姆语
- 马拉地语
- 书面挪威语(Bokmål)
- 波斯语
- 波兰语
- 葡萄牙语(葡萄牙)
- 旁遮普语(果鲁穆奇文,印度)
- 罗马尼亚语
- 俄语
- 塞尔维亚语(西里尔文)
- 简体中文(中国大陆)
- 简体中文(新加坡)
- 斯洛伐克语
- 斯洛文尼亚语
- 西班牙语(西班牙)
- 斯瓦希里语(坦桑尼亚)
- 瑞典语
- 泰米尔语
- 泰卢固语
- 泰语
- 繁体中文(台湾)
- 繁体中文(香港)
- 土耳其语
- 乌克兰语
- 乌尔都语
- 越南语
项目正在持续扩展新的 Go 学习与文档内容,并长期维护各语言版本的术语一致性、翻译质量、独立审核、生产发布与后续更新。
本项目属于非官方社区多语言本地化项目,与 Go 官方无隶属、授权或背书关系。
