文档与翻译
ZeroClaw 拥有两个独立的翻译层:
| 层 | 格式 | 涵盖内容 |
|---|---|---|
| 应用字符串 | Mozilla Fluent (.ftl) | CLI 帮助文本、命令描述、运行时消息 |
| 文档 | gettext(.po) | mdBook 中的所有文件 |
有关这些流程背后的事实来源、存储、加载、回退和发布边界,请参阅本地化目录生命周期。为文档提取提供输入的生成英文参考内容在生成文档流水线中映射。
它们分别填充并分别存储。两者都使用共享的、与提供商无关的运行时路径:在 providers.models.<kind>.<alias> 下配置模型提供商,并将 --model-provider <alias> 传递给填充命令。任何已配置的别名都可以选择:裸别名(--model-provider <alias>),或者当同一别名存在于多个 kind 下时使用 kind.alias 限定符(--model-provider anthropic.<alias>)。解析器要求匹配的条目指定一个模型,然后将端点默认值、身份验证、线路协议以及可选的自定义 uri 处理委托给运行时提供商栈。
通过 Ollama 使用本地模型是首选方案:无需 API 密钥,无按次调用费用。若需发布级质量,使用托管服务提供商也可以。翻译是本地操作。运行 cargo mdbook sync 来生成专门的翻译缓存 PR、发布翻译流程以及新增语言环境;常规英文文档 PR 可将大范围生成的 .po 变更推迟到专门的后续处理中。
提供程序配置
Ollama 是当前文档的规范来源。请确保已安装 Ollama 并已拉取 qwen3:30b-a3b,然后配置一个 Ollama 提供方条目。uri 是完整的端点 URL,且为可选项:将其留空以使用该提供方系列的默认端点(由运行时提供方栈解析)。仅在需要指向自托管网关或代理时才设置它。任何已配置的系列均可使用(Anthropic、OpenAI、OpenRouter、Ollama……);翻译工具会构建真正的运行时提供方,因此每个系列的端点、认证头和传输协议都会为你处理:无需 OpenAI 兼容性要求。
在本地构建文档
翻译目录(git submodule)
已翻译的 .po 目录位于挂载在 docs/book/po 的 zeroclaw-labs/zeroclaw-docs-translations 子模块中。Rust 开发循环(cargo build, cargo test, cargo clippy)不需要它,但构建或同步文档时需要。初始化一次:
sh
git clone --recurse-submodules https://github.com/zeroclaw-labs/zeroclaw # 新克隆
git submodule update --init docs/book/po # 现有克隆
如果没有检出子模块,英文仍然可以构建(英文源位于 docs/book/src/),但翻译后的区域会渲染为空。
一键快速启动
sh
cargo mdbook serve # 在 http://localhost:3000/en/ 提供所有语言环境
cargo mdbook serve --locale ja # 针对日语源码的实时重载
cargo mdbook build # 将所有语言环境的静态构建放入 docs/book/book/
cargo mdbook refs # 重新生成自动生成的参考页面
cargo mdbook sync # 翻译缓存流程:重新提取 + 合并 .po 文件
cargo mdbook sync --locale ja # 仅同步一个区域设置
cargo mdbook sync --force # 强制重新翻译所有内容(质量检查)
cargo mdbook sync --locale ja --force # 强制重新翻译某个区域设置
cargo mdbook stats # 按语言环境显示已翻译/模糊/未翻译的内容
cargo mdbook check # 验证 .po 文件格式(在翻译 PR 之前运行)
始终使用
cargo mdbook …包装器。直接在docs/book/中运行mdbook build会跳过 xtask 步骤,而该步骤负责从locales.toml渲染theme/lang-switcher.js,这会导致构建失败并报错failed to open theme/lang-switcher.js for hashing。
必需的工具
cargo mdbook 会快速失败并告知你缺少什么,但作为参考:
| 工具 | 安装 |
|---|---|
mdbook | cargo install mdbook --version 0.5.4 --locked |
mdbook-mermaid | cargo install mdbook-mermaid --version 0.17.1 |
mdbook-i18n-helpers | cargo install mdbook-i18n-helpers --locked |
cargo | https://rustup.rs |
gettext(msgfmt、msgmerge) | apt install gettext / brew install gettext |
mdbook-mermaid 的版本已固定,但其发布的锁定文件仍选择 mdBook 0.5.0 的预处理器。对该工具不要使用 --locked,以便 Cargo 解析 mdBook 0.5.4 所使用的兼容 0.5.x 预处理器。
构建产物及其位置
| 源 | 输出 | 由…生成 |
|---|---|---|
docs/book/src/**/*.md(手动编写) | docs/book/book/<locale>/ | mdbook build |
docs/book/src/reference/cli.md | (相同路径;已忽略 git) | cargo mdbook refs |
docs/book/src/reference/config.md | (相同路径;已忽略 git) | cargo mdbook refs |
target/doc/(rustdoc) | docs/book/book/api/ | cargo doc --no-deps --workspace --exclude zeroclaw-desktop |
这两个 reference/*.md 文件是从代码中实际的 clap 派生和 JSON schema 生成的,请勿手动编辑。应改为编辑相关 Rust 类型上的 /// 文档注释。
cargo mdbook 是 cargo run -p xtask --bin mdbook -- 的别名(在 cargo 配置中定义)。如需面向贡献者的精简版本,请参阅在本地构建文档。
[!NOTE] 全文搜索仅为主要语言区域(英语,
locales.toml中的第一项)构建。翻译后的语言区域在构建时不包含搜索索引或搜索框。每个语言区域的搜索索引体积很大(每个约 6-7 MB),会显著增加gh-pages克隆的大小;将搜索限制为英语可使克隆保持精简。若要为翻译后的语言区域重新添加搜索框,需在build_locales(xtask/src/cmd/mdbook/build.rs)中为该构建重新启用output.html.search.enable。
如何保持翻译的时效性
当英文源文件发生变化时,cargo mdbook sync 会执行两个阶段:
- 提取:
mdbook-xgettext会根据当前的英文源文件重新生成po/messages.pot。 - 合并:
msgmerge --no-fuzzy-matching更新每个语言环境的.po文件,为新增或已更改的源字符串赋予空的msgstr "",并移除过时的条目。只有在合并之前已存在的模糊条目,才可在后续审查或填充接受时继续使用。
然后该命令会统计模糊 + 未翻译的条目,并在指定 --model-provider 时只填充这些条目。未更改的字符串不会产生任何开销:.po 缓存意味着针对未更改的源重新运行是空操作。如果不指定 --model-provider,同步仍会执行提取 + 合并并报告差异;没有 msgstr 的字符串会在渲染时回退为英文。
Sync 使用稳定的输出规则(msgcat --sort-output --no-wrap --add-location=file)来规范化 catalog,因此 diff 仅聚焦于真实的源代码变更。无法避免的变动包括:header 元数据(如 POT-Creation-Date 等)、字符串在文件间移动时的引用位置更新,以及实际的源字符串编辑。
常规英文文档 PR 可将大范围的 .po 变更推迟到专门的后续跟进中处理。仅在以下情况包含 .po 更新:PR 是翻译缓存更新、发布翻译更新、新增语言区域,或产生的差异较小且便于审查时。
填充应用字符串(Fluent)
应用字符串位于 crates/zeroclaw-runtime/locales/ 中。英语是事实来源,并在编译时嵌入。
运行时加载边界。
- 嵌入式资源: 英语版
cli.ftl与tools.ftl已嵌入。builtin_cli_ftl_source()枚举由运行时嵌入的非英语 CLI 目录;zeroclaw-tools单独嵌入英语工具字符串,以保持 crate 依赖方向。- 磁盘覆盖层:
<config-dir>/data/ftl/<locale>/处的目录可覆盖嵌入的 CLI 值并提供已翻译的运行时/工具值。zeroclaw locales fetch用于填充此共享目录。- 使用注意事项: 填写并提交
.ftl文件会更新已跟踪的目录源,但只有当消费者的加载器嵌入该目录,或该文件安装在加载器可读取的位置时,消费者才会使用它。
apps/zerocodeTUI 维护着一份独立的 Fluent 目录(apps/zerocode/locales/),请参阅下方的 zerocode strings。cargo fluent会遍历两个目录根(runtime + zerocode),因此下面的每个子命令默认都会同时涵盖这两者。
sh
cargo fluent stats # 各语言环境、各目录的覆盖率
cargo fluent check # 校验两个语言目录的 .ftl 语法
cargo fluent fill --locale ja --model-provider anthropic.<alias> # fill missing keys (default batch 50)
cargo fluent fill --locale ja --model-provider anthropic.<alias> --batch 10 # 更小批次:每个请求处理更少条目(缓解速率限制/截断问题)
cargo fluent fill --locale ja --model-provider anthropic.<alias> --force # 重新翻译所有内容
cargo fluent scan # 查找与 Rust 源码相比过期或缺失的密钥
限定到单个目录:每个子命令都接受 --catalog <runtime|zerocode>(默认:两者)。若仅翻译 TUI:
sh
cargo fluent fill --locale ja --model-provider anthropic.<alias> --catalog zerocode
cargo fluent check --catalog zerocode # 仅语法检查 zerocode
未知的 --catalog 值会报错并列出有效的选项。
fill 会为每个具有 en/ 目录的选定目录树根生成 <locale>/<domain>.ftl:包括运行时的 cli.ftl/tools.ftl 以及 zerocode 的 zerocode.ftl。
提供方解析与运行时共享。 --model-provider 接受在 [providers.models.<kind>.<alias>] 下配置的任何别名:可以是裸别名(<alias>),在存在歧义时也可使用 kind.alias 限定符(anthropic.<alias>)。该工具会构建实际的运行时提供方,因此端点、认证标头和传输协议会按家族分别解析(Anthropic 的 /v1/messages + x-api-key、OpenAI 兼容的 /v1/chat/completions + Bearer 等等):不做任何假定。加密的 api_key 值会通过规范的 SecretStore 解密。使用 --config-dir <dir>(与 zeroclaw --config-dir 相对应)可从非默认位置读取配置和 .secret-key;默认位置为 ~/.zeroclaw,其次为 ~/.config/zeroclaw。
批处理: fill 每个批次发送一个请求(将所有 N 个条目作为单个 JSON 对象);--batch 可降低 N 值,以缓解服务商的速率限制或长条目的响应截断问题。每个批次在发送下一个请求之前都会写入磁盘,因此运行中途失败只会丢失正在处理的那个批次。重新运行时会跳过目标 .ftl 中已存在的键,因此可自动续传:无需使用 --force。
zerocode 字符串(Fluent,独立)
apps/zerocode 带有自己独立的 Fluent 配置,与上述运行时目录分离。该 TUI 有意与工作区的其余部分解耦:它不依赖 zeroclaw-* crate,并且其字符串与源代码放在一起,而非位于 zeroclaw-runtime/locales/ 之下。
| 在哪里 | 什么 |
|---|---|
apps/zerocode/locales/en/zerocode.ftl | 编译时嵌入的可信源 |
apps/zerocode/locales/<locale>/zerocode.ftl | 纳入版本控制的翻译目录源,用于 fill/fetch 和发布工作流;不会自动嵌入 |
$ZEROCODE_LOCALE_DIR/<locale>/zerocode.ftl | 显式覆盖,用于测试翻译 |
<config-dir>/data/ftl/<locale>/zerocode.ftl | 由 zeroclaw locales fetch 写入并由 zerocode 加载的共享的每用户目录 |
密钥命名空间
所有 zerocode 键都以 zc- 为前缀,绝不会与运行时的 cli-、channel- 或 tool- 命名空间发生冲突。zc- 内部的命名约定为 zc-<pane>-<purpose>:
zc-pane-<name>:顶级模式栏标签zc-app-<purpose>:由app.rs拥有的字符串(对话框、帮助、状态)zc-<pane>-<purpose>:特定窗格本地的字符串(zc-dashboard-*、zc-chat-*……)
和弦字面量不会被翻译
像 Ctrl+C、Esc、Shift+Up 这样的组合键字形属于协议,而非自然语言。HelpEntry 和 HelpNode 构造函数将组合键向量作为 &'static str 接收,将描述作为 String 接收,因此组合键字面量保持硬编码,而描述则通过 t() 传递。当文本中内嵌组合键时,请使用 { $keys } Fluent 占位符,并在渲染时传入组合键,而不是在字面量周围拼接翻译后的文本。
区域设置解析
Locale 来自 zerocode 配置中的顶层 locale 字段。未设置时,i18n::detect_locale() 会读取按以下顺序解析的配置目录:--config-dir,然后是 ZEROCLAW_CONFIG_DIR,再是 ~/.zeroclaw,否则回退到 en。zerocode 独立于其自身配置解析 locale;它不共享守护进程的查找逻辑。
添加字符串
- 将键 + 英文值添加到
apps/zerocode/locales/en/zerocode.ftl。按源文件对键进行分组,并添加分区注释,使目录保持易于浏览。 - 将源代码中的字面量替换为
crate::i18n::t("zc-…")。对于枚举→标签的match分支,请从fluent_key()方法返回键常量(&'static str),并在渲染处调用t(),切勿对字符串进行match。 cargo check -p zerocode和i18n单元测试(cargo test -p zerocode i18n)会在编译/测试时捕获缺失的键。运行时缺失的键会渲染为{zc-key-name}并发出一次性的 stderr 警告。
正在填充翻译
cargo fluent 会同时遍历 zerocode 目录和运行时目录,因此无需单独的填充命令。运行 cargo fluent fill --locale <code> --model-provider <alias> 会在填充运行时目录的同一过程中生成 apps/zerocode/locales/<code>/zerocode.ftl。cargo fluent check 和 cargo fluent stats 同样会报告 zerocode;scan 会为 apps/ 建立索引,因此 zc- 键引用可以针对 zerocode 的源文件解析。要在 zerocode 中体验翻译,请通过 zeroclaw locales fetch 安装它,或将其放在上述两个磁盘搜索根目录之一中。
填充文档翻译(gettext)
文档翻译位于 docs/book/po/。cargo mdbook sync 会一步运行 extract → merge → strip obsolete → AI-fill。如果不带 --model-provider,sync 仍会运行 extract + merge 并报告有多少字符串需要翻译:部分翻译在渲染时会回退到英文。
sh
cargo mdbook sync --model-provider anthropic.<alias> # delta fill
cargo mdbook sync --model-provider anthropic.<alias> --force # 质量检查:重新翻译所有条目
cargo mdbook sync --model-provider anthropic.<alias> --batch 1 # 每条记录后写入(最安全的恢复方式)
cargo mdbook sync --locale ja --model-provider anthropic.<alias> # single locale
cargo mdbook sync --model-provider anthropic.<alias> --config-dir ~/.zeroclaw # 限定别名 + 显式配置目录
--model-provider 通过与 cargo fluent 相同的共享运行时提供方路径进行解析(任何已配置的系列/别名、按系列设置的端点 + 身份验证 + 线路协议、SecretStore 解密、--config-dir 支持)。与将整个批次作为单个 JSON 对象发送的 cargo fluent 不同,gettext 填充器对每个源字符串发出一次请求,以保持 msgid → msgstr 映射的明确性,因此 --batch 控制的是 .po 刷新到磁盘的频率(检查点间隔),而非请求大小。完整目录的语言区域意味着数千次连续请求;对于日常增量填充,廉价的本地 Ollama 别名是经济之选。
该流水线具有内置的弹性:
- 泄漏检测:如果模型返回自身的指令而非翻译结果,工具会检测该模式(通过响应长度比例和项目符号列表结构),尝试从响应末尾恢复真实的翻译内容,若恢复失败则清空该条目以便重新翻译。
- 受保护字面量检查:
cargo mdbook check同样会拒绝生成的.po文件中高置信度的字面量损坏。诸如ZeroClaw Maturity Framework之类的产品名称、zeroclaw daemon之类的命令字面量,以及围栏 TOML 段/键字面量,在译文中必须逐字节保持完整。请翻译周围的叙述文字,而非面向机器的文本。 - 路径泄漏检查:生成的译文不得引入英文源文本中不存在的机器本地绝对路径;这些条目会被清空以重新翻译,并被
cargo mdbook check拒绝。 - 增量写入:每批处理完成后,都会重写
.po文件。运行过程中按下 Ctrl-C 不会丢失此前的处理进度。 - 过时条目清理:
msgmerge+msgattrib --no-obsolete可防止已移除的源字符串作为#~条目堆积。
维护者应接受 Building the docs locally 中记录的常规英文文档例外情况。仅当 PR 本身是翻译缓存更新、发布翻译更新、新语言区域变更,或生成的差异足够小可供审查时,才要求更新 .po 文件。
添加新的区域设置
-
编辑仓库根目录下的
locales.toml,这是你唯一需要修改的文件: -
翻译应用字符串:
sh
cargo fluent fill --locale <code> --model-provider ollama -
引导并填充文档
.po文件:sh
cargo mdbook sync --locale <code> --model-provider ollama -
步骤 2 中运行的
cargo fluent fill会在同一遍处理中生成apps/zerocode/locales/<code>/zerocode.ftl,因为cargo fluent会同时遍历运行时和 zerocode 两个目录。无需手动执行 zerocode 步骤;可使用cargo fluent stats验证覆盖情况。
其他所有内容,包括 lang-switcher.js、CI 部署目标列表以及 cargo mdbook locales 的输出,都会自动从 locales.toml 读取。
翻译目录子模块
翻译后的 .po 目录不在此仓库的主树中。它们位于专用的 zeroclaw-labs/zeroclaw-docs-translations 仓库中,并作为 git 子模块挂载在 docs/book/po(默认分支 main)。该挂载点对路径是透明的:book.toml 的 gettext 预处理器、cargo mdbook sync 和 cargo mdbook build 都会像之前一样精确读取 po/。
Rust crate 开发循环从不需要该子模块。只有文档构建以及 docs-deploy / release 作业需要它;这些检出都会传递 submodules: recursive。其他所有内容都保持不包含子模块。
每次发布时,scripts/release/refresh-translations.sh 会将变更的目录发布到子模块的 main 分支,将该提交标记为 v{version},检出该标签,并暂存主仓库的 gitlink。bump-version.sh 会有意将翻译固定留给该辅助脚本处理。messages.pot 和 *.failures.log 是重新生成的构建产物,在两个仓库中都被 Git 忽略,而不是受跟踪的文件。
发布翻译工作流
发布时的刷新、验证、打标签、推送和 gitlink 固定流程是发布运行手册中的第 2 步的一部分。本页面介绍翻译系统;准备发布时,请以运行手册作为操作依据。
模型质量说明
翻译质量因语言和模型的不同而有显著差异。
| 区域设置 | 得到充分支持的 | 备注 |
|---|---|---|
ja, zh-CN | qwen3 系列,任何前沿托管模型 | Qwen 以中文为首选;日语能力也很强 |
es, fr | qwen3、mistral、gemma3、托管 | 罗曼语族在广泛范围内训练良好 |
| 低资源语言环境 | 仅限托管的前沿模型 | 本地模型经常会出现幻觉 |
对于发布级别的传递,建议通过 --force 使用托管的前沿模型。在开发过程中进行持续的增量填充时,使用本地的 Ollama 模型即可,且免费。