没有不值得去解决的问题,也没有不值得去学习的技术!

A Tour of Go 中文翻译完成 7 个代表页校准:最后 3 页又发现了哪些真实问题

图 3:methods/24 中文页面,静态代码、Bounds 行内代码和链接内的 image.Rectangle 均正确渲染

作者:

在

,

Go 学习与文档多语言本地化项目

图3:访问过去的 Go Tour 简体中文站 tour.go-zh.org 时,当前已经无法正常建立连接。

(1) 从「A Tour of Go 中文版」这个搜索词开始:我决定做一个持续维护的 Go Tour 中文版

本地运行的 A Tour of Go「Methods continued」课程页面,左侧为课程说明,右侧为 Go 代码编辑器及运行结果。

(2) A Tour of Go 中文版项目设计冻结:从 101 页到 103 页,从 Gin 转向 Cobra CLI

A Tour of Go 中文版开发实战:英文基线、在线运行与 101 页上游同步体系

(3) A Tour of Go 中文版开发实战:英文基线、在线运行与 101 页上游同步体系

go-tour-i18n 项目完成首个简体中文课程页面 welcome/1 的整页翻译、结构校验和本地预览。

(4) A Tour of Go 多语言翻译项目实录:完成首个 zh-CN 页面翻译闭环

图 1:DeepSeek 官方更新日志显示,本次只更新 DeepSeek-V4-Flash,DeepSeek-V4-Pro API 与 APP、Web 模型均未更新

(5) A Tour of Go 中文翻译项目进展:完成前 8 页、修复 present 语法,并暂缓 DeepSeek 对比

图 1:generics/1 简体中文页面本地预览

(6) 一个页面重试五次:使用 GLM-5.2 翻译 A Tour of Go 时遇到的 Token 与 Present 结构问题

图 1:methods/16 简体中文页面浏览器预览

(7) A Tour of Go 中文翻译实录:如何只翻译教学代码注释,而不破坏 Go 代码

图 2:A Tour of Go methods/20「练习:错误」中文候选页面最终渲染效果

(8) A Tour of Go 多语言翻译:当正确的中文语序被受保护标记顺序校验误判

图 3:methods/24 中文页面,静态代码、Bounds 行内代码和链接内的 image.Rectangle 均正确渲染

(9) A Tour of Go 中文翻译完成 7 个代表页校准:最后 3 页又发现了哪些真实问题

图 2:首批 10 个普通页面经过试跑与流程校准后全部进入 ready

(10) A Tour of Go 多语言翻译项目:首批 10 个普通页面试跑,从 2 个 blocked 到全部 ready

图 2:flowcontrol/6 最终中文页面,return 与 v 为适应自然中文语序发生整体换位

(11) A Tour of Go 中文翻译第二批实跑:从 Inline Code 顺序误判到历史响应重新验证

图 1:flowcontrol/6 首次原始输入实验直接通过统一自动校验

(12) A Tour of Go 多语言翻译项目:从 swap 问题重新审视 Token 保护,原始输入与最小保护的一次真实实验

图 7:moretypes/1 最终中文页面预览。左侧课程正文、静态代码块、行内代码和教学注释均正常渲染,右侧官方 Go 示例继续保持原样。

(13) A Tour of Go 多语言翻译实战:第三批 10 页全部 Ready,继续校准 Protected Token 的结构角色

图 4:上游源码确认共有 103 个课程页面,zh-CN 最终达到 ready=103、pending=0、blocked=0

(14) A Tour of Go 多语言翻译项目:zh-CN 103 个课程页面全部 ready,课程正文翻译阶段完成

图 4:GitHub 与 ChatGPT 已成功连接

(15) ChatGPT 连接 GitHub 实测:让 AI 直接读取 go-tour-i18n 仓库参与译文审核

图 3:中文 Go 术语校准完成后,将确定的译法写入 zh-CN glossary

(16) 为什么 channel 最终选择“通道”:A Tour of Go 中文术语统一的一次实践

图 1:技术含义基本正确,但“返回一个返回……”已经明显影响阅读,因此仍被列入 C 类修订

(17) 103 页逐页审核后,只返修 16 页:A Tour of Go 中文正文发布前质量审计

图 2:中文课程页面以及已经完成本地化的编辑器控制区

(18) A Tour of Go 多语言翻译项目:公共 UI 本地化完成,从课程译文走向完整中文界面

图 2:完整 zh-CN 正式投影成功生成,103 个课程页面被重新组装为 7 个 .article

(19) 从 103/103 ready 到完整站点验收:A Tour of Go 中文版补齐正式投影与课程元数据本地化

图 3:从 production bundle 独立启动的 A Tour of Go 简体中文页面,课程正文、公共 UI 和官方 Go 示例均已进入最终发布形态。

(20) A Tour of Go 多语言翻译项目:103 页全部完成后,我终于生成了可独立部署的 zh-CN Production Bundle

图 1:A Tour of Go 简体中文版正式生产页面,远程运行已经成功输出“Hello, 世界”。

(21) A Tour of Go 多语言翻译项目:zh-CN 正式上线,从生产发布到 go.dev Playground 的完整部署记录

图 1:新生产域名 go-dev.shuijingwanwq.com 已正常访问,Go 示例远程运行成功

(22) A Tour of Go 多语言翻译项目:从 go-tour 到 go-dev,完成 EdgeOne、Nginx 与 HTTPS 生产域名迁移

图 1:A Tour of Go 多语言翻译项目正式生产首页

(23) A Tour of Go 多语言翻译项目正式上线:从项目首页、公共 Footer 到生产发布元数据的完整收尾

图 3:GA4 g/collect 请求返回 HTTP 204,并携带当前课程页面地址,确认 Google Analytics 已产生真实事件上报

(24) A Tour of Go 多语言翻译项目:接入 Google Analytics 与百度统计,从 systemd 注入到 EdgeOne 与真实上报验证

图 1:生产环境 robots.txt 与 sitemap.xml 已正确对外提供,Sitemap 共包含 104 个规范 URL。

(25) A Tour of Go 中文站上线后:补齐 robots.txt、Sitemap,并完成五大搜索引擎提交

图 4:发布生产并刷新 EdgeOne 缓存后,再次通过真实手机访问,顶栏项目名称已经完整保持在一行,最终移动端验收通过。

(26) A Tour of Go 多语言翻译项目:修复手机端首页顶栏标题换行,并完成真机验证

图 3:生产自动部署脚本第一次真实运行时,systemd 已经显示 active,但首次 localhost 探测仍然得到 HTTP 000;随后连续 3 次同时满足 active + HTTP 200 后,脚本才判定部署成功,并继续完成公网 HTTP 200 验收。这次真实运行验证了连续应用层健康检查的必要性。

(27) A Tour of Go 多语言翻译项目:从一次 203/EXEC 故障到生产自动部署脚本落地

图 1:阿里云生产环境访问 go.dev Playground 时出现 TLS 握手超时

