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

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

作者:

,

A Tour of 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 连续上线三门语言后,我又优化了哪些流程

上一篇文章中,我完成了 A Tour of Go 中文版项目的设计冻结,重点讨论了页面数量、翻译单元、状态流程和命令行架构等问题。(Shuijing Wanwq)

设计冻结以后,我并没有立即调用 GLM-5.2 开始翻译。

真正进入实现阶段后,我首先完成了三件更基础的工作:

  1. 调查官方 Tour 和多个现有翻译项目;
  2. 从固定的官方源码中提取可独立运行的英文基线;
  3. 为 101 个课程页面建立机器可读目录、持久身份和上游变化预览。

这一阶段还专门确认了右侧 Go 示例代码的运行方式。

A Tour of Go 不只是一组静态课程文章。读者可以直接修改示例代码、格式化代码并点击 Run。如何保留这项能力,同时又不在普通 Web 服务器上运行陌生代码,是这个项目绕不开的问题。

本文不再重复上一篇文章已经说明的完整页面翻译原则,而是记录这些设计进入代码实现以后,最终形成了什么。

一、开始开发以前,我先调查了六个翻译项目

在导入官方源码之前,我先对六个具有代表性的 A Tour of Go 翻译项目进行了只读调查:

  • Go-zh/website
  • Go-zh/tour
  • atotto/go-tour-jp
  • golang-id/tour
  • golangbr/go-tour-br
  • suzusime/go-tour-jp

这些项目覆盖了几种常见路线:

路线代表形式
完整复制 golang/website中文 website 项目
复制旧版单语言 Tour中文、日语、印尼语和巴西葡萄牙语项目
在旧 Tour 上生成静态页面日语静态项目
每种语言独立部署多数社区翻译站

这些项目并不是没有价值。

相反,它们证明了完整 .article 翻译、课程正文与公共 UI 分离、本地运行使用 /socket、正式网站调用远程 Playground 等基本方向是可行的。

但经过多年维护以后,一些共同问题也逐渐显现出来。

二、单语言复制能够快速上线,但长期维护成本很高

多数旧翻译项目采用的方式可以概括为:

Plaintext
复制一套 Tour 服务端
→ 复制模板和静态资源
→ 复制全部 Go 示例
→ 翻译课程正文
→ 单独部署一个语言站

这种方式的优点很明显。

项目刚开始时,维护者只需要复制官方代码、修改 .article 和 UI 文案,就能较快得到一个可以运行的翻译站。

问题在于,每增加一种语言,就会增加一套独立维护的服务端、模板、JavaScript、示例代码和部署配置。

官方 Tour 更新以后,各个翻译项目都需要分别同步:

  • 服务端代码;
  • 前端资源;
  • 课程页面;
  • Go 示例;
  • 第三方依赖;
  • 部署运行时。

如果某个语言项目停止维护,它往往不会立即完全失效。

更常见的情况是:网站暂时还能打开,但课程内容、依赖和部署方式已经逐渐落后。

因此,这次项目没有选择为简体中文复制一套永久独立的 Tour,也没有计划以后为日语、德语或其他语言继续复制更多服务端。

当前确定的原则是:

  • Go 服务端尽量共享;
  • 模板基础结构和静态资源尽量共享;
  • Go 示例只维护一份官方基准;
  • 每种语言只独立维护课程译文、UI 文案、术语表和页面状态。

三、完整复制 website 又会产生另一类问题

当前官方 A Tour of Go 已经位于 golang/website 仓库中。

最直接的方案似乎是 Fork 整个 website,然后在里面修改 Tour。

golang/website 不只包含 Tour,还包含:

  • Go 官方网站服务;
  • 博客和文档内容;
  • 下载页面;
  • 包文档相关逻辑;
  • 官方构建和部署配置;
  • App Engine 与 Cloud Build 文件;
  • 与 Tour 无关的大量静态资源和工具。

如果只想维护一个多语言 Tour,复制整个 website 会让每次上游同步都混入大量无关变化。

因此,我最终采用的是另一种方式:

从固定的官方提交中,提取 Tour 能够独立运行所需要的最小源码闭包。

当前固定的官方基线提交为:

e11dacba76c5aae474746e9eedee19693f492803

首次导入共涉及 199 个上游来源文件:

  • 192 个文件保持逐字节一致;
  • 7 个文件为了适配独立仓库进行了最小修改。

