Service

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.

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 fromExportLanguage
ngwr/i18n/arwrAr العربية — Arabic
ngwr/i18n/cswrCs čeština — Czech
ngwr/i18n/dewrDe Deutsch — German
ngwr/i18n/enwrEn English — English
ngwr/i18n/eswrEs español — Spanish
ngwr/i18n/frwrFr français — French
ngwr/i18n/hewrHe עברית — Hebrew
ngwr/i18n/hiwrHi हिन्दी — Hindi
ngwr/i18n/idwrId Indonesia — Indonesian
ngwr/i18n/itwrIt italiano — Italian
ngwr/i18n/jawrJa 日本語 — Japanese
ngwr/i18n/kowrKo 한국어 — Korean
ngwr/i18n/nlwrNl Nederlands — Dutch
ngwr/i18n/plwrPl polski — Polish
ngwr/i18n/ptwrPt português — Portuguese
ngwr/i18n/ruwrRu русский — Russian
ngwr/i18n/svwrSv svenska — Swedish
ngwr/i18n/trwrTr Türkçe — Turkish
ngwr/i18n/ukwrUk українська — Ukrainian
ngwr/i18n/viwrVi Tiếng Việt — Vietnamese
ngwr/i18n/zhwrZh 中文 — Chinese
ngwr/i18n/zh-TWwrZhTw 中文(台灣) — 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-ATLOCALE_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.

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.

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.

// 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.

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