python-babel / flask-babel

i18n and l10n support for Flask based on Babel and pytz
https://python-babel.github.io/flask-babel/
Other
444 stars 159 forks source link

how to correctly work out of context #137

Closed wiwengweng closed 4 years ago

wiwengweng commented 6 years ago

Hi, all. I have two subprocesses. one for flask web(called web.py), and one for some background tasks(called task.py). flask-babel works inside the web context, but also the task subprocess will need some translations. so, I import web app into the task.py and use the app.test_request_context in order to make translations work for me. it works at first but then I found task.py will also get the default language only. here is the web.py:

app.config['BABEL_DEFAULT_LOCALE'] = 'en'
babel = Babel(app)

@babel.localeselector
def get_locale():
    return request.accept_languages.best_match(['zh', 'en'])

task.py

from web import app
def task():
    try:
        with app.test_request_context() as ctx:
            sio.emit('loading', {'data': _("please wait a moment.")})
....

so how can I get the correct locale before I return the translation?? TIA :)

wiwengweng commented 6 years ago

I also see this function:

flask_babel\__init__.py

def get_translations():
    """Returns the correct gettext translations that should be used for
    this request.  This will never fail and return a dummy translation
    object if used outside of the request or if a translation cannot be
    found.
    """
    ctx = _get_current_context()

    if ctx is None:
        return support.NullTranslations()

    translations = getattr(ctx, 'babel_translations', None)
    if translations is None:
......

I track codes to this function and find the ctx has the attribute 'babel_translations', and this translation catalog seems to be related with the default locale. Is it a bug, or I can get the locale from 'babel_localeselector'??

tvuotila commented 5 years ago
@babel.localeselector
def get_locale():
    return request.accept_languages.best_match(['zh', 'en'])

is what decided which locale to use. If it returns None, the default locale is used.

For example, if you would want to use locale zh, you could write

@babel.localeselector
def get_locale():
    return 'zh'

Probably you want to use something smarter there.

I think you should take a look at force_locale if that solves your problem.

wiwengweng commented 5 years ago

thanks, @tvuotila I did not use force_locale and just solve this as you advised.

4lph4-Ph4un commented 5 years ago

Hi, I'm still unable to use this even with force_locale. Since I have to use multiple locales on my app, I cannot just force a return value on get_locale either. Is there something wrong with my use case. I use Zappa's @task to run different asynchronous tasks on AWS. Here's the minimum setup where I cannot get a translation forced. The real use case likely reads the language from user object's settings:

@task
def async_translation_test():
    from instababy import app
    with force_locale("fi"):
        output = _("Test notification 4 %(name)s", name="Test")
        app.logger.debug(output)

I have working translations on HTML -templates and routines that use requests, but somehow this doesn't seem to work. The logger just messages the default English translation and not Finnish one.

tvuotila commented 5 years ago

I have working translations on HTML -templates and routines that use requests, but somehow this doesn't seem to work.

You need the request for this to work.

@task
def async_translation_test():
    from instababy import app
    with app.test_request_context():
        with force_locale("fi"):
            output = _("Test notification 4 %(name)s", name="Test")
            app.logger.debug(output)
4lph4-Ph4un commented 5 years ago

Ah thanks for the reply. I assumed test_request_context() was only used for testing, but seems it is used in variety of situations. :)

4lph4-Ph4un commented 5 years ago

Uff.. somehow doesn't seem to work :/ I'll try to get more info to the get bottom of this.