Linux 的中文化问题简介(4)
2008-02-23 07:19:52来源:互联网 阅读 ()
setlocale(LC_MESSAGES, "");
.....
我个人的建议是,在 setlocale() 时只要设我们程式中需要的项目即可,而不要设 LC_ALL, 原因是在某些 locale 下 (如我们的 zh_TW.Big5), 并非所有的项目都能正确运作。我想对大部分的程式而言,设好 LC_CTYPE 与 LC_MESSAGES 就差不多了,故以下我针对这两个做说明。
wcs. vs. mbs. (详见 man mbstowcs 与相关 man page)
"wcs" 是 "wide-chararater string" 的缩写,而 "mbs" 是 "multi-byte string" 的缩写,二者分别代表字串的表现方式。所谓的 multi-byte 是指数个 char 组成一个字 (如全形字或中文字是由两个 char 组成),而 wide-char 是指一个 wchar_t type 就是一个字, 而 sizeof(wchar_t) 的大小与系统有关,一般而言是 4 bytes。一般我们可以直接看、输出输入等都是 multi-byte, 如:
char *str = "这是一个句子: abcd";
但我们会建议在程式内部,用 mbstowcs() 将它转成 wchar_t 来统一处理,这个转换其实是根据 locale 中的 LC_CTYPE 的机制,它定义了 multi-byte 与 wide- char 值二者间的对应关。做这样转换的好处是,您不用担心全形、半形的问题,因为一个 wchar_t 矩阵元就是一个字。
wchar_t 有一组与 string.h 中相对应的字串处理函式 (目前在 Linux 中可能还没有 man page 说明),就定义在 wchar.h 中,让我们可以如同处理 (char *) 那样地处理 (wchar_t *), 其部分的对应关如下,其他的可以直接看 wchar.h 的内容:
wcscpy() <====> strcpy()
wcsncpy() <====> strncpy()
wcslen() <====> strlen()
wcsdup() <====> strdup()
wcscmp() <====> strcmp()
wcsncmp() <====> strncmp()
........................................
由於 mbs 码与 wcs 码的对应关是由该 locale 的 LC_CTYPE 来决定的,也就是不同的 locale 写法其对应关可能会不一样。就我们的 glibc2, zh_TW.Big5 locale 而言,由 mbs 转成的 wcs 即为 unicode (有关 unicode 的资讯可以在 http://www.unicode.org/ 中找到),但不能保在其他的系统或环境下也是如此。故最保险的做法,是将字串储存成 multi-byte, 然後在 run-time 时才用 mbstowcs() 转成 wide-char 来运作。
讯息输出 (详见 info gettext):
一般我们程式的讯息输出,是经由 stdio.h 头的函式,直接输出到 stdout 或 stderr, 而输出的内容是直接写死在程式码中。这样的程式要做多国语文化会造成困扰,因为我们必须要修改原始码,将所有的讯息字串翻译成另一种语文。因此,我们必须透过 locale 的 LC_MESSAGES 来处理讯息输出。其原理很简单,就是将程式中的所有讯息抽离出来,为每一个 locale 分别做好一个讯息档,当程式要输出讯息时,则透过 libc 的函式依目前的 locale 去正确的讯息档中抓取讯息。
在此我用 GNU gettext 为例,简单说明其原理。在 /usr/share/locale 中,头有各种 locale 的资料目录。而每个目录下,都会有一个 LC_MESSAGES 的目录,而这些目录就是用来放各别程式的讯息档。例如:
/usr/share/locale/ja/LC_MESSAGES/prog.mo (日文)
/usr/share/locale/zh_TW.Big5/LC_MESSAGES/prog.mo (Big5)
其中在 ja/ 目录下的 prog.mo 就是 prog 这个程式的日文讯息,而 zh_TW.Big5/ 下的 prog.mo 就是 prog 这个程式的中文讯息。假设在还没加入 LC_MESSAGES 支援之前, prog.c 长得像这样:
--------------------------------------------------------------------------------
#include
main()
{
printf("This is a test string.\n");
}
--------------------------------------------------------------------------------
现在我们要用 gettext 来加入支援,则程式只要改成:
--------------------------------------------------------------------------------
#include
#include
#define _(STRING) gettext(STRING)
#define PACKAGE "prog"
main()
{
setlocale(LC_MESSAGES, "");
textdomain(PACKAGE);
/* 这就是指定用
/usr/share/locale/$LOC/LC_MESSAGES/prog.mo
作为讯息档。其中 $LOC 是在 setlocale 中设定的 */
printf(_("This is a test string.\n"));
/* 使用 gettext 来抓出讯息,再交给 printf 来印 */
}
--------------------------------------------------------------------------------
如果在指定的 locale 下找不到 prog.mo 档,则程式就直接以原英文讯息印出。因此,加入 LC_MESSAGES 的支援,原 source code 修改并不多,其实相当方便。
比较麻烦的是各 locale 下的讯息档作,而这些步骤可以经由 GNU gettext 套件很容易地达成,其步骤简述如下 (详见 info gettext):
xgettext editor msgfmt (install)
source code --> .pot --> .pox --> .gmo --> .mo -->
(节录自 Platin.bbs@csie.nctu.edu.tw 的文章:
[REF] 关於 gettext (一、简介))
使用 xgettext 产生 .pot 档:
xgettext -a -o prog.pot prog.c
而 prog.pot 档的内容如下:
--------------------------------------------------------------------------------
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR Free Software Foundation, Inc.
# FIRST AUTHOR
, YEAR.
#
#: prog.c:8
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 1999-02-28 19:18 0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI ZONE\n"
"Last-Translator: FULL NAME
\n"
"Language-Team: LANGUAGE
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
相关文章