传送门
00 开篇 01 Hello world 02 模板 03 Web表单
04 数据库 05 用户登录 06 个人资料和头像 07 错误处理
08 关注 09 分页 10 支持QQ邮箱 11 美化页面
12 时间和日期 14 Ajax(百度翻译API 15 更好的App结构(蓝图)
16 全文搜索 17 部署到腾讯云Ubuntu 18 部署到Heroku 19 部署到Docker容器
20 JavaScript魔法 21 用户通知 22 后台工作(Redis) 23 应用程序编程接口(API)

本章将学习如何扩展Microblog以支持多种语言。作为该工作的一部分,将学习向`flask命令` 建立自己CLI扩展。

l18n,是Internationalization的缩写,即首末字符i和n,18为中间的字符数,译作 软件国际化,是一个代码修改的过程,以实现代码完全独立于特定文化信息。

类似,L10n,是localization的缩写,即即在 l 和 n 之间有 10 个字母,译作 软件本地化。

为了使得我们的Microblog应用程序对不会说英语的人友好,将实现一个翻译工作流程,在语言翻译的帮助下,允许以多种语言为用户提供应用程序。

Flask-Babel简介

有一个Flask扩展可以让翻译变得很容易。该扩展名为 [Flask-Babel](https://pythonhosted.org/Flask-Babel/),安装:

Flask-Babel像大多数其他Flask扩展一样需要进行初始化:

app/__init__.py:Flask-Babel实例

现在为应用程序使用双语言代码,但如果需要更具体,还可以添加国家/地区代码。例,可使用、、以支持美国、英国、加拿大作为不同的语言。再如中文(语言代码 zh,不要后面的含区域的语言代码,有坑!), 香港, 澳门, 台湾, 新加坡。

这个实例提供了一个装饰器。对每个请求调用装饰函数,以选择一个用于该请求的语言翻译:

app/__init__.py

上述代码中使用了一个Flask的对象的属性。这个对象提供了一个高级接口,用于处理随客户端随请求发送的Accept-Languages header。这个header 将客户端 语言和区域 设置首选项 指定为加权列表。可在浏览器的首选项页面中配置这个标题这个header的内容,默认情况下,通常从计算机操作系统中的语言设置中导入。大多数人甚至不知道存在这样的设置,但这很有用,因为用户提供首选语言列表,每个语言都有权重。如果你充满好奇心,如下正是一个复杂的 header示例:

表示 丹麦语()是首选语言(默认权重=1.0),其次是英国英语() 权重为0.8,最后是通用语言() 权重为0.7。

要选择最佳的语言,需将客户端请求的语言列表与应用程序支持的语言进行比较,并使用客户端提供的权重,找到最佳语言。执行这个操作的逻辑有点复杂,但它全部封装在 方法中,它将应用程序提供的语言列表作为参数,并返回最佳选择。

在Python源代码中标记要翻译的文本

坏消息来了!使应用程序以多种语言提供时 的正常工作流程是标记源代码中需要翻译的所有文本。标记文本后,Flask-Babel将扫描所有文件并使用[gettext](https://www.gnu.org/software/gettext/)工具将这些文本提取到单独的翻译文件中。不幸的是,这是一项繁琐的工作,需要进行翻译才能实现。

在此,将展示这个标记的一些示例。文本被标记为翻译 的方式是将它们包装在一个函数调用中,这个函数调用约定为 ,只是一个下划线。最简单的情况是文字字符串出现在源代码中的情况。下方是一个声明的示例:
app/routes.py

上述代码表示 函数将文本包装在基本语言中(本例是英语)。这个函数将使用由函数装饰选择的最佳语言 去为一个给定客户端查找正确的翻译。接着返回已翻译的文本,在这种情况下,将变成参数给。

不幸的是,并非所有案例都那么简单。考虑到来自应用程序的另一个调用:
app/routes.py

这个文本有一个动态组件,这个组件插入到静态文本的中间。函数有支持这类文本的语法,但它是基于较旧的字符串替换语法:修改版如下

还有一个更难处理的案例。某些字符串文字是在请求之外分配的,通常是在应用程序启动时,因此评估这些文本时,无法知道要使用的语言。一个例子是与表单字段相关联的标签。处理这些文本的唯一解决方案是找到一种方法来延迟对字符串的评估,直到它被使用为止,这将在实际请求之下。Flask-Babel提供了一个的懒惰评估版本,称为 :
app/forms.py

在上述代码中,将导入这个替换翻译函数,并重命名为,让其看起来跟原始的类似。这个新函数将文本包装在一个特殊对象中,该对象在使用字符串时触发稍后执行的转换。

Flask-Login扩展在将用户重定向到页面时会闪烁一条消息。这条消息是英文的,来自扩展本身。为了确保这个消息也被翻译,将覆盖默认消息并提供我自己的包装器,其中包含 _()用于延迟处理的函数:

app/__init__.py

“` #… from flask_babel import Babel,lazy_gettext as _l #…

login = LoginManager(app)
login.login_view = ‘login’
login.login_message = _l(‘Please log in to access this page.’)
#…

def send_password_reset_email(user):
token = user.get_reset_password_token()
send_email(_(’[Microblog] Reset Your Password’),#…

File Not Found

“` 启用翻译的版本为:

不过要注意,除了用包装文本之外,还需要添加,以强制进行评估,而不是将其视为模板中的文字。

对于具有 动态组件 这样更复杂的短语,也可以使用参数:

在中有一个特别棘手的案列,需要花一些时间来弄明白:

这里的问题是 我想 是一个指向用户的个人资料页面的链接,而不仅仅是 名称,因此我必须建立一个名为 的中间变量 用到 和模板指令中,然后将其作为参数传递给翻译函数。

剩下的工作是将所有模板中需要翻译的内容进行处理。
app/templates目录下 、、、、、、、、、、都得对要翻译的内容进行更新。

提取要翻译的文本

提取过程需要一个小的配置文件,它告诉应该扫描哪些文件用于可翻译文本。下方将看到为这个应用程序创建的 :
microblog/babel.cfg

前两行分别定义了Python和Jinja2模板文件的文件名模式。
第三行定义了Jinja2模板引擎提供的两个扩展,帮助Flask-Babel正确解析模板文件。

要将所有文本提取到.pof文件,可使用如下命令:

读取选项中给出的配置文件;然后,从命令中给出的目录(当前目录 或 本例中)开始扫描与配置的源匹配的目录中的所有代码和模板文件。默认情况下,pybabel将查找这样的文本标记,而且上述还使用了导入的惰性版本,所以需要告诉工具查找那些 。-o 选项提供输出文件的名称。

要注意到,文件(生成在/microblog目录下)不是需要合并到项目中的文件。这是一个可在需要时轻松重新生成的文件,只需再次运行上面的命令即可。因此,无需将此文件提交给源代码控制。

生成语言目录

下一步是 为除基本语言之外 将支持的每种语言创建翻译,在本例中为英语。首先添加 中文(语言代码 `zh`,下方执行这个操作的命令:

文件是一个可用于翻译的源文件。当想要开始使用这些翻译文本时,得将此文件 编译为在运行时 由应用程序有效使用的格式。要编译应用程序的所有翻译,可使用以下 命令:

更新翻译

使用翻译时有一个常见情况是,即便 文档不完整,但也希望可以使用翻译文件。这也是好的,可以编译一个不完整的 `messages.po`文件,并将使用任何可用的翻译,而任何缺少的翻译将使用基本语言。然后,可继续处理翻译,并再次编译,以便在我们取得进展时更新`messages.mo`文件。

如果在添加包装器时 错过了某些文本,则会出现另一种常见情况。在这种情况下,将看到错过的那些文本将保留为英文,因为Flask-Babel对它们一无所知。在这种情形下,需要 在检测到没有它们的文本时 添加 或包装器,然后再执行更新过程,其中包括两个步骤:

命令 等同于早些时候发布的那个,但现在它会产生一个新版本的文件,它包含所有之前的文本,并加上最新用 或包装器的新内容。
调用将得到新文件,并将其合并到与项目相关联的所有文件中。这是一个智能合并,其中任何已存在文本将保持不变,而只有在中添加或删除的条目受到影响。

在更新之后,可以继续翻译任何新测试;然后,再次编译消息以使其可供应用程序使用。

翻译日期和时间

现在,Python源代码、模板中的所有文本都有完整的 中文翻译,但是如果用中文运行程序,会注意到仍然有一些东西为英语。在此指定是 Flask-Moment和`moment.js`生成的时间戳,这些时间戳显然没有包含在翻译工作中,因为这些包生成的文本都不是应用程序的源代码或模板的一部分。

确实支持本地化和国际化,所以我们需要做的是配置正确的语言。Flask-Babel通过函数返回给定请求的选定语言和语言环境,所以要做的是将语言环境添加到 对象,以便我可以从基础模板中访问它:
app/routes.py:将所选语言存储在 flask.g中

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2018年7月20日
下一篇 2018年7月20日

相关推荐