From bff312df8c36ac3ef5389a89c7459b282f944f77 Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Thu, 8 Dec 2016 15:00:29 +0100 Subject: Fix bug where plural rules would not be loaded for the default 'messages' domain. --- CHANGES.txt | 5 +++++ pyramid/i18n.py | 12 +++++++++++- pyramid/tests/test_i18n.py | 30 ++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index 65a1f15cd..2dc80c005 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -149,6 +149,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') -- cgit v1.2.3