Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change Flask-Babel locale outside of request context for scheduled tasks

I run a job every hour that can send an email to users. When the email is sent, it needs to be in the language set by the user (saved in the db). I can't figure out a way to set a different locale outside of a request context.

Here is what I would like to do:

def scheduled_task():
  for user in users:
    set_locale(user.locale)
    print lazy_gettext(u"This text should be in your language")
like image 239
mickael Avatar asked Mar 19 '14 10:03

mickael


3 Answers

You can also use method force_locale from package flask.ext.babel:

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

Here's what its docstring say:

"""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').
"""
like image 111
ZeWaren Avatar answered Sep 30 '22 14:09

ZeWaren


One way to do it is to set up dummy request context:

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 gets its locale settings by calling @babel.localeselector. My localeselector looks something like this:

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

Now, every time you change your g.user you should call refresh() to refresh Flask-Babel locale settings

like image 31
Tamm Avatar answered Sep 29 '22 14:09

Tamm


@ZeWaren 's answer is great if you are using Flask-Babel, but if you are using Flask-BabelEx, there is no force_locale method.

This is a solution for 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")

Note the .split() is important if you are using blueprints. I struggled for a couple of hours because the app object was created with a root_path of 'app.main', which would make Babel look for translation files in 'app.main.translations' while they were in 'app.translations'. And it would silently fall back to NullTranslations i.e. not translating.

like image 31
patb Avatar answered Oct 01 '22 14:10

patb