C#世界迈入python总是令人有一种如释重负之感,同样的效果同样的功能,只需要付出1/10不到的代价,可能正是Python所倡导的简美哲学所带来的威力。

我还深深地记得在ASP.NET中做全球化的经历,可谓是苦不堪言。由于 .net 是采用xml格式的资源文件作为资源承载格式,导致对全球化资源的引用就必须要采用严格的合乎c#命名规范。这样一来在资源的使用过程中就增加“命名”这一复杂度。以前从不认为有什么问题,不过一但转译成多国版本或者要对资源文件进行更新就会面临着巨大的工作量。

而且ASP.NET官方推荐的全球化做法则更是坑人,简直就是将“Quickly and duty”发挥到了极至,一但做了也只好陷入永不休止似的维护地狱之中。

还是直到在接触 Web2Py 时才发现他们对全球化的做法有点像样了,Web2Py中没有了中间关键字命名,而是将自然用词直接作为资源的搜索关键字,这对于长期用ASP.NET开发全球化项目的我无疑是一咱脑洞大开的过程。而且,制作默认语言模板的工作量还是巨大的这个过程仍然需要手工处理,因此我一直在寻找更好的应用方案。

直至在Flask 中遇到了 Flask-Babel 这个插件。花了10多分钟就能上手了,看到它的用法简直是让人兴奋不已——简单、省事。

Flask-Babel 就是在Flask中对Babel的插件,它有几个很让人印象深刻的特色:

  • 自动从代码、页面中搜索并提取出使用全球化资源的关键字并生成默认字典
  • 提供一系列命令行工具去同步和翻译全球化资源文件
  • 资源文件可被编译为通用的 *.mo 格式,能通过其它的编辑器来维护字典
  • 代码与页面可以用一种方法访问资源 gettext(), _()
  • 能自动切换当前区域化语言

Flask-Babel 的用法

将 Flask-Babel 加载至 Flask 的应用上下文

from flask import Flask
from flask.ext.babel import Babel app = Flask(__name__)
app.config.from_pyfile('babel.cfg')
babel = Babel(app)

babel.cfg 配置文件

babel.cfg 是一个放置于Flask项目根目录下的Babel配置文件,它是一个固定的配置,以下是官方推荐的写法:

