import { Readable, Writable } from "@embra/reactivity";

//#region src/detect-lang.d.ts
/**
 * Get browser/nodejs language
 *
 * @returns BCP 47 tags of the browser/nodejs language
 */
declare function detectLang(): string;
/**
 * Get browser/nodejs language that matches the given language tags
 *
 * @param langs The language tags to match (BCP 47 tags and sub-tags are supported)
 * @returns The first language tag that matches the browser/nodejs language, or `null` if no match
 *
 * @example
 * ```js
 * detectLang(["en", "zh-CN"]) || "zh-TW"
 * ```
 */
declare function detectLang<T extends string>(langs: readonly T[]): T | null;
declare function detectLang(langs: readonly string[]): string | null;
//#endregion
//#region src/interface.d.ts
type LocaleLang = string;
type LocaleLangObservable = Readable<LocaleLang>;
type Locale = {
  readonly [key: string]: string | Locale;
};
type Locales = {
  readonly [lang: LocaleLang]: Locale;
};
type TFunctionArgs = {
  readonly [key: string | number]: any;
  /**
   * Modifier matching.
   * @see {@link https://github.com/embrajs/i18n#modifier-matching}
   */
  readonly "@"?: string | number;
};
/**
 * @param keyPath Dot-separated key path to the locale message, e.g. `"a.b.c"`
 * @param args Optional arguments for interpolation
 * @returns locale message or `keyPath` if not found
 */
type TFunction = (keyPath: string, args?: TFunctionArgs) => string;
type TFunctionObservable = Readable<TFunction>;
type LocaleFetcher = (lang: LocaleLang) => Promise<Locale> | Locale;
//#endregion
//#region src/i18n.d.ts
interface I18nOptions {
  /** Fetch locale of the specified lang. */
  fetcher?: LocaleFetcher;
  /** Fallback language if the current language doesn't have the requested key. */
  fallback?: LocaleLang;
}
declare class I18n {
  /** Fetch locale of `initialLang` and return an I18n instance with the locale. */
  static preload(initialLang: LocaleLang, fetcher: LocaleFetcher, options?: Omit<I18nOptions, "fetcher">): Promise<I18n>;
  /** A {@link Readable} of current lang. */
  readonly lang$: Readable<LocaleLang>;
  /** Current lang. */
  get lang(): LocaleLang;
  /** A {@link Readable} of current translate function. */
  readonly t$: Readable<TFunction>;
  /** Translation function that uses the current `t$` function. */
  readonly t: TFunction;
  /** Fetch locale of the specified lang. */
  fetcher?: LocaleFetcher;
  /** A {@link Writable} of all loaded locales. */
  readonly locales$: Writable<Locales>;
  /** All loaded locales. */
  get locales(): Locales;
  /** A {@link Readable} of current locale. */
  readonly locale$: Readable<Locale>;
  /** Current locale */
  get locale(): Locale;
  constructor(initialLang: LocaleLang, locales: Locales, options?: I18nOptions);
  /**
   * Change language.
   *
   * @returns — a promise that resolves when the new locale is fetched.
   */
  switchLang(lang: LocaleLang): Promise<void>;
  /**
   * @returns — boolean indicating whether a message with the specified key in current language exists or not.
   */
  hasKey(key: string): boolean;
  /**
   * Add a locale to the locales.
   *
   * Use `i18n.locales$.set()` for more control.
   */
  addLocale(lang: LocaleLang, locale: Locale): void;
  dispose(): void;
}
//#endregion
export { I18n, I18nOptions, Locale, LocaleFetcher, LocaleLang, LocaleLangObservable, Locales, TFunction, TFunctionArgs, TFunctionObservable, detectLang };