可以通过 gettext 进行处理,一个在 Linux 上的 i18n 国际化常用的解决方案。
示例
在进行翻译的时候需要指定翻译哪些字符串,如下是一个简单示例。
#include <stdio.h>
#include <locale.h>
#include <libintl.h>
#define _(string) gettext(string)
int main(void)
{
//char *info = _("World"); // NOT WORK
char info[64];
setlocale(LC_ALL, ""); // OR "zh_CN.utf8"
bindtextdomain("foobar", "langs");
textdomain("foobar");
strncpy(info, _("World"), sizeof(info));
printf(_("Hello %s!\n"), info);
return 0;
}
使用 gcc -o foobar foobar.c 生成对应二进制文件,然后通过 LC_ALL="en_US.utf8" ./foobar 或者 LC_ALL="zh_CN.utf8" ./foobar 进行测试,此时一般会输出是 Hello World! 。
对上述的代码比较核心的内容介绍如下。
setlocale(LC_ALL, "");设置区域,如果第二参数为""表示设置成系统环境变量指定的值;bindtextdomain("foobar", "langs");设置语言文件的查找路径,其中langs指定的是当前路径下的目录;textdomain("foobar");设置当前程序需要的 domain 需要与上述的第一个参数保持一致。
如果程序使用了多个 .mo 文件,那么就需要通过 bindtextdomain() 指定多次,然后通过 textdomain() 选择对应的文件。
在 Linux i18n 中,资源文件是二进制的 .mo 文件,使用工具生成,之所以是二进制,估计是为了性能,那么,上述的 bindtextdomain() 设置,实际上就会查找 langs/foobar.mo 文件。
然后将所有要翻译的字符串写成 gettext("STR") 的形式,上述是使用的一个宏,方便进行修改。
生成翻译文件
首先生成翻译模板 (Portable Object Template) 文件 foobar.pot 。
$ xgettext -k_ foobar.c --add-comments --add-location --default-domain foobar \
--no-wrap --copyright-holder="Foobar Copyright Message" \
--package-name="Foobar Package Name" --package-version="v1.0.0" \
--msgid-bugs-address="foobar@mail.com" -o foobar.pot
此时如果直接通过 msgfmt 转换会报错,可以通过如下方式初始化为 Portable Object 文件。
$ msginit --no-translator --locale zh_CN.UTF-8 --output-file foobar.po --input foobar.pot
然后,修改上述文件中的一些常见字段,包括了编辑第一作者 (FIRST AUTHOR)、翻译者 (Last Translator)、语言工作组 (Language Team) 等信息,大致如下。
msgid ""
msgstr ""
"Project-Id-Version: Foobar Package Name v1.0.0\n"
"Report-Msgid-Bugs-To: foobar@mail.com\n"
"POT-Creation-Date: 2012-06-01 19:33+0800\n"
"PO-Revision-Date: 2012-08-03 14:14+0800\n"
"Last-Translator: Your Name<foobar@email.com>\n"
"Language-Team: Simplified Chinese <foobar@hi.org>\n"
"Language: zh_CN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: foobar.c:16
msgid "World"
msgstr "世界"
#: foobar.c:17
#, c-format
msgid "Hello %s!\n"
msgstr "你好 %1$s!\n"
然后创建一个子目录,用来保存生成的 .mo 文件。
# mkdir -p language/zh_CN/LC_MESSAGES
# msgfmt -o langs/zh_CN/LC_MESSAGES/foobar.mo foobar.po
如果此时再执行 foobar 文件会直接翻译成中文。
其它
可以通过 msgunfmt *.mo -o *.po 命令反向生成 po 文件,如果有新的翻译项,可以直接通过 msgmerge 合并新的 pot 文件。
注解
在使用 gettext 工具进行分析时,也可以使用一些特殊的注解,通常以 , 开头,常见的有:
, fuzzy翻译可能不正确,需要重新 review 之后再删除;, c-format信息会使用到 C 语言的 printf ,例如%d%s等。
参考
- 官方相关的介绍 Overview of GNU gettext 。