- 将字符串、图标、图片从程序中抽取出来,以文本的形式表示
- 选择编码页(code page),如果需要并定义编码页转换
- 修改所有的文本处理函数,以适应代码页的引入
- 修改所有与格式化输出有关的函数(如日期、时间、货币、数值等)的实现逻辑
- 修改整理/排除函数的实现逻辑
什么是编码页(code page)?
正如我们所知,计算机只懂得数值。因此,当我们想要它处理文本时,就把一门语言中每个字符都赋以特定的值。简单地说来,这种字符与数值的对照表就叫编码页。在这种情况下,你可能常会听到诸如字符集(charset),字符表(charmap),编码(encoding),编码字符集(coded character set)等术语。虽然彼此间还有一些细微的差异,为理解的目的你可以认为它们都是指每种语言的字符、数值映射表。ASCII编码页就是一个很著名的例子,它把英文字母表和一些控制字符映射到一些特定的数值上去。
还有哪些编码页?围绕着编码页有哪些问题?
ASCII编码映射了127个字符,因此7位(bit)二进制数足够用来表示127个字符。程序则典型地在8位的缓冲区内处理文本。这在处理其它的语言的编码页是会出问题。例如日语这种语言,有成千让万个字符,8位二制只能表示256个不同的字符,不可能唯一地表示每一个日语字符。因此,人们用几个字节来表示一个日语字符。现在,我们又遇到另一个问题。缓冲区的字节数不等于缓冲区中的字符数。每一个简单地字符串操作,都需要将字节组装成字符。认识到这种复杂性,开发人员利用一种叫宽字符(wide-character)的技术来处理外语字符串。宽字符基本上是16位或32位的数据类型。容量够大,能满足亚洲语言的需求。处理字符串不再使用8位的缓冲区(char *),而是使用16位的缓冲(unsigned short *)。因此每次移动指针,你都可以保证跳过了一个字符(而不是原先那可能是半个)。
不同的开发商使用不同的编码页,给这带来了混乱。也就是说,同一个日语字符,在一个机器上可能用0x95和0x5c两个字节表示,而在另外的机器的上则可能是0xc9和0xbd。这样一事每次交换数据都要进行一次转换(称为码表转换(charmap conversion)或码集转换(codeset conversion))。
什么是Unicode?它是如何解决这个问题的?
每一种语言的不同的编码页,增加了那些需要支持不同语言的软件的复杂度。因而人们制定了一个世界标准,叫做unicode(http://www.unicode.org).Unicode为每个字符提供了唯一的特定数值,不论在什么平台上、不论在什么软件中,也不论什么语言。也就是说,它世界上使用的所有字符都列出来,并给每一个字符一个唯一特定数值。什么是UTF-8?它与UNICODE是一回事吗?
Unicode的最初目标,是用1个16位的编码来为超过65000字符提供映射。但这还不够,它不能覆盖全部历史上的文字,也不能解决传输的问题(implantation head-ache's),尤其在那些基于网络的应用中。已有的软件必须做大量的工作来程序16位的数据。因此,Unicode用一些基本的保留字符制定了三套编码方式。它们分别是UTF-8,UTF-16和UTF-32。正如名字所示,在UTF-8中,字符是以8位序列来编码的,用一个或几个字节来表示一个字符。这种方式的最大好处,是UTF-8保留了ASCII字符的编码做为它的一部分,例如,在UTF-8和ASCII中,“A”的编码都是0x41.
UTF-16和UTF-32分别是Unicode的16位和32位编码方式。考虑到最初的目的,通常说的Unicode就是指UTF-16。在讨论Unicode时,搞清楚哪种编码方式非常重要。Unicdoe相关的技术介绍参见http://www.unicode.org/unicode/standard/principles.html.
通常说的”特定文化信息(cultural specific information)”包含哪些内容?
- 特定文化有关的字符串(hard-coded strings),程序中不能包含与特定文化有关的任何字符串,这类串都要放在外部文件中,从而能译成多种语言。
- 字符分类(character classification) 如何对字符进行分类呢?例如,英文中可以将字符分为大写字符和小写字符,如果你是个C程序员,则可以用isupper()和islower()来检查。当面临多种语言时,需要考虑更多分类方法,有时候大小写分类法在某些语言中没有任何意义。
- 数值和货币格式 货币符号,以及将数值中数位分组的方式,每个国家各不相同。
- 日期和时间格式 年、月、日哪个写在最前面?
- 整理/排序 如果比较字符”A”和“B”,你可以实际比较它们的ASCII值来决定它们的顺序。但是,在不同的编码页可能并不如此。因此必须用特殊的规则来决定字符顺序。
什么是locale?
I18N的主要目标,是将所有与特定文化有关的信息从代码抽取出来。这也就意味着,你需要在运行时要装载这些数据,因而你的软件能够在那种语言中正常运行。在开发人员的语言中,一个locale不过是一个这种动态加载的数据的句柄(handle)。基于这种技术,locale有几个组件,基本的组件有语言、地域和编码页。
什么是“code page”?为什么需要它?
由于一种语言可有多个编码页(如日语,有EUC、Shift-JIS、UTF-8等编码页),有时在两个系统间交换数据时必须做编码页转换。另一种情况是,当你在一个分布式系统上工作时且决定用Unicode编码页保存数据时,在进行显示时必须转换成本地的编码;或者当你收到用户的输入等。编码页转换通常是一个查表操作,非常耗费资源。只有很少的编码页转换,如UTF-16到UTF-8提供了转换算法。
什么是转换敏感的编码页shift sensitive codepages?
在一些亚洲语言的编码中,一些特殊的字节序列,是用来区分单字节字符和双字节字符的。例如,在日语ISO-2022-JP编码页中,字节序列/x1B/x24/x40用来表示从单字节字符进入双字节字符,而字节序列/x1B/x28/x42则用来表示从双字节字符到单字节字符。换句话说,在分析一个字符串时,如果你遇到了字节序列/x1B/x24/x40,则你知道从此以后的将是一些双字节字符。用以标志从单字节字符转到双字节字符的字节序列叫做shift-in序列,另一个则叫shift-out序列。这些转换点对解析字符串提出了挑战,因为你要一直保存着当前的状态,以便进行相关的字符器操作。ISO-2022-JP 和 ISO-2022-KR 是两个非常著名的日语和韩语转换敏感编码页,流行于很多的HTML页面中。
什么是EBCDIC编码页?
EBCDIC这个编码页的缺点是,即使英文字符也不与ASCII值一致。这儿有EBCDIC和ASCII的对照表。
关于亚洲字符集有什么好的参考书供初学者?
Ken Lunde的CJKV Information Processing.
什么是国际化QA(internationalization QA)?
就是那些特别关注产品的语言兼容性测试的QA。这包括测试产品在其语言环境中识别和初始化语言处理的行为、适应那个环境的能力。白盒测试应当典型地包括检查那此实现I18N兼容性标准的代码(如使用正确实的API等)。黑盒测试应典型地包括在不同的语言环境中产品全部功能的回归测试以及测试界面上的本地化语言的字符串。特定文化信息也需要检查(如日期、时间显示等)。
什么是本地化QA(localization QA)?
本地化QA在软件本地化/翻译完这后进行。重点不仅包括功能,而且包括GUI上下文中的信息的翻译是否适宜。还包括检查GUI布局,确保没有信息被截断等。它通常由以某种语言为母语的人来测试。
我只懂英文,也能做国际化QA吗 ?
当然可以。QA中i18n的那部分,不需要特定语言的任何知识,虽然懂得这种语言迟早会用上排场,尤其是进行环境语言设置的时候。如果你作i18nQA,你的产品还没有进行翻译,则它的界面仍以英文显示。也可能有一些来自己运行环境的错误信息你搞不清楚,但通常你可以据错误代码到英文错误信息库中查找相关内容。
在亚洲语言环境中,常有哪些问题会造成软件运行的中断?
许多的亚洲语言的编码页中,多字节字符的第二个字节在ASCII范围内。这类字符易造成软件的中断。
如何将字符串从一种编码转换到其它编码?
利用*nix环境中利用iconv命令,或下载jiconv。
如何看某一个字符的16进制编码?
在*nix环境中利用od -x命令,在win环境下用hod.exe
什么是jchardet?
jchardet是mozilla自动字符集探测算法代码的java移植,其源代码可以从sourceforge下载。这个算法的最初作者是frank Tang,C++源代码在http://www.infomall.cn/cgi-bin/mallgate/20040514/http://lxr.mozilla.org/mozilla/source/intl/chardet/,可以从http://www.infomall.cn/cgi-bin/mallgate/20040514/http://www.mozilla.org/projects/intl/chardet.html得到更多关于这个算法的信息。
什么是jchardet?
jchardet是mozilla自动字符集探测算法代码的java移植,其源代码可以从sourceforge下载。这个算法的最初作者是frank Tang,C++源代码在http://www.infomall.cn/cgi-bin/mallgate/20040514/http://lxr.mozilla.org/mozilla/source/intl/chardet/,可以从http://www.infomall.cn/cgi-bin/mallgate/20040514/http://www.mozilla.org/projects/intl/chardet.html得到更多关于这个算法的信息。
编译及应用
将下载后的chardet.zip解压缩后,到~/mozilla/intl/chardet/java/目录下,运行ant即可在dist/lib目录下生成chardet.jar,将这个jar包加入CLASSPATH.然后
结果:CHARSET = GB18030
运行:java org.mozilla.intl.chardet.HtmlCharsetDetector http://www.wesnapcity.com/
结果:CHARSET = ASCII
运行:java org.mozilla.intl.chardet.HtmlCharsetDetector http://www.wesnapcity.com/blog/
结果:CHARSET = UTF-8
编程使用
下面就jchardet.jar中的HtmlCharsetDetector.java,对调用jchardet过程予以说明:
nsICharsetDetectionObserver cdo=new nsICharsetDetectionObserver() {
public void Notify(String charset) {
HtmlCharsetDetector.found = true ;
System.out.println("CHARSET = " + charset);
}
};
/**
* 初始化nsDetector()
*lang为一个整数,用以提示语言线索,可以提供的语言线索有以下几个:
*
- Japanese
- Chinese
- Simplified Chinese
- Traditional Chinese
- Korean
- Dont know (默认)
*/
nsDetector det = new nsDetector(lang) ;
// 设置一个Oberver
det.Init(cdo);
BufferedInputStream imp = new BufferedInputStream(url.openStream());
byte[] buf = new byte[1024] ;
boolean done = false ; //是否已经确定某种字符集
boolean isAscii = true ;//假定当前的串是ASCII编码
while( (len=imp.read(buf,0,buf.length)) != -1) {
// 检查是不是全是ascii字符,当有一个字符不是ASC编码时,则所有的数据即不是ASCII编码了。
if (isAscii) isAscii = det.isAscii(buf,len);
// 如果不是ascii字符,则调用DoIt方法.
if (!isAscii && !done) done = det.DoIt(buf,len, false);//如果不是ASCII,又还没确定编码集,则继续检测。
}
det.DataEnd();//最后要调用此方法,此时,Notify被调用。
if (isAscii) {
System.out.println("CHARSET = ASCII");
found = true ;
}
if (!found) {//如果没找到,则找到最可能的那些字符集
String prob[] = det.getProbableCharsets() ;
for(int i=0; i System.out.println("Probable Charset = " + prob[i]);
}
}
jchardet主要解决什么样的问题?
Java字符串(及字符)类以Unicode编码保存数据。当处理来自外部的国际性文本时,我们需要提供关于这些文本的编码,以便准确地将它们转换为Unicode。这意味着你必须知道你的java代码要处理的所有文件的编码。许多基于Internet的Java应用程序,要处理来自随机数据源的数据,而很多数据的编码不能确切的知道。例如,一个HTML页面中的数据,如果没有元数据标签明确地指定页面的字符集,就很难确实其编码,将其转换为Java Unicode字符串时也会误用而终止。
这个算法是如何工作的?
浏览器处理这个问题的方法,是对数据一个字节一个字节的检查,以力图测试字符集(当你点击菜单View->Auto-select或auto-detect时)。这个算法(最初由Frank Tang开发)检查字节序列,基于每个字节的值,利用逐步消除法(elimination logic)逐步缩小以至最后确定字符集。如果这个方法仍难以确定,就利用另一个方法,根据某种语言的字符的频次统计来确实字符集。
iconv和jiconv都可以将文本信息的从一种编码转换为另一种。
iconv是*nix上的一个工具程序。其基本格式是:
iconv能认识的字字符集有
已知perl、php等语言,都有对这个iconv包装接口。
对Java语言,则更简单,不需要外部的程序或包就可以实现。
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out,toEncoding));
String str ;
while((str=in.readLine()) != null) {
out.write(str,0,str.length());
out.newLine();
out.flush();
}
java支持的字符集有:
Basic Encoding Set (contained in rt.jar)
Canonical Name | Description |
---|---|
ASCII | American Standard Code for Information Interchange |
Cp1252 | Windows Latin-1 |
ISO8859_1 | ISO 8859-1, Latin alphabet No. 1 |
UnicodeBig | Sixteen-bit Unicode Transformation Format, big-endian byte order, with byte-order mark |
UnicodeBigUnmarked | Sixteen-bit Unicode Transformation Format, big-endian byte order |
UnicodeLittle | Sixteen-bit Unicode Transformation Format, little-endian byte order, with byte-order mark |
UnicodeLittleUnmarked | Sixteen-bit Unicode Transformation Format, little-endian byte order |
UTF8 | Eight-bit Unicode Transformation Format |
UTF-16 | Sixteen-bit Unicode Transformation Format, byte order specified by a mandatory initial byte-order mark |
Extended Encoding Set (contained in i18n.jar)
Canonical Name | Description |
---|---|
Big5 | Big5, Traditional Chinese |
Big5_HKSCS | Big5 with Hong Kong extensions, Traditional Chinese |
Cp037 | USA, Canada (Bilingual, French), Netherlands, Portugal, Brazil, Australia |
Cp273 | IBM Austria, Germany |
Cp277 | IBM Denmark, Norway |
Cp278 | IBM Finland, Sweden |
Cp280 | IBM Italy |
Cp284 | IBM Catalan/Spain, Spanish Latin America |
Cp285 | IBM United Kingdom, Ireland |
Cp297 | IBM France |
Cp420 | IBM Arabic |
Cp424 | IBM Hebrew |
Cp437 | MS-DOS United States, Australia, New Zealand, South Africa |
Cp500 | EBCDIC 500V1 |
Cp737 | PC Greek |
Cp775 | PC Baltic |
Cp838 | IBM Thailand extended SBCS |
Cp850 | MS-DOS Latin-1 |
Cp852 | MS-DOS Latin-2 |
Cp855 | IBM Cyrillic |
Cp856 | IBM Hebrew |
Cp857 | IBM Turkish |
Cp858 | Variant of Cp850 with Euro character |
Cp860 | MS-DOS Portuguese |
Cp861 | MS-DOS Icelandic |
Cp862 | PC Hebrew |
Cp863 | MS-DOS Canadian French |
Cp864 | PC Arabic |
Cp865 | MS-DOS Nordic |
Cp866 | MS-DOS Russian |
Cp868 | MS-DOS Pakistan |
Cp869 | IBM Modern Greek |
Cp870 | IBM Multilingual Latin-2 |
Cp871 | IBM Iceland |
Cp874 | IBM Thai |
Cp875 | IBM Greek |
Cp918 | IBM Pakistan (Urdu) |
Cp921 | IBM Latvia, Lithuania (AIX, DOS) |
Cp922 | IBM Estonia (AIX, DOS) |
Cp930 | Japanese Katakana-Kanji mixed with 4370 UDC, superset of 5026 |
Cp933 | Korean Mixed with 1880 UDC, superset of 5029 |
Cp935 | Simplified Chinese Host mixed with 1880 UDC, superset of 5031 |
Cp937 | Traditional Chinese Host miexed with 6204 UDC, superset of 5033 |
Cp939 | Japanese Latin Kanji mixed with 4370 UDC, superset of 5035 |
Cp942 | IBM OS/2 Japanese, superset of Cp932 |
Cp942C | Variant of Cp942 |
Cp943 | IBM OS/2 Japanese, superset of Cp932 and Shift-JIS |
Cp943C | Variant of Cp943 |
Cp948 | OS/2 Chinese (Taiwan) superset of 938 |
Cp949 | PC Korean |
Cp949C | Variant of Cp949 |
Cp950 | PC Chinese (Hong Kong, Taiwan) |
Cp964 | AIX Chinese (Taiwan) |
Cp970 | AIX Korean |
Cp1006 | IBM AIX Pakistan (Urdu) |
Cp1025 | IBM Multilingual Cyrillic: Bulgaria, Bosnia, Herzegovinia, Macedonia (FYR) |
Cp1026 | IBM Latin-5, Turkey |
Cp1046 | IBM Arabic - Windows |
Cp1097 | IBM Iran (Farsi)/Persian |
Cp1098 | IBM Iran (Farsi)/Persian (PC) |
Cp1112 | IBM Latvia, Lithuania |
Cp1122 | IBM Estonia |
Cp1123 | IBM Ukraine |
Cp1124 | IBM AIX Ukraine |
Cp1140 | Variant of Cp037 with Euro character |
Cp1141 | Variant of Cp273 with Euro character |
Cp1142 | Variant of Cp277 with Euro character |
Cp1143 | Variant of Cp278 with Euro character |
Cp1144 | Variant of Cp280 with Euro character |
Cp1145 | Variant of Cp284 with Euro character |
Cp1146 | Variant of Cp285 with Euro character |
Cp1147 | Variant of Cp297 with Euro character |
Cp1148 | Variant of Cp500 with Euro character |
Cp1149 | Variant of Cp871 with Euro character |
Cp1250 | Windows Eastern European |
Cp1251 | Windows Cyrillic |
Cp1253 | Windows Greek |
Cp1254 | Windows Turkish |
Cp1255 | Windows Hebrew |
Cp1256 | Windows Arabic |
Cp1257 | Windows Baltic |
Cp1258 | Windows Vietnamese |
Cp1381 | IBM OS/2, DOS People's Republic of China (PRC) |
Cp1383 | IBM AIX People's Republic of China (PRC) |
Cp33722 | IBM-eucJP - Japanese (superset of 5050) |
EUC_CN | GB2312, EUC encoding, Simplified Chinese |
EUC_JP | JIS X 0201, 0208, 0212, EUC encoding, Japanese |
EUC_JP_LINUX | JIS X 0201, 0208, EUC encoding, Japanese |
EUC_KR | KS C 5601, EUC encoding, Korean |
EUC_TW | CNS11643 (Plane 1-3), EUC encoding, Traditional Chinese |
GBK | GBK, Simplified Chinese |
ISO2022CN | ISO 2022 CN, Chinese (conversion to Unicode only) |
ISO2022CN_CNS | CNS 11643 in ISO 2022 CN form, Traditional Chinese (conversion from Unicode only) |
ISO2022CN_GB | GB 2312 in ISO 2022 CN form, Simplified Chinese (conversion from Unicode only) |
ISO2022JP | JIS X 0201, 0208 in ISO 2022 form, Japanese |
ISO2022KR | ISO 2022 KR, Korean |
ISO8859_2 | ISO 8859-2, Latin alphabet No. 2 |
ISO8859_3 | ISO 8859-3, Latin alphabet No. 3 |
ISO8859_4 | ISO 8859-4, Latin alphabet No. 4 |
ISO8859_5 | ISO 8859-5, Latin/Cyrillic alphabet |
ISO8859_6 | ISO 8859-6, Latin/Arabic alphabet |
ISO8859_7 | ISO 8859-7, Latin/Greek alphabet |
ISO8859_8 | ISO 8859-8, Latin/Hebrew alphabet |
ISO8859_9 | ISO 8859-9, Latin alphabet No. 5 |
ISO8859_13 | ISO 8859-13, Latin alphabet No. 7 |
ISO8859_15_FDIS | ISO 8859-15, Latin alphabet No. 9 |
JIS0201 | JIS X 0201, Japanese |
JIS0208 | JIS X 0208, Japanese |
JIS0212 | JIS X 0212, Japanese |
JISAutoDetect | Detects and converts from Shift-JIS, EUC-JP, ISO 2022 JP (conversion to Unicode only) |
Johab | Johab, Korean |
KOI8_R | KOI8-R, Russian |
MS874 | Windows Thai |
MS932 | Windows Japanese |
MS936 | Windows Simplified Chinese |
MS949 | Windows Korean |
MS950 | Windows Traditional Chinese |
MacArabic | Macintosh Arabic |
MacCentralEurope | Macintosh Latin-2 |
MacCroatian | Macintosh Croatian |
MacCyrillic | Macintosh Cyrillic |
MacDingbat | Macintosh Dingbat |
MacGreek | Macintosh Greek |
MacHebrew | Macintosh Hebrew |
MacIceland | Macintosh Iceland |
MacRoman | Macintosh Roman |
MacRomania | Macintosh Romania |
MacSymbol | Macintosh Symbol |
MacThai | Macintosh Thai |
MacTurkish | Macintosh Turkish |
MacUkraine | Macintosh Ukraine |
SJIS | Shift-JIS, Japanese |
TIS620 | TIS620, Thai |
需要说明的是:j2sdk的 US-only 版本只支持第一个表格中的字符集,而国际版(有lib/i18n.jar的那个)则可支持这两个表格中的字符集。
东坡有诗“无竹则俗,无肉则廋;不俗不廋,竹笋炒肉”。:)
欢迎光临的每一位朋友。这是我的第一个BLOG,用来记录我的所学、所做、所思、所想、所经历、所感受。