# @comvi/core/loader

API reference for @comvi/core/loader: loader(map), attachLoader, createImportMapLoader, acquireLoaderApi and the members the loader capability adds to the i18n instance.

Canonical: https://comvi.io/docs/i18n/api/core-loader

The loader capability fetches catalogs on demand. Compose it with `.use(loader(map))` or
`.use(attachLoader)` on a [`@comvi/core`](/docs/i18n/api/core) instance.

## Exports

- Values: `loader`, `attachLoader`, `createImportMapLoader`, `acquireLoaderApi`.
- Types: `LoaderImportMap`, `LoaderImportResult`, `AcquiredLoaderApi`, `I18nLoaderApi`,
`LoaderFn`, `LoaderResult`.

## `loader(importMap)`

```ts
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`

```ts

export const i18n = createI18n({ locale: 'en' }).use(
loader({
    en: () => import('./locales/en.json'),
    'en:admin': () => import('./locales/en/admin.json'),
}),
);
```

## `attachLoader(i18n)`

```ts
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`

```ts

export const i18n = createI18n({ locale: 'en' }).use(attachLoader);

i18n.registerLoader(async (locale, namespace) => {
const res = await fetch(`/locales/${locale}/${namespace}.json`);
return res.json();
});
```

## `createImportMapLoader(map, getDefaultNs)`

```ts
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()`.

## `acquireLoaderApi(i18n)`

```ts
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.

## `I18nLoaderApi`

The members the capability adds to the i18n instance.

```ts
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.

## Read next

- [`@comvi/core`](/docs/i18n/api/core): the i18n instance this capability composes onto.
- [Load translations on demand](/docs/i18n/loading-translations): strategies, namespace activation and cache behaviour.
- [Fetch loader](/docs/i18n/plugins/fetch-loader): the CDN and API loader plugins built on this capability.
