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

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

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

作者:

在

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 看同类问题完整性

最近在 Go Learning & Documentation v2 的翻译流程里,我遇到过一种很让人困惑的情况。

独立 Reviewer 审核一个完整页面以后,给出了 B。

finding 里也明确列出了几个问题。

Generation 按照这些问题逐项修改。

机器校验通过。

然后进入 successor re-QC。

结果 Reviewer 再次给出:

B。

而且新一轮指出的问题,和上一轮其实还是同一种问题。

最开始看到这种结果,很容易怀疑:

Generation 是不是没有认真按照 finding 修改?

但继续拆解以后发现,真正的问题并不一定是“没有修改”。

更常见的情况反而是:

Reviewer 只列出了几个代表实例,Generation 又把这些实例误认为完整修订边界。

于是最终形成了这样一个循环:

Plaintext
第一次独立审核判定为 B
→ Reviewer 列出若干实例
→ Generation 修复这些实例
→ successor re-QC
→ 同一类别仍有残留
→ 再次判定为 B

这类问题后来促使我把 Reviewer finding 和 Generation exact revision 的边界重新梳理了一遍。

最后形成了一条现在看来非常重要的原则:

finding-anchored 不等于 example-anchored。

也就是说:

修订必须由正式 finding 授权,但 Reviewer 举出的几个例子,并不默认等于这一类问题的全部范围。

这篇就专门整理这个问题。


最开始的问题:Reviewer 发现了“类别”,却只写了“例子”

假设一个中文页面里,某类 inline Go API identifier 与前后中文正文之间存在重复性的间距问题。

完整页面中实际有 8 处。

Reviewer 阅读时先看到了其中 3 处,于是在 finding 中写:

某些 inline API identifier 与中文正文粘连,例如 A、B、C,请修正。

从人的阅读习惯来看,这段 finding 很自然。

因为“例如”已经表达了:

我是在举例。

但对精确修订工作流来说,它存在一个很大的问题:

到底授权修多少?

Generation 可能有两种理解。

第一种理解是:

Reviewer 列出的 A、B、C 就是全部正式授权范围,我只能改这 3 处。

第二种理解是:

Reviewer 已经识别出一种重复 defect category,A、B、C 只是 evidence,我应该在当前 TranslationUnit 内继续检查同类实例。

如果合同没有说清楚,这两种解释都看起来有一定道理。

而正式工作流最怕的就是:

依赖猜。


“例如”对人很自然,对机器工作流却很危险

自然语言审核里经常会写:

例如……

比如……

等。

这种写法对普通人工协作没有太大问题。

因为接收者通常会自行理解:

这是一个类别,请顺手把同类情况一起处理。

但 v2 的 exact revision 不是普通编辑。

它有一个很重要的限制:

Generation 不允许借一个 finding 扩大成整页自由润色。

也就是说,Generation 不能看到:

某处标点有问题。

然后顺便去修改:

  • 其他语序;
  • 自己觉得不够自然的句子;
  • Reviewer 没有授权的术语;
  • 无关标点;
  • 其他 style preference。

所以工作流一直强调:

finding-anchored。

问题也正好出在这里。

如果把 finding-anchored 理解成:

只允许修改 finding 里逐字列出的几个实例。

那么重复型问题就很容易漏。

如果把它理解成:

只要感觉类似就可以全页随便改。

又会造成 scope expansion。

所以中间必须有一个更准确的概念:

defect category + bounded scope。


Reviewer 真正应该提交的,不只是几个 examples

后来正式规则变得更明确。

Reviewer 对一个完整 current TranslationUnit 做 fresh judgment 时,一旦决定给出 B、C 或 D,并且已经识别出某个 defect category,就不能看到两三个例子以后直接停止。

而应该:

在当前完整 TranslationUnit 内,对这个类别再做一次 same-class scan。

这里的 same-class 可以理解成:

同一缺陷类别的完整扫描。

它不要求数学意义上的绝对穷举。

但至少不能:

明明已经看出来这是一个重复模式,却只写两个代表例子,然后把剩余实例留给下一轮 Reviewer 再发现。

例如已经确定问题类别是:

当前 Page 中,inline Go API identifier 与紧邻中文正文之间存在不符合中文排版习惯的粘连。

那么 Reviewer 后续就应该检查:

当前完整 Page 中还有没有同样满足这个 predicate 的位置。

如果只有 4 处,就尽量把 4 处都列出来。

