Stop Translating Month Names by Hand: PHP's intl Extension
You can date a PHP codebase by its formatting helpers: an array of German month names here, a number_format() with hardcoded separators there, a $currencySymbols map that puts every symbol on the left. All of it re-implements, badly, what the intl extension ships complete.
Money: NumberFormatter
$usd = new NumberFormatter('en_US', NumberFormatter::CURRENCY);
$usd->formatCurrency(1234.5, 'USD'); // "$1,234.50"
$de = new NumberFormatter('de_DE', NumberFormatter::CURRENCY);
$de->formatCurrency(1234.5, 'EUR'); // "1.234,50 €" - symbol AFTER, comma decimal
Separators, symbol position, spacing, negative formats - per locale, correct, maintained by the Unicode CLDR project rather than your utils file. The locale and the currency are independent inputs, which is exactly right: a German customer viewing USD prices gets "1.234,50 $" - their notation, your currency. (This is the server-side twin of JavaScript's Intl.NumberFormat - same CLDR data underneath, so both sides of your app agree.)
Percent, ordinal and spellout styles ride along: NumberFormatter::ORDINAL gives "3rd"/"3." per locale; SPELLOUT writes "one thousand two hundred" - the check-printing feature you didn't know existed.
Dates: IntlDateFormatter, because strftime is dead
strftime() - the old locale-aware formatter - was deprecated in 8.1 and removed in 8.4. Its replacement is better anyway:
$fmt = new IntlDateFormatter(
'de_DE',
IntlDateFormatter::LONG, // date style
IntlDateFormatter::SHORT, // time style
);
$fmt->format(new DateTimeImmutable('2026-07-04 14:30'));
// "4. Juli 2026 um 14:30"
// Or full pattern control (ICU syntax, not date()'s letters!)
$fmt = new IntlDateFormatter('en_US', pattern: 'EEEE, MMMM d');
$fmt->format($date); // "Saturday, July 4"
Month and weekday names in 700+ locales, correct genitive forms in Slavic languages, era handling, all free. The one trap: ICU patterns share letters with date() but mean different things (MM is month in both, but yyyy vs Y, EEEE vs l) - never paste date() formats into IntlDateFormatter.
The setup footnote that stops most people
intl is bundled with PHP but not always enabled - notably XAMPP ships it commented out. One line in php.ini (extension=intl), restart, done; on Debian/Ubuntu servers it's apt install php-intl. Guard library code with extension_loaded('intl') and a plain-number_format fallback if you distribute to unknown hosts.
Beyond formatting, the same extension hides more gems: Collator (natural, locale-aware sorting - details here), IntlChar, transliteration for slug generation from any script. It's the standard library's best-kept secret, one ini line away.
Full-stack web developer sharing practical tutorials and building tools that ship.
Got something on your mind?
My inbox is open - no forms disappearing into the void here.
- Just say hello Found a tutorial useful? Spotted a mistake? Tell me.
- Hire me for a project Have something custom in mind? Let's talk scope and timelines.
- Product support Bought something here? I'll help you get it running.
I usually reply within 1-2 business days.