import type { I18nError, I18nMissingKey, Locale, PackageTranslations, PluralParams, TranslationLoader, TranslationOptions, TranslationParams, Translations } from './types.js'; import { isLocaleSupported } from './types.js'; /** * Module-global translation **registry** — the static, request-identical half of * the old `I18nService`. * * It holds only read-only translation *data* (package bundles, the global * mirror, loaded/loading status) and stateless resolution logic. Every resolver * takes the active `locale`/`fallbackLocale` as **explicit arguments** instead of * reading a stored value, so a single module-global instance is safe to share * across SSR requests: there is no mutable per-request state here. The mutable * locale lives in the request-scoped {@link I18nState} context instead. * * The data fields stay reactive (`SvelteMap`/`SvelteSet`/`$state`) so that a * package registering or a locale chunk loading *after* first render still * invalidates the `$derived` expressions that read them — but those mutations are * idempotent and identical for every request, so they cannot leak request state. */ export declare class I18nRegistry { private packageTranslations; private translations; private loadedLocales; private loadingLocales; private translationLoaders; private packageLoaders; private loadingPackageLocales; private pluralRulesCache; private numberFormatCache; /** * Optional error sink. Set once by the app (e.g. via the provider) so loader * failures surface somewhere; defaults to `console.warn`. */ onError?: (error: I18nError) => void; /** * Optional missing-key sink. Set once by the app via `configureI18n`. Unlike * `onError` there is NO default `console.warn`: a provider-less, read-tolerant * render legitimately misses keys, so warning on every miss would be noise. * Opt-in only — the loud signal for "this key resolved nowhere" when a consumer * wants it (dev overlay, telemetry, a test collector). Fires exactly once per * resolved-nowhere `translate` call, just before the key-as-itself fallback. */ onMissingKey?: (info: I18nMissingKey) => void; get registeredPackages(): string[]; get isLoading(): boolean; private reportError; private reportMissingKey; registerPackage(packageName: string, translations: PackageTranslations): void; registerTranslationLoader(locale: Locale, loader: TranslationLoader): void; /** * Register a per-package lazy loader for one locale (WP4 code-splitting). The * loader returns that package's bundle for `locale` (typically * `() => import('./translations/de').then((m) => m.default)`), kept out of the * initial chunk until the locale is activated. */ registerPackageLoader(packageName: string, locale: Locale, loader: () => Promise): void; /** * Additively register one locale's already-loaded bundle for a package — the * synchronous, eager counterpart to {@link loadPackageLocale}. * * Unlike {@link registerPackage} (which `.set`s the *whole* package entry and so * drops any sibling locale already registered), this **merges** the single * locale into the existing entry, preserving the eager base bundle. That makes * it the correct primitive for an eager-register escape hatch: a consumer that * has passed a locale as a lazy `loader` can register its imported bundle up * front (e.g. once at SSR/app start) so the very first server render already * resolves that locale — no fallback-locale flash, no hydration text mismatch — * instead of waiting for the provider's client-only on-mount chunk load. * * A fresh object reference is written so the reactive SvelteMap notifies * `$derived` readers (an in-place mutation would not). Idempotent-friendly: * re-registering the same locale simply overwrites it with identical data. */ registerPackageLocale(packageName: string, locale: Locale, data: Translations): void; hasLoader(locale: Locale): boolean; isLoaded(locale: Locale): boolean; private loaderKeyLocale; addTranslations(locale: Locale, translations: Translations): void; /** * Load every lazy bundle registered for `locale` — the legacy global loader and * all per-package loaders — merging each into the (reactive) registry so that * `$derived` reads re-resolve once the chunks arrive. Idempotent: bundles * already present (eager or previously loaded) are skipped. Returns `false` if * any triggered load rejected. */ loadLocale(locale: Locale): Promise; private loadGlobalLocale; /** * Load one package's bundle for `locale` via its registered loader and merge it * into the package map (so the package-scoped hook lookup finds it) and the * global mirror. Idempotent; no-op when the bundle is already present or no * loader is registered. */ loadPackageLocale(packageName: string, locale: Locale): Promise; /** * Whether `locale` has any resolvable data (eager or already lazily loaded). * Used by the request-scoped state to decide if switching to it is safe even * when its loader rejected. */ hasTranslations(locale: Locale): boolean; translate(key: string, locale: Locale, fallbackLocale: Locale, params?: TranslationParams, options?: TranslationOptions | string): string; pluralize(key: string, params: PluralParams, locale: Locale, fallbackLocale: Locale, options?: TranslationOptions): string; private getPluralRule; private interpolate; private getNestedParam; private getPackageTranslation; private getTranslation; private deepMerge; getAvailableLocales(): Locale[]; getPackageLocales(packageName: string): Locale[]; hasPackage(packageName: string): boolean; getPackageTranslations(packageName: string): Partial> | undefined; exists(key: string, locale: Locale, packageName?: string): boolean; formatNumber(value: number, locale: Locale, options?: Intl.NumberFormatOptions): string; formatDate(date: Date, locale: Locale, options?: Intl.DateTimeFormatOptions): string; formatRelativeTime(value: number, unit: Intl.RelativeTimeFormatUnit, locale: Locale): string; formatTimeAgo(date: Date, locale: Locale, fallbackLocale: Locale): string; /** Re-exported for callers that need the guard without importing from types. */ isLocaleSupported: typeof isLocaleSupported; reportLoadError(error: I18nError): void; } export declare function getRegistry(): I18nRegistry;