Skip to content
Carl Victor Fontanos
Carl Victor Fontanos

Carl Victor Fontanos

Software Engineer

I build web applications and share what I learn along the way.

© 2026

Stop Translating Month Names by Hand: PHP's intl Extension

C
Carlo Fontanos
· 2 min read

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.

C
Written by Carlo Fontanos

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.

Message sent!

Your details are only used to reply to you.

Keep reading