(28) A Tour of Go 多语言翻译项目:为 Playground 搭建独立的 ZgoCloud 执行代理

图 3:清除 /tour/script.js 缓存后,Run 已直接请求 ZgoCloud /compile 并返回 HTTP 200

(29) A Tour of Go 多语言翻译项目:将生产 Run / Format 切换到 ZgoCloud 执行节点

【图 1:微信中运行 Go 示例时出现 Error communicating with remote server.】

(30) A Tour of Go 中文版手机端运行与格式化偶发失败排查:从间歇性报错到补强 Nginx 可观测性

【图 4:向 golang-dev 公开邮件列表发送 Playground 使用告知邮件并投递成功】

(31) A Tour of Go 多语言项目:为 Playground 代理增加唯一 User-Agent,并主动告知 Go 官方

【图 3:百度剩余 9 个核心 URL 提交成功,remain 归零】

(32) A Tour of Go 搜索引擎收录实测:从 Google 自然索引到百度主动提交与 Bing IndexNow

【图 1:当前正式中文 methods/24 页面,右侧示例代码运行成功】

(33) A Tour of Go 中文翻译完成后,我为什么重新评估 minimal-protect 翻译模式

【图 3:5 个页面 Request SHA256 完全一致,但 Response SHA256 全部不同】

(34) A Tour of Go 翻译实验:更多原始上下文为什么没有更好?从 157 个保护标记到 30 次重复盲评

图 3:3 个代表页 × 4 个评审模型,共 12 次匿名评审的完整排名与第一名票数。

(35) A Tour of Go 翻译质量再评估:minimal-protect 未达预期后,我开始比较 ChatGPT、Codex 与 GLM-5.2

图 2:GitHub 中的 chatgpt-zh-CN-008 重译批次。一个 Batch 同时保存 inputs、raw-responses、candidates、validation 和 retry 记录,GitHub 成为 ChatGPT 与本地翻译流水线之间的数据交接层。

(36) 没有 OpenAI API,我如何用 ChatGPT + GitHub 完成 A Tour of Go 103 页全量重译

图 1:103 个正式课程页面完成最终语义质量审核,结果为 A=103、B/C/D=0,同时不存在缺失、重复或额外页面。A/B/C/D 是本轮项目内部语义质量分级,并不是自动结构 validator 的结果。

(37) 103 页翻完还不能发布:A Tour of Go ChatGPT 译文的语义审核与 Canonical Promotion

图 3:7 个 article endpoint 的 production origin 与 EdgeOne 公网响应全部 exact match,同时新的 ChatGPT 译文标记存在,旧版译文标记已经消失。

(38) 103/103 与 7/7 Exact Match:A Tour of Go ChatGPT 新译文的最终线上验收

【图 2:upstream source preview】

(39) A Tour of Go 多语言翻译项目首次实现 upstream 同步机制:从一次性翻译到长期维护

图 2:A/B/C/D 质量评级规则,展示正式质量 rubric 与 Promotion gate。

(40) A Tour of Go 多语言翻译项目引入 Translation Quality Review:从自动验证到 AI 翻译质量控制

图 4:翻译后 Playground Example,展示中文注释与保持不变的 Go 代码结构。

(41) A Tour of Go 多语言翻译项目实现 Playground Example 本地化:从代码注释翻译到完整学习体验

图 5:公网页面验证广告脚本输出

(42) A Tour of Go 多语言翻译项目接入广告系统:从 AdSense 专用配置到通用 HTML 注入架构

图 3:百度统计单页应用设置

(43) go-dev 单页网站接入统计与 Google AdSense Auto Ads 验证记录

图 1:GitHub 仓库中的多语言翻译项目结构

(44) A Tour of Go 多语言翻译项目:选择日语作为第二语言并启动翻译验证

图 5:模型身份描述不一致

(45) A Tour of Go 多语言翻译项目中的 AI 协作异常排查:一次长期工程会话失效分析

【图 1:ChatGPT GitHub 写入流程调整说明截图】

(46) go-tour-i18n 翻译流程调整:从 ChatGPT GitHub 写入到本地 artifact 导入

图 4 展示了本次异常状态。

(47) go-tour-i18n 翻译自动化流程复盘:已验证的 ChatGPT 翻译能力在新任务中的稳定性问题

【图 6:全部评审结束以后才读取 secret key,完成最终揭盲】

(48) A Tour of Go 翻译质量再评估:Codex High 已接近 ChatGPT High,我决定调整默认翻译引擎

图 4:ja-JP 生产课程页实际运行 Go 示例

(49) A Tour of Go 日语版正式上线:第二门语言 ja-JP 完成生产发布

图 1:ja-JP 上线以后,先提交“新增语言标准化流程”

(50) A Tour of Go 多语言扩展复盘:为第三门语言建立标准化流程

图 1:课程正文结束以后,页面左侧仍然存在大块视觉空白,但 AdSense 并没有在这里插入展示广告。

(51) A Tour of Go 明明有大片空白,为什么 AdSense 就是不显示展示广告?

图 2:golang/website 当前的 _content/tour/。课程内容、静态资源和模板都在这个上游目录中持续维护。

(52) 为了 AdSense,要不要放弃 SPA?A Tour of Go 页面架构的一次取舍

图 4:最终的手动课程广告真实展示在课程内容区域内,而不是 footer 之后。

(53) 保留 SPA 以后,广告应该放在哪里?从 AdSense 预览到方案 B

图 1:Google Search Console 中,多个不同的 A Tour of Go 课程 URL 被判断为“重复网页,用户未选定规范网页”。

(54) SPA 的 SEO 老问题:为什么最后还是给 103 个 A Tour of Go 课程页生成了 Prerender HTML

图 2:方案 B 生产环境中,源码已经正常,但课程主体高度异常缩短,footer 提前进入第一屏。

(55) 从源码空白到 AdSense 高度污染:A Tour of Go 方案 B 的生产收尾

图 1:A Tour of Go 德语版 de-DE 已正式运行在生产环境

(56) A Tour of Go de-DE 上线复盘:第三门语言用了约 16 小时,下一门如何压到 8 小时?

图 1:fr-FR 首次 production 验收完成后,我没有立即开始 ko-KR,而是先连续完成新增语言与首次生产流程的优化

(57) 法语版上线后,我没有马上开始韩语:A Tour of Go 新增语言流程的一轮完善与简化

图 1:根据 ko-KR 期间 76 次 Git 提交估算实际工作时间

(58) 原本预计 6 小时,最后用了约 16~18 小时:A Tour of Go 韩语版上线复盘

图 2:英文 source 与当时发生 validation failure 的 ko-KR candidate 对比

(59) Validator 报错,到底该改译文还是改规则?一次 A Tour of Go 韩语翻译实战

图 2:法语 A Tour of Go 仓库目前已经归档,页面仍保留 553 Commits 和 61 Contributors 的历史

