GoogleCloudPlatform / webapp2

webapp2 is a framework for Google App Engine
https://webapp2.readthedocs.org
Other
141 stars 63 forks source link

lazy_gettext doesn't use current locale settings #84

Open GoogleCodeExporter opened 8 years ago

GoogleCodeExporter commented 8 years ago

What steps will reproduce the problem?

1.
Create a new form using wtforms, e.g.:

import wtforms
from webapp2_extras.i18n import lazy_gettext as _

class TetForm(wtforms.Form):
    first_name = wtforms.TextField(_('First name'))

This uses lazy_gettext, so that it will not execute gettext on "First name" on 
module load, but is supposed to execute it each time the string "First name" is 
used.

Now init this form in a test request handler and set its route to /test/:

class TestHandler(webapp2.RequestHandler):

    def render_template(self, template, context):
        """
        Renders the template using jinja2
        """
        ...

    def get(self):
        locale = self.request.get('locale')
        i18n_obj = i18n.get_i18n()
        i18n_obj.set_locale(locale)
        form = TestForm()
        self.render_template('form.html', {'form': form})

Use the following jinja2 template (form.html):
<h1>{{ gettext("Form") }}</h1>
<form action='/test/' method="post">
{{ form.first_name }}
</form>

2.
Create translations for two languages for the string "First name" using gettext.

Let's say:

locale/de_DE/LC_MESSAGES/messages.po for german version:
"Form" = "Formular"
"First name" = "Vorname"

locale/sl_SI/LC_MESSAGES/messages.po for slovenian version:
"Form" = "Obrazec"
"First name" = "Ime"

Compile them.

3.

Open the following url:
/test/?locale=sl_SI
this one will show "Obrazec" in h1 and "Ime" as input label, both strings in 
slovenian, which corresponds to the locale setting sl_SI.

And now go to:
/test/?locale=de_DE

What is the expected output? What do you see instead?
Now it will show "Formular" (german) in h1 and input label will show "Ime" 
(slovenian) instead of "Vorname" (german), although we set the locale setting 
on this request to de_DE.

What version of the product are you using? On what operating system?
webapp2 2.5.2

Please provide any additional information below.

After looking into it, the issue is clearly related to the fact that Babel's 
LazyProxy class is caching the value - babel.support.py:

def value(self):
    if self._value is None:
        value = self._func(*self._args, **self._kwargs)
        object.__setattr__(self, '_value', value)
    return self._value
value = property(value)

and i18n.lazy_gettext is using LazyProxy for lazy execution of the non-lazy 
i18n.gettext, but it only gets executed once in the lifetime of the app 
instace, instead of once per request.

Original issue reported on code.google.com by mytix.m...@gmail.com on 18 Sep 2013 at 11:37

GoogleCodeExporter commented 8 years ago
here's a rough workaround -- effectively disabling the caching of translations. 
I've not checked out the performance hit, but it certainly beats having text 
coming out in every language imaginable:

from babel.support import LazyProxy
from webapp2_extras import i18n

class LazierProxy(LazyProxy):
    def value(self):
        return self._func(*self._args, **self._kwargs)
    value = property(value)

def lazy_gettext(string, **variables):
    '''
    https://code.google.com/p/webapp-improved/issues/detail?id=84
    '''
    return LazierProxy(i18n.gettext, string, **variables)

[then import lazy_gettext from here rather than webapp2_extras.i18n]

Original comment by ohuig...@gmail.com on 17 Feb 2014 at 10:56

rdoursenaud commented 8 years ago

I faced the same issue and the workaround is working for me. Thanks to the OP.

dogen-zeni commented 4 years ago

Babel.support.LazyProxy now accepts enable_cache, which is defaulted to True.

This should work - i18n.lazy_gettext(text, enable_cache=False)