summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Merickel <mmerickel@users.noreply.github.com>2016-12-12 11:07:33 -0600
committerGitHub <noreply@github.com>2016-12-12 11:07:33 -0600
commit58fd29d1922fd6420d696a7458a12b24d52edffc (patch)
tree595e3fb8f4ddfad2da0fef6df2f1e968bb024573
parent98b7bc973092cb92395ecfc50c097793d00e6551 (diff)
parentbff312df8c36ac3ef5389a89c7459b282f944f77 (diff)
downloadpyramid-58fd29d1922fd6420d696a7458a12b24d52edffc.tar.gz
pyramid-58fd29d1922fd6420d696a7458a12b24d52edffc.tar.bz2
pyramid-58fd29d1922fd6420d696a7458a12b24d52edffc.zip
Merge pull request #2859 from MatthewWilkes/i18n_plurals_in_default_domain
Fix pluralization in default domain for non-germanic languages
-rw-r--r--CHANGES.txt5
-rw-r--r--pyramid/i18n.py12
-rw-r--r--pyramid/tests/test_i18n.py30
3 files changed, 46 insertions, 1 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 11eab9f26..0a810a0d6 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -159,6 +159,11 @@ Bug Fixes
from previous orders have executed.
See https://github.com/Pylons/pyramid/pull/2757
+- Fix bug in i18n where the default domain would always use the Germanic plural
+ style, even if a different plural function is defined in the relevant messages
+ file.
+ See https://github.com/Pylons/pyramid/pull/2102
+
Deprecations
------------
diff --git a/pyramid/i18n.py b/pyramid/i18n.py
index 79209d342..1d11adfe3 100644
--- a/pyramid/i18n.py
+++ b/pyramid/i18n.py
@@ -22,6 +22,7 @@ from pyramid.threadlocal import get_current_registry
TranslationString = TranslationString # PyFlakes
TranslationStringFactory = TranslationStringFactory # PyFlakes
+DEFAULT_PLURAL = lambda n: int(n != 1)
class Localizer(object):
"""
@@ -233,7 +234,13 @@ class Translations(gettext.GNUTranslations, object):
# GNUTranslations._parse (called as a side effect if fileobj is
# passed to GNUTranslations.__init__) with a "real" self.plural for
# this domain; see https://github.com/Pylons/pyramid/issues/235
- self.plural = lambda n: int(n != 1)
+ # It is only overridden the first time a new message file is found
+ # for a given domain, so all message files must have matching plural
+ # rules if they are in the same domain. We keep track of if we have
+ # overridden so we can special case the default domain, which is always
+ # instantiated before a message file is read.
+ # See also https://github.com/Pylons/pyramid/pull/2102
+ self.plural = DEFAULT_PLURAL
gettext.GNUTranslations.__init__(self, fp=fileobj)
self.files = list(filter(None, [getattr(fileobj, 'name', None)]))
self.domain = domain
@@ -285,6 +292,9 @@ class Translations(gettext.GNUTranslations, object):
:rtype: `Translations`
"""
domain = getattr(translations, 'domain', self.DEFAULT_DOMAIN)
+ if domain == self.DEFAULT_DOMAIN and self.plural is DEFAULT_PLURAL:
+ self.plural = translations.plural
+
if merge and domain == self.domain:
return self.merge(translations)
diff --git a/pyramid/tests/test_i18n.py b/pyramid/tests/test_i18n.py
index 67b2ac356..d72d0d480 100644
--- a/pyramid/tests/test_i18n.py
+++ b/pyramid/tests/test_i18n.py
@@ -357,6 +357,36 @@ class TestTranslations(unittest.TestCase):
inst.add(inst2)
self.assertEqual(inst._catalog['a'], 'b')
+ def test_add_default_domain_replaces_plural_first_time(self):
+ # Create three empty message catalogs in the default domain
+ inst = self._getTargetClass()(None, domain='messages')
+ inst2 = self._getTargetClass()(None, domain='messages')
+ inst3 = self._getTargetClass()(None, domain='messages')
+ inst._catalog = {}
+ inst2._catalog = {}
+ inst3._catalog = {}
+
+ # The default plural scheme is the germanic one
+ self.assertEqual(inst.plural(0), 1)
+ self.assertEqual(inst.plural(1), 0)
+ self.assertEqual(inst.plural(2), 1)
+
+ # inst2 represents a message file that declares french plurals
+ inst2.plural = lambda n: n > 1
+ inst.add(inst2)
+ # that plural rule should now apply to inst
+ self.assertEqual(inst.plural(0), 0)
+ self.assertEqual(inst.plural(1), 0)
+ self.assertEqual(inst.plural(2), 1)
+
+ # We load a second message file with different plural rules
+ inst3.plural = lambda n: n > 0
+ inst.add(inst3)
+ # It doesn't override the previously loaded rule
+ self.assertEqual(inst.plural(0), 0)
+ self.assertEqual(inst.plural(1), 0)
+ self.assertEqual(inst.plural(2), 1)
+
def test_dgettext(self):
t = self._makeOne()
self.assertEqual(t.dgettext('messages', 'foo'), 'Voh')