(60) 从法语 553 次提交到韩语两代离线:A Tour of Go 社区翻译为什么难以长期维护

【图 4:es-ES 首次 Production 收口后连续完成的流程优化 commit】

(61) 从 es-ES 首次上线复盘:我把 A Tour of Go 新增语言的 Production 流程又收敛了一轮

图 1:旧公网验收链路连续出现 curl 28 超时,最终导致 public-machine 阶段失败

(62) A Tour of Go Production 公网验收踩坑:从跨境 SOCKS 链路改为 zgocloud direct

图 1:两次 Production Machine Acceptance 都已经通过,但 Headless Chrome 分别在 / 和 /tour/ 判定页面没有完成渲染

(63) 页面明明能打开,为什么 Headless Chrome 仍然判定 Production 失败?

图 3:Bing 从 Google Search Console 中识别到新的 it-IT 站点,并同时发现已有的 1 个 sitemap

(64) GSC → Bing Webmaster Tools:多语言站点如何减少重复验证

图 3:英文站 3 小时内出现 565 个 Cloudflare 来源 URL

(65) IndexNow 实战:手工提交长期不显示,Cloudflare Crawler Hints 却很快出现在 Bing Webmaster Tools

【图 1:A Tour of Go 项目首页目前的语言版本列表】

(66) 从 nl-NL 到 tr-TR:A Tour of Go 连续上线三门语言后,我又优化了哪些流程

【图 4:Go local 页面中已经出现 French、German、Korean、Simplified Chinese】

(67) 从邮件无人回复到进入 Go 官方 Go local:我的 4 个 A Tour of Go 翻译站终于被收录

图8:最终只保留一把启用的新 API Key

(68) 腾讯云 EdgeOne API 自动化:从 CAM 子用户到最小权限 API Key 的完整配置

【图 7:Production Release Batch 最终汇总】

(69) 从同步 Go 官方上游到一个命令发布 10 个语言站:A Tour of Go Production 流程的再次收敛

【图 3:Cloudflare Smart Tiered Cache 已启用】

(70) Cloudflare 缓存 HIT 很快,MISS 却不稳定:回源阿里云杭州的一次真实优化

【图 3:简体中文站 Support 页面】

(71) 广告之外,社区项目如何长期活下去?我给 A Tour of Go 多语言项目加了 Support

图5:评论成功发布

(72) 从 Go Weekly 到 Reddit、DEV 和 Go Forum:第一次系统推广 A Tour of Go 多语言项目

【图 4:RTL 桌面课程布局修复后的效果】

(73) 第一次把 A Tour of Go 做成 RTL:阿拉伯语版本上线,以及我踩过的几个坑

多语言项目应该先做哪些语言?我的 66 个语言版本商业优先级排序

(74) 多语言项目应该先做哪些语言?我的 66 个语言版本商业优先级排序

当术语一致性遇到性能瓶颈:Go 多语言翻译项目的一次架构取舍

(75) 当术语一致性遇到性能瓶颈:Go 多语言翻译项目的一次架构取舍

从 A Tour of Go 走向 Go Learning & Documentation:为什么这个多语言项目需要 v2

(76) 从 A Tour of Go 走向 Go Learning & Documentation:为什么这个多语言项目需要 v2

Markdown 明明可以拆成很多段,为什么 v2 仍然坚持一个 Page 就是一个 TranslationUnit

(77) Markdown 明明可以拆成很多段,为什么 v2 仍然坚持一个 Page 就是一个 TranslationUnit

Tour、Learn、Docs 为什么不应该各维护一份术语表:v2 的统一 Glossary 设计

(78) Tour、Learn、Docs 为什么不应该各维护一份术语表:v2 的统一 Glossary 设计

v2 术语表变更后的页面影响范围判断流程:区分 Compatible 与 Affected,只处理真正受影响的页面。

(79) 术语表改了,为什么不应该让所有页面重新翻译?v2 的影响范围判断

CLI 性能优化示意图:通过 Prepare Once、Reuse Many Times,将执行时间从 6m54.554s 降至 10.335s,约提升 40.1 倍。

(80) 从 6 分 54 秒到 10.3 秒:Go 多语言项目一次 CLI 性能优化实战

Markdown Page 经过 Parse / Protect、Generation 和 Reconstruct / Validate 的流程示意图,强调保护 inline code、链接、代码等机器语义,同时允许译文按照自然语言调整语序。

(81) Markdown 不是纯文本:Learn / Docs 为什么需要新的 parser 与结构保护

历史为什么值得保留:复用已经完成的翻译成果,而不是重新做一遍

(82) 历史为什么值得保留:复用已经完成的翻译成果,而不是重新做一遍

历史状态通过 Trusted Checkpoint 建立可信断点,旧记录继续保留用于审计和诊断,后续工作流从当前状态继续向前,不再要求无限重建过去。

(83) 历史应该被保留,而不是被反复重建:v2 为什么最终需要一个“断点”

v2 依赖与失效传播流程图:从内容变化开始,评估依赖关系和真实影响,将结果区分为“仍然有效”和“需要失效”,只让真正受影响的状态重新进入流程。

(84) 一次内容变化,到底应该让哪些状态失效?v2 的依赖与失效传播设计

v2 本地内容覆盖判断流程图:官方英文页面先检查是否已有正式本地覆盖,有覆盖时使用本地 URL,没有覆盖时直接链接 go.dev,并保持本地路径真实 404。

(85) 有英文页面,不代表一定应该有本地页面:v2 如何处理本地内容覆盖、canonical 与真实 404

v2 代码注释完整性审计流程图:从源页面建立代码块清单,分类教学注释、机器语义和无法判断的内容,再与当前译文精确对应,确认 missing、extra 和 protected mutation 均为 0。

(86) 代码块里的注释为什么不能只靠肉眼检查?v2 如何统计并验证代码注释翻译完整性

结构化语义输入扩展示意图:同一份 books.yaml 原始文件保持不变,旧 parser 识别 10 个可本地化单元,当前 parser 识别 12 个,并新增 PDF 和 GitHub,确认旧单元无删除无修改后重新进入 Generation。

(87) 原始文件一个字没变,为什么还要重新翻译?从 books.yaml 10→12 看语义输入扩展

v2 Activation 流程图:Surface PASS 后先执行只读 activation-preflight 获取 prior_sha256,activation-apply 时通过 CAS 再次比较当前状态,只有 current 等于 prior 才提交 result_sha256,否则停止并重新 preflight。

(88) 审核都通过了,为什么上线前还要再检查一次?v2 的 Activation、prior SHA 与 CAS 设计

v2 分层验证流程图:TranslationUnit、Package Closure 和 Integrated Surface 均通过后进入 Activation,再由 Preview 检查 LoadContent、Compose、Resolver 和 Renderer 的真实运行链;如果实际使用错误 renderer,即使前置内容全部通过,Preview 仍然失败。

(89) Surface 已经 PASS,为什么 Preview 还是会失败?从一次 wrong renderer 看分层验证的价值

更快不一定更好:为什么我主动撤销了一次已经明显变快的性能优化

(90) 更快不一定更好:为什么我主动撤销了一次已经明显变快的性能优化

TranslationUnit 同类问题完整性示意图:左侧 Reviewer 只列出 3 个 examples,Generation 只修这 3 处后仍留下 5 个同类问题,re-QC 再次判 B;右侧 Reviewer 明确 defect category 和 bounded scope,Generation 执行 same-class complete sweep,最终同类残留为 0 并进入 re-QC A。

(91) 为什么修完 Reviewer 指出的所有例子,下一轮还是会失败?从 B→revision→B 看同类问题完整性

immutable source 与 replacement successor 示意图:左侧直接把旧 canonical source A 覆盖成 source B,会使旧 Generation、Review 和 Closure evidence 失去准确对应;右侧保留 source A 作为 immutable predecessor,为新正文建立 source B successor,并重新进入 corpus、glossary review、Generation、QC、closure、Surface 和 Activation 生命周期。

(92) 页面明明是我自己的,为什么不能直接重写?从 /translation/ 改版看 immutable source 与 replacement successor

protected representation 修订能力示意图:左侧 http.Client 被正确保护为 token;中间普通自然语言 Documentation 被错误保护为 opaque token,导致合法 revision 被阻塞;右侧保留旧 representation,通过 representation successor 建立新的可编辑表示,再继续 Generation 和独立 re-QC。

(93) 保护机制也会保护错东西:为什么一个 Documentation 能阻塞整页修订?

一个候选快照原本只应包含 1 个首页翻译单元,却因内容包范围未显式绑定而错误纳入 122 个翻译单元;通过 --content-package site-v2-shell 明确内容包后恢复到正确范围。

(94) 一个候选快照为什么突然多出 122 个单元?从隐式范围到显式内容包契约

Shell 自动化中,当前性检查命令失败并打印 RESULT=FAILED,但由于顶层子 Shell 中错误使用 return,后续命令仍继续执行,最终又打印出错误的 RESULT=PASS。

(95) 命令明明失败了,为什么最后还是 PASS?一次 Shell 自动化的 fail-closed 教训

【图8:Google AI 概览——引用网站的课程目录页】

(96) 同一个 Go 语言之旅网站,Bing、Google 和百度的搜索表现差距有多大?

多个正式命令原本分别重复构建当前内容成员、历史审核链、回执、SHA 和身份标识等可信环境;优化后改为先建立一次已验证的执行环境,再由 current-check、result-pack、import 等连续命令安全复用。

(97) 一个命令快了还不够:为什么我的性能优化开始转向跨命令环境复用

learn-docs-v1 原本以 49 个页面完成了翻译、审核和最终确认,后来发现还缺少 /doc/ 与 /doc/install 两个页面,导致内容包必须从 49 Page 迁移到 51 Page。图片对比了“后期补齐造成迁移成本”和“在 Generation 前先完成成员完整性审计”两种方式。

(98) 只是多了 2 个页面,为什么却触发了一次 49→51 的迁移?

【图2:维护者在 GitHub Issue #1 中回复,说明 math.pi 是官方课程有意设计的教学示例】

(99) 开源项目收到第一个 Issue:为什么我最终选择不修改代码?

一个翻译项目,为什么最后花了大部分时间证明基础设施?

(100) 一个翻译项目,为什么最后花了大部分时间证明基础设施?

上一篇文章结束时,我已经把代表页校准阶段接下来的计划确定了下来。

当时已经完成 4 个代表页:

  1. generics/1
  2. flowcontrol/8
  3. methods/16
  4. methods/20

并且明确选定最后 3 个代表页:

  • concurrency/7
  • concurrency/11
  • methods/24

计划也已经很清楚:

如果这 3 页也稳定通过,总代表页将达到 7 页。

然后就结束逐页校准阶段,进入:

10 个普通 pending 页面自动试跑。

所以这一次并不是重新选择代表页,也不是继续无限增加测试样本。

目标从一开始就已经确定:

把上一篇留下的最后 3 个代表页真正跑完。

原本我以为,经过前 4 个代表页不断修正以后,最后 3 页可能更多只是验证已有机制。

实际结果却再次说明,真实页面往往比人为设计的测试更容易暴露边界问题。

concurrency/7、concurrency/11、methods/24 不但没有简单地“一次翻译通过”,反而又陆续发现了:

  • 非尾部指令位置校验缺口;
  • standalone 条件源码投影范围过窄;
  • 普通英语动词 Go 被误当成 Go 语言名称保护;
  • 链接显示文本中的行内代码没有受到完整保护;
  • 中文全角标点与行内代码之间仍可能缺少 legacy present 所需的结构性空格。

这些问题全部解决以后,原定的 7 个代表页终于真正完成。

这篇文章就接着上一篇的计划,记录最后 3 个代表页是怎样一步一步跑完的。


一、前 4 页完成后,为什么还坚持把最后 3 页做完

做到前 4 个代表页以后,整个翻译流程其实已经比较稳定。

当时已经真实覆盖了很多关键结构,包括:

  • 泛型和较复杂的技术说明;
  • 普通行内代码和旧式程序字体片段;
  • 普通链接;
  • 受保护内容按照自然中文语序重新排列;
  • 静态预格式化代码;
  • 可翻译的教学代码注释及其中的标识符;
  • 强调与字体样式片段;
  • 练习页面;
  • .play;
  • Section 拓扑;
  • 尾部指令。

而且此前还刚刚解决了一个非常重要的问题:

受保护标记的全局顺序,并不是可靠的多语言结构不变量。

也就是说,中文可以合理改变受保护内容的出现顺序,只要真正的代码、链接、指令和 present 结构没有遭到破坏。

到了这里,如果只是为了“多翻译几页”,确实已经可以开始批量处理。

但上一篇已经确定,最后还要用 3 个不同类型的页面补齐真实覆盖。

现在回头看,这个决定很值得。

因为接下来发现的问题,大多数都不是靠普通单元测试很容易提前想到的。


二、concurrency/7:.image 内容没变,位置却可能悄悄跑掉

第 5 个代表页是:

Plaintext
concurrency/7

对应课程标题:

Plaintext
Exercise: Equivalent Binary Trees

它之所以被选中,是因为页面中包含:

Plaintext
.image /tour/static/img/tree.png

这是当前正式课程页面中非常少见的 .image。

而且它不是放在页面最后,而是夹在两段正文之间:

Plaintext
正文 A

.image /tour/static/img/tree.png

正文 B

开始翻译之前,我先让 Codex 做了只读分析。

结果发现,当时的系统虽然能够严格检查:

  • .image 是否丢失;
  • 图片路径是否变化;
  • 指令数量是否变化;
  • 指令内容是否被修改;
  • 指令之间的顺序是否改变。

但还有一个漏洞:

如果模型完整保留 .image /tour/static/img/tree.png,只是把它从正文中间移动到了页面开头或者页面末尾,现有校验可能仍然通过。

原因在于,此前已经对尾部指令建立了位置约束,但 .image 在这一页属于非尾部指令。

如果整个 Section 里只有这一条指令,那么它即使移动位置,指令数量、内容和指令之间的顺序都没有变化。

于是第 5 个代表页首先发现了:

同一个 Section 内,非尾部指令的结构位置还没有真正受到保护。


三、增加 directiveLayout:保护结构关系,而不是锁死中文段落

这个问题不能简单通过记录 .image 的绝对元素编号解决。

因为项目一直坚持:

以完整课程页面为单位翻译,而不是要求中英文逐段一一对应。

英文可能是两段,中文翻译以后合理合并成一段;反过来也可能发生。

如果要求:

Plaintext
第 3 个 present 元素必须永远还是第 3 个

就很容易重新退回段落级结构绑定。

最终采用的办法是为含指令的 Section 建立 directiveLayout,也就是指令结构布局。

例如一个页面可以抽象成:

Plaintext
正文区域
→ 指令
→ 正文区域
→ 预格式化代码
→ 正文区域

连续的普通自然语言文本会折叠成一个正文区域,而:

  • 预格式化代码;
  • 列表;
  • 嵌套 Section;
  • .play;
  • .image;
  • 其他指令

则继续作为稳定的结构节点存在。

这样:

Plaintext
正文
→ .image
→ 正文

就不能被随意变成:

Plaintext
.image
→ 正文

或者:

Plaintext
正文
→ .image

与此同时,普通中文段落仍然可以合理拆分、合并和调整措辞。

修复以后,concurrency/7 第一次真实 -dev 翻译就直接通过。

最终中文标题为:

Plaintext
练习:等价二叉树

其中 .image 保持在原来的正文混排位置,页面中的 JavaScript 链接目标:

Plaintext
javascript:click('.next-page')

也完整保留。

这一页最终提交为:

Plaintext
b74b3b36c513b516938d0fe4ea3e09b766aed54d
feat: 完成 concurrency/7 并增强非尾部 directive 位置校验
图 1:concurrency/7 中文页面,.image 正确保持在前后正文之间
图 1:concurrency/7 中文页面,.image 正确保持在前后正文之间

四、concurrency/11:真正的问题首先出在翻译源

第 6 个代表页:

Plaintext
concurrency/11

对应标题:

Plaintext
Where to Go from here...

上一篇已经预期这一页主要用于验证:

  • 长篇、多段正文;
  • 大量链接目标;
  • 跨段链接;
  • slides 强制术语;
  • 没有代码和指令时的长文本稳定性。

结果真正开始之前,却先发现了一个更基础的问题。

固定 upstream 中,这一页包含:

Plaintext
#appengine: You can get started by
#appengine: [[/doc/install/][installing Go]].

#appengine: Once you have Go installed, the
The
[[/doc/][Go Documentation]] is a great place to
#appengine: continue.
start.

其中 #appengine: 行并不是当前 standalone Tour 实际显示的正文。

standalone 页面真正需要的是:

Plaintext
The
[[/doc/][Go Documentation]] is a great place to
start.

项目此前其实已经实现过条件源码投影。

问题在于:

当时这套处理只覆盖了 welcome.article。

其他 .article 中如果同样存在 #appengine:,原始条件内容仍然可能进入翻译目录。

而校验器本来就有一道严格防线:

standalone 源码中只要还存在 #appengine:,候选译文就必须拒绝。

因此,在这种情况下即使 GLM-5.2 翻译得再正确,也不可能通过校验。


五、不是放宽校验器,而是修正 standalone 源码投影

这个问题最终没有通过删除:

Plaintext
standalone source contains #appengine content

这条校验解决。

相反,这条检查继续完整保留。

因为真正的问题不是校验器太严格,而是:

进入翻译流程的 standalone 源码本身就不应该包含这些条件行。

于是原先只覆盖 welcome.article 的 standalone 条件源码投影被泛化到了其他 Tour .article。

固定 upstream 中除了 welcome.article,还发现两个页面受影响:

Plaintext
flowcontrol/10
concurrency/11

两页当时都还是 pending,因此只需要安全更新对应的源码哈希。

这里还专门限制了源码迁移条件:

只有旧源码含 #appengine:,并且新源码恰好等于按照规则删除这些条件行后的结果,才允许识别为安全迁移。

普通 upstream 内容变化仍然不会被自动放过。

这样既修正了 standalone 翻译源,也没有放松原本的源码锁。


六、concurrency/11 连续两次失败,却发现是我们保护错了

源码投影修复以后,终于可以开始真实翻译。

投影后的页面共有:

Plaintext
15 个受保护链接目标
12 个必须保留的 Go
总计 27 个受保护标记

第一次:

Plaintext
attempt-001

API 正常成功,GLM-5.2 也返回了完整页面。

但校验失败:

Plaintext
protected token count = 26, want 27
token 1 occurrence count = 0, want 1

丢失的是标题:

Plaintext
Where to Go from here...

中的 Go。

模型把标题翻译成:

Plaintext
从这里去往何处...

第二次:

Plaintext
attempt-002

结果几乎完全一样。

仍然是:

Plaintext
26 / 27

仍然只缺标题里的那个 Go。

两次模型都认为这里应该翻译成“接下来往哪里走”这一类普通中文含义。

如果停在这里,很容易得出一个结论:GLM-5.2 连续两次违反了受保护标记必须完整保留的规则。

但继续分析以后,结论发生了变化。


七、Where to Go from here... 中的 Go,未必是 Go 语言

项目当时会保护所有独立的大写:

Plaintext
Go

原因很合理。

A Tour of Go 中绝大部分 Go 都明确表示 Go 语言,例如:

Plaintext
Go has...
Go's...
in Go
Go Documentation
Go Blog
A Tour of Go

所以裸 Go 默认需要保护。

但是:

Plaintext
Where to Go from here...

不一样。

这里的 Go 大写,很可能只是因为它处于英文标题中。

从英语语义上看,它就是非常自然的:接下来该去哪里?

我当时还用 Google 翻译简单对照了一下,得到的也是:接下来该去哪里……

随后又检查了固定 upstream 中大约 66 个独立大写 Go。

绝大多数确实明确表示 Go 语言。

真正不是明确语言名称的只有极少数,例如:

Plaintext
Where to Go from here...
Go local
Go offline (optional)

其中:

Plaintext
Where to Go from here...

作为普通英语动词的语义最明确。

这说明问题并不是:

模型不愿意保留 Go。

而更可能是:

我们的词面保护规则,把标题大小写造成的大写普通动词 Go 错误识别成了 Go 语言名称。


八、不取消 Go 保护,只放行高置信度的普通英语动词

