| 1 | from __future__ import unicode_literals
|
|---|
| 2 | import locale
|
|---|
| 3 | import os
|
|---|
| 4 |
|
|---|
| 5 | from django.utils.translation.trans_real import (get_supported_language_variant,
|
|---|
| 6 | parse_accept_lang_header,
|
|---|
| 7 | get_language_from_path,
|
|---|
| 8 | check_for_language,
|
|---|
| 9 | all_locale_paths,
|
|---|
| 10 | to_locale,
|
|---|
| 11 | _accepted)
|
|---|
| 12 |
|
|---|
| 13 | # TODO: locale mapper (map locale in url to one of supported locales)
|
|---|
| 14 | # this may be convenient to design localized url first (for SEO purposes)
|
|---|
| 15 | # and add more locales later
|
|---|
| 16 |
|
|---|
| 17 | def LocaleSelector(object):
|
|---|
| 18 | def __init__(self, check_path=False):
|
|---|
| 19 | from django.conf import settings
|
|---|
| 20 | self.supported = dict(settings.LANGUAGES)
|
|---|
| 21 | self.cookie_name = settings.LANGUAGE_COOKIE_NAME
|
|---|
| 22 | self.default_language_code = settings.LANGUAGE_CODE
|
|---|
| 23 | self.check_path = check_path
|
|---|
| 24 | self.selectors = [self.get_language_from_path,
|
|---|
| 25 | self.get_language_from_session,
|
|---|
| 26 | self.get_language_from_cookie,
|
|---|
| 27 | self.get_language_from_header,
|
|---|
| 28 | self.get_fallback_language] # last one should always return a result
|
|---|
| 29 |
|
|---|
| 30 | def get_language_from_path(request):
|
|---|
| 31 | if self.check_path:
|
|---|
| 32 | lang_code = get_language_from_path(request.path_info, self.supported)
|
|---|
| 33 | if lang_code is not None:
|
|---|
| 34 | return lang_code
|
|---|
| 35 |
|
|---|
| 36 | def get_language_from_session(request):
|
|---|
| 37 | if hasattr(request, 'session'):
|
|---|
| 38 | lang_code = request.session.get('django_language', None)
|
|---|
| 39 | if lang_code in self.supported and lang_code is not None and check_for_language(lang_code):
|
|---|
| 40 | return lang_code
|
|---|
| 41 |
|
|---|
| 42 | def get_language_from_cookie(request):
|
|---|
| 43 | lang_code = request.COOKIES.get(self.cookie_name)
|
|---|
| 44 | try:
|
|---|
| 45 | return get_supported_language_variant(lang_code, self.supported)
|
|---|
| 46 | except LookupError:
|
|---|
| 47 | pass
|
|---|
| 48 |
|
|---|
| 49 | def get_language_from_header(request):
|
|---|
| 50 | global _accepted
|
|---|
| 51 |
|
|---|
| 52 | accept = request.META.get('HTTP_ACCEPT_LANGUAGE', '')
|
|---|
| 53 | for accept_lang, unused in parse_accept_lang_header(accept):
|
|---|
| 54 | if accept_lang == '*':
|
|---|
| 55 | break
|
|---|
| 56 |
|
|---|
| 57 | # We have a very restricted form for our language files (no encoding
|
|---|
| 58 | # specifier, since they all must be UTF-8 and only one possible
|
|---|
| 59 | # language each time. So we avoid the overhead of gettext.find() and
|
|---|
| 60 | # work out the MO file manually.
|
|---|
| 61 |
|
|---|
| 62 | # 'normalized' is the root name of the locale in POSIX format (which is
|
|---|
| 63 | # the format used for the directories holding the MO files).
|
|---|
| 64 | normalized = locale.locale_alias.get(to_locale(accept_lang, True))
|
|---|
| 65 | if not normalized:
|
|---|
| 66 | continue
|
|---|
| 67 | # Remove the default encoding from locale_alias.
|
|---|
| 68 | normalized = normalized.split('.')[0]
|
|---|
| 69 |
|
|---|
| 70 | if normalized in _accepted:
|
|---|
| 71 | # We've seen this locale before and have an MO file for it, so no
|
|---|
| 72 | # need to check again.
|
|---|
| 73 | return _accepted[normalized]
|
|---|
| 74 |
|
|---|
| 75 | for lang, dirname in ((accept_lang, normalized),
|
|---|
| 76 | (accept_lang.split('-')[0], normalized.split('_')[0])):
|
|---|
| 77 | if lang.lower() not in self.supported:
|
|---|
| 78 | continue
|
|---|
| 79 | for path in all_locale_paths():
|
|---|
| 80 | if os.path.exists(os.path.join(path, dirname, 'LC_MESSAGES', 'django.mo')):
|
|---|
| 81 | _accepted[normalized] = lang
|
|---|
| 82 | return lang
|
|---|
| 83 |
|
|---|
| 84 | def get_fallback_language(_request):
|
|---|
| 85 | try:
|
|---|
| 86 | return get_supported_language_variant(self.default_language_code, self.supported)
|
|---|
| 87 | except LookupError:
|
|---|
| 88 | return self.default_language_code
|
|---|
| 89 |
|
|---|
| 90 | def select(request):
|
|---|
| 91 | for selector in self.selectors:
|
|---|
| 92 | lang_code = selector(request)
|
|---|
| 93 | if lang_code is not None:
|
|---|
| 94 | return lang_code
|
|---|