← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Locale-Aware Formatting

i18n PHP 5.3+ Intermediate

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'

Added 15 Mar 2026
Edited 22 Mar 2026
Views 26
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings F 1 ping S 0 pings S 0 pings M 1 ping T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 1 ping F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S
No pings yet today
Amazonbot 7 Perplexity 7 Unknown AI 3 Ahrefs 2 Google 2 Majestic 1 ChatGPT 1
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

✓ schema.org compliant