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
11 changes: 9 additions & 2 deletions babel/messages/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -579,8 +579,15 @@ def _set_mime_headers(self, headers: Iterable[tuple[str, str]]) -> None:
self.charset = params['charset'].lower()
elif name == 'plural-forms':
params = parse_separated_header(f" ;{value}")
self._num_plurals = int(params.get('nplurals', 2))
self._plural_expr = params.get('plural', '(n != 1)')
# nplurals/plural values may be left as the untranslated
# xgettext placeholders (e.g. in a fresh POT template);
# fall back to the defaults in that case instead of
# crashing on int(), mirroring the po-revision-date guard
# for the analogous 'YEAR' placeholder below.
num_plurals = params.get('nplurals', 2)
self._num_plurals = 2 if num_plurals == 'INTEGER' else int(num_plurals)
plural_expr = params.get('plural', '(n != 1)')
self._plural_expr = '(n != 1)' if plural_expr == 'EXPRESSION' else plural_expr
elif name == 'pot-creation-date':
self.creation_date = _parse_datetime_header(value)
elif name == 'po-revision-date':
Expand Down
16 changes: 16 additions & 0 deletions tests/messages/test_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,22 @@ def test_catalog_mime_headers_set_locale():
]


def test_catalog_mime_headers_xgettext_plural_forms_placeholder():
"""
A freshly-generated POT template from xgettext may leave the
Plural-Forms header with unexpanded placeholder tokens
(``nplurals=INTEGER; plural=EXPRESSION;``) instead of real values.
Parsing such a header should not raise, and should fall back to the
same defaults used elsewhere in the catalog.
"""
cat = catalog.Catalog()
cat.mime_headers = [
('Plural-Forms', 'nplurals=INTEGER; plural=EXPRESSION;'),
]
assert cat.num_plurals == 2
assert cat.plural_expr == '(n != 1)'


def test_catalog_mime_headers_type_coercion():
"""
Test that mime headers' keys and values are coerced to strings
Expand Down
14 changes: 14 additions & 0 deletions tests/messages/test_pofile.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,20 @@ def test_issue_1087():
assert pofile.read_po(buf).locale is None


def test_issue_1154():
# A freshly-generated POT template from xgettext may leave the
# Plural-Forms header with unexpanded placeholder tokens instead of
# real values; parsing it should not raise.
buf = StringIO(r'''
msgid ""
msgstr ""
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
''')
cat = pofile.read_po(buf)
assert cat.num_plurals == 2
assert cat.plural_expr == '(n != 1)'


@pytest.mark.parametrize("case", ['msgid "foo"', 'msgid "foo"\nmsgid_plural "foos"'])
@pytest.mark.parametrize("abort_invalid", [False, True])
def test_issue_1134(case: str, abort_invalid: bool):
Expand Down