当前位置:Linux教程 - Linux文化 - Linux 国际化本地化和中文化(三)

Linux 国际化本地化和中文化(三)


--------------------------------------------------------------------------
国际化、本地化和中文化 国际化、本地化和多语言化的概念 中文化 X11 国际化的历史和级别 国际化标准组织 国际化的意义

Locale Locale 的概念 在X中使用Locale 文化习俗的差别

X 窗口系统的国际化 显示的国际化 字符集和编码 多字节字符(Multibyte)和宽字符(WideChar)的使用 Unicode 字体(Font)和字体集(FontSet) 信息的国际化 输入的国际化 打印的国际化 客户程序间通讯的国际化

开发符合国际化标准的软件 开发国际化软件 使非国际化软件国际化

目前中文化中存在的问题 编码动态切换的问题 中文编码自动识别问题 Linux上的中文平台到国际化的过渡

附录 宽字符处理函数函数与普通函数对照表 X 窗口系统下支持中文的函数库 支持多语言的典型软件 支持Unicode的软件 --------------------------------------------------------------------------

三 X 窗口系统的国际化

在 X 窗口系统上的国际化, 特别是中文化, 主要体现在显示,输入和打印三个方面.

1. 显示的国际化

1. 字符集和编码

在Linux上经常使用的字符集是ISO 8859系列的字符集. 它包含了10个 多语 言的单字节编码字符集. 它们分别是, 字符集 涵盖语言 拉丁一字符集, 包含绝大多数的欧洲语言, 例如French(fr), Spanish (es), Catalan (ca), Basque (eu), Portuguese (pt), Italian (it), Albanian (sq), Rhaeto-Romanic (rm), Dutch (nl), ISO 8859-1(Latin1) German (de), Danish (da), Swedish (sv), Norwegian (no), Finnish (fi), Faroese (fo), Icelandic (is), Irish (ga), Scottish (gd), English (en), Afrikaans (af) 和 Swahili (sw). 影响了 美洲, 澳洲和非洲. 拉丁二字符集, 包含了中欧和东欧的语 ISO 8859-2(Latin2) 言:Czech (cs), Hungarian (hu), Polish (pl), Romanian (ro), Croatian (hr), Slovak (sk), Slovenian (sl), Sorbian.

ISO 8859-3(Latin3) 拉丁三字符集, 包括: Esperanto (eo) and Maltese (mt)

拉丁四字符集, 包括: Estonian (et), 巴 ISO 8859-4(Latin4) 尔地克 Latvian (lv) 和 Lithuanian (lt), Greenlandic (kl) , Lappish. Bulgarian (bg), Byelorussian (be), ISO 8859-5(西里尔语) Macedonian (mk), Russian (ru), Serbian (sr) ISO 8859-6(阿拉伯语) 阿拉伯语(ar) ISO 8859-7(希腊语) 希腊语(el) ISO 8859-8(希伯来语) Hebrew (iw) 和Yiddish (ji)

ISO 8859-9(Latin5) 重排了Latin1, 用土耳其语的几个字母做了 替换

ISO 8859-9(Latin6) 重排了Latin4, 去掉了某些符号, 增加了 Inuit等 ISO 8859-11(泰国语) 泰国语(th)

ISO 8859-12 Celtic

ISO 8859-13(Latin7) Baltic Rim 和 Lativian(lv) ISO 8859-14(Latin8) Gaelic 和 Welsh (cy) ISO 8859-15(Latin9) Latin1的变种, 修改了某些字母

双字节字符集主要包含中文,日文和韩文. 它由前导字节(Lead Byte) 和尾 部字节(Trail Byte)构成, 由于一个字符采用了两个字节, 在软件的 国际 化方面又增加了一些麻烦, 比如在显示上, 光标的位置不能位于汉字 之间, 删除和移动时必须是整字操作等, 在输入上, 一般需要预编辑服务器 才能 输入汉字. 下表列出了中日韩语言编码的有关信息:

