Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions babel/messages/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -1000,6 +1000,8 @@ def _merge(
else:
oldmsg = remaining.pop(oldkey, None)
assert oldmsg is not None
if 'fuzzy' in oldmsg.flags:
message.previous_id = list(oldmsg.previous_id)
message.string = oldmsg.string

if keep_user_comments and oldmsg.user_comments:
Expand Down
29 changes: 23 additions & 6 deletions babel/messages/pofile.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ def _reset_message_state(self) -> None:
self.flags = []
self.user_comments = []
self.auto_comments = []
self.previous = []
self.context = None
self.obsolete = False
self.in_msgid = False
Expand Down Expand Up @@ -215,6 +216,7 @@ def _add_message(self) -> None:
self.user_comments,
lineno=self.offset + 1,
context=msgctxt,
previous_id=[p.denormalize() for p in self.previous],
)
if self.obsolete:
if not self.ignore_obsolete:
Expand Down Expand Up @@ -322,6 +324,17 @@ def _process_comment(self, line) -> None:
self.auto_comments.append(comment)
return

if prefix == '#|':
# The previous msgid of a fuzzy message (msgmerge --previous). Message has
# no field for a previous msgctxt, so that line is dropped.
content = line[2:].strip()
keyword, _, arg = content.partition(' ')
if keyword in ('msgid', 'msgid_plural'):
self.previous.append(_NormalizedString(arg))
elif content.startswith('"') and self.previous:
self.previous[-1].append(content)
return

# These are called user comments
self.user_comments.append(line[1:].strip())

Expand Down Expand Up @@ -644,6 +657,14 @@ def _format_comment(comment, prefix=''):
for line in comment_wrapper.wrap(comment):
yield f"#{prefix} {line.strip()}\n"

def _format_previous(keyword, value):
# One "#| " line per line of the normalized string, as msgmerge writes it;
# wrapping it like a comment would split the quoted strings.
first, *rest = normalize(value, width=width).splitlines()
yield f"#| {keyword} {first}\n"
for line in rest:
yield f"#| {line}\n"

def _format_conflict_comment(file, project, version, prefix=''):
comment = f"#-#-#-#-# {file} ({project} {version}) #-#-#-#-#"
yield f"{normalize(comment, prefix=prefix, width=width)}\n"
Expand Down Expand Up @@ -737,13 +758,9 @@ def _format_message(message, prefix=''):
yield f"#{', '.join(['', *sorted(message.flags)])}\n"

if message.previous_id and include_previous:
yield from _format_comment(
f'msgid {normalize(message.previous_id[0], width=width)}',
prefix='|',
)
yield from _format_previous('msgid', message.previous_id[0])
if len(message.previous_id) > 1:
norm_previous_id = normalize(message.previous_id[1], width=width)
yield from _format_comment(f'msgid_plural {norm_previous_id}', prefix='|')
yield from _format_previous('msgid_plural', message.previous_id[1])

if len(conflicts := catalog.get_conflicts(message.id)) > 0:
yield from _format_conflict(message.id, conflicts)
Expand Down
9 changes: 9 additions & 0 deletions tests/messages/test_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,15 @@ def test_catalog_update_fuzzy_matching_with_char_change():
assert cat['foo'].fuzzy is True


def test_catalog_update_keeps_previous_id_of_fuzzy_message():
cat = catalog.Catalog()
cat.add('foo', 'Voh', flags=['fuzzy'], previous_id='fo')
tmpl = catalog.Catalog()
tmpl.add('foo')
cat.update(tmpl)
assert cat['foo'].previous_id == ['fo']


def test_catalog_update_fuzzy_matching_no_msgstr():
cat = catalog.Catalog()
cat.add('fo', '')
Expand Down
24 changes: 24 additions & 0 deletions tests/messages/test_pofile.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,30 @@ def test_wrapped_comments_roundtrip(attribute):
assert second.getvalue() == first.getvalue()


def test_previous_msgid_roundtrip():
catalog = Catalog()
catalog.add('Save this file', 'Datei speichern', flags=['fuzzy'], previous_id='Save the file')
first = BytesIO()
pofile.write_po(first, catalog, omit_header=True, include_previous=True)
first.seek(0)

restored = pofile.read_po(first)
assert restored['Save this file'].previous_id == ['Save the file']
assert restored['Save this file'].user_comments == []


def test_long_previous_msgid_roundtrip():
previous = 'Save the file to the disk before closing the application window so nothing is lost'
catalog = Catalog()
catalog.add('Save this file', 'Datei speichern', flags=['fuzzy'], previous_id=previous)
first = BytesIO()
pofile.write_po(first, catalog, omit_header=True, include_previous=True)
first.seek(0)

restored = pofile.read_po(first)
assert restored['Save this file'].previous_id == [previous]


def test_enclosed_filenames_in_location_comment():
catalog = Catalog()
catalog.add("foo", lineno=2, locations=[("main 1.py", 1)], string="")
Expand Down
Loading