☰
翻译一篇 PDF,难的不是调模型,是把译文插回对的位置
2026/9/30 7:18:08 网站建设 项目流程

一段英文交给模型,几秒钟就能得到中文。可把一本几百页的技术手册做成双语 PDF,问题往往出在翻译之后。

原文写着:

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

理想的结果是:“运行npm install,然后阅读指南。”命令保持原样,“指南”仍然可以点击。

如果把整个 HTML 节点直接交给模型,译文可能改掉命令、丢掉链接,或者生成一段看起来正确、却无法放回原节点的文本。PDF 还要面对双栏阅读顺序、表格、坐标和分页。模型翻对了,不代表双语文档就做对了。


图 1:从文档解析到双语写回的主要环节。

一、为什么“提取文字 → 翻译 → 拼回去”容易出错?

HTML 的一个段落里可能混有文字、代码、链接和公式。PDF 中看起来连续的一段话,底层可能是几十个独立绘制的文本片段。EPUB 的一章也可能分布在多个 XHTML 文件中。

直接按字符或固定 Token 数切分,容易遇到四种情况:

  • **切错顺序:**PDF 双栏的左右两列被交替拼接,页眉或脚注混进正文。
  • **丢失结构:**链接、代码或公式与普通文字一起翻译,写回时无法恢复原节点。
  • **找错位置:**只凭原文字符串定位;相同句子在文档里出现多次,译文可能放错段落。
  • **撑坏版面:**译文长度改变,固定文本框溢出,表格行高和分页随之变化。

所以第一步不是决定“每段多少 Token”,而是先识别:文档里哪些内容属于同一个语义块,哪些内容虽然出现在块内,却不能让模型改动。

二、先给原文块一个稳定身份

标题、段落、列表项、表格单元格、图注,可以分别成为语义块。每个块记录自己的blockId和来源位置,而不是仅靠它在数组里的序号。

一个简化的中间结构可以长这样:

{"blockId":"p-0286-04","sourceAnchor":{"page":286,"bbox":[72,180,510,232]},"sourceText":"Run npm install, then read the guide.","inlineTokens":["CODE_1","LINK_1"],"status":"segmented"}

HTML 可以记录 DOM 路径,PDF 可以记录页码、坐标和阅读顺序,EPUB 可以记录 spine 与元素路径。这一层可称为Document IR(文档中间表示):不同格式的来源信息各自保留,翻译调度则统一按块管理。

这里还要分清两个概念:**语义块是最终写回和检查的单位;翻译单元是一次送给模型的输入。**为了让模型理解上下文,可以把相邻的几个块放在一次请求中;返回后仍要按blockId拆回原块。

三、代码和链接先保护,再翻译

回到开头的例子。如果希望链接文字“the guide”可以翻译,但链接地址和 HTML 节点不被改动,可以把输入整理为:

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

npm install的原始代码节点,以及链接的href,由系统单独保存。模型只处理可翻译的文字,并保留占位符。

写回前至少要检查:占位符有没有缺失、重复或被改名;链接的开始和结束标记是否仍然成对。检查通过,再恢复代码与链接节点。公式、URL、产品型号、{name}和%s这类变量,也可以按各自规则保护。

这一步并不能保证译文质量,但能防止模型在翻译时顺手改掉文档结构。

四、翻译完成后,怎么找到原来的位置?

假设第 286 页有两个几乎一样的提示段落。只用原文内容搜索,两个位置都可能匹配。即使保存了 PDF 坐标,重新解析或排版后,坐标也可能发生变化。

比较稳妥的做法是把三个信号放在一起核对:

  1. **结构位置:**原来属于哪一页、哪个节点或 EPUB 文件。
  2. **邻居特征:**前后分别是什么块,阅读顺序是否一致。
  3. **内容校验:**原文摘要或关键特征是否仍然匹配。

先按原始位置查找;对不上时,只在附近范围内重定位。如果仍有多个候选位置,就标记为待复核,而不是选一个“最像的”自动写入。


图 2:blockId关联原文和译文,多个定位信号确认最终写回位置。

最隐蔽的错误不是没翻出来,而是译文读起来没问题,却出现在错误的原文下面。

五、写回 PDF,位置正确还不够

HTML 可以在原文段落后插入译文节点;EPUB 可以修改对应 XHTML,再检查章节导航和内部链接。PDF 更难:译文通常不能直接塞回原来的文本框。

例如原文只有两行,译文变成四行。如果仍按原坐标绘制,可能压住下一个段落。表格单元格里的译文变长,还会影响行高、跨页和图注位置。

因此,双语 PDF 通常要在“原文块与译文块保持对应”的前提下重新安排版面,并在生成后检查溢出、阅读顺序和链接。准确写回包含两件事:找对内容位置,以及让新页面仍然可读。

网页实时翻译又是另一种写回场景。页面可能被 React、Vue 等框架重新渲染,插件插入的译文也会触发 DOM 变化监听。因此它还需要节点标记、重复翻译检测和视口调度。两种场景可以共用分块与占位符的思路,但不能直接共用写回实现。

六、翻到第 286 块失败,前面的结果怎么办?

几百页的文档不可能假设一次处理永远成功。接口超时、某个块解析失败、人工审核暂停,都可能打断任务。

如果每个块都保存状态和结果,流程就可以从未完成的块继续:

segmented → translating → translated → approved → rendered

这里要区分第 286 页和第 286 块:一页可能包含多个块,真正用于续跑和局部复核的是块级状态。

术语更新也类似。比如一份手册里API Gateway已确认译为“API 网关”,后续块应尽量遵循同一译法。若术语表变更,可以找出命中该术语的块,逐块检查或重译,而不必默认重跑整本书。

七、怎么检查双语成品有没有做好?

只看“翻译是否通顺”还不够。更能暴露系统问题的是下面几类测试:

  • 代码与变量:npm install、{name}、%s是否保持原样?
  • **链接:**链接文字翻译后,点击是否仍指向原地址?
  • **重复段落:**两处相同原文的译文,是否写回各自位置?
  • **复杂页面:**双栏、表格、脚注和图注的阅读顺序是否正确?
  • **长译文:**文本框、表格和分页有没有溢出或遮挡?
  • **中断恢复:**某一块失败后,已确认的块是否可以保留?

占位符完整性、数字与单位异常、疑似漏译、异常长度等,可以先由程序筛查;语义准确性和有歧义的写回位置,仍需要复核。自动检查是质量门槛,不等于质量保证。

最后:模型翻对一句话,只是开始

文档翻译真正难的是模型前后的工程:识别结构、保护内联对象、保持块与位置的关联、适配新版面,以及在失败后继续处理。

翻译 API 可以返回一段不错的中文。但要把几百页的原文变成可阅读、可核对的双语文档,每一段译文还得知道自己从哪里来、该回哪里去。

双语文档最怕的不是某段没有译文,而是译文看着正确,却放错了位置。


如果想进一步了解这些能力在产品里的实际应用,可以体验:

有谷大脑:https://brain.yogu.pro

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询