{"version":3,"file":"create-i18n.cjs","names":[],"sources":["../../src/i18n/create-i18n.ts"],"sourcesContent":["import { dateTimeFormat, numberFormat } from \"@/utils/intl-cache\";\nexport type Messages = Record<string, string>;\nexport type Catalog = Record<string, Messages>;\nexport type InterpolationValues = Record<string, string | number>;\n\nexport interface CreateI18nOptions {\n    /** Initial locale. */\n    locale: string;\n    /** Fallback locale used when a key is missing in the active locale. */\n    fallbackLocale?: string;\n    /** Catalog `{ [locale]: { [key]: \"...\" } }`. */\n    messages: Catalog;\n}\n\n/** Per-call options for {@link I18n.t} and {@link I18n.plural}. */\nexport interface TranslateOptions {\n    /**\n     * Text to use when the catalog defines neither the key nor its fallback.\n     *\n     * Without this, a miss returns the key, and a caller that wants its own text\n     * instead has to *detect* the miss — which from the outside means comparing\n     * the result against the key it just passed in. That heuristic is wrong for a\n     * catalog that legitimately maps a key to itself, and it is what every\n     * translatable string the SDK ships would otherwise have to copy.\n     *\n     * Interpolated like any other message, so a default carries `{placeholders}`\n     * too and is not second-class.\n     */\n    default?: string;\n}\n\nexport interface I18n {\n    /** Currently active locale. */\n    locale: string;\n    /** Fallback locale (or `null` when not configured). */\n    fallbackLocale: string | null;\n    /**\n     * Translate `key`, interpolating `{name}` placeholders from `params`.\n     * Falls back to the configured fallback locale, then to `options.default`,\n     * then to the key itself.\n     */\n    t: (key: string, params?: InterpolationValues, options?: TranslateOptions) => string;\n    /**\n     * Plural-aware translation. Tries `${key}_one` for `count === 1` and\n     * `${key}_other` otherwise, with `{count}` available for interpolation.\n     * Falls back to `options.default`, then to the key itself.\n     */\n    plural: (\n        key: string,\n        count: number,\n        params?: InterpolationValues,\n        options?: TranslateOptions,\n    ) => string;\n    /** Format a number using `Intl.NumberFormat` on the active locale. */\n    formatNumber: (value: number, options?: Intl.NumberFormatOptions) => string;\n    /** Format a Date using `Intl.DateTimeFormat` on the active locale. */\n    formatDate: (value: Date | string, options?: Intl.DateTimeFormatOptions) => string;\n    /** Build a new `I18n` instance pointing at a different locale. */\n    withLocale: (locale: string) => I18n;\n}\n\nfunction interpolate(template: string, params?: InterpolationValues): string {\n    if (!params) return template;\n    return template.replace(/\\{(\\w+)\\}/g, (_match, name: string) => {\n        const value = params[name];\n        return value === undefined ? `{${name}}` : String(value);\n    });\n}\n\nfunction lookup(\n    catalog: Catalog,\n    locale: string,\n    fallback: string | null,\n    key: string,\n): string | null {\n    const direct = catalog[locale]?.[key];\n    if (direct !== undefined) return direct;\n    if (fallback) {\n        const fallbackValue = catalog[fallback]?.[key];\n        if (fallbackValue !== undefined) return fallbackValue;\n    }\n    return null;\n}\n\n/**\n * Create an i18n object with translation, pluralization and Intl helpers.\n *\n * The catalog is a plain `{ [locale]: { [key]: \"...\" } }` map — bring your\n * own keys, namespaces, or nested-key conventions. The SDK does not enforce\n * a schema so you can plug it into any string-loading pipeline.\n *\n * @example\n * const i18n = createI18n({\n *     locale: \"pt-BR\",\n *     fallbackLocale: \"en\",\n *     messages: {\n *         \"pt-BR\": {\n *             \"greet\": \"Olá, {name}\",\n *             \"alos_one\": \"{count} Alô\",\n *             \"alos_other\": \"{count} Alôs\",\n *         },\n *         \"en\": { greet: \"Hi, {name}\", alos_one: \"{count} Alo\", alos_other: \"{count} Alos\" },\n *     },\n * });\n * i18n.t(\"greet\", { name: \"Mau\" });          // \"Olá, Mau\"\n * i18n.plural(\"alos\", 3);                     // \"3 Alôs\"\n *\n * @example\n * // A key the catalog does not define, with text to show instead of the key.\n * i18n.t(\"cart.empty\", undefined, { default: \"Seu carrinho está vazio\" });\n */\nexport function createI18n(options: CreateI18nOptions): I18n {\n    const { locale, fallbackLocale = null, messages } = options;\n\n    function t(key: string, params?: InterpolationValues, options?: TranslateOptions): string {\n        const template = lookup(messages, locale, fallbackLocale, key) ?? options?.default;\n        if (template === undefined) return key;\n        return interpolate(template, params);\n    }\n\n    function plural(\n        key: string,\n        count: number,\n        params?: InterpolationValues,\n        options?: TranslateOptions,\n    ): string {\n        const suffix = count === 1 ? \"_one\" : \"_other\";\n        const template =\n            lookup(messages, locale, fallbackLocale, `${key}${suffix}`) ??\n            lookup(messages, locale, fallbackLocale, key) ??\n            options?.default;\n        if (template === undefined) return key;\n        return interpolate(template, { count, ...(params ?? {}) });\n    }\n\n    function formatNumber(value: number, opts?: Intl.NumberFormatOptions): string {\n        return numberFormat(locale, opts).format(value);\n    }\n\n    function formatDate(value: Date | string, opts?: Intl.DateTimeFormatOptions): string {\n        const date = typeof value === \"string\" ? new Date(value) : value;\n        if (Number.isNaN(date.getTime())) return \"\";\n        return dateTimeFormat(locale, opts).format(date);\n    }\n\n    return {\n        locale,\n        fallbackLocale,\n        t,\n        plural,\n        formatNumber,\n        formatDate,\n        withLocale: (nextLocale) =>\n            createI18n({\n                locale: nextLocale,\n                fallbackLocale: fallbackLocale ?? undefined,\n                messages,\n            }),\n    };\n}\n"],"mappings":"2CA6DA,SAAS,EAAY,EAAkB,EAAsC,CAEzE,OADK,EACE,EAAS,QAAQ,cAAe,EAAQ,IAAiB,CAC5D,IAAM,EAAQ,EAAO,GACrB,OAAO,IAAU,IAAA,GAAY,IAAI,EAAK,GAAK,OAAO,CAAK,CAC3D,CAAC,EAJmB,CAKxB,CAEA,SAAS,EACL,EACA,EACA,EACA,EACa,CACb,IAAM,EAAS,EAAQ,EAAO,GAAG,GACjC,GAAI,IAAW,IAAA,GAAW,OAAO,EACjC,GAAI,EAAU,CACV,IAAM,EAAgB,EAAQ,EAAS,GAAG,GAC1C,GAAI,IAAkB,IAAA,GAAW,OAAO,CAC5C,CACA,OAAO,IACX,CA6BA,SAAgB,EAAW,EAAkC,CACzD,GAAM,CAAE,SAAQ,iBAAiB,KAAM,YAAa,EAEpD,SAAS,EAAE,EAAa,EAA8B,EAAoC,CACtF,IAAM,EAAW,EAAO,EAAU,EAAQ,EAAgB,CAAG,GAAK,GAAS,QAE3E,OADI,IAAa,IAAA,GAAkB,EAC5B,EAAY,EAAU,CAAM,CACvC,CAEA,SAAS,EACL,EACA,EACA,EACA,EACM,CAEN,IAAM,EACF,EAAO,EAAU,EAAQ,EAAgB,GAAG,IAFjC,IAAU,EAAI,OAAS,UAEwB,GAC1D,EAAO,EAAU,EAAQ,EAAgB,CAAG,GAC5C,GAAS,QAEb,OADI,IAAa,IAAA,GAAkB,EAC5B,EAAY,EAAU,CAAE,QAAO,GAAI,GAAU,CAAC,CAAG,CAAC,CAC7D,CAEA,SAAS,EAAa,EAAe,EAAyC,CAC1E,OAAO,EAAA,aAAa,EAAQ,CAAI,CAAC,CAAC,OAAO,CAAK,CAClD,CAEA,SAAS,EAAW,EAAsB,EAA2C,CACjF,IAAM,EAAO,OAAO,GAAU,SAAW,IAAI,KAAK,CAAK,EAAI,EAE3D,OADI,OAAO,MAAM,EAAK,QAAQ,CAAC,EAAU,GAClC,EAAA,eAAe,EAAQ,CAAI,CAAC,CAAC,OAAO,CAAI,CACnD,CAEA,MAAO,CACH,SACA,iBACA,IACA,SACA,eACA,aACA,WAAa,GACT,EAAW,CACP,OAAQ,EACR,eAAgB,GAAkB,IAAA,GAClC,UACJ,CAAC,CACT,CACJ"}