Linux 国际化本地化和中文化 (2)
时间:2007-02-17 来源:PHP爱好者
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原子传输.
四 开发符合国际化标准的软件
在X窗口系统下开发软件, 应尽量符合国际化标准. 它包括, 设置合适 的locale(见前
面讲述的在X下使用locale), 注意选择字符集和字体集, 本地化文本的处理, 输入方法
等等. 这里推荐用户尽量使用在国际化方面 已经比较完善的高层图形库, 如Qt, gtk+,
Java等, 这样可以避免考虑以 上问题. 选择Motif时需要考虑资源的国际化问题和
FontList等.
1. 开发国际化软件
使用已经支持国际化的高层图形库开发支持国际化的软件基本上可以不用 考虑国
际化问题. 特别是输入问题, 在标准的输入区内(单行输入和多行输入), 都可以
自动输入汉字. 在字体处理上, 注意使用字体集. 许多软件需要在资源 文件中指
定字体和字体集, 所以开发的软件应提供一个缺省支持字体集的资源 文件.
下面所介绍的开发国际化的软件是基于libX11的开发方法. 除了前面所说的 在软
件初始化时调用一些Locale的函数外, 在实际编程时, 还应注意以下问题:
1. 字体载入: 在处理字符串时, 使用FontSet, 而不是Font:
XCreateFontSet() - 建立字体集
XFreeFontSet() - 释放字体集内存
XFontsOfFontSet() - 返回XFontStruct和字体名
XBaseFontNameListOfFontSet() - 返回字体集的名称
XLocaleOfFontSet() - 返回XFontSet的locale名
XExtentsOfFontSet() - 获得FontSet的最大Extents
2. 计算字符串的屏幕尺寸并画字符串:
Xmb/XwcDrawString() - 只画字型(glyphs)的前景
Xmb/XwcDrawImageString() - 画前景和背景
Xmb/XwcDrawText() - 复杂的间隔和字体集
Xmb/XwcTextEscapement() - X 方向像素
Xmb/XwcTextExtents() - 字符串轮廓
3. 客户程序间通讯:
Xmb/wcTextListToTextProperty() - 根据locale的文本转换
Xmb/wcTextPropertyToTextList() - 根据locale的文本转换
XFreeStringList()
Xmb/wcFreeStringList() - 释放StringList
XSetWMProperties() - 设置窗口管理器属性
XSetWMName() - 设置窗口窗口名
XSetWMIconName() - 设置窗口图标名
4. 输入:
XOpenIM()/XCloseIM() - 打开/关闭输入服务器
XDisplayOfIM()/XLocaleOfIM()
XSetIMValues()/XGetIMValues() - 设置/获取输入服务器属性
XCreateIC()/XDestroyIC() - 建立/释放IC
XIMOfIC()
XSetICValues()/XGetICValues() - 设置/获取IC的值
XSetICFocus()/XUnsetICFocus() - 聚焦/取消聚焦
XmbResetIC()/XwcResetIC() - 重设IC
XFilterEvent() - 过滤事件
Xmb/wcLookupString() - 查找字符串
XRegister/UnregisterIMInstantiateCallback() - 注册/取消回调
2. 使非国际化软件国际化
修改已经存在的非国际化软件, 应根据具体情况采用不同的补丁. 需要 注意的是
修改后的软件应与原来的软件兼容, 不会对软件以前在西文和其它 语言的支持造
成影响. Locale应该是软件的语言切换中心点. 下面是笔者在 修改软件的过程中
一些经验, 仅供参考.
o 在软件初始化时设置Locale.
o 定义gettext的宏, 并且把它与信息文件绑定.
o 对所有静态信息使用gettext
o 对文本绘制使用字体集代替字体
o 绘制函数使用X下的多字节或宽字符函数
o 初始化和XIM服务器的联接
o 在事件循环中用XFilterEvent()过滤事件到XIM服务器
o 使用Xmb/wcLookupString()查找字符串
五 目前中文化中存在的问题
现有的国际化标准中存在许多问题, 问题的原因主要出自目前的 国际化架构. 对于中
文化来说, 这些问题显得更加突出.
1. 编码动态切换的问题
对中文软件来说, 同时支持多内码(GB和Big5)是比较完善的中文软件, 但是动态
切换内码, 特别是切换软件界面(如菜单项)的内码, 是受到信息 (Message)国际
化中 gettext 的限制的. 一般来说, 一旦软件载入, 所有 文本信息便被初始化,
而且在整个过程中不会再重新装载信息. 退一步说, 即使重新装载了信息, 由于
所装载信息的长度发生了变化, 软件界面调整 布局也是十分困难的.
所以现有软件的动态编码切换仅仅是在部分区域实现, 例如Netscape. 遗憾的是,
Netscape的编码切换并不彻底, 它切换的仅仅是显示部分, 输入 部分仍然有问
题. 比如在zh_CN.GBK的环境下启动Netscape, 当切换到有 输入条的繁体中文页
面时, 如果采用输入软件自动识别Input Context的 编码的方式, 仍然会认为
Netscape是GB编码, 输入结果不正确. 如果输入 Big5编码, 必须缩定输出的编码
为Big5. Chinput在这方面做了一些尝试, 结论是可以输入Big5编码, 但是在输入
条中的显示不正确.
一般来说, 使用中文平台来动态切换编码更容易实现. 在中文Linux 的发布版本
中, 有几个是可以使用中文平台来实现动态切换编码的, 其原理 十分简单, 只要
在应用程序或X服务器把某个窗口的编码状态记住就行了, 以后的文本显示和输入
都以此编码为标准. 这种方法的缺点是, 应用程序 初始界面上的中文由于转化了
编码变成了乱码.
2. 中文编码自动识别问题
在文本浏览,网页浏览或网页翻译时, 通常需要自动识别汉字的内码, 但是中文的
GB编码和Big5编码有重叠区域, 所以很难区分开. 目前公开 源代码的识别软件很
少, 识别结果不能令人满意, 远没有达到目前商业软件 的识别水平.
3. Linux上的中文平台到国际化的过渡
但是从长远的角度看, 因为中文在对中文显示和输入上与国际化标准 存在很大差
异, 所以亟需一种从中文平台到国际化标准的过渡性方案. 在 过渡的过程中, 中
文平台可能会和国际化标准共同存在一段时间.
以CLE和TurboLinux为例, 它们在早期的版本中都采用了中文平台来 支持中文的
显示和输入, 随着支持国际化标准的软件的增多, 逐步采用了 中文平台和国际化
标准共同存在的版本作为过渡性版本. 到目前为止, 已经 在缺省情况下放弃中文
平台的使用. 中文平台只是作为残留物包含在发布 版本中.
4. Linux 文档中文化
Linux文档, 主要是指Linux上的一些命令帮助文档(man文件), 软件 手册和说明,
软件本身的Message文件(po). 目前在这方面的工作还缺乏 统一的管理和广大
Linux爱好者的参与.
参考资料
* Unicode: http://www.unicode.org/
* 香港增补字符集: http://www.digital21.gov.hk/chi/hkscs/introduction.html
* CJK 有关信息: ftp://ftp.ora.com/pub/examples/nutshell/ujip/doc/cjk.inf
* Linux国际化资料: http://i18n.linux.org.tw/
* Linux国际化标准: http://www.li18nux.org/. http://
* MicroSoft 国际化: http://www.microsoft.com/globaldev/
六 附录
1. 宽字符处理函数函数与普通函数对照表
字符分类:
宽字符函数 普通C函数 描述
iswalnum() isalnum() 测试字符是否为数字或字母
iswalpha() isalpha() 测试字符是否是字母
iswcntrl() iscntrl() 测试字符是否是控制符
iswdigit() isdigit() 测试字符是否为数字
iswgraph() isgraph() 测试字符是否是可见字符
iswlower() islower() 测试字符是否是小写字符
iswprint() isprint() 测试字符是否是可打印字符
iswpunct() ispunct() 测试字符是否是标点符号
iswspace() isspace() 测试字符是否是空白符号
iswupper() isupper() 测试字符是否是大写字符
iswxdigit() isxdigit() 测试字符是否是十六进制的数字
大小写转换:
宽字符函数 普通C函数 描述
towlower() tolower() 把字符转换为小写
towupper() toupper() 把字符转换为大写
字符比较:
宽字符函数 普通C函数 描述
wcscoll() strcoll() 比较字符串
日期和时间转换:
宽字符函数 描述
strftime() 根据指定的字符串格式和locale设置格式
化日期和时间
wcsftime() 根据指定的字符串格式和locale设置格式
化日期和时间, 并返回宽字符串
strptime() 根据指定格式把字符串转换为时间值,
是strftime的反过程
打印和扫描字符串:
宽字符函数 描述
fprintf()/fwprintf() 使用vararg参量的格式化输出
fscanf()/fwscanf() 格式化读入
printf() 使用vararg参量的格式化输出到标准输出
scanf() 从标准输入的格式化读入
sprintf()/swprintf() 根据vararg参量表格式化成字符串
sscanf() 以字符串作格式化读入
vfprintf()/vfwprintf() 使用stdarg参量表格式化输出到文件
vprintf() 使用stdarg参量表格式化输出到标准输出
vsprintf()/vswprintf() 格式化stdarg参量表并写到字符串
数字转换:
宽字符函数 普通C函数 描述
wcstod() strtod() 把宽字符的初始部分转换为双精度浮点数
wcstol() strtol() 把宽字符的初始部分转换为长整数
wcstoul() strtoul() 把宽字符的初始部分转换为无符号长整数
多字节字符和宽字符转换及操作:
宽字符函数 描述
mblen() 根据locale的设置确定字符的字节数
mbstowcs() 把多字节字符串转换为宽字符串
mbtowc()/btowc() 把多字节字符转换为宽字符
wcstombs() 把宽字符串转换为多字节字符串
wctomb()/wctob() 把宽字符转换为多字节字符
输入和输出:
宽字符函数 普通C函数 描述
fgetwc() fgetc() 从流中读入一个字符并转换为宽字符
fgetws() fgets() 从流中读入一个字符串并转换为宽字符串
fputwc() fputc() 把宽字符转换为多字节字符并且输出到标
准输出
fputws() fputs() 把宽字符串转换为多字节字符并且输出到
标准输出串
getwc() getc() 从标准输入中读取字符, 并且转换为宽字
符
getwchar() getchar() 从标准输入中读取字符, 并且转换为宽字
符
None gets() 使用fgetws()
putwc() putc() 把宽字符转换成多字节字符并且写到标准
输出
putwchar() getchar() 把宽字符转换成多字节字符并且写到标准
输出
None puts() 使用fputws()
ungetwc() ungetc() 把一个宽字符放回到输入流中
字符串操作:
宽字符函数 普通C函数 描述
wcscat() strcat() 把一个字符串接到另一个字符串的尾部
wcsncat() strncat() 类似于wcscat(), 而且指定粘接字符串的
粘接长度.
wcschr() strchr() 查找子字符串的第一个位置
wcsrchr() strrchr() 从尾部开始查找子字符串出现的第一个位
置
wcspbrk() strpbrk() 从一字符字符串中查找另一字符串中任何
一个字符第一次出现的位置
wcswcs()/wcsstr() strchr() 在一字符串中查找另一字符串第一次出现
的位置
wcscspn() strcspn() 返回不包含第二个字符串的的初始数目
wcsspn() strspn() 返回包含第二个字符串的初始数目
wcscpy() strcpy() 拷贝字符串
wcsncpy() strncpy() 类似于wcscpy(), 同时指定拷贝的数目
wcscmp() strcmp() 比较两个宽字符串
wcsncmp() strncmp() 类似于wcscmp(), 还要指定比较字符字符
串的数目
wcslen() strlen() 获得宽字符串的数目
wcstok() strtok() 根据标示符把宽字符串分解成一系列字符
串
wcswidth() None 获得宽字符串的宽度
wcwidth() None 获得宽字符的宽度
另外还有对应于memory操作的 wmemcpy(), wmemchr(), wmemcmp(), wmemmove(),
wmemset().
2. X 窗口系统下支持中文的函数
支持西文的函数 支持中文的函数 描述
XLoadFont XCreateFontSet 载入字体集
XTextExtents(16) Xmb/wcTextExtents 返回文本的限制框
Xmb/wcTextPerCharExtents
XDrawString Xmb/wcDrawString 在窗口中画字符串, 背景填充
XDrawImageString Xmb/wcDrawImageString 在窗口中画字符串
XDrawText Xmb/wcDrawText 在窗口中画字符串
XLookupString Xmb/wcLookupString 查找字符串
3. 支持国际化的高层库
o OSF/Motif
o Qt/kdelib
o gtk+/gnome-lib
o Perl
o Java
4. 支持多语言的典型软件
o 浏览器 Netscape
o 编辑器 XEmacs
o 编辑器 Mule
o 编辑器 vim
o 终端 rxvt
o 排版软件 LaTeX/lyx
o PostScript/PDF: gs/acroread
o 图像处理: gimp
o 幻灯片制作 mgp
o 即将完成: StarOffice, KOffice
5. 支持Unicode的软件
o 高级图形库函数 Qt 2.x
o Java 语言开发工具 JDK
o 编辑器 yudit
o 专用的支持Unicode的 X 终端
o 基于GTK+的文本处理器 GScript
非常全面的一个php技术网站,php 爱好者站 http://www.phpfans.net 有相当丰富的文章和源代码.
在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原子传输.
四 开发符合国际化标准的软件
在X窗口系统下开发软件, 应尽量符合国际化标准. 它包括, 设置合适 的locale(见前
面讲述的在X下使用locale), 注意选择字符集和字体集, 本地化文本的处理, 输入方法
等等. 这里推荐用户尽量使用在国际化方面 已经比较完善的高层图形库, 如Qt, gtk+,
Java等, 这样可以避免考虑以 上问题. 选择Motif时需要考虑资源的国际化问题和
FontList等.
1. 开发国际化软件
使用已经支持国际化的高层图形库开发支持国际化的软件基本上可以不用 考虑国
际化问题. 特别是输入问题, 在标准的输入区内(单行输入和多行输入), 都可以
自动输入汉字. 在字体处理上, 注意使用字体集. 许多软件需要在资源 文件中指
定字体和字体集, 所以开发的软件应提供一个缺省支持字体集的资源 文件.
下面所介绍的开发国际化的软件是基于libX11的开发方法. 除了前面所说的 在软
件初始化时调用一些Locale的函数外, 在实际编程时, 还应注意以下问题:
1. 字体载入: 在处理字符串时, 使用FontSet, 而不是Font:
XCreateFontSet() - 建立字体集
XFreeFontSet() - 释放字体集内存
XFontsOfFontSet() - 返回XFontStruct和字体名
XBaseFontNameListOfFontSet() - 返回字体集的名称
XLocaleOfFontSet() - 返回XFontSet的locale名
XExtentsOfFontSet() - 获得FontSet的最大Extents
2. 计算字符串的屏幕尺寸并画字符串:
Xmb/XwcDrawString() - 只画字型(glyphs)的前景
Xmb/XwcDrawImageString() - 画前景和背景
Xmb/XwcDrawText() - 复杂的间隔和字体集
Xmb/XwcTextEscapement() - X 方向像素
Xmb/XwcTextExtents() - 字符串轮廓
3. 客户程序间通讯:
Xmb/wcTextListToTextProperty() - 根据locale的文本转换
Xmb/wcTextPropertyToTextList() - 根据locale的文本转换
XFreeStringList()
Xmb/wcFreeStringList() - 释放StringList
XSetWMProperties() - 设置窗口管理器属性
XSetWMName() - 设置窗口窗口名
XSetWMIconName() - 设置窗口图标名
4. 输入:
XOpenIM()/XCloseIM() - 打开/关闭输入服务器
XDisplayOfIM()/XLocaleOfIM()
XSetIMValues()/XGetIMValues() - 设置/获取输入服务器属性
XCreateIC()/XDestroyIC() - 建立/释放IC
XIMOfIC()
XSetICValues()/XGetICValues() - 设置/获取IC的值
XSetICFocus()/XUnsetICFocus() - 聚焦/取消聚焦
XmbResetIC()/XwcResetIC() - 重设IC
XFilterEvent() - 过滤事件
Xmb/wcLookupString() - 查找字符串
XRegister/UnregisterIMInstantiateCallback() - 注册/取消回调
2. 使非国际化软件国际化
修改已经存在的非国际化软件, 应根据具体情况采用不同的补丁. 需要 注意的是
修改后的软件应与原来的软件兼容, 不会对软件以前在西文和其它 语言的支持造
成影响. Locale应该是软件的语言切换中心点. 下面是笔者在 修改软件的过程中
一些经验, 仅供参考.
o 在软件初始化时设置Locale.
o 定义gettext的宏, 并且把它与信息文件绑定.
o 对所有静态信息使用gettext
o 对文本绘制使用字体集代替字体
o 绘制函数使用X下的多字节或宽字符函数
o 初始化和XIM服务器的联接
o 在事件循环中用XFilterEvent()过滤事件到XIM服务器
o 使用Xmb/wcLookupString()查找字符串
五 目前中文化中存在的问题
现有的国际化标准中存在许多问题, 问题的原因主要出自目前的 国际化架构. 对于中
文化来说, 这些问题显得更加突出.
1. 编码动态切换的问题
对中文软件来说, 同时支持多内码(GB和Big5)是比较完善的中文软件, 但是动态
切换内码, 特别是切换软件界面(如菜单项)的内码, 是受到信息 (Message)国际
化中 gettext 的限制的. 一般来说, 一旦软件载入, 所有 文本信息便被初始化,
而且在整个过程中不会再重新装载信息. 退一步说, 即使重新装载了信息, 由于
所装载信息的长度发生了变化, 软件界面调整 布局也是十分困难的.
所以现有软件的动态编码切换仅仅是在部分区域实现, 例如Netscape. 遗憾的是,
Netscape的编码切换并不彻底, 它切换的仅仅是显示部分, 输入 部分仍然有问
题. 比如在zh_CN.GBK的环境下启动Netscape, 当切换到有 输入条的繁体中文页
面时, 如果采用输入软件自动识别Input Context的 编码的方式, 仍然会认为
Netscape是GB编码, 输入结果不正确. 如果输入 Big5编码, 必须缩定输出的编码
为Big5. Chinput在这方面做了一些尝试, 结论是可以输入Big5编码, 但是在输入
条中的显示不正确.
一般来说, 使用中文平台来动态切换编码更容易实现. 在中文Linux 的发布版本
中, 有几个是可以使用中文平台来实现动态切换编码的, 其原理 十分简单, 只要
在应用程序或X服务器把某个窗口的编码状态记住就行了, 以后的文本显示和输入
都以此编码为标准. 这种方法的缺点是, 应用程序 初始界面上的中文由于转化了
编码变成了乱码.
2. 中文编码自动识别问题
在文本浏览,网页浏览或网页翻译时, 通常需要自动识别汉字的内码, 但是中文的
GB编码和Big5编码有重叠区域, 所以很难区分开. 目前公开 源代码的识别软件很
少, 识别结果不能令人满意, 远没有达到目前商业软件 的识别水平.
3. Linux上的中文平台到国际化的过渡
但是从长远的角度看, 因为中文在对中文显示和输入上与国际化标准 存在很大差
异, 所以亟需一种从中文平台到国际化标准的过渡性方案. 在 过渡的过程中, 中
文平台可能会和国际化标准共同存在一段时间.
以CLE和TurboLinux为例, 它们在早期的版本中都采用了中文平台来 支持中文的
显示和输入, 随着支持国际化标准的软件的增多, 逐步采用了 中文平台和国际化
标准共同存在的版本作为过渡性版本. 到目前为止, 已经 在缺省情况下放弃中文
平台的使用. 中文平台只是作为残留物包含在发布 版本中.
4. Linux 文档中文化
Linux文档, 主要是指Linux上的一些命令帮助文档(man文件), 软件 手册和说明,
软件本身的Message文件(po). 目前在这方面的工作还缺乏 统一的管理和广大
Linux爱好者的参与.
参考资料
* Unicode: http://www.unicode.org/
* 香港增补字符集: http://www.digital21.gov.hk/chi/hkscs/introduction.html
* CJK 有关信息: ftp://ftp.ora.com/pub/examples/nutshell/ujip/doc/cjk.inf
* Linux国际化资料: http://i18n.linux.org.tw/
* Linux国际化标准: http://www.li18nux.org/. http://
* MicroSoft 国际化: http://www.microsoft.com/globaldev/
六 附录
1. 宽字符处理函数函数与普通函数对照表
字符分类:
宽字符函数 普通C函数 描述
iswalnum() isalnum() 测试字符是否为数字或字母
iswalpha() isalpha() 测试字符是否是字母
iswcntrl() iscntrl() 测试字符是否是控制符
iswdigit() isdigit() 测试字符是否为数字
iswgraph() isgraph() 测试字符是否是可见字符
iswlower() islower() 测试字符是否是小写字符
iswprint() isprint() 测试字符是否是可打印字符
iswpunct() ispunct() 测试字符是否是标点符号
iswspace() isspace() 测试字符是否是空白符号
iswupper() isupper() 测试字符是否是大写字符
iswxdigit() isxdigit() 测试字符是否是十六进制的数字
大小写转换:
宽字符函数 普通C函数 描述
towlower() tolower() 把字符转换为小写
towupper() toupper() 把字符转换为大写
字符比较:
宽字符函数 普通C函数 描述
wcscoll() strcoll() 比较字符串
日期和时间转换:
宽字符函数 描述
strftime() 根据指定的字符串格式和locale设置格式
化日期和时间
wcsftime() 根据指定的字符串格式和locale设置格式
化日期和时间, 并返回宽字符串
strptime() 根据指定格式把字符串转换为时间值,
是strftime的反过程
打印和扫描字符串:
宽字符函数 描述
fprintf()/fwprintf() 使用vararg参量的格式化输出
fscanf()/fwscanf() 格式化读入
printf() 使用vararg参量的格式化输出到标准输出
scanf() 从标准输入的格式化读入
sprintf()/swprintf() 根据vararg参量表格式化成字符串
sscanf() 以字符串作格式化读入
vfprintf()/vfwprintf() 使用stdarg参量表格式化输出到文件
vprintf() 使用stdarg参量表格式化输出到标准输出
vsprintf()/vswprintf() 格式化stdarg参量表并写到字符串
数字转换:
宽字符函数 普通C函数 描述
wcstod() strtod() 把宽字符的初始部分转换为双精度浮点数
wcstol() strtol() 把宽字符的初始部分转换为长整数
wcstoul() strtoul() 把宽字符的初始部分转换为无符号长整数
多字节字符和宽字符转换及操作:
宽字符函数 描述
mblen() 根据locale的设置确定字符的字节数
mbstowcs() 把多字节字符串转换为宽字符串
mbtowc()/btowc() 把多字节字符转换为宽字符
wcstombs() 把宽字符串转换为多字节字符串
wctomb()/wctob() 把宽字符转换为多字节字符
输入和输出:
宽字符函数 普通C函数 描述
fgetwc() fgetc() 从流中读入一个字符并转换为宽字符
fgetws() fgets() 从流中读入一个字符串并转换为宽字符串
fputwc() fputc() 把宽字符转换为多字节字符并且输出到标
准输出
fputws() fputs() 把宽字符串转换为多字节字符并且输出到
标准输出串
getwc() getc() 从标准输入中读取字符, 并且转换为宽字
符
getwchar() getchar() 从标准输入中读取字符, 并且转换为宽字
符
None gets() 使用fgetws()
putwc() putc() 把宽字符转换成多字节字符并且写到标准
输出
putwchar() getchar() 把宽字符转换成多字节字符并且写到标准
输出
None puts() 使用fputws()
ungetwc() ungetc() 把一个宽字符放回到输入流中
字符串操作:
宽字符函数 普通C函数 描述
wcscat() strcat() 把一个字符串接到另一个字符串的尾部
wcsncat() strncat() 类似于wcscat(), 而且指定粘接字符串的
粘接长度.
wcschr() strchr() 查找子字符串的第一个位置
wcsrchr() strrchr() 从尾部开始查找子字符串出现的第一个位
置
wcspbrk() strpbrk() 从一字符字符串中查找另一字符串中任何
一个字符第一次出现的位置
wcswcs()/wcsstr() strchr() 在一字符串中查找另一字符串第一次出现
的位置
wcscspn() strcspn() 返回不包含第二个字符串的的初始数目
wcsspn() strspn() 返回包含第二个字符串的初始数目
wcscpy() strcpy() 拷贝字符串
wcsncpy() strncpy() 类似于wcscpy(), 同时指定拷贝的数目
wcscmp() strcmp() 比较两个宽字符串
wcsncmp() strncmp() 类似于wcscmp(), 还要指定比较字符字符
串的数目
wcslen() strlen() 获得宽字符串的数目
wcstok() strtok() 根据标示符把宽字符串分解成一系列字符
串
wcswidth() None 获得宽字符串的宽度
wcwidth() None 获得宽字符的宽度
另外还有对应于memory操作的 wmemcpy(), wmemchr(), wmemcmp(), wmemmove(),
wmemset().
2. X 窗口系统下支持中文的函数
支持西文的函数 支持中文的函数 描述
XLoadFont XCreateFontSet 载入字体集
XTextExtents(16) Xmb/wcTextExtents 返回文本的限制框
Xmb/wcTextPerCharExtents
XDrawString Xmb/wcDrawString 在窗口中画字符串, 背景填充
XDrawImageString Xmb/wcDrawImageString 在窗口中画字符串
XDrawText Xmb/wcDrawText 在窗口中画字符串
XLookupString Xmb/wcLookupString 查找字符串
3. 支持国际化的高层库
o OSF/Motif
o Qt/kdelib
o gtk+/gnome-lib
o Perl
o Java
4. 支持多语言的典型软件
o 浏览器 Netscape
o 编辑器 XEmacs
o 编辑器 Mule
o 编辑器 vim
o 终端 rxvt
o 排版软件 LaTeX/lyx
o PostScript/PDF: gs/acroread
o 图像处理: gimp
o 幻灯片制作 mgp
o 即将完成: StarOffice, KOffice
5. 支持Unicode的软件
o 高级图形库函数 Qt 2.x
o Java 语言开发工具 JDK
o 编辑器 yudit
o 专用的支持Unicode的 X 终端
o 基于GTK+的文本处理器 GScript
非常全面的一个php技术网站,php 爱好者站 http://www.phpfans.net 有相当丰富的文章和源代码.
相关阅读 更多 +