Skip to main content

Language Switcher

Detection order: URL prefix → Cookie → Base locale (English)

Current language: English (en)
Formatting locale: en-US

Translated Messages

m.greeting({ name: 'World' }) Hello, World!
m.welcome_message() Welcome to the internationalization showcase
m.sample_text() This text is translated based on the current locale.

Pluralization

ICU MessageFormat handles pluralization rules per language.

m.items_count({ count: 0 }) 0 items
m.items_count({ count: 1 }) 1 items
m.items_count({ count: 2 }) 2 items
m.items_count({ count: 5 }) 5 items
m.items_count({ count: 42 }) 42 items

Date & Number Formatting

Formatting uses the browser's Intl API, decoupled from the translation locale. A German user in Switzerland gets German text but Swiss number formatting.

Formatted date Jan 15, 2025
Formatted date (long) Wednesday, January 15, 2025
Formatted number 1,234,567.89
Formatted currency (EUR) €1,234.50
Formatted currency (USD) $1,234.50
Formatted percentage 85.4%
Relative time 2 days ago

Content Translation (Database)

The tc() helper translates JSON fields from the database, falling back through: current locale → English → first available.

tc(post.title, post.titleI18n, locale) Hello World
tc(post.description, post.descriptionI18n, locale) This content is stored in the database as JSON.

Database Schema Pattern

// EN canonical column + JSONB i18n sibling per non-base locale
name: text('name').notNull(),
nameI18n: jsonb('name_i18n')
  .$type<Partial<Record<'de'|'ru', string>>>()
  .notNull().default(sql`'{}'::jsonb`),
// Render: tc(row.name, row.nameI18n, locale)

Error Codes

Domain code throws stable error codes; adapters resolve them to localized strings via errorMessage(code). Switching locale re-renders without re-submitting.

errorMessage(ErrorCode.AUTH_INVALID) Invalid credentials.
errorMessage(ErrorCode.VALIDATION_REQUIRED) This field is required.
errorMessage(ErrorCode.RATE_LIMITED) Too many requests. Please slow down.
errorMessage(ErrorCode.RESOURCE_NOT_FOUND) We couldn't find what you're looking for.

Type Safety

All message keys are compile-time checked with full IntelliSense support. Missing keys or wrong parameters cause build errors, not runtime errors.

Compile-time Guarantees

// ✅ Type-safe with autocomplete
m.greeting({ name: 'Alice' });

// ❌ Compile error — missing parameter
m.greeting();

// ❌ Compile error — unknown message key
m.unknownKey();
← Back to Showcases