一、前言:
最近这个话题大家吵得有点厉害,大家都希望 Linux 能在中文方面有所进步,各家有各家的说法,莫衷一是。由於我最近常与 CLE 的 group 有联系,同时也正在写一些与 中文相关的程式,因此我大略说一下「我们正在做什麽」,让大家参考。
我希望大家能将这篇文章当做技术性文章来读,不要再有情绪化的批评,必境我们要的 是 solution, 情绪化的批评对我们实在没有帮助。除此之外,我的观点可能有错,也 可能过份乐观,也欢迎大家能就技术方面给予我指教。
二、 I18N 与 locale:
要将 Linux 中文化,朝著标准走才是长远之计。各位如果有见过近代商业版的 UNIX 就会晓得,它们「中文化」之彻底,令人惊叹,诸如中文选单、中文讯息 .... 您能想 像得到,或说只能在 Win95/98/NT OS/2 .... 等上头才见得到的 中文环境,它们都 有。然而,它们的中文并不是像目前 Linux 上常见到的那样,由一堆程式七拼八凑出
来的,它们全部都是遵循一个标准: I18N 。
I18N 是 InternationalizatioN (国际化) 的缩写,第一个字 I 与最後一个字 N 之间 有 18 的字母,故名。 I18N 并不是只有表面上将 X Window 「国际化」而已,它是□ 基在最底层的 libc 上。 libc 必须要有 locale 的支援,才能向 I18N 起步。
什麽是 locale? 简单说就是一组「地区语言」的资讯。它包括了 (详见 man setlocale):
LC_CTYPE: 字元定义
LC_MESSAGES: 讯息显示
LC_TIME: 时间显示格式
LC_NUMERIC: 数字显示格式
LC_MONETARY: 货币显示格式
LC_COLLATE: 字母顺序与字串比较
其中,与一般使用者最有关系的,是 LC_CTYPE 与 LC_MESSAGES 。 LC_CTYPE 直接关 系到某些字元或内码在目前的 locale 下是否可印? 要如何转换? 对应到那一个字? .... 等等。 LC_MESSAGES 则关系到软体的讯息输出是什麽样的语文。真正完整的 locale 支援,是当我们在 shell prompt 下,直接设好环境变数,则我们马上就能切
换到那个语文了。例如:
bash: export LC_CTYPE=zh_TW.Big5
有了 locale 的「协定」,使得任何地区的语文,只要在加入适当的 locale data 之後, libc 就能正确地处理它了,而我们的「中文」当然也不例外。由於前人与 CLE
group 的努力,目前我们已有自己的 locale data 了。有安装 CLE 的朋友可以到
/usr/share/locale 下看看, zh_TW.Big5 就是我们的 locale data, 虽然还不够完整,但已能 work。
目前 Linux 对於 locale 的支援如何? 可以大概地说,西方语系差不多没问题了,但 东方语系还有不少问题。如果您的 Linux 系统是用 libc5 (例如 Slackware) 的话,
那差不多可以说支援得相当差,几乎只能靠「七拼八凑」的方法来有限度地使用中文。
如果是用 libc6 (glibc2) 的话,那就有相当的 locale 支援了。
然而,目前大部分使用 glibc2 的系统都是 glibc-2.0.7, 这一版对东方语系的支援还 不够好,特别是 LC_CTYPE ,它无法辨认、转换我们的 Big5 码,必须要等到
glibc-2.1 以後,才能完全解决这些问题。但这并不是说使用 glibc-2.0.7 的广大使 用者都没希望了,事实上有一个 libwcsmbs 的套件,它可以将 glibc 中有问题的部分
取代掉,让我们的 LC_CTYPE 部分可以「几乎 90% 正确」地工作。而这个套件就是目 前 CLE 的标准之一,也是很重要的一个部分,虽然大家可能感受不到它的存在。
最近 glibc-2.1 的 pre-release 已经出来,我个人已做过初步测试, LC_CTYPE 在我 们的 locale 下已经正常,虽然仍有其他问题存在,但这已是一个好消息,我预计在未来的一年内,等大部分的 Linux distribution 都换装了 glibc-2.1 之後,我们就有
了最底层的「中文化」条件。
三、 X Window 的部分:
接著我们来看看上层, X Window 的「中文化」 (或「国际化」)。 X11R6 也有一个 locale 的目录,在 /usr/X11R6/lib/X11/locale □头,如果是装 CLE 的朋友,就
会见到一个 zh_TW.Big5 的目录,那就是我们的 XLC Locale data。在「标准」的情况 下, XLC Locale 必须架构在 libc locale 之上运作,它□头除了定义一些字元对 应,最重要的是内码与字型的对应。以我们的 locale 为例,我们需要两种字型,一是「半形 (单位元)」,显示 ASCII 码用,另一是「全形 (双位元)」用来显示中文。举 一个例子,像以下这一串字:
这是一个 abcd .... 测试字串 string! OK!
那些要用全形显示? 那些要用半形显示? 这必须靠 libc 的 LC_CTYPE 来判断。因此, LC_CTYPE 如果挂掉,可以说什麽都没辄。
我相信,有了上述的「配备」後,基本的 I18N 环境就已经具备了。但一定有人会问: 「看起来 CLE 在上述所说的都没问题,为什麽还是到处都不是中文?」 没错,那是因
为目前 Linux 上大部分的程式还不是用 I18N 的标准而写的。例如大家常用的Netscape, xcin, crxvt .... 等等,它们都是用「自己」的招术来处理中文,这也就
是为什麽 xcin 只能在 crxvt 上输入,为什麽我们要靠 CXWin 来看中文 .... 等等。 这些都不是正解,只是暂时的一个手段,最後都是要放弃的。
目前,有越来越多程式将朝向 I18N 来发展,而我们目前最需要的工作,就是弄 I18N 的 zh_TW.Big5 部分。举个例子,目前 CLE group 正忙於 GNOME 的中文化,它算是目 前 I18N 化相当彻底的一个 X Disktop / Window Manager, Platin 预计在下一版的
CLE 就是以 GNOME 为主,只要将其中的讯息都翻译成中文,做好 LC_MESSAGES 的工 作,未来在 GNOME 中,将不需要依靠 CXWin, 打开後就到处都是中文。
其他的 GNU 软体也是,有另一组人马正将一些常见指令如 ls, cp 等的讯息中文化, 并将结果回报给 GNU, 期望未来新版的 GNU 软体中,中文讯息就是标准的一部分,我 们不再需要每次人家更新版就急急忙忙地做 patch 了。
中文输入就比较复杂,除了上述的 I18N 以外,还有一个 XIM (X Input Method) 协 定。我们必须要有 XIM server 来取代目前的 xcin, 而且还要 X Window 的应用程式 能够遵循 XIM 协定,才能做到 "Chinese Input Anywhere"。目前 CLE 已有一个 XIM server, 即 xcin-cxim 之类的程式,但麻烦的是遵循 XIM 协定的应用程式仍不多,最 著名的就是 GNOME, xemacs, 以及一些 X11R6 所附的软体 (如 xedit, 由 Xt 及 Xaw
提供 I18N 支援)。而我个人目前正在写的 xcin-2.5 就是一个 XIM server, 我希望这 个软体能在将来与「各路人马」配合,做出一点贡献。
因此,「中文化」的工作,并不是那麽简单地说「因为 Linux 是免费、没有人付钱给 程式设计师,所以做不好」,或者说「我们中国人不团结,大家不肯合作发展程式」, 或者说「 Linux 是 server 导向,不适合做中文」 .... 等等。 Linux 可以发展中 文,而且有很多人正努力地在工作,但是更重要的是,我们还得配合国外 (或说软体的
原设计者) 的脚步。前面说过,我们要有完整 locale 支援的 libc, 这一切才有希 望,我们也需要我们常用的软体 (如 Netscape, window manager, 甚至 database,
office ....) 的设计者觉悟到,真正的标准是 I18N, 是 locale, 是 XIM, 我们才能 跟进,将中文化的部分加进去。更重要的一点,我们自己的程式设计师在写软体时,是
不是也能遵循 I18N, locale, XIM??
中文化,需要一个标准,而我们希望这个标准,是世界通用的,而不是我们自己七拼八 凑出来的。否则的话,我们永远都要自己玩自己的,永远都会事倍功半,永远会抱怨
「为什麽 Linux 的中文支援比不上 Win95?」
四、中文列印:
中文列印与上述的关系较小,但也是大家关心的问题之一,在此我也稍作一些说明。
在 UNIX 的世界,就我所知印表机输出最常见的就是两个: ASCII 码与 Postscript, 而 Postscript 就是「图形列印」的共通语言。因此,当我们要做中文列印,就是要寻 求「图形列印」的途径,也就是找一个「能将中文字档转成Postscript 输出」的程式」。目前大家常见的,如传统的 cnprint、 CLE 中能直接使用 TTF 字型的 bg5ps, 或是 ChiTeX, CJK+LaTeX, lyx .... 等等。
在此稍微值得一提的是, CJK 似乎已渐渐成为 Free Software / Open Source 所公认 的标准之一,其原因如下:
它是 Free Software 。
目前 CJK 与 freetype 配合,已经可以完全整合到 LaTeX 的环境中,而不需要 像以往一样需要再更动 LaTeX 的程式与环境。相信在不久的将来它应该会成为 LaTeX 的标
准附件之一。就我所知, Netscape 在下一版的列印部分将支援 CJK 做为中日文 Postscript 输出,我想这一点很值得成为我们未来发展中文列印的一个参考。
五、准备您的 I18N 环境:
以下我针对目前大家常用的系统,如何做到像 CLE 那样,有基本的 locale 环境,而 不必真的非装 CLE 不可 (因为常听大家说 CLE 太大)。虽然以下所说的对各位的中文
环境可能改善不多 (因为目前大部分的软体都还没有 I18N 化),但就当做是为未来做准备。也希望对 source code 有兴趣,喜欢东玩玩、西摸摸 Linux 的网友们,能多多 熟悉这个领域,或者能加入这个领域与我们共同努力。
以下的软体我以 tgz 为主,而不用 RedHat 的 RPM, 或 Debian 的 deb, 希望这个 「共通语言」在大部分的 Linux distribution 都能适用。
请确定您的 Linux 的 libc 是 glibc-2.0.7 以上,若您还是用 libc5, 请参 考您的
distribution 套件,将 glibc-2.0.7 装起来。若您有冒险的精神,想直接玩 glibc-2.1 的话, 可以在这□找到 source:
glibc-pre2.1_*.tar.gz
请注意,如果您决定玩 glibc-2.1, 您必须为自己负责,除非您是有经验者, 否则您要有「 Linux 可能会被我不小心玩挂掉」的心□准备。一个保险的做 法,是找一台空
机器,或一个空的 partition 灌一个白老鼠系统来玩。如果 您不小心出差错而造成任何损失的话,本人不负任何责任。
如果您是用 glibc-2.1 且一切正常的话,那麽恭喜您,您可以略过这一步。 如果您是 用 glibc-2.0.7, 请至 xcin.linux.org.tw 抓
libwcsmbs-0.0.4.tar.gz
wcsmbs-locale-0.4.7.tar.gz
并将它们装起来。这两个套件其实是来自 CLE, 其中特别注意 wcsmbs-locale 这 个套 件,其原始套件不包函 zh_TW.Big5 locale data, 这个 locale data 是 Platin 加入的,有了它才有用。然後,在 /etc/profile 中加一行:
export LD_PRELOAD=<路径名>/libwcsmbs.so
如果您是使用 glibc-2.0.7 的话,请跳过这一步。若您是用 glibc-2.1, 您的系 统多半还没有 zh_TW.Big5 locale data, 此 locale data 可以在上述 wcsmbs-locale 套 件中找到。请将该套件抓回并解开後,找到 localedata 目录下的 zh_TW.Big5 及
charmaps/BIG5 两个档,这两个分别是 locale def 与 charmap 档,您必须 将这两个档 compile 之後才能使用:
localedef -i zh_TW.Big5 -f BIG5 -u charids.894 zh_TW.Big5
(有关 localedef 的用法请见 localedef --help), compile 完成後的 locale data 会自动安装到 /usr/share/locale/zh_TW.big5 下,但由於我们的 locale 名是
zh_TW.Big5, 所以请您自行将它改名,或做一个 symbolic link。
请抓回
ftp://xcin.linux.org.tw/pub/xcin/libwcs/XLC_LOCALE
档,并放在 /usr/X11R6/lib/X11/locale/zh_TW.Big5 目录下 (您可能需要自 行建此目录) ,同时修改 /usr/X11R6/lib/X11/locale/locale.dir 档,在最 後加入这一行:
zh_TW.Big5/XLC_LOCALE zh_TW.Big5
您如果没有中文字型的话,必须抓几个回来装。我个人建议使用 twmoe 字型, 您应该 可以在
ftp://linux.cis.nctu.edu.tw/pcakges/Chinese
□头找到。 twmoe 字型非常多,您不用全抓,像我就只有
kai14.pcf.gz kai15.pcf.gz kai16.pcf.gz
kai18.pcf.gz kai20.pcf.gz kai24.pcf.gz
而已。安装方式是: 造一个 /usr/X11R6/lib/X11/fonts/chinese 目录,将字 型档放 进去,在那个目录下执行 mkfontdir, 在 /etc/X11/XF86Config 中将
/usr/X11R6/lib/X11/fonts/chinese 这个路径加入 FontPath 列表□头。最 後在那个 目录下写一个 fonts.alias 档,建议内容如下
kai18 -twmoe-kai-medium-r-normal--18-180-75-75-c-180-big5-1
kai16 -twmoe-kai-medium-r-normal--16-160-75-75-c-160-big5-1
kai20 -twmoe-kai-medium-r-normal--20-200-75-75-c-200-big5-1
kai14 -twmoe-kai-medium-r-normal--14-140-75-75-c-140-big5-1
kai15 -twmoe-kai-medium-r-normal--15-150-75-75-c-150-big5-1
kai24 -twmoe-kai-medium-r-normal--24-240-75-75-c-240-big5-1
-twmoe-kai-medium-r-normal-fs-18-180-75-75-c-180-big5-0 (接下一行)
-twmoe-kai-medium-r-normal--18-180-75-75-c-180-big5-1
-twmoe-kai-medium-r-normal-fs-16-160-75-75-c-160-big5-0 (接下一行)
-twmoe-kai-medium-r-normal--16-160-75-75-c-160-big5-1
-twmoe-kai-medium-r-normal-fs-20-200-75-75-c-200-big5-0 (接下一行)
-twmoe-kai-medium-r-normal--20-200-75-75-c-200-big5-1
-twmoe-kai-medium-r-normal-fs-14-140-75-75-c-140-big5-0 (接下一行)
-twmoe-kai-medium-r-normal--14-140-75-75-c-140-big5-1
-twmoe-kai-medium-r-normal-fs-15-150-75-75-c-150-big5-0 (接下一行)
-twmoe-kai-medium-r-normal--15-150-75-75-c-150-big5-1
-twmoe-kai-medium-r-normal-fs-24-240-75-75-c-240-big5-0 (接下一行)
-twmoe-kai-medium-r-normal--24-240-75-75-c-240-big5-1
然後重新进入 X-Window 。
到此为止,您的系统已具备 I18N 的环境了,如果应用程式有支援 I18N, 则只要您设
以下的环境变数:
export LC_CTYPE=zh_TW.Big5 (字元显示、转换为 zh_TW.Big5)
export LC_MESSAGES=zh_TW.Big5 (讯息显示为中文)
或
export LC_ALL=zh_TW.Big5
export LANG=zh_TW.Big5 (二者皆为所有的东东都变成中文)
则应该马上可以见到效果。但由於大部分的程式都还没有 I18N 化,因此这□提供两个 例子供您测试:
在 wcsmbs-locale 套件的 source 中,请到 test 目录 make 一下,执行 testmwm 程
式,然後输入任意中英文字 (用 xcin & crxvt) 後按 return, 像这样:
THH:thhpc $ testmwm
我是居士 1234567
mb -> wc, size: 13
wc -> mb, size: 17
a7 da ac 4f a9 7e a4 68 20 31 32 33 34 35 36 37 0a
string in buffer *after* mb -> wc then wc -> mb
我是居士 1234567
表示 LC_CTYPE locale 成功了,若是
THH:thhpc $ testmwm
我是居士 1234567
mb -> wc, size: -1
wc -> mb, size: 0
表示没有成功。可能原因是: 您没有设 LD_PRELOAD? 没有设 LC_CTYPE? 或您以上 的
安装出错了?
您可以在 xedit 中显示中文。但因为 Xlib 有一个 bug, 请您找这个软体回来
compile:
ftp://xcin.linux.org.tw/pub/xcin/libwcs/lcGen.tar.gz
然後在您的 $HOME/.Xresources 中加入:
xtDefaultFontSet: -*-big5-0,-adobe-*-iso8859-1
xedit*international: True
xedit*fontSet: -*-big5-0, -adobe-*-iso8859-1
执行:
xrdb merge ~/.Xresources
LD_PRELOAD="<路径名>/libwcsmbs.so <路径名>/lcGen.so" xedit
这时会跑出一个 xedit 视窗,您可以用 xcin & crxvt 在别的地方先打好一段 中英文 文字,然後用滑鼠 cut & copy 到 xedit, 是不是见到正确的中文了?
(PS. xedit 还有点问题,所以用这个方式用 xedit 读取档案可能会不正常)
六、撰写 I18N 的程式:
在此我将我的一些心得与大家分享。由於这个问题牵涉的层面很广,而我只有针对部分 子题稍微摸索一下,因此本文的目的不在於成为一个「完整」的文件说明,也许做为入 门导引来得好些,希望能对 I18N 程式写作有兴趣的朋友提供一个方向。有兴趣的朋友 同时也可以参考 info libc 的 Locale 章节,以及
ftp.nctu.edu.tw:
/documents/FAQ/comp/answers/internationalization/programming-faq.gz
(感谢 stevel 兄提供)
□头有更完整的说明。
除此之外,在这□我也会参杂一些我个人的理念,不一定是对的,仅供参考,也请各位 多多给予我批评与指教。
第一步: setlocale (详见 man setlocale 与其他相关 man page) 程式的第一步必须要设定 locale, 而一般的写法是 locale 资料是经由环境变数取 得,而不要写死在程式□头,例如:
#include
main()
{
setlocale(LC_ALL, "");
.....
}
或分别设定:
setlocale(LC_CTYPE, "");
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 \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
#: prog.c:10
msgid "This is a test string.\n"
msgstr ""
各位可以注意到倒数两行, msgid 就是原来 source □头的英文讯息,而我 们可以直
接在 msgstr 中将原讯息翻译成中文。所以,接下来的工作其实就 是翻译,我们可以
用任意的编辑器编辑这个档案,并将翻译好的档案存成 prog.pox 档。
将 prog.pox 编译成 prog.gmo:
msgfmt -o prog.gmo prog.pox
其中 prog.gmo。就是我们要的讯息档,等到我们把它安装到
/usr/share/locale/..../LC_MESSAGES/
之後,就名改为 prog.mo 。在此, .pot, pox, gmo 等附档名是 info gettext 中建 议的,分别代表未翻译前的讯息原始档、翻译後的讯息原始档、 经 GNU gettext 套件 编译後的讯息档。
七、撰写 Xi18n 程式:
Xi18n 意指在 X Window 中加入 I18N 的支援。除了上述的部分外, Xi18n 还需要考 虑字形设定、图形字串输出、以及输入的问题。由於目前我只有看过 Xlib, 对於其他 Widget 还没有深入研究,因此我只能对 Xlib 的部分稍作说明。而这类的参考资料, 有兴趣的朋友可以找
The Definitive Guides to the X Window System
这一系列的书来看,出版商是 OReilly & Associates Inc. ,其中有两本
Volume One, Xlib Programming Manual (for Version 11)
Author: Adrian Nye
R6 Update for the R5 Editions of vols. 1, 2, 4, & 5 Programmers Supplement
for Release 6 of the X Window System.
Author: Adrian Nye
在 I18N 方面有详尽的资料,很值得参考。或者是可以看看 XFree86 内附的 .ps 文件 (如果您有安装的话,应该在 /usr/X11R6/lib/X11/doc □头)。
第一步 (详见 man XSupportsLocale):
除了 setlocale() 之外,您还要呼叫 XSupportsLocale() 来确定 X Window 对您 目 前的 locale 是否有支援。另外,您还要呼叫XSetLocaleModifiers() 来设定 一些 X-modifier 的值,□例如下:
#include
#include
#include
main()
{
setlocale(LC_CTYPE, "");
if (XSupportsLocale() != True) {
printf("error X locale setting\n");
exit(0);
}
XSetLocaleModifiers("");
}
在此我们用 X11/Xlocale.h 来取代原来的 locale.h, 这是 "Xlib programming manual" 书中建议的,在其备完整 locale 支援的 libc 环境下,它其实是等价 於
include , 但若在其他环境, Xlocale.h 会用 XLOCALE 机制来 取代原有的机制。
上头的 XSetLocaleModifiers 会存环境变数 XMODIFIERS 中取得 X-modifier 的值并 加以设定之。 XMODIFIERS 的格式为:
export XMODIFIERS=@category=value
目前 category 只有 "im" 有用,如 "@im=xcin-cxims", 意指设定 xcin-cxims 作为
此 X Window 程式的 XIM server。
设定 fontset (详见 man XCreateFontSet):
以往 X Window 程式都是呼叫 XLoadQueryFont() 之类的函式来载入并使用字型。 但 在 Xi18n 的架构下,一个 locale 的 encoding 通常不能光用一种字型来表示。 例如 我们的 zh_TW.Big5, 半形字需用英文字型 (如 -*-iso8859-1),而全形字需 用中文字 型 (如 -twmoe-*-big5-0), 因此,我们不能用 XLoadQueryFont() 将这 些字型分别载 入,而要用 XCreateFontSet() 来载入所需的 fontset。
Display *display;
XFontSet fontset;
char *fontset_name, **missing_charset, *def_string;
int missing_charset_count;
fontset_name = "-*-iso8859-1,-twmoe-*-big5-0";
fontset = XCreateFontSet(display, fontset_name,
&missing_charset_list,
&missing_charset_count,
&def_string);
在这□我们可以将 fontset 看成一个「字型物件」,而不要把它看成 "-*-iso8859-1"
与 "-twmoe-*-big5-0" 这两种字型的组合。当我们要画任何字 串时,我们不用担心要 画的到底是全型字或半型字,使用 fontset 便能帮我们 处理一切。
画出字串 (详见 man XwcDrawImageString, man XmbDrawImageString, manXOpenOM) 平常我们要在视窗画字串时,都会用 XDrawImageString() 等函式,或者用
XDrawImageString16() 来画双位元的字串 (即全型字)。现在可以我们用 XwcDrawImageString (用来画 wide-char (wchar_t *) 字串) 或 XmbDrawImageString
(用来画 multi-byte (char *) 字串) 。不管您输入的字 串是全型或半型,或二者的 混合,使用者两个函式都能正确处理,同时会根据 您的 fontset 的设定来画字。
除此之外, X11R6 还有一个 Output Method 机制,用来做多国语系字串输出 (画字 串),我们可以在程式中呼叫 XOpenOM() 来开启一个 Output Method 。 但这部分我还 没有仔细研究,有兴趣的朋友可以参考本章开头所列的参考资料 以获得进一步资讯。 XIM (详见 man XOpenIM) XIM 应分两方面来谈,一是 XIM server, 另一是 XIM client。对 XIM client 而言,
如同 Output Method 一般,我们可以在程式中呼叫 XOpenIM() 来开启一 个 Input Method, 同时指定 XIM server 的名字。但这部分我还没有仔细研究, 有兴趣的朋友
可以参考本章开头所列的参考资料。
我目前是在写 XIM server 的部分,但我没有直接拿 X Window 的函式来写,而 是拿 IMdkit lib 来写,以简化整个程式写作。在此我不多作说明了,有兴趣的 朋友可以抓
取:
xcin-2.5-19990218.tar.gz
回去看,□头的doc/programming/ 目录中有对此稍作说明,同时 IMdkit 的 source 也整个附在 xcin-2.5 source 中。
文章来源于领测软件测试网 https://www.ltesting.net/