Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determine the user language in Pyramid

I want to make internationalization for my project. I followed how it is described in official documentation, but localization still doesn't work. Here is how I try get user locale:

def get_locale_name(request):
    """ Return the :term:`locale name` associated with the current
    request (possibly cached)."""
    locale_name = getattr(request, 'locale_name', None)
    if locale_name is None:
       locale_name = negotiate_locale_name(request)
       request.locale_name = locale_name
   return locale_name

But request doesn't have attr "local_name", but it has "Accept-Language" and so when function get_local_name doesn't find "local_name" in the request, it calls another function:

def negotiate_locale_name(request):
    """ Negotiate and return the :term:`locale name` associated with
    the current request (never cached)."""
    try:
        registry = request.registry
    except AttributeError:
        registry = get_current_registry()
    negotiator = registry.queryUtility(ILocaleNegotiator,
                                       default=default_locale_negotiator)
    locale_name = negotiator(request)

   if locale_name is None:
        settings = registry.settings or {}
        locale_name = settings.get('default_locale_name', 'en')

   return locale_name

How can I see negotiator try to get local from global environment but if it cant to do that its set value from config. And I cant understand why Pyramid doesn't get locale directly from request's field "Accept-Language"?

And, how can I make a correct determination of the locale?

like image 464
Denis Avatar asked Jun 30 '12 13:06

Denis


2 Answers

Pyramid doesn't dictate how a locale should be negotiated. Basing your site language on the "Accept-Language" header can cause problems as most users do not know how to set their preferred browser languages. Make sure your users can switch languages easily and use a cookie to store that preference for future visits.

You either need to set a _LOCALE_ key on the request (via an event handler, for example), or provide your own custom locale negotiator.

Here's an example using the NewRequest event and the accept_language header, which is an instance of the webob Accept class:

from pyramid.events import NewRequest
from pyramid.events import subscriber

@subscriber(NewRequest)
def setAcceptedLanguagesLocale(event):
    if not event.request.accept_language:
        return
    accepted = event.request.accept_language
    event.request._LOCALE_ = accepted.best_match(('en', 'fr', 'de'), 'en')
like image 96
Martijn Pieters Avatar answered Sep 30 '22 15:09

Martijn Pieters


Do note that the request._LOCALE_ works only because by default the locale negotiator is a default_locale_negotiator. If you have very complex checks, for example you have to fetch the user from DB if a cookie does not exist, the NewRequest handler does have overhead for requests that do not need any translations. For them you can also use a custom locale negotiator, like:

def my_locale_negotiator(request):
    if not hasattr(request, '_LOCALE_'):
        request._LOCALE_ = request.accept_language.best_match(
            ('en', 'fr', 'de'), 'en')

    return request._LOCALE_


from pyramid.config import Configurator
config = Configurator()
config.set_locale_negotiator(my_locale_negotiator)