Skip to content
Comvi

@comvi/core/loader

View .md

The loader capability fetches catalogs on demand. Compose it with .use(loader(map)) or .use(attachLoader) on a @comvi/core instance.

  • Values: loader, attachLoader, createImportMapLoader, acquireLoaderApi.
  • Types: LoaderImportMap, LoaderImportResult, AcquiredLoaderApi, I18nLoaderApi, LoaderFn, LoaderResult.
function loader(importMap: LoaderImportMap): <T extends I18n<any>>(i18n: T) => T & I18nLoaderApi
type LoaderImportMap = Record<string, () => Promise<LoaderImportResult>>
type LoaderImportResult = LoaderResult | { default: LoaderResult }

Attaches the capability and registers createImportMapLoader(map). The map is required; a missing map throws E_LOADER_IMPORT_MAP (the production message; development builds throw a longer one). Keys are 'locale' (the default namespace, read live) or 'locale:namespace'. Attaching is idempotent. Composing after init() warns in development, because init() has already loaded its namespaces and does not run again for the new loader.

src/loader-map.ts
import { createI18n } from '@comvi/core';
import { loader } from '@comvi/core/loader';
export const i18n = createI18n({ locale: 'en' }).use(
loader({
en: () => import('./locales/en.json'),
'en:admin': () => import('./locales/en/admin.json'),
}),
);
function attachLoader<T extends I18n<any>>(i18n: T): T & I18nLoaderApi

The attach-only installer, for an app that registers a LoaderFn itself.

src/loader-fn.ts
import { createI18n } from '@comvi/core';
import { attachLoader } from '@comvi/core/loader';
export const i18n = createI18n({ locale: 'en' }).use(attachLoader);
i18n.registerLoader(async (locale, namespace) => {
const res = await fetch(`/locales/${locale}/${namespace}.json`);
return res.json();
});
function createImportMapLoader(importMap: LoaderImportMap, getDefaultNs: () => string): LoaderFn
type LoaderFn = (locale: string, namespace: string) => Promise<LoaderResult>
type LoaderResult = Record<string, TranslationValue>

Wraps an import map as a LoaderFn for registerLoader().

function acquireLoaderApi(instance: WrapperI18nInstance): AcquiredLoaderApi
interface AcquiredLoaderApi {
addActiveNamespace(namespace: string): Promise<void>;
addActiveNamespaces(namespaces: string[]): Promise<void>;
removeActiveNamespace(namespace: string): void;
removeActiveNamespaces(namespaces: string[]): void;
reloadMessages(locale?: string, namespace?: string): Promise<void>;
onLoadError(cb: (locale: string, namespace: string, error: Error) => void): () => void;
}

The component-facing slice behind every binding’s useI18nLoader(). It throws missingCapability('loader'), in development and production, when the instance has no loader. The result is cached per instance, so callers share function identities.

The members the capability adds to the i18n instance.

registerLoader(loader: LoaderFn): void
getLoader(): LoaderFn | undefined
reloadMessages(locale?: string, namespace?: string): Promise<void>
addActiveNamespace(namespace: string): Promise<void>
addActiveNamespaces(namespaces: string[]): Promise<void>
removeActiveNamespace(namespace: string): void
removeActiveNamespaces(namespaces: string[]): void
onLoadError(cb: (locale: string, namespace: string, error: Error) => void): () => void
Member Meaning
registerLoader(fn) Takes a function only; a later call replaces the earlier one
getLoader() The registered loader, or undefined
reloadMessages(l?, ns?) Drops matching cache entries and refetches. Defaults: current locale plus fallbacks, every active namespace. Rejects with no loader, or when every locale in the set failed. With nothing active it falls back to the default namespace and warns in development
addActiveNamespace(ns) Activates and loads for the current locale and for each locale of the fallback chain; emits configChanged with source 'namespaceActivated'
addActiveNamespaces(ns[]) Same, for several
removeActiveNamespace(ns) Deactivates and cancels pending loads. Synchronous; cached content stays until clearMessages(undefined, ns). Emits configChanged with source 'namespaceDeactivated'
removeActiveNamespaces(ns[]) Same, for several
onLoadError(cb) Typed subscription to loadError; returns an unsubscribe

reloadMessages() fetches every locale in its set in parallel and rejects only when all of them failed. One failed fallback locale out of three is reported through onLoadError and the call still resolves.

With the capability composed, setLocale() loads the active namespaces for the target locale before applying it.