解决方案没有改成:

Plaintext
所有 Go 都不保护

这样会让大量真正的 Go 语言名称失去硬保护。

也没有针对:

Plaintext
concurrency/11

或者完整标题写特殊规则。

最终采用了一条非常保守的上下文判断:

裸 Go 默认继续保护;只有处于高置信度的 where + to + Go 疑问不定式结构时,才不生成受保护标记。

因此:

Plaintext
Where to Go from here...

中的 Go 不再保护。

而:

Plaintext
Go has...
Go's...
in Go
install Go
Go Documentation
A Tour of Go

仍然受到保护。

甚至:

Plaintext
migrate to Go from another language

也不能因为出现 to Go from 就被简单放行。

这里的 Go 仍然可能明确表示 Go 语言。

至于:

Plaintext
Go local
Go offline

目前继续采用保守策略,没有为了这一个问题试图一次解决所有英语词义消歧。


九、第 3 次遇到网络问题,第 4 次终于成功

修正 Go 的误保护以后,concurrency/11 的受保护标记数量从:

Plaintext
27

减少为:

Plaintext
26

少掉的唯一一个,就是标题中错误保护的 Go。

接下来新的真实翻译尝试本应验证这次修复。

不过:

Plaintext
attempt-003

遇到了 DNS/网络沙箱错误,GLM-5.2 实际上没有收到请求。

这一份记录仍然被保留下来。

因为当前代表页校准一直使用开发模式 -dev。

开发模式本来就允许针对同一个页面持续调试,不受未来正式运行“三次有限重试”的限制。

网络恢复以后继续:

Plaintext
attempt-004

这一次顺利通过。

26 个受保护标记全部完整。

15 个链接目标全部保留。

3 个 slides 链接显示文本也按照当前强制术语翻译为:

Plaintext
页面

最终标题:

Plaintext
接下来去哪……

没有再为了错误保留一个 Go 而制造生硬中文。

这一页最终提交为:

Plaintext
652839a0e5c14488b1391a61303dad03e8260668
feat: 完成 concurrency/11 并修复条件源码投影与 Go 误保护
图 2:concurrency/11 最终中文页面,“Where to Go from here...”自然翻译为“接下来去哪……”
图 2:concurrency/11 最终中文页面,“Where to Go from here…”自然翻译为“接下来去哪……”

这次经历也说明了一点:

受保护标记失败,不一定意味着模型错了,也可能意味着我们保护了错误的东西。


十、最后一个代表页 methods/24,遇到了链接里的行内代码

上一篇已经把最后一个代表页定为:

Plaintext
methods/24

主要目的是验证 API 说明型页面、较长静态接口代码、多个 API 链接、强调文本和尾部 .play。

实际分析时,又发现了一个此前没有真正覆盖到的组合:

