Source snapshot bcc79fcc · Declared package version 3.0.4. This page combines the checked-in package guide and manifest; commands and runtime behavior were not executed in this review.
Framework-independent runtime for ContractSpec translation contracts.
Static catalog diagnostics, translation validation (including ICU, readability, keyword density and locale validation), and tenant override declarations are available from ./contracts/diagnostics, ./contracts/validation, and
./contracts/tenant. Historical ContractSpec imports forward to the same implementations. Static diagnostics retain their distinct contract namespace; the existing runtime ./diagnostics API is unchanged. Private source partitions preserve validation ordering, issue codes, defaults and the nominal
TranslationRegistry and TranslationValidationError identities.
@lssm-tech/lib.contracts-spec-core/translations/spec remains the canonical source of truth for TranslationSpec contracts, metadata, ownership, versions, locale variants, validation, fallback declarations, and override policy. This package consumes those specs at runtime to resolve, format, cache, load, diagnose, and serialize translations across server code, React, React Native, CLIs, and tests.
create() resolves the requested locale within supportedLocales ("fr-FR" falls back to "fr", then to defaultLocale), so keep that list aligned with the locale of each catalog. A missing message falls back to the catalog's declared fallback locale, then to the key itself. Root catalogs declare no fallback; only variants point at their parent locale.
t() interpolates {placeholder} values only. Format ICU messages (plural, select, selectordinal, number, date) with the formatter engine:
Removed in 1.0.0. The createTranslationRuntime engine, its ./runtime, ./registry and ./runtime-helpers subpaths, and the preference override-layer builders (createTranslationRuntimeFromPreferences and related helpers) no longer exist. Migrate render paths to createI18nFactory. resolveTranslationPreferenceContext (./preferences) still resolves app, workspace, team, user and request locale precedence.
SSR and hydration
The factory stack produces a versioned, framework-neutral I18nFactoryHydrationPayload that never aliases live catalog references:
ts
import {
createI18nFactory,
createI18nFactoryFromHydrationPayload,
} from "@lssm-tech/lib.translation-runtime/contracts/i18n-factory";
// Server (RSC / route handler)
const factory = createI18nFactory({
specKey: "cart.messages",
catalogs: [cartEn, cartFr, cartEs],
supportedLocales: ["en", "fr", "es"],
defaultLocale: "en",
});
const payload = factory.hydrationPayload(requestLocale);
// Transfer payload to the client (inline script, RSC stream, etc.)
// Client: rehydrate without refetching or renegotiating locale
const hydrated = createI18nFactoryFromHydrationPayload(payload);
hydrated.create(payload.snapshot.locale).t("cart.greeting", { name: "Alice" });
The payload carries only the catalogs for the resolved locale and its declared fallback chain. createI18nFactoryFromHydrationPayload rebuilds the factory with the default en/fr/es locale set and en default, so create the client instance with payload.snapshot.locale and keep catalog locales within that set when you rehydrate.
validateI18nFactorySnapshot(snapshot) and validateI18nFactoryHydrationPayload(payload) return human-readable error strings for partial or unknown payloads before hydration.
The ./snapshot helpers (createTranslationHydrationPayload, createTranslationSnapshotStreamChunk, validateTranslationHydrationPayload) serialize a host-assembled TranslationRuntimeSnapshot, which the i18next adapter can consume. createTranslationSnapshotStreamChunk(snapshot) returns a cloned payload that is safe to enqueue before later async catalog loads; validateTranslationHydrationPayload(payload) returns invalid_snapshot diagnostics for unsupported payloads.
Shard-scoped catalog loading
src/loader.ts accepts an optional specKeys? array on TranslationBundleLoadRequest to load a subset of catalogs per route. Use loadShardDelta to fetch only the incremental shards needed on navigation:
Optimization surfaces (Model A — per-request inline payload)
Scope: per-request inline HTML reduction. Catalogs remain bundled and cached in the JS bundle (shipped once per deploy). These optimizations reduce the per-request inline <script> hydration payload — NOT total transferred bytes. The ~90% total-bytes win requires Model B (catalog code-splitting + load-bearing inline payload). See .omc/plans/ralplan-translation-catalog-sharding-ssr.md § "Optimization Wave — ARCHITECTURE DECISION: Model A".
O2/O3 — Slim inline payload + value-pool dedup
Enable slim mode on your scoped hydration builder to strip spec metadata from each shard before serialization. The value-pool dedup step folds message values appearing ≥2× into a values[] pool; expansion is automatic on rehydration.
Realized:/ en 96.6 KB → 37.8 KB (−61%); /companyos/founder en 93.9 KB → 35.6 KB (−62%); fr routes ~−60%. No-flash (AC1) re-proven through slim+dedup path. CI budget gates: single-locale ≤ 64 KB, with-fallback ≤ 128 KB.
O3 adds only ~2% over O2 (five lanes have disjoint key namespaces; ~53 pooled value strings). The projected ~41 KB en-fallback win requires a shared-base architecture follow-up.
At bundle build time, call buildPrecompiledIcuCatalogFromSpecs(specs) from @lssm-tech/lib.translation-runtime/precompile over your TranslationSpec[] set. This produces a PrecompiledIcuCatalog with FormatJS IR AST entries for every message. Pass createPrecompiledIcuLookup(catalog) as the precompiled option to createIntlMessageFormatter to activate the parse-skip fast-path:
ts
// build step (runs once at bundle time, e.g. in your bundler plugin)
import {
buildPrecompiledIcuCatalogFromSpecs,
createPrecompiledIcuLookup,
serializePrecompiledIcuCatalog,
} from "@lssm-tech/lib.translation-runtime/precompile";
const catalog = buildPrecompiledIcuCatalogFromSpecs([enMessages, frMessages]);
// optionally serialize and ship as a build asset
const serialized = serializePrecompiledIcuCatalog(catalog);
// runtime (wire the formatter with the precompiled lookup)
import { parsePrecompiledIcuCatalog, createPrecompiledIcuLookup } from "@lssm-tech/lib.translation-runtime/precompile";
import { createIntlMessageFormatter } from "@lssm-tech/lib.translation-runtime/formatters/intl-messageformat";
const precompiled = createPrecompiledIcuLookup(parsePrecompiledIcuCatalog(serialized));
const formatter = createIntlMessageFormatter({ precompiled });
// formatter skips ICU re-parsing for any message with a precompiled entry
Additive opt-in — messages without a precompiled entry fall back to the standard parser transparently. Scope: formatter-path latency win only. Factory proof routes use {placeholder} interpolation (no ICU); O4 benefits apply to ICU-heavy catalogs (plural/select/date/number).
O5b (#17) — Scoped-hydration intersection (wired, currently no-op)
App-layer wiring — not a translation-runtime export.intersectScopedI18nHydration and isEffectiveReachabilityMap are implemented in web-application-monolith's scoped hydration path (packages/apps/web-application-monolith/src/i18n/scoped-hydration.reachability.ts and reachability-map.loader.ts). They compose with the loader's loadShardDelta but are not themselves library APIs. Do not import them from @lssm-tech/lib.translation-runtime.
Wired into getRequestI18n and fail-safe (pruned keys resolve via the bundled combined runtime — no flash). Currently no-op (77/129 t() call sites use dynamic dispatch; scanner emits retain-all map). Auto-activates if a precise reachability map ships. Zero regression.
@lssm-tech/tool.i18n-prune in packages/tools/ walks t('key') call sites against a RouteShardManifest and reports dead keys per route. Use it in CI to surface dead-key drift. It does not drive the runtime inline payload under Model A.
Optional i18next adapter
i18next is an optional downstream adapter, not the canonical ContractSpec model. Import it through the dedicated subpath so core runtime consumers do not load i18next:
The adapter exports resources as { [locale]: { [namespace]: { [messageKey]: string } } }. TranslationSpec.locale becomes the i18next language, while the namespace defaults to the stable TranslationSpec.meta.key. Flat ContractSpec keys such as "cart.items" remain flat because generated init options set keySeparator: false.
ContractSpec ICU messages are exported intact. i18next does not use ICU as its default JSON format, so apps that call i18next.t() for ICU plural/select/selectordinal messages must install and configure an ICU-capable i18next format plugin such as i18next-icu. The adapter reports i18next_icu_plugin_required unless you explicitly acknowledge that formatting layer.
Utiliser exportTranslationSnapshotToI18next(snapshot) when the host already assembles a TranslationRuntimeSnapshot (./snapshot); it carries the snapshot locale, default locale and fallback chain into the init options. For SSR, export from the same catalogs and locale used by the server render and reuse those resources/options on the client. Do not let client-only language detection renegotiate the first hydrated render. For React Native, pass the host-selected locale explicitly; the adapter does not use DOM APIs or browser storage.
React Native
The core runtime uses no DOM APIs. Locale detection is host-owned; pass the device or user locale to factory.create(locale), or negotiate it first with negotiateLocale({ requestedLocales, supportedLocales, defaultLocale }) from ./locale. Ensure the host JS engine provides the required Intl APIs or install platform polyfills before using the default formatter.
Compatible factory and registry ownership
The registry and BCP 47 contract helpers live in this package under ./contracts/registry and ./contracts/locale. The pure package i18n factory and its hydration snapshot are owned by Core (@lssm-tech/lib.contracts-spec-core/translations/i18n-factory and ./translations/i18n-factory-snapshot), so domain specs can use them; ./contracts/i18n-factory and ./contracts/i18n-factory-snapshot here forward those same implementations, with unchanged resolution. Historical ContractSpec translation imports forward these same implementations. The existing runtime root and locale exports retain their names and behavior; use the explicit contract subpaths for the factory stack. Translation declarations come from @lssm-tech/lib.contracts-spec-core/translations/spec.
Translation catalog model ownership
The unchanged Locale, MessageKey, TranslationEntry,
TranslationCatalogMeta, PlatformTranslationCatalog and
BlueprintTranslationCatalog declarations are canonical at
@lssm-tech/lib.translation-runtime/contracts/catalog. Historical
@lssm-tech/lib.contracts-spec/translations/catalog imports forward these same declarations. The model move adds no loading, formatting or runtime initialization behavior; Core continues to own TranslationSpec.
These are package-manifest entry points. Named symbols listed above come from the capability catalogue; this is not an exhaustive TypeScript symbol reference.