Nest a plural inside a select so every gender and count combination is a full sentence, for example `{gender, select, female {{count, plural, one {She has # cat} other {She has # cats}}} male {...} other {...}}`. Keep nesting to two levels and never build the sentence from fragments in code.
Quote a literal brace with ASCII apostrophes, `'{'` and `'}'`, and write a literal apostrophe as `''`. In ICU an apostrophe only starts quoting before `{`, `}` or a plural's `#`, so `don't` needs no escaping; `java.text.MessageFormat` quotes on every apostrophe.
Give the argument a type and a style, such as `{n, number}`, `{n, number, percent}`, `{d, date, long}` or `{t, time, short}`, or a skeleton such as `{price, number, ::currency/EUR}` and `{d, date, ::yMMMd}`. Pass raw values from code and let the message format them for its locale.
Use a plural argument such as `{count, plural, one {# item} other {# items}}`. `#` prints the number formatted for the locale, `=0` matches an exact value, and the branch names are the CLDR plural categories of the target language, with `other` always required.
A plural argument picks a branch from a number using the locale's CLDR plural categories and exact matches such as `=0`. A select argument picks a branch from a string value such as a gender, and selectordinal is plural for ordinals (1st, 2nd, 3rd). All three need an `other` branch.
ICU4C, ICU4J and Android (API 24+) implement the full syntax; FormatJS and react-intl, @messageformat/core, PHP's intl MessageFormatter, Dart intl with Flutter ARB files and Angular i18n support plural and select; java.text.MessageFormat has no plural rules, and iOS has none built in.
Usually because `one` is treated as "exactly 1". In French `one` also matches 0 and in Russian 21 and 31, so use `=1` for an exact match. Other causes are translations that keep the source language's categories, a missing `other`, and `zero` used where `=0` was meant.