语 前导字节范 言 字符集 代码页 围 尾部字节范围 简 GB2312-1980 CP936 0xA1-0xF7 0xA1-0xFE 体 中 文 GBK 无 0x81-0xFE 0x40-0x7E, 0x80-0xFE 中 文 繁 BIG-5 CP950 0x81-0xFE 0x40-0x7E, 0xA1-0xFE 体 日 0x81-0x9F, 文 Shift-JIS CP932 0xE0-0xFC 0x40-0xFC(0x7F除外) KSC-5601-1987 CP949 0x81-0xFE 0x41-0x5A,0x61-0x7A,0x81-0xFE 0x84-0xD3 韩 0xD8 0x41-0x7E 文 KSC-5601-1992 CP1361 0xD90-0xDE 0x81-0xFE 0xE0-0xF9 0x31-0x7E 0x41,0xFE

最近, 信息产业部和国家质量技术监督局联合发布了两项新的中文信息 处 理基础性国家标准,为解决偏、生汉字的输入提供了方案。其中GB18030- 2000《信息技术和信息交换用汉字编码字符集、基本集的扩充》,为强制性 国家标准. 它收录了2.7万多个汉字,总编码空间超过150万个码位,为彻底 解决邮政、户政、金融、 地理信息系统等迫切需要的人名、地名用字问题 提供了解决方案,也为汉字研究、古籍整理等领域提供了统一的信息平台基 础。 这项标准还同时收录了藏文、蒙文、维吾尔文等主要的少数民族文字. 字符 集编码范围是:

字节数 编码空间 码位数目 单字节 0x00-0x80 129

双字节 第一字节:0x81-0xFE 23940 第二字节:0x40-0x7E,0x80-0xFE

四字节 四字节范围分别是: 1587600 0x80-0xFE,0x30-0x39,0x81-0xFE,0x30-0x39

香港特别行政区也对Big5编码提出了"香港增补字符集", 其目的,是 收纳 香港特区政府及市民在中文电子通讯中有需要使用的字符,来补充目前 大 五码和ISO10646编码标准内并未包含的字符,以作为一个通用的中文界面, 方便大家能准确地以中文进行电子通讯。香港增补字符集有两套编码方案, 一套适用於大五码系统,另一套适用於ISO10646平台。香港增补字符集的大 五码版本,实际上是政府通用字库的增订版。ISO10646国际编码标准目前并 未包含香港增补字符集内的所有字符。目前尚未收纳在ISO10646内的香港增 补字符集字符,均已提交国际标准化组织管辖下的表意文字小组,以考虑是 否纳入ISO10646日后的新增版本内.

上述标准和草案应该是以后的中文Linux所应该遵循的.

2. 多字节字符(Multibyte)和宽字符(WideChar)的使用

我们平时见到的以文本方式存在的字符都是多字节字符, 它主要用于 文件 存储和网络上的以流(Stream)的方式传输. 一个GB编码的汉字需要两个 字 节. 多字节字符的缺点是在中文处理上不方便, 比如汉字的删除和光标的 移动都会有半汉字问题. 为了文本处理的方便, 在内部操作上通常是把汉字 与英文的混和字符串先转换成等宽度的字符串, 即宽字符, 为软件的内部处 理 提供方便.

glibc2.1.x中多字节字符串和宽字符串的转换有时有问题. 在X下还可以 使 用另外一种方式完成转换, 即使用XmbTextListToTextProperty()和 XwcTextPropertyToTextList() 联合完成转换.

3. Unicode

目前所使用的Unicode 是一种16位字宽的字符编码, 它由非赢利的计算机 组织Unicode研讨会维护和改进. 它起源于Xerox和Apple之间的合作研究. 几 个公司组成了一个非正式的论坛, 接着IBM, Microsoft等公司迅速加入. Unicode研讨会在1990年发表了Unicode标准版本1, 同时国际标准化组织完 成 了一种类似的编码----ISO 10646. 因为没有必要存在两套标准, 所以 Unicode 研讨会和国际标准化组织在1991到1992合二为一. 1994年, 中国和 日本开始对 基于ISO10646上的国家标准进行工作. 现在, Unicode 开始用 在许多产品中.

Unicode包含了当今计算机领域中广泛使用的所由字符, 如世界上大部分 的 书面语言, 印刷字符, 数字和技术符号, 地理图形和标点符号. 由于 Unicode 的一致性, 它在大多数情况下都可能简化软件的国际化过程. 它取 消了处理 多种代码页的必要, 并且由于是16位编码, 因此由双字节字符集 所引起的额外 处理也不必要了.