项目使用 UPSTREAM_MANIFEST.tsv 记录每个来源文件的:

  • 上游路径;
  • 本地路径;
  • 文件类型;
  • 是否保持原样;
  • SHA-256;
  • 必要的适配说明。

这样既避免了复制整个 website,也避免了每次构建时临时下载源码造成的网络依赖和不可重复性。

四、从其他翻译项目中看到的几个长期问题

除了重复维护服务端以外,这次调查还暴露出几个更值得注意的问题。

1. 很多项目没有明确的上游版本

Git 仓库中有一份课程译文,并不能直接说明它对应官方的哪个提交。

最近有提交,也不代表课程正文已经同步。

因此,本项目同时记录:

  • 固定 upstream commit;
  • 文件级 SHA-256;
  • 页面级 source_sha256
  • 页面身份和当前路径;
  • 未来上游变化的分类结果。

2. 部署平台退役可能导致整个语言站下线

多个旧翻译项目与 App Engine runtime 深度绑定。

当旧 runtime 退役以后,一批社区翻译站曾经同时离线。官方 Go 项目虽然在页面中提供了这些语言入口,但这些站点由社区维护者拥有,官方无法直接替维护者恢复部署。

这说明:

源码仍然存在,不等于线上服务能够长期运行。

因此,当前项目不会把某个云平台的专有部署文件作为核心架构,也不会把个人项目 ID、账号配置或固定运行时写入通用流程。

3. 缺少自动校验时,错误主要依赖读者发现

现有翻译项目通常拥有基础 Go 测试,但很少具备:

  • 英文页面与译文结构比较;
  • .play 路径完整性检查;
  • 链接目标检查;
  • 行内代码检查;
  • 页面身份检查;
  • 翻译状态门禁;
  • 上游变化预览;
  • 损坏译文阻止发布。

这意味着译文即使破坏了课程结构,也可能要等到维护者或读者偶然发现。

4. 示例代码很容易产生语言分叉

部分翻译项目修改过示例代码中的注释或字符串。

短期看,这样可以让代码显得更本地化;长期看,却会导致不同语言拥有不同的示例基准。

官方修改代码以后,维护者不仅要同步代码,还要判断每个语言版本中的修改是否仍然适用。

因此,第一阶段决定:

  • .play 引用的 Go 示例保持官方原样;
  • 不翻译变量名、函数名和输出字符串;
  • 不为每种语言复制一套不同的示例;
  • 使用哈希和测试持续确认示例没有发生意外变化。

5. 纯静态页面更容易部署,但会失去完整交互

静态日语项目证明,课程正文可以预生成成普通 HTML。

这种方式迁移方便,也不依赖持续运行的 Go 服务。

但静态页面通常无法完整保留:

  • 编辑器;
  • Run;
  • Format;
  • Kill;
  • 与 Playground 的交互。

因此,静态页面未来可以作为只读备份或故障降级产物,但不适合作为当前项目唯一的正式形态。

五、英文 Tour 基线已经可以独立运行

完成最小源码导入以后,项目已经不再依赖完整的 golang/website 仓库才能运行 Tour。

当前英文基线已经完成以下验证:

  • Go Module 可以正常解析;
  • 所有 Go 测试通过;
  • 七个 .article 可以被 present 解析;
  • 示例代码可以完成原有构建和运行测试;
  • Tour HTTP 服务可以正常启动;
  • 页面、CSS、JavaScript、Logo 和 favicon 可以访问;
  • /_/fmt 可以正常格式化代码;
  • 本地 /socket 可以完成 WebSocket 握手;
  • 进程退出后没有监听端口或临时文件残留。

当前源码结构统计为:

项目数量
顶层 .article7
standalone 普通页面101
普通 .play 引用92
.image 引用1
#appengine: 条件页面2

这组 7 / 101 / 92 / 1 数据,已经成为当前固定英文基线的一部分。

六、为什么上一篇是 103 页,现在状态文件却只有 101 页

上一篇文章从官方 integrated production 投影视角统计,得到了 103 个页面。

其中多出的两个页面是:

  • Go offline (optional)
  • The Go Playground

它们来自 welcome.article 中的 #appengine: 条件内容。

真正开始导入独立 Tour 以后,我决定先以当前 standalone 运行方式中的 101 个普通页面建立第一阶段状态,同时将两个条件页面单独记录在:

