Internationalization & Localization
We serve customers across many countries, languages, and locales. The product cannot assume everyone speaks English, lives in one timezone, or uses one currency and date format. Internationalization (i18n) is building the product so it can adapt. Localization (l10n) is the actual translations and regional formats. Designing for this from the start is far cheaper than adding it later.
Common beginner assumptions cause problems later: that text is English and fits a fixed space, that dates are "obviously" dd/mm or mm/dd, that names have a first and last name, that everyone uses the same number and currency format, and that a string is just a string. None of these hold across locales. i18n means moving text out into resources, handling Unicode properly, and formatting dates, numbers, and currency by locale.
For us this also affects correctness and compliance. Timezones and date formats matter for audit and transactions (store UTC, display local). Currency must be explicit (see Money & Currency). And names and addresses vary far more than a Western format assumes.
Build to adapt
- DoMove user-facing text into resource files and keys instead of hard-coding strings, so it can be translated without code changes.
- DoFormat dates, times, numbers, and currency using locale-aware libraries. Never build formats by hand or assume one regional convention.
- DoStore timestamps in UTC and convert to the user's timezone for display. Be explicit about timezone everywhere (see C# / .NET gotchas).
- DoUse Unicode (UTF-8) end to end, and do not assume ASCII. Names, addresses, and input contain accents, non-Latin scripts, and emoji.
- ConsiderSupporting right-to-left layout and longer text (translations are often longer), so the UI does not break in other languages (see Accessibility).
var msg = "Payment of £" + amount + " on " + date.ToString("dd/MM/yyyy");
Hard-coded English and £, an assumed date format, and a string that cannot be translated. Wrong for a euro customer, confusing for a US date reader, and untranslatable.
var msg = string.Format(L["PaymentOn"], // translatable, placeholdered
money.Format(culture), // amount + currency, locale-aware
date.ToLocal(tz).ToString("d", culture));
Text comes from resources, currency and date format follow the user's locale, and the timestamp is converted from UTC for display.
Avoid locale assumptions
- DoModel names, addresses, and phone numbers flexibly. Not everyone has a first and last name, a postcode, or a state.
- AvoidBuilding translated sentences by joining fragments. Grammar and word order differ by language. Translate whole phrases with placeholders instead.
- AvoidAssuming that string length, character set, sort order, or capitalisation rules are the same across languages.
- AvoidHard-coding a currency, country, date format, or language as the hidden default in logic (see Money & Currency).
Self-review checklist
- AskIs any user-facing text hard-coded instead of externalised for translation?
- AskAre dates, numbers, and currency formatted by locale — and timestamps stored in UTC?
- AskDoes this assume English/ASCII, a name shape, or one regional format?
- AskWould the UI survive a longer translation or a non-Latin script?