但是, Unicode作为一种编码也有它的缺陷, 比如编码的位置与排序无关, 所以使软件支持Unicode仅仅是国际化的第一步, 实际情况中还需要与语言 相关 的信息和规则. 所以Unicode一般作为程序的内部处理编码, 必须提供 与其它 编码的双向转换表.

最后需要说明的是, 虽然使用Unicode会使普通的英文文本大两倍, 但是 使 用Unicode的整个系统却不会增加太大, 因为系统存放的文件大部分是二进 制 文件格式, 同时, 使用针对Unicode的压缩方式, 可以把文件压缩成和使 用对应 的8位正文一样大小.

4. 字体(Font)和字体集(FontSet)

在X窗口系统下使用的字体都必须在X服务器中注册X逻辑字体描述(X Logical Font Description)名. 它包括了字体的许多信息, 例如以下为西 文字体和中文 字体的两个例子.

1. -adobe-times-medium-r-normal--14-140-75-75-p-74-iso8859-1 2. -tlc-song-medium-r-normal--24-240-75-75-c-240-gbk-0

为了方便使用, 用户还可以给每一个字体加一个或多个别名, 别名文件 fonts.alias 放在字体目录下, 可以手工编辑. 当字体目录变更或别名变更 后, 必须使用命令 "xset fp rehash"或重新启动X才起作用.

X 字体也可以通过字体服务器(Font Server)加载. 这对于本地不放字体 的 系统或X终端特别有用. 加载的协议可以是TCP或DECNET.

X 窗口系统的字体在X Server中之存在一份, 当所由软件都不使用它时, 字 体的内存自动施放.

字体中包含了制造商名, 字体类型, 权重, 字体大小, 字符集等信息. 它们 也 可以缩写, 省去的部分用星号代替, 比如对上面的中文字体, 可以缩写 为:

-*-song-*-24-*-gbk-0

在实际应用中, 字符串往往是中文和英文的混和字符串, 所以必须使用两种 字体来绘出该字符串, 这种指定两种或两种以上的字体的描述就是字体集. 字体 集一般的格式是把多种字体用逗号隔开, 比如, 指定下列字体集:

"-adobe-helvetica-medium-r-normal--14-*-*-*-*-*-iso8859-*,\ -tlc-song-medium-r-normal--14-*-*-*-*-*-gbk-0"

令人遗憾的是, 中文的GB编码和Big5编码有重叠区域, 不能区分开来, 所以 字体集并不能同时指定GB和Big5的字体.

字体集的具体载入受到Locale的影响.

在许多已经国际化的软件和图形库中, 一般通过资源文件让用户指定字体 集, 比如gtk的简体中文资源文件为/etc/gtk/gtkrc.zh_CN, qt-1.44(国际 化的)的 资源文件是 ~/.qti18nrc 等等.

2. 信息的国际化

信息(Message)国际化是软件国际化中比较重要的一环, 如果使软件可以 支持多 种语言, 在设计时就应当考虑到信息的国际化问题. 现在的绝大多数 软件使用 GNU的gettext作为基本工具. 信息国际化的基本步骤是: o 在软件初始化时设置使用setlocale()设置Locale o 使用gettext宏定义, 使程序看上去比较方便: o 指定信息的位置: o 指定翻译信息: _("Some Strings"); o 在软件完成后,使用 xgettext 提取信息并翻译 o 使用msgfmt把信息文件转换为.mo文件, 安装到locale目录下

/* file this_app.c */ #include #include #define _(String) gettext(String) #define N_(String) gettext(String) #define __(String) (String)

int main(){ //由环境变量决定locale setlocale(LC_ALL, "");

//设置message的位置和文件名 bindtextdomain("this_app", "/usr/share/locale"); textdomain("this_app");

printf(_("Some String")); }

至此, 本程序的国际化过程已完成. 编译并联接成可执行文件this_app.

gcc -o this_app this_app.c

下面是本地化的过程.

o 提取要翻译的信息: xgettext -a -o this_app.po this_app.c o 翻译信息

在文件this_app.po 中含有"Some String":

msgid "Some String" msgstr ""

翻译成:

msgid "Some String" msgstr "一些字符串"

o 格式化信息文件: msgfmt -o this_app.mo this_app.po o 拷贝信息文件到locale的目录下, 比如对于中文zh_CN, cp this_app.mo /usr/share/locale/zh_CN/LC_MESSAGES o 执行文件: LC_ALL=zh_CN ./this_app