data/tour-conditional-pages.tsv

因此,现在的结构并不是忽略那两个页面,而是:

Plaintext
101 个 standalone 普通页面
→ 进入 zh-CN 页面状态

2 个 appengine 条件页面
→ 单独登记
→ 暂不进入第一阶段翻译状态

这样可以让第一阶段的页面目录与当前独立运行基线保持一致,同时保留条件页面的来源、标题和哈希。

以后真正实现生产投影或者等价页面时,再明确决定如何处理这两个页面,而不是现在把 standalone 与 App Engine 两种运行模式混在同一个状态文件中。

七、右侧的 Go 示例代码到底在哪里运行

A Tour of Go 最重要的特点之一,是读者可以直接修改右侧代码并点击 Run。

但是,“点击 Run”并不意味着所有环境都以相同方式运行代码。

本地开发模式

本地启动 Tour 时,执行链路大致是:

Plaintext
浏览器中的代码编辑器
→ WebSocket /socket
→ 本地 Tour 进程
→ 本机 Go 工具链
→ 返回运行结果

这种方式适合个人电脑上的本地学习和开发。

当前项目导入英文基线以后,也保留了这项上游行为,并实际验证了 /socket 能够完成 WebSocket 101 Switching Protocols 握手。

/socket 会调用 Tour 所在机器上的 Go 工具链执行代码,因此只能用于可信的本地开发环境。

它不能直接作为公开网站的代码执行接口。

官方生产模式

当前官方 Tour 的生产链路并不是浏览器直接在本地运行 Go,也不是让 go.dev 普通 Web 进程直接执行用户代码。

实际链路是:

Plaintext
浏览器
→ 同源 /_/compile
→ go.dev 服务端代理
→ play.golang.org/compile
→ Go Playground 沙箱
→ 返回运行结果

Go Playground 会在受限沙箱中编译和运行代码,并对执行时间、CPU、内存和外部访问进行限制。官方也允许有益于 Go 社区的第三方服务使用 Playground,但要求调用方事先联系并提供可识别的独特 User-Agent。(Go)

当前项目未来采用的方式

正式网站仍然计划保留 Run,但不会把公开 /socket 暴露到互联网。

计划中的正式链路是:

Plaintext
浏览器
→ 项目同源轻量代理
→ Go 官方 Playground
→ 返回运行结果

这里的“代理”只负责转发受限制的请求。

它不代表用户代码在项目 Web 服务器上运行。

这样可以继续保留交互式学习体验,同时避免自己承担恶意代码隔离、系统调用限制和完整沙箱运维。

不过,这部分目前仍然只是已经确定的正式方案,代理尚未开始实现,也没有公开上线。

八、101 个课程页面已经拥有机器可读目录

完成英文基线以后,项目没有直接开始翻译,而是先生成:

data/tour-pages.tsv

其中每个页面都记录:

  • page_id
  • 所属 article;
  • 当前 Section 编号;
  • 当前 route;
  • 英文标题;
  • 完整页面 source_sha256
  • .play 数量;
  • .image 数量。

例如,一个页面可以拥有如下关系:

Plaintext
page_id: welcome/1
article: welcome.article
section_number: 1
route: /welcome/1
source_sha256: 491d9386ffb917083a1e556bc9849d57894dd8b29bd243ac855cd9e99f701893

这里的哈希不是只根据标题生成,也不是根据抽象语法树生成。

它对应的是从英文 article 中导出的完整顶层页面源文本,包括:

  • 页面标题;
  • 普通正文;
  • present 指令;
  • 代码引用;
  • 结尾换行。

以后官方修改某个页面时,项目可以准确判断英文源是否发生变化,而不是只依赖文件修改时间或人工肉眼比较。

九、页面可以按完整 Section 单独导出

当前维护工具已经可以根据 page_id 导出一个完整英文页面:

Bash
go run -mod=readonly ./cmd/tour-i18n page export \
  --id welcome/1 \
  --output /tmp/welcome-1.article

导出结果:

  • 只包含一个完整顶层 Section;
  • 不包含同一个 article 中的其他页面;
  • 保持原始 present 格式;
  • 可以重新解析;
  • SHA-256 与页面目录一致;
  • 默认不会覆盖已有文件。

未来 GLM-5.2 接收的就是这样的完整页面,而不是从页面中拆出的若干句子或 JSON 字段。

