Implementing Internationalization (i18n)

1. Implementing Message Bundles

Example: messages_en.properties

# messages_en.properties
order.confirmation.subject=Order {0} confirmed
# messages_de.properties
order.confirmation.subject=Bestellung {0} bestätigt

2. Implementing Locale Detection

SourceDetail
User preferenceStored on profile (highest priority)
Accept-Language headerBrowser default
CookiePersisted last choice
URL prefix/de/...
FallbackApp default (e.g., en-US)

3. Implementing Translation Lookup

Example: Spring MessageSource

String subject = messages.getMessage(
    "order.confirmation.subject",
    new Object[]{ order.id() },
    LocaleContextHolder.getLocale());

4. Handling Pluralization

ToolDetail
ICU MessageFormatPlural / select / number rules
CLDRLocale-aware plural categories
Libraryicu4j

Example: ICU plural

{count, plural, one {# item} other {# items}}

5. Implementing Date/Time Localization

Example: java.time formatters

DateTimeFormatter f = DateTimeFormatter
    .ofLocalizedDateTime(FormatStyle.MEDIUM)
    .withLocale(locale)
    .withZone(user.zoneId());
String s = f.format(Instant.now());

6. Implementing Number/Currency Localization

Example: Currency format

NumberFormat nf = NumberFormat.getCurrencyInstance(locale);
nf.setCurrency(Currency.getInstance("EUR"));
String price = nf.format(amount);  // "1.234,56 €" in de-DE

7. Implementing Right-to-Left Support

ConcernDetail
Text directionHTML dir="rtl"
CSSLogical properties (margin-inline-start)
Bidi algorithmUnicode UAX #9 handles mixed text
ServerSend Content-Language + dir hint

8. Implementing Locale-Specific Validation

FieldDetail
Postal codeFormat per country
Phonelibphonenumber for E.164 + national
VAT/Tax IDCountry-specific patterns
AddressRequired fields vary

9. Implementing Translation Caching

LayerDetail
In-processMessageSource caches loaded bundles
DistributedRedis for dynamic translations
InvalidationOn translation update
CDNFor client-side bundles

10. Implementing Fallback Locale Logic

OrderLookup
1Specific (de_AT)
2Language only (de)
3App default (en)
4Key returned literally (with warning)

11. Implementing Dynamic Language Switching

Example: LocaleChangeInterceptor

@Bean
LocaleChangeInterceptor localeChangeInterceptor() {
    var i = new LocaleChangeInterceptor();
    i.setParamName("lang");  // ?lang=de
    return i;
}
@Bean LocaleResolver localeResolver() {
    var r = new CookieLocaleResolver();
    r.setDefaultLocale(Locale.ENGLISH);
    return r;
}

12. Implementing Translation Management

PracticeDetail
Source of truthTMS (Crowdin, Phrase, Lokalise)
CI syncPush keys, pull translations
Missing-key trackingLog + alert
Translation memoryReuse phrases
Context for translatorsScreenshots, descriptions