如果有几十处,不适合全部逐条写,也至少应该给出:

一个足够精确的 predicate,加一个明确的 bounded scope。


finding 应该描述“问题类别”,而不是只有“这里错了”

我现在越来越觉得,一个高质量 finding 最核心的不是例子数量。

而是能回答四个问题。

第一:

Finding category 是什么?

也就是到底是哪一类问题。

第二:

Observed instances 是哪些?

已经观察到哪些实际实例,以及它们在哪里。

第三:

Revision scope 到哪里为止?

Generation 允许在什么范围里做同类完整扫描。

第四:

Out of scope 是什么?

哪些东西明确不能顺便改。

例如,一个相对清楚的 finding 可以表达成:

Plaintext
问题类别:
当前 Page 中,inline Go API identifier 与紧邻中文正文之间存在同一种不当粘连。

已观察实例:
列出已经发现的实例,并提供稳定的段落、section 或相邻文本定位。

修订范围:
当前完整 Page 内,仅针对上述同一类别做完整扫描与修复。

范围外:
其他措辞偏好、普通润色、其他标点类别、术语调整,以及所有 protected 内容。

这样 Generation 才真正知道:

我应该继续找什么。

以及:

我绝对不应该顺手改什么。


examples 是 evidence,不默认是完整 revision boundary

这是后来我觉得最关键的一条规则。

Reviewer 提供的 examples,首先是:

finding evidence。

它们证明:

这个问题真实存在。

但它们不默认意味着:

只有这些具体位置才能修改。

只有 Reviewer 明确说明:

这是 exact-instance-only finding。

Generation 才应该严格限制在列出的几个实例上。

否则,对于已经清楚定义:

  • defect category;
  • predicate;
  • bounded scope;

的重复型问题,Generation 还需要继续做:

same-class complete sweep。

也就是:

在同一个当前 TranslationUnit、同一个问题类别、同一个授权范围内,把明确属于同一 predicate 的其他实例一起处理掉。


finding-anchored 不等于只改 finding 里的字面例子

这也是 Generation 一侧最容易误解的地方。

项目一直强调:

exact revision 必须 finding-anchored。

这个规则没有问题。

因为如果没有 finding 约束,Generation 很容易退化成:

“既然已经打开这个 Page,那我顺便把整页重新润色一下。”

这会破坏:

  • Reviewer 授权边界;
  • candidate identity;
  • revision provenance;
  • unaffected 内容的稳定性。

所以必须保持:

finding-anchored。

但是它真正的含义应该是:

所有修改都必须能回到 persisted finding 的 defect category 和授权 scope。

而不是:

只允许修改 finding prose 中逐字列出的几个 example。

这两种理解差别很大。


locally complete 也不是“把这一句话修完整”

还有一个容易误解的词:

locally complete。

以前很容易把它理解成:

找到这个位置,把这句话修完整。

后来才发现,这样还不够。

在重复型 finding 里,locally complete 真正应该表达的是:

在已授权的局部范围内,把同一类别的问题完整关闭。

这里的“local”限制的是:

scope。

不是:

instance count。

例如 Reviewer 的 finding scope 是:

当前 Page 全文中的 inline identifier spacing。

那么 local 就是:

当前 Page。

Generation 不能扩到其他 Page。

但在这个 Page 内,属于同一个 predicate 的 8 个实例,就不应该只修其中 3 个。


为什么“只修 examples”看起来很安全,实际却会制造 re-QC 循环

从 Generation 的角度看,只修 Reviewer 明列实例其实非常保守。

因为它最大程度避免了:

scope expansion。

但副作用是:

把 Reviewer 的 examples 错误地当成 exhaustive list。

于是第一次 revision 以后:

Plaintext
Reviewer 明列实例:3
Generation 修复实例:3
页面真实同类实例:8
剩余残留:5

机器 validation 仍然可能完全 PASS。

因为:

机器 validator 通常只能验证结构、protected content、identity、schema 和正式机械语义。

它不会替 Reviewer 判断:

另外 5 处中文排版是否仍然存在同样问题。

所以最终只能等 successor re-QC 再发现。


机器 validation PASS 并不能关闭语言 finding

这也是这个循环里一个很重要的误区。

revision 完成以后,如果看到:

Plaintext
validation:PASS

很容易产生一种心理:

修订应该已经完成了。

实际上 validation 只能证明:

