38 p = language.find('-') |
39 p = language.find('-') |
39 if p >= 0: |
40 if p >= 0: |
40 if to_lower: |
41 if to_lower: |
41 return language[:p].lower()+'_'+language[p+1:].lower() |
42 return language[:p].lower()+'_'+language[p+1:].lower() |
42 else: |
43 else: |
|
44 # Get correct locale for sr-latn |
|
45 if len(language[p+1:]) > 2: |
|
46 return language[:p].lower()+'_'+language[p+1].upper()+language[p+2:].lower() |
43 return language[:p].lower()+'_'+language[p+1:].upper() |
47 return language[:p].lower()+'_'+language[p+1:].upper() |
44 else: |
48 else: |
45 return language.lower() |
49 return language.lower() |
46 |
50 |
47 def to_language(locale): |
51 def to_language(locale): |
54 |
58 |
55 class DjangoTranslation(gettext_module.GNUTranslations): |
59 class DjangoTranslation(gettext_module.GNUTranslations): |
56 """ |
60 """ |
57 This class sets up the GNUTranslations context with regard to output |
61 This class sets up the GNUTranslations context with regard to output |
58 charset. Django uses a defined DEFAULT_CHARSET as the output charset on |
62 charset. Django uses a defined DEFAULT_CHARSET as the output charset on |
59 Python 2.4. With Python 2.3, use DjangoTranslation23. |
63 Python 2.4. |
60 """ |
64 """ |
61 def __init__(self, *args, **kw): |
65 def __init__(self, *args, **kw): |
62 from django.conf import settings |
66 from django.conf import settings |
63 gettext_module.GNUTranslations.__init__(self, *args, **kw) |
67 gettext_module.GNUTranslations.__init__(self, *args, **kw) |
64 # Starting with Python 2.4, there's a function to define |
68 # Starting with Python 2.4, there's a function to define |
81 return self.__language |
85 return self.__language |
82 |
86 |
83 def __repr__(self): |
87 def __repr__(self): |
84 return "<DjangoTranslation lang:%s>" % self.__language |
88 return "<DjangoTranslation lang:%s>" % self.__language |
85 |
89 |
86 class DjangoTranslation23(DjangoTranslation): |
|
87 """ |
|
88 Compatibility class that is only used with Python 2.3. |
|
89 Python 2.3 doesn't support set_output_charset on translation objects and |
|
90 needs this wrapper class to make sure input charsets from translation files |
|
91 are correctly translated to output charsets. |
|
92 |
|
93 With a full switch to Python 2.4, this can be removed from the source. |
|
94 """ |
|
95 def gettext(self, msgid): |
|
96 res = self.ugettext(msgid) |
|
97 return res.encode(self.django_output_charset) |
|
98 |
|
99 def ngettext(self, msgid1, msgid2, n): |
|
100 res = self.ungettext(msgid1, msgid2, n) |
|
101 return res.encode(self.django_output_charset) |
|
102 |
|
103 def translation(language): |
90 def translation(language): |
104 """ |
91 """ |
105 Returns a translation object. |
92 Returns a translation object. |
106 |
93 |
107 This translation object will be constructed out of multiple GNUTranslations |
94 This translation object will be constructed out of multiple GNUTranslations |
114 t = _translations.get(language, None) |
101 t = _translations.get(language, None) |
115 if t is not None: |
102 if t is not None: |
116 return t |
103 return t |
117 |
104 |
118 from django.conf import settings |
105 from django.conf import settings |
119 |
|
120 # set up the right translation class |
|
121 klass = DjangoTranslation |
|
122 if sys.version_info < (2, 4): |
|
123 klass = DjangoTranslation23 |
|
124 |
106 |
125 globalpath = os.path.join(os.path.dirname(sys.modules[settings.__module__].__file__), 'locale') |
107 globalpath = os.path.join(os.path.dirname(sys.modules[settings.__module__].__file__), 'locale') |
126 |
108 |
127 if settings.SETTINGS_MODULE is not None: |
109 if settings.SETTINGS_MODULE is not None: |
128 parts = settings.SETTINGS_MODULE.split('.') |
110 parts = settings.SETTINGS_MODULE.split('.') |
171 |
153 |
172 for localepath in settings.LOCALE_PATHS: |
154 for localepath in settings.LOCALE_PATHS: |
173 if os.path.isdir(localepath): |
155 if os.path.isdir(localepath): |
174 res = _merge(localepath) |
156 res = _merge(localepath) |
175 |
157 |
176 if projectpath and os.path.isdir(projectpath): |
|
177 res = _merge(projectpath) |
|
178 |
|
179 for appname in settings.INSTALLED_APPS: |
158 for appname in settings.INSTALLED_APPS: |
180 app = import_module(appname) |
159 app = import_module(appname) |
181 apppath = os.path.join(os.path.dirname(app.__file__), 'locale') |
160 apppath = os.path.join(os.path.dirname(app.__file__), 'locale') |
182 |
161 |
183 if os.path.isdir(apppath): |
162 if os.path.isdir(apppath): |
184 res = _merge(apppath) |
163 res = _merge(apppath) |
|
164 |
|
165 if projectpath and os.path.isdir(projectpath): |
|
166 res = _merge(projectpath) |
185 |
167 |
186 if res is None: |
168 if res is None: |
187 if fallback is not None: |
169 if fallback is not None: |
188 res = fallback |
170 res = fallback |
189 else: |
171 else: |
200 """ |
182 """ |
201 Fetches the translation object for a given tuple of application name and |
183 Fetches the translation object for a given tuple of application name and |
202 language and installs it as the current translation object for the current |
184 language and installs it as the current translation object for the current |
203 thread. |
185 thread. |
204 """ |
186 """ |
|
187 if isinstance(language, basestring) and language == 'no': |
|
188 warnings.warn( |
|
189 "The use of the language code 'no' is deprecated. " |
|
190 "Please use the 'nb' translation instead.", |
|
191 PendingDeprecationWarning |
|
192 ) |
205 _active[currentThread()] = translation(language) |
193 _active[currentThread()] = translation(language) |
206 |
194 |
207 def deactivate(): |
195 def deactivate(): |
208 """ |
196 """ |
209 Deinstalls the currently active translation object so that further _ calls |
197 Deinstalls the currently active translation object so that further _ calls |
264 Translates 'message' using the given 'translation_function' name -- which |
252 Translates 'message' using the given 'translation_function' name -- which |
265 will be either gettext or ugettext. It uses the current thread to find the |
253 will be either gettext or ugettext. It uses the current thread to find the |
266 translation object to use. If no current translation is activated, the |
254 translation object to use. If no current translation is activated, the |
267 message will be run through the default translation object. |
255 message will be run through the default translation object. |
268 """ |
256 """ |
|
257 eol_message = message.replace('\r\n', '\n').replace('\r', '\n') |
269 global _default, _active |
258 global _default, _active |
270 t = _active.get(currentThread(), None) |
259 t = _active.get(currentThread(), None) |
271 if t is not None: |
260 if t is not None: |
272 result = getattr(t, translation_function)(message) |
261 result = getattr(t, translation_function)(eol_message) |
273 else: |
262 else: |
274 if _default is None: |
263 if _default is None: |
275 from django.conf import settings |
264 from django.conf import settings |
276 _default = translation(settings.LANGUAGE_CODE) |
265 _default = translation(settings.LANGUAGE_CODE) |
277 result = getattr(_default, translation_function)(message) |
266 result = getattr(_default, translation_function)(eol_message) |
278 if isinstance(message, SafeData): |
267 if isinstance(message, SafeData): |
279 return mark_safe(result) |
268 return mark_safe(result) |
280 return result |
269 return result |
281 |
270 |
282 def gettext(message): |
271 def gettext(message): |
349 lang_code = request.session.get('django_language', None) |
338 lang_code = request.session.get('django_language', None) |
350 if lang_code in supported and lang_code is not None and check_for_language(lang_code): |
339 if lang_code in supported and lang_code is not None and check_for_language(lang_code): |
351 return lang_code |
340 return lang_code |
352 |
341 |
353 lang_code = request.COOKIES.get(settings.LANGUAGE_COOKIE_NAME) |
342 lang_code = request.COOKIES.get(settings.LANGUAGE_COOKIE_NAME) |
|
343 |
|
344 if lang_code and lang_code not in supported: |
|
345 lang_code = lang_code.split('-')[0] # e.g. if fr-ca is not supported fallback to fr |
|
346 |
354 if lang_code and lang_code in supported and check_for_language(lang_code): |
347 if lang_code and lang_code in supported and check_for_language(lang_code): |
355 return lang_code |
348 return lang_code |
356 |
349 |
357 accept = request.META.get('HTTP_ACCEPT_LANGUAGE', '') |
350 accept = request.META.get('HTTP_ACCEPT_LANGUAGE', '') |
358 for accept_lang, unused in parse_accept_lang_header(accept): |
351 for accept_lang, unused in parse_accept_lang_header(accept): |
386 if os.path.exists(langfile): |
379 if os.path.exists(langfile): |
387 _accepted[normalized] = lang |
380 _accepted[normalized] = lang |
388 return lang |
381 return lang |
389 |
382 |
390 return settings.LANGUAGE_CODE |
383 return settings.LANGUAGE_CODE |
391 |
|
392 def get_date_formats(): |
|
393 """ |
|
394 Checks whether translation files provide a translation for some technical |
|
395 message ID to store date and time formats. If it doesn't contain one, the |
|
396 formats provided in the settings will be used. |
|
397 """ |
|
398 from django.conf import settings |
|
399 date_format = ugettext('DATE_FORMAT') |
|
400 datetime_format = ugettext('DATETIME_FORMAT') |
|
401 time_format = ugettext('TIME_FORMAT') |
|
402 if date_format == 'DATE_FORMAT': |
|
403 date_format = settings.DATE_FORMAT |
|
404 if datetime_format == 'DATETIME_FORMAT': |
|
405 datetime_format = settings.DATETIME_FORMAT |
|
406 if time_format == 'TIME_FORMAT': |
|
407 time_format = settings.TIME_FORMAT |
|
408 return date_format, datetime_format, time_format |
|
409 |
|
410 def get_partial_date_formats(): |
|
411 """ |
|
412 Checks whether translation files provide a translation for some technical |
|
413 message ID to store partial date formats. If it doesn't contain one, the |
|
414 formats provided in the settings will be used. |
|
415 """ |
|
416 from django.conf import settings |
|
417 year_month_format = ugettext('YEAR_MONTH_FORMAT') |
|
418 month_day_format = ugettext('MONTH_DAY_FORMAT') |
|
419 if year_month_format == 'YEAR_MONTH_FORMAT': |
|
420 year_month_format = settings.YEAR_MONTH_FORMAT |
|
421 if month_day_format == 'MONTH_DAY_FORMAT': |
|
422 month_day_format = settings.MONTH_DAY_FORMAT |
|
423 return year_month_format, month_day_format |
|
424 |
384 |
425 dot_re = re.compile(r'\S') |
385 dot_re = re.compile(r'\S') |
426 def blankout(src, char): |
386 def blankout(src, char): |
427 """ |
387 """ |
428 Changes every non-whitespace character to the given char. |
388 Changes every non-whitespace character to the given char. |
535 return [] |
495 return [] |
536 priority = priority and float(priority) or 1.0 |
496 priority = priority and float(priority) or 1.0 |
537 result.append((lang, priority)) |
497 result.append((lang, priority)) |
538 result.sort(lambda x, y: -cmp(x[1], y[1])) |
498 result.sort(lambda x, y: -cmp(x[1], y[1])) |
539 return result |
499 return result |
|
500 |
|
501 # get_date_formats and get_partial_date_formats aren't used anymore by Django |
|
502 # and are kept for backward compatibility. |
|
503 # Note, it's also important to keep format names marked for translation. |
|
504 # For compatibility we still want to have formats on translation catalogs. |
|
505 # That makes template code like {{ my_date|date:_('DATE_FORMAT') }} still work |
|
506 def get_date_formats(): |
|
507 """ |
|
508 Checks whether translation files provide a translation for some technical |
|
509 message ID to store date and time formats. If it doesn't contain one, the |
|
510 formats provided in the settings will be used. |
|
511 """ |
|
512 warnings.warn( |
|
513 "'django.utils.translation.get_date_formats' is deprecated. " |
|
514 "Please update your code to use the new i18n aware formatting.", |
|
515 PendingDeprecationWarning |
|
516 ) |
|
517 from django.conf import settings |
|
518 date_format = ugettext('DATE_FORMAT') |
|
519 datetime_format = ugettext('DATETIME_FORMAT') |
|
520 time_format = ugettext('TIME_FORMAT') |
|
521 if date_format == 'DATE_FORMAT': |
|
522 date_format = settings.DATE_FORMAT |
|
523 if datetime_format == 'DATETIME_FORMAT': |
|
524 datetime_format = settings.DATETIME_FORMAT |
|
525 if time_format == 'TIME_FORMAT': |
|
526 time_format = settings.TIME_FORMAT |
|
527 return date_format, datetime_format, time_format |
|
528 |
|
529 def get_partial_date_formats(): |
|
530 """ |
|
531 Checks whether translation files provide a translation for some technical |
|
532 message ID to store partial date formats. If it doesn't contain one, the |
|
533 formats provided in the settings will be used. |
|
534 """ |
|
535 warnings.warn( |
|
536 "'django.utils.translation.get_partial_date_formats' is deprecated. " |
|
537 "Please update your code to use the new i18n aware formatting.", |
|
538 PendingDeprecationWarning |
|
539 ) |
|
540 from django.conf import settings |
|
541 year_month_format = ugettext('YEAR_MONTH_FORMAT') |
|
542 month_day_format = ugettext('MONTH_DAY_FORMAT') |
|
543 if year_month_format == 'YEAR_MONTH_FORMAT': |
|
544 year_month_format = settings.YEAR_MONTH_FORMAT |
|
545 if month_day_format == 'MONTH_DAY_FORMAT': |
|
546 month_day_format = settings.MONTH_DAY_FORMAT |
|
547 return year_month_format, month_day_format |
|
548 |