@intlayer/core 8.5.2 → 8.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/formatters/compact.cjs +1 -1
- package/dist/cjs/formatters/compact.cjs.map +1 -1
- package/dist/cjs/formatters/currency.cjs +1 -1
- package/dist/cjs/formatters/currency.cjs.map +1 -1
- package/dist/cjs/formatters/date.cjs +1 -1
- package/dist/cjs/formatters/date.cjs.map +1 -1
- package/dist/cjs/formatters/index.cjs +1 -1
- package/dist/cjs/formatters/list.cjs +1 -1
- package/dist/cjs/formatters/list.cjs.map +1 -1
- package/dist/cjs/formatters/number.cjs +1 -1
- package/dist/cjs/formatters/number.cjs.map +1 -1
- package/dist/cjs/formatters/percentage.cjs +2 -2
- package/dist/cjs/formatters/percentage.cjs.map +1 -1
- package/dist/cjs/formatters/relativeTime.cjs +1 -1
- package/dist/cjs/formatters/relativeTime.cjs.map +1 -1
- package/dist/cjs/formatters/units.cjs +1 -1
- package/dist/cjs/formatters/units.cjs.map +1 -1
- package/dist/cjs/index.cjs +17 -9
- package/dist/cjs/interpreter/getContent/getContent.cjs +1 -1
- package/dist/cjs/interpreter/getContent/getContent.cjs.map +1 -1
- package/dist/cjs/interpreter/getContent/index.cjs +1 -0
- package/dist/cjs/interpreter/getContent/plugins.cjs +20 -9
- package/dist/cjs/interpreter/getContent/plugins.cjs.map +1 -1
- package/dist/cjs/interpreter/index.cjs +1 -0
- package/dist/cjs/interpreter/splitAndJoinInsertion.cjs +10 -35
- package/dist/cjs/interpreter/splitAndJoinInsertion.cjs.map +1 -1
- package/dist/cjs/localization/generateSitemap.cjs +111 -0
- package/dist/cjs/localization/generateSitemap.cjs.map +1 -0
- package/dist/cjs/localization/getBrowserLocale.cjs +1 -1
- package/dist/cjs/localization/getBrowserLocale.cjs.map +1 -1
- package/dist/cjs/localization/getLocale.cjs +2 -2
- package/dist/cjs/localization/getLocale.cjs.map +1 -1
- package/dist/cjs/localization/getLocalizedUrl.cjs +1 -1
- package/dist/cjs/localization/getPrefix.cjs +1 -1
- package/dist/cjs/localization/index.cjs +8 -7
- package/dist/cjs/localization/localeMapper.cjs +1 -1
- package/dist/cjs/transpiler/html/getHTMLCustomComponents.cjs +2 -3
- package/dist/cjs/transpiler/html/getHTMLCustomComponents.cjs.map +1 -1
- package/dist/cjs/utils/index.cjs +9 -3
- package/dist/cjs/utils/intl.cjs +88 -72
- package/dist/cjs/utils/intl.cjs.map +1 -1
- package/dist/cjs/utils/localeStorage.cjs +191 -64
- package/dist/cjs/utils/localeStorage.cjs.map +1 -1
- package/dist/esm/formatters/compact.mjs +2 -2
- package/dist/esm/formatters/compact.mjs.map +1 -1
- package/dist/esm/formatters/currency.mjs +2 -2
- package/dist/esm/formatters/currency.mjs.map +1 -1
- package/dist/esm/formatters/date.mjs +2 -2
- package/dist/esm/formatters/date.mjs.map +1 -1
- package/dist/esm/formatters/index.mjs +2 -2
- package/dist/esm/formatters/list.mjs +2 -2
- package/dist/esm/formatters/list.mjs.map +1 -1
- package/dist/esm/formatters/number.mjs +2 -2
- package/dist/esm/formatters/number.mjs.map +1 -1
- package/dist/esm/formatters/percentage.mjs +3 -3
- package/dist/esm/formatters/percentage.mjs.map +1 -1
- package/dist/esm/formatters/relativeTime.mjs +2 -2
- package/dist/esm/formatters/relativeTime.mjs.map +1 -1
- package/dist/esm/formatters/units.mjs +2 -2
- package/dist/esm/formatters/units.mjs.map +1 -1
- package/dist/esm/index.mjs +11 -11
- package/dist/esm/interpreter/getContent/getContent.mjs +1 -1
- package/dist/esm/interpreter/getContent/getContent.mjs.map +1 -1
- package/dist/esm/interpreter/getContent/index.mjs +2 -2
- package/dist/esm/interpreter/getContent/plugins.mjs +20 -10
- package/dist/esm/interpreter/getContent/plugins.mjs.map +1 -1
- package/dist/esm/interpreter/index.mjs +2 -2
- package/dist/esm/interpreter/splitAndJoinInsertion.mjs +10 -35
- package/dist/esm/interpreter/splitAndJoinInsertion.mjs.map +1 -1
- package/dist/esm/localization/generateSitemap.mjs +109 -0
- package/dist/esm/localization/generateSitemap.mjs.map +1 -0
- package/dist/esm/localization/getBrowserLocale.mjs +2 -2
- package/dist/esm/localization/getBrowserLocale.mjs.map +1 -1
- package/dist/esm/localization/getLocale.mjs +3 -3
- package/dist/esm/localization/getLocale.mjs.map +1 -1
- package/dist/esm/localization/getLocalizedUrl.mjs +1 -1
- package/dist/esm/localization/getPrefix.mjs +1 -1
- package/dist/esm/localization/index.mjs +7 -7
- package/dist/esm/localization/localeMapper.mjs +1 -1
- package/dist/esm/transpiler/html/getHTMLCustomComponents.mjs +2 -4
- package/dist/esm/transpiler/html/getHTMLCustomComponents.mjs.map +1 -1
- package/dist/esm/utils/index.mjs +4 -4
- package/dist/esm/utils/intl.mjs +87 -72
- package/dist/esm/utils/intl.mjs.map +1 -1
- package/dist/esm/utils/localeStorage.mjs +186 -65
- package/dist/esm/utils/localeStorage.mjs.map +1 -1
- package/dist/types/deepTransformPlugins/getFilterMissingTranslationsContent.d.ts +10 -10
- package/dist/types/deepTransformPlugins/getFilterMissingTranslationsContent.d.ts.map +1 -1
- package/dist/types/deepTransformPlugins/getFilterTranslationsOnlyContent.d.ts +10 -10
- package/dist/types/deepTransformPlugins/getFilterTranslationsOnlyContent.d.ts.map +1 -1
- package/dist/types/deepTransformPlugins/getFilteredLocalesContent.d.ts +10 -10
- package/dist/types/deepTransformPlugins/getFilteredLocalesContent.d.ts.map +1 -1
- package/dist/types/dictionaryManipulator/orderDictionaries.d.ts +2 -2
- package/dist/types/dictionaryManipulator/orderDictionaries.d.ts.map +1 -1
- package/dist/types/formatters/index.d.ts +2 -2
- package/dist/types/formatters/number.d.ts +4 -1
- package/dist/types/formatters/number.d.ts.map +1 -1
- package/dist/types/formatters/percentage.d.ts +4 -1
- package/dist/types/formatters/percentage.d.ts.map +1 -1
- package/dist/types/index.d.ts +5 -5
- package/dist/types/interpreter/getContent/getContent.d.ts.map +1 -1
- package/dist/types/interpreter/getContent/index.d.ts +2 -2
- package/dist/types/interpreter/getContent/plugins.d.ts +7 -1
- package/dist/types/interpreter/getContent/plugins.d.ts.map +1 -1
- package/dist/types/interpreter/index.d.ts +2 -2
- package/dist/types/interpreter/splitAndJoinInsertion.d.ts +0 -17
- package/dist/types/interpreter/splitAndJoinInsertion.d.ts.map +1 -1
- package/dist/types/localization/generateSitemap.d.ts +93 -0
- package/dist/types/localization/generateSitemap.d.ts.map +1 -0
- package/dist/types/localization/getBrowserLocale.d.ts +2 -2
- package/dist/types/localization/getBrowserLocale.d.ts.map +1 -1
- package/dist/types/localization/index.d.ts +2 -2
- package/dist/types/transpiler/html/getHTMLCustomComponents.d.ts.map +1 -1
- package/dist/types/utils/index.d.ts +3 -3
- package/dist/types/utils/intl.d.ts +15 -11
- package/dist/types/utils/intl.d.ts.map +1 -1
- package/dist/types/utils/localeStorage.d.ts +85 -68
- package/dist/types/utils/localeStorage.d.ts.map +1 -1
- package/package.json +8 -8
- package/dist/cjs/getStorageAttributes.cjs +0 -135
- package/dist/cjs/getStorageAttributes.cjs.map +0 -1
- package/dist/esm/getStorageAttributes.mjs +0 -133
- package/dist/esm/getStorageAttributes.mjs.map +0 -1
- package/dist/types/getStorageAttributes.d.ts +0 -29
- package/dist/types/getStorageAttributes.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getBrowserLocale.mjs","names":[],"sources":["../../../src/localization/getBrowserLocale.tsx"],"sourcesContent":["import configuration from '@intlayer/config/built';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { ENGLISH } from '@intlayer/types/locales';\nimport {\n
|
|
1
|
+
{"version":3,"file":"getBrowserLocale.mjs","names":[],"sources":["../../../src/localization/getBrowserLocale.tsx"],"sourcesContent":["import configuration from '@intlayer/config/built';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { ENGLISH } from '@intlayer/types/locales';\nimport {\n getLocaleFromStorageClient,\n type LocaleStorageClientOptions,\n} from '../utils/localeStorage';\nimport { localeDetector } from './localeDetector';\n\nexport enum LanguageDetector {\n Querystring = 'querystring',\n Storage = 'storage',\n Navigator = 'navigator',\n HtmlTag = 'htmlTag',\n}\n\nexport const localeStorageOptions: LocaleStorageClientOptions = {\n getCookie: (name: string) =>\n document.cookie\n .split(';')\n .find((c) => c.trim().startsWith(`${name}=`))\n ?.split('=')[1],\n getLocaleStorage: (name: string) => localStorage.getItem(name),\n getSessionStorage: (name: string) => sessionStorage.getItem(name),\n isCookieEnabled: true,\n setCookieStore: (name, value, attributes) =>\n cookieStore.set({\n name,\n value,\n path: attributes.path,\n domain: attributes.domain,\n expires: attributes.expires,\n sameSite: attributes.sameSite,\n }),\n setCookieString: (_name, cookie) => {\n // biome-ignore lint/suspicious/noDocumentCookie: set cookie fallback\n document.cookie = cookie;\n },\n setSessionStorage: (name, value) => sessionStorage.setItem(name, value),\n setLocaleStorage: (name, value) => localStorage.setItem(name, value),\n};\n\n// Default settings for the language detector\ntype LanguageDetectorOptions = {\n order?: LanguageDetector[];\n lookupQuerystring?: string;\n htmlTag?: HTMLElement | null;\n};\n\nconst getDefaultsOptions = (): LanguageDetectorOptions => {\n return {\n order: [\n LanguageDetector.Querystring,\n LanguageDetector.Storage,\n LanguageDetector.Navigator,\n LanguageDetector.HtmlTag,\n ],\n lookupQuerystring: 'locale',\n htmlTag: typeof document !== 'undefined' ? document.documentElement : null,\n };\n};\n\nconst detectLanguage = (\n order: string[],\n options: LanguageDetectorOptions\n): Record<LanguageDetector, Locale | undefined> => {\n const detected: Record<LanguageDetector, Locale | undefined> = {} as Record<\n LanguageDetector,\n Locale | undefined\n >;\n\n const queryStringDetector = () => {\n if (typeof window === 'undefined') return;\n const search = window.location.search || '';\n const params = new URLSearchParams(search);\n const value = params.get(options.lookupQuerystring ?? '');\n if (value) {\n detected[LanguageDetector.Querystring] = value as Locale;\n }\n };\n\n const storageDetector = () => {\n if (typeof window === 'undefined') return;\n\n const locale = getLocaleFromStorageClient({\n getCookie: (name: string) => {\n try {\n const cookies = document.cookie.split(';');\n const cookieName = `${name}=`;\n\n const cookie = cookies.find((cookie) =>\n cookie.trim().startsWith(cookieName)\n );\n\n if (cookie) {\n return cookie.split('=')[1].trim();\n }\n } catch {}\n return undefined;\n },\n getSessionStorage: (name: string) => {\n try {\n return window.sessionStorage.getItem(name) ?? undefined;\n } catch {}\n return undefined;\n },\n getLocaleStorage: (name: string) => {\n try {\n return window.localStorage.getItem(name) ?? undefined;\n } catch {}\n return undefined;\n },\n });\n\n if (locale) {\n detected[LanguageDetector.Storage] = locale;\n }\n };\n\n const navigatorDetector = () => {\n if (typeof navigator === 'undefined') return;\n\n const { internationalization } = configuration;\n const languages = navigator.languages ?? [navigator.language];\n\n // Use localeDetector to find the best matching locale\n const locale = localeDetector(\n { 'accept-language': languages.join(',') },\n internationalization.locales,\n internationalization.defaultLocale\n );\n\n if (locale) {\n detected[LanguageDetector.Navigator] = locale;\n }\n };\n\n const htmlTagDetector = () => {\n const htmlTag = options.htmlTag;\n if (htmlTag && typeof htmlTag.getAttribute === 'function') {\n const lang = htmlTag.getAttribute('lang');\n if (lang) {\n const { internationalization } = configuration;\n\n // Validate and resolve the locale\n const locale = localeDetector(\n { 'accept-language': lang },\n internationalization.locales,\n internationalization.defaultLocale\n );\n\n detected[LanguageDetector.HtmlTag] = locale;\n }\n }\n };\n\n // Map detector names to their corresponding functions\n const detectors: Record<string, () => void> = {\n [LanguageDetector.Querystring]: queryStringDetector,\n [LanguageDetector.Storage]: storageDetector,\n [LanguageDetector.Navigator]: navigatorDetector,\n [LanguageDetector.HtmlTag]: htmlTagDetector,\n };\n\n // Use the provided order to run each detector\n order.forEach((detectorName) => {\n detectors[detectorName]?.();\n });\n\n return detected;\n};\n\nconst getFirstAvailableLocale = (\n locales: Record<LanguageDetector, Locale | undefined>,\n order: LanguageDetector[]\n): Locale => {\n const { internationalization } = configuration;\n\n for (const detector of order) {\n const locale = locales[detector];\n\n if (locale && internationalization.locales.includes(locale)) {\n return locale;\n }\n }\n\n return internationalization?.defaultLocale ?? ENGLISH;\n};\n\n/**\n * Core language detector function for browser environments.\n *\n * Detects the user's preferred locale by checking multiple sources in order:\n * 1. Query string parameter\n * 2. Storage (cookies, localStorage, sessionStorage) - uses getLocaleFromStorage\n * 3. Navigator languages - uses localeDetector\n * 4. HTML lang attribute - uses localeDetector\n *\n * @param userOptions - Optional configuration for detection order and lookup keys\n * @returns The detected locale or the default locale\n *\n * @example\n * const locale = getBrowserLocale({ order: [LanguageDetector.Storage, LanguageDetector.Navigator] });\n */\nexport const getBrowserLocale = (\n userOptions: LanguageDetectorOptions | undefined = {}\n): Locale => {\n const options = { ...getDefaultsOptions(), ...userOptions };\n\n const locales = detectLanguage(options.order ?? [], options);\n\n return getFirstAvailableLocale(locales, options.order ?? []);\n};\n"],"mappings":"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"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getLocaleFromStorageServer } from "../utils/localeStorage.mjs";
|
|
2
2
|
import { localeResolver } from "./localeResolver.mjs";
|
|
3
3
|
import { getPreferredLanguages } from "./localeDetector.mjs";
|
|
4
|
-
import { DEFAULT_LOCALE, LOCALES } from "@intlayer/config/defaultValues";
|
|
5
4
|
import configuration from "@intlayer/config/built";
|
|
5
|
+
import { DEFAULT_LOCALE, LOCALES } from "@intlayer/config/defaultValues";
|
|
6
6
|
|
|
7
7
|
//#region src/localization/getLocale.ts
|
|
8
8
|
const getLocale = async (ctx = {}) => {
|
|
9
9
|
const defaultLocale = configuration?.internationalization?.defaultLocale ?? DEFAULT_LOCALE;
|
|
10
10
|
const availableLocales = configuration?.internationalization?.locales ?? LOCALES;
|
|
11
|
-
const storedLocale =
|
|
11
|
+
const storedLocale = getLocaleFromStorageServer({
|
|
12
12
|
getCookie: ctx.getCookie,
|
|
13
13
|
getHeader: ctx.getHeader
|
|
14
14
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getLocale.mjs","names":[],"sources":["../../../src/localization/getLocale.ts"],"sourcesContent":["import configuration from '@intlayer/config/built';\nimport { DEFAULT_LOCALE, LOCALES } from '@intlayer/config/defaultValues';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport {
|
|
1
|
+
{"version":3,"file":"getLocale.mjs","names":[],"sources":["../../../src/localization/getLocale.ts"],"sourcesContent":["import configuration from '@intlayer/config/built';\nimport { DEFAULT_LOCALE, LOCALES } from '@intlayer/config/defaultValues';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { getLocaleFromStorageServer } from '../utils/localeStorage';\nimport { getPreferredLanguages } from './localeDetector';\nimport { localeResolver } from './localeResolver';\n\nexport type RequestContext = {\n getHeader?: (name: string) => string | null | undefined;\n getCookie?: (name: string) => string | null | undefined;\n};\n\nexport const getLocale = async (ctx: RequestContext = {}): Promise<Locale> => {\n const defaultLocale =\n configuration?.internationalization?.defaultLocale ?? DEFAULT_LOCALE;\n const availableLocales =\n configuration?.internationalization?.locales ?? LOCALES;\n\n // Try locale from storage (cookie or header)\n const storedLocale = getLocaleFromStorageServer({\n getCookie: ctx.getCookie,\n getHeader: ctx.getHeader,\n });\n\n if (storedLocale) {\n return storedLocale;\n }\n\n // Fallback to Accept-Language negotiation\n const acceptLanguageHeader = ctx.getHeader?.('accept-language');\n\n if (!acceptLanguageHeader) {\n return defaultLocale;\n }\n\n const preferredLocaleStrings = getPreferredLanguages(\n acceptLanguageHeader,\n availableLocales\n );\n\n const userFallbackLocale = localeResolver(\n preferredLocaleStrings,\n availableLocales,\n defaultLocale\n );\n\n if (userFallbackLocale) {\n return userFallbackLocale;\n }\n\n // Default locale\n return defaultLocale;\n};\n"],"mappings":";;;;;;;AAYA,MAAa,YAAY,OAAO,MAAsB,EAAE,KAAsB;CAC5E,MAAM,gBACJ,eAAe,sBAAsB,iBAAiB;CACxD,MAAM,mBACJ,eAAe,sBAAsB,WAAW;CAGlD,MAAM,eAAe,2BAA2B;EAC9C,WAAW,IAAI;EACf,WAAW,IAAI;EAChB,CAAC;AAEF,KAAI,aACF,QAAO;CAIT,MAAM,uBAAuB,IAAI,YAAY,kBAAkB;AAE/D,KAAI,CAAC,qBACH,QAAO;CAQT,MAAM,qBAAqB,eALI,sBAC7B,sBACA,iBACD,EAIC,kBACA,cACD;AAED,KAAI,mBACF,QAAO;AAIT,QAAO"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { checkIsURLAbsolute } from "../utils/checkIsURLAbsolute.mjs";
|
|
2
|
-
import { getPrefix, resolveRoutingConfig } from "./getPrefix.mjs";
|
|
3
2
|
import { getPathWithoutLocale } from "./getPathWithoutLocale.mjs";
|
|
3
|
+
import { getPrefix, resolveRoutingConfig } from "./getPrefix.mjs";
|
|
4
4
|
import { getCanonicalPath, getLocalizedPath, getRewriteRules } from "./rewriteUtils.mjs";
|
|
5
5
|
import configuration from "@intlayer/config/built";
|
|
6
6
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DEFAULT_LOCALE, LOCALES, ROUTING_MODE } from "@intlayer/config/defaultValues";
|
|
2
1
|
import configuration from "@intlayer/config/built";
|
|
2
|
+
import { DEFAULT_LOCALE, LOCALES, ROUTING_MODE } from "@intlayer/config/defaultValues";
|
|
3
3
|
|
|
4
4
|
//#region src/localization/getPrefix.ts
|
|
5
5
|
/**
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getPathWithoutLocale } from "./getPathWithoutLocale.mjs";
|
|
2
|
+
import { getPrefix } from "./getPrefix.mjs";
|
|
3
|
+
import { getCanonicalPath, getInternalPath, getLocalizedPath, getRewritePath, getRewriteRules } from "./rewriteUtils.mjs";
|
|
4
|
+
import { getLocalizedUrl } from "./getLocalizedUrl.mjs";
|
|
5
|
+
import { getMultilingualUrls } from "./getMultilingualUrls.mjs";
|
|
6
|
+
import { generateSitemap, generateSitemapUrl } from "./generateSitemap.mjs";
|
|
2
7
|
import { localeResolver } from "./localeResolver.mjs";
|
|
3
8
|
import { localeDetector } from "./localeDetector.mjs";
|
|
4
9
|
import { getBrowserLocale, localeStorageOptions } from "./getBrowserLocale.mjs";
|
|
5
10
|
import { getHTMLTextDir } from "./getHTMLTextDir.mjs";
|
|
6
11
|
import { getLocale } from "./getLocale.mjs";
|
|
7
|
-
import { getPrefix } from "./getPrefix.mjs";
|
|
8
12
|
import { getLocaleFromPath } from "./getLocaleFromPath.mjs";
|
|
9
13
|
import { getLocaleLang } from "./getLocaleLang.mjs";
|
|
10
14
|
import { getLocaleName } from "./getLocaleName.mjs";
|
|
11
|
-
import { getPathWithoutLocale } from "./getPathWithoutLocale.mjs";
|
|
12
|
-
import { getCanonicalPath, getInternalPath, getLocalizedPath, getRewritePath, getRewriteRules } from "./rewriteUtils.mjs";
|
|
13
|
-
import { getLocalizedUrl } from "./getLocalizedUrl.mjs";
|
|
14
|
-
import { getMultilingualUrls } from "./getMultilingualUrls.mjs";
|
|
15
15
|
import { localeFlatMap, localeMap, localeRecord } from "./localeMapper.mjs";
|
|
16
16
|
import { validatePrefix } from "./validatePrefix.mjs";
|
|
17
17
|
|
|
18
|
-
export { getBrowserLocale, getCanonicalPath, getHTMLTextDir, getInternalPath, getLocale, getLocaleFromPath, getLocaleLang, getLocaleName, getLocalizedPath, getLocalizedUrl, getMultilingualUrls, getPathWithoutLocale, getPrefix, getRewritePath, getRewriteRules,
|
|
18
|
+
export { generateSitemap, generateSitemapUrl, getBrowserLocale, getCanonicalPath, getHTMLTextDir, getInternalPath, getLocale, getLocaleFromPath, getLocaleLang, getLocaleName, getLocalizedPath, getLocalizedUrl, getMultilingualUrls, getPathWithoutLocale, getPrefix, getRewritePath, getRewriteRules, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, localeStorageOptions, validatePrefix };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getPrefix } from "./getPrefix.mjs";
|
|
2
|
-
import { DEFAULT_LOCALE } from "@intlayer/config/defaultValues";
|
|
3
2
|
import configuration from "@intlayer/config/built";
|
|
3
|
+
import { DEFAULT_LOCALE } from "@intlayer/config/defaultValues";
|
|
4
4
|
|
|
5
5
|
//#region src/localization/localeMapper.ts
|
|
6
6
|
/**
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { HTML_TAGS } from "./htmlTags.mjs";
|
|
2
|
-
|
|
3
1
|
//#region src/transpiler/html/getHTMLCustomComponents.ts
|
|
4
2
|
const parseAttributes = (attributesString) => {
|
|
5
3
|
const attributes = {};
|
|
6
|
-
if (!attributesString
|
|
4
|
+
if (!attributesString?.trim()) return attributes;
|
|
7
5
|
[...attributesString.matchAll(/([a-zA-Z0-9-:_@]+)(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^>\s]+))?/g)].forEach((match) => {
|
|
8
6
|
const attrName = match[1];
|
|
9
7
|
attributes[attrName] = "string";
|
|
@@ -24,7 +22,7 @@ const getHTMLCustomComponents = (content) => {
|
|
|
24
22
|
const tagName = match[2];
|
|
25
23
|
const attributesString = match[3];
|
|
26
24
|
const isSelfClosing = !!match[4];
|
|
27
|
-
if (
|
|
25
|
+
if (/^[a-z][a-z0-9]*$/.test(tagName)) {
|
|
28
26
|
components[tagName] = true;
|
|
29
27
|
return;
|
|
30
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getHTMLCustomComponents.mjs","names":[],"sources":["../../../../src/transpiler/html/getHTMLCustomComponents.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"getHTMLCustomComponents.mjs","names":[],"sources":["../../../../src/transpiler/html/getHTMLCustomComponents.ts"],"sourcesContent":["const parseAttributes = (attributesString: string): Record<string, string> => {\n const attributes: Record<string, string> = {};\n\n if (!attributesString?.trim()) {\n return attributes;\n }\n\n // Regex to match attribute names\n // Matches: name=\"value\", name='value', name=value, or just name\n const attrRegex =\n /([a-zA-Z0-9-:_@]+)(?:\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^>\\s]+))?/g;\n\n const matches = [...attributesString.matchAll(attrRegex)];\n\n matches.forEach((match) => {\n const attrName = match[1];\n attributes[attrName] = 'string';\n });\n\n return attributes;\n};\n\n/**\n * Extracts component names from an HTML string.\n * - Standard HTML tags are set to `true`.\n * - Custom components are parsed to extract their attributes/props.\n */\nexport const getHTMLCustomComponents = (\n content: string\n): Record<string, Record<string, string> | true> => {\n if (typeof content !== 'string') {\n throw new Error('content must be a string');\n }\n\n const tagRegex = /<(\\/)?([a-zA-Z0-9.-]+)\\s*([\\s\\S]*?)(\\/?)>/g;\n const matches = [...content.matchAll(tagRegex)];\n\n const components: Record<string, Record<string, string> | true> = {};\n\n matches.forEach((match) => {\n const isClosing = !!match[1];\n const tagName = match[2];\n const attributesString = match[3];\n const isSelfClosing = !!match[4];\n\n // Matches any tag that is entirely lowercase letters and numbers (e.g., div, h1)\n const isStandardHTMLTag = /^[a-z][a-z0-9]*$/.test(tagName);\n\n if (isStandardHTMLTag) {\n components[tagName] = true;\n return;\n }\n\n if (!components[tagName]) {\n components[tagName] = {};\n }\n\n if (components[tagName] === true) {\n return;\n }\n\n if (isClosing) {\n return;\n }\n\n const attributes = parseAttributes(attributesString);\n const componentDef = components[tagName] as Record<string, string>;\n Object.assign(componentDef, attributes);\n\n if (!isSelfClosing) {\n componentDef.children = 'string';\n }\n });\n\n return components;\n};\n"],"mappings":";AAAA,MAAM,mBAAmB,qBAAqD;CAC5E,MAAM,aAAqC,EAAE;AAE7C,KAAI,CAAC,kBAAkB,MAAM,CAC3B,QAAO;AAUT,CAFgB,CAAC,GAAG,iBAAiB,SAFnC,6DAEsD,CAAC,CAEjD,SAAS,UAAU;EACzB,MAAM,WAAW,MAAM;AACvB,aAAW,YAAY;GACvB;AAEF,QAAO;;;;;;;AAQT,MAAa,2BACX,YACkD;AAClD,KAAI,OAAO,YAAY,SACrB,OAAM,IAAI,MAAM,2BAA2B;CAI7C,MAAM,UAAU,CAAC,GAAG,QAAQ,SADX,6CAC6B,CAAC;CAE/C,MAAM,aAA4D,EAAE;AAEpE,SAAQ,SAAS,UAAU;EACzB,MAAM,YAAY,CAAC,CAAC,MAAM;EAC1B,MAAM,UAAU,MAAM;EACtB,MAAM,mBAAmB,MAAM;EAC/B,MAAM,gBAAgB,CAAC,CAAC,MAAM;AAK9B,MAF0B,mBAAmB,KAAK,QAAQ,EAEnC;AACrB,cAAW,WAAW;AACtB;;AAGF,MAAI,CAAC,WAAW,SACd,YAAW,WAAW,EAAE;AAG1B,MAAI,WAAW,aAAa,KAC1B;AAGF,MAAI,UACF;EAGF,MAAM,aAAa,gBAAgB,iBAAiB;EACpD,MAAM,eAAe,WAAW;AAChC,SAAO,OAAO,cAAc,WAAW;AAEvC,MAAI,CAAC,cACH,cAAa,WAAW;GAE1B;AAEF,QAAO"}
|
package/dist/esm/utils/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { parseYaml } from "./parseYaml.mjs";
|
|
2
2
|
import { isValidElement } from "./isValidReactElement.mjs";
|
|
3
|
-
import { CachedIntl, bindIntl,
|
|
4
|
-
import { getCookie } from "./getCookie.mjs";
|
|
5
|
-
import { LocaleStorage, getLocaleFromStorage, setLocaleInStorage } from "./localeStorage.mjs";
|
|
3
|
+
import { CachedIntl, bindIntl, getCachedIntl } from "./intl.mjs";
|
|
6
4
|
import { checkIsURLAbsolute } from "./checkIsURLAbsolute.mjs";
|
|
5
|
+
import { getCookie } from "./getCookie.mjs";
|
|
6
|
+
import { LocaleStorage, LocaleStorageClient, LocaleStorageServer, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer } from "./localeStorage.mjs";
|
|
7
7
|
import { isSameKeyPath } from "./isSameKeyPath.mjs";
|
|
8
8
|
|
|
9
|
-
export { CachedIntl, CachedIntl as Intl, LocaleStorage, bindIntl, checkIsURLAbsolute,
|
|
9
|
+
export { CachedIntl, CachedIntl as Intl, LocaleStorage, LocaleStorageClient, LocaleStorageServer, bindIntl, checkIsURLAbsolute, getCachedIntl, getCookie, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, isSameKeyPath, isValidElement, parseYaml, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer };
|
package/dist/esm/utils/intl.mjs
CHANGED
|
@@ -1,87 +1,102 @@
|
|
|
1
|
-
import
|
|
1
|
+
import configuration from "@intlayer/config/built";
|
|
2
2
|
|
|
3
3
|
//#region src/utils/intl.ts
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Cached Intl helper – drop‑in replacement for the global `Intl` object.
|
|
6
|
+
* ‑‑‑
|
|
7
|
+
* • Uses a `Proxy` to lazily wrap every *constructor* hanging off `Intl` (NumberFormat, DateTimeFormat, …).
|
|
8
|
+
* • Each wrapped constructor keeps an in‑memory cache keyed by `[locales, options]` so that identical requests
|
|
9
|
+
* reuse the same heavy instance instead of reparsing CLDR data every time.
|
|
10
|
+
* • A polyfill warning for `Intl.DisplayNames` is emitted only once and only in dev.
|
|
11
|
+
* • The public API is fully type‑safe and mirrors the native `Intl` surface exactly –
|
|
12
|
+
* you can treat `CachedIntl` just like the built‑in `Intl`.
|
|
13
|
+
*
|
|
14
|
+
* Usage @example:
|
|
15
|
+
* ---------------
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { CachedIntl } from "./cached-intl";
|
|
18
|
+
*
|
|
19
|
+
* const nf = CachedIntl.NumberFormat("en-US", { style: "currency", currency: "USD" });
|
|
20
|
+
* console.log(nf.format(1234));
|
|
21
|
+
*
|
|
22
|
+
* const dn = CachedIntl.DisplayNames(["fr"], { type: "language" });
|
|
23
|
+
* console.log(dn.of("en")); * → "anglais"
|
|
24
|
+
*
|
|
25
|
+
* You can also spin up an isolated instance with its own caches (handy in test suites):
|
|
26
|
+
* const TestIntl = createCachedIntl();
|
|
27
|
+
* ```
|
|
8
28
|
*/
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
if (!options) return localeKey;
|
|
12
|
-
return `${localeKey}|${JSON.stringify(options)}`;
|
|
13
|
-
};
|
|
29
|
+
const MAX_CACHE_SIZE = 50;
|
|
30
|
+
const cache = /* @__PURE__ */ new Map();
|
|
14
31
|
/**
|
|
15
|
-
* Generic
|
|
32
|
+
* Generic caching instantiator for Intl constructors.
|
|
16
33
|
*/
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
resolvedOptions = locales;
|
|
25
|
-
resolvedLocales = locales.locale;
|
|
26
|
-
}
|
|
27
|
-
if (Ctor.name === "DisplayNames" && typeof Intl?.DisplayNames !== "function") {}
|
|
28
|
-
const key = getCacheKey(resolvedLocales, resolvedOptions);
|
|
29
|
-
let instance = cache.get(key);
|
|
30
|
-
if (instance) return instance;
|
|
31
|
-
instance = new Ctor(resolvedLocales, resolvedOptions);
|
|
32
|
-
if (cache.size >= MAX_CACHE_SIZE) {
|
|
33
|
-
const oldestKey = cache.keys().next().value;
|
|
34
|
-
if (oldestKey) cache.delete(oldestKey);
|
|
35
|
-
}
|
|
36
|
-
cache.set(key, instance);
|
|
37
|
-
return instance;
|
|
34
|
+
const getCachedIntl = (Ctor, locale, options) => {
|
|
35
|
+
const resLoc = locale ?? configuration?.internationalization?.defaultLocale;
|
|
36
|
+
const key = `${resLoc}|${options ? JSON.stringify(options) : ""}`;
|
|
37
|
+
let ctorCache = cache.get(Ctor);
|
|
38
|
+
if (!ctorCache) {
|
|
39
|
+
ctorCache = /* @__PURE__ */ new Map();
|
|
40
|
+
cache.set(Ctor, ctorCache);
|
|
38
41
|
}
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
let instance = ctorCache.get(key);
|
|
43
|
+
if (!instance) {
|
|
44
|
+
if (ctorCache.size > MAX_CACHE_SIZE) ctorCache.clear();
|
|
45
|
+
instance = new Ctor(resLoc, options);
|
|
46
|
+
ctorCache.set(key, instance);
|
|
47
|
+
}
|
|
48
|
+
return instance;
|
|
41
49
|
};
|
|
42
50
|
/**
|
|
43
|
-
*
|
|
51
|
+
* Optional: Keep bindIntl if your library exports it publicly.
|
|
52
|
+
* It now uses the much smaller getCachedIntl under the hood.
|
|
44
53
|
*/
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
const bindIntl = (boundLocale) => {
|
|
55
|
+
const bindWrap = (Ctor) => function intlConstructor(locales, options) {
|
|
56
|
+
const isOptsFirst = locales !== null && typeof locales === "object" && !Array.isArray(locales);
|
|
57
|
+
const resOpts = isOptsFirst ? locales : options;
|
|
58
|
+
return getCachedIntl(Ctor, isOptsFirst ? resOpts.locale || boundLocale : locales || boundLocale, resOpts);
|
|
59
|
+
};
|
|
60
|
+
return {
|
|
61
|
+
...Intl,
|
|
62
|
+
Collator: bindWrap(Intl.Collator),
|
|
63
|
+
DateTimeFormat: bindWrap(Intl.DateTimeFormat),
|
|
64
|
+
DisplayNames: bindWrap(Intl.DisplayNames),
|
|
65
|
+
ListFormat: bindWrap(Intl.ListFormat),
|
|
66
|
+
NumberFormat: bindWrap(Intl.NumberFormat),
|
|
67
|
+
PluralRules: bindWrap(Intl.PluralRules),
|
|
68
|
+
RelativeTimeFormat: bindWrap(Intl.RelativeTimeFormat),
|
|
69
|
+
Locale: bindWrap(Intl.Locale),
|
|
70
|
+
Segmenter: bindWrap(Intl.Segmenter)
|
|
71
|
+
};
|
|
57
72
|
};
|
|
58
|
-
const CachedIntl =
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return
|
|
82
|
-
}
|
|
73
|
+
const CachedIntl = {
|
|
74
|
+
Collator: function Collator(locales, options) {
|
|
75
|
+
return getCachedIntl(Intl.Collator, locales, options);
|
|
76
|
+
},
|
|
77
|
+
DateTimeFormat: function DateTimeFormat(locales, options) {
|
|
78
|
+
return getCachedIntl(Intl.DateTimeFormat, locales, options);
|
|
79
|
+
},
|
|
80
|
+
DisplayNames: function DisplayNames(locales, options) {
|
|
81
|
+
return getCachedIntl(Intl.DisplayNames, locales, options);
|
|
82
|
+
},
|
|
83
|
+
ListFormat: function ListFormat(locales, options) {
|
|
84
|
+
return getCachedIntl(Intl.ListFormat, locales, options);
|
|
85
|
+
},
|
|
86
|
+
NumberFormat: function NumberFormat(locales, options) {
|
|
87
|
+
return getCachedIntl(Intl.NumberFormat, locales, options);
|
|
88
|
+
},
|
|
89
|
+
PluralRules: function PluralRules(locales, options) {
|
|
90
|
+
return getCachedIntl(Intl.PluralRules, locales, options);
|
|
91
|
+
},
|
|
92
|
+
RelativeTimeFormat: function RelativeTimeFormat(locales, options) {
|
|
93
|
+
return getCachedIntl(Intl.RelativeTimeFormat, locales, options);
|
|
94
|
+
},
|
|
95
|
+
Segmenter: function Segmenter(locales, options) {
|
|
96
|
+
return getCachedIntl(Intl.Segmenter, locales, options);
|
|
97
|
+
}
|
|
83
98
|
};
|
|
84
99
|
|
|
85
100
|
//#endregion
|
|
86
|
-
export { CachedIntl, CachedIntl as Intl, bindIntl,
|
|
101
|
+
export { CachedIntl, CachedIntl as Intl, bindIntl, getCachedIntl };
|
|
87
102
|
//# sourceMappingURL=intl.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intl.mjs","names":[],"sources":["../../../src/utils/intl.ts"],"sourcesContent":["// Cached Intl helper – drop‑in replacement for the global `Intl` object.\n// ‑‑‑\n// • Uses a `Proxy` to lazily wrap every *constructor* hanging off `Intl` (NumberFormat, DateTimeFormat, …).\n// • Each wrapped constructor keeps an in‑memory cache keyed by `[locales, options]` so that identical requests\n// reuse the same heavy instance instead of reparsing CLDR data every time.\n// • A polyfill warning for `Intl.DisplayNames` is emitted only once and only in dev.\n// • The public API is fully type‑safe and mirrors the native `Intl` surface exactly –\n// you can treat `CachedIntl` just like the built‑in `Intl`.\n//\n// Usage examples:\n// ---------------\n// import { CachedIntl } from \"./cached-intl\";\n//\n// const nf = CachedIntl.NumberFormat(\"en-US\", { style: \"currency\", currency: \"USD\" });\n// console.log(nf.format(1234));\n//\n// const dn = CachedIntl.DisplayNames([\"fr\"], { type: \"language\" });\n// console.log(dn.of(\"en\")); // → \"anglais\"\n//\n// You can also spin up an isolated instance with its own caches (handy in test suites):\n// const TestIntl = createCachedIntl();\n//\n// ---------------------------------------------------------------------\n\nimport { ENGLISH } from '@intlayer/types/locales';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\n\n// Helper type that picks just the constructor members off `typeof Intl`.\n// The \"capital‑letter\" heuristic is 100 % accurate today and keeps the\n// mapping short‑lived, so we don't have to manually list every constructor.\ntype IntlConstructors = {\n [K in keyof typeof Intl as (typeof Intl)[K] extends new (\n ...args: any\n ) => any\n ? K\n : never]: (typeof Intl)[K];\n};\n\n// Type wrapper to replace locale arguments with LocalesValues\ntype ReplaceLocaleWithLocalesValues<T> = T extends new (\n locales: any,\n options?: infer Options\n) => infer Instance\n ? {\n new (locales?: LocalesValues, options?: Options): Instance;\n new (options?: Options & { locale?: LocalesValues }): Instance;\n }\n : T extends new (\n locales: any\n ) => infer Instance\n ? {\n new (locales?: LocalesValues): Instance;\n new (options?: { locale?: LocalesValues }): Instance;\n }\n : T;\n\n// Wrapped Intl type with LocalesValues\nexport type WrappedIntl = {\n [K in keyof typeof Intl]: K extends keyof IntlConstructors\n ? ReplaceLocaleWithLocalesValues<(typeof Intl)[K]>\n : (typeof Intl)[K];\n};\n\n// ... (Keep your Type Helper definitions here: IntlConstructors, ReplaceLocaleWithLocalesValues, WrappedIntl) ...\n\n/**\n * Optimized Cache Key Generator\n * 1. Fast path: If no options, just use the locale string.\n * 2. Normal path: JSON.stringify for deterministic object comparison.\n */\nconst getCacheKey = (\n locales: LocalesValues | undefined,\n options: unknown\n): string => {\n const localeKey = locales ? String(locales) : ENGLISH;\n\n if (!options) return localeKey;\n\n // JSON.stringify is the most robust way to handle nested options objects\n // without a heavy custom hashing function.\n return `${localeKey}|${JSON.stringify(options)}`;\n};\n\n/**\n * Generic wrapper for any `new Intl.*()` constructor.\n */\nconst createCachedConstructor = <T extends new (...args: any[]) => any>(\n Ctor: T\n) => {\n // The cache lives here, inside the closure of the wrapped constructor.\n const cache = new Map<string, InstanceType<T>>();\n const MAX_CACHE_SIZE = 50;\n\n function Wrapped(locales?: LocalesValues | any, options?: any) {\n let resolvedLocales = locales;\n let resolvedOptions = options;\n\n // Handle case where first argument is an options object instead of locales\n if (\n typeof locales === 'object' &&\n !Array.isArray(locales) &&\n locales !== null\n ) {\n resolvedOptions = locales;\n resolvedLocales = locales.locale;\n }\n\n // Handle DisplayNames Polyfill warning\n if (\n Ctor.name === 'DisplayNames' &&\n typeof (Intl as any)?.DisplayNames !== 'function'\n ) {\n // ... (Existing polyfill logic would go here if needed, but let's keep it simple for now as it was empty in the read output)\n // Actually the read output had \"// ... (Your existing polyfill warning logic) ...\"\n // I should check what was there before or just preserve it.\n }\n\n // Generate Key\n const key = getCacheKey(resolvedLocales, resolvedOptions);\n\n // Check Cache\n let instance = cache.get(key);\n if (instance) return instance;\n\n // Create New Instance\n instance = new Ctor(resolvedLocales as never, resolvedOptions as never);\n\n // Smart Eviction (LRU-ish)\n // Map iterates in insertion order. Deleting the first key removes the \"oldest\".\n if (cache.size >= MAX_CACHE_SIZE) {\n const oldestKey = cache.keys().next().value;\n if (oldestKey) cache.delete(oldestKey);\n }\n\n cache.set(key, instance as InstanceType<T>);\n return instance as InstanceType<T>;\n }\n\n // Preserve prototype for `instanceof` checks\n (Wrapped as any).prototype = (Ctor as any).prototype;\n\n return Wrapped as unknown as ReplaceLocaleWithLocalesValues<T>;\n};\n\n/**\n * Factory that turns the global `Intl` into a cached clone.\n */\nexport const createCachedIntl = (): WrappedIntl => {\n // We must cache the *wrapped constructors* themselves.\n // Otherwise, the Proxy creates a new `Wrapped` function (and a new empty Map)\n // on every single property access.\n const constructorCache = new Map<string | symbol, any>();\n\n return new Proxy(Intl as IntlConstructors, {\n get: (target, prop, receiver) => {\n // Fast return if we already wrapped this constructor\n if (constructorCache.has(prop)) {\n return constructorCache.get(prop);\n }\n\n const value = Reflect.get(target, prop, receiver);\n\n // Wrap only Constructors (Heuristic: Function + starts with Uppercase)\n // This prevents wrapping static methods like `Intl.getCanonicalLocales`\n if (\n typeof value === 'function' &&\n typeof prop === 'string' &&\n /^[A-Z]/.test(prop)\n ) {\n const wrapped = createCachedConstructor(value);\n constructorCache.set(prop, wrapped);\n return wrapped;\n }\n\n // Pass through everything else (static methods, constants)\n return value;\n },\n }) as unknown as WrappedIntl;\n};\n\nexport const CachedIntl = createCachedIntl();\n\n/**\n * Creates a proxied Intl object with a preset locale.\n *\n * @example\n * const intl = bindIntl(Locales.FRENCH);\n * new intl.NumberFormat(undefined, { style: 'currency', currency: 'EUR' }).format(10);\n * // Uses 'fr' automatically\n */\nexport const bindIntl = (locale: LocalesValues): WrappedIntl => {\n return new Proxy(CachedIntl, {\n get: (target, prop) => {\n const value = Reflect.get(target, prop);\n\n // We only want to intercept Constructors (e.g., NumberFormat, DateTimeFormat)\n // to inject the locale into their arguments.\n if (\n typeof value === 'function' &&\n typeof prop === 'string' &&\n /^[A-Z]/.test(prop)\n ) {\n return new Proxy(value, {\n construct: (Ctor, args) => {\n let [locales, options] = args;\n\n // If the user provided a locale (args[0]), respect it.\n // If args[0] is undefined, inject the bound locale.\n // If args[0] is an object (not array), it's the options object.\n if (\n typeof locales === 'object' &&\n !Array.isArray(locales) &&\n locales !== null\n ) {\n options = locales;\n locales = options.locale ?? locale;\n } else if (locales === undefined) {\n locales = locale;\n }\n\n // We pass it to `CachedIntl` which handles caching logic.\n return new Ctor(locales, options);\n },\n // Ensure static methods (like supportedLocalesOf) still work\n get: (Ctor, key) => Reflect.get(Ctor, key),\n });\n }\n\n // Return constants or static methods as-is\n return value;\n },\n }) as unknown as WrappedIntl;\n};\n\n// new CachedIntl.DisplayNames(Locales.FRENCH, { type: 'language' });\n// new CachedIntl.DisplayNames('fr', { type: 'language' });\n// new CachedIntl.DateTimeFormat('fr', {\n// year: 'numeric',\n// month: 'long',\n// day: 'numeric',\n// });\n// new CachedIntl.NumberFormat('fr', {\n// style: 'currency',\n// currency: 'EUR',\n// });\n// new CachedIntl.Collator('fr', { sensitivity: 'base' });\n// new CachedIntl.PluralRules('fr');\n// new CachedIntl.RelativeTimeFormat('fr', { numeric: 'auto' });\n// new CachedIntl.ListFormat('fr', { type: 'conjunction' });\nexport { CachedIntl as Intl };\n"],"mappings":";;;;;;;;AAsEA,MAAM,eACJ,SACA,YACW;CACX,MAAM,YAAY,UAAU,OAAO,QAAQ,GAAG;AAE9C,KAAI,CAAC,QAAS,QAAO;AAIrB,QAAO,GAAG,UAAU,GAAG,KAAK,UAAU,QAAQ;;;;;AAMhD,MAAM,2BACJ,SACG;CAEH,MAAM,wBAAQ,IAAI,KAA8B;CAChD,MAAM,iBAAiB;CAEvB,SAAS,QAAQ,SAA+B,SAAe;EAC7D,IAAI,kBAAkB;EACtB,IAAI,kBAAkB;AAGtB,MACE,OAAO,YAAY,YACnB,CAAC,MAAM,QAAQ,QAAQ,IACvB,YAAY,MACZ;AACA,qBAAkB;AAClB,qBAAkB,QAAQ;;AAI5B,MACE,KAAK,SAAS,kBACd,OAAQ,MAAc,iBAAiB,YACvC;EAOF,MAAM,MAAM,YAAY,iBAAiB,gBAAgB;EAGzD,IAAI,WAAW,MAAM,IAAI,IAAI;AAC7B,MAAI,SAAU,QAAO;AAGrB,aAAW,IAAI,KAAK,iBAA0B,gBAAyB;AAIvE,MAAI,MAAM,QAAQ,gBAAgB;GAChC,MAAM,YAAY,MAAM,MAAM,CAAC,MAAM,CAAC;AACtC,OAAI,UAAW,OAAM,OAAO,UAAU;;AAGxC,QAAM,IAAI,KAAK,SAA4B;AAC3C,SAAO;;AAIT,CAAC,QAAgB,YAAa,KAAa;AAE3C,QAAO;;;;;AAMT,MAAa,yBAAsC;CAIjD,MAAM,mCAAmB,IAAI,KAA2B;AAExD,QAAO,IAAI,MAAM,MAA0B,EACzC,MAAM,QAAQ,MAAM,aAAa;AAE/B,MAAI,iBAAiB,IAAI,KAAK,CAC5B,QAAO,iBAAiB,IAAI,KAAK;EAGnC,MAAM,QAAQ,QAAQ,IAAI,QAAQ,MAAM,SAAS;AAIjD,MACE,OAAO,UAAU,cACjB,OAAO,SAAS,YAChB,SAAS,KAAK,KAAK,EACnB;GACA,MAAM,UAAU,wBAAwB,MAAM;AAC9C,oBAAiB,IAAI,MAAM,QAAQ;AACnC,UAAO;;AAIT,SAAO;IAEV,CAAC;;AAGJ,MAAa,aAAa,kBAAkB;;;;;;;;;AAU5C,MAAa,YAAY,WAAuC;AAC9D,QAAO,IAAI,MAAM,YAAY,EAC3B,MAAM,QAAQ,SAAS;EACrB,MAAM,QAAQ,QAAQ,IAAI,QAAQ,KAAK;AAIvC,MACE,OAAO,UAAU,cACjB,OAAO,SAAS,YAChB,SAAS,KAAK,KAAK,CAEnB,QAAO,IAAI,MAAM,OAAO;GACtB,YAAY,MAAM,SAAS;IACzB,IAAI,CAAC,SAAS,WAAW;AAKzB,QACE,OAAO,YAAY,YACnB,CAAC,MAAM,QAAQ,QAAQ,IACvB,YAAY,MACZ;AACA,eAAU;AACV,eAAU,QAAQ,UAAU;eACnB,YAAY,OACrB,WAAU;AAIZ,WAAO,IAAI,KAAK,SAAS,QAAQ;;GAGnC,MAAM,MAAM,QAAQ,QAAQ,IAAI,MAAM,IAAI;GAC3C,CAAC;AAIJ,SAAO;IAEV,CAAC"}
|
|
1
|
+
{"version":3,"file":"intl.mjs","names":[],"sources":["../../../src/utils/intl.ts"],"sourcesContent":["/**\n * Cached Intl helper – drop‑in replacement for the global `Intl` object.\n * ‑‑‑\n * • Uses a `Proxy` to lazily wrap every *constructor* hanging off `Intl` (NumberFormat, DateTimeFormat, …).\n * • Each wrapped constructor keeps an in‑memory cache keyed by `[locales, options]` so that identical requests\n * reuse the same heavy instance instead of reparsing CLDR data every time.\n * • A polyfill warning for `Intl.DisplayNames` is emitted only once and only in dev.\n * • The public API is fully type‑safe and mirrors the native `Intl` surface exactly –\n * you can treat `CachedIntl` just like the built‑in `Intl`.\n *\n * Usage @example:\n * ---------------\n * ```ts\n * import { CachedIntl } from \"./cached-intl\";\n *\n * const nf = CachedIntl.NumberFormat(\"en-US\", { style: \"currency\", currency: \"USD\" });\n * console.log(nf.format(1234));\n *\n * const dn = CachedIntl.DisplayNames([\"fr\"], { type: \"language\" });\n * console.log(dn.of(\"en\")); * → \"anglais\"\n *\n * You can also spin up an isolated instance with its own caches (handy in test suites):\n * const TestIntl = createCachedIntl();\n * ```\n */\n\nimport configuration from '@intlayer/config/built';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\n\nconst MAX_CACHE_SIZE = 50;\nconst cache = new Map<any, Map<string, any>>();\n\ntype IntlConstructors = {\n [K in keyof typeof Intl as (typeof Intl)[K] extends new (\n ...args: any\n ) => any\n ? K\n : never]: (typeof Intl)[K];\n};\n\ntype ReplaceLocaleWithLocalesValues<T> = T extends new (\n locales: any,\n options?: infer Options\n) => infer Instance\n ? {\n new (locales?: LocalesValues, options?: Options): Instance;\n new (options?: Options & { locale?: LocalesValues }): Instance;\n (locales?: LocalesValues, options?: Options): Instance;\n (options?: Options & { locale?: LocalesValues }): Instance;\n }\n : T extends new (\n locales: any\n ) => infer Instance\n ? {\n new (locales?: LocalesValues): Instance;\n new (options?: { locale?: LocalesValues }): Instance;\n (locales?: LocalesValues): Instance;\n (options?: { locale?: LocalesValues }): Instance;\n }\n : T;\n\nexport type WrappedIntl = {\n [K in keyof typeof Intl]: K extends keyof IntlConstructors\n ? ReplaceLocaleWithLocalesValues<(typeof Intl)[K]>\n : (typeof Intl)[K];\n};\n\n/**\n * Generic caching instantiator for Intl constructors.\n */\nexport const getCachedIntl = <T extends new (...args: any[]) => any>(\n Ctor: T,\n locale?: LocalesValues | string,\n options?: any\n): InstanceType<T> => {\n const resLoc = locale ?? configuration?.internationalization?.defaultLocale;\n const optKey = options ? JSON.stringify(options) : '';\n const key = `${resLoc}|${optKey}`;\n\n let ctorCache = cache.get(Ctor);\n\n if (!ctorCache) {\n ctorCache = new Map();\n cache.set(Ctor, ctorCache);\n }\n\n let instance = ctorCache.get(key);\n\n if (!instance) {\n if (ctorCache.size > MAX_CACHE_SIZE) ctorCache.clear();\n instance = new Ctor(resLoc, options);\n ctorCache.set(key, instance);\n }\n return instance;\n};\n\n/**\n * Optional: Keep bindIntl if your library exports it publicly.\n * It now uses the much smaller getCachedIntl under the hood.\n */\nexport const bindIntl = (boundLocale: LocalesValues): WrappedIntl => {\n const bindWrap = (Ctor: any) =>\n // function is used as a constructor, do not change in arrow function\n function intlConstructor(locales?: any, options?: any) {\n const isOptsFirst =\n locales !== null &&\n typeof locales === 'object' &&\n !Array.isArray(locales);\n const resOpts = isOptsFirst ? locales : options;\n const resLoc = isOptsFirst\n ? (resOpts as any).locale || boundLocale\n : locales || boundLocale;\n\n return getCachedIntl(Ctor, resLoc, resOpts);\n };\n\n return {\n ...Intl,\n Collator: bindWrap(Intl.Collator),\n DateTimeFormat: bindWrap(Intl.DateTimeFormat),\n DisplayNames: bindWrap(Intl.DisplayNames),\n ListFormat: bindWrap(Intl.ListFormat),\n NumberFormat: bindWrap(Intl.NumberFormat),\n PluralRules: bindWrap(Intl.PluralRules),\n RelativeTimeFormat: bindWrap(Intl.RelativeTimeFormat),\n Locale: bindWrap(Intl.Locale),\n Segmenter: bindWrap((Intl as any).Segmenter),\n } as unknown as WrappedIntl;\n};\n\n// Add this to the bottom of utils/intl.ts ONLY if required for public API compatibility.\nexport const CachedIntl = {\n // function is used as a constructor, do not change in arrow function\n Collator: function Collator(locales?: any, options?: any) {\n return getCachedIntl(Intl.Collator, locales, options);\n },\n DateTimeFormat: function DateTimeFormat(locales?: any, options?: any) {\n return getCachedIntl(Intl.DateTimeFormat, locales, options);\n },\n DisplayNames: function DisplayNames(locales?: any, options?: any) {\n return getCachedIntl(Intl.DisplayNames, locales, options);\n },\n ListFormat: function ListFormat(locales?: any, options?: any) {\n return getCachedIntl(Intl.ListFormat as any, locales, options);\n },\n NumberFormat: function NumberFormat(locales?: any, options?: any) {\n return getCachedIntl(Intl.NumberFormat, locales, options);\n },\n PluralRules: function PluralRules(locales?: any, options?: any) {\n return getCachedIntl(Intl.PluralRules, locales, options);\n },\n RelativeTimeFormat: function RelativeTimeFormat(\n locales?: any,\n options?: any\n ) {\n return getCachedIntl(Intl.RelativeTimeFormat, locales, options);\n },\n Segmenter: function Segmenter(locales?: any, options?: any) {\n return getCachedIntl((Intl as any).Segmenter, locales, options);\n },\n} as any; // Cast to 'any' internally to avoid TS readonly errors\n\nexport { CachedIntl as Intl };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,MAAM,iBAAiB;AACvB,MAAM,wBAAQ,IAAI,KAA4B;;;;AAwC9C,MAAa,iBACX,MACA,QACA,YACoB;CACpB,MAAM,SAAS,UAAU,eAAe,sBAAsB;CAE9D,MAAM,MAAM,GAAG,OAAO,GADP,UAAU,KAAK,UAAU,QAAQ,GAAG;CAGnD,IAAI,YAAY,MAAM,IAAI,KAAK;AAE/B,KAAI,CAAC,WAAW;AACd,8BAAY,IAAI,KAAK;AACrB,QAAM,IAAI,MAAM,UAAU;;CAG5B,IAAI,WAAW,UAAU,IAAI,IAAI;AAEjC,KAAI,CAAC,UAAU;AACb,MAAI,UAAU,OAAO,eAAgB,WAAU,OAAO;AACtD,aAAW,IAAI,KAAK,QAAQ,QAAQ;AACpC,YAAU,IAAI,KAAK,SAAS;;AAE9B,QAAO;;;;;;AAOT,MAAa,YAAY,gBAA4C;CACnE,MAAM,YAAY,SAEhB,SAAS,gBAAgB,SAAe,SAAe;EACrD,MAAM,cACJ,YAAY,QACZ,OAAO,YAAY,YACnB,CAAC,MAAM,QAAQ,QAAQ;EACzB,MAAM,UAAU,cAAc,UAAU;AAKxC,SAAO,cAAc,MAJN,cACV,QAAgB,UAAU,cAC3B,WAAW,aAEoB,QAAQ;;AAG/C,QAAO;EACL,GAAG;EACH,UAAU,SAAS,KAAK,SAAS;EACjC,gBAAgB,SAAS,KAAK,eAAe;EAC7C,cAAc,SAAS,KAAK,aAAa;EACzC,YAAY,SAAS,KAAK,WAAW;EACrC,cAAc,SAAS,KAAK,aAAa;EACzC,aAAa,SAAS,KAAK,YAAY;EACvC,oBAAoB,SAAS,KAAK,mBAAmB;EACrD,QAAQ,SAAS,KAAK,OAAO;EAC7B,WAAW,SAAU,KAAa,UAAU;EAC7C;;AAIH,MAAa,aAAa;CAExB,UAAU,SAAS,SAAS,SAAe,SAAe;AACxD,SAAO,cAAc,KAAK,UAAU,SAAS,QAAQ;;CAEvD,gBAAgB,SAAS,eAAe,SAAe,SAAe;AACpE,SAAO,cAAc,KAAK,gBAAgB,SAAS,QAAQ;;CAE7D,cAAc,SAAS,aAAa,SAAe,SAAe;AAChE,SAAO,cAAc,KAAK,cAAc,SAAS,QAAQ;;CAE3D,YAAY,SAAS,WAAW,SAAe,SAAe;AAC5D,SAAO,cAAc,KAAK,YAAmB,SAAS,QAAQ;;CAEhE,cAAc,SAAS,aAAa,SAAe,SAAe;AAChE,SAAO,cAAc,KAAK,cAAc,SAAS,QAAQ;;CAE3D,aAAa,SAAS,YAAY,SAAe,SAAe;AAC9D,SAAO,cAAc,KAAK,aAAa,SAAS,QAAQ;;CAE1D,oBAAoB,SAAS,mBAC3B,SACA,SACA;AACA,SAAO,cAAc,KAAK,oBAAoB,SAAS,QAAQ;;CAEjE,WAAW,SAAS,UAAU,SAAe,SAAe;AAC1D,SAAO,cAAe,KAAa,WAAW,SAAS,QAAQ;;CAElE"}
|