]> git.ipfire.org Git - thirdparty/babel.git/commitdiff
Add support for `msgctxt`. See #54.
authorPedro Algarvio <pedro@algarvio.me>
Thu, 18 Dec 2008 00:14:40 +0000 (00:14 +0000)
committerPedro Algarvio <pedro@algarvio.me>
Thu, 18 Dec 2008 00:14:40 +0000 (00:14 +0000)
babel/messages/mofile.py
babel/support.py
babel/tests/support.py

index 59384022dd836e6df1ca7218860a9a9bf3b071d0..168613c97e56e1dbb2d94e599ecba27db3c67afb 100644 (file)
@@ -186,7 +186,8 @@ def write_mo(fileobj, catalog, use_fuzzy=False):
             else:
                 msgstr = message.string.encode(catalog.charset)
         if message.context:
-            msgid = '\x04'.join(message.context.encode(catalog.charset), msgid)
+            msgid = '\x04'.join([message.context.encode(catalog.charset),
+                                 msgid])
         offsets.append((len(ids), len(msgid), len(strs), len(msgstr)))
         ids += msgid + '\x00'
         strs += msgstr + '\x00'
index ddc0894011522e9b01e62a8f601efca701c71615..20eac9160fb5d0f0244e0635e2782ad87c640d77 100644 (file)
@@ -19,6 +19,7 @@ in applications.
 
 from datetime import date, datetime, time, timedelta
 import gettext
+import locale
 
 from babel.core import Locale
 from babel.dates import format_date, format_datetime, format_time, \
