接上回:48小时翻译 Qi 的 OPE 新书——那次用 DeepSeek V3 完成了中→英翻译,三个月后,Qi 又来了新需求:法语版和日语版。
这一次,翻译引擎换代了。
换引擎:从 DeepSeek 到 Claude Opus 4.6
上次翻译用的是 DeepSeek V3 直连 API,temperature=1.3(DeepSeek 官方推荐的翻译温度)。效果很好,但这次我想试试不同的模型。
恰好,我的 CopilotX 项目最近稳定下来了——它把多种模型统一包装成 OpenAI-compatible 接口,部署在 api.polly.wang,模型切换只需改一个配置项。
Claude Opus 4.6 是目前可用的最强模型之一。翻译这种需要精确、忠实的任务,正是它的强项。
改造 Master Translator 的 llm_provider.py 只需要三处:
- 添加模型配置——
claude-opus-4.6,provider 设为copilotx - 添加路由逻辑——在
complete()方法里加一个 CopilotX 分支 - 实现直连方法——
_complete_copilotx(),流式传输,复用连接池
Temperature 设为 0.1。翻译不需要创造性,需要的是确定性输出。这和 DeepSeek 的 1.3 完全不同——那个值是 DeepSeek 针对自家模型的特殊优化,不能套到 Claude 上。
分块大小从 8000 调到 12000。Claude Opus 4.6 的 max_tokens 是 16384,比 DeepSeek 宽一倍。更大的分块意味着更少的边界、更连贯的翻译。
术语表:278 个术语的双语扩展
长文档翻译的灵魂是术语表——ContextWeave 的 Context Weaving 机制会把术语注入每个分块的 prompt 里,确保全书一致。
上次做英文版时已经有了 ope_zh_en_optimized.json(278 个术语)。这次要做的是基于它生成中→日和中→法两个版本。
策略很简单:把 278 个术语分成 4 批,每批 70 个,发给 Claude Opus 4.6,让它在英文翻译的参考下生成对应的日语/法语翻译。
prompt = f"""Translate the following Chinese terms to {target_lang}.
Each term has its English translation as reference context.
Return ONLY valid JSON."""
几个有意思的翻译选择:
| 中文 | 日语 | 法语 | 点评 |
|---|---|---|---|
| 个体创业者 | 一人起業家 | Solopreneur | 日语造了新词,法语直接用英文借词 |
| 人机协同 | 人間とAIの協働 | Collaboration humain-IA | 日语用了"人間"而非"人",更正式 |
| 出海 | 海外展開 | Expansion internationale | 三种语言三种视角 |
| 全球化 | グローバル化 | Mondialisation | 法语坚持用自己的词,不用 Globalisation |
| 低代码 | ローコード | Low-code | 都是直接音译/借用 |
8 次 API 调用(4 批 × 2 语言),全部成功。术语表生成完毕。
双线翻译:30万字 × 2
万事俱备,启动翻译。
法语先行:
translate_document(
document_path="ope_formated.md",
target_language="french",
terminology_file="ope_zh_fr.json"
)
32 个分块,5 路并发,零失败。29 分钟完成。
紧接着日语:
translate_document(
document_path="ope_formated.md",
target_language="japanese",
terminology_file="ope_zh_ja.json"
)
同样 32 块零失败,31 分钟。
两个语言的扩展比差异非常有趣:
| 语言 | 输入 | 输出 | 扩展比 |
|---|---|---|---|
| 法语 | 291,858 字符 | 1,193,303 字符 | 4.09x |
| 日语 | 291,858 字符 | 436,172 字符 | 1.49x |
法语的 4.09x 远超预期的 2.5x——法语的语法结构(冠词、介词、动词变位)确实让文本膨胀得厉害。日语的 1.49x 则很合理,中日共用汉字体系,很多术语可以直接对应。
pandoc 与法语重音符的战争
翻译搞定了,接下来是 Word 转换。上次英文版用 pandoc 很顺利,这次我以为也一样。
pandoc ope_formated_french_parallel.md \
-o ope_formated_french_pandoc.docx \
--embed-resources --standalone --mathml
打开 Word 文件,表格全没了。
原文有 10 个 HTML <table> 标签。检查 pandoc 的内部 AST:
pandoc file.md -t json | python3 -c "
import json, sys
d = json.load(sys.stdin)
tables = [b for b in d['blocks'] if b['t']=='Table']
print(f'Table blocks: {len(tables)}')
"
# 结果:Table blocks: 0
直接就不认。
排查过程
假设 1:HTML 表格没被解析?→ 对,pandoc 的 markdown 格式默认开启 raw_html 扩展,会把 HTML 表格当作 raw block 直通,不做解析。
尝试 1:把 HTML 表格预处理成 markdown 表格语法(| --- |)→ 正则替换成功,10 个 HTML 表格变成 16 个 markdown 表格。
# HTML <table> → Markdown |table|
result = re.sub(
r'<table>.*?</table>',
html_table_to_md,
content, flags=re.DOTALL
)
再转 → 还是 0 个表格。
尝试 2:单独提取一个表格片段测试 → 成功,1 个表格。说明表格格式没问题,问题在全文上下文。
突破口:检查文件编码时发现法语特殊字符(È → Ère de l'IA)在 cat -v 下显示异常。长文件中法语重音符触发了 pandoc docx writer 的序列化 bug。
最终方案——两步转换:
# Step 1: md → HTML(pandoc 内部正确识别了 10 个表格)
pandoc input.md -o intermediate.html --standalone --mathml
# Step 2: HTML → docx(绕过 md→docx 的编码 bug)
pandoc intermediate.html -f html -o output.docx --standalone
Tables: 10 ✅
日语版也用同样的流程处理后,从 4 个表格变成 10 个。最后用 python-docx 给所有表格加上实线边框:
border_xml = '''<w:tblBorders>
<w:top w:val="single" w:sz="4" w:color="000000"/>
<w:insideH w:val="single" w:sz="4" w:color="000000"/>
<w:insideV w:val="single" w:sz="4" w:color="000000"/>
...
</w:tblBorders>'''
for table in doc.tables:
table._tbl.tblPr.append(parse_xml(border_xml))
最终交付
| 语言 | 术语表 | 正文 (md) | 正文 (Word) | 序言 |
|---|---|---|---|---|
| 法语 | 278 terms | ✅ 32 块/0 失败 | ✅ 10 表格+边框 | ✅ |
| 日语 | 278 terms | ✅ 32 块/0 失败 | ✅ 10 表格+边框 | ✅ |
模型:Claude Opus 4.6 via CopilotX。
一个人的出版社
上次翻完英文版时,我写道"用践行 OPE 的方式,翻译阐述 OPE 的书籍"。
今天这个闭环更大了。
422 页的书,现在有了英、法、日三个语言版本。术语表构建、翻译引擎、质量验证、Word 排版——全部一个人完成,全部用 AI 驱动。如果算上三个月前的英文版,这本书的翻译工作量大概相当于一个小型翻译公司几周的产出。
Qi 在书里写道:
"一个人,加上 AI,组成一个完整的团队——并解锁无限可能。"
现在这本书自己正在证明这件事——从北京到东京到巴黎,用的就是一个人和一台笔记本电脑。
这是 Master Translator 的第 6 和第 7 次翻译任务——同一本书,两个新语言。引擎从 DeepSeek V3 升级到 Claude Opus 4.6,pandoc 的表格 bug 让我学会了 md→HTML→docx 两步法。下一个语言会是什么?也许是阿拉伯语——该测试一下从右到左的排版了。

