Pluralization rules
Languages don't all split counts into one and many. Russian has four buckets, Arabic six, Japanese one, and your strings have to handle each.
See it
What it is
English splits counts two ways: 1 item, 2 items. That is unusually simple. Unicode CLDR defines six possible categories (zero, one, two, few, many, other) and every language uses some subset. Arabic uses all six. Russian and Polish use one, few, many, other. Japanese, Korean, and Chinese use only 'other'. Welsh picks a different set again.
You never write these rules yourself. You declare the plural branches your message format supports (ICU plural, gettext nplurals, Android quantity strings) and the runtime looks up the category in CLDR data for the active locale. Intl.PluralRules exposes the same lookup in the browser if you need the category directly.
Gotcha: categories are grammar, not arithmetic. Russian files 21 under 'one' and 5 under 'many'. French files 0 under 'one'. And the 'zero' category is not a slot for your nice empty state: it exists because a few languages inflect at zero. If you want different copy at none, write an explicit =0 branch in the message.
Ask AI for it
Make this counted string safe across plural systems. Express it as an ICU plural message using # for the count. For each target locale, implement exactly the cardinal categories that locale actually has, read from new Intl.PluralRules(locale).resolvedOptions().pluralCategories, always including 'other', and do not invent branches for categories the locale never returns. Add an exact-number branch such as =0 only where the copy is genuinely different rather than just grammatical. Do not branch on the count with if/else in code. Then render the message separately for en, ru, ar, and ja at counts 0, 1, 2, 5, 21, and 101 in a table so I can see which category fires where.