> For the complete documentation index, see [llms.txt](https://freebsd-journal-cn.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://freebsd-journal-cn.bsdcn.org/20170102-quan-qiu-ke-fang-wen-de-freebsd/improving-the-freebsd-translation-tools.md).

# 改进 FreeBSD 翻译工具

作者：Warren Block

## 改进 FreeBSD 翻译工具

关于翻译，第一个浮现的问题是“何苦来哉？”或者更客气地说：投入的精力是否值得换得的结果？世界上很大一部分地区居住着本可受益于使用 FreeBSD——却又因不会说英语，即便作为第二或第三语言也不会——而无法使用的人。我们能给他们带来的益处巨大。

其次，译者通常是进入新地区、新区域或新国家的大使。他们不仅是译者，还在使用自己翻译的内容。如果能让译者的工作更轻松，你也就能增加在这些地区使用你系统的人数。最终，你可以扩大社区规模。Metcalfe 定律大致意译为：电信网络的价值与网络中节点数量成正比。换言之，节点越多，网络越有价值。对互联网而言，如果只有两个节点，它并不那么有用；但如果有上百万个节点，它就变得有用得多。我说 FreeBSD 就是一个电信网络，而人就是网络中的节点。更多用户意味着更多人发现 bug、提交补丁、添加功能、完善文档，而这一切又为做这些工作的人提升了 FreeBSD 的价值。这是一个正反馈循环。这就是翻译的价值。

**年度新增翻译统计**

| 年份   | 新增翻译数 | 年份   | 新增翻译数 |
| ---- | ----- | ---- | ----- |
| 2005 | 9     | 2011 | 0     |
| 2006 | 12    | 2012 | 11    |
| 2007 | 7     | 2013 | 3     |
| 2008 | 17    | 2014 | 0     |
| 2009 | 8     | 2015 | 6     |
| 2010 | 2     | 2016 | 11    |

## FreeBSD 文档

FreeBSD 文档有几个不同类别。首先是图书与文章，使用 DocBook XML 标记。这不仅是著名的《FreeBSD Handbook》，还包括其他图书，如《Porter’s Handbook》（描述如何向 FreeBSD 移植程序）。这是一本内容详尽、持续更新的厚书，值得一读。还有一些独立的文章也使用 DocBook XML 标记。使用 DocBook XML 让我们能够将源码渲染为多种输出格式，如 HTML、PDF、ePUB、PostScript，乃至纯 ASCII。其次是手册页。十到二十年前，开源世界的部分人对手册页的优势尚未充分认识或理解，曾走过一些弯路。但对 BSD 社区而言，手册页是一项主要功能。手册页不是教程，而是当无法记住某条命令的精确格式或某个配置细节时快速查阅的参考。手册页是一笔巨大资源，且持续被更新与改进。它们主要使用 **mdoc(7)** 标记语言，也有一些老的手册页使用 roff 或 troff。还有其他文档。FreeBSD 文档项目的范围涵盖源代码。如果源文件中存在拼写、语法或清晰度方面的错误，我们被允许直接修改。这对文本文件或任何文件都同样适用。这就是 FreeBSD 文档项目的范围。

## 空白字符

翻译中遇到的一个出乎意料地困难的问题是空白字符。它们是文本之间的空白区域：空格、制表符、换行符、回车符等。因为不可见，这些字符难以察觉，也难以解释。它们之所以在翻译中重要，是因为当文档被编辑时，译者没有简便的方法判断内容是否变化、是否需要新翻译，还是只有空白字符变化而现有翻译仍然有效。典型例子是某人在编辑器中重新折行某段以适应特定行长。内容并未变化，但译者不重读整段就难以察觉。最坏情况下，译者会不必要地重新翻译整篇文档。这非常打击士气，而当我们依赖志愿者译者时，这是个严重问题。空白字符的变化传统上与源代码一样处理：内容的修改放在一次提交里完成；第二次提交再修改空白字符——且仅修改空白字符——以调整格式。仅修改空白字符的提交通常会在提交信息中注明内容未变，文档无需重新翻译。把内容提交与空白字符提交分开对译者有帮助，但给原文编辑者增加了大量工作。同一时间只能修改内容或空白字符其一，于是文档变得参差不齐、格式糟糕。在做后续仅修改空白字符的更改时，常常会发现内容错误。这些错误无法立即修复，而需要再一轮内容修改，然后又一次仅修改空白字符。因此，空白字符对几乎所有从事文档工作的人都是个问题。

## 旧翻译方法

传统的 FreeBSD 文档翻译方法概念上简单：译者按提交工作。译者逐步处理英文文档的变更，将其翻译为目标语言。实际操作中，这种方法对译者既困难又耗时。它是完全手动的，不给译者任何辅助，甚至恰恰相反：译者必须按顺序处理提交，对原文档的修改规模几乎毫无掌控。可能只改了一个句子，也可能重写了整章。在该变更翻译完成之前，后续变更无法翻译，这会阻止其他译者继续推进文档翻译。变更规模对于志愿者译者同样是个问题，他们可能视大型变更为超出其愿意贡献时间的负担。并无正式方法，但翻译团队通常用一条注释记录最新已翻译版本对应的英文文档最后提交号，这也是完全手动的。要按提交定位并工作，需要对版本控制系统有相当熟悉度。由于译者直接与 DocBook XML 源文件打交道，对 DocBook 的相当熟悉通常也是必需的。用这种旧方法产出的翻译质量与数量，是翻译团队奉献精神的明证。在所有这些开销之后，译者才终于定位到英文文档中必须加入翻译版本的下一处变更。这处变更可以是任何内容：新增文本、删除旧文本，或两者皆有。在某个时刻，译者会将先前已翻译的文档与包含变更的 diff 文件进行比对。由于此方法完全手动，在文档源码中定位变更发生的位置没有任何辅助。翻译与英文文档并非逐行对应，译者被迫自行定位变更必须施加的位置。当英文文档变更非同小可时，这会耗费大量时间。最后，译者才能着手做自己真正想做的事：用目标语言为英文文档创建翻译。未来的译者对这种打击积极性、劳动密集型的工作流反应并不积极。

## 新翻译方法

必须有改变。2012 年，Thomas Abthorpe 和 Benedict Reuschling 谈论了一种使用“PO 文件”的新翻译方法。尽管我是个只说英语的美国人，这项工作显然非常重要，我逐步学习了如何使用这种新翻译方法。2015 年，我们终于有了一套可工作的系统。新翻译方法使用 gettext，这是一个为避免厂商为使程序消息显示为不同语言而不得不重新编译程序而开发的程序。取而代之，创建一个 Portable Object（PO）文件，其中同时包含英文字符串及其对应的翻译。用户定义其 locale 后，字符串就以本地语言显示。乍看之下，这似乎不是一套适合翻译整篇文档的系统，但事实证明它对此出奇地好用。用一个程序从原始英文 DocBook XML 源中提取字符串到 PO 文件。译者用 PO 编辑器编辑这些文件。系统展示英文字符串，译者在旁边填入对应翻译。原文与译文一一对应。译者不必翻阅源文件来定位变更必须施加的位置。空白字符从严重问题变得大体不再是问题。最后，还有“翻译记忆”功能，可复用此前已知翻译。这既不像人们想象得那么好，也不像那么糟，但能将译者工作量减少约 5–15%。新翻译方法只有三步：

1. 运行 `make po` 从英文文档中提取可翻译字符串。如果翻译已存在，会保留并更新已变化的字符串。
2. 运行 PO 编辑器，在英文字符串旁输入翻译。
3. 运行 `make tran` 构建原文档的翻译版本。

整个过程就这些。译者无需对版本控制系统或 DocBook 标记有深入了解。他们不必翻译某次具体变更或整次大型变更，可以想做多少就做多少翻译，而不会阻碍其他译者。自动化尽可能辅助翻译，PO 编辑器通常会显示文档已翻译的进度。这与旧翻译方法相比是巨大变化，让志愿者译者真正能贡献，而不是把他们推走。

## 实现

有几款程序可以从 XML 文件中提取可翻译字符串。本项目选用的是 itstool（<http://itstool.org>），因其简洁且符合标准。同时还使用了 gettext-tools 包中的几个小工具。itstool 依赖 Python，而 Python 已是文档 Port（textproc/docproj）的必需依赖。Port gettext-tools（devel/gettext-tools）在文档作者或译者的系统上很可能已安装，因此这些工具的开销很小。

## 成果

新的 PO 翻译系统于 2015 年 8 月底上线。在 2015 年剩余时间里，新增了 6 篇文章与图书的德语、荷兰语、西班牙语、中文和韩语翻译。相比之下，2013 年仅有 3 篇新翻译，2014 年则一篇都没有。2016 年又有 10 篇新翻译，包括两篇分量很重的《Handbook》与《Porter’s Handbook》繁体中文翻译。诚然，这些数字未考虑新翻译的规模以及对既有翻译的持续维护。然而，它们表明简化的翻译方法可以是一种赋能技术，而有了更好的工具，志愿者能产出大量有用的工作。

## 挑战

我们仍有一些挑战，我把它们称作“挑战”，因为当你遇到一个 problem，它只是问题；而当你遇到一个 challenge，你被激励着去找出解决方案。有些内容不应被翻译。一个典型例子是我们那篇包含开发者 PGP 加密密钥的文章。它只包含这些：两句开场白（基本就是“我们的开发者有 PGP 密钥。密钥如下。”），然后是 600 页 PGP 密钥。这些只是数字，我们不希望它们被翻译，因为其翻译形式与原文完全相同。让译者看到这些字符串就是浪费译者时间。但我们同时也希望这类信息只有单一来源。如果这些字符串被翻译，它们会被复制到翻译文件中，造成多份副本，注定其中一些在翻译版本中总是过时。因此，我们需要一种标记源码的方式来说明“此字符串不应被翻译”。理想情况下，译者根本看不到该字符串。译者不应看到 600 页 XML 源码，而只看到那两句开场白。搜索标记不应翻译字符串的标准方式，没有找到任何明显的实现途径。少数组织使用过与特定工具链绑定的方法，看起来不适用于我们的文档。用 XML 处理指令实现一个 messy hack 也许能配合我们的工具链工作，但更好的方式始终更可取。寻找仍在继续，建议永远欢迎。另一个挑战是保留用旧翻译方法创建的大量翻译工作。其中一些非常新近，我们希望尽可能多地保留这些工作。理想情况下，我们希望把这些翻译转换为 PO 翻译而不丢失任何工作。GNOME 的 xml2po 程序可以接收英文原文档和完整翻译版本，从中生成 PO 文件。但两个文档必须逐行精确对应。然而我们的翻译团队有自己的折行规则，原文与翻译并不匹配。也许还有其他程序基于匹配两个文件的 XML 元素来做到这一点。可能没有太多精力投入到转换程序中，因为对大多数组织而言转换是一次性事件。文档译者会受益于看到源字符串前后几行文本，以了解其使用上下文。许多 PO 编辑器不显示多少上下文。gettext 最初用于翻译程序提示，那里几乎没有什么上下文可显示。对于文档，情况截然不同，显示周边上下文会让翻译工作更轻松。这并非技术问题，因为 PO 文件已经带有每行的注释，标注它在原始 XML 文件中的行号。PO 编辑器有许多，但只有少数几个已被 port 到 FreeBSD。目前有三种：editors/poedit、devel/gtranslator 和 devel/lokalize。Ports 中有更多 PO 编辑器会让译者更容易选择适合特定文档或目标语言的编辑器。备受好评的 Virtaal（<http://virtaal.translatehouse.org/>）的 Port 已接近可用，可能不需要太多工作就能完成。基于 Java 的 PO 编辑器也已存在，基于 Web 的在线 Pootle 系统也已在 Ports 中，路径为 textproc/pootle。PC-BSD 曾使用 Pootle 进行翻译。PC-BSD 现已更名为 TrueOS，目前使用 Weblate（<https://weblate.org/en/>）进行基于 Web 的翻译。此外还有功能类似的商业托管站点，如 Transifex（<https://www.transifex.com/>），对开源用途免费。

## 我们学到了什么

让 PO 翻译工具在 FreeBSD 上可用的旅程也教会了我们一些相关的事。与其他项目交叉授粉的价值不应被低估。一些最有价值的洞见来自我与 GNOME 项目的 Ryan Lortie 在 BSDCan 演讲前后交谈之时。不同项目有不同经验，两个或多个项目可从共享知识中受益。我们不应把其他项目视作竞争者，而应视为富矿。旧翻译方法本质上是一种按提交移植的工作，把英文文档移植到另一种语言。当 X11 团队询问按提交移植与按文件移植的取舍时，我们得以识别出按提交移植方法固有的一些问题：

* 提交必须按顺序进行，即便后面有至关重要的提交需要先做。
* 移植者通常被迫以整次源码提交为单位工作，无论该次提交规模多大，项目可能在某位移植者卡在某次大型提交时停滞。
* 即便较早的提交可能被后面的提交完全抹去，仍需先移植它们，因为后面的提交依赖于它们的存在。

技术债可能是个严重问题。当我们告诉别人我们通过把章节定义为实体来在 XML 文件中引入它们，他们停下来说“我们还以为没人这么做了”时，这是一个警告信号。即便我们遵循标准，仍存在新工具可能不支持旧方法的风险。最终，这可能在实现新方法时让文档或翻译工作陷入停滞。如果逐步跟进行业标准而非突然紧急应对，通常更不痛苦。与上一点关于技术债相关：我们的文档需要切换到 UTF-8。早已该做，我已经写了一个程序来做这件事。剩下的只是验证转换正确进行的艰苦工作。

## 潜力

基于 PO 翻译最显而易见且最具吸引力的可能性是翻译 FreeBSD 手册页。itstool 严格只用于 XML 文件，而 Debian 的 po4a 包可以从手册页提取字符串到 PO 文件。一套完整翻译的 FreeBSD 手册页将极具价值。借助 PO 系统降低翻译门槛，这成为可能。新译者常常会成长为 FreeBSD 文档贡献者和提交者。PO 翻译提供了一种简便的入门贡献方式，以及通向社区的引子，从而带来更多参与。新的文档翻译会从新的地区和国家带来新用户，他们会对社区的问题与机遇提供自己独特的视角。其中一些人会继续成为贡献者，让 FreeBSD 对所有用户都更好。

***

## 链接

本文讨论的资料，包括演讲、用于收集统计的脚本、图表以及 Virtaal 的 Port，位于：

<http://wonkity.com/~wblock/translation/>

## 致谢

将 PO 翻译工具引入 FreeBSD 文档的工作已开展数年。许多来自 FreeBSD 项目内外的人都做出了贡献。这份名单并不完整，如有遗漏完全是我个人健忘所致。我真诚感谢每一位为让 FreeBSD 更易为世界各地的人们所用而做出贡献的人！

Thomas Abthorpe、Glen Barber、Mark Felder、Hiroki Sato、René Ladan、Ryan Lortie、Koop Mast、Shaun McCance、Chris Petrik、Benedict Reuschling……以及更多。

***

**Warren Block** 自 1998 年起使用 FreeBSD，用于服务器、文档创作、网络监控和企业计算等多种场景。他自 2011 年起成为 FreeBSD 文档提交者，自 2014 年起是文档工程团队成员。2016 年起，他为 iXsystems Inc. 编写 FreeNAS 文档。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://freebsd-journal-cn.bsdcn.org/20170102-quan-qiu-ke-fang-wen-de-freebsd/improving-the-freebsd-translation-tools.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
