~ubuntu-branches/ubuntu/saucy/python-django/saucy-updates

« back to all changes in this revision

Viewing changes to django/utils/translation/trans_real.py

  • Committer: Package Import Robot
  • Author(s): Raphaël Hertzog
  • Date: 2012-03-31 14:48:00 UTC
  • mfrom: (1.2.12)
  • mto: This revision was merged to the branch mainline in revision 38.
  • Revision ID: package-import@ubuntu.com-20120331144800-6a44u7d8z6pd2br4
Tags: upstream-1.4
Import upstream version 1.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
import os
5
5
import re
6
6
import sys
7
 
import warnings
8
7
import gettext as gettext_module
9
 
from cStringIO import StringIO
10
8
from threading import local
11
9
 
 
10
try:
 
11
    from cStringIO import StringIO
 
12
except ImportError:
 
13
    from StringIO import StringIO
 
14
 
12
15
from django.utils.importlib import import_module
13
16
from django.utils.safestring import mark_safe, SafeData
14
17
 
30
33
 
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.
36
39
        ''', re.VERBOSE)
37
40
 
 
41
language_code_prefix_re = re.compile(r'^/([\w-]+)(/|$)')
 
42
 
38
43
def to_locale(language, to_lower=False):
39
44
    """
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):
64
69
    """
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
67
 
    Python 2.4.
 
71
    charset.
68
72
    """
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.
74
 
        try:
75
 
            self.set_output_charset('utf-8')
76
 
        except AttributeError:
77
 
            pass
 
75
        self.set_output_charset('utf-8')
78
76
        self.django_output_charset = 'utf-8'
79
77
        self.__language = '??'
80
78
 
193
191
    language and installs it as the current translation object for the current
194
192
    thread.
195
193
    """
196
 
    if isinstance(language, basestring) and language == 'no':
197
 
        warnings.warn(
198
 
            "The use of the language code 'no' is deprecated. "
199
 
            "Please use the 'nb' translation instead.",
200
 
            DeprecationWarning
201
 
        )
202
194
    _active.value = translation(language)
203
195
 
204
196
def deactivate():
349
341
    """
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.
354
346
    """
355
347
    for path in all_locale_paths():
356
348
        if gettext_module.find('django', path, [to_locale(lang_code)]) is not None:
357
349
            return True
358
350
    return False
359
351
 
360
 
def get_language_from_request(request):
 
352
def get_language_from_path(path, supported=None):
 
353
    """
 
354
    Returns the language-code if there is a valid language-code
 
355
    found in the `path`.
 
356
    """
 
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)
 
361
    if regex_match:
 
362
        lang_code = regex_match.group(1)
 
363
        if lang_code in supported and check_for_language(lang_code):
 
364
            return lang_code
 
365
 
 
366
def get_language_from_request(request, check_path=False):
361
367
    """
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.
 
372
 
 
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.
366
375
    """
367
376
    global _accepted
368
377
    from django.conf import settings
369
378
    supported = dict(settings.LANGUAGES)
370
379
 
 
380
    if check_path:
 
381
        lang_code = get_language_from_path(request.path_info, supported)
 
382
        if lang_code is not None:
 
383
            return lang_code
 
384
 
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):
423
437
    """
424
438
    return dot_re.sub(char, src)
425
439
 
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"""(?<!%)%(?!%)""")
 
447
 
431
448
 
432
449
def templatize(src, origin=None):
433
450
    """
438
455
    from django.template import (Lexer, TOKEN_TEXT, TOKEN_VAR, TOKEN_BLOCK,
439
456
            TOKEN_COMMENT, TRANSLATOR_COMMENT_MARK)
440
457
    out = StringIO()
 
458
    message_context = None
441
459
    intrans = False
442
460
    inplural = False
443
461
    singular = []
467
485
                pluralmatch = plural_re.match(t.contents)
468
486
                if endbmatch:
469
487
                    if inplural:
470
 
                        out.write(' ngettext(%r,%r,count) ' % (''.join(singular), ''.join(plural)))
 
488
                        if message_context:
 
489
                            out.write(' npgettext(%r, %r, %r,count) ' % (message_context, ''.join(singular), ''.join(plural)))
 
490
                        else:
 
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'))
475
496
                    else:
476
 
                        out.write(' gettext(%r) ' % ''.join(singular))
 
497
                        if message_context:
 
498
                            out.write(' pgettext(%r, %r) ' % (message_context, ''.join(singular)))
 
499
                        else:
 
500
                            out.write(' gettext(%r) ' % ''.join(singular))
477
501
                        for part in singular:
478
502
                            out.write(blankout(part, 'S'))
 
503
                    message_context = None
479
504
                    intrans = False
480
505
                    inplural = False
481
506
                    singular = []
493
518
                else:
494
519
                    singular.append('%%(%s)s' % t.contents)
495
520
            elif t.token_type == TOKEN_TEXT:
496
 
                contents = t.contents.replace('%', '%%')
 
521
                contents = one_percent_re.sub('%%', t.contents)
497
522
                if inplural:
498
523
                    plural.append(contents)
499
524
                else:
505
530
                cmatches = constant_re.findall(t.contents)
506
531
                if imatch:
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)
 
533
                    if g[0] == '"':
 
534
                        g = g.strip('"')
 
535
                    elif g[0] == "'":
 
536
                        g = g.strip("'")
 
537
                    g = one_percent_re.sub('%%', g)
 
538
                    if imatch.group(2):
 
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
 
548
                    else:
 
549
                        out.write(' gettext(%r) ' % g)
511
550
                elif bmatch:
512
551
                    for fmatch in constant_re.findall(t.contents):
513
552
                        out.write(' _(%s) ' % fmatch)
 
553
                    if bmatch.group(1):
 
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("'")
514
561
                    intrans = True
515
562
                    inplural = False
516
563
                    singular = []
557
604
        result.append((lang, priority))
558
605
    result.sort(key=lambda k: k[1], reverse=True)
559
606
    return result
560
 
 
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():
567
 
    """
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.
571
 
    """
572
 
    warnings.warn(
573
 
        "'django.utils.translation.get_date_formats' is deprecated. "
574
 
        "Please update your code to use the new i18n aware formatting.",
575
 
        DeprecationWarning
576
 
    )
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
588
 
 
589
 
def get_partial_date_formats():
590
 
    """
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.
594
 
    """
595
 
    warnings.warn(
596
 
        "'django.utils.translation.get_partial_date_formats' is deprecated. "
597
 
        "Please update your code to use the new i18n aware formatting.",
598
 
        DeprecationWarning
599
 
    )
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