2009年5月3日星期日

认识下linux下程序的国际化(C语言实例)

要让程序能够根据操作系统的环境的不同而显示不同的UI界面,需要将程序的本地化;如果手工将源程序中的字符串替换为与环境相符的字符来实现本地化的方法 不具有通用性,因为针对每一种操作系统环境都要重复以上操作工作量很大,一般的方法是先将程序国际化,然后再进行本地化;linux上的这个过程主要用到 了两个工具:xgettext和msgfmt;
not: xgettext是国际化的工具,提取出源文件中的字符串,生成*.po的文件,而msgfmt是本地化的工具,首先是人工的翻译*.po文件中的字符串,然后使用msgfmt生成*.mo文件,再编译后,程序启动时会扫描系统环境提取mo文件中的字符串代替原来的英文。
测试实例(helloworld):
#include ;
#include ;
#include ; //包含了两个头文件

#define _(STRING) gettext(STRING) //定义了_(STRING)宏,只是为了简化
#define PACKAGE "test_locale" //定义了软件包的名字,最后生成的.mo文件名应该命名为这个
#define LOCALEDIR "./po" //定义了mo文件将要存放的位置

int main(int argv,int*argc[])
{
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR); //bind软件包与mo文件存放的位置
textdomain (PACKAGE);

printf(_("hello,world!\n")); //将_(STRING)宏应用到了字符串上
}
将程序这样改写以后,就叫国际化了,简单吧?但不是说这样程序就能根据系统环境显示相应的界面了,我们还需要将它本地化;我们将程序保存为test_locale.c;
利用xgettext生成test_locale.po文件
xgettext -k_ -o test_locale.po test_locale.c
-k 指定翻译字符以何种宏定义括起,我们在前面使用的是 _( ) 所以用 -k_
编辑test_locale.po文件成:

# 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 , YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-05-03 23:25+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" //注意修改charset的值
"Content-Transfer-Encoding: 8bit\n"

#: hello_I18N.c:15
#, c-format
msgid "hello,world!\n"
msgstr "你好,世界!\n" //翻译
接下来再利用msgfmt生成test_locale.mo文件
msgfmt -o test_locale.mo test_locale.po
将test_locale.mo文件放在之前设定的LOCALEDIR/xxxx/yyyyy目录下,其中的xxxx和yyyy稍后就明白了;
现在再来看看程序的运行结果
当系统环境 LANG=en_US的时候,结果如下:
hello,world!
当系统环境 LANG=zh_CN.UTF-8的时候,结果如下:
你好,世界!
就是说,在程序运行时,会根据LANG自动到LOCALEDIR/zh_CN/LC_MESSAGES寻找mo文件,从而正确显示;所以上文中的xxxx和yyyy就是zh_CN和LC_MESSAGES。

没有评论: