API REFERENCE · UTILITIES
@dojo-ng/i18n
Locale, formatting, and translated messages for Dojo NG components.
There is no provider element. A component reads lang and dir from its nearest ancestor that sets them, then from the document, then from the default locale.
npm install @dojo-ng/i18n
Register French strings for the dj namespace, then set lang. Components on the page re-render in French.
<dj-alert closable>Enregistré.</dj-alert>
<script type="module">
import "@dojo-ng/alert";
import { messages } from "@dojo-ng/i18n";
messages.register("dj", "fr", { close: "Fermer" });
document.documentElement.lang = "fr";
</script>
Locale and direction
getLocale(el)andgetDir(el)return the locale and direction that apply to an element. They also look outside shadow roots.LocaleControllerkeeps a Lit component'slocaleanddircurrent, and re-renders the component when either one changes.setDefaultLocale()sets the locale to use when nolangis found. The default isen.- Only changes to
langanddirin the light DOM are observed. That is where they are usually set.
Formatting
formatDate,formatNumber,formatList, andpluraluse the nativeIntlAPIs and take an explicit locale.- The
Intlobjects are cached by locale and options, because they are slow to create. format(template, params)fills{name}placeholders.
Messages
messagesis the sharedMessageStore. It keeps message bundles by namespace and locale.- A lookup tries the locale, then its base language, then the default locale, then
en. For example,fr-CAtriesfr-ca, thenfr, thenen. - Every component registers its English strings under
en, so it always has labels, even with no translations loaded. - The built-in component strings use the
djnamespace. - Register translations before the components render, or before you change
lang. Registering messages does not re-render components that are already on the page.
Loaders
staticLoader(data)serves bundles that you include at build time.fetchLoader(pattern)fetches one JSON file for each namespace and locale. The default pattern is/i18n/{ns}.{locale}.json.- For your own transport or cache, write an object with a
load(namespace, locale)method that returns a promise of messages.
Examples
Load translations from JSON files
Set a loader, load the bundle, then switch lang.
import { messages, fetchLoader } from "@dojo-ng/i18n";
messages.setLoader(fetchLoader("/i18n/{ns}.{locale}.json"));
await messages.load("dj", "de"); // fetches /i18n/dj.de.json
document.documentElement.lang = "de";
Format in your own component
LocaleController gives the component its locale and re-renders it when lang changes.
import { LitElement, html } from "lit";
import { LocaleController, formatDate, plural } from "@dojo-ng/i18n";
class VisitSummary extends LitElement {
static properties = { when: { attribute: false }, count: { type: Number } };
#i18n = new LocaleController(this);
render() {
const { locale } = this.#i18n;
return html`${formatDate(this.when, locale, { dateStyle: "medium" })}:
${plural(locale, this.count, { one: "{count} visit", other: "{count} visits" })}`;
}
}
customElements.define("visit-summary", VisitSummary);
Functions
clearIntlCache
function clearIntlCache(): void;
fetchLoader
function fetchLoader(pattern?: string): MessageLoader;
format
function format(template: string, params?: FormatParams): string;
getDefaultLocale
function getDefaultLocale(): string;
getDir
function getDir(el?: Element | null): "ltr" | "rtl";
getLocale
function getLocale(el?: Element | null): string;
localeChain
function localeChain(locale: string, fallback?: string): string[];
onLocaleChange
function onLocaleChange(listener: Listener): () => void;
plural
function plural(locale: string, count: number, forms: Partial<Record<Intl.LDMLPluralRule, string>>): string;
registerDefaults
function registerDefaults(namespace: string, defaults: Messages): void;
setDefaultLocale
function setDefaultLocale(locale: string): void;
staticLoader
function staticLoader(data: Record<string, Record<string, Messages>>): MessageLoader;
Classes
LocaleController
class LocaleController implements ReactiveController {
locale: string;
dir: "ltr" | "rtl";
constructor(host: ReactiveControllerHost & HTMLElement);
hostConnected(): void;
hostDisconnected(): void;
}
MessageStore
class MessageStore {
constructor(loader?: MessageLoader);
setLoader(loader: MessageLoader | undefined): void;
get version(): number;
register(namespace: string, locale: string, messages: Messages): void;
has(namespace: string, locale: string): boolean;
get(namespace: string, locale: string, key: string): string | undefined;
resolve(namespace: string, locale: string, key: string, params?: FormatParams): string | undefined;
load(namespace: string, locale: string): Promise<void>;
}
Values
collator
const collator: (locale: string, opts?: Intl.CollatorOptions) => Intl.Collator;
dateTimeFormat
const dateTimeFormat: (locale: string, opts?: Intl.DateTimeFormatOptions) => Intl.DateTimeFormat;
displayNames
const displayNames: (locale: string, opts: Intl.DisplayNamesOptions) => Intl.DisplayNames;
formatDate
const formatDate: (value: Date | number | string, locale: string, opts?: Intl.DateTimeFormatOptions) => string;
formatList
const formatList: (items: string[], locale: string, opts?: Intl.ListFormatOptions) => string;
formatNumber
const formatNumber: (value: number, locale: string, opts?: Intl.NumberFormatOptions) => string;
listFormat
const listFormat: (locale: string, opts?: Intl.ListFormatOptions) => Intl.ListFormat;
messages
const messages: MessageStore;
numberFormat
const numberFormat: (locale: string, opts?: Intl.NumberFormatOptions) => Intl.NumberFormat;
pluralRules
const pluralRules: (locale: string, opts?: Intl.PluralRulesOptions) => Intl.PluralRules;
relativeTimeFormat
const relativeTimeFormat: (locale: string, opts?: Intl.RelativeTimeFormatOptions) => Intl.RelativeTimeFormat;
Types
FormatParams
type FormatParams = Record<string, string | number>;
MessageLoader
interface MessageLoader {
namespaces?(): Promise<string[]>;
load(namespace: string, locale: string): Promise<Messages>;
}
Messages
type Messages = Record<string, string>;