这是 Mozilla 的身份团队推出的 Node.JS 节日季系列 中的第 10 集,共 12 集。让我们继续谈论本地化!
在我们之前的文章 “如何本地化您的 Node.js 服务” 中,我们学习了如何将 i18n-abide 添加到我们的代码中。
我们在模板和 JavaScript 文件中都包裹了字符串。
作为开发人员,我们的工作到此结束。但是,将我们的文字本地化工作才刚刚开始。
工具链
Persona 基于 Node.js 的 L10N 工具链与更大的 Mozilla 社区兼容,但保留了 Node 闻名的友好性和灵活性。
Mozilla 项目已有近 15 年的历史,拥有开源界最庞大(也是最酷)的 L10n 社区之一。
因此,它拥有许多现有的工具,有时是旧的 *古板的工具*。
Gettext
GNU Gettext 是一款工具链,允许您本地化来自 Web 应用或原生应用的文本。当您编写 Node.js 代码和模板时,您会像往常一样输入英文字符串,但每个字符串都包裹在函数调用 `gettext` 中。
`gettext` 为您做了几件事
- 在构建步骤中,gettext 将所有字符串提取到字符串目录中
- 在运行时,gettext 将英文字符串替换为其本地化的等效项。
构建步骤中的字符串提取是我们将从您的代码和模板文件中创建字符串目录的方式。
所有这些字符串最终都存储在以 `.po` 为后缀的文本文件中。我将这些文件称为 **PO 文件**。
PO 文件
.PO 文件是纯文本文件,具有 Gettext 工具可以读取、写入和合并的特定格式。
名为 zh-TW/LC_MESSAGES/messages.po 的 PO 文件的示例片段
#: resources/views/about.ejs:46
msgid "Persona preserves your privacy"
msgstr "Persona 保護您的隱私"
我们将在下面更详细地研究它,但我们可以看到 `msgid` 是英文字符串,而 `msgstr` 包含中文翻译。注释是所有以 `#` 开头的内容。
上面的注释显示了字符串在代码库中的使用位置。
Gettext 提供了许多其他工具:它可以管理字符串、PO 文件等。我们将在稍后介绍这些。
为什么需要新的工具链?
在我们开始介绍使 Gettext 变得容易使用的 Node 模块之前,我们必须问问自己……为什么使用这款工具链?
一年前,我对所有 Node L10n 和 I18n 模块进行了深入调查。
大多数模块都 “重新发明轮子”,创建自己的基于 JSON 的格式来存储字符串。
Mozilla 社区已经使用了很多工具,例如 POEdit、Verbatim、Translate Toolkit 和 Pootle。我们没有强迫社区使用新工具,而是决定让我们的工具在他们的标准内工作。
这就是我们告诉本地化人员我们所有字符串是什么,以及他们将如何向我们提供最终翻译的方式。PO 文件是 L10n 社区的“数据交换媒介”。
在 Mozilla 使用 PHP 和 Python 的过程中,我发现 Gettext 工作得很好。当 Web 应用变得很大,并且有更多文字时,本地化文本有很多细微差别,需要 Gettext 的经过充分测试的工具和 API。
为本地化人员提供 PO 文件
因此,我们的代码用 `gettext` 调用标记了起来。现在呢?
找一个 **字符串管理员**。这个人可以是你,可以是本地化专家,也可以是构建系统专家。
字符串管理员做什么?
- 第一次从软件中提取字符串
- 在后续版本中提取新的、已更改的或已删除的字符串
- 为每个本地化团队准备 PO 文件
- 解决冲突并标记已更改或已删除的字符串
这听起来可能很复杂,但有一个好消息!
这些步骤可以自动化。大多数这些步骤可以自动化。当出现问题时,字符串管理员负责解决问题。
`msginit`、`xgettext`、`msgfmt` 和其他 GNU Gettext 工具 是一种强大的方法来管理字符串目录。只有字符串管理员需要这些工具,大多数开发人员(以及 Node.js)可以对此一无所知。
设置区域设置文件系统
$ mkdir -p locale/templates/LC_MESSAGES
此目录是我们将存储 PO 模板或 POT 文件的位置。POT 文件由 Gettext 工具链使用。
提取字符串
在上篇文章中,我们安装了 **i18n-abide**,其中包含:
npm install i18n-abide
除了其他命令行工具之外,它还提供了 `extract-pot`。
要将字符串提取到 `locale` 目录中,我们将使用以下命令。
mkdir -p locale/templates/LC_MESSAGES
$ ./node_modules/.bin/extract-pot --locale locale .
`extract-pot` 创建一个 .POT 文件,它是一个 PO 文件模板。
此脚本将递归地遍历您的源代码并提取字符串。
那么 `extract-pot` 如何创建这些 POT 文件呢?您可以使用传统的 GNU Gettext 实用程序,但我们也编写了一个 Node 模块 `jsxgettext`,它是一种不错的跨平台方法。
`extract-pot` 在幕后使用 `jsxgettext`。
jsxgettext 解析您的源文件,查找 Gettext 函数的使用情况,然后仅提取字符串部分。然后,它会格式化一个 PO 文件,该文件与任何其他 Gettext 工具兼容。
这是 POT 文件的摘录。
#: resources/views/about.ejs:46
msgid "Persona preserves your privacy"
msgstr ""
#: resources/views/about.ejs:47
msgid ""
"Persona does not track your activity around the Web. It creates a wall "
"between signing you in and what you do once you're there. The history of "
"what sites you visit is stored only on your own computer."
msgstr ""
""
#: resources/views/about.ejs:51
msgid "Persona for developers"
msgstr ""
稍后,我们将从该模板创建 PO 文件。
在您的本地化人员编辑他们的 PO 文件后,它将看起来更像这样
#: resources/views/about.ejs:46
msgid "Persona preserves your privacy"
msgstr "Persona 保護您的隱私"
#: resources/views/about.ejs:47
msgid ""
"Persona does not track your activity around the Web. It creates a wall "
"between signing you in and what you do once you're there. The history of "
"what sites you visit is stored only on your own computer."
msgstr ""
"Persona 只是連結您登入過程的一座橋樑,不會追蹤您在網路上的行為。您的網頁瀏覽"
"紀錄只會留在您自己的電腦當中。"
#: resources/views/about.ejs:51
msgid "Persona for developers"
msgstr "Persona 的開發人員資訊"
您可以 查看完整的 zh_TW PO 文件,以更好地了解。
创建区域设置
Gettext 工具 `msginit` 用于基于我们的 POT 文件为目标区域设置创建一个空的 PO 文件。
$ for l in en_US de es; do
mkdir -p locale/${l}/LC_MESSAGES/
msginit --input=./locale/templates/LC_MESSAGES/messages.pot
--output-file=./locale/${l}/LC_MESSAGES/messages.po
-l ${l}
done
我们可以看到,我们已经创建了英语、德语和西班牙语的 PO 文件。
PO 文件
因此,我们已经提取了字符串并创建了许多区域设置。
以下是一个示例文件系统布局
locale/
el/
LC_MESSAGES/
messages.po
en_US
LC_MESSAGES/
messages.po
es
LC_MESSAGES/
messages.po
templates
LC_MESSAGES/
messages.pot
您可以让您的本地化人员访问代码库的这一部分。例如,西班牙语团队将需要访问 `locale/es/LC_MESSAGES/messages.po`。如果您有一个非常大的团队,您可能会有 `es-ES` 代表西班牙语,`es-AR` 代表阿根廷西班牙语,而不是仅仅用一个基础的 `es` 代表所有西班牙语区域设置。
您可以随着时间的推移增加区域设置的数量。
合并字符串更改
一个版本接一个版本,您将添加新的字符串,更改或删除其他字符串。您需要使用这些更改更新所有 PO 文件。
Gettext 拥有强大的工具,可以轻松完成此操作。
我们提供了一个名为 `merge-po.sh` 的包装 shell 脚本,它在幕后使用 GNU Gettext 的 `msgmerge`。
让我们将 i18n-abide 工具放在我们的路径中
$ export PATH=$PATH:node_modules/i18n-abide/bin
并运行一个字符串合并
$ ./node_modules/.bin/extract-pot --locale locale .
$ merge_po.sh ./locale
就像第一次一样…… `extract-pot` 获取所有字符串并更新 POT 文件。接下来,`merge_po.sh` 更新每个区域设置的 PO 文件,使其与我们的代码库匹配。您现在可以要求您的 L10n 团队本地化任何新的或更改的字符串。
Gettext 与自己发明
放弃 Gettext 并使用新的 JSON 格式重新发明轮子很容易。这是大多数节点模块采用的策略。
如果您有一个健康的应用,随着您添加区域设置和开发新功能,您会发现自己被无数的小问题困扰。
如果没有 `merge_po.sh`,您将不得不编写自己的合并工具。这是因为,如果您有 30 个区域设置,您将需要更新 30 个 JSON 文件,而不会丢失他们已经完成的工作。
Gettext 提供了一个强大的合并功能,这将为我们节省许多痛苦的协调时间。
总结
现在,我们有了每个区域设置一个 po 文件中的各种字符串目录,我们可以将它们交给我们的本地化团队。
在开始提取/合并步骤之前,与本地化人员进行沟通总是好的。告诉他们 PO 文件何时准备就绪,他们有多少字符串,以及您希望何时完成本地化工作。此外,您可以阅读 Gettext 教程,因为它们都与我们的设置兼容。
好了,去翻译您的字符串吧,在下一篇文章中,我们将让它们发挥作用!
本系列的之前文章
这是 关于 Node.js 的 12 篇文章系列 中的第十篇。之前的文章是
- 追踪 Node.js 中的内存泄漏
- 全负载 Node
- 使用安全客户端会话构建简单且可扩展的 Node.JS 应用
- 出色的前端性能 第 1 部分 - 连接、压缩和缓存
- 构建不会熔化的 Node.JS 服务器
- 出色的前端性能,第 2 部分:使用 etagify 缓存动态内容
- 使用 node-convict 驯服配置
- 出色的前端性能,第 3 部分 - 通过优化字体获得巨大的性能提升
- 本地化您的 Node.js 服务,三部分中的第一部分
关于 Austin King
位于西雅图的非教条主义艺术家/程序员类型的人类。应用工程团队的流氓 Web 开发人员。拼写检查是为星期而设计的。
关于 Robert Nyman [荣誉编辑]
Mozilla Hacks 的技术布道者和编辑。发表有关 HTML5、JavaScript 和开放网络的演讲和博客文章。Robert 坚信 HTML5 和开放网络,自 1999 年以来一直在从事 Web 前端开发工作 - 在瑞典和纽约市。他还经常在 http://robertnyman.com 上写博客,热爱旅行和结识新朋友。