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

1""" 

2Internationalization support. 

3""" 

4from contextlib import ContextDecorator 

5from decimal import ROUND_UP, Decimal 

6 

7from django.utils.autoreload import autoreload_started, file_changed 

8from django.utils.functional import lazy 

9from django.utils.regex_helper import _lazy_re_compile 

10 

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] 

34 

35 

36class TranslatorCommentWarning(SyntaxWarning): 

37 pass 

38 

39 

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

47 

48 

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

56 

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

61 

62 def __getattr__(self, real_name): 

63 from django.conf import settings 

64 

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 ) 

71 

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) 

82 

83 

84_trans = Trans() 

85 

86# The Trans class is no more needed, so remove it from the namespace. 

87del Trans 

88 

89 

90def gettext_noop(message): 

91 return _trans.gettext_noop(message) 

92 

93 

94def gettext(message): 

95 return _trans.gettext(message) 

96 

97 

98def ngettext(singular, plural, number): 

99 return _trans.ngettext(singular, plural, number) 

100 

101 

102def pgettext(context, message): 

103 return _trans.pgettext(context, message) 

104 

105 

106def npgettext(context, singular, plural, number): 

107 return _trans.npgettext(context, singular, plural, number) 

108 

109 

110gettext_lazy = lazy(gettext, str) 

111pgettext_lazy = lazy(pgettext, str) 

112 

113 

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

120 

121 class NumberAwareString(resultclass): 

122 def __bool__(self): 

123 return bool(kwargs["singular"]) 

124 

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 ) 

134 

135 def _translate(self, number_value): 

136 kwargs["number"] = number_value 

137 return func(**kwargs) 

138 

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) 

144 

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 

157 

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 

164 

165 

166def _lazy_number_unpickle(func, resultclass, number, kwargs): 

167 return lazy_number(func, resultclass, number=number, **kwargs) 

168 

169 

170def ngettext_lazy(singular, plural, number=None): 

171 return lazy_number(ngettext, str, singular=singular, plural=plural, number=number) 

172 

173 

174def npgettext_lazy(context, singular, plural, number=None): 

175 return lazy_number( 

176 npgettext, str, context=context, singular=singular, plural=plural, number=number 

177 ) 

178 

179 

180def activate(language): 

181 return _trans.activate(language) 

182 

183 

184def deactivate(): 

185 return _trans.deactivate() 

186 

187 

188class override(ContextDecorator): 

189 def __init__(self, language, deactivate=False): 

190 self.language = language 

191 self.deactivate = deactivate 

192 

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

199 

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) 

207 

208 

209def get_language(): 

210 return _trans.get_language() 

211 

212 

213def get_language_bidi(): 

214 return _trans.get_language_bidi() 

215 

216 

217def check_for_language(lang_code): 

218 return _trans.check_for_language(lang_code) 

219 

220 

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

228 

229 

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 

244 

245 

246def get_language_from_request(request, check_path=False): 

247 return _trans.get_language_from_request(request, check_path) 

248 

249 

250def get_language_from_path(path): 

251 return _trans.get_language_from_path(path) 

252 

253 

254def get_supported_language_variant(lang_code, *, strict=False): 

255 return _trans.get_supported_language_variant(lang_code, strict) 

256 

257 

258def templatize(src, **kwargs): 

259 from .template import templatize 

260 

261 return templatize(src, **kwargs) 

262 

263 

264def deactivate_all(): 

265 return _trans.deactivate_all() 

266 

267 

268def get_language_info(lang_code): 

269 from django.conf.locale import LANG_INFO 

270 

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 ) 

287 

288 if info: 

289 info["name_translated"] = gettext_lazy(info["name"]) 

290 return info 

291 

292 

293trim_whitespace_re = _lazy_re_compile(r"\s*\n\s*") 

294 

295 

296def trim_whitespace(s): 

297 return trim_whitespace_re.sub(" ", s.strip()) 

298 

299 

300def round_away_from_one(value): 

301 return int(Decimal(value - 1).quantize(Decimal("0"), rounding=ROUND_UP)) + 1