intl MessageFormatter — ICU-Backed Proper i18n
PHP bundles the ICU library via the intl extension. That means real internationalisation: pluralization rules for all languages, gender agreements, locale-aware number and date formatting — the things every web app needs and usually gets wrong.
use MessageFormatter;
// Pluralization that actually works for every language
$fmt = new MessageFormatter('en_US',
'{count, plural, one{# item} other{# items}}'
);
echo $fmt->format(['count' => 1]); // "1 item"
echo $fmt->format(['count' => 5]); // "5 items"
echo $fmt->format(['count' => 0]); // "0 items"
// Russian has four plural forms — ICU handles them automatically
$fmt_ru = new MessageFormatter('ru_RU',
'{count, plural, one{# товар} few{# товара} many{# товаров} other{# товара}}'
);
echo $fmt_ru->format(['count' => 1]); // "1 товар"
echo $fmt_ru->format(['count' => 3]); // "3 товара"
echo $fmt_ru->format(['count' => 11]); // "11 товаров"
The same extension provides locale-aware number, currency, and date formatting through NumberFormatter and IntlDateFormatter:
// Format numbers correctly for the locale
$nf = new NumberFormatter('de_DE', NumberFormatter::DECIMAL);
echo $nf->format(1234567.89); // "1.234.567,89" — German conventions
$cf = new NumberFormatter('en_US', NumberFormatter::CURRENCY);
echo $cf->formatCurrency(9.99, 'USD'); // "$9.99"
echo $cf->formatCurrency(9.99, 'EUR'); // "€9.99"
// Collation — sort strings correctly for the locale
$coll = new Collator('fr_FR');
$words = ['éclair', 'apple', 'été', 'banane'];
$coll->sort($words);
// Sorted according to French alphabetical rules, not ASCII byte order
Significance: Correctness at Scale
Hardcoded plural rules ("1 item, N items") break for Arabic (six plural forms), Polish (four), and many others. ICU's CLDR data covers 700+ locales. Using
intl means your app handles pluralization and formatting correctly in languages you don't know, without writing a single locale-specific branch.