使用 GNU gettext 来翻译软件
GNU gettext 是使用最广泛的自由软件国际化工具之一。它为软件的本地化提供了一种简单而灵活的方法。它对复数有很好的支持,可以为已翻译字符串添加更多的上下文,并且有很多围绕它构建的工具。当然,它在 Weblate 中有很好的支持(请参见 GNU gettext 文件格式说明)。
备注
如果您打算在专有软件中使用它,请先查阅许可证,它可能不适合您。
GNU gettext 可以用于多种语言(C、Python、PHP、Ruby、JavaScript 等等),通常 UI 框架已经提供了对其的一些支持。标准用法是通过 gettext() 函数调用,该函数通常具有 _() 别名,以使代码更简单易读。
此外,它提供了 pgettext() 调用,可用于为译者提供更多的上下文;还提供了 ngettext(),可以处理目标语言定义的复数类型。
作为广泛传播的工具,它具有很多封装,使其使用相当简单,你也许会想尝试其中之一,例如 intltool,而非下面描述的对 gettext 的手动调用。
工作流程概览
GNU gettext 使用几个文件来管理本地化工作:
PACKAGE.pot
包含从您的源代码中提取的字符串,典型地使用 xgettext 或一些高级封装,如 intltool。LANGUAGE.po
包含翻译为单一语言的字符串。一旦PACKAGE.pot
更新,那么必须由 msgmerge 来更新它。您可以使用 msginit 或在 Weblate 内新建新的语言文件。LANGUAGE.mo
包含LANGUAGE.po
的二进制表达,并且应用运行时使用。它典型地并不保持在版本控制之下,但在编译时使用 msgfmt 生成。在您想要使它处于版本控制中时,可以使用 生成 MO 文件 附加组件在 Weblate 中生成它。
GNU gettext 总体工作流程如下所示:
示例程序
使用 gettext 的 C 语言简单程序看起来会像后面这样:
#include <libintl.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int count = 1;
setlocale(LC_ALL, "");
bindtextdomain("hello", "/usr/share/locale");
textdomain("hello");
printf(
ngettext(
"Orangutan has %d banana.\n",
"Orangutan has %d bananas.\n",
count
),
count
);
printf("%s\n", gettext("Thank you for using Weblate."));
exit(0);
}
提取可翻译的字符串
一旦您具有了使用 gettext 调用的代码,您可以使用 xgettext 从中提取消息,并将它们存储在 .pot 中:
$ xgettext main.c -o po/hello.pot
备注
有另外的程序从代码中提取字符串,例如 pybabel。
这新建了模板文件,您可以用它来开始新的翻译(使用 msginit),或在代码更改后更新现有的翻译(为此您将使用 msgmerge)。结果文件是简单的结构化文本文件:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-10-23 11:02+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
#: main.c:14
#, c-format
msgid "Orangutan has %d banana.\n"
msgid_plural "Orangutan has %d bananas.\n"
msgstr[0] ""
msgstr[1] ""
#: main.c:20
msgid "Thank you for using Weblate."
msgstr ""
每个 msgid
行定义了要翻译的字符串,开头的特殊空字符串是包含关于翻译的元数据的文件标头。
开始新的翻译
准备好模板后,我们就可以开始我们的第一个翻译了:
$ msginit -i po/hello.pot -l cs --no-translator -o po/cs.po
Created cs.po.
刚刚创建的 cs.po
已经填写了一些信息。最重要的是,它为所选语言提供了正确的复数形式定义,您可以看到复数数量也随之改变:
# Czech translations for PACKAGE package.
# Copyright (C) 2015 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Automatically generated, 2015.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-10-23 11:02+0200\n"
"PO-Revision-Date: 2015-10-23 11:02+0200\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: cs\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ASCII\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
#: main.c:14
#, c-format
msgid "Orangutan has %d banana.\n"
msgid_plural "Orangutan has %d bananas.\n"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
#: main.c:20
msgid "Thank you for using Weblate."
msgstr ""
这个文件被编译为优化的二进制形式,.mo 文件,由 GNU gettext 函数在运行时使用。时使用。
更新字符串
一旦在您的程序中添加了更多的字符串或更改了一些字符串,您再次执行 xgettext,生成模板文件:
$ xgettext main.c -o po/hello.pot
然后您可以更新各自的翻译文件来匹配新建的模板(这包括重新排序字符串,赖于新的模板匹配):
$ msgmerge --previous --update po/cs.po po/hello.pot
导入到 Weblate
要将这样的翻译导入 Weblate,您只需要在创建部件时定义以下字段(字段的详细说明,请参见 部件配置):
字段 |
值 |
---|---|
源代码仓库 |
您的项目的版本控制系统(VCS)仓库的 URL |
文件掩码 |
|
新翻译的翻译模版 |
|
文件格式 |
选择 gettext PO 文件 |
新语言 |
选择 创建新语言文件 |
就这样,现在您可以开始翻译您的软件了!
参见
你可以在 GitHub 上的 Weblate Hello 项目中找到包含多种语言的 gettext 示例:<https://github.com/WeblateOrg/hello>。