Locale-Aware Formatting
Also Known As
NumberFormatter
DateFormatter
Intl extension
ICU
TL;DR
Formatting numbers, currencies, and dates according to locale conventions — 1,234.56 in en-US is 1.234,56 in de-DE, and currency symbols and date formats vary by locale.
Explanation
PHP's Intl extension (ICU-based) provides locale-aware formatting: NumberFormatter (numbers, currencies, percentages), DateFormatter (dates, times with locale-specific patterns), and MessageFormatter (pluralisation rules, placeholders). Locale identifiers use BCP 47 format (en-US, de-DE, zh-Hans-CN). Formatting must happen at the presentation layer — store raw values (1234.56, timestamps in UTC) and format for display.
Common Misconception
✗ Replacing '.' with ',' is sufficient for European number formatting — locale formatting also affects grouping separators, currency symbols, percent signs, and date patterns.
Why It Matters
Displaying $1,234.56 to a German user when they expect 1.234,56 € is both confusing and potentially a trust issue — locale-aware formatting is user respect.
Common Mistakes
- Hardcoding currency symbols — $ means dollars only in en-US context; use NumberFormatter with the currency code.
- Manual date string replacement for localisation — different locales have completely different date structures.
- Not handling pluralisation with MessageFormatter — '1 item' vs '2 items' varies by language in non-obvious ways.
- Assuming number formatting is sufficient — order of day/month/year varies by locale and cannot be fixed by number formatting alone.
Code Examples
✗ Vulnerable
// Manual locale formatting — fragile:
$price = 1234.56;
echo '€' . number_format($price, 2, ',', '.'); // '€1.234,56'
// Hardcoded to German format — wrong for French (1 234,56 €)
✓ Fixed
// Intl NumberFormatter — correct for any locale:
$formatter = new NumberFormatter('de-DE', NumberFormatter::CURRENCY);
echo $formatter->formatCurrency(1234.56, 'EUR'); // '1.234,56 €'
$formatter = new NumberFormatter('fr-FR', NumberFormatter::CURRENCY);
echo $formatter->formatCurrency(1234.56, 'EUR'); // '1 234,56 €'
// Date formatting:
$fmt = new IntlDateFormatter('de-DE', IntlDateFormatter::LONG, IntlDateFormatter::NONE);
echo $fmt->format(new DateTime('2026-03-15')); // '15. März 2026'
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
15 Mar 2026
Edited
22 Mar 2026
Views
26
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
Amazonbot 7
Perplexity 7
Unknown AI 3
Ahrefs 2
Google 2
Majestic 1
ChatGPT 1
Also referenced
How they use it
crawler 21
crawler_json 1
pre-tracking 1
⚡
DEV INTEL
Tools & Severity
🟡 Medium
⚙ Fix effort: Medium
⚡ Quick Fix
Use NumberFormatter for currency (€1.234,56 in German, $1,234.56 in US), DateFormatter for dates — never hardcode format strings; locale determines thousands separator, decimal point, date order
📦 Applies To
PHP 5.3+
web
cli
🔗 Prerequisites
🔍 Detection Hints
number_format($price, 2, '.', ',') hardcoded separators; date('d/m/Y') hardcoded format instead of locale-aware; currency symbol hardcoded
Auto-detectable:
✓ Yes
phpstan
psalm
⚠ Related Problems
🤖 AI Agent
Confidence: Medium
False Positives: Medium
✗ Manual fix
Fix: Medium
Context: File
Tests: Update