# Setup & loaders

> Provide `WrI18n` plus one of the two catalog loaders — static (inline objects) or HTTP (fetched JSON). The active locale persists in `WrStorage` between reloads.

Source: https://ngwr.dev/guides/translations/setup  
Kind: Service

## What is in the box

One entry point per locale, so an app pays only for the languages it imports. Every one of them is held to the English key set by a test, and none of them can ship a value that lost a placeholder.

| Import from | Export | Language |
| --- | --- | --- |
| `ngwr/i18n/ar` | `wrAr` | العربية — Arabic |
| `ngwr/i18n/cs` | `wrCs` | čeština — Czech |
| `ngwr/i18n/de` | `wrDe` | Deutsch — German |
| `ngwr/i18n/en` | `wrEn` | English — English |
| `ngwr/i18n/es` | `wrEs` | español — Spanish |
| `ngwr/i18n/fr` | `wrFr` | français — French |
| `ngwr/i18n/he` | `wrHe` | עברית — Hebrew |
| `ngwr/i18n/hi` | `wrHi` | हिन्दी — Hindi |
| `ngwr/i18n/id` | `wrId` | Indonesia — Indonesian |
| `ngwr/i18n/it` | `wrIt` | italiano — Italian |
| `ngwr/i18n/ja` | `wrJa` | 日本語 — Japanese |
| `ngwr/i18n/ko` | `wrKo` | 한국어 — Korean |
| `ngwr/i18n/nl` | `wrNl` | Nederlands — Dutch |
| `ngwr/i18n/pl` | `wrPl` | polski — Polish |
| `ngwr/i18n/pt` | `wrPt` | português — Portuguese |
| `ngwr/i18n/ru` | `wrRu` | русский — Russian |
| `ngwr/i18n/sv` | `wrSv` | svenska — Swedish |
| `ngwr/i18n/tr` | `wrTr` | Türkçe — Turkish |
| `ngwr/i18n/uk` | `wrUk` | українська — Ukrainian |
| `ngwr/i18n/vi` | `wrVi` | Tiếng Việt — Vietnamese |
| `ngwr/i18n/zh` | `wrZh` | 中文 — Chinese |
| `ngwr/i18n/zh-TW` | `wrZhTw` | 中文（台灣） — Chinese (Taiwan) |

Codes are LANGUAGES wherever a language is one thing, because the resolver truncates a region to its language and not the other way round: a `pt-BR` or `de-AT``LOCALE_ID` finds `pt` and `de` on its own, while a bare `de` would never reach a `de-DE` catalog. A region appears only where the writing system genuinely differs — `zh` is Simplified, which is also what `zh-CN` and `zh-Hans` fall back to, and `zh-TW` is Traditional. `zh-HK` and `zh-Hant` would land on Simplified by that rule, so map those to `zh-TW` yourself if you ship there.

## Static loader

Inline the catalogs at bootstrap. Best for small apps or when SSR-rendered translations are critical. Pass only your own keys: ngwr's go in underneath, as base catalogs.

```angular-ts
import { provideHttpClient } from '@angular/common/http';
import {
  provideWrI18n,
  provideWrI18nBaseCatalogs,
  provideWrI18nStaticLoader,
} from 'ngwr/i18n';
import { wrEn } from 'ngwr/i18n/en';
import { wrRu } from 'ngwr/i18n/ru';

bootstrapApplication(AppComponent, {
  providers: [
    provideHttpClient(),
    provideWrI18n({
      defaultLocale: 'en',
      availableLocales: ['en', 'ru'],
    }),
    // ngwr's strings, looked up key by key underneath yours. Not a
    // `{ ...wrEn, ...yours }` spread: it is shallow, so any namespace you share
    // with ngwr, e.g. `common`, `validation`, `table`, keeps only one side's keys.
    provideWrI18nBaseCatalogs({ en: wrEn, ru: wrRu }),
    provideWrI18nStaticLoader({
      en: { app: { title: 'My app' } },
      ru: { app: { title: 'Моё приложение' } },
    }),
  ],
});
```

## HTTP loader

Fetch catalogs on demand. The `{locale}` token is interpolated; pair with `registerScope` to lazy-load feature catalogs.

```angular-ts
provideWrI18nHttpLoader({
  path: '/assets/i18n/{locale}.json',
  // Optional — different template for scoped catalogs:
  // rootPath: '/assets/i18n/root/{locale}.json',
});

// Then per-feature lazy load:
i18n.registerScope('checkout');
// → fetches /assets/i18n/checkout/{locale}.json
```

## Keep ngwr's own strings

A loader replaces the catalog for a locale rather than extending it, so a catalog holding only your keys leaves every built-in label on its hardcoded English fallback — with nothing logged to point at it. `provideWrI18nBaseCatalogs()` registers ngwr's catalogs as a floor underneath the loader: your keys still win, and you only pay for the locales you list. It is also the answer to merging by hand: `{ ...wrRu, ...yours }` is shallow, so any namespace you share with ngwr, e.g. `common`, `validation`, `table`, keeps only the side spread last, and the other side's keys stop resolving with nothing logged — ngwr's components fall back to English and a `wrT` read of a lost key renders the raw key. A base catalog is looked up key by key, so both halves survive.

```angular-ts
// A loader REPLACES the catalog for a locale, it does not extend it — so a
// JSON file holding only your own keys would leave every ngwr built-in label
// on its hardcoded English fallback, silently.
//
// Register the shipped catalogs as a BASE and they fill in underneath:
import { provideWrI18n, provideWrI18nBaseCatalogs, provideWrI18nHttpLoader } from 'ngwr/i18n';
import { wrRu } from 'ngwr/i18n/ru';

bootstrapApplication(AppComponent, {
  providers: [
    provideHttpClient(),
    provideWrI18n({ defaultLocale: 'ru', availableLocales: ['ru'] }),
    provideWrI18nBaseCatalogs({ ru: wrRu }),   // <- the one line
    provideWrI18nHttpLoader({ path: '/assets/i18n/{locale}.json' }),
  ],
});

// Your /assets/i18n/ru.json now only needs YOUR keys. Yours always win;
// the base is a floor, not an override. Pass only the locales you ship —
// the rest stay out of the bundle.
//
// Prefer plain files? The same catalogs are published as JSON:
//   node_modules/ngwr/i18n/{en,ru}.json
```

## Missing-key handler

Override the default (returns the key) to surface gaps in the catalog during development.

```angular-ts
provideWrI18n({
  defaultLocale: 'en',
  availableLocales: ['en', 'ru'],
  missingHandler: (key) => '⚠️ ' + key,
});
```
