summaryrefslogtreecommitdiff
path: root/lib/python2.7/site-packages/django/utils/translation/__init__.py
blob: 10a6cd60fc24cb38e8a93c6627fcf413e8da2427 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
"""
Internationalization support.
"""
from __future__ import unicode_literals

from django.utils.encoding import force_text
from django.utils.functional import lazy
from django.utils import six


__all__ = [
    'activate', 'deactivate', 'override', 'deactivate_all',
    'get_language',  'get_language_from_request',
    'get_language_info', 'get_language_bidi',
    'check_for_language', 'to_locale', 'templatize', 'string_concat',
    'gettext', 'gettext_lazy', 'gettext_noop',
    'ugettext', 'ugettext_lazy', 'ugettext_noop',
    'ngettext', 'ngettext_lazy',
    'ungettext', 'ungettext_lazy',
    'pgettext', 'pgettext_lazy',
    'npgettext', 'npgettext_lazy',
]


class TranslatorCommentWarning(SyntaxWarning):
    pass


# Here be dragons, so a short explanation of the logic won't hurt:
# We are trying to solve two problems: (1) access settings, in particular
# settings.USE_I18N, as late as possible, so that modules can be imported
# without having to first configure Django, and (2) if some other code creates
# a reference to one of these functions, don't break that reference when we
# replace the functions with their real counterparts (once we do access the
# settings).

class Trans(object):
    """
    The purpose of this class is to store the actual translation function upon
    receiving the first call to that function. After this is done, changes to
    USE_I18N will have no effect to which function is served upon request. If
    your tests rely on changing USE_I18N, you can delete all the functions
    from _trans.__dict__.

    Note that storing the function with setattr will have a noticeable
    performance effect, as access to the function goes the normal path,
    instead of using __getattr__.
    """

    def __getattr__(self, real_name):
        from django.conf import settings
        if settings.USE_I18N:
            from django.utils.translation import trans_real as trans
        else:
            from django.utils.translation import trans_null as trans
        setattr(self, real_name, getattr(trans, real_name))
        return getattr(trans, real_name)

_trans = Trans()

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

def gettext_noop(message):
    return _trans.gettext_noop(message)

ugettext_noop = gettext_noop

def gettext(message):
    return _trans.gettext(message)

def ngettext(singular, plural, number):
    return _trans.ngettext(singular, plural, number)

def ugettext(message):
    return _trans.ugettext(message)

def ungettext(singular, plural, number):
    return _trans.ungettext(singular, plural, number)

def pgettext(context, message):
    return _trans.pgettext(context, message)

def npgettext(context, singular, plural, number):
    return _trans.npgettext(context, singular, plural, number)

gettext_lazy = lazy(gettext, str)
ugettext_lazy = lazy(ugettext, six.text_type)
pgettext_lazy = lazy(pgettext, six.text_type)

def lazy_number(func, resultclass, number=None, **kwargs):
    if isinstance(number, int):
        kwargs['number'] = number
        proxy = lazy(func, resultclass)(**kwargs)
    else:
        class NumberAwareString(resultclass):
            def __mod__(self, rhs):
                if isinstance(rhs, dict) and number:
                    try:
                        number_value = rhs[number]
                    except KeyError:
                        raise KeyError('Your dictionary lacks key \'%s\'. '
                            'Please provide it, because it is required to '
                            'determine whether string is singular or plural.'
                            % number)
                else:
                    number_value = rhs
                kwargs['number'] = number_value
                translated = func(**kwargs)
                try:
                    translated = translated % rhs
                except TypeError:
                    # String doesn't contain a placeholder for the number
                    pass
                return translated

        proxy = lazy(lambda **kwargs: NumberAwareString(), NumberAwareString)(**kwargs)
    return proxy

def ngettext_lazy(singular, plural, number=None):
    return lazy_number(ngettext, str, singular=singular, plural=plural, number=number)

def ungettext_lazy(singular, plural, number=None):
    return lazy_number(ungettext, six.text_type, singular=singular, plural=plural, number=number)

def npgettext_lazy(context, singular, plural, number=None):
    return lazy_number(npgettext, six.text_type, context=context, singular=singular, plural=plural, number=number)

def activate(language):
    return _trans.activate(language)

def deactivate():
    return _trans.deactivate()

class override(object):
    def __init__(self, language, deactivate=False):
        self.language = language
        self.deactivate = deactivate
        self.old_language = get_language()

    def __enter__(self):
        if self.language is not None:
            activate(self.language)
        else:
            deactivate_all()

    def __exit__(self, exc_type, exc_value, traceback):
        if self.deactivate:
            deactivate()
        else:
            activate(self.old_language)

def get_language():
    return _trans.get_language()

def get_language_bidi():
    return _trans.get_language_bidi()

def check_for_language(lang_code):
    return _trans.check_for_language(lang_code)

def to_locale(language):
    return _trans.to_locale(language)

def get_language_from_request(request, check_path=False):
    return _trans.get_language_from_request(request, check_path)

def get_language_from_path(path, supported=None):
    return _trans.get_language_from_path(path, supported=supported)

def templatize(src, origin=None):
    return _trans.templatize(src, origin)

def deactivate_all():
    return _trans.deactivate_all()

def _string_concat(*strings):
    """
    Lazy variant of string concatenation, needed for translations that are
    constructed from multiple parts.
    """
    return ''.join([force_text(s) for s in strings])
string_concat = lazy(_string_concat, six.text_type)

def get_language_info(lang_code):
    from django.conf.locale import LANG_INFO
    try:
        return LANG_INFO[lang_code]
    except KeyError:
        if '-' not in lang_code:
            raise KeyError("Unknown language code %s." % lang_code)
        generic_lang_code = lang_code.split('-')[0]
        try:
            return LANG_INFO[generic_lang_code]
        except KeyError:
            raise KeyError("Unknown language code %s and %s." % (lang_code, generic_lang_code))