Setting Up Date and Number Formatting by Locale in Mobile Applications
Application shows "1,234.56" to user from Germany, which for them looks like "one thousand two hundred thirty-four point five six". Or date "04/05/2024" — April fifth or May fourth? Depends on user locale, and this not cosmetics: in financial and medical applications incorrect formatting — bug with real consequences.
Where Exactly It Breaks
Android. String.format("%.2f", price) — uses Locale.getDefault() system, but only if not explicitly pass locale. On some MIUI versions Locale.getDefault() returns Locale.US regardless of user settings. Correct: String.format(Locale.getDefault(Locale.Category.FORMAT), "%.2f", price). Or NumberFormat.getInstance(locale).format(price).
SimpleDateFormat — not thread-safe and deprecated. DateTimeFormatter (java.time, API 26+) or ThreeTenABP for old versions. Pattern "dd/MM/yyyy" — hardcode, doesn't account locale. DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withLocale(locale) — correct way.
iOS. DateFormatter without explicit locale set takes Locale.current — seems correct. But if DateFormatter created on background thread and cached, it may capture locale before user changed language in app. NumberFormatter similarly. Rule: formatter.locale = Locale(identifier: userSelectedLocale) — always explicit.
Locale(identifier: "ru_RU") vs Locale(identifier: "ru") — difference exists: with region applies regional settings for numbers and dates (in Russia decimal separator — comma, in Belarus — also, but phone formats different).
Flutter. Package intl: DateFormat.yMd(locale).format(date), NumberFormat.currency(locale: locale, symbol: symbol).format(amount). Important: intl doesn't include locale-data automatically — need initializeDateFormatting(locale) before first use, else MissingLocaleDataException at runtime.
Currency — Separate Story
NumberFormat.getCurrencyInstance(locale).format(amount) — formats sum with currency symbol by locale rules. But symbol and its position depend on locale: in en_US this $1,234.56, in de_DE — 1.234,56 €, in ru_RU — 1 234,56 ₽. For multi-currency app, symbol pass explicitly through NumberFormat.getCurrencyInstance(locale).apply { currency = Currency.getInstance("EUR") }.
Separate pain — thousand separators. In hi_IN (Hindi) grouping not by threes, but by schema 2-2-3 (lakhs): 1,23,456. NumberFormat supports this, custom implementation through replace — no.
What We Do
Audit all formatting places in code: grep -rn "SimpleDateFormat\|String.format\|\.toString()". Replace with locale-aware formatters. Add utility layer LocaleFormatter / AppFormatter — centralized place where locale substituted from current app context. Write unit tests with several locale-fixtures (de_DE, ar_SA, hi_IN).
Timeframe: 1 day for application without custom display components. Cost calculated individually.







