如何用一个 Agent 将一篇博文翻译成 13 种语言
单个 TypeScript agent 并行调用 Claude API,在 90 秒内将一篇英文文章翻译为 12 种语言。保留写作风格需要两段式系统提示:先是风格约束,然后是语言特定说明。使用 Haiku 每篇文章的成本约为 $0.004–$0.02。我的网站在 60 天内国际流量增长了 34%。
每周三。28,400+ 读者。纯干货。
✓ Check your inbox — click the confirmation link to complete sign-up.
✓ You're subscribed!
✓ You're already on the list.
目录
2026 年 5 月更新。
TL;DR: 单个 TypeScript agent 并行调用 Claude API,在 90 秒内将一篇英文文章翻译为 12 种语言。保留写作风格需要两段式系统提示:先是风格约束,然后是语言特定说明。使用 Haiku 每篇文章的成本约为 $0.004–$0.02。我的网站在 60 天内国际流量增长了 34%。
[运营者视角] 我每次发布新文章都会运行这个 agent。它已处理了 341 篇文章的 12 种语言版本,而我从未手动修改过任何一篇翻译。下面详细说明它的工作原理。
为什么我选择构建翻译 agent 而不是雇佣翻译人员
多语言 SEO 的价值我就不赘述了——你应该已经明白它的重要性。我面临的问题是工作流程。每篇文章都雇佣翻译人员成本极高($40–$120/篇 × 12 种语言 = $480–$1,440/篇),速度慢(交付周期 3–7 天),而且当你有 341 篇存量文章需要追赶时,根本无法批量处理。
另一个常见建议是使用 Google Translate 或 DeepL。两者准确度尚可,但会破坏写作风格。我的写作风格是直接、第一人称、略带反常规。机器翻译倾向于让一切听起来正式而被动。当风格一致性是品牌的一部分时,这就是个问题。
于是我构建了一个基于 Claude 的 TypeScript agent。它在每次合并到 main 时在 CI 中运行,并行分发翻译任务,将文件写回磁盘,并跳过已有文件的任何语言。对于一篇新文章,整个过程在 90 秒内完成。
项目结构
agent 位于 scripts/agent/translate-worker.ts,由上层编排器调用——编排器读取英文文章、提取 frontmatter,并为每种语言分发一个翻译任务。
scripts/
agent/
translate-worker.ts # 每个语言的翻译逻辑
translate-all.ts # 编排器:读取 EN,分发到 12 种语言
lib/
frontmatter.ts # 解析/序列化 gray-matter frontmatter
voice-prompt.ts # 共享系统提示构建器编排器(translate-all.ts)使用 Promise.allSettled,因此单个语言的失败不会阻塞其余任务。
系统提示的设计
这是大多数人犯错的地方。他们写了一行指令:“把这翻译成法语,保留作者的风格。“这只会产生平庸的结果。
我的系统提示有两个必需部分:
第一部分——风格约束(通用,添加到每次调用的开头):
// scripts/agent/lib/voice-prompt.ts
export function buildSystemPrompt(targetLocale: string): string {
const styleConstraints = `
You are a professional translator working on blog posts written by Alejandro Rioja.
STYLE RULES — apply to every locale:
- Short paragraphs (1–3 sentences max). Do not merge them.
- First-person, direct voice. Never passive if active is natural.
- No filler phrases: no "In today's world", no "It is worth noting that".
- Preserve all markdown: headings, bold, italics, code blocks, links.
- Translate heading text but keep the ## / ### prefix exactly.
- Code blocks: translate comments only. Keep all variable names, strings, and syntax in English.
- Preserve frontmatter keys exactly. Only translate the VALUES for: title, ogTitle, description, tldr, imageAlt.
- Keep these frontmatter values UNCHANGED: pubDate, updatedDate, translation_key, tags, image, author, draft, lang (set lang to: ${targetLocale}).
`.trim();第二部分——语言特定说明(每次调用时追加):
const localeNotes: Record<string, string> = {
ar: "Arabic: use Modern Standard Arabic (MSA). RTL layout is handled by the CMS — do not add any RTL markup. Avoid overly formal Classical Arabic registers.",
de: "German: use informal 'du' not formal 'Sie'. Compound nouns are fine; don't over-hyphenate. Keep tech terms in English when that's the industry standard (e.g. 'Content Marketing', 'SEO').",
es: "Spanish: use neutral Latin American Spanish, not Castilian. Tuteo ('tú') over 'usted'. Keep anglicisms that are standard in tech (SEO, agente, prompt).",
fr: "French: use informal 'tu'. Avoid over-formalizing. Tech anglicisms are acceptable when widely used (SEO, agent, prompt).",
hi: "Hindi: use Devanagari script. Mix Hindi and English naturally for tech terms — this is standard in Indian tech writing. Don't force Hindi equivalents for words like 'agent', 'prompt', 'SEO'.",
it: "Italian: use 'tu' form. Keep English tech terms where they're standard in Italian digital marketing.",
ja: "Japanese: use です/ます (polite) style, not casual or keigo. Keep technical English terms in katakana where standard (e.g. エージェント, プロンプト, SEO).",
ko: "Korean: use 합쇼체 (formal polite). Tech terms in English or standard Korean loanwords. Keep SEO, agent, prompt as-is or standard loanwords.",
nl: "Dutch: use 'je/jij' (informal). Keep English tech terms standard in Dutch digital marketing.",
pt: "Portuguese: use Brazilian Portuguese (pt-BR). Informal 'você'. Keep tech anglicisms standard in Brazilian digital marketing.",
ru: "Russian: use modern, accessible Russian. Avoid overly bureaucratic phrasing. Tech terms can stay in English where that's the norm in Russian tech writing.",
zh: "Chinese: use Simplified Chinese (zh-CN). Modern, accessible tone. Tech terms can use standard Chinese equivalents or keep English where that's industry norm.",
};
return `${styleConstraints}\n\nLOCALE-SPECIFIC NOTES for ${targetLocale}:\n${localeNotes[targetLocale]}`;
}翻译 worker
以下是完整的 worker。它读取 EN 文件,调用 Claude,并将输出写入磁盘。
// scripts/agent/translate-worker.ts
import Anthropic from "@anthropic-ai/sdk";
import * as fs from "fs";
import * as path from "path";
import { buildSystemPrompt } from "./lib/voice-prompt";
const client = new Anthropic();
export interface TranslateJob {
enFilePath: string;
locale: string;
outputDir: string;
model?: "claude-haiku-4-5" | "claude-sonnet-4-5";
dryRun?: boolean;
}
export async function translatePost(job: TranslateJob): Promise<string> {
const { enFilePath, locale, outputDir, model = "claude-haiku-4-5", dryRun = false } = job;
// 幂等性:如果翻译已存在则跳过
const filename = path.basename(enFilePath);
const outPath = path.join(outputDir, locale, filename);
if (fs.existsSync(outPath)) {
console.log(`[${locale}] 已存在 — 跳过:${outPath}`);
return outPath;
}
const enContent = fs.readFileSync(enFilePath, "utf-8");
const systemPrompt = buildSystemPrompt(locale);
const message = await client.messages.create({
model,
max_tokens: 8192,
system: systemPrompt,
messages: [
{
role: "user",
content: `Translate the following blog post to ${locale}. Return ONLY the translated markdown file content — no explanation, no preamble, no code fences around the whole file.\n\n${enContent}`,
},
],
});
const translated = (message.content[0] as { type: string; text: string }).text;
if (!dryRun) {
fs.mkdirSync(path.join(outputDir, locale), { recursive: true });
fs.writeFileSync(outPath, translated, "utf-8");
console.log(`[${locale}] 已写入:${outPath}`);
}
return outPath;
}编排器
// scripts/agent/translate-all.ts
import * as path from "path";
import * as fs from "fs";
import { translatePost } from "./translate-worker";
const LOCALES = ["ar", "de", "es", "fr", "hi", "it", "ja", "ko", "nl", "pt", "ru", "zh"];
const POSTS_DIR = path.resolve("src/content/posts");
const MODEL = (process.env.TRANSLATE_MODEL as "claude-haiku-4-5" | "claude-sonnet-4-5") ?? "claude-haiku-4-5";
async function main() {
// 接受特定文件或翻译所有 EN 文章
const targetFile = process.argv[2];
const enFiles = targetFile
? [path.resolve(targetFile)]
: fs.readdirSync(path.join(POSTS_DIR, "en")).map((f) => path.join(POSTS_DIR, "en", f));
console.log(`正在翻译 ${enFiles.length} 篇文章 × ${LOCALES.length} 种语言。模型:${MODEL}`);
for (const enFile of enFiles) {
const results = await Promise.allSettled(
LOCALES.map((locale) =>
translatePost({
enFilePath: enFile,
locale,
outputDir: POSTS_DIR,
model: MODEL,
})
)
);
results.forEach((r, i) => {
if (r.status === "rejected") {
console.error(`[${LOCALES[i]}] 失败:`, r.reason);
}
});
}
console.log("完成。");
}
main();运行方式:
# 翻译单篇新文章
npx ts-node scripts/agent/translate-all.ts src/content/posts/en/my-new-post.md
# 翻译所有文章(幂等——跳过已存在的)
npx ts-node scripts/agent/translate-all.ts成本对比:Haiku vs Sonnet
根据我的实际使用情况,每篇文章的真实成本:
| 模型 | 输入 token(均值) | 输出 token(均值) | 每种语言成本 | × 12 种语言成本 |
|---|---|---|---|---|
| claude-haiku-4-5 | ~2,400 | ~2,600 | ~$0.0004 | ~$0.005 |
| claude-sonnet-4-5 | ~2,400 | ~2,600 | ~$0.015 | ~$0.18 |
Haiku 处理 341 篇 × 12 种语言:总计约 $1.70。这就是整个积压内容的成本。
Sonnet 的地道表达略胜一筹,但对大多数文章来说,这点差异不值 36 倍的价格。我只在需要细腻说服力语气的文章(如销售页面或高流量的核心内容)时才使用 Sonnet。
可以通过 TRANSLATE_MODEL 环境变量在每次运行时切换模型:
TRANSLATE_MODEL=claude-sonnet-4-5 npx ts-node scripts/agent/translate-all.ts src/content/posts/en/flagship-post.md真实结果:我的流量发生了什么
我在 2025 年 12 月完成了整个积压内容(341 篇)的翻译发布。60 天内:
- 自然搜索访问量增长 34%(全站,Google Search Console,2026 年 1–2 月 vs 2025 年 10–11 月)
- 访问量最高的新语言: 巴西葡萄牙语(pt)——占新增国际流量的 11%
- 转化率最高的新语言: 德语(de)——咨询预约率 2.1%,高于全球均值 1.8%
- 表现最差: 阿拉伯语(ar)——有流量进来但零转化。我怀疑预约流程在文章内容以外没有做本地化。
- 日语(ja)和韩语(ko): 流量显著增长(分别占国际访问的 8% 和 6%),参与度高于平均水平(页面停留时间比英文基准高 40%)
日语和韩语的结果出乎我意料。这两种语言都有高质量的 AI 社区,对实操性运营内容显然有真实需求。
运营者的结论
一个 agent,一小时配置,$1.70 API 成本。这就是让 341 篇文章在 12 种额外语言中可被搜索到所需的全部投入。仅 SEO 提升就在第一周覆盖了计算成本。如果你经营着内容丰富的网站,却还没构建这套流程,你正在放弃国际流量。以上代码就是完整实现——fork 它,换上你的 voice-prompt 说明,今晚就在你的积压内容上运行。
每周三。28,400+ 读者。纯干货。
✓ Check your inbox — click the confirmation link to complete sign-up.
✓ You're subscribed!
✓ You're already on the list.
将AI实战手册发送到您的邮箱
每周三。28,400+ 读者。纯干货。
Check your inbox.
We sent you a confirmation email — click the link inside to complete your subscription. Check spam if you don't see it within a minute.
You're subscribed.
Welcome — the next edition lands in your inbox soon.
You're already on the list — look for it every Wednesday.