这个 replacement 在机器合同上合法。

例如:

  • protected token 没有丢;
  • source identity 没变;
  • 结构合法;
  • 输出格式正确;
  • 没有修改禁止修改的技术内容。

它不能证明:

Reviewer 指出的语言类别已经完全关闭。

所以:

machine validation PASS ≠ finding closure PASS。

这也是为什么必须继续有独立 successor re-QC。


Generation 在提交前也应该做 finding closure check

为了减少这种明显的往返,Generation 一侧后来也需要承担一个任务完成性检查。

注意,这不是自审。

Generation 不能给自己 A。

也不能说:

我觉得翻译质量已经通过。

它应该做的是更机械的:

finding closure check。

也就是在提交 replacement 前确认:

  • 明列实例是否都已处理;
  • persisted finding category 是否已经理解;
  • bounded scope 内是否仍有明显 same-class residual;
  • 是否意外修改了 finding 之外的其他内容;
  • protected 内容是否保持不变;
  • 如果 category 或 scope 不清楚,是否应该停止并报告 ambiguity。

这是一种:

任务完成性检查。

不是:

正式语言质量审核。

最终 rating 仍然只能由独立 Reviewer 给出。


same-class sweep 也不能变成“顺便润色全文”

规则收紧以后,另一个风险马上出现了。

Generation 可能会想:

既然要求同类扫描,那我看到类似问题都一起修。

这个方向本身没错。

但“类似”不能无限扩大。

比如 persisted finding 是:

当前 section 中中文标点前存在同一种异常空格。

那么 same-class sweep 可以检查:

当前授权 section 里,是否还有同样的异常空格。

但不能顺手扩展到:

  • 另一种标点问题;
  • 术语风格;
  • 标题语气;
  • 句子重写;
  • 其他 section 的无关表达。

所以 same-class completeness 需要同时满足三个约束:

同一个 category。

同一个 bounded scope。

同一个正式 Unit / slot authorization。

只要超出其中一个,就不再属于这次 finding-anchored revision。


不能靠“看起来差不多”判断 same-class

这个边界也非常重要。

假设 finding 是:

inline API identifier 与中文正文粘连。

Generation 又看到另一个地方有:

英文品牌名与中文正文之间没有空格。

这两个从视觉上可能很像。

但它们是否属于同一 defect category,不一定。

可能前者涉及:

  • code / identifier formatting;

后者涉及:

  • 品牌名的中文排版规范。

如果无法可靠判断:

这是不是同一个 predicate。

那么 Generation 不应该猜。

正确处理方式应该是:

保持该处不变,并报告 ambiguity / blocker。

因为 same-class completeness 的目标是:

把已经授权的一类问题修完整。

而不是借这个机会扩充新的语言判断。


Reviewer 的 completeness 也不能变成无限找问题

Reviewer 一侧同样需要边界。

same-class scan 并不是:

判了一个 B 以后,再重新寻找整页所有可能的语言问题。

如果 Reviewer 在 fresh judgment 中另外发现一个独立问题,当然可以记录。

但应该把它作为:

新的 defect category。

而不是混进原来的 finding。

例如页面同时存在:

  1. inline identifier spacing;
  2. 某个术语译法错误;
  3. 某张表格中的语义遗漏。

这应该是三个独立类别。

每个类别分别定义:

  • observed instances;
  • predicate;
  • bounded scope;
  • revision boundary。

不能最终写成:

页面还有一些语言问题,请整体优化。

因为这种 finding 几乎等于授权:

整页重译。

这正是 exact revision 想避免的事情。


successor re-QC 也不能只检查旧 examples

这一轮规则真正闭环的地方,在 successor re-QC。

以前 re-QC 很容易退化成:

Reviewer 上次列了 A、B、C。

现在看看 A、B、C 修没修。

如果全修了:

PASS。

问题是,这样仍然会漏掉同类残留。

所以 successor re-QC 必须重新对:

完整 current TranslationUnit

做 fresh judgment。

尤其对于 persisted finding,还要检查:

这个 finding category 在原授权 scope 内有没有完整关闭。

也就是说,它不仅要问:

上次列出的 3 个 examples 修了吗?

还要问:

当前 scope 里还有没有第 4、第 5 个同类 residual?


如果还有残留,就应该明确写成 same-class residual

假设上一轮 finding 是:

当前 Page 中存在 inline identifier spacing 问题。

Generation 修掉大部分。

