import type { IlingoOptions } from './options'; import type { IStore } from './store'; import type { Fallback, GetContext, IIlingo, Leaf, MissingKeyHandler } from './types'; import type { Formatter } from './utils'; import { FormatterRegistry } from './utils'; export declare class Ilingo implements IIlingo { /** * Registered stores, keyed by a `symbol` identity. Insertion order is * preserved (it drives the serial intra-locale store walk — earlier * registrations are consulted first) and the symbol key is how * registration deduplicates (see {@link registerStore}). * * Use `Symbol.for('@scope/pkg')` as the key for library catalogs so a * duplicate package copy (pnpm / peer-dep mismatch) resolves to the * same identity and re-registration stays a no-op. */ readonly stores: Map; protected locale: string; protected fallback: Fallback | undefined; protected onMissingKey: MissingKeyHandler | undefined; protected pluralRulesCache: Map; /** * Per-instance registry for `{{value, formatter(opts)}}` template * modifiers. Built-in entries: `number`, `date`, `list` (each backed * by the matching `Intl.*Format`, memoised by `(locale, options)`). */ formatters: FormatterRegistry; /** * Per-instance set of `(locale, namespace, key)` triples that have already * triggered a missing-key warning. Kept on the instance — not module * scope — so multiple `Ilingo` instances do not dedupe each other's * warnings. */ protected warnedKeys: Set; /** * Mirror of `warnedKeys` for unknown-formatter diagnostics. */ protected warnedFormatters: Set; constructor(input?: IlingoOptions); /** * Register a store, keyed by its own `store.id` identity. * * Idempotent: if a store is already registered under `store.id`, this * is a no-op and the existing store is kept. Library catalogs set * `id` to a `Symbol.for('@scope/pkg')` (e.g. `createMemoryStore()` / * `createLoaderStore()` from `@ilingo/validup`), so re-registering — * even from a duplicate package copy — never stacks duplicates. * Anonymous stores default to a fresh `Symbol(...)`, so each is always * added. * * Insertion order drives the serial intra-locale store walk, so a * store registered earlier is consulted first and wins per key. To * override individual keys of a library catalog, register your own * store before registering the library's. */ registerStore(store: IStore): void; /** * Register a custom formatter for use inside `{{value, name(opts)}}` * placeholders. Equivalent to `this.formatters.register(name, fn)` — * exposed as an instance method for discoverability and parity with * `setLocale` / `merge` / `clone`. * * @example * ilingo.registerFormatter('upper', (value, _opts, locale) => * String(value).toLocaleUpperCase(locale)); * await ilingo.get({ * namespace: 'app', key: 'shout', * data: { name: 'peter' }, * }); * // "{{name, upper}}" → "PETER" */ registerFormatter(name: string, formatter: Formatter): void; /** * Build a new `Ilingo` that inherits this instance's configuration * (locale, fallback, missing-key handler), shares its formatter * registry, and includes its stores in order. The new instance is * independent — mutating its `stores` does not affect the parent — * but the shared `formatters` registry means custom formatters * registered on either side are visible to both. * * `overrides.store`, when provided, becomes the **first** store(s) in * the new instance (resolved before any inherited store; an array is * registered in order). Other overrides replace the corresponding * inherited config field. * * `overrides.formatters`, when provided, is registered on the shared * registry — visible to both the parent and the child (consistent with * the registry-sharing design). Callers that need formatter isolation * should construct manually instead of cloning. * * Designed for consumers that need a scoped variant of an existing * orchestrator — e.g. `@ilingo/vue`'s `useScopedCatalog`. */ clone(overrides?: IlingoOptions): IIlingo; /** * Fold another instance's stores into this one, deduping by symbol * identity. A foreign store whose key is already present is skipped * (the existing store wins); foreign keys not present here are appended * in order. Library catalogs keyed by `Symbol.for('@scope/pkg')` thus * never stack across a merge, while anonymously-keyed stores (minted * `Symbol()`) are always distinct and so always carried over. */ merge(instance: IIlingo): void; setLocale(key: string): void; resetLocale(): void; getLocale(): string; getLocales(): Promise; /** * Locale chain that would be tried for the given context, in order. */ getResolvedLocaleChain(ctx: Pick): string[]; /** * Which locale in the chain actually yielded a value for the given * `(namespace, key)`, or `undefined` if the key is missing in every locale. */ getResolvedLocale(ctx: GetContext): Promise; get(ctx: GetContext): Promise; /** * The post-lookup half of `get()`: pick the plural form for `ctx.count`, * auto-merge `count` into the interpolation data (so `{{count}}` works * without restating it), and substitute `{{var}}` placeholders against * the *resolved* locale. */ protected render(leaf: Leaf, locale: string, ctx: GetContext): string; /** * Walk the locale chain in order. Within each locale, query stores * serially in insertion order and stop at the first hit. * * Locale-first composition: the closer locale always beats the farther * one, regardless of which store would have answered. Within a single * locale, a store is only consulted when every earlier store has * missed — so a network-backed adapter registered after a Memory * adapter is never called when the Memory adapter hits. */ protected lookup(chain: string[], ctx: Pick): Promise<{ locale: string; leaf: Leaf; } | undefined>; /** * Run the configured `onMissingKey` (or the built-in warn-once default) * and return whatever it produces. */ protected handleMissingKey(ctx: GetContext, requestedLocale: string, chain: string[]): string | undefined; /** * Pick the matching plural form for `count`. Pass-through when the leaf * is already a string. Falls back to `other` if the selected category * isn't present. */ protected selectPluralForm(leaf: Leaf, locale: string, count: number | undefined): string; protected getPluralRules(locale: string): Intl.PluralRules; /** * Substitute `{{var}}` placeholders. Modifier syntax * (`{{var, number(currency=EUR)}}`) is dispatched through * `this.formatters`. The optional `locale` argument controls which * locale `Intl.*Format` instances are constructed for; if omitted, the * instance's current locale is used. */ format(input: string, data: Record, locale?: string): string; protected handleUnknownFormatter(name: string): void; }