2

I've recently added Babel to my GAE/webapp2 site, and it works, but I'm confused about the proper way to get the locale.

In this answer, he gets the locale with self.request.get('locale', 'es_ES') but this only seems to work if something like ?locale=fr_FR is in the URL. I've never seen anyone set a locale in the URL. Is there any reason to get a locale from the URL?

Getting the locale from the headers seems to make more sense:

self.request.headers.get('Accept-Language').split(",")

One quirk is that browsers provide locale with a hyphen and lower case ("fr-fr") but Babel expects an underscore and mixed case (fr_FR). Where the browser provides a locale header of only "fr-fr", the following:

locale = self.request.headers.get('Accept-Language').split(",")[0]
i18n.get_i18n().set_locale(locale)

will end up using the default language rather than French because Babel is looking for "fr_FR". Should I take the locale from the header and convert the hyphen to underscore and lower case to mixed case? Seems that Babel should do that for me.

(I know that the header may have multiple locales and that I should check them all, but I'd still need to do the conversion for each one.)

Community
  • 1
  • 1
new name
  • 15,861
  • 19
  • 68
  • 114

2 Answers2

1

I'll provide an answer based on the research I've done since I asked the question.

If you are providing links to allow a user to change the locale (e.g., a drop down of languages), then putting the locale in the URL seems like a good solution. For my situation, I'm only interested in automatic detection of locale so I won't implement getting locale from a URL.

Regarding the different locale formats (browsers vs. Babel), it seems that you just need to convert yourself. This answer has great suggestions.

For my use case, it is unlikely that I will implement multiple locales for the same language in different countries any time soon (e.g., I will implement fr_FR but not any other fr_*). I'm just going to take the first two letters of the locale and drop the rest, and that makes the options much simpler.

Community
  • 1
  • 1
new name
  • 15,861
  • 19
  • 68
  • 114
  • Did it work? If one uses `.po` and `.mo` files they are usually loaded by filenames corresponding to locale names. For now I too had to do some tricks to achieve localization that is the same as the generated content (therefore I set it rather than following the http headers). It seems that Babel localizations can inherit a language so that a dialect you didn't localize uses an ancestor (for example an en-gb localization can default to en) so that you start with the language (en) and then the specific dialects do only what the dialects (or national variants) diverge from the ancestor. – Niklas Rosencrantz Feb 19 '17 at 20:49
  • 1
    @DacSaunders, yes it does work. E.g., I have `locale/fr_FR/LC_MESSAGES/messages.po` and when I extract the locale from the HTTP headers, I extract only the first two letters (e.g., `fr`) and calling `set_locale("fr")` will pick up the "po" file under the `fr_FR` directory. – new name Feb 21 '17 at 01:24
  • 1
    @DacSaunders, though since I wrote this answer, I have a better understanding of how to implement locale detection, and I'll write a better answer later. – new name Feb 21 '17 at 01:27
0

I set locale in my code this way.

def dispatch(self):
    # Get a session store for this request.
    self.session_store = sessions.get_store(request=self.request)
    if self.request.host.find('.br') > 0:
        i18n.get_i18n().set_locale('pt-br')
    elif self.request.host.find('klok') > 0:
        i18n.get_i18n().set_locale('sv')
    elif self.request.host.find('business') > 0:
        i18n.get_i18n().set_locale('en')
    else:
        lang_code_get = self.request.get('hl', None)
        if lang_code_get is None:
            lang_code = self.session.get('HTTP_ACCEPT_LANGUAGE', None)
            lang_code_browser = os.environ.get('HTTP_ACCEPT_LANGUAGE')
            if lang_code:
                i18n.get_i18n().set_locale(lang_code)
            if lang_code_browser and lang_code is None:
                self.session['HTTP_ACCEPT_LANGUAGE'] = lang_code_browser
                i18n.get_i18n().set_locale(lang_code_browser)
        else:
            i18n.get_i18n().set_locale(lang_code_get)
    try:
        # Dispatch the request.
        #logging.info('trying to dispatch')
        webapp2.RequestHandler.dispatch(self)
    except Exception, ex:
        logging.error(ex)
        self.error(404)
    finally:
        # Save all sessions.
        self.session_store.save_sessions(self.response)
Niklas Rosencrantz
  • 25,640
  • 75
  • 229
  • 424