re-QC 后仍发现 1 处。

这时候最准确的表达不是:

新发现一个 spacing 问题。

因为它并不是一个全新的类别。

它是:

persisted category 的 same-class residual。

这样历史链条才清楚:

Plaintext
原 finding category
→ revision
→ successor re-QC
→ same-class residual

而不是看起来像:

Plaintext
旧问题已经完全关闭
→ Reviewer 又突然发现一个全新问题

这对后续 revision scope 也更准确。


为什么旧 finding 不应该回写

规则变得更完整以后,很容易产生另一个冲动:

既然现在知道第一次 finding 写得不够完整,要不要把历史 finding 改掉?

答案应该是:

不要。

因为历史 evidence 应该记录:

当时 Reviewer 实际提交了什么。

后来的 successor re-QC 如果发现残留,就创建新的证据。

而不是回头把旧 evidence 改成:

“其实我当时已经发现了全部问题。”

否则历史就不再可信。

所以正确方式是:

Plaintext
旧 finding:保持不变
新的 re-QC:记录 same-class residual
新的 revision:继续处理 residual

历史可以不完美。

但不能被重新书写。


为什么这条规则不要求数学意义上的穷举

看到 same-class completeness,可能会担心:

Reviewer 是不是必须证明整页绝对一个都没漏?

其实不是。

语言判断很难做到数学意义上的 exhaustive proof。

正式要求更接近:

reasonable complete scan。

也就是说:

一旦 Reviewer 已经识别出重复型 pattern,就应该有意识地扫描整个授权范围,而不是随手看到两个就停止。

如果实例非常多,可以用:

exact predicate + bounded scope。

而不是必须写几十行列表。

真正禁止的是:

明知道是重复型 defect,却故意只给几个 example,然后把剩下的问题留给下一轮。


一个好的 predicate 可以比几十个 examples 更有价值

假设一个页面有 30 处相同问题。

逐条列 30 个实例当然可以。

但更稳定的 finding 可能是:

当前 Page 全文中,所有按中文排版规范应与相邻正文分隔、但实际发生不当粘连的 inline Go API identifier。

这里已经明确了:

  • category;
  • predicate;
  • scope。

然后再列几个具体实例作为 evidence 和定位参考。

Generation 就可以在当前 Page 内做完整 sweep。

而 Reviewer 在 successor re-QC 时也知道:

应该验证哪个 predicate 已经关闭。

这比:

例如 A、B、C 等。

稳定得多。


bounded scope 为什么一定要明确

如果只有 predicate,没有 scope,也会出问题。

例如:

修复所有 API identifier spacing。

这里的“所有”到底是:

  • 当前 paragraph;
  • 当前 section;
  • 当前 Page;
  • 整个 package;
  • 整个 locale?

都不清楚。

所以 scope 必须被限定。

例如:

当前 Page 全文。

或者:

当前 Page 的 Security Considerations section。

或者:

当前表格的 description 列。

或者:

当前授权的 teaching-comment 区域。

这样 Generation 才不会跨 TranslationUnit 扩散。


exact-instance-only 什么时候才应该使用

并不是所有 finding 都适合 same-class sweep。

有时候 Reviewer 判断的问题就是:

某一句具体翻译存在一次性语义错误。

例如某句话漏掉了一个否定关系。

而页面其他位置并不存在同类 pattern。

这时候完全可以明确:

exact-instance-only。

也就是:

只授权修改这一个具体实例。

这样 Generation 就不需要为了“完整”再去全页寻找一个并不存在的类别。

所以关键不是:

每个 B 都必须扩大范围。

而是:

重复型问题应该完整扫描;一次性问题应该明确限制。


Reviewer examples 和 Generation examples 的角色不一样

这里还有一个很值得区分的地方。

Reviewer examples 是:

evidence。

Generation 输出中的实际修改,则是:

finding closure。

二者不是一一对应关系。

例如 Reviewer 提供 3 个 examples,但 category + scope 明确覆盖当前完整 Page。

Generation 最终可能修改 7 处。

这不代表:

Generation 擅自扩大范围。

只要新增修改的另外 4 处都满足:

  • 同一个 defect category;
  • 同一个 predicate;
  • 同一个 bounded scope;
  • 没有跨 formal authorization;

那么它仍然是:

finding-anchored revision。

这就是后来我觉得特别重要的一点:

finding-anchored 描述的是“修改的因果来源”,不是“修改实例数量必须和 finding examples 数量一样”。


