Files
2026-06-09 21:06:27 +01:00

19 KiB

@suaveplan/i18n - Internationalization core: message catalog, ICU-like interpolation, pluralization, locale resolution, middleware, date/currency formatting.

Summary

Slim integration core for the i18n family. After the Wave 6 modular split, this package owns the MessageCatalog, the createI18n / I18nInstance plugin slot, the locale negotiation/resolver, the server middleware, the observability state, the schemas, the key/translation utilities, and the default FormatBridge that wires the per-formatter packages into the universal ICU parser. Everything else — constants, error codes, the ICU parser itself, the interpolation engine, the pluralization engine, every formatter, the locale detector chain, and the translation backends — lives in a sibling package and is re-exported here for back-compat.

Works in Bun, Node.js, and modern browsers (zero DOM dependencies).

Documentation tree

  • catalog — (no submodules)
  • plugin — (no submodules)
  • negotiation — (no submodules)
  • resolver — (no submodules)
  • server — (no submodules)
  • backend-metrics — OpenTelemetry instruments for the Backend plugin family. Every concrete backend (MemoryBackend, HttpBackend, `Sto…
  • detector-metrics — This module hosts the OTel instruments and an in-memory test ring for the locale-detector chain. The instruments live h…
  • metrics — @suaveplan/i18n/observability/metrics is the package's instrumentation surface. It exposes a lazily-built singleton h…
  • format-bridge-default — (no submodules)
  • missing-key-reporter — A development-time plugin that subscribes to the missingKey event on an I18nInstance and forwards every miss to a l…
  • pseudo-localize — Layout-stress transform for translated strings. Three modes deliberately produce non-translated output that exercises f…
  • schemas — (no submodules)
  • utils — (no submodules)
    • utils — (no submodules)
- [catalog](./src/core/catalog/catalog.md) — _(no submodules)_- [plugin](./src/core/plugin/instance.md) — _(no submodules)_- [instance](./src/core/plugin/instance.md) — _(no submodules)_- [negotiation](./src/locale/negotiation/negotiation.md) — _(no submodules)_- [negotiation](./src/locale/negotiation/negotiation.md) — _(no submodules)_- [resolver](./src/locale/resolver/resolver.md) — _(no submodules)_- [resolver](./src/locale/resolver/resolver.md) — _(no submodules)_- [server](./src/middleware/server/server.md) — _(no submodules)_- [server](./src/middleware/server/server.md) — _(no submodules)_- [backend-metrics](./src/observability/backend-metrics.md) — OpenTelemetry instruments for the `Backend` plugin family. Every concrete backend (`MemoryBackend`, `HttpBackend`, `Sto…
  • detector-metrics — This module hosts the OTel instruments and an in-memory test ring for the locale-detector chain. The instruments live h…
  • metrics — @suaveplan/i18n/observability/metrics is the package's instrumentation surface. It exposes a lazily-built singleton h…
  • format-bridge-default — (no submodules)- format-bridge-default — (no submodules)- missing-key-reporter — A development-time plugin that subscribes to the missingKey event on an I18nInstance and forwards every miss to a l…
  • pseudo-localize — Layout-stress transform for translated strings. Three modes deliberately produce non-translated output that exercises f…
  • schemas — (no submodules)- i18n.schemas — (no submodules)- utils — (no submodules)- utils — (no submodules)- catalog — (no submodules)- plugin — (no submodules)- instance — (no submodules)- negotiation — (no submodules)- negotiation — (no submodules)- resolver — (no submodules)- resolver — (no submodules)- server — (no submodules)- server — (no submodules)- backend-metrics — OpenTelemetry instruments for the Backend plugin family. Every concrete backend (MemoryBackend, HttpBackend, `Sto…
  • detector-metrics — This module hosts the OTel instruments and an in-memory test ring for the locale-detector chain. The instruments live h…
  • metrics — @suaveplan/i18n/observability/metrics is the package's instrumentation surface. It exposes a lazily-built singleton h…
  • format-bridge-default — (no submodules)- format-bridge-default — (no submodules)- missing-key-reporter — A development-time plugin that subscribes to the missingKey event on an I18nInstance and forwards every miss to a l…
  • pseudo-localize — Layout-stress transform for translated strings. Three modes deliberately produce non-translated output that exercises f…
  • schemas — (no submodules)- i18n.schemas — (no submodules)- utils — (no submodules)- utils — (no submodules)- catalog — (no submodules)- plugin — (no submodules)- instance — (no submodules)- negotiation — (no submodules)- negotiation — (no submodules)- resolver — (no submodules)- resolver — (no submodules)- server — (no submodules)- server — (no submodules)- backend-metrics — OpenTelemetry instruments for the Backend plugin family. Every concrete backend (MemoryBackend, HttpBackend, `Sto…
  • detector-metrics — This module hosts the OTel instruments and an in-memory test ring for the locale-detector chain. The instruments live h…
  • metrics — @suaveplan/i18n/observability/metrics is the package's instrumentation surface. It exposes a lazily-built singleton h…
  • format-bridge-default — (no submodules)- format-bridge-default — (no submodules)- missing-key-reporter — A development-time plugin that subscribes to the missingKey event on an I18nInstance and forwards every miss to a l…
  • pseudo-localize — Layout-stress transform for translated strings. Three modes deliberately produce non-translated output that exercises f…
  • schemas — (no submodules)- i18n.schemas — (no submodules)- utils — (no submodules)- utils — (no submodules)- catalog — (no submodules)- plugin — (no submodules) - instance — (no submodules)- negotiation — (no submodules) - negotiation — (no submodules)- resolver — (no submodules) - resolver — (no submodules)- server — (no submodules) - server — (no submodules)- backend-metrics — OpenTelemetry instruments for the Backend plugin family. Every concrete backend (MemoryBackend, HttpBackend, `Sto…
  • detector-metrics — This module hosts the OTel instruments and an in-memory test ring for the locale-detector chain. The instruments live h…
  • metrics — @suaveplan/i18n/observability/metrics is the package's instrumentation surface. It exposes a lazily-built singleton h…
  • format-bridge-default — (no submodules) - format-bridge-default — (no submodules)- missing-key-reporter — A development-time plugin that subscribes to the missingKey event on an I18nInstance and forwards every miss to a l…
  • pseudo-localize — Layout-stress transform for translated strings. Three modes deliberately produce non-translated output that exercises f…
  • schemas — (no submodules) - i18n.schemas — (no submodules)- utils — (no submodules) - utils — (no submodules)

Modules in the slim core

Module Path Description
Catalog src/core/catalog/ MessageCatalog, deepMerge — namespaced + lazy-loaded translations
Plugin src/core/plugin/ createI18n, I18nInstance — facade with plugin slot + post-processors
Locale negotiation src/locale/negotiation/ negotiateLocale, parseAcceptLanguage — RFC 4647 lookup
Locale resolver src/locale/resolver/ LocaleResolver, extractLanguage, extractRegion, normalizeLocaleCode, isValidBcp47 — strategy-based resolver with BCP-47 validation
Server middleware src/middleware/server/ createLocaleMiddleware, detectLocale, getDirection
Observability src/observability/ Detector + backend metrics state + OTel adapters
Schemas src/schemas/ CatalogOptionsSchema, InterpolationConfigSchema, ResolverConfigSchema, TranslationRecordSchema
Utilities src/utils/ buildKey, countKeys, flattenRecord, getNestedValue, getTextDirection, hasKey, isRtl, parseKey, sanitize, unflattenRecord
Default FormatBridge src/parser/format-bridge-default/ Wires the formatter packages into MessageParser.format
Subpath shims src/subpaths/ Forwarders for the four kept back-compat subpaths

Re-exports from sibling packages

Every symbol the pre-split monolith exposed continues to resolve from @suaveplan/i18n. The source of each symbol is now a sibling package:

Capability Sibling package
Constants (locale descriptors, RTL set, BCP-47 map, defaults) @suaveplan/i18n-shared
Error registry (I18N_CODES, I18nError, I18nErrorCode) @suaveplan/i18n-shared
ICU parser (MessageParser, renderNodes, AST node types) @suaveplan/i18n-icu-parser
Interpolation (InterpolationEngine, escapeHtmlChars, escapeRegex) @suaveplan/i18n-icu-parser
Pluralization (9 CLDR rules, PluralizationEngine, getBaseLocale) @suaveplan/i18n-icu-parser
Number formatting (formatNumber, helpers, observability) @suaveplan/i18n-formatter-number
Currency formatting (formatCurrency, formatCurrencyValue, info helpers) @suaveplan/i18n-formatter-currency
Date / time formatting (formatDate, formatTime, formatDateOnly, formatDateRange, getDayNames, getMonthNames) @suaveplan/i18n-formatter-date
Relative time (formatRelativeTime, selectRelativeUnit, helpers) @suaveplan/i18n-formatter-relative-time
List formatting (formatList, formatConjunction, formatDisjunction) @suaveplan/i18n-formatter-list
Display name formatting (formatDisplayName, language/region/script helpers) @suaveplan/i18n-formatter-display-name
Locale detection chain (createDetectorChain, every detector factory, direction helpers) @suaveplan/i18n-detector
Memory backend @suaveplan/i18n-backend-memory
HTTP backend @suaveplan/i18n-backend-http
Storage-backed backend @suaveplan/i18n-backend-storage
Chained backend @suaveplan/i18n-backend-chained
Filesystem multi-file backend (server-tier — NOT re-exported at root) @suaveplan/i18n-backend-fs-multifile

Collator (@suaveplan/i18n-formatter-collator) and Segmenter (@suaveplan/i18n-formatter-segmenter) are not currently re-exported at the root — consumers import directly from the leaf packages. Add them to src/index.ts if cross-package call-sites stabilise.

Subpaths

Four subpaths are kept indefinitely for back-compat with downstream consumers (@suaveplan/react-i18n, react-ui, react-forms):

Subpath Forwards to
@suaveplan/i18n/detector @suaveplan/i18n-detector
@suaveplan/i18n/parser @suaveplan/i18n-icu-parser
@suaveplan/i18n/plugin local core/plugin/instance.ts
@suaveplan/i18n/errors @suaveplan/i18n-shared

New consumers SHOULD import directly from the sibling package for tighter tree-shaking.

Quick start

import { createI18n, defaultFormatBridge, MessageParser } from "@suaveplan/i18n";

const i18n = createI18n({
    defaultLocale: "en",
    fallbackLocale: "en",
    messages: {
        en: { greeting: "Hello, {name}!" },
        fr: { greeting: "Bonjour, {name} !" },
    },
});

i18n.t("greeting", { values: { name: "world" } });
// "Hello, world!"

// ICU placeholders are rendered through the default FormatBridge
// when consumers reach for the parser directly:
const parser = new MessageParser();
const parsed = parser.parse("Total: {amount, number, currency/USD}");
const formatted = parsed.format(
    { amount: 49.99 },
    { locale: "en-US", formatBridge: defaultFormatBridge }
);
// "Total: $49.99"

Custom FormatBridge

The slim core's defaultFormatBridge covers every method on the FormatBridge contract by delegating to the formatter packages. Consumers MAY override individual methods (or build a no-Intl bridge via noopFormatBridge):

import { defaultFormatBridge, noopFormatBridge } from "@suaveplan/i18n";
import type { FormatBridge } from "@suaveplan/i18n";

const customBridge: FormatBridge = {
    ...defaultFormatBridge,
    relativeTime: () => "(some other language)",
};

Bundle size (post-slim, 2026-05-09)

  • dist/ total: 592 KB
  • dist/index.js: 4.76 KB (1.60 KB gzip) — pure barrel
  • Heaviest module: dist/core/catalog/catalog.js at 17.52 KB (5.48 KB gzip)
  • 15 modules in the build output (was ~120 pre-Wave-6)

Status

  • 320 tests in the slim core (bunx turbo test --filter=@suaveplan/i18n) — green
  • Coverage: 100/100/100/100 on the surviving modules (Istanbul)
  • Downstream sweep (bunx turbo test --filter='@suaveplan/react-*'): 40 tasks green, 1238 tests in react-ui alone