/** * Generic i18n machinery shared by the widget and the dashboard. * * Each package owns its `Translations` interface (their key sets differ) and * its locale dictionaries; everything else — locale normalization, the * custom-locale registry, lazy loading of built-ins, the translate-function * factory, interpolation — is identical and lives here once. * * The `loaders` map is typed `Record, …>`: the * moment a locale code is added to {@link BUILTIN_LOCALES}, every consuming * package fails to compile until its loader entry (and therefore its * dictionary file) exists. Adding a locale cannot silently fall back to * English anymore. */ import { type BuiltinLocale } from "./types.cjs"; /** * Lazy dictionary loaders for every non-English built-in locale. Use static * `() => import("./xx.cjs").then((m) => m.xx)` thunks — bundlers keep * emitting one chunk per locale, and only the requested one ships. */ export type LocaleLoaders = Record, () => Promise>; /** Translate function over the message catalog `T`. */ export type TranslateFunction = (key: keyof T & string) => string; /** The i18n API returned by {@link createI18n}. */ export interface I18n { /** * Create a translation function for the given locale. * * Locale resolution: exact language match > English fallback, per key. * Non-English built-in locales are lazy-loaded via `loadLocale` — call * `await loadLocale(locale)` at init if you want the UI to render in the * target language immediately; until the dictionary lands, keys resolve * to English. */ createT(locale: string): TranslateFunction; /** * Dynamically import a built-in locale and register it. Returns the * loaded dictionary, or `null` if the locale isn't a known built-in. * Custom locales registered via `registerLocale` bypass this loader — * they are already in the registry (and are returned as registered, so a * partial custom dictionary comes back partial). */ loadLocale(locale: string): Promise | null>; /** * Register a custom locale at runtime. Partial dictionaries are welcome — * missing keys fall back to English per key, so overriding a single * string never requires copying the whole catalog. */ registerLocale(code: string, translations: Partial): void; } /** * `locale` as `Intl` accepts it. Locale options take any string, and a * backend-style tag (`fr_FR` from PHP / WordPress) makes every `Intl` * constructor and `toLocale*` call throw a RangeError: `_` reads as `-`, and * a tag `Intl` still rejects falls back to English, as `createT` does. * Silent, so it is safe on a render path; see `canonicalizeLocale` for the * one-time, warning variant. */ export declare function intlLocale(locale: string): string; /** * The host's locale tag as `Intl` accepts it. `SitepingLocale` takes any * string, and PHP / WordPress hand out POSIX-style tags (`fr_FR`, `pt_BR`) * that every `Intl` constructor rejects with a RangeError: `_` becomes `-`, * then the tag is canonicalised (`fr-FR`). Falls back to `"en"`, with a * warning, only when the tag is still invalid (empty, garbage) — meant to run * once, where the config is read. */ export declare function canonicalizeLocale(locale: string): string; /** * Build the i18n machinery for one message catalog. * * @param en — the complete English catalog, bundled synchronously as the fallback. * @param loaders — lazy import thunks for every other built-in locale. */ export declare function createI18n>(en: T, loaders: LocaleLoaders): I18n; /** * Interpolate `{paramName}` placeholders in a translated string with the * values from `params`. Stringifies numbers and booleans inline so callers * can pass `t("marker.count")` along with `{ count: 3 }` directly. * * Unknown placeholders are left as-is. */ export declare function interpolate(template: string, params: Readonly>): string; /** Shorthand for `interpolate(t(key), params)` — key-checked against the catalog. */ export declare function tWithParams(t: (key: K) => string, key: K, params: Readonly>): string;