Search code examples
pythonpyramidpython-babel

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).


Solution

  • 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.