changeset 350:9166eab61e29 trunk

More work on msgctxt support (#54).
author cmlenz
date Mon, 16 Jun 2008 16:49:56 +0000
parents 76bfb34282af
children 0d287b3c935e
files babel/messages/catalog.py babel/messages/tests/catalog.py babel/messages/tests/pofile.py
diffstat 3 files changed, 79 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/babel/messages/catalog.py
+++ b/babel/messages/catalog.py
@@ -470,19 +470,17 @@
 
     def __delitem__(self, id):
         """Delete the message with the specified ID."""
-        key = self._key_for(id)
-        if key in self._messages:
-            del self._messages[key]
+        self.delete(id)
 
     def __getitem__(self, id):
         """Return the message with the specified ID.
 
         :param id: the message ID
-        :return: the message with the specified ID, or `None` if no such message
-                 is in the catalog
+        :return: the message with the specified ID, or `None` if no such
+                 message is in the catalog
         :rtype: `Message`
         """
-        return self._messages.get(self._key_for(id))
+        return self.get(id)
 
     def __setitem__(self, id, message):
         """Add or update the message with the specified ID.
@@ -507,7 +505,7 @@
         :param message: the `Message` object
         """
         assert isinstance(message, Message), 'expected a Message object'
-        key = self._key_for(id)
+        key = self._key_for(id, message.context)
         current = self._messages.get(key)
         if current:
             if message.pluralizable and not current.pluralizable:
@@ -595,6 +593,27 @@
                 if errors:
                     yield message, errors
 
+    def get(self, id, context=None):
+        """Return the message with the specified ID and context.
+
+        :param id: the message ID
+        :param context: the message context, or ``None`` for no context
+        :return: the message with the specified ID, or `None` if no such
+                 message is in the catalog
+        :rtype: `Message`
+        """
+        return self._messages.get(self._key_for(id, context))
+
+    def delete(self, id, context=None):
+        """Delete the message with the specified ID and context.
+        
+        :param id: the message ID
+        :param context: the message context, or ``None`` for no context
+        """
+        key = self._key_for(id, context)
+        if key in self._messages:
+            del self._messages[key]
+
     def update(self, template, no_fuzzy_matching=False):
         """Update the catalog based on the given template catalog.
 
@@ -649,10 +668,10 @@
         # Prepare for fuzzy matching
         fuzzy_candidates = []
         if not no_fuzzy_matching:
-            fuzzy_candidates = [
-                self._key_for(msgid) for msgid in messages
-                if msgid and messages[msgid].string
-            ]
+            fuzzy_candidates = dict([
+                (self._key_for(msgid), messages[msgid].context)
+                for msgid in messages if msgid and messages[msgid].string
+            ])
         fuzzy_matches = set()
 
         def _merge(message, oldkey, newkey):
@@ -688,16 +707,24 @@
 
         for message in template:
             if message.id:
-                key = self._key_for(message.id)
+                key = self._key_for(message.id, message.context)
                 if key in messages:
                     _merge(message, key, key)
                 else:
                     if no_fuzzy_matching is False:
                         # do some fuzzy matching with difflib
-                        matches = get_close_matches(key.lower().strip(),
-                                                    fuzzy_candidates, 1)
+                        if isinstance(key, tuple):
+                            matchkey = key[0] # just the msgid, no context
+                        else:
+                            matchkey = key
+                        matches = get_close_matches(matchkey.lower().strip(),
+                                                    fuzzy_candidates.keys(), 1)
                         if matches:
-                            _merge(message, matches[0], key)
+                            newkey = matches[0]
+                            newctxt = fuzzy_candidates[newkey]
+                            if newctxt is not None:
+                                newkey = newkey, newctxt
+                            _merge(message, newkey, key)
                             continue
 
                     self[message.id] = message
@@ -707,11 +734,14 @@
             if no_fuzzy_matching or msgid not in fuzzy_matches:
                 self.obsolete[msgid] = remaining[msgid]
 
-    def _key_for(self, id):
+    def _key_for(self, id, context=None):
         """The key for a message is just the singular ID even for pluralizable
+        messages, but is a ``(msgid, msgctxt)`` tuple for context-specific
         messages.
         """
         key = id
         if isinstance(key, (list, tuple)):
             key = id[0]
+        if context is not None:
+            key = (key, context)
         return key
--- a/babel/messages/tests/catalog.py
+++ b/babel/messages/tests/catalog.py
@@ -146,6 +146,36 @@
         self.assertEqual(None, cat['foo'].string)
         self.assertEqual(False, cat['foo'].fuzzy)
 
+    def test_update_fuzzy_matching_with_new_context(self):
+        cat = catalog.Catalog()
+        cat.add('foo', 'Voh')
+        cat.add('bar', 'Bahr')
+        tmpl = catalog.Catalog()
+        tmpl.add('Foo', context='Menu')
+        cat.update(tmpl)
+        self.assertEqual(1, len(cat.obsolete))
+        assert 'foo' not in cat
+
+        message = cat.get('Foo', 'Menu')
+        self.assertEqual('Voh', message.string)
+        self.assertEqual(True, message.fuzzy)
+        self.assertEqual('Menu', message.context)
+
+    def test_update_fuzzy_matching_with_changed_context(self):
+        cat = catalog.Catalog()
+        cat.add('foo', 'Voh', context='Menu|File')
+        cat.add('bar', 'Bahr', context='Menu|File')
+        tmpl = catalog.Catalog()
+        tmpl.add('Foo', context='Menu|Edit')
+        cat.update(tmpl)
+        self.assertEqual(1, len(cat.obsolete))
+        assert cat.get('Foo', 'Menu|File') is None
+
+        message = cat.get('Foo', 'Menu|Edit')
+        self.assertEqual('Voh', message.string)
+        self.assertEqual(True, message.fuzzy)
+        self.assertEqual('Menu|Edit', message.context)
+
     def test_update_fuzzy_matching_no_cascading(self):
         cat = catalog.Catalog()
         cat.add('fo', 'Voh')
@@ -186,6 +216,7 @@
         self.assertEqual(None, cat2['foo'].string)
         self.assertEqual(False, cat2['foo'].fuzzy)
 
+
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(doctest.DocTestSuite(catalog, optionflags=doctest.ELLIPSIS))
--- a/babel/messages/tests/pofile.py
+++ b/babel/messages/tests/pofile.py
@@ -158,9 +158,9 @@
 ''')
         catalog = pofile.read_po(buf, ignore_obsolete=True)
         self.assertEqual(2, len(catalog))
-        message = catalog['foo']
+        message = catalog.get('foo', context='Menu')
         self.assertEqual('Menu', message.context)
-        message = catalog['bar']
+        message = catalog.get('bar', context='Menu')
         self.assertEqual('Menu', message.context)
 
 
Copyright (C) 2012-2017 Edgewall Software