Internationalization (i18n)
Internationalize web apps with react-i18next - ICU message format, pluralization, date/number formatting, RTL layouts, and locale detection.
skill: Internationalization (i18n) category: Frontend tags: [i18n, Localization, react-i18next, ICU, Pluralization] readingTime: 5
Internationalization is a requirement, not a feature. Design for it from day one - retrofitting i18n onto an existing app is 5-10x more work than building it in. The hardest parts are pluralization rules (they differ by language), date/time formatting (calendar systems, timezone), and RTL layouts (Arabic, Hebrew).
Workflow
- Set up react-i18next with ICU formatreact-i18next is the standard React i18n library. ICU message format handles plurals, genders, and select across 200+ language rules.
- Write ICU message strings for plurals and gendersPluralization rules differ by language - English has 2 forms, Russian has 4, Arabic has 6. ICU format handles all cases without code changes.
- Format dates, numbers, and currencies with IntlDate formats vary by locale (MM/DD/YYYY vs. DD.MM.YYYY vs. YYYY年MM月DD日), and currency formatting is complex. The built-in Intl API handles all cases.
- Support RTL layouts with logical propertiesArabic, Hebrew, and Farsi are right-to-left. CSS logical properties (margin-inline-start vs. margin-left) flip correctly for both LTR and RTL without duplicating styles.
- Load translations lazily and manage keysLoading all translation files on startup bloats the initial bundle. Namespace splitting loads only what the current route needs.
Output Format
i18n: react-i18next with ICU format, plural/gender messages, Intl API for dates/currencies, CSS logical properties for RTL, and namespace-split lazy loading.
i18n.init({ use: [ICU, LanguageDetector], resources, fallbackLng })
ICU: {count, plural, one {# item} other {# items}}
Intl.DateTimeFormat(locale).format(date)
document.documentElement.dir = i18n.dir()
namespace split: common.json + route-specific.jsonExamples
Input
Output
Edge Cases & Gotchas
- Missing translation keys - react-i18next returns the key string when a translation is missing. In development, enable missingKeyHandler to log missing keys. In CI, fail on missing keys with a custom detector.
- Pseudo-localization testing - Before professional translation, use pseudo-localization (replace characters with accented versions, add ~30% length) to catch layout breaks from longer translations (German is 30% longer than English).
- Number input from RTL users - Arabic users enter numbers left-to-right (1234) even in RTL layouts. Don't mirror input direction for numeric fields.
- Currency without symbol - Intl.NumberFormat with currency shows the currency symbol. For prices where currency is shown elsewhere, use style: "decimal" and format separately.
When to Break These Rules
- Use simple JSON + t() function without ICU format for small apps with limited locales - the ICU parser adds ~10KB and is overkill for apps that only need simple string substitution.
- Use a localization platform (Phrase, Lokalise, Crowdin) for professional translation workflows - managing JSON files in git is only sustainable for small teams with in-house translators.
Reference Files
https://react.i18next.com/https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl