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