Concept
Internationalization (i18n) vs Localization (l10n)
- Internationalization (i18n): The engineering work of designing your code to be language-agnostic (e.g. replacing hardcoded strings with dictionary keys like
t('cart.checkout')). - Localization (l10n): The content work of adapting the app for a specific region, which includes text translations, date formatting, number spacing, and currencies.
ICU Message Format for Plurals & Selects
Simple key-value lookups are not enough for complex grammar rules like plurals or gender variations. The ICU Message Format is the industry standard for handling translation logic:
{
"cart.itemsCount": "You have {count, plural, =0 {no items} one {1 item} other {# items}} in your cart."
}This prevents developers from writing complex conditional rendering logic in UI components:
// ❌ WRONG: Hardcoded conditional branches
<span>{count === 0 ? 'No items' : count === 1 ? '1 item' : `${count} items`}</span>
// CORRECT: ICU translation lookup
<span>{t('cart.itemsCount', { count })}</span>Layout Direction (RTL vs LTR)
Languages like Arabic and Hebrew are read from Right-to-Left (RTL). To support RTL layouts dynamically:
- HTML dir attribute: Set
<html dir="rtl">on the root. This reverses page flows, scrolls, and text alignments. - CSS Logical Properties: Avoid directional margins/paddings like
margin-leftorright. Instead, use logical properties likemargin-inline-startormargin-inline-end.
/* ❌ Directional property: requires custom override for RTL */
.button { margin-left: 8px; }
[dir="rtl"] .button { margin-right: 8px; margin-left: 0; }
/* Logical property: adapts automatically */
.button { margin-inline-start: 8px; }Common Mistakes
1. Inlining translation calculations inside React render loops
Re-evaluating ICU plural structures or parsing dates inside active component loops wastes CPU. Use dedicated, memoized translation providers or hook contexts.
2. Hardcoding date/number delimiters
Manually stringifying dates using formats like MM/DD/YYYY fails internationally. Always use the native Intl API:
// Adapts formatting to user's local region automatically
new Intl.DateTimeFormat('fr-FR').format(new Date()); // "22/07/2026"Best Practices
- Use logical properties: Ensure your spacing utility systems use start/end labels instead of left/right.
- Never concatenate strings: Avoid constructing translated sentences out of segments like
t('hello') + userName + t('welcome'). Use template parameters:t('welcome_user', { name: userName }). - Integrate dynamic imports: Lazy-load translation dictionary JSON files dynamically based on the current locale to keep initial bundle sizes small.