3. 输入的国际化

在X窗口系统下输入主要有三种方式:

1. 单此击键输入单字符 2. 两个或多个组合键输入单字符 3. 除键输入外, 还需要转换服务器

其中前两种用于输入西文字符, 比如对于欧洲语言的特殊字符的输入, 通常采用 重映射键盘的方法. 或者使用"加速键"的方法输入, 加速键是键盘 上的特殊键, 按下后不会使光标向后移动.

在Linux下, 使用软件xkeycaps可以把键盘重新映射并且保存整个键盘 在映射后 的对照表, 使用命令xmodmap可以加载映射表.

对于中文输入, 主要使用第三种输入方式. 针对各种语言的综合考虑, X 窗口系 统在输入上定义了下列区域:

1. 预编辑区域(Preedit Area), 用于显示输入的过程, 当用户输入 字符时, 应立即显示在该区域 2. 状态区域(Status Area), 用于显示输入状态, 对中文来说, 用于显示输入 方法, 全角/半角状态, 中文/西文标点符号状态. 3. 辅助区域(Auxiliary Area), 显示可供选择的列表, 又称选择 区域, 它由 输入服务器控制.

根据预编辑区域和状态区域的不同组合, X 窗口系统共定义了四种输入 的风格 (Input Style):

1. Root风格: 预编辑区域和选择区域都在应用软件之外, 它们都是 由输入服 务器完成的, 输入服务器所显示的界面是根窗口的子 窗口. 如类似"中文之 星"的独立的输入条模式. 2. OffTheSpot风格: 预编辑区域和选择区域在应用软件之内, 通常 是在窗口 下方的某个固定区域内. 如XEmacs的缺省输入模式. 3. OverTheSpot风格: 预编辑区域在当前的输入位置, 状态区域 在应用程序的 某一固定区域. 它通常又称为光标跟随模式, 类似 于Windows下的智能ABC 输入方法 4. OnTheSpot风格: 预编辑区域和选择区域都在应用软件之内, 内容是又输入 服务器发送的, 应用程序负责显示.

对中文输入来说, 最好的风格是(3),(4),(1). 对大部分中文输入方法, 必须弹出 辅助区域, 供用户选择, 只有少数的中文输入方法, 如五笔字型, 比较适合(4). 对于状态区域, 中文输入多数选用在Root风格的窗口的某个 位置或使用专用的控 制条. 在MS Windows下比较常用的光标跟随模式, 可以 用(3),(4)来实现. 鉴于 Linux下有的用户把X Window设置成为虚屏模式, 选 择上述的任何一种模式都不 尽满意.

对应用软件来说, 最简单的输入接口是Root风格, 它把显示部分交给 输入服务器 去做. 编写软件时所用的代码量少, 是对软件初步使用国际化 标准的最佳选择. 从方便用户的角度来看, 应用软件, 特别是高层的库函数 应该同时支持四种输入 风格. 令人遗憾的是, 一般软件仅支持两到三种输入 风格. 所以在现在的输入服 务器(IM Server)也很少支持四种风格, 这似乎 成了鸡和蛋的问题.

下面列出几种常用软件和图形库的XIM支持情况:

NetscapeRoot,OffTheSpot,OverTheSpot Java Root,OnTheSpot Qt Root,OverTheSpot gtk+ Root,OverTheSpot rxvt Root,OffTheSpot,OverTheSpot

中文输入需要客户软件和服务器软件的的密切配合, 它们之间是通过 XIM(X Input Method)协议来通讯的. 输入服务器首先起动, 在X Server里 注册自己, 服务器的名字也被注册. 当客户程序起动时, 到X Server里查寻 有没有符合自己 locale类型的输入服务器(如果用XMODIFIERS指定服务器名, 则同时用locale和名 字区分). 找到后, 根据输入服务器提供的风格种类 选择一个最适合自己的风格. 然后客户程序为每一个需要输入的窗口都建立 一个自己的标示IC(Input Context), 里面含有客户程序的信息, 以后的通讯 则一直使用该标示.

下面是直接使用X Lib和服务器联接的过程, 在高层函数库中, 把这一 过程隐藏 了起来:

XIM im; XIC ic; ... if( (im = XOpenIM(display, NULL, NULL, NULL)) == NULL ) { printf("Error : XOpenIM !\n"); exit(0); }

