有谷大脑
返回博客

翻译一篇 PDF,难的不是调模型,是把译文插回对的位置

译文比原文长、链接不能断、代码不能翻、第 286 页失败不能整本重跑。有谷可译用稳定 blockId 和占位符保护,把双语写回 HTML、PDF 和 EPUB。

把一段英文交给翻译 API,再把中文拼到后面——几十行代码就够。

处理一本 400 页的技术手册,还要输出可读的双语 PDF,事情复杂得多:代码不能被翻译,表格不能串行,链接仍要可点击,页码不能失真,翻译到第 286 页失败不能整本重跑,术语表更新后要知道哪些块该重译。

有谷「可译」产品和阅读器里的翻译功能,核心工程问题都是同一个:把译文准确地插回原处。模型只返回受约束的文本,不能决定 DOM 结构、PDF 坐标或 EPUB 的 spine 路径。

双语翻译:分块与占位符保护 → 术语约束翻译 → 双语对照或原位写回。

翻译单元 ≠ 视觉块

浏览器里的一个段落可能由文本、链接、粗体术语和代码 组成;PDF 里视觉上的一个段落可能被拆成几十个绘制指令;EPUB 的一章可能跨多个 XHTML 文件。

若把「能提取出的字符串」直接当翻译单元,很快会遇到五类故障:

  1. 结构破坏 — <a>、MathML、代码片段一并送去翻译,返回后无法恢复合法结构
  2. 顺序错误 — PDF 双栏按坐标排序后左右穿插,页眉脚注混入正文
  3. 锚点漂移 — 用文本内容做唯一定位,源文档更新后写回到错误位置
  4. 版面爆炸 — 译文通常更长,固定 PDF 文本框溢出,表格行高失控
  5. 不可运维 — 失败后只能整本重跑;术语表改了不知道哪些块失效

因此需要两个概念:

  • 语义块(semantic block) — 标题、段落、列表项、表格单元格、图注等,是写回和质量检查的 stable unit
  • 翻译单元(translation unit) — 为模型上下文临时合并多个块,或把超长块切分;但每块原文的 blockId 必须不变

可以把连续 8 个段落放进同一上下文窗口翻译,结果必须按 stable ID 拆回 8 个块。

Document IR:跨格式共用的中间表示

HTML、PDF、EPUB 底层模型完全不同,但双语流水线共用一层 Document IR(中间表示):

  • 每块有稳定的 blockId(不用数组下标)
  • sourceAnchor 记录来源:HTML 用 DOM path,PDF 用 page + bbox + 阅读序,EPUB 用 spine + element path
  • inlineTokens 保存 code、link、公式等占位符
  • translatedText 与原文块一一对应
  • status 跟踪 segmented → translating → approved → rendered

写回时组合定位:结构位置 + 前后邻居特征 + 内容校验和。对不上就在有限范围内重定位,仍有歧义进人工队列——不「找一个最像的地方」自动写入。

占位符:内联对象必须先保护

<p>Run <code>npm install</code>, then read <a href="/guide">the guide</a>.</p>

抽取层应变成:

Run ⟪PH_001:CODE⟫, then read ⟪PH_002:LINK_START⟫the guide⟪PH_003:LINK_END⟫.

模型只允许成对移动这些标记,不得改 ID 或造新标记。写回前检查占位符 multiset 是否相等,再把原始节点恢复。URL、变量、公式、产品型号、命令行、模板占位符({name}、%s)用同一机制保护。

这和长文术语库里「解释不能污染全局定义」是同一类问题:翻译时也要把「不能动的东西」和「要翻的东西」分开。

两种写回场景

文档成品(HTML / PDF / EPUB) — 你拥有源文件结构,写回器按格式分别把译文写入 DOM、PDF 内容流或 EPUB XHTML。支持双语对照版(原文块下插入译文块)和仅译文版。

网页实时翻译 — 你不拥有 DOM:站点随时重渲染,自己插入的节点不能触发无限循环。做法是按视口标记段落、视口外不立刻翻译;写回分双语对照(译文插在原文后)和原位替换(尽量改宿主文本节点)。

阅读器里打开一篇外文 PDF,通常走文档成品路径;浏览器插件翻译当前 Tab,走实时 DOM 路径——共用「stable block + 占位符」思想,不共用写回器。

术语表与断点续跑

企业手册翻译绕不开术语一致。「API Gateway」不能一段译「API 网关」、一段译「接口网关」。有谷在调度层注入术语表和翻译记忆库(TM):已批准译法优先匹配,新块继承同一约束。

流水线按块持久化状态:翻译到第 286 块失败,从该块续跑,不必重翻前 285 块。术语表更新后,可以按 blockId 失效受影响的块,局部重译。

质量门禁在块级做:占位符完整性、数字/unit 一致、错语种、异常长度、漏译——低置信块不进成品,进人工复核队列。

和阅读器、知识库的关系

  • 可译 — 面向多格式文档翻译交付,版式还原和术语一致是产品承诺
  • 阅读器 — 已入库的外文资料可在阅读界面发起翻译,译文写回后可在分块渲染环境里继续划线和问答
  • 知识库 — 翻译后的 bilingual 版本可作为新文档入库,RAG 检索中英内容;原文 chunk 与译文 chunk 可关联,避免重复索引时语义分裂

翻译是「读」的延伸,不是独立工具。把译文插回对的位置,和网页收藏把干净正文送进索引一样——下游体验取决于上游有没有尊重格式结构。