| 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 |
|
|---|