diff --git a/babel/messages/catalog.py b/babel/messages/catalog.py index f84a5bd1b..856ccbc6f 100644 --- a/babel/messages/catalog.py +++ b/babel/messages/catalog.py @@ -398,8 +398,9 @@ def __init__( # Dictionary of obsolete messages self.obsolete: dict[str | tuple[str, str], Message] = {} - self._num_plurals = None - self._plural_expr = None + + self._num_plurals: str | int | None = None + self._plural_expr: str | None = None def _set_locale(self, locale: Locale | str | None) -> None: if locale is None: @@ -538,7 +539,8 @@ 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)) + nplurals = params.get('nplurals') + self._num_plurals = int(nplurals, 10) if nplurals.isdigit() else nplurals self._plural_expr = params.get('plural', '(n != 1)') elif name == 'pot-creation-date': self.creation_date = _parse_datetime_header(value) @@ -600,20 +602,21 @@ def _set_mime_headers(self, headers: Iterable[tuple[str, str]]) -> None: """) @property - def num_plurals(self) -> int: + def num_plurals(self) -> int | str: """The number of plurals used by the catalog or locale. + If read from a catalog template, this may be a string. + >>> Catalog(locale='en').num_plurals 2 >>> Catalog(locale='ga').num_plurals 5 - - :type: `int`""" + """ if self._num_plurals is None: num = 2 if self.locale: num = get_plural(self.locale)[0] - self._num_plurals = num + return num return self._num_plurals @property @@ -632,7 +635,7 @@ def plural_expr(self) -> str: expr = '(n != 1)' if self.locale: expr = get_plural(self.locale)[1] - self._plural_expr = expr + return expr return self._plural_expr @property diff --git a/tests/messages/test_pofile.py b/tests/messages/test_pofile.py index 2bcc3df8d..f8eabfad1 100644 --- a/tests/messages/test_pofile.py +++ b/tests/messages/test_pofile.py @@ -1096,3 +1096,17 @@ def test_issue_1134(case: str, abort_invalid: bool): output = pofile.read_po(buf) assert len(output) == 1 assert output["foo"].string in ((''), ('', '')) + + +def test_issue_1154(): + # Via `echo 'ngettext("Hello World!", "Hello Worlds!", 3);' | xgettext --output=- - --language=C`, + # minimized for reproducing the issue. + template = """ +msgid "" +msgstr "" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + """.strip() + cat = pofile.read_po(StringIO(template)) + assert cat.num_plurals == "INTEGER" + assert cat.plural_expr == "EXPRESSION" + assert cat.plural_forms == "nplurals=INTEGER; plural=EXPRESSION;"