1
|
|
|
""" |
2
|
|
|
The configuration wrappers that are used for :ref:`PARLER_LANGUAGES`. |
3
|
|
|
""" |
4
|
|
|
from django.conf import settings |
5
|
|
|
from django.core.exceptions import ImproperlyConfigured |
6
|
|
|
from django.utils import six |
7
|
|
|
from django.utils.translation import get_language |
8
|
|
|
from parler.utils.i18n import is_supported_django_language |
9
|
|
|
import warnings |
10
|
|
|
|
11
|
|
|
|
12
|
|
|
def add_default_language_settings(languages_list, var_name='PARLER_LANGUAGES', **extra_defaults): |
13
|
|
|
""" |
14
|
|
|
Apply extra defaults to the language settings. |
15
|
|
|
This function can also be used by other packages to |
16
|
|
|
create their own variation of ``PARLER_LANGUAGES`` with extra fields. |
17
|
|
|
For example:: |
18
|
|
|
|
19
|
|
|
from django.conf import settings |
20
|
|
|
from parler import appsettings as parler_appsettings |
21
|
|
|
|
22
|
|
|
# Create local names, which are based on the global parler settings |
23
|
|
|
MYAPP_DEFAULT_LANGUAGE_CODE = getattr(settings, 'MYAPP_DEFAULT_LANGUAGE_CODE', parler_appsettings.PARLER_DEFAULT_LANGUAGE_CODE) |
24
|
|
|
MYAPP_LANGUAGES = getattr(settings, 'MYAPP_LANGUAGES', parler_appsettings.PARLER_LANGUAGES) |
25
|
|
|
|
26
|
|
|
# Apply the defaults to the languages |
27
|
|
|
MYAPP_LANGUAGES = parler_appsettings.add_default_language_settings(MYAPP_LANGUAGES, 'MYAPP_LANGUAGES', |
28
|
|
|
code=MYAPP_DEFAULT_LANGUAGE_CODE, |
29
|
|
|
fallback=MYAPP_DEFAULT_LANGUAGE_CODE, |
30
|
|
|
hide_untranslated=False |
31
|
|
|
) |
32
|
|
|
|
33
|
|
|
The returned object will be an :class:`~parler.utils.conf.LanguagesSetting` object, |
34
|
|
|
which adds additional methods to the :class:`dict` object. |
35
|
|
|
|
36
|
|
|
:param languages_list: The settings, in :ref:`PARLER_LANGUAGES` format. |
37
|
|
|
:param var_name: The name of your variable, for debugging output. |
38
|
|
|
:param extra_defaults: Any defaults to override in the ``languages_list['default']`` section, e.g. ``code``, ``fallback``, ``hide_untranslated``. |
39
|
|
|
:return: The updated ``languages_list`` with all defaults applied to all sections. |
40
|
|
|
:rtype: LanguagesSetting |
41
|
|
|
""" |
42
|
|
|
languages_list = LanguagesSetting(languages_list) |
43
|
|
|
|
44
|
|
|
languages_list.setdefault('default', {}) |
45
|
|
|
defaults = languages_list['default'] |
46
|
|
|
defaults.setdefault('hide_untranslated', False) # Whether queries with .active_translations() may or may not return the fallback language. |
47
|
|
|
|
48
|
|
|
if 'fallback' in defaults: |
49
|
|
|
#warnings.warn("Please use 'fallbacks' instead of 'fallback' in the 'defaults' section of {0}".format(var_name), DeprecationWarning) |
50
|
|
|
defaults['fallbacks'] = [defaults.pop('fallback')] |
51
|
|
|
if 'fallback' in extra_defaults: |
52
|
|
|
#warnings.warn("Please use 'fallbacks' instead of 'fallback' in parameters for {0} = add_default_language_settings(..)".format(var_name), DeprecationWarning) |
53
|
|
|
extra_defaults['fallbacks'] = [extra_defaults.pop('fallback')] |
54
|
|
|
|
55
|
|
|
defaults.update(extra_defaults) # Also allow to override code and fallback this way. |
56
|
|
|
|
57
|
|
|
# This function previously existed in appsettings, where it could reference the defaults directly. |
58
|
|
|
# However, this module is a more logical place for this function. To avoid circular import problems, |
59
|
|
|
# the 'code' and 'fallback' parameters are always passed by the appsettings module. |
60
|
|
|
# In case these are missing, default to the original behavior for backwards compatibility. |
61
|
|
|
if 'code' not in defaults: |
62
|
|
|
from parler import appsettings |
63
|
|
|
defaults['code'] = appsettings.PARLER_DEFAULT_LANGUAGE_CODE |
64
|
|
|
if 'fallbacks' not in defaults: |
65
|
|
|
from parler import appsettings |
66
|
|
|
defaults['fallbacks'] = appsettings.PARLER_DEFAULT_LANGUAGE_CODE |
67
|
|
|
|
68
|
|
|
if not is_supported_django_language(defaults['code']): |
69
|
|
|
raise ImproperlyConfigured("The value for {0}['defaults']['code'] ('{1}') does not exist in LANGUAGES".format(var_name, defaults['code'])) |
70
|
|
|
|
71
|
|
|
for site_id, lang_choices in six.iteritems(languages_list): |
72
|
|
|
if site_id == 'default': |
73
|
|
|
continue |
74
|
|
|
|
75
|
|
|
if not isinstance(lang_choices, (list, tuple)): |
76
|
|
|
raise ImproperlyConfigured("{0}[{1}] should be a tuple of language choices!".format(var_name, site_id)) |
77
|
|
|
for i, choice in enumerate(lang_choices): |
78
|
|
|
if not is_supported_django_language(choice['code']): |
79
|
|
|
raise ImproperlyConfigured("{0}[{1}][{2}]['code'] does not exist in LANGUAGES".format(var_name, site_id, i)) |
80
|
|
|
|
81
|
|
|
# Copy all items from the defaults, so you can provide new fields too. |
82
|
|
|
for key, value in six.iteritems(defaults): |
83
|
|
|
choice.setdefault(key, value) |
84
|
|
|
|
85
|
|
|
return languages_list |
86
|
|
|
|
87
|
|
|
|
88
|
|
|
|
89
|
|
|
class LanguagesSetting(dict): |
90
|
|
|
""" |
91
|
|
|
This is the actual object type of the :ref:`PARLER_LANGUAGES` setting. |
92
|
|
|
Besides the regular :class:`dict` behavior, it also adds some additional methods. |
93
|
|
|
""" |
94
|
|
|
|
95
|
|
|
def get_language(self, language_code, site_id=None): |
96
|
|
|
""" |
97
|
|
|
Return the language settings for the current site |
98
|
|
|
|
99
|
|
|
This function can be used with other settings variables |
100
|
|
|
to support modules which create their own variation of the ``PARLER_LANGUAGES`` setting. |
101
|
|
|
For an example, see :func:`~parler.appsettings.add_default_language_settings`. |
102
|
|
|
""" |
103
|
|
|
if site_id is None: |
104
|
|
|
site_id = getattr(settings, 'SITE_ID', None) |
105
|
|
|
|
106
|
|
|
for lang_dict in self.get(site_id, ()): |
107
|
|
|
if lang_dict['code'] == language_code: |
108
|
|
|
return lang_dict |
109
|
|
|
|
110
|
|
|
# no language match, search for variant: fr-ca falls back to fr |
111
|
|
|
for lang_dict in self.get(site_id, ()): |
112
|
|
|
if lang_dict['code'].split('-')[0] == language_code.split('-')[0]: |
113
|
|
|
return lang_dict |
114
|
|
|
|
115
|
|
|
return self['default'] |
116
|
|
|
|
117
|
|
|
|
118
|
|
|
def get_active_choices(self, language_code=None, site_id=None): |
119
|
|
|
""" |
120
|
|
|
Find out which translations should be visible in the site. |
121
|
|
|
It returns a list with either a single choice (the current language), |
122
|
|
|
or a list with the current language + fallback language. |
123
|
|
|
""" |
124
|
|
|
if language_code is None: |
125
|
|
|
language_code = get_language() |
126
|
|
|
|
127
|
|
|
lang_dict = self.get_language(language_code, site_id=site_id) |
128
|
|
|
if not lang_dict['hide_untranslated']: |
129
|
|
|
return [language_code] + [lang for lang in lang_dict['fallbacks'] if lang != language_code] |
130
|
|
|
else: |
131
|
|
|
return [language_code] |
132
|
|
|
|
133
|
|
|
|
134
|
|
|
def get_fallback_languages(self, language_code=None, site_id=None): |
135
|
|
|
""" |
136
|
|
|
Find out what the fallback language is for a given language choice. |
137
|
|
|
|
138
|
|
|
.. versionadded 1.5 |
139
|
|
|
""" |
140
|
|
|
choices = self.get_active_choices(language_code, site_id=site_id) |
141
|
|
|
return choices[1:] |
142
|
|
|
|
143
|
|
|
|
144
|
|
|
def get_fallback_language(self, language_code=None, site_id=None): |
145
|
|
|
""" |
146
|
|
|
Find out what the fallback language is for a given language choice. |
147
|
|
|
|
148
|
|
|
.. deprecated:: 1.5 |
149
|
|
|
Use :func:`get_fallback_languages` instead. |
150
|
|
|
""" |
151
|
|
|
choices = self.get_active_choices(language_code, site_id=site_id) |
152
|
|
|
if choices and len(choices) > 1: |
153
|
|
|
# Still take the last, like previous code. |
154
|
|
|
# With multiple fallback languages that means taking the base language. |
155
|
|
|
# Hence, upgrade the code to use get_fallback_languages() instead. |
156
|
|
|
return choices[-1] |
157
|
|
|
else: |
158
|
|
|
return None |
159
|
|
|
|
160
|
|
|
|
161
|
|
|
def get_default_language(self): |
162
|
|
|
""" |
163
|
|
|
Return the default language. |
164
|
|
|
""" |
165
|
|
|
return self['default']['code'] |
166
|
|
|
|
167
|
|
|
|
168
|
|
|
def get_first_language(self, site_id=None): |
169
|
|
|
""" |
170
|
|
|
Return the first language for the current site. |
171
|
|
|
This can be used for user interfaces, where the languages are displayed in tabs. |
172
|
|
|
""" |
173
|
|
|
if site_id is None: |
174
|
|
|
site_id = getattr(settings, 'SITE_ID', None) |
175
|
|
|
|
176
|
|
|
try: |
177
|
|
|
return self[site_id][0]['code'] |
178
|
|
|
except (KeyError, IndexError): |
179
|
|
|
# No configuration, always fallback to default language. |
180
|
|
|
# This is essentially a non-multilingual configuration. |
181
|
|
|
return self['default']['code'] |
182
|
|
|
|