changeset 422:38feb97d4934

Add support for `msgctxt`. See #54.
author palgarvio
date Thu, 18 Dec 2008 00:14:40 +0000
parents cadc2f937a78
children 322b257aeb3c
files babel/messages/mofile.py babel/support.py babel/tests/support.py
diffstat 3 files changed, 323 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/babel/messages/mofile.py
+++ b/babel/messages/mofile.py
@@ -186,7 +186,8 @@
             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'
--- a/babel/support.py
+++ b/babel/support.py
@@ -19,6 +19,7 @@
 
 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 @@
         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)
+
--- a/babel/tests/support.py
+++ b/babel/tests/support.py
@@ -12,13 +12,161 @@
 # 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__':
Copyright (C) 2012-2017 Edgewall Software