Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Pyramid i18n outside of views and templates?

Pyramid documentation shows us how to use i18n inside views (and templates as well). But how to does one use it outside of views and templates where we have no access to current request (for example, in forms and models)?

@Michael said to pass request to models and forms. But is it right? I mean if form fields defines before __init__() method calls, the same with models. They don't see any parameters from views...

In Pylons we could simply use get_lang() and set_lang() and define preferable language in parent controller and then use ugettext() and ungettext() in any place we want without calling it from request directly every possible time (in views).

How to do that in Pyramid? Note that the language must be set from user's settings (session, cookies, db, etc).

like image 760
Vitalii Ponomar Avatar asked Apr 29 '12 15:04

Vitalii Ponomar


3 Answers

My solution is to create the form class when it's needed with localizer as parameter. For example

forms.py

class FormFactory(object):

    def __init__(self, localizer):
        self.localizer = localizer
        _ = self.localizer
        self.required_msg = _(u'This field is required.')
        self.invalid_email_msg = _(u'Invalid email address.')
        self.password_not_match_msg = _(u'Password must match')

    def make_contact_form(self):
        _ = self.localizer
        class ContactForm(Form):
            email = TextField(_(u'Email address'), [
                validators.Required(self.required_msg),
                validators.Email(self.invalid_email_msg)
            ])
            content = TextAreaField(_(u'Content'), [
                validators.Required(self.required_msg)
            ])
        return ContactForm

When you need to use the form

@view_config(route_name='front_pages.contact_us',
             renderer='myweb:templates/front_pages/contact_us.genshi')
def contact_us(request):
    """Display contact us form or send mail

    """
    _ = get_localizer(request)

    factory = FormFactory(_)
    ContactForm = factory.make_contact_form()
    form = ContactForm(request.params)
    return dict(form=form)

As you can see, we get the localizer in the view, and pass it to the FormFactory, then create a form with that factory. By doing that, all messages in the form was replaced with current locale language.

Likewise, you can do the same with model.

like image 144
Fang-Pen Lin Avatar answered Nov 17 '22 22:11

Fang-Pen Lin


Have you found pyramid.18n.get_localizer yet?

http://docs.pylonsproject.org/projects/pyramid/en/1.3-branch/narr/i18n.html#using-a-localizer

like image 2
Michael Merickel Avatar answered Nov 17 '22 20:11

Michael Merickel


Actually I had this very same problem. What I ended up doing was to see how the default locale negotiator works - it looks for a LOCALE property on the given request object. So just use a dummy to create the localizer. You may cache this value too, if you want

def my_get_localizer(locale=None):
    request = Request({})
    request._LOCALE_ = locale

    return get_localizer(request)

Alternatively, join the irc channel #pyramid @ freenode and pester the guys enough there to split the functionality of get_localizer in 2 separate documented functions (get_localizer and get_localizer_for_locale_name) for us to enjoy ;)

Also, notice that Pyramid TranslationStrings are lazy, so you can translate them as late as you want, e.g.

class MyModel(Base):
    description = TranslationString("My model number ${number}")

...

def view(request):
    m = MyModel()
    localizer = get_localizer(request)
    description = localizer.translate(m.description, mapping={'number': 1})

Sidenote: pylons' i18n was the worst can of worms I had opened in ages. The set_lang, get_lang hack was really awful, and pain in the ass as we needed to send emails to users in their native languages and then tried to restore the language back... also, it was IMPOSSIBLE to translate anything outside of a request in a pylons program, as a translator or the registry did not exist then.