Building products for international markets is more than translation. It's understanding that different cultures have different expectations: date formats, number formats, text direction (RTL), color meanings, and even how to structure information. Get it right, and your product feels native everywhere. Get it wrong, and users in other countries feel like afterthoughts.
Translation: The Obvious Part
Extract all user-facing text from code. Don't hardcode "Hello" — use a translation key:
// Bad
export function Greeting() {
return Hello, {username}
}
// Good
export function Greeting() {
return {t('greeting.hello', { name: username })}
}
Tools like i18next (JavaScript), Laravel's localization, or Phrase/POEditor help manage translations. Store translations in JSON or spreadsheets.
Translation considerations:
- String length varies by language: German words are long, Chinese is compact. Don't hardcode button widths.
- Context matters: "Date" means different things in "Date of birth" vs "Date with someone." Translators need context.
- Plurals: English has singular/plural. Other languages have complex plural rules. Use library support for pluralization.
Localization: Numbers, Dates, Currency
Different locales have different conventions. US uses MM/DD/YYYY; most of the world uses DD/MM/YYYY. US uses commas for thousands separators; many European countries use periods.
// Use Intl API for localization
const date = new Date('2024-03-15')
// US format
console.log(new Intl.DateTimeFormat('en-US').format(date)) // 3/15/2024
// German format
console.log(new Intl.DateTimeFormat('de-DE').format(date)) // 15.3.2024
// Numbers
new Intl.NumberFormat('en-US').format(1234.56) // 1,234.56
new Intl.NumberFormat('de-DE').format(1234.56) // 1.234,56
// Currency
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
}).format(49.99) // $49.99
new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: 'EUR',
}).format(49.99) // 49,99 €
Right-to-Left (RTL) Languages
Arabic, Hebrew, and Urdu are written right-to-left. Your layout needs to mirror when displaying these languages.
.sidebar {
float: left; /* LTR */
margin-left: 20px;
}
[dir="rtl"] .sidebar {
float: right; /* RTL */
margin-right: 20px;
margin-left: 0;
}
.sidebar {
margin-inline-start: 20px; /* Works in both LTR and RTL */
float: inline-start; /* Adapts to text direction */
}
Choosing Which Languages to Support
You can't support every language. Prioritize based on:
- Market opportunity: Your biggest users' locations
- Business value: Which languages drive revenue?
- Language complexity: Supporting 10 European languages is easier than 1 Asian language (more complex scripts and pluralization)
Start with 1-2 languages. Get them right. Then expand.
Testing International Features
Internationalization is easy to get wrong. Test it:
- Pseudo-translation: Replace all text with placeholder strings (XXXXXXXXXXXX) to find hardcoded text and layout issues
- Long text testing: Some languages use 30% more characters. Test with long translations.
- Screen reader testing: Screen readers need language hints to pronounce correctly
- Real language testing: Have native speakers test your product in their language. Cultural differences matter.
Infrastructure Considerations
Translations and locale data are assets to serve. Consider:
- CDN delivery: Serve localization data from a CDN
- Lazy loading: Only load the language/locale data for the user's language, not all 50
- Caching: Translations don't change constantly. Cache them aggressively
Building for global audiences is an investment. But if you want to scale globally, doing internationalization right from the start saves massive effort later.