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
6 changes: 5 additions & 1 deletion babel/messages/checkers.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,11 @@ def python_format(catalog: Catalog | None, message: Message) -> None:
msgstrs = (msgstrs,)

if msgstrs[0]:
_validate_format(msgids[0], msgstrs[0])
msgid = msgids[0]
# A single plural form must also support the plural source's placeholders.
if message.pluralizable and catalog is not None and catalog.num_plurals == 1:
msgid = msgids[1]
_validate_format(msgid, msgstrs[0])
if message.pluralizable:
for msgstr in msgstrs[1:]:
if msgstr:
Expand Down
33 changes: 32 additions & 1 deletion tests/messages/test_checkers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from babel.core import Locale, UnknownLocaleError
from babel.dates import format_datetime
from babel.messages import Message, checkers
from babel.messages.catalog import TranslationError
from babel.messages.catalog import Catalog, TranslationError
from babel.messages.checkers import _validate_format, python_format
from babel.messages.plurals import PLURALS
from babel.messages.pofile import read_po
Expand Down Expand Up @@ -416,3 +416,34 @@ def test__validate_format_invalid(msgid, msgstr, error):
)
def test__validate_format_valid(msgid, msgstr):
_validate_format(msgid, msgstr)


@pytest.mark.parametrize('locale', ['zh', 'ja', 'ko'])
def test_python_format_single_plural_uses_plural_placeholders(locale):
message = Message(
('One file for %(owner)s', '%(num)d files for %(owner)s'),
('%(owner)s: %(num)d',),
)
python_format(Catalog(locale), message)


@pytest.mark.parametrize(('translation', 'error'), [
('%(owner)s: %(num)s', "incompatible format for placeholder 'num'"),
('%(other)s: %(num)d', "unknown named placeholder 'other'"),
])
def test_python_format_single_plural_rejects_invalid_placeholders(translation, error):
message = Message(
('One file for %(owner)s', '%(num)d files for %(owner)s'),
(translation,),
)
with pytest.raises(TranslationError, match=error):
python_format(Catalog('zh'), message)


def test_python_format_multiple_plurals_checks_singular_placeholders():
message = Message(
('One file for %(owner)s', '%(num)d files for %(owner)s'),
('%(owner)s: %(num)d', '%(owner)s: %(num)d'),
)
with pytest.raises(TranslationError, match="unknown named placeholder 'num'"):
python_format(Catalog('en'), message)