这能明显减少无意义的 Reviewer 往返

如果没有 same-class completeness,一个重复型问题可能变成:

Plaintext
QC:发现 3 处
→ revision:修 3 处
→ re-QC:发现另外 2 处
→ revision:再修 2 处
→ re-QC:又发现 1 处

每一轮都是真实工作。

但大量成本其实不是语言问题本身,而是:

第一次 finding 边界表达得不够完整。

这会额外消耗:

  • Generation invocation;
  • Reviewer invocation;
  • Bundle export;
  • validation;
  • Snapshot;
  • evidence;
  • re-QC;
  • 人工协调时间。

所以 completeness 并不仅仅是质量问题。

它也是非常直接的:

成本优化。


但这和“让 Reviewer 一次找完所有问题”仍然不同

这里需要特别避免走向另一个极端。

same-class completeness 不是要求 Reviewer:

第一次 QC 必须找出整个 TranslationUnit 未来所有可能的问题。

Reviewer 仍然是一次 fresh judgment。

它应该尽力发现当前看到的问题。

区别只在于:

一旦已经识别出某个重复型 defect category,就不要故意只审几个代表实例。

换句话说:

要求的是类别内部完整,不是要求 Reviewer 拥有预知能力。

如果 successor re-QC 后确实出现一个此前完全没有识别过的新类别,那么它仍然可以作为新的 finding。


这套规则仍然保持 Reviewer 和 Generation 独立

增加 completeness 以后,也不能让两个角色合并。

Reviewer 的职责仍然是:

判断质量,定义 finding category、evidence 和 revision scope。

Generation 的职责仍然是:

在正式 finding 授权内生成 replacement。

Generation 可以做 same-class complete sweep。

但它不能:

因为自己觉得已经修好了,就给自己 A。

Reviewer 可以指出完整 category。

但它不能:

顺手直接生成 replacement 再批准自己的修改。

角色隔离仍然保持。


machine scope 和语言 scope 也不能混在一起

same-class completeness 只解决:

语言 finding 的完整关闭。

它不改变:

  • TranslationUnit membership;
  • package membership;
  • parser slot authorization;
  • protected token;
  • candidate identity;
  • Snapshot;
  • machine validation;
  • A-only finalization。

例如当前正式 scope 只有一个 Page TranslationUnit。

即使 Reviewer 发现另一个 Page 似乎也有相似问题,也不能顺手把另一个 Page 纳入本轮 revision。

那已经属于:

新的正式 affected scope。

需要走它自己的 authority。


这件事其实暴露了一个很普遍的问题

回头看,这并不只是翻译流程的问题。

很多工程协作都会遇到:

报 bug 的人给了两个 example。

修 bug 的人只修了这两个 example。

测试人员下一轮又找到第三个。

真正缺少的是:

问题类别是否已经定义清楚。

例如一个 parser bug,如果只修:

fixture A 和 fixture B。

而没有定义:

什么样的输入属于同一个 failure predicate。

那未来很可能还会出现 fixture C。

所以 same-class completeness 其实是一种更一般的工程习惯:

不要只修样本,要理解样本背后的 defect class。


但是 defect class 也必须有边界

这句话同样不能被滥用。

“理解类别”不代表:

发现一个问题后顺便重构整套系统。

在翻译 revision 里 especially 如此。

正确的问题应该是:

这个 instance 为什么属于当前 finding?

而不是:

既然这里有问题,那我还有什么地方看着不顺眼?

前者是:

category closure。

后者是:

scope expansion。

这两者必须严格区分。


我现在更认可的 Reviewer finding 结构

如果以后再遇到 B/C/D,我会更倾向于让 finding 至少具备下面四部分。

第一部分说明:

Finding category:具体缺陷类别。

第二部分说明:

Observed instances:尽量完整的已观察实例,或者 exact predicate。

第三部分说明:

Revision scope:当前 TranslationUnit 内允许执行 same-class complete sweep 的明确范围。

第四部分说明:

Out of scope:其他类别、普通润色和 protected 内容明确不允许修改。

这并不需要新增新的 JSON schema。

也不需要增加 CLI 字段。

它完全可以继续存在于 Reviewer 的自然语言 evidence 中。

但表达精度会高很多。


Generation 也有一套对应的问题清单

收到 revision Bundle 以后,Generation 应该先问:

