真人牛牛


真人牛牛当我们再一次醒来的时候,我也许会告诉你:我很想你!那些很短很短的细碎的日子里,我以为我都在梦里。
真人牛牛给生活一个安静
真人牛牛墨染纸香,文字解怀,绕过世间的红尘万物,社会浮华躁动的侵蚀,物欲横流的纠葛,繁杂纷扰的迷茫。以一颗素雅幽静之心,行走在文字中体味人生的淳厚与清欢,淡泊中的安然静美。如佛坐莲心,出污泥而不染的荷花,即使身处污秽也要呈现出美丽圣洁的灵魂,娉婷在秋色中出水芙蓉,上善若水,不迎春百花斗艳之争,以一份淡然中的曼妙给人惊奇的目光!
真人牛牛看老公朋友圈,嘴贱说一句:“老公,我一直以为你很丑,看了你朋友圈,发现你还蛮帅的。”然后,那货不理我了。真人牛牛 一盘酸菜几片肥肉,那便是童年的味道。如梭岁月怎么样匆匆也带不走那浓浓的香味,许多许多往事一挥而去,但童年时的酸菜味总能勾起我的馋欲。
真人牛牛我和王毅是单独交易的,没有任何人能证明我的清白,他又是我的大学同学,别人很容易就会把我想成和王毅是一伙的。退一万步说,就算不把我和王毅想成是同伙,那我说给了十五万,谁相信?真人牛牛她突然抬着头盯着彭丰:不用说了,我回香港!真人牛牛时光眨眼分分秒秒过,何时妙舞生棒逍遥乐?

皇冠足球比分

大发论坛时时彩平台尊龙娱乐是黑网吗海天国际娱乐城注册送钱凯发娱乐亚美国际娱乐城 金龙国际 www.am8.com 亚洲城娱乐 老k国际娱乐城 666k8.com 金威国际娱乐城 名人国际娱乐城 ag娱乐平台 V博娱乐城 澳门百家乐赌场网上足球外围投注澳门新葡京娱乐场注册送钱e8889.com澳门赌场澳门博彩乐橙娱乐注册送钱e8889.com全讯博彩论坛去澳门国际澳门赌场代理久乐国际娱乐ag平台注册送钱e8889.com狮威国际娱乐城博彩平台金沙备用网址真人博彩论坛维也纳在线娱乐城长江国际娱乐大发注册送钱e8889.com

Flask 开发全球化应用

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=gb2312\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的友人们。

posted @ 2015-11-23 09:32 Ray Liang 阅读(...) 评论(...) 编辑 收藏