A startup built a product for 6 months.
Launched in Japan. Zero users. App was fully in English. đ€Š
Here's what Localisation actually means â and how to do it right đ
đ§ đȘđ”đźđ đ¶đ đđŒđ°đźđčđ¶đđźđđ¶đŒđ»?
đ i18n (Internationalisation) â designing app to support multiple languages
đ L10n (Localisation) â actually adapting it for a specific region
đ They are NOT the same thing
i18n = building the infrastructure
L10n = filling it with regional content
i18n is done once.
L10n is done for every new market.
â Language translation
â Date, time & number formats
â Currency symbols
â Text direction (LTR vs RTL)
â Cultural sensitivities
đ 1ïžâŁ đ§đżđźđ»đđčđźđđ¶đŒđ» â đĄđČđđČđż đđźđżđ±đ°đŒđ±đČ đŠđđżđ¶đ»đŽđ
đ Every visible string must live outside your code
// â Hardcoded â impossible to translate
<h1>Welcome back, John!</h1>
// â
Using i18n keys
<h1>{t('welcome', { name: 'John' })}</h1>
// en.json
{ "welcome": "Welcome back, {{name}}!" }
// ja.json
{ "welcome": "ăăăăăȘăăă{{name}}ăăïŒ" }
â Use libraries: react-i18next, i18next, react-intl
â Keys should be semantic â not the English text itself
â Never use Google Translate for production â hire translators
đ 2ïžâŁ đđźđđČ & đ§đ¶đșđČ đđŒđżđșđźđđ
đ Date formats are wildly different across regions
// â Hardcoded format â confusing globally
"04/05/2025" // Is this April 5 or May 4?
// â
Use Intl.DateTimeFormat
new Intl.DateTimeFormat('en-US').format(date)
// â "4/5/2025"
new Intl.DateTimeFormat('en-GB').format(date)
// â "05/04/2025"
new Intl.DateTimeFormat('ja-JP').format(date)
// â "2025/4/5"
â Always store dates in UTC internally
â Format only at display time
â Never hardcode date separators or order
đ° 3ïžâŁ đđđżđżđČđ»đ°đ & đĄđđșđŻđČđżđ
đ Numbers & currency look different in every country
// â Hardcoded â wrong for most of the world
"$1,000.50"
// â
Use Intl.NumberFormat
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(1000.50)
// â "$1,000.50"
new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: 'EUR'
}).format(1000.50)
// â "1.000,50 âŹ"
â Decimal separator: . in US, , in Germany
â Currency symbol position varies by locale
â Always use Intl.NumberFormat â never manual formatting
âïž 4ïžâŁ đ„đ§đ đđźđ»đŽđđźđŽđČđ (đ„đ¶đŽđ”đ-đđŒ-đđČđłđ)
đ Arabic, Hebrew, Urdu â entire layout flips direction
<!-- â Hardcoded direction â breaks RTL languages -->
<div style="text-align: left">Content</div>
<!-- â
Dynamic direction -->
<html dir="rtl" lang="ar">
<!-- â
Tailwind RTL support -->
<div class="text-left rtl:text-right">Content</div>
<div class="ml-4 rtl:mr-4 rtl:ml-0">Icon</div>
â Use dir="rtl" on <html> tag
â CSS logical properties: margin-inline-start instead of margin-left
â Test your entire layout in RTL â icons, buttons, animations all flip
đ 5ïžâŁ đ§đ¶đșđČđđŒđ»đČđ
đ One of the most common bugs in global apps
// â Using local time â breaks for other timezones
new Date().toString()
// â
Always work in UTC, format locally
new Intl.DateTimeFormat('en-US', {
timeZone: 'Asia/Tokyo',
hour: '2-digit',
minute: '2-digit'
}).format(new Date())
// â
Use date-fns-tz or Luxon for complex timezone logic
import { zonedTimeToUtc } from 'date-fns-tz';
â Store all timestamps in UTC in your database
â Convert to user's timezone only at display
â Never use new Date() for timezone-sensitive features
đ€ 6ïžâŁ đŁđčđđżđźđčđ¶đđźđđ¶đŒđ» & đđČđ»đ±đČđż
đ "1 item" vs "2 items" â every language handles this differently
// â English-only logic â fails in Russian, Arabic
`You have ${count} message${count !== 1 ? 's' : ''}`
// â
i18next plural handling
t('messages', { count: 5 })
// en.json
{
"messages_one": "You have {{count}} message",
"messages_other": "You have {{count}} messages"
}
// ar.json â Arabic has 6 plural forms!
{
"messages_zero": "...",
"messages_one": "...",
"messages_two": "...",
"messages_few": "...",
"messages_many": "...",
"messages_other": "..."
}
â Never build plural logic manually
â Use CLDR plural rules via i18next
â Arabic has 6 forms. Russian has 3. Plan for this.
đŒïž 7ïžâŁ đđșđźđŽđČđ, đđ°đŒđ»đ & đđŒđčđŒđđżđ
đ Visuals carry cultural meaning â not just language
â đ Thumbs up = positive in West, offensive in Middle East
â âȘ White = purity in West, mourning in parts of Asia
â Avoid country-specific idioms in illustrations
â Flag icons can be politically sensitive
// â Using flags to represent languages
đșđž English đ«đ· French
// â
Use language names â not flags
EN FR DE JA
âïž đ„đČđźđč đŠđČđđđœ đ¶đ» đ„đČđźđ°đ
npm install react-i18next i18next
// i18n.js
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
i18n.use(initReactI18next).init({
lng: 'en',
fallbackLng: 'en',
resources: {
en: { translation: require('./locales/en.json') },
ja: { translation: require('./locales/ja.json') }
}
});
// Component usage
const { t, i18n } = useTranslation();
<h1>{t('welcome')}</h1>
<button onClick={() => i18n.changeLanguage('ja')}>æ„æŹèȘ</button>
â Lazy load translations â don't bundle all languages upfront
â Detect browser language automatically with i18next-browser-languagedetector
â Store user language preference in localStorage
đš đđŒđșđșđŒđ» đ đ¶đđđźđžđČđ
â Hardcoding strings directly in components
â Using new Date() without timezone handling
â Building plural logic manually in English
â Using flag icons to represent languages
â Adding i18n as an afterthought â design for it from day one
â Assuming all text expands the same â German text is 30% longer than English
đĄ đŠđČđ»đ¶đŒđż-đđČđđČđč đđ»đđ¶đŽđ”đ
i18n is architecture. L10n is content. Confuse the two and you rebuild from scratch.
Design for localisation on day one â retrofitting it costs 10x more.
đŻ đđ»đđČđżđđ¶đČđ đąđ»đČ-đđ¶đ»đČđż
Localisation (L10n) is the process of adapting software for a specific region â covering language translation, date/time/currency formatting, RTL support, pluralisation, and cultural nuances â built on top of Internationalisation (i18n), which is the architecture that makes localisation possible without rewriting code.
Is your current app localised? Which language did you add first? đ
#Localisation #i18n #Frontend #ReactJS #WebDevelopment #JavaScript #InterviewPrep #GlobalProduct #EngineeringMindset
Top comments (0)