一篇文章 19 种语言:文件结构、翻译 prompt、5 个真实翻车点、如何一次 POST。
Anthropic 和 OpenAI 的官方文档只有英文。这是全球 AI 开发者内容生态一个很大的空白。how2claude 正在做的事就是填这个空白——每篇文章同时发 19 种语言:zh / en / zh-TW / ja / ko / es / pt-BR / id / vi / tr / ar / fr / de / it / ru / uk / pl / he / th。
让人做这事不现实(一篇文章 20 个人工译本,每篇成本几千美金)。让 Claude 做,边际成本接近零——但直接甩一句 "翻成 ja" 过去会得到机翻味十足、作者声音全无的稿子。本文是这事做对的完整流程:文件结构、翻译 prompt 怎么写、哪些地方 Claude 一定会翻车、怎么把 19 种语言 + 每种语言的推文一次 POST 到 API。
这两个词区别很大。
翻译是把 A 语言的意思搬到 B 语言——Google Translate 干的事。结果读起来"对",但是"平"。
本地化是保持原文的语气、节奏、专业度,用目标语言读者的"技术博客语气"重写。结果读起来像母语写的。
让 Claude 做翻译是 5 分钟的事;让 Claude 做本地化需要 prompt 里明确:
how2claude 的 /write-article 命令里给每种语言都写了风格要求:
| 语言文件 | 风格要求 |
|---|---|
ja.md |
技术博客语气,自然日语 |
ko.md |
技术博客语气,自然韩语 |
zh-TW.md |
台湾用语习惯,繁体字 |
ar.md |
标准阿拉伯语(现代书面语) |
id.md |
标准印尼语 |
看起来只是一句话的差别,但对 Claude 来说是关键——没有这句它会默认生成"教科书译本"。
每篇草稿一个目录,20 个文件:
docs/drafts/let-claude-translate-articles/
├── meta.json # 所有 19 种语言的 title + summary
├── zh.md # 中文(原文,最先写)
├── en.md # 英文(第一批翻译)
├── zh-TW.md
├── ja.md
├── ko.md
├── ...(其余 14 种)
└── th.md
meta.json:
{
"category_slug": "use-cases",
"series_slug": "writing",
"free": true,
"title": {
"zh": "让 Claude 把一篇文章翻译成 19 种语言",
"en": "Letting Claude Translate One Article Into 19 Languages",
"ja": "Claude に 1 本の記事を 19 言語に翻訳させる",
"...": "..."
},
"summary": {
"zh": "一篇文章 19 种语言:文件结构、翻译 prompt、5 个真实翻车点、如何一次 POST。",
"...": "..."
}
}
每个 .md 文件第一行是 # 标题,后面是正文。title 不从 md 第一行取,从 meta.json 取——这样每种语言的 title 都是经过专门润色的短句,而不是文章里那句可能已经被翻长了的标题。
两种流程会走错:
错的:链式翻译。zh → en → ja → ko → ...
问题是:ja 基于 en、ko 基于 ja,每跳一次都丢一点原意。到了 th(泰语)已经是四手信息了。
对的:辐射式翻译。zh 写完定稿 → 基于 zh 一次性翻出 en / ja / ko / ar / id / ...
每种语言都直接从原文生成,不走中间跳板。
具体 prompt 结构(/write-article 里封装好了):
这是一篇关于 X 的技术博客,中文原文:
[zh.md 全文]
请翻译成以下语言,每种语言的要求:
- ja.md: 技术博客语气,自然日语
- ko.md: 技术博客语气,自然韩语
- ar.md: 标准阿拉伯语(现代书面语)
...
要求:
1. 保留作者的直接、专业、略带自嘲的语气
2. 代码块、命令、API 名、URL 不翻
3. 标题、小标题、段落行文允许重组
4. title 另出一条,要短、有钩子,不是原标题的直译
并行翻译 18 种语言,Claude 一次 session 搞定。重要的一点:在同一个 session/同一个模型版本里做——跨会话或跨模型 voice 会漂移。
X 给 CJK 字符(中、日、韩)更严格的计数。我让 Claude 生成推文时给过这样的要求:
第一次生成中文推文时,三条超了(160、164、152 字)。因为 Claude 把英文推文直译过来——英文 260 字符翻成中文正好踩线。
规律:中文推文必须重写不是翻译。要求:140 字上限、要有钩子、可以损失一点细节。
zh → zh-TW 最容易犯懒:丢给转换器把简体转繁体。结果是字对了,词没对:
| zh | zh-TW(错) | zh-TW(对) |
|---|---|---|
| 文件 | 文件 | 檔案 |
| 信息 | 信息 | 資訊 |
| 软件 | 軟件 | 軟體 |
| 视频 | 視頻 | 影片 |
让 Claude 翻 zh-TW 时必须明确:"台湾用语习惯,繁体字"——两句都要有。只说"繁体"会得到字转换。
阿拉伯语、希伯来语从右往左写。Rails 侧要在 <html dir="rtl">,Tailwind 用 rtl: 变体。但翻译本身也会踩坑:
unicode-bidi: isolate 不然代码会被"吸"到 RTL 方向里، 代替 ,,用 ؟ 代替 ?。Claude 默认会用英文标点,要明确要求2026),但整个段落流向是右到左。这个浏览器会处理,但 Claude 写的时候经常乱原文里的口语("一把梭"、"踩坑"、"翻车")Claude 翻成日语韩语默认会变成书面表达(「一気に実装」「落とし穴」「失敗」)——意思对,但作者的语气没了。
修法:prompt 里明确 "保留原文的直接、略自嘲、不拘礼的技术博客语气,不要学术化"。即使这样,某些语言(德语、俄语)还是会比原文"正"一点——语言本身有书面 bias。
代码里的字符串,有些是 UI 文字(要翻),有些是占位符/变量名(不能翻):
t("pricing.page_title") # 不翻(i18n key)
"user_id" # 不翻(变量名)
"Monthly subscription" # 如果在文中作为示例展示给读者看 → 不翻
和代码相关的字符串,默认不翻比较安全。真要翻的是 i18n locale 文件(config/locales/xx.yml),那是另一回事。
/publish-article 命令把草稿 POST 到 how2claude.com/api/articles:
{
"category_slug": "use-cases",
"series_slug": "writing",
"free": true,
"thread": true,
"title": { "zh": "...", "en": "...", "ja": "...", ... },
"summary": { "zh": "...", "en": "...", ... },
"content": { "zh": "<md>", "en": "<md>", ... },
"tweets": { "en": ["...", "..."], "zh": [...], ... }
}
一个请求 300KB 左右(19 种语言 × 约 15KB)。服务端拆到数据库:
articles 表,title / summary / content 是 jsonb,按 locale 存x_queue_tweets 表按 locale + account 分发,推文排期进队列Tweet 只发给有连接 X 账户的 locale(当前是 en/zh/ja/ko/ar/id 6 个),没连接账户的语言 tweets 传 []。查账户:
Account.all.each { |a| puts "#{a.locale}: #{a.name}" }
# en: @how2claude
# zh: @howtoclaude
# ja: @how2claude_ja
# ko: @how2claude_ko
# ar: @how2claude_ar
# id: @how2claude_id
让 Claude 把一篇文章翻译成 19 种语言的完整清单:
dir="rtl" + Tailwind rtl: 变体。标点混排、代码块隔离要单独处理。真正的瓶颈不是翻译质量——Claude 4 级模型翻成日韩阿拉伯俄文的质量都接近母语。瓶颈是你肯不肯把一篇文章分发到 19 种语言的读者面前。技术上 5 分钟能跑完,内容上只要你愿意同时服务 200 倍的人。