8
7
import gettext as gettext_module
9
from cStringIO import StringIO
10
8
from threading import local
11
from cStringIO import StringIO
13
from StringIO import StringIO
12
15
from django.utils.importlib import import_module
13
16
from django.utils.safestring import mark_safe, SafeData
31
34
# Format of Accept-Language header values. From RFC 2616, section 14.4 and 3.9.
32
35
accept_language_re = re.compile(r'''
33
([A-Za-z]{1,8}(?:-[A-Za-z]{1,8})*|\*) # "en", "en-au", "x-y-z", "*"
34
(?:;q=(0(?:\.\d{,3})?|1(?:.0{,3})?))? # Optional "q=1.00", "q=0.8"
35
(?:\s*,\s*|$) # Multiple accepts per header.
36
([A-Za-z]{1,8}(?:-[A-Za-z]{1,8})*|\*) # "en", "en-au", "x-y-z", "*"
37
(?:\s*;\s*q=(0(?:\.\d{,3})?|1(?:.0{,3})?))? # Optional "q=1.00", "q=0.8"
38
(?:\s*,\s*|$) # Multiple accepts per header.
41
language_code_prefix_re = re.compile(r'^/([\w-]+)(/|$)')
38
43
def to_locale(language, to_lower=False):
40
45
Turns a language name (en-us) into a locale name (en_US). If 'to_lower' is
63
68
class DjangoTranslation(gettext_module.GNUTranslations):
65
70
This class sets up the GNUTranslations context with regard to output
66
charset. Django uses a defined DEFAULT_CHARSET as the output charset on
69
73
def __init__(self, *args, **kw):
70
74
gettext_module.GNUTranslations.__init__(self, *args, **kw)
71
# Starting with Python 2.4, there's a function to define
72
# the output charset. Before 2.4, the output charset is
73
# identical with the translation file charset.
75
self.set_output_charset('utf-8')
76
except AttributeError:
75
self.set_output_charset('utf-8')
78
76
self.django_output_charset = 'utf-8'
79
77
self.__language = '??'
193
191
language and installs it as the current translation object for the current
196
if isinstance(language, basestring) and language == 'no':
198
"The use of the language code 'no' is deprecated. "
199
"Please use the 'nb' translation instead.",
202
194
_active.value = translation(language)
204
196
def deactivate():
350
342
Checks whether there is a global language file for the given language
351
343
code. This is used to decide whether a user-provided language is
352
available. This is only used for language codes from either the cookies or
353
session and during format localization.
344
available. This is only used for language codes from either the cookies
345
or session and during format localization.
355
347
for path in all_locale_paths():
356
348
if gettext_module.find('django', path, [to_locale(lang_code)]) is not None:
360
def get_language_from_request(request):
352
def get_language_from_path(path, supported=None):
354
Returns the language-code if there is a valid language-code
357
if supported is None:
358
from django.conf import settings
359
supported = dict(settings.LANGUAGES)
360
regex_match = language_code_prefix_re.match(path)
362
lang_code = regex_match.group(1)
363
if lang_code in supported and check_for_language(lang_code):
366
def get_language_from_request(request, check_path=False):
362
368
Analyzes the request to find what language the user wants the system to
363
369
show. Only languages listed in settings.LANGUAGES are taken into account.
364
370
If the user requests a sublanguage where we have a main language, we send
365
371
out the main language.
373
If check_path is True, the URL path prefix will be checked for a language
374
code, otherwise this is skipped for backwards compatibility.
368
377
from django.conf import settings
369
378
supported = dict(settings.LANGUAGES)
381
lang_code = get_language_from_path(request.path_info, supported)
382
if lang_code is not None:
371
385
if hasattr(request, 'session'):
372
386
lang_code = request.session.get('django_language', None)
373
387
if lang_code in supported and lang_code is not None and check_for_language(lang_code):
424
438
return dot_re.sub(char, src)
426
inline_re = re.compile(r"""^\s*trans\s+((?:".*?")|(?:'.*?'))\s*""")
427
block_re = re.compile(r"""^\s*blocktrans(?:\s+|$)""")
440
context_re = re.compile(r"""^\s+.*context\s+((?:"[^"]*?")|(?:'[^']*?'))\s*""")
441
inline_re = re.compile(r"""^\s*trans\s+((?:"[^"]*?")|(?:'[^']*?'))(\s+.*context\s+(?:"[^"]*?")|(?:'[^']*?'))?\s*""")
442
block_re = re.compile(r"""^\s*blocktrans(\s+.*context\s+(?:"[^"]*?")|(?:'[^']*?'))?(?:\s+|$)""")
428
443
endblock_re = re.compile(r"""^\s*endblocktrans$""")
429
444
plural_re = re.compile(r"""^\s*plural$""")
430
445
constant_re = re.compile(r"""_\(((?:".*?")|(?:'.*?'))\)""")
446
one_percent_re = re.compile(r"""(?<!%)%(?!%)""")
432
449
def templatize(src, origin=None):
467
485
pluralmatch = plural_re.match(t.contents)
470
out.write(' ngettext(%r,%r,count) ' % (''.join(singular), ''.join(plural)))
489
out.write(' npgettext(%r, %r, %r,count) ' % (message_context, ''.join(singular), ''.join(plural)))
491
out.write(' ngettext(%r, %r, count) ' % (''.join(singular), ''.join(plural)))
471
492
for part in singular:
472
493
out.write(blankout(part, 'S'))
473
494
for part in plural:
474
495
out.write(blankout(part, 'P'))
476
out.write(' gettext(%r) ' % ''.join(singular))
498
out.write(' pgettext(%r, %r) ' % (message_context, ''.join(singular)))
500
out.write(' gettext(%r) ' % ''.join(singular))
477
501
for part in singular:
478
502
out.write(blankout(part, 'S'))
503
message_context = None
505
530
cmatches = constant_re.findall(t.contents)
507
532
g = imatch.group(1)
508
if g[0] == '"': g = g.strip('"')
509
elif g[0] == "'": g = g.strip("'")
510
out.write(' gettext(%r) ' % g)
537
g = one_percent_re.sub('%%', g)
539
# A context is provided
540
context_match = context_re.match(imatch.group(2))
541
message_context = context_match.group(1)
542
if message_context[0] == '"':
543
message_context = message_context.strip('"')
544
elif message_context[0] == "'":
545
message_context = message_context.strip("'")
546
out.write(' pgettext(%r, %r) ' % (message_context, g))
547
message_context = None
549
out.write(' gettext(%r) ' % g)
512
551
for fmatch in constant_re.findall(t.contents):
513
552
out.write(' _(%s) ' % fmatch)
554
# A context is provided
555
context_match = context_re.match(bmatch.group(1))
556
message_context = context_match.group(1)
557
if message_context[0] == '"':
558
message_context = message_context.strip('"')
559
elif message_context[0] == "'":
560
message_context = message_context.strip("'")
557
604
result.append((lang, priority))
558
605
result.sort(key=lambda k: k[1], reverse=True)
561
# get_date_formats and get_partial_date_formats aren't used anymore by Django
562
# and are kept for backward compatibility.
563
# Note, it's also important to keep format names marked for translation.
564
# For compatibility we still want to have formats on translation catalogs.
565
# That makes template code like {{ my_date|date:_('DATE_FORMAT') }} still work
566
def get_date_formats():
568
Checks whether translation files provide a translation for some technical
569
message ID to store date and time formats. If it doesn't contain one, the
570
formats provided in the settings will be used.
573
"'django.utils.translation.get_date_formats' is deprecated. "
574
"Please update your code to use the new i18n aware formatting.",
577
from django.conf import settings
578
date_format = ugettext('DATE_FORMAT')
579
datetime_format = ugettext('DATETIME_FORMAT')
580
time_format = ugettext('TIME_FORMAT')
581
if date_format == 'DATE_FORMAT':
582
date_format = settings.DATE_FORMAT
583
if datetime_format == 'DATETIME_FORMAT':
584
datetime_format = settings.DATETIME_FORMAT
585
if time_format == 'TIME_FORMAT':
586
time_format = settings.TIME_FORMAT
587
return date_format, datetime_format, time_format
589
def get_partial_date_formats():
591
Checks whether translation files provide a translation for some technical
592
message ID to store partial date formats. If it doesn't contain one, the
593
formats provided in the settings will be used.
596
"'django.utils.translation.get_partial_date_formats' is deprecated. "
597
"Please update your code to use the new i18n aware formatting.",
600
from django.conf import settings
601
year_month_format = ugettext('YEAR_MONTH_FORMAT')
602
month_day_format = ugettext('MONTH_DAY_FORMAT')
603
if year_month_format == 'YEAR_MONTH_FORMAT':
604
year_month_format = settings.YEAR_MONTH_FORMAT
605
if month_day_format == 'MONTH_DAY_FORMAT':
606
month_day_format = settings.MONTH_DAY_FORMAT
607
return year_month_format, month_day_format