1 | diff --git a/django/utils/translation/__init__.py b/django/utils/translation/__init__.py
|
---|
2 | index f3cc634..9333ba8 100644
|
---|
3 | --- a/django/utils/translation/__init__.py
|
---|
4 | +++ b/django/utils/translation/__init__.py
|
---|
5 | @@ -80,11 +80,42 @@ def npgettext(context, singular, plural, number):
|
---|
6 | return _trans.npgettext(context, singular, plural, number)
|
---|
7 |
|
---|
8 | gettext_lazy = lazy(gettext, str)
|
---|
9 | -ngettext_lazy = lazy(ngettext, str)
|
---|
10 | ugettext_lazy = lazy(ugettext, six.text_type)
|
---|
11 | -ungettext_lazy = lazy(ungettext, six.text_type)
|
---|
12 | pgettext_lazy = lazy(pgettext, six.text_type)
|
---|
13 | -npgettext_lazy = lazy(npgettext, six.text_type)
|
---|
14 | +
|
---|
15 | +
|
---|
16 | +def lazy_number(func, resultclasses, number=None, **kwargs):
|
---|
17 | + if isinstance(number, int):
|
---|
18 | + kwargs['number'] = number
|
---|
19 | + proxy = lazy(func, *resultclasses)(**kwargs)
|
---|
20 | + else:
|
---|
21 | + proxy = lazy(func, *resultclasses)(**kwargs)
|
---|
22 | + def mod(self, rhs):
|
---|
23 | + if isinstance(rhs, dict) and number:
|
---|
24 | + number_value = rhs[number]
|
---|
25 | + else:
|
---|
26 | + number_value = rhs
|
---|
27 | + self._proxy____kw['number'] = number_value
|
---|
28 | + result = original_mod(self, rhs)
|
---|
29 | + del self._proxy____kw['number']
|
---|
30 | + return result
|
---|
31 | + original_mod = getattr(proxy.__class__, '__mod__')
|
---|
32 | + setattr(proxy.__class__, '__mod__', mod)
|
---|
33 | + return proxy
|
---|
34 | +
|
---|
35 | +def ngettext_lazy(singular, plural, number=None):
|
---|
36 | + return lazy_number(
|
---|
37 | + ngettext, [str], singular=singular, plural=plural, number=number)
|
---|
38 | +
|
---|
39 | +def ungettext_lazy(singular, plural, number=None):
|
---|
40 | + return lazy_number(
|
---|
41 | + ungettext, [six.text_type], singular=singular, plural=plural, number=number)
|
---|
42 | +
|
---|
43 | +def npgettext_lazy(context, singular, plural, number=None):
|
---|
44 | + return lazy_number(
|
---|
45 | + npgettext, [six.text_type], context=context, singular=singular, plural=plural, number=number)
|
---|
46 | +
|
---|
47 | +
|
---|
48 |
|
---|
49 | def activate(language):
|
---|
50 | return _trans.activate(language)
|
---|
51 | diff --git a/docs/topics/i18n/translation.txt b/docs/topics/i18n/translation.txt
|
---|
52 | index 0b13ea1..82199ba 100644
|
---|
53 | --- a/docs/topics/i18n/translation.txt
|
---|
54 | +++ b/docs/topics/i18n/translation.txt
|
---|
55 | @@ -408,6 +408,33 @@ convert them to strings, because they should be converted as late as possible
|
---|
56 | (so that the correct locale is in effect). This necessitates the use of the
|
---|
57 | helper function described next.
|
---|
58 |
|
---|
59 | +Lazy translations and plural
|
---|
60 | +----------------------------
|
---|
61 | +
|
---|
62 | +.. versionadded:: 1.5
|
---|
63 | +
|
---|
64 | +When using lazy translation for a plural string (``[u]n[p]gettext_lazy``), you
|
---|
65 | +generally don't know the ``number`` argument at the time of the string
|
---|
66 | +definition. Therefore, you are authorized to pass a dictionary key name in place
|
---|
67 | +of an integer as the ``number`` argument. Then, when the string is effectively
|
---|
68 | +translated with a placeholders dictionary, the ``number`` argument will get
|
---|
69 | +substituted by the value of the key in the dictionary. Alternatively, if the
|
---|
70 | +string contains only one unnamed placeholder, you can also omit passing the
|
---|
71 | +``number`` argument at all. For example::
|
---|
72 | +
|
---|
73 | + class MyForm(forms.Form):
|
---|
74 | + error1_message = ungettext_lazy("You only provided %(num)d argument",
|
---|
75 | + "You only provided %(num)d arguments", 'num')
|
---|
76 | + error2_message = ungettext_lazy("You provided %d argument",
|
---|
77 | + "You provided %d arguments")
|
---|
78 | +
|
---|
79 | + def clean(self):
|
---|
80 | + if err_1:
|
---|
81 | + raise forms.ValidationError(self.error1_message % {'num': number})
|
---|
82 | + if err_2:
|
---|
83 | + raise forms.ValidationError(self.error2_message % number)
|
---|
84 | +
|
---|
85 | +
|
---|
86 | Joining strings: string_concat()
|
---|
87 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
---|
88 |
|
---|
89 | diff --git a/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.mo b/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.mo
|
---|
90 | index f825e3918b7fd74b7af37e55e704b260101367b7..b43f2824584826898add21d2c013063b1a869186 100644
|
---|
91 | GIT binary patch
|
---|
92 | delta 594
|
---|
93 | zcmajaJ4*vW5Ww-d<b1}Y&_;=dlO&L!AQqyH2paHgg7|1`<RFU%E{S*-EK_PBSOgn8
|
---|
94 | zEqv6ewDo%g5&RH>h5v~`42TZQ{q~mG+1ZEKUA)mAwJ(K8kdx#&IYxev8m=X>i5r;0
|
---|
95 | zD;&Z{T*YV9bNvw!8`C(CIn<texQJz3!)r|98!n49#EOaxvay2uG;>ieyr)|R-*Ey{
|
---|
96 | zeIi9%LLKB3b<kT(;}ddJ+Bk!+SinTT$T)7}0{Tcxxj{?TSrIxwj2s{tOh!n3r4~}x
|
---|
97 | z34P6QcdgLB6LG%L=9IPD$d;UgTCL<9o1pH8()$}o!3)h?Sgsgx%T6{|^(rPG%<8IM
|
---|
98 | z$@d=puON_}L({#-Iq?FT9GTXI^%BYGt@Y3Z&Q@m%?`sZrs^2@NS+$cz*Yo|_Z*%mX
|
---|
99 | O{;TXq%hs7aZG8e%lWzb3
|
---|
100 |
|
---|
101 | delta 327
|
---|
102 | zcmXBQyJ`YK7>410SI5&v@lbdQi-$(E5DT$N6)(WX%0etGEIbev(gZAnwOH6#32H6r
|
---|
103 | zLaref5Tb>b;05^p`oYIDyE{8GySwPYng1vKD<MzxnSRg&{iB+KCDOqnhVc#W^U%-r
|
---|
104 | z8XLI582(}lPxy*yTO^M?e8G1N;TQHTnad9Y-N0qFEKbqI1*UM1W&B1Tp0S1(Y-8Mr
|
---|
105 | zWUz}(oFI>6i=06MR5#S<eT{y|BP9`sQIP858s5AAjR<l!S<b8qt%lnJZ&>$6<KfZR
|
---|
106 | NS9|H2-0{;CtQ%0kA8G&q
|
---|
107 |
|
---|
108 | diff --git a/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.po b/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.po
|
---|
109 | index a471d38..e138bb0 100644
|
---|
110 | --- a/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.po
|
---|
111 | +++ b/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.po
|
---|
112 | @@ -35,6 +35,18 @@ msgid "May"
|
---|
113 | msgstr "Kann"
|
---|
114 |
|
---|
115 | #: models.py:11
|
---|
116 | +msgid "%d good result"
|
---|
117 | +msgid_plural "%d good results"
|
---|
118 | +msgstr[0] "%d gutes Resultat"
|
---|
119 | +msgstr[1] "%d guten Resultate"
|
---|
120 | +
|
---|
121 | +#: models.py:11
|
---|
122 | +msgid "Hi %(name)s, %(num)d good result"
|
---|
123 | +msgid_plural "Hi %(name)s, %(num)d good results"
|
---|
124 | +msgstr[0] "Hallo %(name)s, %(num)d gutes Resultat"
|
---|
125 | +msgstr[1] "Hallo %(name)s, %(num)d guten Resultate"
|
---|
126 | +
|
---|
127 | +#: models.py:11
|
---|
128 | msgctxt "search"
|
---|
129 | msgid "%d result"
|
---|
130 | msgid_plural "%d results"
|
---|
131 | @@ -75,4 +87,4 @@ msgstr "Es gibt %(num_comments)s Kommentare"
|
---|
132 | #: models.py:23
|
---|
133 | msgctxt "other comment count"
|
---|
134 | msgid "There are %(num_comments)s comments"
|
---|
135 | -msgstr "Andere: Es gibt %(num_comments)s Kommentare"
|
---|
136 | \ No newline at end of file
|
---|
137 | +msgstr "Andere: Es gibt %(num_comments)s Kommentare"
|
---|
138 | diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py
|
---|
139 | index 44d84f9..1aa7fd9 100644
|
---|
140 | --- a/tests/regressiontests/i18n/tests.py
|
---|
141 | +++ b/tests/regressiontests/i18n/tests.py
|
---|
142 | @@ -23,7 +23,7 @@ from django.utils.safestring import mark_safe, SafeBytes, SafeString, SafeText
|
---|
143 | from django.utils import six
|
---|
144 | from django.utils.six import PY3
|
---|
145 | from django.utils.translation import (ugettext, ugettext_lazy, activate,
|
---|
146 | - deactivate, gettext_lazy, pgettext, npgettext, to_locale,
|
---|
147 | + deactivate, gettext_lazy, ungettext_lazy, pgettext, npgettext, to_locale,
|
---|
148 | get_language_info, get_language, get_language_from_request, trans_real)
|
---|
149 |
|
---|
150 |
|
---|
151 | @@ -51,7 +51,6 @@ extended_locale_paths = settings.LOCALE_PATHS + (
|
---|
152 | )
|
---|
153 |
|
---|
154 | class TranslationTests(TestCase):
|
---|
155 | -
|
---|
156 | def test_override(self):
|
---|
157 | activate('de')
|
---|
158 | with translation.override('pl'):
|
---|
159 | @@ -95,6 +94,20 @@ class TranslationTests(TestCase):
|
---|
160 | self.assertEqual(six.text_type(s2), "test")
|
---|
161 |
|
---|
162 | @override_settings(LOCALE_PATHS=extended_locale_paths)
|
---|
163 | + def test_ungettext_lazy(self):
|
---|
164 | + s = ungettext_lazy("%d good result", "%d good result")
|
---|
165 | + with translation.override('de'):
|
---|
166 | + self.assertEqual(s % 1, "1 gutes Resultat")
|
---|
167 | + self.assertEqual(s % 4, "4 guten Resultate")
|
---|
168 | +
|
---|
169 | + s1 = ungettext_lazy("Hi %(name)s, %(num)d good result", "Hi %(name)s, %(num)d good results", 4)
|
---|
170 | + s2 = ungettext_lazy("Hi %(name)s, %(num)d good result", "Hi %(name)s, %(num)d good results", 'num')
|
---|
171 | + with translation.override('de'):
|
---|
172 | + self.assertEqual(s1 % {'num': 4, 'name': 'Jim'}, "Hallo Jim, 4 guten Resultate")
|
---|
173 | + self.assertEqual(s2 % {'name': 'Jim', 'num': 1}, "Hallo Jim, 1 gutes Resultat")
|
---|
174 | + self.assertEqual(s2 % {'name': 'Jim', 'num': 5}, "Hallo Jim, 5 guten Resultate")
|
---|
175 | +
|
---|
176 | + @override_settings(LOCALE_PATHS=extended_locale_paths)
|
---|
177 | def test_pgettext(self):
|
---|
178 | trans_real._active = local()
|
---|
179 | trans_real._translations = {}
|
---|
180 | --
|
---|
181 | 1.8.0.2
|
---|
182 |
|
---|