Code

Ticket #19160: 19160-4.diff

File 19160-4.diff, 6.8 KB (added by claudep, 19 months ago)

Aggregated patch

Line 
1diff --git a/django/utils/translation/__init__.py b/django/utils/translation/__init__.py
2index f3cc634..05440e5 100644
3--- a/django/utils/translation/__init__.py
4+++ b/django/utils/translation/__init__.py
5@@ -80,11 +80,43 @@ 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 key:
24+                number = rhs[key]
25+            else:
26+                number = rhs
27+            self._proxy____kw['number'] = number
28+            result = original_mod(self, rhs)
29+            del self._proxy____kw['number']
30+            return result
31+        key = number
32+        original_mod = getattr(proxy.__class__, '__mod__')
33+        setattr(proxy.__class__, '__mod__', mod)
34+    return proxy
35+
36+def ngettext_lazy(singular, plural, number=None):
37+    return lazy_number(
38+        ngettext, [str], singular=singular, plural=plural, number=number)
39+
40+def ungettext_lazy(singular, plural, number=None):
41+    return lazy_number(
42+        ungettext, [six.text_type], singular=singular, plural=plural, number=number)
43+
44+def npgettext_lazy(context, singular, plural, number=None):
45+    return lazy_number(
46+        npgettext, [six.text_type], context=context, singular=singular, plural=plural, number=number)
47+
48+
49 
50 def activate(language):
51     return _trans.activate(language)
52diff --git a/docs/topics/i18n/translation.txt b/docs/topics/i18n/translation.txt
53index 65c6fe2..ad7e9d4 100644
54--- a/docs/topics/i18n/translation.txt
55+++ b/docs/topics/i18n/translation.txt
56@@ -408,6 +408,33 @@ convert them to strings, because they should be converted as late as possible
57 (so that the correct locale is in effect). This necessitates the use of the
58 helper function described next.
59 
60+Lazy translations and plural
61+----------------------------
62+
63+.. versionadded:: 1.5
64+
65+When using lazy translation for a plural string (``[u]n[p]gettext_lazy``), you
66+generally don't know the ``number`` argument at the time of the string
67+definition. Therefore, you are authorized to pass a dictionary key name in place
68+of an integer as the ``number`` argument. Then, when the string is effectively
69+translated with a placeholders dictionary, the ``number`` argument will get
70+substituted by the value of the key in the dictionary. Alternatively, if the
71+string contains only one unnamed placeholder, you can also omit passing the
72+``number`` argument at all. For example::
73+
74+    class MyForm(forms.Form):
75+        error1_message = ungettext_lazy("You only provided %(num)d argument",
76+            "You only provided %(num)d arguments", 'num')
77+        error2_message = ungettext_lazy("You provided %d argument",
78+            "You provided %d arguments")
79+
80+        def clean(self):
81+            if err_1:
82+                raise forms.ValidationError(self.error1_message % {'num': number})
83+            if err_2:
84+                raise forms.ValidationError(self.error2_message % number)
85+
86+
87 Joining strings: string_concat()
88 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
89 
90diff --git a/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.mo b/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.mo
91index f825e39..b43f282 100644
92Binary files a/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.mo and b/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.mo differ
93diff --git a/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.po b/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.po
94index a471d38..e138bb0 100644
95--- a/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.po
96+++ b/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.po
97@@ -35,6 +35,18 @@ msgid "May"
98 msgstr "Kann"
99 
100 #: models.py:11
101+msgid "%d good result"
102+msgid_plural "%d good results"
103+msgstr[0] "%d gutes Resultat"
104+msgstr[1] "%d guten Resultate"
105+
106+#: models.py:11
107+msgid "Hi %(name)s, %(num)d good result"
108+msgid_plural "Hi %(name)s, %(num)d good results"
109+msgstr[0] "Hallo %(name)s, %(num)d gutes Resultat"
110+msgstr[1] "Hallo %(name)s, %(num)d guten Resultate"
111+
112+#: models.py:11
113 msgctxt "search"
114 msgid "%d result"
115 msgid_plural "%d results"
116@@ -75,4 +87,4 @@ msgstr "Es gibt %(num_comments)s Kommentare"
117 #: models.py:23
118 msgctxt "other comment count"
119 msgid "There are %(num_comments)s comments"
120-msgstr "Andere: Es gibt %(num_comments)s Kommentare"
121\ No newline at end of file
122+msgstr "Andere: Es gibt %(num_comments)s Kommentare"
123diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py
124index dcc288e..50654df 100644
125--- a/tests/regressiontests/i18n/tests.py
126+++ b/tests/regressiontests/i18n/tests.py
127@@ -23,7 +23,7 @@ from django.utils.safestring import mark_safe, SafeBytes, SafeString, SafeText
128 from django.utils import six
129 from django.utils.six import PY3
130 from django.utils.translation import (ugettext, ugettext_lazy, activate,
131-    deactivate, gettext_lazy, pgettext, npgettext, to_locale,
132+    deactivate, gettext_lazy, ungettext_lazy, pgettext, npgettext, to_locale,
133     get_language_info, get_language, get_language_from_request, trans_real)
134 
135 
136@@ -51,7 +51,6 @@ extended_locale_paths = settings.LOCALE_PATHS + (
137 )
138 
139 class TranslationTests(TestCase):
140-
141     def test_override(self):
142         activate('de')
143         with translation.override('pl'):
144@@ -95,6 +94,20 @@ class TranslationTests(TestCase):
145         self.assertEqual(six.text_type(s2), "test")
146 
147     @override_settings(LOCALE_PATHS=extended_locale_paths)
148+    def test_ungettext_lazy(self):
149+        s = ungettext_lazy("%d good result", "%d good result")
150+        with translation.override('de'):
151+            self.assertEqual(s % 1, "1 gutes Resultat")
152+            self.assertEqual(s % 4, "4 guten Resultate")
153+
154+        s1 = ungettext_lazy("Hi %(name)s, %(num)d good result", "Hi %(name)s, %(num)d good results", 4)
155+        s2 = ungettext_lazy("Hi %(name)s, %(num)d good result", "Hi %(name)s, %(num)d good results", 'num')
156+        with translation.override('de'):
157+            self.assertEqual(s1 % {'num': 4, 'name': 'Jim'}, "Hallo Jim, 4 guten Resultate")
158+            self.assertEqual(s2 % {'name': 'Jim', 'num': 1}, "Hallo Jim, 1 gutes Resultat")
159+            self.assertEqual(s2 % {'name': 'Jim', 'num': 5}, "Hallo Jim, 5 guten Resultate")
160+
161+    @override_settings(LOCALE_PATHS=extended_locale_paths)
162     def test_pgettext(self):
163         trans_real._active = local()
164         trans_real._translations = {}