import type { ReactiveController, ReactiveControllerHost } from 'lit'; /** * In-house localization for the built-in UI strings the elements ship (button * labels, "Loading", toolbar names…). Deliberately tiny and dependency-free: * * - A `Map` registry of translations keyed by lowercased `$code`. * - A pure `resolveTerm()` (no DOM) so the registry/fallback logic is unit- * testable in plain Node — this is also what guarantees SSR safety: importing * this module, or any element, never touches `document`/`window` at module * scope, and `resolveTerm` returns correct English with no DOM present. * - A `LocalizeController` (Lit ReactiveController) that resolves the active * language from the closest `[lang]` ancestor and re-renders connected * elements when ``/`` changes, via ONE lazily-created * MutationObserver (created in `hostConnected`, which only runs in a browser). * * Consumers activate a locale with a side-effect import, e.g. * `import 'luxen-ui/translations/fr'`. English is always bundled as the fallback. * * Precedence: an explicit consumer-provided label (host `aria-label`, a prop) * always wins — elements only fall back to a localized default when nothing was * supplied. */ /** Direction of a locale's script. */ export type Direction = 'ltr' | 'rtl'; /** * The full term catalog. New terms added later MUST be optional (`?`) so existing * community locales keep working and fall back to English per-term. Plurals and * interpolation are plain functions per locale (no ICU/MessageFormat). */ export interface LuxenTranslation { /** BCP-47 code, e.g. `en`, `fr`, `fr-CA`. */ $code: string; /** Human-readable name, e.g. `English`, `Français`. */ $name: string; /** Script direction. */ $dir: Direction; loading: string; close: string; previousSlide: string; nextSlide: string; toggleFullscreen: string; goToSlide: (n: number) => string; showPassword?: string; increaseValue: string; decreaseValue: string; rangeMinimum?: string; rangeMaximum?: string; clear?: string; noResults?: string; selectOption?: string; suggestions?: string; richTextEditor: string; formatting: string; heading1: string; heading2: string; heading3: string; bold: string; italic: string; underline: string; strikethrough: string; highlight: string; bulletList: string; orderedList: string; blockquote: string; codeBlock: string; horizontalRule: string; link: string; emoji: string; attachFile: string; undo: string; redo: string; stories: string; storyProgress: string; previousStory: string; nextStory: string; mute: string; unmute: string; } /** A localizable term key — every `LuxenTranslation` field except the metadata ones. */ export type TermKey = keyof Omit; /** Register (or replace) a locale. Idempotent; keyed by lowercased `$code`. */ export declare function registerTranslation(...translations: LuxenTranslation[]): void; /** Resolve a locale: exact (`fr-ca`) → primary subtag (`fr`) → English. */ export declare function getTranslation(lang: string): LuxenTranslation; /** * Pure term resolution — no DOM, safe to call in Node. Per-term fallback to * English when a registered locale omits an (optional) term. */ export declare function resolveTerm(lang: string, key: K, ...args: LuxenTranslation[K] extends (...a: infer A) => string ? A : []): string; type LocalizeHost = ReactiveControllerHost & HTMLElement; /** * Attach to a Lit element to read localized terms. Re-renders the host when the * document language/direction changes. * * ```ts * private _localize = new LocalizeController(this); * // …in render(): * html`