在Django中试验了简单的mako模板之后,运行是没有问题了,于是我想试一试中文如何处理,这一试才发现还有许多细节需要注意。在处理中文前建议先阅读一下mako文档中关于Unicode那部分。从这部分的内容我们可以了解到mako在模板内部全部使用unicode进行处理。涉及到模板处理的数据我想大概有三个地方:
- 模板文件
- 模板数据
- 模板中运算结果
让我们一个个来看如何正确使用。
模板文件
mako有一种全局性的处理,那就是在TemplateLookup中使用input_encoding参数,它指明了每个模板文件的缺省编码。另外,针对每个模板文件,你可以为每个模板声明一个模板所用的编码,正象python中所用的格式,如:
## -*- coding: utf-8 -*-
要注意在mako中支持两种注释方式,一种是单行的,它使用两个’#'符,这与python不同。上面一行要象python源程序一样放在最前面。而mako采用与PEP-0263相同的判断方式,因此它其实是一个正则表达式,表达式为:
#.*coding[:=]/s*([-/w.]+).*/n
因此你可以使用简化的方式:##coding=utf-8或##coding:utf-8
一旦你在某个页面设置了这个编码声明,它将覆盖全局性的编码设置。
感觉这个还是挺方便的。
模板数据
模板数据是将要传入模板中的变量,它在调用时是通过关键字参数来传的,因此你可以使用一个字典,如:a,然后使用template.render(**a)来传递。如果有中文那么你需要转为unicode,如果不转,mako会自动使用unicode()来进行转换,因为没有指定编码类型,再加上缺省编码如果不手工修改的话是ascii,所以相当于mako会按ascii编码来转换字符串,这一定会出错的。因此你要自已进行转换。
模板中运算结果
在mako模板中是可以直接写程序,表达式,调用外部模板进行处理的,因此有可能得到的结果不是unicode。因此你需要对计算结果进行转换,如${‘中文’},这样在模板中调用了一个中文字符串,但这样会出错,要这样写:${u’中文’}。不过每个表达式都这样处理真是很麻烦,因此mako提供了在TemplateLookup或Template创建时的一个default_filters参数,你可以指定对于每个表达式计算后使用哪些过滤器进行处理,因此可以指定一个decode.utf_8之类的进行处理。而这个decode是mako预定义。不过mako的过滤器目前好象不支持参数。使用这个过滤器后,当信息返回本身为unicode,则不会有问题,当为非unicode时会自动按utf-8进行转换。
为了将上述处理简化,我修改了mako_django.py文件(在zipbook项目中可以找到),增加了以下的处理:
- 将TemplateLookup类中的一些参数做成settings.py中的选项,这样用户可以通过修改settings.py的选项来控制模板的处理。主要有:
MAKO_FILESYSTEM_CHECKS 缺省值为settings.DEBUG,它主要用来控制是否自动监控文件的变化以重新生成模板的py模块。
MAKO_OUTPUT_ENCODING 缺省值为settings.DEFAULT_CHARSET,它用来控制模板输出时的编码。因为在整个模板处理时,内部是unicode,因此需要一个编码来转成字节字符串。
MAKO_INPUT_ENCODING 缺省值为settings.DEFAULT_CHARSET,它用来控制模板文件读取时使用的文件编码。
MAKO_DEFAULT_FILTERS 缺省值为['decode.' + settings.DEFAULT_CHARSET.replace('-', '_')]。可以看到使用了settings.DEFAULT_CHARSET编码。后面的replace是为了把"utf-8"转为"utf_8",不然在mako处理中会出错。 - 在使用TemplateLookup时使用了上述的参数
- 在得到一个template后进行渲染时,对于传入模板的字典对象进行扫描,将所有的字符串值(包括list, tuple,dict中的字符串)都转为了unicode。
经过上述的处理,只要保证模板,返回值,字符串都是统一的编码,如使用utf-8,那么使用中文应该不会有什么问题。