linux编程之国际化和本地化

时间:2021-12-04 04:41:00

1 国际化(internationalization, i18n),本地化(localization, l10n)

这里不多说,想具体了解可以上wikipedia。

2 如何把“Hello world!”打印显示为“你好,世界!”?

1)编辑test_helloworld.c

$vim test_helloworld.c
  1 #include <stdio.h>
2 #include <locale.h>
3 #include <libintl.h>
4
5 #define PACKAGE_NAME "test_helloworld"
6 #define PACKAGE_LOCALEDIR "po"
7 #define _(x) gettext(x)
8
9 int main (int argc, char *argv[])
10 {
11 setlocale(LC_ALL, "");
12
13 // Comment: printf "1 Hello world!"
14 printf(_("1 Hello world!\n"));
15
16 setlocale(LC_MESSAGES, "zh_CN.UTF-8");
17
18 bindtextdomain(PACKAGE_NAME, PACKAGE_LOCALEDIR);
19 textdomain(PACKAGE_NAME);
20
21 // Comment: printf "2 Hello world!"
22 printf(_("2 Hello world!\n"));
23
24 return 0;
25 }

2)从.c源文件中提取需要进行国际化/翻译的字串,生成.po(portable object file)

$ xgettext --add-comments --keyword=_ test_helloworld.c -o test_helloworld.pot --from-code=UTF-8
$ cp test_helloworld.pot test_helloworld.po

3)修改并翻译字串文件.po

用xgettext命令提取出来的.pot文件内容如下:

# 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: 2013-01-14 16:42+0800\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"

#. Comment: printf "1 Hello world!"
#: test_helloworld.c:14
#, c-format
msgid "1 Hello world!\n"
msgstr ""

#. Comment: printf "2 Hello world!"
#: test_helloworld.c:22
#, c-format
msgid "2 Hello world!\n"
msgstr ""
修改和翻译后的.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 <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-01-14 16:42+0800\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=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#. Comment: printf "1 Hello world!"
#: test_helloworld.c:14
#, c-format
msgid "1 Hello world!\n"
msgstr "1 你好,世界!\n"

#. Comment: printf "2 Hello world!"
#: test_helloworld.c:22
#, c-format
msgid "2 Hello world!\n"
msgstr "2 你好,世界!\n"

可以选择用gedit或自己喜欢的编辑工具来修改,推荐使用poedit工具,方便实用。

linux编程之国际化和本地化

4)把翻译好的.po文件转化为程序运行时可读取的二进制文件.mo(machine object file)

$ msgfmt test_helloworld.po -o test_helloworld.mo

5)把转化好的.mo文件放置到相应的LOCALEDIR路径下供程序执行时使用

$ mkdir -p po/zh_CN.UTF-8/LC_MESSAGES/
$ cp test_helloworld.mo po/zh_CN.UTF-8/LC_MESSAGES/

6)最后就可以编译并运行

$ gcc -Wall test_helloworld.c -o test_helloworld
$ ./test_helloworld 
1 Hello world!
2 你好,世界!

3 GNU locale 

locale被设计用来设定当前系统区域环境相关的信息来满足不同用户对国际化和本地化的需要,相关环境变量信息如下:

$ locale
LANG=en_US.UTF-8
LANGUAGE=
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES=en_US.UTF-8
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

4 GNU gettext 

gettext被设计用来实现国际化和本地化,通过gettext可以索引到字串的多国语言翻译,从而为国际化和本地化的字串显示提供基础。

5 Self-check

要理解test_helloworld.c里面相关locale和国际化相关API最好的方法就是亲自读一读glibc中的locale和intl相关目录下的src code,如setlocale.c、textdomain.c、bindtextdom.c、gettext.c等。多用man命令查一下这些命令或API,配合google和wikipedia。

这里只是用中文举例,有兴趣的可以尝试加一下其它语言。

(待完善)