翻译
了解 scribe translate 的工作原理:状态哈希、Gemini 集成、输出验证、成本估算以及审校工具。
View as MarkdownScribe 通过 LLM (Gemini) 将英文原文翻译成所有目标语言,并将结果直接存入 SQLite。你完全不需要手动修改多语言文件,只需编辑英文原文,重新运行 scribe translate,然后提交数据存储库即可。
翻译内容
每个文档中,只有两部分内容会被送入翻译引擎:
- 标记为
field.translatable()的 Frontmatter 字段,包含嵌套在数组和对象中的字段。 - MDX 正文。
其他所有内容(如 field.structural()、关联项以及内置字段)在加载时均会从英文文档中直接复制。在启用 slugStrategy: "localized" 的情况下,翻译引擎还会为每种语言生成对应的 URL 别名(采用 ASCII 风格的 kebab-case 格式,针对非拉丁语系进行音译处理)。
即使某种语言尚未完成翻译,也不会在运行时出现报错。resolve() 会通过语言回退链提供最接近的可用翻译(例如 pt-BR 会回退到 pt,接着回退到默认语言),让你可以逐步发布不同语言的内容。
过期状态追踪
每份入库的翻译都会记录其对应的英文原文内容的 SHA-256 哈希值。scribe translate 仅在以下情况才会重新翻译页面:
- 该语言的翻译尚未建立(缺失),或者
- 英文源内容已发生修改(过期)。
修改结构化字段或 _redirects.json 条目不会将翻译标记为过期,因为这些字段本身不需要翻译。
输出验证
只有通过以下两项检查,翻译结果才会被保存:
- 返回的 MDX 正文必须能够成功解析(系统会自动修复模型偶尔生成的错误转义字符和 JSX 属性引号问题)。
- 返回的 Frontmatter 必须通过你设定的完整 Zod schema 验证。
未通过验证的内容会在运行结束时自动重试一次,系统会将验证错误反馈给模型以便其自行修正(批处理模式会作为一个额外的批处理任务进行重试,并继续享受批量计费费率)。如果重试依然失败,系统会在最终总结里列出这些内容及最新的错误信息,同时命令会以非零状态退出。这就保证了错误的模型输出绝不会进入存储库,更不可能被带到生产环境。
运行命令
export GEMINI_API_KEY=... # also read from .env / .env.local
scribe status # coverage per type and locale
scribe translate # interactive picker in a TTY
scribe translate --locale fr de # specific locales
scribe translate --preset active # a localePresets group from the config
scribe translate --type blog # one content type (comma-separated: --type blog,glossary)
scribe translate --slug my-post # one document
scribe translate --dry-run # show the worklist + est. tokens/cost, write nothing
scribe translate --force # re-translate even when hashes match
scribe translate --strategy missing-only # skip stale, only fill gaps
scribe translate --batch # force batch mode (the default)
scribe translate --direct # per-page API calls, immediate results
scribe translate --resume # pick up pending batch jobs, submit nothing new
scribe translate --concurrency 5 # parallel requests (direct mode only)
scribe translate --model gemini-3.1-pro
在终端里执行时,scribe translate 会提供实时进度界面,展示批处理任务状态、每项内容的翻译结果、当前的 Token 消耗量以及预估的美元成本。思维链 Token 也计算在报告的使用量中,因此该预估值完全与 Google 的实际账单相符。如果想要逐行打印日志,可以传递 --no-progress 参数(或者在 CI 等非交互式环境中运行)。
--dry-run 只会打印待办列表而不写入任何数据,同时根据实际的提示词与英文负载大小,报告单项和总计的预估 Token 消耗及美元成本。在 --batch 模式下,预估成本会自动应用批量折扣,为你准确预览真实运行的开销。
最后请提交 .scribe/store.sqlite 文件。
批处理模式与断点续传
默认情况下,整个待办列表会通过 Gemini Batch API 处理,这种方式只需消耗直调成本的 50%。Scribe 会提前规划所有请求(每个模型一个任务,遇到超大任务列表时会分块处理),一次性提交全部任务,然后统一轮询,并在每个任务完成时立即保存结果。批处理任务通常几分钟内就能跑完,但 Google 只承诺在 24 小时内完成,因此该命令会持续等待,而不是逐页流式返回结果。
在开始轮询之前,每个任务及其提交时的英文原文快照都会记录到 SQLite 存储中。这种机制让你随时可以安全地中断操作:
- 轮询期间直接退出 (Ctrl+C) 绝不会丢失任何进度。
scribe translate --resume会检查挂起的任务,拉取已完成的结果,不再提交新的请求。- 正常运行
scribe translate也会优先恢复挂起的任务,处理中的项目绝对不会被重复提交。 - 在批处理期间修改英文页面完全没问题。系统会基于当时的翻译快照保存结果,并在下次运行时自动将其识别为过期。
想要按原价快速看到逐页的翻译结果?使用 --direct 就能恢复逐页的 API 调用,并支持通过 --concurrency 控制并发数。在终端中,交互式选择器也会提供相同的选项。无论是哪种模式,只要遇到临时性的 API 错误(如 429、5xx 或网络断开),系统都会通过指数退避机制自动重试。
翻译引擎引导
内置的提示词专为创译而非直译而设计。模型会化身为母语为目标语言的营销文案专家进行本地化创作。它会生动还原习语和文字游戏,摒弃字面翻译,并严格遵循当地语言的排版习惯(如引号、撇号以及标点符号的间距)。你配置的 context、rules 以及 prompt 都会在这个框架之上发挥作用。
项目级默认配置与按类型覆盖设置:
export default defineConfig({
translate: {
context: "MyBrand is a B2B SaaS. Never translate the brand name MyBrand.",
rules: ["Keep numbers and statistics accurate."],
},
types: [
defineContentType({
id: "blog",
// ...
translate: {
rules: [
"Preserve all MDX/JSX component tags, props, and URLs exactly.",
"Translate link anchor text; never change href paths.",
],
},
}),
],
});
| 选项 | 作用域 | 描述 |
|---|---|---|
context | 项目 + 类型 | 添加到每个请求前的品牌或领域上下文(项目级和类型级上下文会合并生效)。 |
rules | 项目 + 类型 | 追加在默认规则之后的额外规则。 |
prompt | 项目 或 类型 | 附加的本地化指令,添加在目标语言指令之前(语言名称和代码会自动追加)。 |
defaultModel / model | 项目 / 类型 | Gemini 模型 ID。默认为 gemini-3.1-pro(也可以通过 PROSE_GEMINI_MODEL 环境变量或 --model 参数覆盖)。 |
内置的必选规则包括:除非品牌在目标市场有广为人知的本地名称,否则不翻译品牌名;返回包含真实换行符而非转义符的 MDX 正文;以及在值包含双引号时,自动修复 JSX 属性引号。
翻译审校
scribe history blog my-post fr # EN snapshot timeline for one page
scribe studio # read-only web UI on :3600
每份翻译都会链接到生成它时的英文原文快照(存储在同一个 SQLite 文件中),方便你随时审计页面被翻译的时间、原内容以及使用的模型。scribe history 会打印出这条时间线。工作室界面则会展示各语言的覆盖率、当前缺失或过期的待办列表,并提供详细的单文档视图,将快照与最终入库的翻译并排显示。
语言预设配置
如果是为了渐进式发布,可以在配置中对语言组进行命名,并通过 --preset 指定目标:
localePresets: {
active: ["fr", "es", "ja"],
ultraLight: ["fr"],
}
scribe translate --preset ultraLight