这项设计原则已经在上一篇文章中详细说明,本文不再重复展开。

十、zh-CN 的 101 个页面目前全部是 pending

项目已经创建独立的简体中文语言空间:

locales/zh-CN/

其中分别维护:

  • locale 元数据;
  • 页面状态;
  • 未来的完整页面译文;
  • UI 文案边界;
  • 术语表。

当前 status.tsv 中恰好有 101 条记录:

Plaintext
pending:101
candidate:0
ready:0
blocked:0
published:0

这意味着项目已经知道需要处理哪些页面,但还没有生成任何正式中文译文。

没有英文内容冒充中文页面,也没有为了展示进度提前创建空的 .article 文件。

十一、结构校验不再锁死普通段落

上一篇设计阶段曾经倾向于严格保持普通段落的数量、顺序和位置。

真正分析 101 个页面并实现 candidate 校验器以后,我调整了这项规则。

现在的原则变为:

只严格保护真正危险或不可翻译的内容,不因为英文段落形式限制正常的中文表达。

当前必须保持的内容包括:

  • .play 指令及目标路径;
  • .image 指令及目标路径;
  • 链接目标 URL;
  • JavaScript 链接目标;
  • 行内代码;
  • 预格式化代码;
  • present 指令;
  • protected 内容的数量和顺序;
  • 顶层 Section 数量。

允许变化的内容包括:

  • 页面标题;
  • 普通正文;
  • 中文语序;
  • 句子数量;
  • 普通段落数量;
  • 普通文本换行;
  • 链接显示文字。

例如,下面的链接显示文字可以翻译:

Plaintext
[[/cmd/gofmt/][gofmt tool]]

但是链接目标 /cmd/gofmt/ 不能被模型修改。

同样,.play welcome/hello.go 可以出现在译文页面中,但其中的路径必须保持原样。

这样既保留整页翻译所需要的上下文,也避免为了追求机械结构一致而产生生硬中文。

十二、page_id 不能永远等于页面位置

最初生成页面目录时,page_id 看起来与当前路由完全一致:

Plaintext
page_id: basics/5
route: /basics/5

但如果官方以后在 Basics 的第 5 页前面插入一页,原来的第 5 页就会移动到第 6 页。

如果继续根据位置重新生成 ID,后续所有页面都会发生变化:

Plaintext
basics/5 → basics/6
basics/6 → basics/7
basics/7 → basics/8

这会进一步导致:

  • 译文文件路径变化;
  • 状态记录失去关联;
  • 历史 Candidate 无法匹配;
  • 已发布页面身份漂移;
  • 同步结果产生大量无意义变化。

因此,当前 101 个 page_id 已经正式冻结为持久身份。

各字段现在具有不同职责:

字段含义
page_id项目内部持久身份
route当前访问路径
section_number当前上游位置
source_title识别和诊断信息
source_sha256当前英文源版本

未来即使页面移动,routesection_number 可以变化,page_id 仍然保持不变。

新增页面也不会插入编号并重排旧页面,而是显式分配一个从未使用的新 ID。

十三、上游变化现在可以先预览

项目新增了只读的上游变化预览命令:

Bash
go run -mod=readonly ./cmd/tour-i18n upstream preview \
  --source-root /path/to/website

预览结果将页面分为六种类型:

类型含义
unchanged页面内容和位置都没有变化
content_changed可以确认是同一页面,但英文内容已更新
moved完整源内容相同,但位置或 route 发生变化
added上游新增页面
removed上游删除页面
ambiguous证据不足,不能安全自动匹配

匹配策略保持保守。

完整源哈希唯一相同,可以确认页面发生了移动。

当前 route 仍然存在,且 protected structure 保持兼容,可以确认普通内容发生了变化。

但以下情况不会自动迁移:

  • 页面移动的同时又发生较大结构变化;
  • .play 路径发生变化;
  • 多个页面具有重复特征;
  • 只能依靠标题相同判断;
  • 只能依靠普通正文相似判断;
  • 跨 article 移动但没有唯一证据。

这些情况会进入 ambiguous,等待明确处理。

预览命令不会:

  • 修改正式目录;
  • 修改 status.tsv
  • 删除语言状态;
  • 创建新页面 ID;
  • 移动 Candidate;
  • 自动覆盖译文。

十四、当前固定基线的预览结果