@@ -404,3 +405,175 @@ class Translations(gettext.GNUTranslations, object):
         domain.
         """
         return self._domains.get(domain, self).ungettext(singular, plural, num)
+
+    # Most of the downwards code, until it get's included in stdlib, from:
+    #    http://bugs.python.org/file10036/gettext-pgettext.patch
+    #    
+    # The encoding of a msgctxt and a msgid in a .mo file is
+    # msgctxt + "\x04" + msgid (gettext version >= 0.15)
+    CONTEXT_ENCODING = '%s\x04%s'
+
+    def pgettext(self, context, message):
+        """Look up the `context` and `message` id in the catalog and return the
+        corresponding message string, as an 8-bit string encoded with the
+        catalog's charset encoding, if known.  If there is no entry in the
+        catalog for the `message` id and `context` , and a fallback has been
+        set, the look up is forwarded to the fallback's ``pgettext()``
+        method. Otherwise, the `message` id is returned.
+        """
+        ctxt_msg_id = self.CONTEXT_ENCODING % (context, message)
+        missing = object()
+        tmsg = self._catalog.get(ctxt_msg_id, missing)
+        if tmsg is missing:
+            if self._fallback:
+                return self._fallback.pgettext(context, message)
+            return message
+        # Encode the Unicode tmsg back to an 8-bit string, if possible
+        if self._output_charset:
+            return tmsg.encode(self._output_charset)
+        elif self._charset:
+            return tmsg.encode(self._charset)
+        return tmsg
+
+    def lpgettext(self, context, message):
+        """Equivalent to ``pgettext()``, but the translation is returned in the
+        preferred system encoding, if no other encoding was explicitly set with
+        ``bind_textdomain_codeset()``.
+        """
+        ctxt_msg_id = self.CONTEXT_ENCODING % (context, message)
+        missing = object()
+        tmsg = self._catalog.get(ctxt_msg_id, missing)
+        if tmsg is missing:
+            if self._fallback:
+                return self._fallback.lpgettext(context, message)
+            return message
+        if self._output_charset:
+            return tmsg.encode(self._output_charset)
+        return tmsg.encode(locale.getpreferredencoding())
+
+    def npgettext(self, context, singular, plural, num):
+        """Do a plural-forms lookup of a message id.  `singular` is used as the
+        message id for purposes of lookup in the catalog, while `num` is used to
+        determine which plural form to use.  The returned message string is an
+        8-bit string encoded with the catalog's charset encoding, if known.
+        
+        If the message id for `context` is not found in the catalog, and a
+        fallback is specified, the request is forwarded to the fallback's
+        ``npgettext()`` method.  Otherwise, when ``num`` is 1 ``singular`` is
+        returned, and ``plural`` is returned in all other cases.
+        """
+        ctxt_msg_id = self.CONTEXT_ENCODING % (context, singular)
+        try:
+            tmsg = self._catalog[(ctxt_msg_id, self.plural(num))]
+            if self._output_charset:
+                return tmsg.encode(self._output_charset)
+            elif self._charset:
+                return tmsg.encode(self._charset)
+            return tmsg
+        except KeyError:
+            if self._fallback:
+                return self._fallback.npgettext(context, singular, plural, num)
+            if num == 1:
+                return singular
+            else:
+                return plural
+
+    def lnpgettext(self, context, singular, plural, num):
+        """Equivalent to ``npgettext()``, but the translation is returned in the
+        preferred system encoding, if no other encoding was explicitly set with
+        ``bind_textdomain_codeset()``.
+        """
+        ctxt_msg_id = self.CONTEXT_ENCODING % (context, singular)
+        try:
+            tmsg = self._catalog[(ctxt_msg_id, self.plural(num))]
+            if self._output_charset:
+                return tmsg.encode(self._output_charset)
+            return tmsg.encode(locale.getpreferredencoding())
+        except KeyError:
+            if self._fallback:
+                return self._fallback.lnpgettext(context, singular, plural, num)
+            if num == 1:
+                return singular
+            else:
+                return plural
+
+    def upgettext(self, context, message):
+        """Look up the `context` and `message` id in the catalog and return the
+        corresponding message string, as a Unicode string.  If there is no entry
+        in the catalog for the `message` id and `context`, and a fallback has
+        been set, the look up is forwarded to the fallback's ``upgettext()``
+        method.  Otherwise, the `message` id is returned.
+        """
+        ctxt_message_id = self.CONTEXT_ENCODING % (context, message)
+        missing = object()
+        tmsg = self._catalog.get(ctxt_message_id, missing)
+        if tmsg is missing:
+            if self._fallback:
+                return self._fallback.upgettext(context, message)
+            return unicode(message)
+        return tmsg
+
+    def unpgettext(self, context, singular, plural, num):
+        """Do a plural-forms lookup of a message id.  `singular` is used as the
+        message id for purposes of lookup in the catalog, while `num` is used to
+        determine which plural form to use.  The returned message string is a
+        Unicode string.
+        
+        If the message id for `context` is not found in the catalog, and a
+        fallback is specified, the request is forwarded to the fallback's
+        ``unpgettext()`` method.  Otherwise, when `num` is 1 `singular` is
+        returned, and `plural` is returned in all other cases.
+        """
+        ctxt_message_id = self.CONTEXT_ENCODING % (context, singular)
+        try:
+            tmsg = self._catalog[(ctxt_message_id, self.plural(num))]
+        except KeyError:
+            if self._fallback:
+                return self._fallback.unpgettext(context, singular, plural, num)
+            if num == 1:
+                tmsg = unicode(singular)
+            else:
+                tmsg = unicode(plural)
+        return tmsg
+
+    def dpgettext(self, domain, context, message):
+        """Like `pgettext()`, but look the message up in the specified
+        `domain`.
+        """
+        return self._domains.get(domain, self).pgettext(context, message)
+    
+    def dupgettext(self, domain, context, message):
+        """Like `upgettext()`, but look the message up in the specified
+        `domain`.
+        """
+        return self._domains.get(domain, self).upgettext(context, message)
+
+    def ldpgettext(self, domain, context, message):
+        """Equivalent to ``dpgettext()``, but the translation is returned in the
+        preferred system encoding, if no other encoding was explicitly set with
+        ``bind_textdomain_codeset()``.
+        """
+        return self._domains.get(domain, self).lpgettext(context, message)
+
+    def dnpgettext(self, domain, context, singular, plural, num):
+        """Like ``npgettext``, but look the message up in the specified
+        `domain`.
+        """
+        return self._domains.get(domain, self).npgettext(context, singular,
+                                                         plural, num)
+        
+    def dunpgettext(self, domain, context, singular, plural, num):
+        """Like ``unpgettext``, but look the message up in the specified
+        `domain`.
+        """
+        return self._domains.get(domain, self).unpgettext(context, singular,
+                                                          plural, num)
+
+    def ldnpgettext(self, domain, context, singular, plural, num):
+        """Equivalent to ``dnpgettext()``, but the translation is returned in
+        the preferred system encoding, if no other encoding was explicitly set
+        with ``bind_textdomain_codeset()``.
+        """
+        return self._domains.get(domain, self).lnpgettext(context, singular,
+                                                          plural, num)
+
index 215e8dd31ba57f5acfefcb550fa63355ef797fc8..00a1a0eb1f5e01768160f19a1cc4718d76969eec 100644 (file)
 # history and logs, available at http://babel.edgewall.org/log/.
 
 import doctest
+import os
+from StringIO import StringIO
 import unittest
 
 from babel import support
+from babel.messages import Catalog
+from babel.messages.mofile import write_mo
+
+class TranslationsTestCase(unittest.TestCase):
+    
+    def setUp(self):
+        # Use a locale which won't fail to run the tests
+        os.environ['LANG'] = 'en_US.UTF-8'
+        messages1 = [
+            ('foo', {'string': 'Voh'}),
+            ('foo', {'string': 'VohCTX', 'context': 'foo'}),
+            (('foo1', 'foos1'), {'string': ('Voh1', 'Vohs1')}),
+            (('foo1', 'foos1'), {'string': ('VohCTX1', 'VohsCTX1'), 'context': 'foo'}),
+        ]
+        messages2 = [
+            ('foo', {'string': 'VohD'}),
+            ('foo', {'string': 'VohCTXD', 'context': 'foo'}),
+            (('foo1', 'foos1'), {'string': ('VohD1', 'VohsD1')}),
+            (('foo1', 'foos1'), {'string': ('VohCTXD1', 'VohsCTXD1'), 'context': 'foo'}),
+        ]
+        catalog1 = Catalog(locale='en_GB', domain='messages')
+        catalog2 = Catalog(locale='en_GB', domain='messages1')
+        for ids, kwargs in messages1:
+            catalog1.add(ids, **kwargs)            
+        for ids, kwargs in messages2:
+            catalog2.add(ids, **kwargs)
+        catalog1_fp = StringIO()
+        catalog2_fp = StringIO()
+        write_mo(catalog1_fp, catalog1)
+        catalog1_fp.seek(0)
+        write_mo(catalog2_fp, catalog2)
+        catalog2_fp.seek(0)
+        translations1 = support.Translations(catalog1_fp)
+        translations2 = support.Translations(catalog2_fp, domain='messages1')
+        self.translations = translations1.add(translations2, merge=False)
+
+    def assertEqualTypeToo(self, expected, result):
+        self.assertEqual(expected, result)
+        assert type(expected) == type(result), "instance type's do not " + \
+            "match: %r!=%r" % (type(expected), type(result))
+
+    def test_pgettext(self):
+        self.assertEqualTypeToo('Voh', self.translations.gettext('foo'))
+        self.assertEqualTypeToo('VohCTX', self.translations.pgettext('foo',
+                                                                     'foo'))
+
+    def test_upgettext(self):
+        self.assertEqualTypeToo(u'Voh', self.translations.ugettext('foo'))
+        self.assertEqualTypeToo(u'VohCTX', self.translations.upgettext('foo',
+                                                                       'foo'))
+
+    def test_lpgettext(self):
+        self.assertEqualTypeToo('Voh', self.translations.lgettext('foo'))
+        self.assertEqualTypeToo('VohCTX', self.translations.lpgettext('foo',
+                                                                      'foo'))
+
+    def test_npgettext(self):
+        self.assertEqualTypeToo('Voh1',
+                                self.translations.ngettext('foo1', 'foos1', 1))
+        self.assertEqualTypeToo('Vohs1',
+                                self.translations.ngettext('foo1', 'foos1', 2))
+        self.assertEqualTypeToo('VohCTX1',
+                                self.translations.npgettext('foo', 'foo1',
+                                                            'foos1', 1))
+        self.assertEqualTypeToo('VohsCTX1',
+                                self.translations.npgettext('foo', 'foo1',
+                                                            'foos1', 2))
+
+    def test_unpgettext(self):
+        self.assertEqualTypeToo(u'Voh1',
+                                self.translations.ungettext('foo1', 'foos1', 1))
+        self.assertEqualTypeToo(u'Vohs1',
+                                self.translations.ungettext('foo1', 'foos1', 2))
+        self.assertEqualTypeToo(u'VohCTX1',
+                                self.translations.unpgettext('foo', 'foo1',
+                                                             'foos1', 1))
+        self.assertEqualTypeToo(u'VohsCTX1',
+                                self.translations.unpgettext('foo', 'foo1',
+                                                             'foos1', 2))
+
+    def test_lnpgettext(self):
+        self.assertEqualTypeToo('Voh1',
+                                self.translations.lngettext('foo1', 'foos1', 1))
+        self.assertEqualTypeToo('Vohs1',
+                                self.translations.lngettext('foo1', 'foos1', 2))
+        self.assertEqualTypeToo('VohCTX1',
+                                self.translations.lnpgettext('foo', 'foo1',
+                                                             'foos1', 1))
+        self.assertEqualTypeToo('VohsCTX1',
+                                self.translations.lnpgettext('foo', 'foo1',
+                                                             'foos1', 2))
+
+    def test_dpgettext(self):
+        self.assertEqualTypeToo(
+            'VohD', self.translations.dgettext('messages1', 'foo'))
+        self.assertEqualTypeToo(
+            'VohCTXD', self.translations.dpgettext('messages1', 'foo', 'foo'))
+
+    def test_dupgettext(self):
+        self.assertEqualTypeToo(
+            u'VohD', self.translations.dugettext('messages1', 'foo'))
+        self.assertEqualTypeToo(
+            u'VohCTXD', self.translations.dupgettext('messages1', 'foo', 'foo'))
+
+    def test_ldpgettext(self):
+        self.assertEqualTypeToo(
+            'VohD', self.translations.ldgettext('messages1', 'foo'))
+        self.assertEqualTypeToo(
+            'VohCTXD', self.translations.ldpgettext('messages1', 'foo', 'foo'))
+
+    def test_dnpgettext(self):
+        self.assertEqualTypeToo(
+            'VohD1', self.translations.dngettext('messages1', 'foo1', 'foos1', 1))
+        self.assertEqualTypeToo(
+            'VohsD1', self.translations.dngettext('messages1', 'foo1', 'foos1', 2))
+        self.assertEqualTypeToo(
+            'VohCTXD1', self.translations.dnpgettext('messages1', 'foo', 'foo1',
+                                                     'foos1', 1))
+        self.assertEqualTypeToo(
+            'VohsCTXD1', self.translations.dnpgettext('messages1', 'foo', 'foo1',
+                                                      'foos1', 2))
+
+    def test_dunpgettext(self):
+        self.assertEqualTypeToo(
+            u'VohD1', self.translations.dungettext('messages1', 'foo1', 'foos1', 1))
+        self.assertEqualTypeToo(
+            u'VohsD1', self.translations.dungettext('messages1', 'foo1', 'foos1', 2))
+        self.assertEqualTypeToo(
+            u'VohCTXD1', self.translations.dunpgettext('messages1', 'foo', 'foo1',
+                                                       'foos1', 1))
+        self.assertEqualTypeToo(
+            u'VohsCTXD1', self.translations.dunpgettext('messages1', 'foo', 'foo1',
+                                                        'foos1', 2))
+
+    def test_ldnpgettext(self):
+        self.assertEqualTypeToo(
+            'VohD1', self.translations.ldngettext('messages1', 'foo1', 'foos1', 1))
+        self.assertEqualTypeToo(
+            'VohsD1', self.translations.ldngettext('messages1', 'foo1', 'foos1', 2))
+        self.assertEqualTypeToo(
+            'VohCTXD1', self.translations.ldnpgettext('messages1', 'foo', 'foo1',
+                                                      'foos1', 1))
+        self.assertEqualTypeToo(
+            'VohsCTXD1', self.translations.ldnpgettext('messages1', 'foo', 'foo1',
+                                                       'foos1', 2))
 
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(doctest.DocTestSuite(support))
+    suite.addTest(unittest.makeSuite(TranslationsTestCase, 'test'))
     return suite
 
 if __name__ == '__main__':