Plaintext
[[/pkg/image/#Rectangle][`image.Rectangle`]]

这是一个链接。

但它的显示文本不是普通自然语言,而是行内代码:

Plaintext
`image.Rectangle`

此前项目已经能够保护:

  • 普通链接目标;
  • 普通正文中的行内代码。

但这里刚好是:

链接显示文本里面又嵌套了一段行内代码。

原来的 presentInlineCodes 会有意跳过链接内部的程序字体片段。

所以:

Plaintext
image.Rectangle

不会成为行内代码受保护标记。

与此同时,校验器虽然能够知道:

这里仍然存在一个程序字体片段。

却没有校验这个程序字体片段里面具体还是不是:

Plaintext
image.Rectangle

理论上,如果模型把它改成:

Plaintext
somethingElse

只要反引号结构还在,就可能漏过自动校验。


十一、链接目标和链接内行内代码分别保护

这次没有简单把整个链接显示文本锁死。

因为链接显示文本完全可能同时包含:

  • 可以自由翻译的自然语言;
  • 必须保持不变的技术代码。

最终增加了专门处理链接显示文本内部程序字体片段的逻辑。

例如:

Plaintext
[[/pkg/image/#Rectangle][`image.Rectangle`]]

现在会分别保护:

Plaintext
链接目标

和:

Plaintext
image.Rectangle

概念上相当于:

Plaintext
[[⟪链接目标标记⟫][⟪行内代码标记⟫]]

恢复后仍然得到:

Plaintext
[[/pkg/image/#Rectangle][`image.Rectangle`]]

校验器也不再只检查“这里有没有一个程序字体片段”。

而是会检查:

这个具体链接内部的程序字体内容是否仍然保持正确。

因此:

Plaintext
[[/pkg/image/#Rectangle][`image.Rectangle`]]

如果变成:

Plaintext
[[/pkg/image/#Rectangle][`somethingElse`]]

就必须失败。

同时,同一个链接标签如果存在多个行内代码,它们仍然允许根据目标语言语序合理调整。

没有重新引入“整个页面的行内代码必须维持英文原始顺序”的限制。


十二、第一次 15 个受保护标记全部正确,页面却还是失败了

修复完成以后,运行:

Plaintext
attempt-001

API 成功。

这一页共有 15 个受保护标记:

Plaintext
4 个链接目标
1 个尾部指令
1 个静态预格式化代码块
9 个行内代码

15 个全部完整。

刚增加保护的:

Plaintext
image.Rectangle

也正确保留在原链接中。

但是最终页面仍然失败:

Plaintext
font span count mismatch: expected 10, actual 9

也就是:

源页面应该有 10 个字体样式片段,恢复后的候选页面却只有 9 个。

最初一度怀疑,是不是静态代码块和后面的:

Plaintext
*Note*

之间缺少了必要空行。

如果当时直接按照这个判断修改预格式化代码逻辑,很可能就会修错地方。


十三、本地回放证明:静态代码块其实没有问题

于是没有马上重新调用 GLM-5.2,而是直接使用已经保存的:

Plaintext
attempt-001

原始模型响应进行本地回放。

结果发现,静态代码块边界其实已经正确恢复:

Plaintext
	type Image interface {
		ColorModel() color.Model
		Bounds() Rectangle
		At(x, y int) color.Color
	}

*注意*:

也就是说:

静态预格式化代码的受保护内容本来就已经包含了结束代码块所需的空白。

问题根本不在这一层。

进一步逐项检查字体样式片段以后,真正缺失的是:

Plaintext
Bounds

十四、: 后面的 Bounds 看起来没问题,present 却不认识

模型生成的结构类似:

Plaintext
*注意*:⟪BOUNDS_TOKEN⟫ 方法

恢复以后视觉上是:

Plaintext
*注意*:`Bounds` 方法

对于正常 Markdown 阅读来说,这看起来完全没有问题。

但 legacy present 并没有把这里的:

Plaintext
`Bounds`

识别为独立的程序字体片段。

原因最终定位到:

Bounds 紧跟全角中文冒号 :,而 legacy present 在这种情况下仍然需要 ASCII 空格作为结构分隔。

这个问题其实与前面 generics/1 已经遇到过的行内代码边界问题属于同一类。

中文自然写作时,我们很容易写:

Plaintext
注意:`Bounds`

但是 legacy present 并不是现代 Markdown 解析器。

对某些组合,它仍然依赖:

Plaintext
注意: `Bounds`

中的那个 ASCII 空格。


十五、这个空格不是排版习惯,而是 present 结构

最终没有增加“所有中文标点后面都加空格”的排版规则。

而是继续扩展已有的行内代码边界归一化。

新的处理仍然只作用于普通正文中的受保护行内代码。

当行内代码前面的相邻字符:

  • 不是空白;
  • 也不是 ASCII 标点;

并且 legacy present 确实需要结构边界时,就补一个 ASCII 空格。

因此:

Plaintext
*注意*:`Bounds` 方法

在实际 present 源码中需要恢复成:

Plaintext
*注意*: `Bounds` 方法

类似的中文全角标点包括:

Plaintext
:
,
。
(

但并不是简单机械地在所有标点前后添加空格。

例如行内代码后面的中文标点,如果 present 已经能够稳定解析,就不会为了“格式统一”再额外加空格。

这里的原则很明确:

这些 ASCII 空格不是中文排版风格,而是 legacy present 所需的结构分隔符。

这一点也意味着,后续人工润色时不能只因为:

“中文冒号后面通常不应该有空格”

就把它删除。


十六、第一次失败的原始模型输出,修复程序以后直接通过

这个问题最有价值的一步,是再次利用了已有失败记录。

没有立即运行 attempt-002。

而是先拿:

Plaintext
attempt-001

的原始模型输出重新执行恢复和校验。

修复前:

Plaintext
font span = 9

修复后:

Plaintext
font span = 10

Bounds 被重新正确识别成程序字体片段。

同时:

Plaintext
[[/pkg/image/#Rectangle][`image.Rectangle`]]

仍然保持在原来的链接中。

静态 Go 代码逐字保持。

尾部:

Plaintext
.play methods/images.go

也没有任何变化。

然后,对第一次已经失败的模型输出重新执行完整候选译文校验:

通过。

这与上一篇 methods/20 的经历非常相似。

不是重新翻译以后碰巧通过。

而是:

同一份原始模型输出,在修正本地保护、恢复或校验逻辑以后重新通过。

这对判断真正根因非常有帮助。


十七、attempt-002 真实翻译最终通过

本地回放验证以后,再运行:

Plaintext
attempt-002

这一次完整成功。

页面中的 9 个行内代码全部正确恢复,包括:

Plaintext
Image
Bounds
Rectangle
image.Rectangle
image
color.Color
color.Model
color.RGBA
color.RGBAModel

最终中文页面为:

Plaintext
* 图片

[[/pkg/image/#Image][image 包]]定义了 `Image` 接口:

	package image

	type Image interface {
		ColorModel() color.Model
		Bounds() Rectangle
		At(x, y int) color.Color
	}

*注意*: `Bounds` 方法的 `Rectangle` 返回值实际上是
[[/pkg/image/#Rectangle][`image.Rectangle`]],因为该声明位于 `image` 包内。

(详见 [[/pkg/image/#Image][文档]]。)

`color.Color` 和 `color.Model` 类型也是接口,不过我们将使用预定义的实现 `color.RGBA` 和 `color.RGBAModel`,因此这里暂不考虑这一点。这些接口和类型由 [[/pkg/image/color/][image/color 包]]定义。

.play methods/images.go

最终提交:

Plaintext
db62b6331019cc7aad0d08c977e79d55343f9d21
feat: 完成 methods/24 并增强链接内代码与行内边界校验
图 3:methods/24 中文页面,静态代码、Bounds 行内代码和链接内的 image.Rectangle 均正确渲染
图 3:methods/24 中文页面,静态代码、Bounds 行内代码和链接内的 image.Rectangle 均正确渲染

十八、上一篇计划中的 7 个代表页,现在终于全部完成

到这里,上一篇文章结尾确定的计划已经真正执行完毕。

7 个代表页全部完成:

Plaintext
generics/1
flowcontrol/8
methods/16
methods/20
concurrency/7
concurrency/11
methods/24

前 4 页建立了基本的整页翻译、结构保护和校验能力。

最后 3 页又继续补出了几个不同方向的问题。

concurrency/7 证明:

指令不仅要保证内容不变,还必须保持合理的结构位置。

concurrency/11 证明:

翻译前首先要保证 standalone 源码本身就是正确的发布内容。

同时也证明:

不能因为单词写成 Go,就无条件认定它一定表示 Go 语言。

methods/24 证明:

链接内部仍然可能嵌套需要独立保护的技术代码。

还再次确认:

中文全角标点与 legacy present 行内代码之间的结构边界,需要由本地程序可靠恢复。

这些问题如果留到几十页、上百页批量翻译以后才出现,排查成本会明显更高。


十九、最后 3 页再次证明:失败不能先怪模型

最后 3 个代表页让我更加确定了一件事:

模型输出没有通过校验,并不等于模型一定翻译错了。

concurrency/11 连续两次缺少 Go 受保护标记。

表面上看:

GLM-5.2 不遵守硬约束。

真正分析以后却发现:

我们保护了一个普通英语动词。

methods/24 第一次 15 个受保护标记全部完整,但结构校验还是失败。

表面上很容易认为:

模型把代码块或者格式搞坏了。

真正本地回放以后发现:

模型输出本身可以成立,是本地的 legacy present 行内边界归一化仍少覆盖了一种中文标点组合。

所以现在我越来越倾向于在失败以后先问:

这到底是模型翻译问题,还是翻译系统自己的问题?

可能出问题的层很多:

Plaintext
upstream 源码
→ standalone 源码投影
→ 受保护内容识别
→ 模型整页翻译
→ 受保护内容恢复
→ present 解析
→ 结构校验
→ 页面验证

只有确定问题真正发生在哪一层,才应该修改对应机制。


二十、保存失败响应,本地回放越来越重要

上一篇处理 methods/20 时,我已经体会到保存原始失败响应的价值。

这一次 methods/24 又再次证明了这一点。

现在比较理想的排查方式已经逐渐固定成:

Plaintext
真实整页翻译
→ 自动校验失败
→ 保留原始响应
→ 本地回放
→ 定位最小差异
→ 修改本地通用机制
→ 用同一份响应重新校验
→ 再决定是否需要重新调用模型

这种方式有几个明显好处。

第一,可以节省 GLM-5.2 Tokens。

第二,可以分清:

模型是否真的需要重新翻译。

第三,如果修复以后同一份原始响应就能够通过,那么对根因的证明也更加有说服力。

因为这说明:

译文没有变化,变化的只是我们对于“什么才算结构安全”的判断或恢复能力。

对于以后扩展到其他语言,这一点尤其重要。


二十一、代表页校准阶段现在可以结束了

最后一个代表页完成以后,项目再次执行了完整验证:

Plaintext
go test ./internal/i18n
go test ./...

全部通过。

课程目录校验:

Plaintext
catalog OK: 103 published pages, 2 conditional source records

简体中文状态校验:

Plaintext
status OK: 103 pages for zh-CN

最后一个代表页提交:

Plaintext
db62b6331019cc7aad0d08c977e79d55343f9d21
feat: 完成 methods/24 并增强链接内代码与行内边界校验

提交并推送以后:

Plaintext
git status --short

再次恢复为空。

至此,原先计划中的 7 个代表页已经全部完成。

我认为现在没有必要继续为了追求覆盖率,再人为寻找第 8、第 9、第 10 个复杂代表页。

继续这样做,收益会开始下降。

更重要的是进入下一阶段,让已经经过真实校准的系统面对普通页面。


二十二、下一步:10 个普通 pending 页面自动试跑

这正好承接上一篇文章已经确定的下一阶段。

当时的计划是:

如果最后 3 个代表页也稳定通过,总代表页达到 7 页,就结束逐页校准,进入 10 个普通 pending 页面自动试跑。

现在这个前提已经满足。

所以接下来不再刻意寻找:

  • 特殊 .image;
  • 特殊链接组合;
  • 特殊代码结构;
  • 特殊条件源码。

而是从剩余 pending 页面中挑选 10 个相对普通的课程页面。

这一批真正要验证的问题已经不同了。

代表页阶段是在问:

系统有没有明显的结构盲区?

接下来 10 页普通试跑要问的是:

经过这些校准以后,系统面对普通 A Tour of Go 页面时,能不能连续稳定地完成整页翻译和自动校验?

大致流程将是:

Plaintext
10 个普通 pending 页面
→ GLM-5.2 完整页面翻译
→ 自动恢复受保护内容
→ present 解析
→ 结构与术语校验
→ ready / pending / blocked
→ 汇总第一批普通页面实际结果

如果这 10 页也能够比较稳定地通过,就可以进一步降低逐页人工观察的必要性,进入剩余页面的批量翻译阶段。


结语

上一篇结束时,我写下的下一步是:

完成最后 3 个代表页。

现在这个目标终于完成了。

但真正得到的并不只是:

又多了 3 个中文页面。

concurrency/7、concurrency/11 和 methods/24 分别帮助这个项目发现了结构位置、条件源码、词义保护、链接内代码和中文行内边界等问题。

其中几次失败尤其有代表性。

有的问题表面上像模型不听话,最终发现是保护规则错了。

有的问题表面上像模型破坏了格式,最后发现是本地 present 恢复逻辑还缺一个边界。

这让我更加确定,A Tour of Go 多语言翻译项目真正需要建立的,并不是一套:

“让 AI 尽量少犯错,然后失败就重新翻译”

的流程。

而是一套能够明确区分:

哪些内容允许自然翻译,哪些内容必须严格保护,哪些变化属于不同语言的合理表达,哪些变化才真正破坏代码、链接、指令和 present 结构

的自动化体系。

7 个代表页已经把这套体系推到了一个新的阶段。

接下来,就不再继续围绕少数特殊页面校准。

而是让它真正面对第一批普通课程页面:

10 个普通 pending 页面自动试跑。

如果这一批能够稳定运行,那么这个项目也就真正开始从:

翻译流程校准

进入:

规模化生成简体中文 A Tour of Go 内容

的阶段。

A Tour of Go 多语言翻译:当正确的中文语序被受保护标记顺序校验误判 A Tour of Go 多语言翻译项目:首批 10 个普通页面试跑,从 2 个 blocked 到全部 ready

Go 学习与文档多语言本地化项目

本系列完整记录 Go 学习与文档多语言本地化项目从 A Tour of Go 起步,逐步扩展到站点首页、项目说明页、学习内容、文档以及未来内容包的实际开发过程,包括架构设计、统一术语治理、整页翻译、结构保护、自动校验、独立质量审核、生产发布与长期维护。

项目源码:
✅ GitHub:shuijingwan/go-tour-i18n

语言版本:

当前跨项目目标语言池共包含 66 个语言版本。Go 项目本身目前提供 65 个社区 Production 语言版本,下面每一门 Go 语言版本都直接链接到其当前公开站点。语言列表沿用项目首页现有的展示顺序。

英语(美国)仅作为跨项目目标语言纳入列表,并不是单独的 Go Production 语言版本。当前 Go 的英文源内容仍为官方 generic English,因此英语(美国)链接到 Go 官方站点,而不是不存在的本地社区部署。

  1. 阿姆哈拉语
  2. 阿拉伯语
  3. 孟加拉语
  4. 葡萄牙语(巴西)
  5. 保加利亚语
  6. 加泰罗尼亚语
  7. 克罗地亚语
  8. 捷克语
  9. 丹麦语
  10. 荷兰语
  11. 英语(美国)(Go 官方英文站点)
  12. 英语(澳大利亚)
  13. 英语(加拿大)
  14. 英语(印度)
  15. 英语(新加坡)
  16. 英语(南非)
  17. 英语(英国)
  18. 爱沙尼亚语
  19. 菲律宾语
  20. 芬兰语
  21. 法语(法国)
  22. 法语(加拿大)
  23. 德语(德国)
  24. 德语(奥地利)
  25. 德语(瑞士)
  26. 希腊语
  27. 古吉拉特语
  28. 希伯来语
  29. 印地语
  30. 匈牙利语
  31. 印度尼西亚语
  32. 意大利语
  33. 日语
  34. 卡纳达语
  35. 哈萨克语
  36. 韩语
  37. 西班牙语(拉丁美洲)
  38. 拉脱维亚语
  39. 立陶宛语
  40. 马来语
  41. 马拉雅拉姆语
  42. 马拉地语
  43. 书面挪威语(Bokmål)
  44. 波斯语
  45. 波兰语
  46. 葡萄牙语(葡萄牙)
  47. 旁遮普语(果鲁穆奇文,印度)
  48. 罗马尼亚语
  49. 俄语
  50. 塞尔维亚语(西里尔文)
  51. 简体中文(中国大陆)
  52. 简体中文(新加坡)
  53. 斯洛伐克语
  54. 斯洛文尼亚语
  55. 西班牙语(西班牙)
  56. 斯瓦希里语(坦桑尼亚)
  57. 瑞典语
  58. 泰米尔语
  59. 泰卢固语
  60. 泰语
  61. 繁体中文(台湾)
  62. 繁体中文(香港)
  63. 土耳其语
  64. 乌克兰语
  65. 乌尔都语
  66. 越南语

项目正在持续扩展新的 Go 学习与文档内容,并长期维护各语言版本的术语一致性、翻译质量、独立审核、生产发布与后续更新。

本项目属于非官方社区多语言本地化项目,与 Go 官方无隶属、授权或背书关系。