diff --git a/babel/messages/catalog.py b/babel/messages/catalog.py index 5e6c28255..c3ef7e621 100644 --- a/babel/messages/catalog.py +++ b/babel/messages/catalog.py @@ -973,7 +973,11 @@ def update( if msgid and messages[msgid].string: key = self._key_for(msgid) ctxt = messages[msgid].context - fuzzy_candidates[self._to_fuzzy_match_key(key)] = (key, ctxt) + # Several messages can share the same msgid when they + # differ only by context, so keep every candidate. + fuzzy_candidates.setdefault(self._to_fuzzy_match_key(key), []).append( + (key, ctxt) + ) fuzzy_matches = set() def _merge( @@ -1032,7 +1036,13 @@ def _merge( ) if matches: modified_key = matches[0] - newkey, newctxt = fuzzy_candidates[modified_key] + pairs = fuzzy_candidates[modified_key] + # Prefer the candidate whose context matches the + # template message, if there is one. + newkey, newctxt = next( + (pair for pair in pairs if pair[1] == message.context), + pairs[0], + ) if newctxt is not None: newkey = newkey, newctxt _merge(message, newkey, key) diff --git a/tests/messages/test_catalog.py b/tests/messages/test_catalog.py index 7c730d325..e20fbb216 100644 --- a/tests/messages/test_catalog.py +++ b/tests/messages/test_catalog.py @@ -510,6 +510,30 @@ def test_catalog_add(): assert cat['foo'] is foo +def test_catalog_update_fuzzy_matching_with_contexts(): + # Messages that share a msgid but differ by context must each keep + # their own translation when the msgid is renamed. + cat = catalog.Catalog(locale='de') + cat.add('Guide', 'NavFuehrer', context='navigation') + cat.add('Guide', 'MenuHilfe', context='menu') + + template = catalog.Catalog() + template.add('Guids', context='navigation') + template.add('Guids', context='menu') + + cat.update(template) + + nav = cat.get('Guids', context='navigation') + assert nav is not None + assert nav.string == 'NavFuehrer' + assert 'fuzzy' in nav.flags + + menu = cat.get('Guids', context='menu') + assert menu is not None + assert menu.string == 'MenuHilfe' + assert 'fuzzy' in menu.flags + + assert not cat.obsolete def test_catalog_update(): template = catalog.Catalog(header_comment="# A Custom Header") template.add('green', locations=[('main.py', 99)])