@judo/i18n
v0.1.1
Published
Internationalization and localization support for JUDO UI Runtime
Downloads
185
Readme
@judo/i18n
Internationalization and localization support for JUDO UI Runtime
Purpose
Provides translation key generation, locale-aware formatting, a system message catalog, a lightweight I18nService, and React integration via react-i18next (I18nProvider, locale hooks, useModelLabel). Supports runtime locale switching, codegen-based translation key maps, and passthrough mode for non-translated setups.
Architecture Layer
Layer 2 (Cross-cutting) — consumed by components and higher layers for all text localization needs.
Dependencies
@judo/model-api— model type definitions (dependency + peer)date-fns— date formatting and locale support (peer)i18next— internationalization framework (peer)react— React runtime (peer)react-i18next— React bindings for i18next (peer)
File Structure
src/
├── index.ts # Barrel re-export (pure utils + React integration)
├── i18n-provider.tsx # I18nProvider, useLocale, useLocaleOptional, LocaleContextType
├── i18n-provider.test.tsx # Provider + hook tests
├── use-model-label.ts # useModelLabel hook
├── use-model-label.test.tsx # useModelLabel tests
├── i18n-service.ts # I18nService interface + createI18nService factory
├── i18n-service.test.ts # Service tests
├── translation-keys.ts # Translation key generators for model elements
├── translation-keys.test.ts # Translation key tests
├── formatters.ts # Date/number/currency/percent formatting utilities
├── formatters.test.ts # Formatter tests
├── system-messages.ts # SYSTEM_MESSAGES catalog + getSystemMessage
├── system-messages.test.ts # System message tests
└── locale-constants.ts # LOCALE_STORAGE_KEY constant (HMR-safe)Exports Summary
Translation Key Generators
| Function | Description |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| getTranslationKey(element, property?) | Generates {type}.{sourceId\|name}.{property} from a model element. Strips ui:/data: prefix, lowercases. |
| getSystemMessageKey(category, key) | Builds system.{category}.{key}. |
| getColumnTranslationKey(column) | Generates column.{sourceId\|name}.label for a table column. |
| getEnumTranslationKey(enumName, value) | Generates enum.{enumName}.{value} for an enum literal. |
| getNavItemTranslationKey(item) | Generates nav.{sourceId\|name}.label for a navigation item. |
Formatters
| Export | Kind | Description |
| --------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------- |
| DateFormatOptions | interface | Options for date formatting — dateStyle, timeStyle, and custom format (date-fns pattern). |
| NumberFormatOptions | interface | Options for number formatting — maps to Intl.NumberFormat options. |
| parseDate(value) | function | Normalizes a date value (Date, ISO string, or timestamp) into a Date object. |
| getDateLocale(localeCode) | function | Resolves a locale code (e.g. en-US, de) to a date-fns Locale object. Supports en, de, hu. |
| formatDate(date, localeCode, options?) | function | Formats a date by locale. Custom date-fns pattern if provided, otherwise style-based, or default "PP". |
| formatNumber(value, localeCode, options?) | function | Formats a number via Intl.NumberFormat. |
| formatCurrency(value, localeCode, currency) | function | Formats a currency value with currency symbol display. |
| formatRelativeTime(date, localeCode) | function | Produces a human-readable relative time string (e.g. "2 days ago"). Auto-picks the best unit. |
| formatPercent(value, localeCode, fractionDigits?) | function | Formats a value as a percentage (0.1 → "10%"). |
System Messages
| Export | Kind | Description |
| --------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| SYSTEM_MESSAGES | constant (as const) | Deeply-nested readonly object with default English system messages organized by 12 categories: action, validation, nav, session, loading, error, empty, pagination, table, dialog, auth, common. |
| SystemMessageCategory | type | Union of top-level keys of SYSTEM_MESSAGES. |
| SystemMessageKey | type | Union of all flattened dot-notation paths (e.g. "action.save.success", "error.notFound"). Compile-time safe via recursive FlattenKeys. |
| getSystemMessage(path) | function | Retrieves a message string by dot-notation path. Returns undefined if path doesn't resolve. |
| getAllSystemMessageKeys() | function | Returns all leaf keys in flat dot-notation. |
I18n Service
| Export | Kind | Description |
| ------------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| TranslationOptions | interface | Options for t(): defaultValue, count (pluralization), plus arbitrary interpolation values. |
| I18nService | interface | Contract for i18n implementations. Methods: getLanguage, setLanguage, getAvailableLanguages, t, exists, formatDate, formatNumber, formatCurrency, formatRelativeTime, formatPercent, onLanguageChange. |
| I18nServiceConfig | interface | Configuration: defaultLanguage, supportedLanguages, optional resources map. |
| interpolate(template, values) | function | Simple {{key}} template interpolation. Replaces placeholders with values; leaves unresolved ones intact. |
| createI18nService(config) | function | Factory that builds a lightweight I18nService implementation. Manages language state, translation lookup with fallback, interpolation, and language-change subscriptions. |
React Integration
| Export | Kind | Description |
| ----------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| I18nProvider | component | Wraps I18nextProvider, manages i18next instance lifecycle, supports localeLoader, translationKeyMap, and persistLocale. |
| I18nProviderProps | interface | Props: defaultLocale?, locales?, localeLoader?, translationKeyMap?, persistLocale?, children. |
| useLocale() | hook | Access locale context (current locale, setter, available locales). Throws if used outside I18nProvider. |
| useLocaleOptional() | hook | Access locale context (optional). Returns null outside I18nProvider. |
| LocaleContextType | interface | Context shape: locale, setLocale, locales, hasTranslations, i18n, translationKeyMap?. |
| useModelLabel(element, property?) | hook | Resolves translated label for a model element. Uses codegen key map if available, falls back to legacy format, then to element.label ?? element.name. |
| ModelLabelResult | interface | Result: label (translated string), translationKey (key used for lookup). |
| LOCALE_STORAGE_KEY | constant | localStorage key ("judo-locale") used by I18nProvider for locale persistence. |
Key Patterns
- Two layers: Pure utilities (translation keys, formatters, service, system messages) have no React dependency; React integration (
I18nProvider, hooks) requiresreact,i18next,react-i18next. - Interface + Factory:
I18nServiceis a pure interface;createI18nServiceis the default factory. Allows swapping in production implementations (e.g.react-i18next). - Locale-aware formatting via Intl + date-fns: Custom format patterns use date-fns
format(); all other formatters use nativeIntlAPIs. - Translation fallback chain:
t()looks up in current language → falls back todefaultLanguage→ returnsdefaultValueoption → returns the raw key. - Dual-path key resolution:
useModelLabelprefers codegentranslationKeyMap(xmi:id → human-readable path), falls back to legacygetTranslationKey()format. - Passthrough mode: When no
localeLoaderis provided,t(key, { defaultValue })returns thedefaultValue— model labels pass through unchanged. - Subscription model:
onLanguageChange()returns an unsubscribe function, enabling React components to re-render on language switches. - Deeply-typed system messages: Recursive
FlattenKeysutility type generates a union of every valid dot-notation path for compile-time safety. - Key generation convention: All translation-key generators follow a predictable
{type}.{sourceId}pattern derived from model element metadata.
