猆nicode inside Locale outsite
http://www.chedong.com/tech/unicode_java.html
作者: 车东 chedong@bigfoot.com
最后更新:2002-12-21 23:40:30
版权声明:可以任意转载,转载时请务必标明原始出处和作者信息
内容摘要:
1 按照JAVA的国际化设计框架规范:如何通过linux系统的本地化设置让JAVA应用支持中文
2 按照Java Webapp设计框架规范:通过web.xml设置解决URLEncoder.encode()方法和系统缺省编码方式相关的问题
3 以GOOGLE的搜索引擎为例:说明如何将国际化和本地化应用到自己的应用设计中(Unicode inside Locale outsite)
通过linux系统的本地化设置让JAVA应用支持中文
Java 编程技术中汉字问题的分析及解决 这篇文章很不错,直到最近还经常被一些网站转贴,其中有一个例子说明了很多中国程序员遇到汉字乱码问题的思路:"GB2312 it"(汉化)
原文如下:
>>>>>>>
......前不久,我的一位技术上的朋友发信给我说,他终于找到了 Java Servlet 中文问题的根源。两周以来,他一直为 Java Servlet 的中文问题所困扰,因为每面对一个含有中文字符的字符串都必须进行强制转换才能够得到正确的结果(这好象是大家公认的唯一的解决办法)。后来,他确实不想如此继续安分下去了,因为这样的事情确实不应该是高级程序员所要做的工作,他就找出 Servlet 解码的源代码进行分析,因为他怀疑问题就出在解码这部分。经过四个小时的奋斗,他终于找到了问题的根源所在。原来他的怀疑是正确的, Servlet 的解码部分完全没有考虑双字节,直接把 %XX 当作一个字符。(原来 Java Soft 也会犯这幺低级的错误!)
如果你对这个问题有兴趣或者遇到了同样的烦恼的话,你可以按照他的步骤对 Servlet.jar 进行修改:
找到源代码 HttpUtils 中的 static private String parseName ,在返回前将 sb(StringBuffer) 复制成 byte bs[] ,然后 return new String(bs,”GB2312”)。作上述修改后就需要自己解码了:
HashTable form=HttpUtils .parseQueryString(request.getQueryString())或者
form=HttpUtils.parsePostData(……)
千万别忘了编译后放到 Servlet.jar 里面。
......
<<<<<<<<<
请问“高级”程序员几个问题:
1 如果这是一个商业产品的话,难道客户需要你Hacking过的Servlet.jar才运行这个应用吗?
2 难道这个产品只能用在中文GB2312上吗?如果是日文应用怎么办,如法Hacking吗?
也许我错了,但我的感觉是犯低级错误的不是JAVA SOFT,因为JAVA应用的本地化不是在WEB应用这一层实现的,而是JVM的系统缺省编码方式根据操作系统的环境设置(locale)改变来实现。在文章发表在2000年年底,当时的LINUX对中文的locale支持还有限,因此,在LINUX上不能根据locale的设置将系统缺省的编码方式变成GB2312,从而改变JVM缺省的编码方式。
关于LINUX对l10n的支持请看:linux程序员必读:中文化与GB18030标准
如何设置可以让LINUX从系统层次就支持中文编码(系统缺省的file.encoding就按照中文编码解码)呢?
所以在redhat6.x下,无论你怎么设置locale,系统缺省的缺省file.encoding都是ISO_8859_1 因为redhat6.2是基于 glibc-2.1.x的。在redhat7.x 系统内核所基于的glibc-2.2.x对l10n有了更完整的支持,所以可以通过设置
LC_ALL=zh_CN.GB2312;export LC_ALL
LANG=zh_CN.GB2312;export LANG
让系统缺省的编码方式变成GB2312 GBK...从而改变JVM的缺省编码方式(file.encoding),之后,任何字节流到字符流的转换,JVM都会按照系统缺省编码方式进行转换。
在基于glibc2.2以上的linux上:是可以通过locale的设置来改变系统缺省的编码方式,从而改变应用的缺省编码、解码方式的。
这里有2点我想说明:
1 为商业性操作系统说句公道话:linux对国际化的支持远远落后于WINDOWS SOLARIS等商业操作系统:2年甚至更多。
2 linux是依靠GNU的工具发展起来的:没有GNU就没有Linux。所以Linux对本地化的支持,也是在核心的glibc-2.2.x对中文locale有了更好的支持以后才逐步发展起来的。
通过web.xml设置解决URLEncoder.encode()方法和系统缺省编码方式相关的问题
据我所理解的范围内,JDK1.3中非常不符合JAVA的国际化规范的是在使用URLEncoder的时候:
比如在中文WIN98上运行的应用,使用URLEncoder.encode(String s)时:比如“中文”这2个字直接被Encoding的话结果是"%3F%3F"=>"??"。原因很简单,“中文”在encode()过程中需要先按GBK编码方式编码成4个BYTE后再URLEncoding才是正确的。这个在JDK1.4中也修正了。方法encode(String s)已经不鼓励使用,取而代之的是除了需要进行URLEncoding的字符串外,同时需要指定字符串编码方式的encode(String s, String enc)。这样,URLEncoder就可以和系统缺省的编码方式无关了。
在JDK1.3下,一个基于web-app框架的应用中,这个问题可以通过在WEB-INF/web.xml中设置来解决:
<web-app character-encoding="your_system_default_file.encoding">
...
</web-app>
如果产品是在中文WINDOWS98运行,缺省字符集是用GBK,则这个应用的web.xml需要设置成:
<web-app character-encoding="GBK">
...
</web-app>
Unicode inside Locale outsite
以上2个方法仍然只是让应用更方便地本地化了,而应用本身并不是真正的国际化应用。设想一下如何设计一个全球的论坛系统:可以让中文和日文的用户都可以方便的浏览发表呢?在数据中间处理阶段应该以那种字符集存储呢?答案很简单:Unicode。以前很多文章都有关于如何设计一个国际化界面的介绍,只是国际化应用的界面输出,但很少提及数据的输入和存储阶段就需要考虑应用以后的国际化,应使用UNICODE处理和存储。最后,我以GOOGLE的国际语言搜索引擎做一个设计实例说明如何实现国际化应用的设计:GOOGLE是一个非常好的国际化应用榜样(但我可没说GOOGLE是java做的哟)。
GOOGLE用户经常有这样的感觉:
为什么我第一次去GOOGLE,出现的就是中文的界面?
为什么在所有网站中查中文:有时候还会出日文网站的结果?比如:"google 秘密"
就以"google 秘密"这个查询为例:我们在输入框输入"google 秘密"
http://www.google.com/search?hl=zh-CN&newwindow=1&q=google+%C3%D8%C3%DC&btnG=Google%CB%D1%CB%F7&lr=
将处理流程简单的说明如下:
输入:查询(按客户端编码方式)=>GOOLGE(将输入的字节流“解码”成UNICODE)=>查询索引(也是UNICODE的)=>UNICODE的结果集=>输出:查询结果,“编码”成客户端系统编码方式的字节流
具体说明:
* GOOGLE如何识别出浏览器使用的“界面语言”:GOOGLE获得这个查询字符串的同时,一般会根据hl=zh-CN这个参数,知道了客户端使用的字符集编码方式,如果用户第一次访问:GOOGLE会根据浏览器的发送的请求中包含的Accept language: zh_cn这个头信息来判别,这就是为什么现在很多用户第一次去GOOGLE的时候它就能自动识别出来的原因。这个参数在之后的查询和翻页过程中通过cookie保存,并通过get方式一直传递给GOOGLE(因此你也可以使用使用偏好设置界面语言),从而可靠地识别出客户端的编码方式。
* GOOGLE如何查询:也许从URL上你可以看到:传过去的“秘密”这个查询实际上是%C3%D8%C3%DC=>"秘密"这2个字按GBK(WINDOWS客户端缺省的编码方式)编码方式的4个字节URLEncode后的形式(关于中文编码方式请参考:汉字的编码方式),GOOGLE将查询字符串按这个编码方式解码并转成UNICODE,然后用这个UNICODE编码方式的字符串进行内部的查询操作。而任何语言的页面都是先转换成UNICODE后存储在GOOGLE的数据索引库里的。在UNICODE中日文和中文写法一样的字,用的是同样的编码。因此,如果你没有指定语言过滤的话,日文网页的结果就首先被命中了;因此,对于中文客户端的查询:如果在UNICODE中映射的字一样,就可以查询到相应的日文网页,繁体中文网页...,GOOGLE的查询结果也首先是UNICODE的,最后将UNICODE结果按照客户端的编码方式转换成字节流,返回到客户端。
从以上的分析中我们可以看出:UNICODE非常漂亮的解决了应用的国际化问题
1. 数据从输入的开始,就全部先转换成UNICODE,然后再进行处理,并按照UNICODE方式集中存储(Unicode inside)
2. 数据输出过程中,只是在最后输出到客户端的时候,按照客户端的本地化设置将UNICODE数据转换成本地字符集,并配以相应语言/字符的界面(Locale outside)
“汉化”思路的根源在于我们的软件开发中满足于自给自足的小农意识,Microsoft和Sun等国际化大公司的产品从一开始就是为世界市场设计的。如果在此之前的应用的汉化设计相当于UCDOS和RichWin的话,那么这种汉化方式迟早要被内核汉化的WIN95淘汰的。毕竟核心级别对国际化的支持才是一个真正简化前端应用设计,通用的解决方案,国内软件行业对相应国际标准显然重视不足,而不用提什么积极参与标准制定了。
参考文档:
Java的国际化设计
http://java.sun.com/docs/books/tutorial/i18n/index.html
linux 国际化本地化和中文化
http://www.linuxforum.net/doc/i18n-new.html
linux 程序员必读:中文化与GB18030标准
http://www.ccidnet.com/tech/os/2001/07/31/58_2811.html
Unicode FAQ
http://www.cl.cam.ac.uk/~mgk25/unicode.html
http://www.linuxforum.net/books/UTF-8-Unicode.html (中文版)
Java 编程技术中汉字问题的分析及解决
http://www-900.ibm.com/developerWorks/java/java_chinese/index.shtml
汉字的编码方式:
http://www.unihan.com.cn/cjk/ana17.htm
*注释:l10n i18n都是缩写:用的是英文单词的首尾字母和其间字母个数
l10n: localization 本地化
i18n: internationalization 国际化
<<返回