电脑技术学习

Linux 的中文化问题简介

dn001
作者按
底下这篇文章是我最近写程式的一点点心得,除了前段部讨论了;Linux;I18N;环境外;(已在;Linux;连线版贴出),後半部还加了一些有关;I18N;程式写作的简介。我想这篇文章就发表在;CLDP;上,希望;CLDP;可以收录。更希望这篇文章对有兴趣的朋友有帮助,让大家能早日进入;I18N;的世界;:-));

由於我所知很有限,所以文章中可能有很多错误,而关於;Xi18n;的部分,我也有很多因为没有去研究,故略过不提了。因此,希望各位高手能多多给我批评与建议,或帮忙我将不足之处补齐,让这篇文章更完美。;

在此先谢谢各位。;

谢东翰;(Tung-Han;Hsieh);


--------------------------------------------------------------------------------

Linux;的中文化问题简介
一、前言:;
最近这个话题大家吵得有点厉害,大家都希望;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;章节,以及;


http://i44www.info.uni-karlsruhe.de/~drepper/conf96/paper.html
http://www.pgroup.com/ppro_docs/pgC++_lib/stdlibug/int_6094.htm
(感谢;Pofeng;Lee;的提供);
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;VERSIONn"
"POT-Creation-Date:;1999-02-28;19:18+0800n"
"PO-Revision-Date:;YEAR-MO-DA;HO:MI+ZONEn"
"Last-Translator:;FULL;NAME;
n"
"Language-Team:;LANGUAGE;
n"
"MIME-Version:;1.0n"
"Content-Type:;text/plain;;charset=CHARSETn"
"Content-Transfer-Encoding:;ENCODINGn"

#:;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;

这一系列的书来看,出版商是;O'Reilly;&;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;Programmer's;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;settingn");
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;中。

标签: linux