Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/utils/translation/__init__.py: 59%
144 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1"""
2Internationalization support.
3"""
4from contextlib import ContextDecorator
5from decimal import ROUND_UP, Decimal
7from django.utils.autoreload import autoreload_started, file_changed
8from django.utils.functional import lazy
9from django.utils.regex_helper import _lazy_re_compile
11__all__ = [
12 "activate",
13 "deactivate",
14 "override",
15 "deactivate_all",
16 "get_language",
17 "get_language_from_request",
18 "get_language_info",
19 "get_language_bidi",
20 "check_for_language",
21 "to_language",
22 "to_locale",
23 "templatize",
24 "gettext",
25 "gettext_lazy",
26 "gettext_noop",
27 "ngettext",
28 "ngettext_lazy",
29 "pgettext",
30 "pgettext_lazy",
31 "npgettext",
32 "npgettext_lazy",
33]
36class TranslatorCommentWarning(SyntaxWarning):
37 pass
40# Here be dragons, so a short explanation of the logic won't hurt:
41# We are trying to solve two problems: (1) access settings, in particular
42# settings.USE_I18N, as late as possible, so that modules can be imported
43# without having to first configure Django, and (2) if some other code creates
44# a reference to one of these functions, don't break that reference when we
45# replace the functions with their real counterparts (once we do access the
46# settings).
49class Trans:
50 """
51 The purpose of this class is to store the actual translation function upon
52 receiving the first call to that function. After this is done, changes to
53 USE_I18N will have no effect to which function is served upon request. If
54 your tests rely on changing USE_I18N, you can delete all the functions
55 from _trans.__dict__.
57 Note that storing the function with setattr will have a noticeable
58 performance effect, as access to the function goes the normal path,
59 instead of using __getattr__.
60 """
62 def __getattr__(self, real_name):
63 from django.conf import settings
65 if settings.USE_I18N: 65 ↛ 79line 65 didn't jump to line 79, because the condition on line 65 was never false
66 from django.utils.translation import trans_real as trans
67 from django.utils.translation.reloader import (
68 translation_file_changed,
69 watch_for_translation_changes,
70 )
72 autoreload_started.connect(
73 watch_for_translation_changes, dispatch_uid="translation_file_changed"
74 )
75 file_changed.connect(
76 translation_file_changed, dispatch_uid="translation_file_changed"
77 )
78 else:
79 from django.utils.translation import trans_null as trans
80 setattr(self, real_name, getattr(trans, real_name))
81 return getattr(trans, real_name)
84_trans = Trans()
86# The Trans class is no more needed, so remove it from the namespace.
87del Trans
90def gettext_noop(message):
91 return _trans.gettext_noop(message)
94def gettext(message):
95 return _trans.gettext(message)
98def ngettext(singular, plural, number):
99 return _trans.ngettext(singular, plural, number)
102def pgettext(context, message):
103 return _trans.pgettext(context, message)
106def npgettext(context, singular, plural, number):
107 return _trans.npgettext(context, singular, plural, number)
110gettext_lazy = lazy(gettext, str)
111pgettext_lazy = lazy(pgettext, str)
114def lazy_number(func, resultclass, number=None, **kwargs):
115 if isinstance(number, int): 115 ↛ 116line 115 didn't jump to line 116, because the condition on line 115 was never true
116 kwargs["number"] = number
117 proxy = lazy(func, resultclass)(**kwargs)
118 else:
119 original_kwargs = kwargs.copy()
121 class NumberAwareString(resultclass):
122 def __bool__(self):
123 return bool(kwargs["singular"])
125 def _get_number_value(self, values):
126 try:
127 return values[number]
128 except KeyError:
129 raise KeyError(
130 "Your dictionary lacks key '%s'. Please provide "
131 "it, because it is required to determine whether "
132 "string is singular or plural." % number
133 )
135 def _translate(self, number_value):
136 kwargs["number"] = number_value
137 return func(**kwargs)
139 def format(self, *args, **kwargs):
140 number_value = (
141 self._get_number_value(kwargs) if kwargs and number else args[0]
142 )
143 return self._translate(number_value).format(*args, **kwargs)
145 def __mod__(self, rhs):
146 if isinstance(rhs, dict) and number:
147 number_value = self._get_number_value(rhs)
148 else:
149 number_value = rhs
150 translated = self._translate(number_value)
151 try:
152 translated = translated % rhs
153 except TypeError:
154 # String doesn't contain a placeholder for the number.
155 pass
156 return translated
158 proxy = lazy(lambda **kwargs: NumberAwareString(), NumberAwareString)(**kwargs) 158 ↛ exitline 158 didn't run the lambda on line 158
159 proxy.__reduce__ = lambda: ( 159 ↛ exitline 159 didn't run the lambda on line 159
160 _lazy_number_unpickle,
161 (func, resultclass, number, original_kwargs),
162 )
163 return proxy
166def _lazy_number_unpickle(func, resultclass, number, kwargs):
167 return lazy_number(func, resultclass, number=number, **kwargs)
170def ngettext_lazy(singular, plural, number=None):
171 return lazy_number(ngettext, str, singular=singular, plural=plural, number=number)
174def npgettext_lazy(context, singular, plural, number=None):
175 return lazy_number(
176 npgettext, str, context=context, singular=singular, plural=plural, number=number
177 )
180def activate(language):
181 return _trans.activate(language)
184def deactivate():
185 return _trans.deactivate()
188class override(ContextDecorator):
189 def __init__(self, language, deactivate=False):
190 self.language = language
191 self.deactivate = deactivate
193 def __enter__(self):
194 self.old_language = get_language()
195 if self.language is not None: 195 ↛ 196line 195 didn't jump to line 196, because the condition on line 195 was never true
196 activate(self.language)
197 else:
198 deactivate_all()
200 def __exit__(self, exc_type, exc_value, traceback):
201 if self.old_language is None:
202 deactivate_all()
203 elif self.deactivate: 203 ↛ 204line 203 didn't jump to line 204, because the condition on line 203 was never true
204 deactivate()
205 else:
206 activate(self.old_language)
209def get_language():
210 return _trans.get_language()
213def get_language_bidi():
214 return _trans.get_language_bidi()
217def check_for_language(lang_code):
218 return _trans.check_for_language(lang_code)
221def to_language(locale):
222 """Turn a locale name (en_US) into a language name (en-us)."""
223 p = locale.find("_")
224 if p >= 0: 224 ↛ 225line 224 didn't jump to line 225, because the condition on line 224 was never true
225 return locale[:p].lower() + "-" + locale[p + 1 :].lower()
226 else:
227 return locale.lower()
230def to_locale(language):
231 """Turn a language name (en-us) into a locale name (en_US)."""
232 lang, _, country = language.lower().partition("-")
233 if not country: 233 ↛ 234line 233 didn't jump to line 234, because the condition on line 233 was never true
234 return language[:3].lower() + language[3:]
235 # A language with > 2 characters after the dash only has its first
236 # character after the dash capitalized; e.g. sr-latn becomes sr_Latn.
237 # A language with 2 characters after the dash has both characters
238 # capitalized; e.g. en-us becomes en_US.
239 country, _, tail = country.partition("-")
240 country = country.title() if len(country) > 2 else country.upper()
241 if tail: 241 ↛ 242line 241 didn't jump to line 242, because the condition on line 241 was never true
242 country += "-" + tail
243 return lang + "_" + country
246def get_language_from_request(request, check_path=False):
247 return _trans.get_language_from_request(request, check_path)
250def get_language_from_path(path):
251 return _trans.get_language_from_path(path)
254def get_supported_language_variant(lang_code, *, strict=False):
255 return _trans.get_supported_language_variant(lang_code, strict)
258def templatize(src, **kwargs):
259 from .template import templatize
261 return templatize(src, **kwargs)
264def deactivate_all():
265 return _trans.deactivate_all()
268def get_language_info(lang_code):
269 from django.conf.locale import LANG_INFO
271 try:
272 lang_info = LANG_INFO[lang_code]
273 if "fallback" in lang_info and "name" not in lang_info:
274 info = get_language_info(lang_info["fallback"][0])
275 else:
276 info = lang_info
277 except KeyError:
278 if "-" not in lang_code:
279 raise KeyError("Unknown language code %s." % lang_code)
280 generic_lang_code = lang_code.split("-")[0]
281 try:
282 info = LANG_INFO[generic_lang_code]
283 except KeyError:
284 raise KeyError(
285 "Unknown language code %s and %s." % (lang_code, generic_lang_code)
286 )
288 if info:
289 info["name_translated"] = gettext_lazy(info["name"])
290 return info
293trim_whitespace_re = _lazy_re_compile(r"\s*\n\s*")
296def trim_whitespace(s):
297 return trim_whitespace_re.sub(" ", s.strip())
300def round_away_from_one(value):
301 return int(Decimal(value - 1).quantize(Decimal("0"), rounding=ROUND_UP)) + 1