使用当前固定 upstream 运行两次预览,输出完全一致:

Plaintext
普通页面:101
条件页面:2

unchanged:101
content_changed:0
moved:0
added:0
removed:0
ambiguous:0

conditional unchanged:2

这说明正式页面目录与当前英文源码完全一致,也证明预览输出具有确定性。

与此同时:

  • 101 个 page_id 没有变化;
  • status.tsv 保持逐字节不变;
  • 两个条件页面目录没有变化;
  • 英文 article 没有变化;
  • Go 示例没有变化。

十五、多语言域名也从路径方案调整为子域名

设计阶段曾经考虑在同一个域名下使用:

Plaintext
/ja/
/de/

真正考虑 CDN 和部署以后,我改为按语言使用子域名。

当前规划是:

Plaintext
go-tour.<实际域名>
→ 默认简体中文
→ EdgeOne

en.go-tour.<实际域名>
→ 英文
→ Cloudflare

ja.go-tour.<实际域名>
→ 未来日语
→ Cloudflare

默认站点直接提供 zh-CN,不再创建 zh.zh-cn. 子域。

项目介绍、语言选择、上游基线和 GitHub 入口则放在默认站点的 /about/ 页面。

这样不同语言以后可以独立选择:

  • CDN;
  • 部署区域;
  • 缓存策略;
  • 发布时间;
  • 故障处理方式。

目前这些都只是已经记录的域名和部署规划,尚未创建真实 DNS、证书或 CDN 配置。

十六、这一阶段仍然没有翻译任何正式页面

截至目前,项目已经完成:

  • 最小英文 Tour 源码闭包导入;
  • 199 个来源文件追踪;
  • 英文 Tour 独立运行;
  • 七个 article 全量解析;
  • 101 个普通页面目录;
  • 两个条件页面目录;
  • 92 个 .play 引用验证;
  • 示例代码构建和运行测试;
  • 单页完整导出;
  • zh-CN 状态文件;
  • candidate 结构校验;
  • 101 个持久 page_id
  • 上游变化预览;
  • 多语言域名和 CDN 边界规划。

但当前仍然是:

Plaintext
正式中文页面:0
Candidate:0
Ready:0
Blocked:0
Published:0

这不是项目进度停滞。

恰恰相反,这意味着在第一篇译文出现以前,项目已经先建立了:

  • 可重复的英文源;
  • 可追溯的页面身份;
  • 可验证的结构边界;
  • 可预览的上游变化;
  • 不依赖人工记忆的状态基础。

十七、下一步才开始真正调用 GLM-5.2

下一阶段将进入正式翻译流水线:

Plaintext
根据 page_id 导出完整英文页面
→ 保护危险结构
→ 调用 GLM-5.2 整页翻译
→ 保存 Candidate
→ present 重新解析
→ protected structure 比较
→ 更新尝试次数和页面状态

这一阶段仍然不会立即批量处理全部 101 页。

更稳妥的方式是:

  1. 先实现单页翻译执行器;
  2. 使用模拟服务完成自动测试;
  3. 选择一个较短页面进行第一次真实翻译;
  4. 验证 Candidate 落盘和失败恢复;
  5. 验证 readyblocked 状态迁移;
  6. 最后再决定何时开始批量翻译。

到那时,这个项目才会真正生成第一篇简体中文课程页面。

而现在完成的工作,是确保第一篇译文出现以后,它不会成为一份无法确认来源、无法判断是否过期、也无法自动验证结构的孤立文本。

A Tour of Go 中文版项目设计冻结:从 101 页到 103 页,从 Gin 转向 Cobra CLI A Tour of Go 多语言翻译项目实录:完成首个 zh-CN 页面翻译闭环

A Tour of Go 多语言翻译项目

本系列完整记录 A Tour of Go 多语言翻译项目从架构设计、整页翻译、结构保护、自动校验,到生产发布与后续维护的实际开发过程。

项目入口:
✅ 简体中文:A Tour of Go 简体中文版
✅ 日语:A Tour of Go 日语版
✅ 德语:A Tour of Go 德语版
✅ 法语:A Tour of Go 法语版
✅ 项目源码:GitHub:shuijingwan/go-tour-i18n

当前已上线简体中文、日语、德语和法语版本。项目属于非官方社区多语言翻译项目,与 Go 官方无隶属或授权关系。