//指定预编辑的类型等... if( (ic = XCreateIC(im, XNInputStyle, XIMPreeditPosition | XIMStatusNothing, XNClientWindow, window, NULL)) == NULL ) { printf("Error : XCreateIC() ! \n"); XCloseIM(im); exit(0); } ...

for(;;) { XNextEvent(display, &event);

//如果输入服务器接收并处理...继续 if (XFilterEvent(&event, None) == True) continue; switch(event.type) { case Expose: XmbDrawString(...); case KeyPress: count = XmbLookupString(ic, (XKeyPressedEvent *) &event, string, len, &keysym, &status); ... } }

目前使用比较广泛的XIM输入服务器有Chinput(简体中文, 同时支持繁体), xcin (繁体中文), kinput2(日文) 和 hanIM/ami(韩文).

中文输入服务器Chinput 选择了OverTheSpot风格作为缺省的输入模式, 它与标准 的输入风格略有不同, 即把预编辑区域偏离输入位置, 使输入区 域同时作为状态 区域, 在很大程度满足了用户的输入习惯. 同时它还使用 辅助工具条显示和改变 输入状态. Chinput还解决了同时使用GB和Big5编码 的问题, 被动输入(Passive Input)问题等. 对于普通用户, 除了使用键盘 输入外, 还可以使用手写识别输入 和语音识别输入方式. 目前的输入架构 基本能够满足它们的要求. 笔者在手写识 别输入方面做了一些尝试, 发 现对绝大部分软件是能够适合被动输入的.

4. 打印的国际化

在X窗口系统下的打印是一个很难解决的问题, 所以到目前为止没有形成 一个统 一的打印标准. 其原因之一就是X窗口系统在设计上把显示和打印完全 分开了.

在Linux最常见的需要打印的文件格式是普通文本文件和PostScript文件. 对于中 文的普通文本文件的打印一般需要先转换为PostScript文件再打印. 对于 PostScript文件, 如果应用软件在生成时含有中文字体信息, 则打印 比较容易实 现, 反之, 则很难实现甚至不可能打印.

目前中文文本文件常用的打印方法通常是,使用gb2ps/bg2ps/cnprint 等 软件转 换成PS文件打印, 转换过程使用了中文的点阵字体. 对已经形成的PS 文件的打 印, 如果不包含中文字体, 直接打印就会输出乱码, 通常使用的方法 是将这一类 PS文件过滤一下, 改为使用中文字体, 然后再打印. 如陈向阳先生 的过滤软件 ps2cps可以打印Netscape的存储文件. 这种打印的缺点是有时输出 的PS中汉字字 符串和英文字符串对不齐. 最好的方法是在PostScript一级实现 中文打印, 陈向 阳先生对ghostscript进行了中文化, 可以直接使用TTF轻松打 印Netscape, Qt/KDE, lyx等软件输出的PS文件. 这种从底层实现打印的方法 也是日文和韩文 所采用的方法.

使用CID(adobe)字体打印的方法也在尝试之中.

总之, 目前的中文打印缺乏统一标准, 应用软件在输出打印PS文件时多数 不考虑 双字节语言的问题, 使打印变得更加复杂化, 所以当前的中文Linux发 布版本多 数不支持中文打印,

5. 客户程序间通讯的国际化

客户程序间通讯(Interclient Communications Conventions, 简称ICCC)是 客户 程序之间共享资源的手段之一. 最常见的应用是文本的拷贝和粘贴和与窗口 管理 器通讯. 但是如果两个应用程序之间所使用的字符集不同, 粘贴就会出现问 题, 甚至粘贴的内容会丢失. 所以客户程序之间必须国际化了的通讯协议.

应用程序和窗口管理器之间的通讯也属于客户程序间通讯.

如果客户程序之间使用的字符集相同, 但是编码不同, 则不会丢失数据, 这时应 该使用复合文本(COMPOUND TEXT)传输. X内部定义了COMPOUND_TEXT 的原子 (Atom)用于传输中英文混和的字符串. 对7字节编码, ASCII或者其它 ISO8859-1 字符集, 客户程序通讯可以不用转换而直接使用XA_STRING原子传输.

(第三章完)

待续

相关链接: Linux 国际化本地化和中文化(二)