Skip to content

[13.x] Fix trans_choice() picking the wrong plural form for negative numbers - #61700

Merged
taylorotwell merged 1 commit into
laravel:13.xfrom
sumaiazaman:13.x-fix-plural-index-negative-numbers
Sep 24, 2026
Merged

taylorotwell merged 1 commit into
laravel:13.xfrom
sumaiazaman:13.x-fix-plural-index-negative-numbers

Conversation

@sumaiazaman

Copy link
Copy Markdown
Contributor

MessageSelector::getPluralIndex() checks the signed number against each locale's rule, so negative counts fall through to the last form:

trans_choice('item|items', -1);             // "items"
trans_choice('файл|файла|файлов', -1, [], 'ru'); // "файлов", should be "файл"
trans_choice('файл|файла|файлов', -2, [], 'ru'); // "файлов", should be "файла"

This shows up with things like balance or score changes ("-1 point"). CLDR defines the plural operands on the absolute value of the number, and Symfony's copy of the same rule table already calls abs($number) before matching.

This applies abs() to numeric values only, so null or non-numeric strings get the same result as before instead of a deprecation or TypeError. Explicit ranges like {-1} are matched in extract() before the plural rules run, so they're unaffected (#58648).

getPluralIndex() compared the signed number against every rule, so
negative counts always fell through to the last form ("-1 items" in
English, the genitive plural for -1 or -2 in Russian). CLDR plural
operands use the absolute value, and Symfony's copy of these rules
already calls abs(). Explicit ranges like {-1} are matched before the
rules and are unaffected.
@shaedrich

Copy link
Copy Markdown
Contributor

Does this apply to every language?

@taylorotwell
taylorotwell merged commit 1e4633f into laravel:13.x Sep 24, 2026
29 of 62 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants