使用 GNU gettext 实现程序的多国语言本地化
使用 GNU gettext 实现程序的多国语言本地化
1. 基本操作
gettext 是 GNU 出品的一个项目,主要用于将应用程序本地化和国际化的一个实用套件。
首先,我们的程序,如果在源代码中写死了字符串,则我们无法对这个字符串进行国际化和本地化,例如:
1 | int main() |
上面的程序,无论在什么语言版本的系统中,其显示的都是英文的字符串 “hello world” 。
gettext 的方法是,需要进行国际化与本地化的字符串中,全部加上一个叫 gettext() 的函数调用,如下:
1 | // a1.c |
上面示范程序中的字符串 “I come from China.” 和 “I like Java language.” ,在使用之前都加上了 gettext() 函数进行包裹。gettext() 函数的作用是:以原始字符串作为 key,去加载并获取到并返回其对应语言的的本地字符串。
使用 xgettext
命令,将源文件中被 gettext() 函数包裹的字符串全部抓出来,命令如下(用 test1 作为语言包名):
1 | xgettext a1.c -o test1.po |
xgettext 命令可以指定多个原文文件,输出的 .po 文件是一个文本文件,里面包含了需要翻译的所有字符串,文件名是上面源码中指定的对应的语言资源包 PACKAGE 名。
打开 test1.po 文件,把字符编码设置为 UTF-8,将里面的 "Content-Type: text/plain; charset=CHARSET\n"
改为 "Content-Type: text/plain; charset=UTF-8\n"
。然后,对相应的文本进行翻译:
1 | #: a1.c:13 |
上面的 msgid 就是原始字符串,作为 key,不要修改,下面的 msgstr 则应该修改,将翻译过去的文本填进去,如下:
1 | #: a1.c:13 |
然后使用 msgfmt
命令将 .po 文件编译为 gettext() 函数可以识别的 .mo 文件,命令如下:
1 | msgfmt test1.po -o test1.mo |
由于上面 C 程序中指定了 .mo 资源的加载路径,语句 bindtextdomain(PACKAGE, "locale");
指定了 .mo 存放在当前目录的 locale 子目录下面。所以,把生成的 test1.mo 文件放在当前目录的如下路径下:
1 | locale/zh_CN/LC_MESSAGES/test1.mo |
这里假设系统为简体中文,当前 locale 设置为 zh_CN,上面 C 程序的语句 setlocale(LC_ALL, "");
就是使用系统默认的语言环境。执行上面 C 程序 ./a1
得到结果为:
1 | 我来自中国。 |
上面例子说明了 gettext 套件的基本使用流程。
2. 批量操作
xgettext
命令可以一次性指定多个输入源文件,如:
1 | xgettext a1.c a2.c a3.c -o package.po |
xgettext
命令也可以通配符,如:
1 | xgettext *.c -o package.po |
可以把所有需要提取的源文件放在一个列表中(list1.txt 中列出所有源文件名):
1 | xgettext -f list1.txt -o package.po |
增加其他关键字,例如 增加 N() 函数,则 N(“string”) 也会被抓取:
1 | xgettext *.c -kN -o package.po |
如果已经翻译好了字符串,后来源代码发生了更改,增加了一些新的字符串,可以使用 -j 选项,把新增的字符串追加到已经存在的翻译好的 .po 文件中,例如:
1 | xgettext a1.c a2.c a3.c -j -o package.po |
用 msginit
命令可以把 xgettext 生成的 .po 文件(POT)转换成对应语言的翻译文本 .po (会修改好一些编码与语言的相关字段):
1 | msginit --no-translator --locale zh_CN -o package_new.po -i package.po |
可以用 msgmerge
命令把新生成的 .po 合并到已经翻译好的 .po 文件中:
1 | msgmerge -o package.po locale/zh_CN/LC_MESSAGES/package.po package.po |