一个强大的工具一般都支持扩展或插件的开发功能,来允许第三方通过开发新扩展或插件,扩充工具本身功能,并可以贡献给社区。Jinja2也不例外,Jinja2本身提供了一部分扩展,你可以在程序中启用。同时,你还可以创建自己的扩展,来扩充模板引擎功能。本篇会先介绍Jinja2自带的扩展”jinja2.ext.i18n”的使用,自定义扩展的开发会放在下一篇阐述。
在Flask中启用Jinja2扩展
任何时候使用Jinja2时,都需要先创建Jinja2环境,所以启用扩展的方法就是在创建环境时指定:
1
2
|
from jinja2 import Environment
jinja_env = Environment(extensions=[‘jinja2.ext.i18n’,‘jinja2.ext.do’])
|
但是你在使用Flask时,其已经有了一个Jinja2环境,你不能再创建一个,所以你需要想办法添加扩展。Flask对于扩展不像过滤器或测试器那样封装了添加方法和装饰器,这样你就只能直接访问Flask中的Jinja2环境变量来添加。
1
2
3
4
|
from flask import Flask
app = Flask(__name__)
app.jinja_env.add_extension(‘jinja2.ext.i18n’)
app.jinja_env.add_extension(‘jinja2.ext.do’)
|
Jinja2内置扩展
我们已经介绍了四个Jinja2内置扩展的使用:”jinja2.ext.autoescape”, “jinja2.ext.with_”, “jinja2.ext.do”和”jinja2.ext.loopcontrols”。除了这几个以外,Jinja2还有一个非常重要的扩展,就是提供本地化功能的”jinja2.ext.i18n”。它可以与”gettext”或”babel”联合使用,接下来我们采用”gettext”来介绍怎么使用这个本地化扩展。
创建本地化翻译文件
建议大家先去了解下Python gettext相关知识,篇幅关系本文就不准备细讲。这里我们使用Python源代码(记住不是安装包)中”Tools/i18n”目录下的工具来创建翻译文件。
- 首先我们生成翻译文件模板,在”Tools/i18n”目录中找到”pygettext.py”并运行
1
|
$ python pygettext.py
|
上述命令会在当前目录下生成一个名为”message.pot”的翻译文件模板,内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid “”
msgstr “”
“Project-Id-Version: PACKAGE VERSION\n”
“POT-Creation-Date: 2016-02-22 21:45+CST\n”
“PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n”
“Last-Translator: FULL NAME <EMAIL@ADDRESS>\n”
“Language-Team: LANGUAGE <LL@li.org>\n”
“MIME-Version: 1.0\n”
“Content-Type: text/plain; charset=CHARSET\n”
“Content-Transfer-Encoding: ENCODING\n”
“Generated-By: pygettext.py 1.5\n”
|
2. 将”message.pot”中”CHARSET”和”ENCODING”替换成”UTF-8″。同时你可以更改注释信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# Jinja2 i18n Extention Sample
# Copyright (C) 2016 bjhee.com
# Billy J. Hee <billy@bjhee.com>, 2016.
#
msgid “”
msgstr “”
“Project-Id-Version: PACKAGE VERSION\n”
“POT-Creation-Date: 2016-02-22 21:45+CST\n”
“PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n”
“Last-Translator: FULL NAME <EMAIL@ADDRESS>\n”
“Language-Team: LANGUAGE <LL@li.org>\n”
“MIME-Version: 1.0\n”
“Content-Type: text/plain; charset=UTF-8\n”
“Content-Transfer-Encoding: UTF-8\n”
“Generated-By: pygettext.py 1.5\n”
|
修改完后,将其另存为翻译文件”lang.po”。
3.在”lang.po”中添加你要翻译的文字,比如
1
2
|
msgid “Hello World!”
msgstr “世界,你好!
|
将其加在文件末尾。这里”msgid”指定了待翻译的文字,而”msgstr”就是翻译后的文字。
4. 生成”lang.mo”文件
我们依然使用”Tools/i18n”目录提供的工具,”msgfmt.py”:
1
|
$ python msgfmt.py lang.po
|
执行完后,当前目录生成了”lang.mo”文件。注意,只有这个”*.mo”文件才能被应用程序识别。另外,推荐一个工具Poedit,很强的图形化po编辑工具,也可以用来生成mo文件,非常好用,Mac和Windows下都能用。
5. 将po, mo文件加入应用
我们在当前Flask工程下创建子目录”locale/zh_CN/LC_MESSAGES/”,并将刚才生成的”lang.po”和”lang.mo”文件放到这个目录下。这里”locale”子目录的名字可以更改,其他的个人建议不要改。
在模板中使用本地化
让我们在Flask应用代码中启用”jinja2.ext.i18n”,并加载刚创建的翻译文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#coding:utf8
import gettext
from flask import Flask,render_template
app = Flask(__name__)
# 加载扩展
app.jinja_env.add_extension(‘jinja2.ext.i18n’)
# ‘lang’表示翻译文件名为”lang.mo”,’locale’表示所有翻译文件都在”locale”子目录下,
# ‘zh_CN’表示二级子目录,含义上讲就是加载中文翻译。所以下面的代码会加载文件:
# “locale/zh_CN/LC_MESSAGES/lang.mo”
gettext.install(‘lang’, ‘locale’, unicode=True)
translations = gettext.translation(‘lang’, ‘locale’, languages=[‘zh_CN’])
translations.install(True)
app.jinja_env.install_gettext_translations(translations)
|
这个”install_gettext_translations()”方法就是Jinja2提供来加载”gettext”翻译文件对象的。加载完后,你就可以在模板中使用本地化功能了。方法有两种:”{% trans %}”语句或”gettext()”方法。我们先来试下”{% trans %}”语句,在模板文件中,我们加上:
1
|
<h1>{% trans %}Hello World!{% endtrans %}</h1>
|
运行下,有没有看到页面上打印了”世界,你好!”,恭喜你,成功了!使用”gettext()”方法如下,效果同”{% trans %}”语句一样。
1
|
<h1>{{ gettext(‘Hello World!’) }}</h1>
|
Jinja2还提供了”_( )”方法来替代”gettext( )”,代码看起来很简洁,个人推荐使用这个方法。
1
|
<h1>{{ _(‘Hello World!’) }}</h1>
|
上面的例子是在程序中指定本地化语言,你也可以在请求上下文中判断请求头”Accept-Language”的内容,来动态的设置本地化语言。
翻译内容带参数
有时候,待翻译的文字内有一个变量必须在运行时才能确定,怎么办?我可以在翻译文字上加参数。首先,你要在po文件中定义带参数的翻译文字,并生成mo文件:
1
2
|
msgid “Hello %(user)s!”
msgstr “%(user)s,你好!”
|
然后,你就可以在模板中,使用”{% trans %}”语句或”gettext()”方法来显示它:
1
2
|
<h1>{% trans user=name %}Hello {{ user }}!{% endtrans %}</h1>
<h1>{{ _(‘Hello %(user)s!’)|format(user=name) }}</h1>
|
上例中,我们把模板中的变量”name”赋给了翻译文字中的变量”user”。翻译文字上可以有多个变量。
新样式 (Newstyle)
Jinja2从2.5版本开始,支持新的gettext样式,使得带参数的本地化更简洁,上面的例子在新样式中可以写成:
1
|
<h1>{{ _(‘Hello %(user)s!’, user=name) }}</h1>
|
不过使用新样式前,你必须先启用它。还记得我们介绍过Jinja2加载翻译文件的方法吗?对,就是”install_gettext_translations()”。调用它时,加上”newstyle=True”参数即可。
1
|
app.jinja_env.install_gettext_translations(translations, newstyle=True)
|
单/复数支持
英文有个特点就是名词有单/复数形式,一般复数都是单数后面加s,而中文就不区分了,哎,老外就是麻烦。所谓外国人创造的Python gettext,自然也对单/复数提供了特殊的支持。让我们现在po文件中,加上下面的内容,并生成mo文件:
1
2
3
4
|
msgid “%(num)d item”
msgid_plural “%(num)d items”
msgstr[0] “%(num)d个物品”
msgstr[1] “%(num)d个物品集”
|
什么意思呢,这个”msgid_plural”就是指定了它上面”msgid”文字的复数形式。而”msgstr”的[0], [1]分别对应了单/复数形式翻译后的内容。为什么这么写?你别管了,照着写就是了。
在模板中,我们加上下面的代码:
1
2
3
|
{% set items = [1,2,3,4,5] %}
{{ ngettext(‘%(num)d item’, ‘%(num)d items’, items|count) }}<br />
{{ ngettext(‘%(num)d item’, ‘%(num)d items’, items|first) }}
|
文章转载来自:ttlsa.com