Reviewer 定义的 defect category 是什么?

然后问:

bounded scope 到哪里?

再问:

examples 是 evidence,还是明确的 exact-instance-only boundary?

如果不是 exact-instance-only,就继续问:

当前授权 scope 里还有没有明确满足同一 predicate 的其他实例?

最后还要问:

我是否碰到了其他 category、普通润色或者 protected content?

如果碰到了:

不改。

如果同类归属本身无法可靠判断:

不猜。

这时候报告 ambiguity,反而比擅自修改更正确。


successor re-QC 最后负责真正关闭这条链

Generation 完成 replacement 后,最终仍然必须回到独立 Reviewer。

Reviewer 不能只看:

原来列出的 examples 都改了。

而应该检查:

当前完整 TranslationUnit 里,这个 persisted finding category 在原 revision scope 内是否已经真正关闭。

如果全部关闭:

才能根据完整 fresh judgment 给 A。

如果仍有 residual:

继续给 B/C/D,并明确这是 same-class residual。

如果发现完全新的独立问题:

新建另一个 category。

这样整个链条就会变成:

Plaintext
Reviewer 定义 defect category 和 bounded scope
→ Generation 在 scope 内完成 same-class sweep
→ machine validation 验证 replacement 合法
→ successor re-QC 验证 category 是否完整关闭
→ 全部通过后才进入 A-only finalization

这比:

Plaintext
Reviewer 举几个例子
→ Generation 改几个例子
→ Reviewer 再找几个

稳定得多。


这次规则变化真正想解决的不是“Reviewer 要更认真”

如果把这件事简单总结成:

Reviewer 第一次应该看仔细一点。

其实并不准确。

因为真正的问题是:

工作流以前没有把 category、example 和 revision boundary 之间的关系定义得足够清楚。

Reviewer 可能以为:

“例如”已经足够表达同类问题。

Generation 又可能因为 fail-closed 倾向而认为:

只有明列实例才是正式授权。

双方其实都在做各自看来合理的事情。

最后却形成无意义循环。

所以改进的重点不是:

要求某个角色更聪明。

而是:

把交接合同写得更精确。


一个好的工作流应该减少“靠默契理解”

这也是整个项目越来越明确的一条原则。

越是正式、可恢复、跨 session 的流程,就越不能依赖:

“你应该知道我的意思。”

因为 Reviewer 和 Generation 本来就是两个独立 session。

甚至可能跨不同时间执行。

它们真正共享的应该是:

  • Bundle;
  • persisted finding;
  • exact source;
  • candidate;
  • formal authority。

而不是:

隐含默契。

所以 defect category 和 bounded scope 越明确,后续越稳定。


这次最值得保留的几条原则

经过这几轮 B → revision → re-QC 的反复,我觉得可以把现在的规则浓缩成几条。

第一:

Reviewer 一旦识别出重复型 defect category,就应该在完整 current TranslationUnit 内进行 reasonable same-class scan。

第二:

Reviewer examples 是 evidence,不默认构成 exhaustive revision boundary。

第三:

实例过多时,可以使用 exact predicate + bounded scope,而不是用“例如”“等”留下开放边界。

第四:

只有 Reviewer 明确标记为 exact-instance-only,Generation 才只修改列出的具体实例。

第五:

finding-anchored 不等于 example-anchored。

第六:

locally complete 表示在授权局部范围内完整关闭同一类别,不表示只修一个局部句子。

第七:

Generation 应在 persisted category + bounded scope 内做 same-class complete sweep,但不能扩展到其他 category 或普通润色。

第八:

同类归属无法可靠判断时不猜,应该保持原文并报告 ambiguity。

第九:

successor re-QC 不仅检查旧 examples,还要验证 persisted category 在授权 scope 内是否完整关闭。

第十:

如果仍有同类残留,应明确记录为 same-class residual,而不是伪装成一个完全新的问题。

最终我现在最想保留的一句话是:

修订真正应该关闭的是“问题类别”,而不只是 Reviewer 当时碰巧写出来的几个例子。

这并不意味着扩大 revision scope。

恰恰相反。

它要求我们把:

类别、范围和边界

定义得更加精确。

只有这样,才能同时做到两件事:

不漏掉明确属于同一问题的残留。

以及:

不借一个 finding 的名义去重写本来没有问题的内容。

这才是我现在理解的:

finding-anchored,locally complete。

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

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 官方无隶属、授权或背书关系。