從漢化到國際化
發(fā)表時間:2023-08-14 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]摘要: 1 按照J(rèn)AVA的國際化設(shè)計框架規(guī)范:如何通過Linux系統(tǒng)的本地化設(shè)置讓JAVA應(yīng)用支持中文 2 按照J(rèn)ava Webapp設(shè)計框架規(guī)范:通過web.xml設(shè)置解決URLEncoder.e...
摘要:
1 按照J(rèn)AVA的國際化設(shè)計框架規(guī)范:如何通過Linux系統(tǒng)的本地化設(shè)置讓JAVA應(yīng)用支持中文
2 按照J(rèn)ava Webapp設(shè)計框架規(guī)范:通過web.xml設(shè)置解決URLEncoder.encode()方法和系統(tǒng)缺省編碼方式相關(guān)的問題
3 以GOOGLE的搜索引擎為例:說明如何將國際化和本地化應(yīng)用到自己的應(yīng)用設(shè)計中(Unicode inside Locale outsite)
通過Linux系統(tǒng)的本地化設(shè)置讓JAVA應(yīng)用支持中文
Java 編程技術(shù)中漢字問題的分析及解決 這篇文章很不錯,直到最近還經(jīng)常被一些網(wǎng)站轉(zhuǎn)貼,其中有一個例子說明了很多中國程序員遇到漢字亂碼問題的思路:"GB2312 it"(漢化)
原文如下:
>>>>>>>
......前不久,我的一位技術(shù)上的朋友發(fā)信給我說,他終于找到了 Java Servlet 中文問題的根源。兩周以來,他一直為 Java Servlet 的中文問題所困擾,因為每面對一個含有中文字符的字符串都必須進行強制轉(zhuǎn)換才能夠得到正確的結(jié)果(這好象是大家公認(rèn)的唯一的解決辦法)。后來,他確實不想如此繼續(xù)安分下去了,因為這樣的事情確實不應(yīng)該是高級程序員所要做的工作,他就找出 Servlet 解碼的源代碼進行分析,因為他懷疑問題就出在解碼這部分。經(jīng)過四個小時的奮斗,他終于找到了問題的根源所在。原來他的懷疑是正確的, Servlet 的解碼部分完全沒有考慮雙字節(jié),直接把 %XX 當(dāng)作一個字符。(原來 Java Soft 也會犯這幺低級的錯誤。
如果你對這個問題有興趣或者遇到了同樣的煩惱的話,你可以按照他的步驟對 Servlet.jar 進行修改:
找到源代碼 HttpUtils 中的 static private String parseName ,在返回前將 sb(StringBuffer) 復(fù)制成 byte bs[] ,然后 return new String(bs,”GB2312”)。作上述修改后就需要自己解碼了:
HashTable form=HttpUtils .parseQueryString(request.getQueryString())或者
form=HttpUtils.parsePostData(……)
千萬別忘了編譯后放到 Servlet.jar 里面。
......
<<<<<<<<<
請問“高級”程序員幾個問題:
1 如果這是一個商業(yè)產(chǎn)品的話,難道客戶需要你Hacking過的Servlet.jar才運行這個應(yīng)用嗎?
2 難道這個產(chǎn)品只能用在中文GB2312上嗎?如果是日文應(yīng)用怎么辦,如法Hacking嗎?
也許我錯了,但我的感覺是犯低級錯誤的不是JAVA SOFT,因為JAVA應(yīng)用的本地化不是在WEB應(yīng)用這一層實現(xiàn)的,而是JVM的系統(tǒng)缺省編碼方式根據(jù)操作系統(tǒng)的環(huán)境設(shè)置(locale)改變來實現(xiàn)。在文章發(fā)表在2000年年底,當(dāng)時的LINUX對中文的locale支持還有限,因此,在LINUX上不能根據(jù)locale的設(shè)置將系統(tǒng)缺省的編碼方式變成GB2312,從而改變JVM缺省的編碼方式。
關(guān)于LINUX對l10n的支持請看:Linux程序員必讀:中文化與GB18030標(biāo)準(zhǔn)
如何設(shè)置可以讓LINUX從系統(tǒng)層次就支持中文編碼呢?
所以在redhat6.x下,無論你怎么設(shè)置locale,系統(tǒng)缺省的缺省file.encoding都是ISO_8859_1 因為redhat6.2是基于 glibc-2.1.x的。在redhat7.x 系統(tǒng)內(nèi)核所基于的glibc-2.2.x對l10n有了更完整的支持,所以可以通過設(shè)置
LC_ALL=zh_CN.GB2312;export LC_ALL
LANG=zh_CN.GB2312;export LANG
讓系統(tǒng)缺省的編碼方式變成GB2312 GBK...從而改變JVM的缺省編碼方式(file.encoding),之后,任何字節(jié)流到字符流的轉(zhuǎn)換,JVM都會按照系統(tǒng)缺省編碼方式進行轉(zhuǎn)換。
在基于glibc2.2以上的linux上:是可以通過locale的設(shè)置來改變系統(tǒng)缺省的編碼方式,從而改變應(yīng)用的缺省編碼、解碼方式的。
這里有2點我想說明:
1 為商業(yè)性操作系統(tǒng)說句公道話:linux對國際化的支持遠(yuǎn)遠(yuǎn)落后于WINDOWS SOLARIS等商業(yè)操作系統(tǒng):2年甚至更多。
2 Linux是依靠GNU的工具發(fā)展起來的:沒有GNU就沒有Linux。所以Linux對本地化的支持,也是在核心的glibc-2.2.x對中文locale有了更好的支持以后才逐步發(fā)展起來的。
通過web.xml設(shè)置解決URLEncoder.encode()方法和系統(tǒng)缺省編碼方式相關(guān)的問題
據(jù)我所理解的范圍內(nèi),JDK1.3中非常不符合JAVA的國際化規(guī)范的是在使用URLEncoder的時候:
比如在中文WIN98上運行的應(yīng)用,使用URLEncoder.encode(String s)時:比如“中文”這2個字直接被Encoding的話結(jié)果是"%3F%3F"=>"??"。原因很簡單,“中文”在encode()過程中需要先按GBK編碼方式編碼成4個BYTE后再URLEncoding才是正確的。這個在JDK1.4中也修正了。方法encode(String s)已經(jīng)不鼓勵使用,取而代之的是除了需要進行URLEncoding的字符串外,同時需要指定字符串編碼方式的encode(String s, String enc)。這樣,URLEncoder就可以和系統(tǒng)缺省的編碼方式無關(guān)了。
在JDK1.3下,一個基于web-app框架的應(yīng)用中,這個問題可以通過在WEB-INF/web.xml中設(shè)置來解決:
<web-app character-encoding="your_system_default_file.encoding">
...
</web-app>
如果產(chǎn)品是在中文WINDOWS98運行,缺省字符集是用GBK,則這個應(yīng)用的web.xml需要設(shè)置成:
<web-app character-encoding="GBK">
...
</web-app>
Unicode inside Locale outsite
以上2個方法仍然只是讓應(yīng)用更方便地本地化了,而應(yīng)用本身并不是真正的國際化應(yīng)用。設(shè)想一下如何設(shè)計一個全球的論壇系統(tǒng):可以讓中文和日文的用戶都可以方便的瀏覽發(fā)表呢?數(shù)據(jù)應(yīng)該以那種字符集存儲呢?答案很簡單:Unicode。最后,我以GOOGLE的國際語言搜索引擎做一個設(shè)計實例說明如何實現(xiàn)國際化應(yīng)用的設(shè)計:GOOGLE是一個非常好的國際化應(yīng)用榜樣(但我可沒說GOOGLE是java做的喲)。
GOOGLE用戶經(jīng)常有這樣的感覺:
為什么我第一次去GOOGLE,出現(xiàn)的就是中文的界面?
為什么在所有網(wǎng)站中查中文:有時候還會出日文網(wǎng)站的結(jié)果?比如:"google 秘密"
就以"google 秘密"這個查詢?yōu)槔何覀冊谳斎肟蜉斎?quot;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(將輸入的字節(jié)流解碼成UNICODE)=>查詢UNICODE索引=>UNICODE結(jié)果集=>輸出:查詢結(jié)果(按客戶端編碼方式編碼成字節(jié)流)
具體說明:
GOOGLE如何識別出瀏覽器使用的“界面語言”:GOOGLE獲得這個查詢字符串的同時,一般會根據(jù)hl=zh-CN這個參數(shù),知道了客戶端使用的字符集編碼方式,如果用戶第一次訪問:GOOGLE會根據(jù)瀏覽器的發(fā)送的請求中都包含的Accept language: zh_cn這個頭信息來判別,這就是為什么現(xiàn)在很多用戶第一次去GOOGLE的時候它就能自動識別出來的原因。這個參數(shù)在之后的查詢和翻頁過程中通過cookie保存,并通過get方式一直傳遞給GOOGLE(因此你也可以使用使用偏好設(shè)置界面語言),從而可靠地識別出客戶端的編碼方式。
GOOGLE如何查詢:也許從URL上你可以看到:傳過去的“秘密”這個查詢實際上是%C3%D8%C3%DC=>"秘密"這2個字按GBK(WINDOWS客戶端缺省的編碼方式)編碼方式的4個字節(jié)URLEncode后的形式(關(guān)于中文編碼方式請參考:漢字的編碼方式),GOOGLE將查詢字符串按這個編碼方式解碼并轉(zhuǎn)成UNICODE,然后用這個UNICODE編碼方式的字符串進行內(nèi)部的查詢操作。而任何語言的頁面都是先轉(zhuǎn)換成UNICODE后存儲在GOOGLE的數(shù)據(jù)索引庫里的。在UNICODE中日文和中文寫法一樣的字,用的是同樣的編碼。因此,如果你沒有指定語言過濾的話,日文網(wǎng)頁的結(jié)果就首先被命中了;因此,對于中文客戶端的查詢:如果在UNICODE中映射的字一樣,就可以查詢到相應(yīng)的日文網(wǎng)頁,繁體中文網(wǎng)頁...,GOOGLE的查詢結(jié)果也首先是UNICODE的,最后將UNICODE結(jié)果按照客戶端的編碼方式轉(zhuǎn)換成字節(jié)流,返回到客戶端。
從以上的分析中我們可以看出:UNICODE實際非常漂亮的解決了應(yīng)用的國際化問題
1 數(shù)據(jù)按可以轉(zhuǎn)換成任意字符集的UNICODE方式集中存儲(Unicode inside)
2 然后根據(jù)客戶端的本地化設(shè)置轉(zhuǎn)換成本地字符集 (Locale outside)
如果在此之前的應(yīng)用的漢化設(shè)計相當(dāng)于UCDOS和RichWin的話,這種方式遲早要被內(nèi)核漢化的WIN95淘汰的。畢竟核心級別對國際化的支持才是一個真正的簡化應(yīng)用設(shè)計的通用解決方案。Microsoft和Sun的很多產(chǎn)品從一開始就是為世界市場設(shè)計的,“漢化”思路的根源在于我們的軟件開發(fā)中滿足于自給自足的小農(nóng)意識。
參考文檔:
Java的國際化設(shè)計
http://java.sun.com/docs/books/tutorial/i18n/index.html
Linux 國際化本地化和中文化
http://www.linuxforum.net/doc/i18n-new.html
Linux 程序員必讀:中文化與GB18030標(biāo)準(zhǔn)
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 編程技術(shù)中漢字問題的分析及解決
http://www-900.ibm.com/developerWorks/java/java_chinese/index.shtml
漢字的編碼方式:
http://www.unihan.com.cn/cjk/ana17.htm
*注釋:l10n i18n都是縮寫:用的是英文單詞的首位字母和其間字母個數(shù)
l10n: localization 本地化
i18n: internationalization 國際化