Skip to content

i18n

The i18n module provides internationalization support: message translation, pluralization, and locale-aware number and date formatting — all built on the Web Platform's Intl API.

Import

ts
import { createI18n } from '@loewen-digital/fullstack/i18n'

Basic usage

ts
import { createI18n } from '@loewen-digital/fullstack/i18n'

const i18n = createI18n({
  locale: 'en',
  fallback: 'en',
  messages: {
    en: {
      'welcome': 'Welcome, :name!',
      'items': '{0} item|{1} items',
    },
    fr: {
      'welcome': 'Bienvenue, :name !',
      'items': '{0} article|{1} articles',
    },
  },
})

i18n.t('welcome', { name: 'Alice' }) // 'Welcome, Alice!'
i18n.t('items', 1)                   // '1 item'
i18n.t('items', 5)                   // '5 items'

Locale switching

ts
const i18n = createI18n({ locale: 'en', messages: { en: {}, fr: {} } })

// Switch locale at runtime
const fr = i18n.withLocale('fr')
fr.t('welcome', { name: 'Alice' }) // 'Bienvenue, Alice !'

Number formatting

ts
i18n.n(1234567.89)                          // '1,234,567.89'
i18n.n(0.42, { style: 'percent' })          // '42%'
i18n.n(9.99, { style: 'currency', currency: 'USD' }) // '$9.99'

Date formatting

ts
i18n.d(new Date(), 'short')   // '4/5/2026'
i18n.d(new Date(), 'long')    // 'April 5, 2026'
i18n.d(new Date(), 'time')    // '3:45 PM'

Nested message keys

ts
const i18n = createI18n({
  locale: 'en',
  messages: {
    en: {
      auth: {
        login: 'Log in',
        logout: 'Log out',
        errors: {
          invalid: 'Invalid email or password.',
        },
      },
    },
  },
})

i18n.t('auth.errors.invalid') // 'Invalid email or password.'

Config options

OptionTypeDefaultDescription
localestringActive locale code (e.g. 'en', 'fr-CA')
fallbackstringlocaleFallback locale when a key is missing
messagesRecord<string, Record<string, unknown>>{}Locale message dictionaries
missing(key, locale) => stringreturns keyHandler for missing translation keys