在定时任务中更改Flask-Babel区域设置

7 投票
4 回答
4902 浏览
提问于 2025-04-17 22:57

我每小时都会运行一个任务,这个任务可以给用户发送邮件。当邮件发送时,需要使用用户在数据库中设置的语言。

我现在遇到的问题是,我不知道如何在没有请求上下文的情况下设置不同的语言环境。

我想要做的是:

def scheduled_task():
  for user in users:
    set_locale(user.locale)
    print lazy_gettext(u"This text should be in your language")

4 个回答

0

假设 Flask-Babel 使用的是请求上下文来设置地区语言,你可以尝试在一个临时的请求上下文中运行你的代码:

with app.request_context(environ):
    do_something_with(request)

详细信息可以查看 http://flask.pocoo.org/docs/0.10/api/#flask.Flask.request_context

2

@ZeWaren 的回答对于使用 Flask-Babel 的人来说很不错,但如果你用的是 Flask-BabelEx,就没有 force_locale 这个方法了。

这是针对 Flask-BabelEx 的解决方案:

app = Flask(__name__.split('.')[0])   #  See http://flask.pocoo.org/docs/0.11/api/#application-object

with app.test_request_context() as ctx:
    ctx.babel_locale = Locale.parse(lang)
    print _("Hello world")

注意,如果你在使用蓝图(blueprints),.split() 这个方法是很重要的。我花了几个小时才搞明白,因为 app 对象的根路径是 'app.main',这让 Babel 去 'app.main.translations' 找翻译文件,而实际上文件是在 'app.translations' 里。结果它默默地退回到 NullTranslations,也就是不进行翻译。

15

你还可以使用来自 flask.ext.babel 包的 force_locale 方法:

from flask.ext.babel import force_locale as babel_force_locale
english_version = _('Translate me')
with babel_force_locale('fr'):
    french_version = _("Translate me")

这是它的文档说明:

"""Temporarily overrides the currently selected locale.

Sometimes it is useful to switch the current locale to different one, do
some tasks and then revert back to the original one. For example, if the
user uses German on the web site, but you want to send them an email in
English, you can use this function as a context manager::

    with force_locale('en_US'):
        send_email(gettext('Hello!'), ...)

:param locale: The locale to temporary switch to (ex: 'en_US').
"""
5

一种方法是设置一个虚假的请求上下文:

with app.request_context({'wsgi.url_scheme': "", 'SERVER_PORT': "", 'SERVER_NAME': "", 'REQUEST_METHOD': ""}):
    from flask import g
    from flask_babel import refresh
    # set your user class with locale info to Flask proxy
    g.user = user
    # refreshing the locale and timezeone
    refresh()
    print lazy_gettext(u"This text should be in your language")

Flask-Babel通过调用@babel.localeselector来获取地区设置。我的localeselector看起来像这样:

@babel.localeselector
def get_locale():
    user = getattr(g, 'user', None)
    if user is not None and user.locale:
        return user.locale
    return en_GB   

现在,每次你更改g.user时,都应该调用refresh()来更新Flask-Babel的地区设置。

撰写回答