这是一篇我写的关于GB2312码制转换及Plone上的GB2312编码的文章,HTML格式的文档可以在我的主页上找到,相关的下载也在我的主页上可以找到。
从GB2312到Unicode的转换实现经历及如何实现Plone的GB2312编码(一)
作者: limodou 最后修改日期:2003/02/28
起因
为什么要做这个东西?不久前我在Zope下安装Plone时遇到一个问题,那就是中文化的问题。从Plone上以及CZUG上得知它支持中文,于是我找到潘俊勇的一篇文档--Plone的Unicode中文方案--上面有详细的关于如何中文化Plone的过程。[1]
不过他使用的是utf-8编码,这样你在浏览器中查看源码时看到的都是乱码(utf-8编码)。不过我有一个解决的方法是,先在浏览器中选中要拷贝下来的内容,再打开一个编辑器粘贴下来即可。但这样只有文本而不是原来的格式了。对于我个人来说喜欢使用GB2312编码。因此我想能不能在Plone 中使用GB2312编码呢?下面就是我的实践。
首先生成GB2312编码的po文件。安装好plone后,会找到i18n的目录,里面全部是各种语言的翻译文档。其中plone-zh- cn.po就是潘俊勇翻译的utf-8编码的文档。用IE打开它,如果是乱码请改变IE的编码模式为unicode(utf-8)编码。这样就会看到中文了。全选后,打开一个编辑器,粘贴。这样就自动将utf-8编码的文档变成了GB2312编码的文档。将其另存一下,我起的文件名为plone-zh- cn-gb2312.po。然后修改文件开始处的Content-Type为charset=gb2312;Preferred-encodings为 gb2312 utf-8。改好后保存。如果大家仔细看plone-zh-cn.po文件,可以看到文件头的最后一行为"Domain: plone"。这说明后面的翻译在plone域下使用的。
在Localizer中增加messagecatalog组件,ID可以随便起。我起的名字叫plone。增加后,点击plone组件。进入管理界面后,选择languages标签。增加语言为Chinese/China [zh-CN],并将其置为default状态。然后选择Import/Export标签,在下面的Import处导入刚才创建好的plone-zh- cn-gb2312.po文件。
这时候问题来了。导入时报:
Error Type: UnicodeError
Error Value: UTF-8 decoding error: unexpected code byte
于是我想是不是我生成的文件有问题。看到i18n里提供big5编码的翻译文件,我想试试它是否可以装入。但试过后依然不行。
于是我开始到网上到处找资料。在TWZUG上找到一篇文档设定Plone中文环境。其中写到要下载一个转码包,并将其安装到python的 bin/lib/encodings目录下。看来缺省的python的确是不支持gb2312编码的。于是我打开python环境,进行下列测试。
>>> a="我们"
>>> a.decode('gb2312')
Traceback (most recent call last):
File "<pyshell#1>", line 1, in ?
a.decode('gb2312')
LookupError: unknown encoding
>>>
这说明,python不支持GB2312编码。我需要装一个可以支持GB2312编码的转码器才行。
我按照上面那篇文档的说明,下载了Chinese Codecs 1.2.0包。原本想看一看big5的转码器是如何写的。打开压缩包一看,不错还有中文的。这下好了。
Unicode转码器
不过我没有完全采用它的内容,因为我想知道为什么,怎么去做。
转码器是用来实现Unicode编码与本地编码的转换。因此它需要实现编码与解码两种功能。python的lib/encodings目录下有许多转码器,如果你打开看,在文件头会告诉你是使用gencodec.py生成的(关于它以后的文章再说)。一般的转码器都要从codecs模块的 Codec类进行派生,需要实现encode和decode两个功能。其中,encode是用来将Unicode编码转换成其它编码,decode是用来将其它编码转换成Unicode编码。如果你实现了这两个方法,你的转码器基本上就完成了。一个转码器写好后,一般还要注册才行,可以使用codecs模块的register函数。不过,你可能在这些转码器中看不见这个调用。因为encodings目录下的__init__.py文件帮你做了注册工作。在 __init__.py中,它会搜索整个encodings目录下所有的转码器,并一一进行注册。
其实转码器的工作原理很简单。创建两个对照表,Unicode->GB2312的编码对照表和GB2312->Unicode的解码对照表。将Unicode编码转化为GB2312编码时(即调用encode),对每一个Unicode编码,查找编码对照表,找到其对应的GB2312 编码,并将其合成一个字符串返回即可。将GB2312L编码转化为Unicode编码时(即调用decode),查找解码对照表,找到其对应的 Unicode编码,并将其合成一个字符串返回即可。当你仔细阅读下载的转换程序时,你会发现Chinese Codecs包中,两个转换码表放在两个单独的文件中,其实这样是没有必要的。只要我们已经有了一个对照表,可以将键与值进行调换即可生成另一个对照表。其实别的转码器也是这样做的。再仔细观察两个码表,我们会发现编码都是有区间的。这样就没有包含常用的ASCII码。对于ASCII码的处理就放在了 encode和decode函数中完成了。
对于decode函数要复杂一些。它主要是解决如何判断一个字符串中的字符是汉字还是英文。最简单的判断就是当字符值小于0x80时,表示是英文字符,字符长度为1。否则为中文,字符长度为2。然后去解码对照表中查找Unicode编码值。
于是根据以上的理解,我将原有的多个文件合并成了一个文件。原文件中还实现了StreamWriter和StreamReader两个类,但我看到许多转码器都没有内容,于是我也把它给忽略了。这样,我将encode和decode函数保存下来,只保留解码对照表(decoding_map)。编码对照表仿照别的转码器用程序生成。最后生成的文件名为gb2312.py。
把改好的gb2312.py文件拷贝到python/lib/encodings目录下。再测试前面对GB2312编码进行测试的例子,这次成功了!
Plone的GB2312编码的实现
将gb2312.py拷贝到Zope安装目录下的bin/lib/encodeings目录下。重启Zope。将Localizer中 messagecatalog(本例为Plone)组件的语言改成GB2312。再执行Import功能。这次没有报错。再把Plone的语言设置为 GB2312。在浏览器中看一看,可以了吧。
相关链接
gb2312.py(gb2312.zip)
GB2312编码的中文翻译文件(plone-zh-cn-gb2312.zip)