上一篇文章聊了翻译插件的性能优化(从 3 秒到 300 毫秒),这一篇继续深入,讲双语对照视图的三个前端核心问题:段落对齐怎么做、注入样式怎么不污染原页面、以及大文档渲染怎么不卡。
一、段落对齐:从 DOM 区块到翻译单元
整页翻译的输入是"文本节点",但双语对照的基本单位是"视觉段落"。两者之间有一道沟:一个视觉段落可能由多个内联元素组成(<p> 里嵌 <strong>、<a>、<code>),直接按文本节点切分,翻出来的就是碎片。
我们的做法是两步走:
- 区块收集:从块级元素(p、li、td、h1~h6)出发向下递归,把"同一个块级容器内的连续内联文本"归并为一个翻译单元,保留内联结构的骨架。
- 译文回填:译文按句级对齐回填到原骨架里——加粗还是加粗、链接还是链接,只是文字换成了中文。这比"段落整体替换"效果好得多,因为代码片段和变量名不会被翻译破坏。
对齐算法不追求完美:句数不匹配时按长度比例贪婪分配,兜底策略是整段替换。宁可偶尔丢一点内联格式,也不能把译文塞错位置。
二、样式隔离:不把原页面搞花
往别人的页面里注入 DOM,最大的风险是样式互相污染:原页面的 div { line-height: 1.2 !important } 会打乱译文排版,你的译文样式也会反过来影响原页面。
三道防线:
- 容器级隔离:译文统一包进固定 class 的容器,所有译文样式都从这个 class 向下作用,选择器自带命名空间。
- 继承切断:译文容器的 font、color、line-height 全部显式声明,不依赖继承——原页面在
<body>上写的任何东西都影响不到你。 - 渲染模式可选:默认段落下方插入译文块;检测到强样式冲突(比如表格类布局)时降级为悬停显示,保页面可用性优先。
三、渲染性能:长文档的分批策略
一本 10 万词的电子书、一份 300 页的 PDF,翻译结果可能包含上千个翻译单元,一次性插入 DOM 就是灾难。
我们的做法:
- 虚拟化插入:译文块按视口分批渲染,滚动到哪里渲染到哪里,已渲染的缓存复用。
- transform 代替 top:批量插入时用
transform: translateY定位,避免反复触发 layout。 - PDF 特殊处理:PDF 是绝对定位的文本层,译文块按原文块的坐标计算高度后嵌入,保排版的关键是"译文字号自适应块高"——块小就缩字号,宁可小也不溢出遮挡。
这套组合下来,实测 300 页 PDF 的对照渲染首屏 300 毫秒内完成,滚动无卡顿。
写在最后
双语对照听起来只是"翻译完放旁边",工程上的功夫全在对齐、隔离和渲染这三处细节里。做翻译类产品的前端同学,欢迎在评论区交流你踩过的坑。
(本文基于随心翻译插件的工程实践。插件按量计费,2.5 元/百万 token,注册送 40 万 token 体验额度。)