[python: **.py]
[jinja2: **/templates/**.html]
extensions=jinja2.ext.autoescape,jinja2.ext.with_

如果采用了 Flask-Assets 插件的话需要修改一下 extensions 的设置

[python: **.py]
[jinja2: **/templates/**.html]
extensions=jinja2.ext.autoescape,jinja2.ext.with_,webassets.ext.jinja2.AssetsExtension

gettext()/_()

接下来就可以在python代码内或者jinia页面内使用 gettext() 方法引用全球化资源。其实此时我们并没有任何的资源文件,但这正是Babel最吸引人的地方——先使用再生成资源。

在 python 代码内可以这样使用 gettext()

from flask import Flask, render_template

from flaskext.babel import Babel, gettext as _

app = Flask(__name__)
app.config['BABEL_DEFAULT_LOCALE'] = 'zh'
babel = Babel(app) @app.route('/')
def hello():
s = _("Saturday")
return render_template('index.html', day=day) if __name__ == '__main__':
app.debug = True
app.run()

以上代码中_("Saturday")就是从资源中获取名为Saturday的资源,如果没有资源文件或者没有找到对应的区域就会直接输出"Saturday"

然后就是在 jinja 模板内使用:

<p>{{ _("Hello, world!") }}</p>
<p>{{ _("It's %(day)s today", day=day) }}</p>

同理,在其它的代码和模块内就是以这两种方式使用全球化资源。

生成翻译模板

这是很重要的一步,也是Babel最省时省力的一步。Babel可以从代码和模板中抽出用了gettext()的所有的资源名并生成到默认语言模板内。生成这个模板后就可以翻译成各种需要的本地化语言。

只需要在命令行内键入以下命令

$ pybabel extract -F babel.cfg -o messages.pot .

就会在Flask的项目根目录下生成 messages.pot 的默认语言模板

翻译模板

接下来就是从默认模板翻译成指定区域语言的资源文件了,也是通过命令行处理:

$ pybabel init -i messages.pot -d translations -l zh

这个指令的执行结果是按照messages.pot将 中文(zh)资源文件(message.po)生成至 translations 目录。

目录结构如下:

.
├── babel.cfg
├── messages.pot
├── static
├── templates
└── translations
└── zh
└── LC_MESSAGES
└─ message.po

message.po 就是目标资源文件,现在就可以打开并进行相关的翻译工作了。*.po 文件只是一个文本可以直接编辑,或者可以选择一些专用的po编程工具也成。我比较推荐使用POEdit

当指区域时需要使用区域简写而不是区域全名,如果指定 zh-CN(简体中文)的话就直接采用 zh 否则指令会出错。

message.po 文件

以下是 message.op的内容

# Chinese translations for PROJECT.
# Copyright (C) 2015 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# Ray <csharp2002@hotmail>, 2015.
#, fuzzy msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: csharp2002@hotmail.com\n"
"POT-Creation-Date: 2015-03-29 22:46+0800\n"
"PO-Revision-Date: 2015-03-29 21:49+0800\n"
"Last-Translator: Ray <csharp2002@hotmail.com>\n"
"Language-Team: zh <LL@li.org>\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 1.3\n" #: views.py:103
#,fuzzy, python-format
msgid "Articles tagged with:%(value)s"
msgstr "标记%(value)s主题的文章"

: ,fuzzy 这个关键字,如果需要编译资源文件成为 *.mo的话则需要将它删除,否则资源文件编译器会直接忽略掉整个资源文件而不进行编译。

编译资源

编译过程很简单,只需要执行以下指令 translations 下所有的 *.po 文件就会被编译成二进制的 *.mo 资源文件。

$ pybabel compile -d translations

更新默认模板

这可谓是 Babel 一个很为开发者着想的功能,因为我们的程序资源必定是需要变更与维护的,自然而然地资源文件的内容必定会有增减。当我们翻译了N种语言副本之后如果没有相关工具而是由手工来做的话那将是一种极为可怕的工作过程。幸运的是我们只需要执行以下的指令,babel将为更新默认模板和所有从此模板生成的所有资源文件的内容:

$ pybabel update -i messages.pot -d translations

区域切换

默认情况下 Flask-Babel 会读取 flask.g.lang 自动切换当前请求上下文使用的语言区域。但在很多应用场景下我们需要手工改变当前的区域语言,这种情况下我们就需要增加一个 get_local() 函数:

from flask import g, request

@babel.localeselector
def get_locale():
# 如果在g对象内有登入的用户对象则从用户对象中读取 locale 区域信息
user = getattr(g, 'user', None)
if user is not None:
return user.locale # 此方法只需要返会一个区域字符串
return request.accept_languages.best_match(['de', 'fr', 'en']) @babel.timezoneselector
def get_timezone():
"""此函数与 get_locale 类似,只是向babel提供获取时区的设置"""
user = getattr(g, 'user', None)
if user is not None:
return user.timezone

当提供这两个函数之后,在调用 gettext 时 Babel 会自动调用他们。这里是通过装饰器 @babel.localeselector@babel.timezoneselector 实现类似重写的功能,但这个写法代码量会比重写类更少。

小结

当然,Babel 提供的API不止本文中的这几个,如果需要更详细地了解可以仔细地阅读 Flask-Babel 的文档。在这里我旨在记录 Babel 的最常规的用法以作备忘同时也分享给更多正在使用Flask的友人们。

Flask 开发全球化应用的更多相关文章

  1. Windows使用virtualenv搭建flask开发环境

    virtualenv: VirtualEnv用于在一台机器上创建多个独立的Python虚拟运行环境,多个Python环境相互独立,互不影响,它能够: 在没有权限的情况下安装新套件 不同应用可以使用不同 ...

  2. flask开发restful api系列(8)-再谈项目结构

    上一章,我们讲到,怎么用蓝图建造一个好的项目,今天我们继续深入.上一章中,我们所有的接口都写在view.py中,如果几十个,还稍微好管理一点,假如上百个,上千个,怎么找?所有接口堆在一起就显得杂乱无章 ...

  3. flask开发restful api

    flask开发restful api 如果有几个原因可以让你爱上flask这个极其灵活的库,我想蓝图绝对应该算上一个,部署蓝图以后,你会发现整个程序结构非常清晰,模块之间相互不影响.蓝图对restfu ...

  4. 使用flask开发网站后端

    Flask 是一个用于 Python 的微型网络开发框架,可以用于快速的搭建一个小型的网站. 我的搜索引擎:http://www.abelkhan.com 就是基于flask开发 一个flask的He ...

  5. Flask开发遇到的问题:BuildError: Could not build url for endpoint 'main.followers' with values ['username']. Did you mean 'main.user' instead?

    @(Flask Web Development 12th chapter) 描述 Flask开发中遇到BuildError: Could not build url for endpoint 'mai ...

  6. 在 Django/Flask 开发服务器上使用 HTTPS

    使用 Django 或 Flask 这种框架开发 web app 的时候一般都会用内建服务器开发和调试程序,等程序完成后再移交到生产环境部署.问题是这些内建服务器通常都不支持 HTTPS,我们想在开发 ...

  7. 用flask开发个人博客(4)—— flask中4种全局变量

    https://blog.csdn.net/hyman_c/article/details/53512109 一  current_app current_app代表当前的flask程序实例,使用时需 ...

  8. Flask开发系列之初体验

    Flask开发初探 介绍 在日常开发中,如果需要开发一个小型应用或者Web接口,一般我是极力推崇Flask的,主要是因为其简洁.扩展性高. 从这篇文章开始,我会写一个关于Flask的系列文章,通过多个 ...

  9. 【selenium+python】之Python Flask 开发环境搭建(Windows)

    一.先安装python以及pip 二.其次, Python的虚拟环境安装: 在github上下载https://github.com/pypa/virtualenv/tree/master  zip文 ...

随机推荐

  1. 使用Spring Security Oauth2完成RESTful服务password认证的过程

            摘要:Spring Security与Oauth2整合步骤中详细描述了使用过程,但它对于入门者有些重量级,比如将用户信息.ClientDetails.token存入数据库而非内存.配置 ...

  2. Debian

    一.简介 https://zh.wikipedia.org/wiki/Debian 二.下载 https://www.debian.org/ 三.配置 1)挂载iso镜像 mount /dev/cdr ...

  3. UVA 11355 Cool Points(几何)

    Cool Points We have a circle of radius R and several line segments situated within the circumference ...

  4. Storm之spout,bolt编写

    Storm,核心代码使用clojure书写,实用程序使用python开发,使用java开发拓扑. Nimbus节点接收到请求,对提交的拓扑进行分片,分成一个个的task,并将task和supervis ...

  5. 【读书笔记《Android游戏编程之从零开始》】4.Android 游戏开发常用的系统控件(EditText、CheckBox、Radiobutton)

    3.4 EditText EditText类官方文档地址:http://developer.android.com/reference/android/widget/EditText.html Edi ...

  6. AC日记——舒适的路线 codevs 1001 (并查集+乱搞)

    1001 舒适的路线 2006年  时间限制: 2 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题解  查看运行结果     题目描述 Description Z小镇是 ...

  7. IL查看委托

    查看委托的IL 通过IL来查看委托的原理, 委托示例代码 写一个委托的类如下 using System;   namespace MyCollection { //定义一个类,该类包含两个静态方法 c ...

  8. Flash Builder 找不到所需的 Adobe Flash Player

    经测试该方法可用! http://bbs.9ria.com/thread-108472-1-1.html 最近重装了系统,flash开发工具也由flex换成了flash builder.调试时就出现了 ...

  9. java 20 -1 递归的概述和案例

    /* * 递归:方法定义中调用方法本身的现象 * * 方法的嵌套调用,这不是递归. * Math.max(Math.max(a,b),c); * * public void show(int n) { ...

  10. AndroidStudio权威教程 AS添加第三方库的6种方式(Jar module so等)

    点击项目设置按钮 依次选择 App > Dependencies 1. 直接搜索法 依次选择 + > Library dependency 这里的搜索一定要是全名的,不然搜不到哦 下图所表 ...