Billchenchina 标签 联系 朋友们

GNU gettext 使用指南

Posted by Billchenchina on December 9, 2019

一年多没有更新了,终于有心情写写博客了。这次更新将带来 GNU gettext 的使用指南。

什么是 gettext

gettext是 GNU 套件之一,广泛用于软件的国际化。Linux 多数程序的国际化都使用了gettextGit也在使用gettext来进行 i18n。

gettext 官网

gettext PDF 形式的文档

Gettext 工作流程

由于我们需要进行软件的国际化,在编写程序时如果需要输出,我们不能直接使用字符串,而需要使用char * gettext(const char * msgid)将需要国际化的字符串传递给gettext,让gettext对字符串进行国际化。

  1. 编写程序后,我们使用xgettext工具从程序源码中提取所有需要我们进行翻译的字符串,并生成.pot文件(portable object template)。.pot文件是代码中需翻译内容的模板。
  2. 生成.pot文件后我们再次使用msginit工具,基于.pot文件创建一个.po文件(portable object)。我们将在.po文件中贡献我们的翻译。
  3. 翻译后我们将使用msgfmt工具将.po文件转化为.mo文件(machine object)。

至此翻译结束。但是代码是怎么工作的呢?char * gettext(const char * msgid)会在你指定的目录下寻找符合当前locale.mo文件,并在文件中寻找msgid的翻译。如果对应的翻译字符串存在,函数将返回msgid对应的翻译字符串。

Get Started

本文章对应源码将会放置在 https://github.com/billchenchina/gettext_project/tree/master/gettext_project1

程序编写

为了方便,下文中我们指定domainnametest_projectdirnametranslate。我们的代码放在test_project.c文件中。

首先编写程序时,需要#include <locale.h>#include <libintl.h>

由于我们在编写程序时会频繁调用gettext()函数,所以我们通常会添加预处理指令#define _(string) gettext(string)

我们在程序起始时还需要使用setlocale(LC_ALL, "")来保证当前 locale 的正确性,并调用char * bindtextdomain (const char * domainname, const char * dirname)来指定我们翻译文件(即.mo文件)的位置。

除此之外,我们还需要调用textdomain("test_project")来设置当前程序的 domain。

在我们编写程序时,还需要将所有需要国际化的字符串使用 _() 包围。比如将 "Hello, world!\n" 改为 _("Hello, world!\n")

编译

很普通的编译方法gcc test_project.c -o test_project.out

生成 .pot 模板

xgettext --output=test_project.pot -k_ test_project.c

--output指输出文件名,-k_指将_(STRING)作为字符串提取的依据。

更多选项可以查看 xgettext 的 manual。

生成指定(自然)语言的 .po 文件

msginit -i test_project.pot -o translate/zh_CN/LC_MESSAGES/test_project.po -l zh_CN

这条命令将会在translate/zh_CN/LC_MESSAGES/下创建名为test_project.po文件。我们将对该文件进行翻译。

翻译

打开translate/zh_CN/LC_MESSAGES/test_project.po(注意该文件的编码为 gb2312),并进行翻译。

生成 .mo 文件

msgfmt test_project.po -o test_project.mo

运行程序

$ ./test_project.out
你好,世界!

还没完成的…

上述我们只说了怎么去使用gettext来初次翻译,我们还没有讲如何更新翻译一类的。如果我不咕的话会出下一篇文章的。