@intlayer/core 9.5.10 → 9.5.12
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/index.cjs +7 -2
- package/dist/cjs/interpreter/getDictionary.cjs +4 -3
- package/dist/cjs/interpreter/getDictionary.cjs.map +1 -1
- package/dist/cjs/interpreter/getDictionaryAsync.cjs +2 -2
- package/dist/cjs/interpreter/getDictionaryAsync.cjs.map +1 -1
- package/dist/cjs/interpreter/getIntlayer.cjs.map +1 -1
- package/dist/cjs/interpreter/getIntlayerAsync.cjs +10 -1
- package/dist/cjs/interpreter/getIntlayerAsync.cjs.map +1 -1
- package/dist/cjs/interpreter/index.cjs +5 -0
- package/dist/cjs/interpreter/resolveInterpreterLocale.cjs +101 -0
- package/dist/cjs/interpreter/resolveInterpreterLocale.cjs.map +1 -0
- package/dist/cjs/localization/getLocaleFromRequest.cjs +1 -1
- package/dist/cjs/localization/resolveBrowserLocale.cjs +1 -1
- package/dist/cjs/localization/rewriteMatch.cjs +11 -1
- package/dist/cjs/localization/rewriteMatch.cjs.map +1 -1
- package/dist/cjs/markdown/compiler.cjs.map +1 -1
- package/dist/cjs/markdown/constants.cjs.map +1 -1
- package/dist/cjs/transpiler/markdown/getMarkdownMetadata.cjs +29 -9
- package/dist/cjs/transpiler/markdown/getMarkdownMetadata.cjs.map +1 -1
- package/dist/cjs/transpiler/markdown/markdown.cjs.map +1 -1
- package/dist/cjs/utils/index.cjs +2 -2
- package/dist/cjs/utils/intl.cjs.map +1 -1
- package/dist/esm/index.mjs +4 -3
- package/dist/esm/interpreter/getDictionary.mjs +4 -3
- package/dist/esm/interpreter/getDictionary.mjs.map +1 -1
- package/dist/esm/interpreter/getDictionaryAsync.mjs +2 -2
- package/dist/esm/interpreter/getDictionaryAsync.mjs.map +1 -1
- package/dist/esm/interpreter/getIntlayer.mjs +1 -1
- package/dist/esm/interpreter/getIntlayer.mjs.map +1 -1
- package/dist/esm/interpreter/getIntlayerAsync.mjs +10 -1
- package/dist/esm/interpreter/getIntlayerAsync.mjs.map +1 -1
- package/dist/esm/interpreter/index.mjs +2 -1
- package/dist/esm/interpreter/resolveInterpreterLocale.mjs +97 -0
- package/dist/esm/interpreter/resolveInterpreterLocale.mjs.map +1 -0
- package/dist/esm/localization/getLocaleFromRequest.mjs +1 -1
- package/dist/esm/localization/resolveBrowserLocale.mjs +1 -1
- package/dist/esm/localization/rewriteMatch.mjs +11 -1
- package/dist/esm/localization/rewriteMatch.mjs.map +1 -1
- package/dist/esm/markdown/compiler.mjs +1 -1
- package/dist/esm/markdown/compiler.mjs.map +1 -1
- package/dist/esm/markdown/constants.mjs +3 -0
- package/dist/esm/markdown/constants.mjs.map +1 -1
- package/dist/esm/transpiler/markdown/getMarkdownMetadata.mjs +29 -9
- package/dist/esm/transpiler/markdown/getMarkdownMetadata.mjs.map +1 -1
- package/dist/esm/transpiler/markdown/markdown.mjs +1 -1
- package/dist/esm/transpiler/markdown/markdown.mjs.map +1 -1
- package/dist/esm/utils/index.mjs +2 -2
- package/dist/esm/utils/intl.mjs +1 -0
- package/dist/esm/utils/intl.mjs.map +1 -1
- package/dist/types/index.d.ts +2 -1
- package/dist/types/interpreter/getIntlayerAsync.d.ts.map +1 -1
- package/dist/types/interpreter/index.d.ts +2 -1
- package/dist/types/interpreter/resolveInterpreterLocale.d.ts +63 -0
- package/dist/types/interpreter/resolveInterpreterLocale.d.ts.map +1 -0
- package/dist/types/localization/rewriteMatch.d.ts.map +1 -1
- package/dist/types/transpiler/markdown/getMarkdownMetadata.d.ts.map +1 -1
- package/package.json +5 -5
package/dist/cjs/utils/index.cjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_utils_getCookie = require('./getCookie.cjs');
|
|
3
|
+
const require_utils_localeStorage = require('./localeStorage.cjs');
|
|
2
4
|
const require_utils_intl = require('./intl.cjs');
|
|
3
5
|
const require_utils_parseYaml = require('./parseYaml.cjs');
|
|
4
6
|
const require_utils_isValidReactElement = require('./isValidReactElement.cjs');
|
|
5
7
|
const require_utils_checkIsURLAbsolute = require('./checkIsURLAbsolute.cjs');
|
|
6
|
-
const require_utils_getCookie = require('./getCookie.cjs');
|
|
7
|
-
const require_utils_localeStorage = require('./localeStorage.cjs');
|
|
8
8
|
const require_utils_intlayerNodePrototype = require('./intlayerNodePrototype.cjs');
|
|
9
9
|
const require_utils_isSameKeyPath = require('./isSameKeyPath.cjs');
|
|
10
10
|
const require_utils_stringifyYaml = require('./stringifyYaml.cjs');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intl.cjs","names":["internationalization"],"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 { internationalization } 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\n/**\n * Minimal `Intl.ListFormat` surface, declared locally so consumers do not need\n * the `ES2021.Intl` lib in their tsconfig.\n */\ntype ListFormatInstance = {\n format(list: Iterable<string>): string;\n formatToParts(\n list: Iterable<string>\n ): { type: 'element' | 'literal'; value: string }[];\n};\n\n/**\n * Minimal `Intl.Segmenter` surface, declared locally so consumers do not need\n * the `ES2022.Intl` lib in their tsconfig.\n */\ntype SegmenterInstance = {\n segment(input: string): Iterable<{ segment: string; index: number }>;\n};\n\n/**\n * Instance type produced by each `Intl` constructor this module can build.\n */\ntype IntlInstanceByName = {\n Collator: Intl.Collator;\n DateTimeFormat: Intl.DateTimeFormat;\n DisplayNames: Intl.DisplayNames;\n ListFormat: ListFormatInstance;\n Locale: Intl.Locale;\n NumberFormat: Intl.NumberFormat;\n PluralRules: Intl.PluralRules;\n RelativeTimeFormat: Intl.RelativeTimeFormat;\n Segmenter: SegmenterInstance;\n};\n\n/**\n * Names of the `Intl` constructors this module knows how to instantiate.\n */\nexport type IntlConstructorName = keyof IntlInstanceByName;\n\nconst alreadyWarnedConstructors = new Set<string>();\n\n/**\n * Warns once per missing `Intl` constructor, in development only.\n */\nconst warnMissingIntlConstructor = (constructorName: string): void => {\n if (process.env.NODE_ENV === 'production') return;\n if (alreadyWarnedConstructors.has(constructorName)) return;\n\n alreadyWarnedConstructors.add(constructorName);\n\n console.warn(\n `[intlayer] \\`Intl.${constructorName}\\` is not available in this JavaScript engine. ` +\n `A degraded fallback is used instead. ` +\n `On React Native, load a polyfill (e.g. \\`@formatjs/intl-${constructorName.toLowerCase()}/polyfill\\`) before rendering your app.`\n );\n};\n\n/**\n * Minimal stand-ins used when the engine ships without the matching `Intl`\n * constructor. Hermes — the default React Native engine — omits\n * `DisplayNames`, `ListFormat` and `Segmenter` in release builds unless the\n * app opts into the full ICU build or loads a polyfill. Without these shims,\n * `new Intl.DisplayNames(...)` throws\n * `TypeError: undefined cannot be used as a constructor` and takes the whole\n * app down at render time.\n *\n * Each shim mirrors only the surface Intlayer relies on, and returns the\n * un-localized input so rendering degrades rather than crashing.\n */\nconst intlConstructorFallbacks: Partial<\n Record<IntlConstructorName, new (locale?: any, options?: any) => any>\n> = {\n DisplayNames: class DisplayNamesFallback {\n /** Returns the requested code unchanged, since no CLDR data is available. */\n public of(code: string): string {\n return code;\n }\n },\n ListFormat: class ListFormatFallback {\n /** Joins the list with a comma, the most neutral separator available. */\n public format(list: Iterable<string>): string {\n return Array.from(list).join(', ');\n }\n\n /** Mirrors `Intl.ListFormat.prototype.formatToParts` shape. */\n public formatToParts(\n list: Iterable<string>\n ): { type: 'element' | 'literal'; value: string }[] {\n return Array.from(list).flatMap((value, index) =>\n index === 0\n ? [{ type: 'element' as const, value }]\n : [\n { type: 'literal' as const, value: ', ' },\n { type: 'element' as const, value },\n ]\n );\n }\n },\n Segmenter: class SegmenterFallback {\n /** Segments by code point, the closest approximation without ICU data. */\n public segment(input: string): { segment: string; index: number }[] {\n let index = 0;\n\n return Array.from(input).map((segment) => {\n const segmentStart = index;\n index += segment.length;\n\n return { segment, index: segmentStart };\n });\n }\n },\n};\n\n/**\n * Resolves an `Intl` constructor by name at call time, falling back to a\n * degraded shim when the engine does not provide it.\n *\n * Resolution is deliberately lazy: React Native apps install their polyfills\n * at startup, which may run after this module is first imported.\n */\nconst resolveIntlConstructor = (\n constructorName: IntlConstructorName\n): (new (locale?: any, options?: any) => any) | undefined => {\n const nativeConstructor = (\n Intl as unknown as Record<string, new (...args: any[]) => any>\n )[constructorName];\n\n if (typeof nativeConstructor === 'function') return nativeConstructor;\n\n warnMissingIntlConstructor(constructorName);\n\n return intlConstructorFallbacks[constructorName];\n};\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 *\n * Prefer passing the constructor *name* (e.g. `'DisplayNames'`) rather than the\n * constructor itself: the name is resolved lazily against the global `Intl`, so\n * late-installed polyfills are picked up and missing constructors degrade to a\n * fallback instead of throwing.\n */\nexport function getCachedIntl<Name extends IntlConstructorName>(\n constructorName: Name,\n locale?: LocalesValues | string,\n options?: any\n): IntlInstanceByName[Name];\nexport function getCachedIntl<T extends new (...args: any[]) => any>(\n Ctor: T,\n locale?: LocalesValues | string,\n options?: any\n): InstanceType<T>;\nexport function getCachedIntl(\n intlConstructor: IntlConstructorName | (new (...args: any[]) => any),\n locale?: LocalesValues | string,\n options?: any\n): any {\n const resLoc = locale ?? internationalization?.defaultLocale;\n\n const optKey = options ? JSON.stringify(options) : '';\n const key = `${resLoc}|${optKey}`;\n\n // Cache per name when available, so two constructors that are both missing\n // from the engine do not collide on a single `undefined` cache bucket.\n const cacheKey = intlConstructor;\n\n let ctorCache = cache.get(cacheKey);\n\n if (!ctorCache) {\n ctorCache = new Map();\n cache.set(cacheKey, ctorCache);\n }\n\n let instance = ctorCache.get(key);\n\n if (!instance) {\n const ResolvedConstructor =\n typeof intlConstructor === 'string'\n ? resolveIntlConstructor(intlConstructor)\n : intlConstructor;\n\n if (typeof ResolvedConstructor !== 'function') {\n throw new Error(\n `[intlayer] \\`Intl.${String(intlConstructor)}\\` is not available in this JavaScript engine and has no fallback. ` +\n `Load the matching polyfill before formatting.`\n );\n }\n\n if (ctorCache.size > MAX_CACHE_SIZE) ctorCache.clear();\n instance = new ResolvedConstructor(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 = (constructorName: IntlConstructorName) =>\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(constructorName, resLoc, resOpts);\n };\n\n return {\n ...Intl,\n Collator: bindWrap('Collator'),\n DateTimeFormat: bindWrap('DateTimeFormat'),\n DisplayNames: bindWrap('DisplayNames'),\n ListFormat: bindWrap('ListFormat'),\n NumberFormat: bindWrap('NumberFormat'),\n PluralRules: bindWrap('PluralRules'),\n RelativeTimeFormat: bindWrap('RelativeTimeFormat'),\n Locale: bindWrap('Locale'),\n Segmenter: bindWrap('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('Collator', locales, options);\n },\n DateTimeFormat: function DateTimeFormat(locales?: any, options?: any) {\n return getCachedIntl('DateTimeFormat', locales, options);\n },\n DisplayNames: function DisplayNames(locales?: any, options?: any) {\n return getCachedIntl('DisplayNames', locales, options);\n },\n ListFormat: function ListFormat(locales?: any, options?: any) {\n return getCachedIntl('ListFormat', locales, options);\n },\n NumberFormat: function NumberFormat(locales?: any, options?: any) {\n return getCachedIntl('NumberFormat', locales, options);\n },\n PluralRules: function PluralRules(locales?: any, options?: any) {\n return getCachedIntl('PluralRules', locales, options);\n },\n RelativeTimeFormat: function RelativeTimeFormat(\n locales?: any,\n options?: any\n ) {\n return getCachedIntl('RelativeTimeFormat', locales, options);\n },\n Segmenter: function Segmenter(locales?: any, options?: any) {\n return getCachedIntl('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,IAA2B;AAyC7C,MAAM,4CAA4B,IAAI,IAAY;;;;AAKlD,MAAM,8BAA8B,oBAAkC;CACpE,IAAI,QAAQ,IAAI,aAAa,cAAc;CAC3C,IAAI,0BAA0B,IAAI,eAAe,GAAG;CAEpD,0BAA0B,IAAI,eAAe;CAE7C,QAAQ,KACN,qBAAqB,gBAAgB,8IAEwB,gBAAgB,YAAY,EAAE,wCAC7F;AACF;;;;;;;;;;;;;AAcA,MAAM,2BAEF;CACF,cAAc,MAAM,qBAAqB;;EAEvC,AAAO,GAAG,MAAsB;GAC9B,OAAO;EACT;CACF;CACA,YAAY,MAAM,mBAAmB;;EAEnC,AAAO,OAAO,MAAgC;GAC5C,OAAO,MAAM,KAAK,IAAI,CAAC,CAAC,KAAK,IAAI;EACnC;;EAGA,AAAO,cACL,MACkD;GAClD,OAAO,MAAM,KAAK,IAAI,CAAC,CAAC,SAAS,OAAO,UACtC,UAAU,IACN,CAAC;IAAE,MAAM;IAAoB;GAAM,CAAC,IACpC,CACE;IAAE,MAAM;IAAoB,OAAO;GAAK,GACxC;IAAE,MAAM;IAAoB;GAAM,CACpC,CACN;EACF;CACF;CACA,WAAW,MAAM,kBAAkB;;EAEjC,AAAO,QAAQ,OAAqD;GAClE,IAAI,QAAQ;GAEZ,OAAO,MAAM,KAAK,KAAK,CAAC,CAAC,KAAK,YAAY;IACxC,MAAM,eAAe;IACrB,SAAS,QAAQ;IAEjB,OAAO;KAAE;KAAS,OAAO;IAAa;GACxC,CAAC;EACH;CACF;AACF;;;;;;;;AASA,MAAM,0BACJ,oBAC2D;CAC3D,MAAM,oBACJ,KACA;CAEF,IAAI,OAAO,sBAAsB,YAAY,OAAO;CAEpD,2BAA2B,eAAe;CAE1C,OAAO,yBAAyB;AAClC;AAuDA,SAAgB,cACd,iBACA,QACA,SACK;CACL,MAAM,SAAS,UAAUA,6CAAsB;CAG/C,MAAM,MAAM,GAAG,OAAO,GADP,UAAU,KAAK,UAAU,OAAO,IAAI;CAKnD,MAAM,WAAW;CAEjB,IAAI,YAAY,MAAM,IAAI,QAAQ;CAElC,IAAI,CAAC,WAAW;EACd,4BAAY,IAAI,IAAI;EACpB,MAAM,IAAI,UAAU,SAAS;CAC/B;CAEA,IAAI,WAAW,UAAU,IAAI,GAAG;CAEhC,IAAI,CAAC,UAAU;EACb,MAAM,sBACJ,OAAO,oBAAoB,WACvB,uBAAuB,eAAe,IACtC;EAEN,IAAI,OAAO,wBAAwB,YACjC,MAAM,IAAI,MACR,qBAAqB,OAAO,eAAe,EAAE,iHAE/C;EAGF,IAAI,UAAU,OAAO,gBAAgB,UAAU,MAAM;EACrD,WAAW,IAAI,oBAAoB,QAAQ,OAAO;EAClD,UAAU,IAAI,KAAK,QAAQ;CAC7B;CACA,OAAO;AACT;;;;;AAMA,MAAa,YAAY,gBAA4C;CACnE,MAAM,YAAY,oBAEhB,SAAS,gBAAgB,SAAe,SAAe;EACrD,MAAM,cACJ,YAAY,QACZ,OAAO,YAAY,YACnB,CAAC,MAAM,QAAQ,OAAO;EACxB,MAAM,UAAU,cAAc,UAAU;EAKxC,OAAO,cAAc,iBAJN,cACV,QAAgB,UAAU,cAC3B,WAAW,aAE+B,OAAO;CACvD;CAEF,OAAO;EACL,GAAG;EACH,UAAU,SAAS,UAAU;EAC7B,gBAAgB,SAAS,gBAAgB;EACzC,cAAc,SAAS,cAAc;EACrC,YAAY,SAAS,YAAY;EACjC,cAAc,SAAS,cAAc;EACrC,aAAa,SAAS,aAAa;EACnC,oBAAoB,SAAS,oBAAoB;EACjD,QAAQ,SAAS,QAAQ;EACzB,WAAW,SAAS,WAAW;CACjC;AACF;AAGA,MAAa,aAAa;CAExB,UAAU,SAAS,SAAS,SAAe,SAAe;EACxD,OAAO,cAAc,YAAY,SAAS,OAAO;CACnD;CACA,gBAAgB,SAAS,eAAe,SAAe,SAAe;EACpE,OAAO,cAAc,kBAAkB,SAAS,OAAO;CACzD;CACA,cAAc,SAAS,aAAa,SAAe,SAAe;EAChE,OAAO,cAAc,gBAAgB,SAAS,OAAO;CACvD;CACA,YAAY,SAAS,WAAW,SAAe,SAAe;EAC5D,OAAO,cAAc,cAAc,SAAS,OAAO;CACrD;CACA,cAAc,SAAS,aAAa,SAAe,SAAe;EAChE,OAAO,cAAc,gBAAgB,SAAS,OAAO;CACvD;CACA,aAAa,SAAS,YAAY,SAAe,SAAe;EAC9D,OAAO,cAAc,eAAe,SAAS,OAAO;CACtD;CACA,oBAAoB,SAAS,mBAC3B,SACA,SACA;EACA,OAAO,cAAc,sBAAsB,SAAS,OAAO;CAC7D;CACA,WAAW,SAAS,UAAU,SAAe,SAAe;EAC1D,OAAO,cAAc,aAAa,SAAS,OAAO;CACpD;AACF"}
|
|
1
|
+
{"version":3,"file":"intl.cjs","names":["internationalization"],"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 { internationalization } 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\n/**\n * Minimal `Intl.ListFormat` surface, declared locally so consumers do not need\n * the `ES2021.Intl` lib in their tsconfig.\n */\ntype ListFormatInstance = {\n format(list: Iterable<string>): string;\n formatToParts(\n list: Iterable<string>\n ): { type: 'element' | 'literal'; value: string }[];\n};\n\n/**\n * Minimal `Intl.Segmenter` surface, declared locally so consumers do not need\n * the `ES2022.Intl` lib in their tsconfig.\n */\ntype SegmenterInstance = {\n segment(input: string): Iterable<{ segment: string; index: number }>;\n};\n\n/**\n * Instance type produced by each `Intl` constructor this module can build.\n */\ntype IntlInstanceByName = {\n Collator: Intl.Collator;\n DateTimeFormat: Intl.DateTimeFormat;\n DisplayNames: Intl.DisplayNames;\n ListFormat: ListFormatInstance;\n Locale: Intl.Locale;\n NumberFormat: Intl.NumberFormat;\n PluralRules: Intl.PluralRules;\n RelativeTimeFormat: Intl.RelativeTimeFormat;\n Segmenter: SegmenterInstance;\n};\n\n/**\n * Names of the `Intl` constructors this module knows how to instantiate.\n */\nexport type IntlConstructorName = keyof IntlInstanceByName;\n\nconst alreadyWarnedConstructors = new Set<string>();\n\n/**\n * Warns once per missing `Intl` constructor, in development only.\n */\nconst warnMissingIntlConstructor = (constructorName: string): void => {\n if (process.env.NODE_ENV === 'production') return;\n if (alreadyWarnedConstructors.has(constructorName)) return;\n\n alreadyWarnedConstructors.add(constructorName);\n\n console.warn(\n `[intlayer] \\`Intl.${constructorName}\\` is not available in this JavaScript engine. ` +\n `A degraded fallback is used instead. ` +\n `On React Native, load a polyfill (e.g. \\`@formatjs/intl-${constructorName.toLowerCase()}/polyfill\\`) before rendering your app.`\n );\n};\n\n/**\n * Minimal stand-ins used when the engine ships without the matching `Intl`\n * constructor. Hermes — the default React Native engine — omits\n * `DisplayNames`, `ListFormat` and `Segmenter` in release builds unless the\n * app opts into the full ICU build or loads a polyfill. Without these shims,\n * `new Intl.DisplayNames(...)` throws\n * `TypeError: undefined cannot be used as a constructor` and takes the whole\n * app down at render time.\n *\n * Each shim mirrors only the surface Intlayer relies on, and returns the\n * un-localized input so rendering degrades rather than crashing.\n */\nconst intlConstructorFallbacks: Partial<\n Record<IntlConstructorName, new (locale?: any, options?: any) => any>\n> = {\n DisplayNames: class DisplayNamesFallback {\n /** Returns the requested code unchanged, since no CLDR data is available. */\n public of(code: string): string {\n return code;\n }\n },\n ListFormat: class ListFormatFallback {\n /** Joins the list with a comma, the most neutral separator available. */\n public format(list: Iterable<string>): string {\n return Array.from(list).join(', ');\n }\n\n /** Mirrors `Intl.ListFormat.prototype.formatToParts` shape. */\n public formatToParts(\n list: Iterable<string>\n ): { type: 'element' | 'literal'; value: string }[] {\n return Array.from(list).flatMap((value, index) =>\n index === 0\n ? [{ type: 'element' as const, value }]\n : [\n { type: 'literal' as const, value: ', ' },\n { type: 'element' as const, value },\n ]\n );\n }\n },\n Segmenter: class SegmenterFallback {\n /** Segments by code point, the closest approximation without ICU data. */\n public segment(input: string): { segment: string; index: number }[] {\n let index = 0;\n\n return Array.from(input).map((segment) => {\n const segmentStart = index;\n index += segment.length;\n\n return { segment, index: segmentStart };\n });\n }\n },\n};\n\n/**\n * Resolves an `Intl` constructor by name at call time, falling back to a\n * degraded shim when the engine does not provide it.\n *\n * Resolution is deliberately lazy: React Native apps install their polyfills\n * at startup, which may run after this module is first imported.\n */\nconst resolveIntlConstructor = (\n constructorName: IntlConstructorName\n): (new (locale?: any, options?: any) => any) | undefined => {\n const nativeConstructor = (\n Intl as unknown as Record<string, new (...args: any[]) => any>\n )[constructorName];\n\n if (typeof nativeConstructor === 'function') return nativeConstructor;\n\n warnMissingIntlConstructor(constructorName);\n\n return intlConstructorFallbacks[constructorName];\n};\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 *\n * Prefer passing the constructor *name* (e.g. `'DisplayNames'`) rather than the\n * constructor itself: the name is resolved lazily against the global `Intl`, so\n * late-installed polyfills are picked up and missing constructors degrade to a\n * fallback instead of throwing.\n */\nexport function getCachedIntl<Name extends IntlConstructorName>(\n constructorName: Name,\n locale?: LocalesValues | string,\n options?: any\n): IntlInstanceByName[Name];\nexport function getCachedIntl<T extends new (...args: any[]) => any>(\n Ctor: T,\n locale?: LocalesValues | string,\n options?: any\n): InstanceType<T>;\nexport function getCachedIntl(\n intlConstructor: IntlConstructorName | (new (...args: any[]) => any),\n locale?: LocalesValues | string,\n options?: any\n): any {\n const resLoc = locale ?? internationalization?.defaultLocale;\n\n const optKey = options ? JSON.stringify(options) : '';\n const key = `${resLoc}|${optKey}`;\n\n // Cache per name when available, so two constructors that are both missing\n // from the engine do not collide on a single `undefined` cache bucket.\n const cacheKey = intlConstructor;\n\n let ctorCache = cache.get(cacheKey);\n\n if (!ctorCache) {\n ctorCache = new Map();\n cache.set(cacheKey, ctorCache);\n }\n\n let instance = ctorCache.get(key);\n\n if (!instance) {\n const ResolvedConstructor =\n typeof intlConstructor === 'string'\n ? resolveIntlConstructor(intlConstructor)\n : intlConstructor;\n\n if (typeof ResolvedConstructor !== 'function') {\n throw new Error(\n `[intlayer] \\`Intl.${String(intlConstructor)}\\` is not available in this JavaScript engine and has no fallback. ` +\n `Load the matching polyfill before formatting.`\n );\n }\n\n if (ctorCache.size > MAX_CACHE_SIZE) ctorCache.clear();\n instance = new ResolvedConstructor(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 = (constructorName: IntlConstructorName) =>\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(constructorName, resLoc, resOpts);\n };\n\n return {\n ...Intl,\n Collator: bindWrap('Collator'),\n DateTimeFormat: bindWrap('DateTimeFormat'),\n DisplayNames: bindWrap('DisplayNames'),\n ListFormat: bindWrap('ListFormat'),\n NumberFormat: bindWrap('NumberFormat'),\n PluralRules: bindWrap('PluralRules'),\n RelativeTimeFormat: bindWrap('RelativeTimeFormat'),\n Locale: bindWrap('Locale'),\n Segmenter: bindWrap('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('Collator', locales, options);\n },\n DateTimeFormat: function DateTimeFormat(locales?: any, options?: any) {\n return getCachedIntl('DateTimeFormat', locales, options);\n },\n DisplayNames: function DisplayNames(locales?: any, options?: any) {\n return getCachedIntl('DisplayNames', locales, options);\n },\n ListFormat: function ListFormat(locales?: any, options?: any) {\n return getCachedIntl('ListFormat', locales, options);\n },\n NumberFormat: function NumberFormat(locales?: any, options?: any) {\n return getCachedIntl('NumberFormat', locales, options);\n },\n PluralRules: function PluralRules(locales?: any, options?: any) {\n return getCachedIntl('PluralRules', locales, options);\n },\n RelativeTimeFormat: function RelativeTimeFormat(\n locales?: any,\n options?: any\n ) {\n return getCachedIntl('RelativeTimeFormat', locales, options);\n },\n Segmenter: function Segmenter(locales?: any, options?: any) {\n return getCachedIntl('Segmenter', locales, options);\n },\n} as any; // Cast to 'any' internally to avoid TS readonly errors\n\nexport { CachedIntl as Intl };\n"],"mappings":"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"}
|
package/dist/esm/index.mjs
CHANGED
|
@@ -6,6 +6,9 @@ import { findMatchingCondition, getEnumeration } from "./interpreter/getEnumerat
|
|
|
6
6
|
import { getGender } from "./interpreter/getGender.mjs";
|
|
7
7
|
import { getInsertion } from "./interpreter/getInsertion.mjs";
|
|
8
8
|
import { COMPOSITE_ID_SEPARATOR, DEFAULT_VARIANT_ID, getDictionarySelectorCacheKey, isQualifiedDictionaryGroup, parseDictionarySelector, reconstructQualifiedEntry, resolveDictionaryArgument, resolveEffectiveVariantId, resolveProviderVariant, resolveQualifiedDictionary, serializeVariant, serializeVariantChain } from "./dictionaryManipulator/qualifiedDictionary.mjs";
|
|
9
|
+
import { getCookie } from "./utils/getCookie.mjs";
|
|
10
|
+
import { LocaleStorage, LocaleStorageClient, LocaleStorageServer, getCachedLocaleFromStorageClient, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, localeStorageOptions, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer } from "./utils/localeStorage.mjs";
|
|
11
|
+
import { registerAmbientLocaleResolver, registerAsyncAmbientLocaleResolver, resolveInterpreterLocale, resolveInterpreterLocaleAsync } from "./interpreter/resolveInterpreterLocale.mjs";
|
|
9
12
|
import { getDictionary } from "./interpreter/getDictionary.mjs";
|
|
10
13
|
import { getIntlayer } from "./interpreter/getIntlayer.mjs";
|
|
11
14
|
import { getNesting } from "./interpreter/getNesting.mjs";
|
|
@@ -85,8 +88,6 @@ import { getLocalizedPath } from "./localization/getLocalizedPath.mjs";
|
|
|
85
88
|
import { getLocalizedUrl } from "./localization/getLocalizedUrl.mjs";
|
|
86
89
|
import { getMultilingualUrls } from "./localization/getMultilingualUrls.mjs";
|
|
87
90
|
import { generateSitemap, generateSitemapUrl } from "./localization/generateSitemap.mjs";
|
|
88
|
-
import { getCookie } from "./utils/getCookie.mjs";
|
|
89
|
-
import { LocaleStorage, LocaleStorageClient, LocaleStorageServer, getCachedLocaleFromStorageClient, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, localeStorageOptions, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer } from "./utils/localeStorage.mjs";
|
|
90
91
|
import { localeResolver } from "./localization/localeResolver.mjs";
|
|
91
92
|
import { localeDetector } from "./localization/localeDetector.mjs";
|
|
92
93
|
import { getBrowserLocale } from "./localization/getBrowserLocale.mjs";
|
|
@@ -115,4 +116,4 @@ import { getIntlayerNodePrototype } from "./utils/intlayerNodePrototype.mjs";
|
|
|
115
116
|
import { isSameKeyPath } from "./utils/isSameKeyPath.mjs";
|
|
116
117
|
import { stringifyYaml } from "./utils/stringifyYaml.mjs";
|
|
117
118
|
|
|
118
|
-
export { ATTRIBUTES_TO_SANITIZE, ATTRIBUTE_NAME_START_R, ATTRIBUTE_TO_NODE_PROP_MAP, ATTR_EXTRACTOR_R, BLOCKQUOTE_ALERT_R, BLOCKQUOTE_R, BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, BLOCK_END_R, BREAK_LINE_R, BREAK_THEMATIC_R, CAPTURE_LETTER_AFTER_HYPHEN, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, COMPOSITE_ID_SEPARATOR, CONSECUTIVE_NEWLINE_R, CR_NEWLINE_R, CachedIntl, CachedIntl as Intl, DEFAULT_VARIANT_ID, DO_NOT_PROCESS_HTML_ELEMENTS, FENCE_DELIMITER_R, FOOTNOTE_R, FOOTNOTE_REFERENCE_R, FORMFEED_R, FRONT_MATTER_R, GFM_TASK_R, HEADING_ATX_COMPLIANT_R, HEADING_R, HEADING_SETEXT_R, HTML_CHAR_CODE_R, HTML_COMMENT_R, HTML_CUSTOM_ATTR_R, HTML_LEFT_TRIM_AMOUNT_R, HTML_TAGS, INLINE_SKIP_R, INTERPOLATION_R, LINK_AUTOLINK_BARE_URL_R, LINK_AUTOLINK_R, LOOKAHEAD, LocaleStorage, LocaleStorageClient, LocaleStorageServer, NAMED_CODES_TO_UNICODE, NP_TABLE_R, ORDERED, ORDERED_LIST_BULLET, ORDERED_LIST_ITEM_PREFIX, ORDERED_LIST_ITEM_PREFIX_R, ORDERED_LIST_ITEM_R, ORDERED_LIST_R, PARAGRAPH_R, PRELOADED_DYNAMIC_KEY, Priority, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, REFERENCE_IMAGE_OR_LINK, REFERENCE_IMAGE_R, REFERENCE_LINK_R, RuleScope, RuleType, SCOPE_BLOCK, SCOPE_BOTH, SCOPE_INLINE, SHORTCODE_R, SHOULD_RENDER_AS_BLOCK_R, TABLE_CENTER_ALIGN, TABLE_LEFT_ALIGN, TABLE_RIGHT_ALIGN, TABLE_TRIM_PIPES, TAB_R, TEXT_BOLD_R, TEXT_EMPHASIZED_R, TEXT_ESCAPED_R, TEXT_MARKED_R, TEXT_STRIKETHROUGHED_R, TRIM_STARTING_NEWLINES, UNESCAPE_R, UNORDERED, UNORDERED_LIST_BULLET, UNORDERED_LIST_ITEM_PREFIX, UNORDERED_LIST_ITEM_PREFIX_R, UNORDERED_LIST_ITEM_R, UNORDERED_LIST_R, VOID_HTML_ELEMENTS, allowInline, anyScopeRegex, attributeValueToNodePropValue, bindInsertedValues, bindIntl, blockRegex, buildMaskPlugin, captureNothing, checkIsURLAbsolute, checkMissingLocalesPlugin, compact, comparePaths, compile, compileWithOptions, condition as cond, conditionPlugin, createCompiler, createMessageResolver, createRenderer, currency, cx, date, deepTransformNode, editDictionaryByKeyPath, enumeration as enu, enumerationPlugin, fallbackPlugin, filePlugin, filterMissingTranslationsOnlyPlugin, filterTranslationsOnlyPlugin, findMatchingCondition, findPlainDynamicLoader, formatProxyEnabledMessage, gender, genderPlugin, generateListItemPrefix, generateListItemPrefixRegex, generateListItemRegex, generateListRegex, generateSitemap, generateSitemapUrl, get, getBasePlugins, getBrowserLocale, getCachedIntl, getCachedLocaleFromStorageClient, getCanonicalPath, getCondition, getContent, getContentNodeByKeyPath, getCookie, getDefaultNode, getDictionary, getDictionaryAsync, getDictionaryCompositeIds, getDictionaryQualifierIds, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getDictionaryTransformCacheKey, getDomainHostname, getDomainOrigin, getEditedContent, getEditedDictionary, getEmptyNode, getEnumeration, getFilterMissingTranslationsContent, getFilterMissingTranslationsDictionary, getFilterTranslationsOnlyContent, getFilterTranslationsOnlyDictionary, getFilteredLocalesContent, getFilteredLocalesDictionary, getGender, getHTML, getHTMLTextDir, getInsertion, getInsertionValues, getInternalPath, getInterpolableContent, getIntlayer, getIntlayerAsync, getIntlayerNodePrototype, getLocale, getLocaleFromDomain, getLocaleFromPath, getLocaleFromRequest, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, getLocaleLang, getLocaleName, getLocalizedContent, getLocalizedPath, getLocalizedUrl, getMarkdownMetadata, getMaskContent, getMissingLocalesContent, getMissingLocalesContentFromDictionary, getMultilingualDictionary, getMultilingualUrls, getNestedDictionaryGraph, getNestedDictionaryKeys, getNestedDictionaryReferences, getNesting, getNodeChildren, getNodeType, getPathWithoutLocale, getPerLocaleDictionary, getPluginsCacheKey, getPlural, getPrefix, getPreloadLocale, getPreloadedDictionary, getReplacedValuesContent, getRewritePath, getRewriteRules, getRuleSet, getSelect, getSplittedContent, getSplittedDictionaryContent, getTranslation, getVariantIds, html, i18nextToIntlayerFormatter, icuToIntlayerFormatter, inlineRegex, insertion as insert, insertContentInDictionary, insertionPlugin, interpolateMessage, intlayerToI18nextFormatter, intlayerToICUFormatter, intlayerToPortableObjectFormatter, intlayerToVueI18nFormatter, isDeclaredLocale, isInterpolableWrapperNode, isLocaleExclusiveOnDomain, isProxyStorageLocaleEnabled, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, isSameKeyPath, isValidElement, list, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, localeStorageOptions, markdown as md, mergeDictionaries, mergeQualifiedDictionaries, navigatePath, nesting as nest, nestedPlugin, normalizeAttributeKey, normalizeDictionaries, normalizeDictionary, normalizePath, normalizeWhitespace, number, orderDictionaries, parseBlock, parseCaptureInline, parseDictionarySelector, parseInline, parseMarkdown, parseSimpleInline, parseStyleAttribute, parseTableAlign, parseTableAlignCapture, parseTableCells, parseTableRow, parseTaggedMessage, parseYaml, parserFor, percentage, plural, pluralPlugin, portableObjectToIntlayerFormatter, presets, qualifies, readTransformCache, rebuildInterpolableContent, reconstructQualifiedEntry, relativeTime, removeContentNodeByKeyPath, renameContentNodeByKeyPath, renderFor, renderMarkdownAst, renderNothing, resolveBrowserLocale, resolveDictionaryArgument, resolveEffectiveVariantId, resolveInsertedSelector, resolveLocalizedPath, resolveMessage, resolveMessageNode, resolveMessageNodeToString, resolvePlainDynamicLoader, resolveProviderVariant, resolveProxyMode, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, sanitizer, select, selectPlugin, serializeVariant, serializeVariantChain, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer, simpleInlineRegex, slugify, some, splitInsertionTemplate, startsWith, stringifyYaml, translation as t, transformInterpolableNode, translationPlugin, trimEnd, trimLeadingWhitespaceOutsideFences, unescapeString, units, unquote, updateNodeChildren, validateHTML, validateMarkdown, validatePrefix, vueI18nToIntlayerFormatter, writeTransformCache };
|
|
119
|
+
export { ATTRIBUTES_TO_SANITIZE, ATTRIBUTE_NAME_START_R, ATTRIBUTE_TO_NODE_PROP_MAP, ATTR_EXTRACTOR_R, BLOCKQUOTE_ALERT_R, BLOCKQUOTE_R, BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, BLOCK_END_R, BREAK_LINE_R, BREAK_THEMATIC_R, CAPTURE_LETTER_AFTER_HYPHEN, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, COMPOSITE_ID_SEPARATOR, CONSECUTIVE_NEWLINE_R, CR_NEWLINE_R, CachedIntl, CachedIntl as Intl, DEFAULT_VARIANT_ID, DO_NOT_PROCESS_HTML_ELEMENTS, FENCE_DELIMITER_R, FOOTNOTE_R, FOOTNOTE_REFERENCE_R, FORMFEED_R, FRONT_MATTER_R, GFM_TASK_R, HEADING_ATX_COMPLIANT_R, HEADING_R, HEADING_SETEXT_R, HTML_CHAR_CODE_R, HTML_COMMENT_R, HTML_CUSTOM_ATTR_R, HTML_LEFT_TRIM_AMOUNT_R, HTML_TAGS, INLINE_SKIP_R, INTERPOLATION_R, LINK_AUTOLINK_BARE_URL_R, LINK_AUTOLINK_R, LOOKAHEAD, LocaleStorage, LocaleStorageClient, LocaleStorageServer, NAMED_CODES_TO_UNICODE, NP_TABLE_R, ORDERED, ORDERED_LIST_BULLET, ORDERED_LIST_ITEM_PREFIX, ORDERED_LIST_ITEM_PREFIX_R, ORDERED_LIST_ITEM_R, ORDERED_LIST_R, PARAGRAPH_R, PRELOADED_DYNAMIC_KEY, Priority, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, REFERENCE_IMAGE_OR_LINK, REFERENCE_IMAGE_R, REFERENCE_LINK_R, RuleScope, RuleType, SCOPE_BLOCK, SCOPE_BOTH, SCOPE_INLINE, SHORTCODE_R, SHOULD_RENDER_AS_BLOCK_R, TABLE_CENTER_ALIGN, TABLE_LEFT_ALIGN, TABLE_RIGHT_ALIGN, TABLE_TRIM_PIPES, TAB_R, TEXT_BOLD_R, TEXT_EMPHASIZED_R, TEXT_ESCAPED_R, TEXT_MARKED_R, TEXT_STRIKETHROUGHED_R, TRIM_STARTING_NEWLINES, UNESCAPE_R, UNORDERED, UNORDERED_LIST_BULLET, UNORDERED_LIST_ITEM_PREFIX, UNORDERED_LIST_ITEM_PREFIX_R, UNORDERED_LIST_ITEM_R, UNORDERED_LIST_R, VOID_HTML_ELEMENTS, allowInline, anyScopeRegex, attributeValueToNodePropValue, bindInsertedValues, bindIntl, blockRegex, buildMaskPlugin, captureNothing, checkIsURLAbsolute, checkMissingLocalesPlugin, compact, comparePaths, compile, compileWithOptions, condition as cond, conditionPlugin, createCompiler, createMessageResolver, createRenderer, currency, cx, date, deepTransformNode, editDictionaryByKeyPath, enumeration as enu, enumerationPlugin, fallbackPlugin, filePlugin, filterMissingTranslationsOnlyPlugin, filterTranslationsOnlyPlugin, findMatchingCondition, findPlainDynamicLoader, formatProxyEnabledMessage, gender, genderPlugin, generateListItemPrefix, generateListItemPrefixRegex, generateListItemRegex, generateListRegex, generateSitemap, generateSitemapUrl, get, getBasePlugins, getBrowserLocale, getCachedIntl, getCachedLocaleFromStorageClient, getCanonicalPath, getCondition, getContent, getContentNodeByKeyPath, getCookie, getDefaultNode, getDictionary, getDictionaryAsync, getDictionaryCompositeIds, getDictionaryQualifierIds, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getDictionaryTransformCacheKey, getDomainHostname, getDomainOrigin, getEditedContent, getEditedDictionary, getEmptyNode, getEnumeration, getFilterMissingTranslationsContent, getFilterMissingTranslationsDictionary, getFilterTranslationsOnlyContent, getFilterTranslationsOnlyDictionary, getFilteredLocalesContent, getFilteredLocalesDictionary, getGender, getHTML, getHTMLTextDir, getInsertion, getInsertionValues, getInternalPath, getInterpolableContent, getIntlayer, getIntlayerAsync, getIntlayerNodePrototype, getLocale, getLocaleFromDomain, getLocaleFromPath, getLocaleFromRequest, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, getLocaleLang, getLocaleName, getLocalizedContent, getLocalizedPath, getLocalizedUrl, getMarkdownMetadata, getMaskContent, getMissingLocalesContent, getMissingLocalesContentFromDictionary, getMultilingualDictionary, getMultilingualUrls, getNestedDictionaryGraph, getNestedDictionaryKeys, getNestedDictionaryReferences, getNesting, getNodeChildren, getNodeType, getPathWithoutLocale, getPerLocaleDictionary, getPluginsCacheKey, getPlural, getPrefix, getPreloadLocale, getPreloadedDictionary, getReplacedValuesContent, getRewritePath, getRewriteRules, getRuleSet, getSelect, getSplittedContent, getSplittedDictionaryContent, getTranslation, getVariantIds, html, i18nextToIntlayerFormatter, icuToIntlayerFormatter, inlineRegex, insertion as insert, insertContentInDictionary, insertionPlugin, interpolateMessage, intlayerToI18nextFormatter, intlayerToICUFormatter, intlayerToPortableObjectFormatter, intlayerToVueI18nFormatter, isDeclaredLocale, isInterpolableWrapperNode, isLocaleExclusiveOnDomain, isProxyStorageLocaleEnabled, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, isSameKeyPath, isValidElement, list, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, localeStorageOptions, markdown as md, mergeDictionaries, mergeQualifiedDictionaries, navigatePath, nesting as nest, nestedPlugin, normalizeAttributeKey, normalizeDictionaries, normalizeDictionary, normalizePath, normalizeWhitespace, number, orderDictionaries, parseBlock, parseCaptureInline, parseDictionarySelector, parseInline, parseMarkdown, parseSimpleInline, parseStyleAttribute, parseTableAlign, parseTableAlignCapture, parseTableCells, parseTableRow, parseTaggedMessage, parseYaml, parserFor, percentage, plural, pluralPlugin, portableObjectToIntlayerFormatter, presets, qualifies, readTransformCache, rebuildInterpolableContent, reconstructQualifiedEntry, registerAmbientLocaleResolver, registerAsyncAmbientLocaleResolver, relativeTime, removeContentNodeByKeyPath, renameContentNodeByKeyPath, renderFor, renderMarkdownAst, renderNothing, resolveBrowserLocale, resolveDictionaryArgument, resolveEffectiveVariantId, resolveInsertedSelector, resolveInterpreterLocale, resolveInterpreterLocaleAsync, resolveLocalizedPath, resolveMessage, resolveMessageNode, resolveMessageNodeToString, resolvePlainDynamicLoader, resolveProviderVariant, resolveProxyMode, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, sanitizer, select, selectPlugin, serializeVariant, serializeVariantChain, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer, simpleInlineRegex, slugify, some, splitInsertionTemplate, startsWith, stringifyYaml, translation as t, transformInterpolableNode, translationPlugin, trimEnd, trimLeadingWhitespaceOutsideFences, unescapeString, units, unquote, updateNodeChildren, validateHTML, validateMarkdown, validatePrefix, vueI18nToIntlayerFormatter, writeTransformCache };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getDictionaryTransformCacheKey, readTransformCache, writeTransformCache } from "./dictionaryTransformCache.mjs";
|
|
2
2
|
import { getDictionarySelectorCacheKey, parseDictionarySelector, resolveQualifiedDictionary } from "../dictionaryManipulator/qualifiedDictionary.mjs";
|
|
3
|
+
import { resolveInterpreterLocale } from "./resolveInterpreterLocale.mjs";
|
|
3
4
|
import { getBasePlugins, getContent } from "./getContent/getContent.mjs";
|
|
4
|
-
import { internationalization } from "@intlayer/config/built";
|
|
5
5
|
|
|
6
6
|
//#region src/interpreter/getDictionary.ts
|
|
7
7
|
/**
|
|
@@ -20,11 +20,12 @@ const transformsInProgress = /* @__PURE__ */ new WeakSet();
|
|
|
20
20
|
* If omitted, we’ll use a default set of plugins.
|
|
21
21
|
*/
|
|
22
22
|
const getDictionary = (dictionary, localeOrSelector, plugins) => {
|
|
23
|
-
const { locale, selector } = process.env.INTLAYER_DICTIONARY_SELECTOR !== "false" ? parseDictionarySelector(localeOrSelector) : {
|
|
23
|
+
const { locale: requestedLocale, selector } = process.env.INTLAYER_DICTIONARY_SELECTOR !== "false" ? parseDictionarySelector(localeOrSelector) : {
|
|
24
24
|
locale: localeOrSelector,
|
|
25
25
|
selector: void 0
|
|
26
26
|
};
|
|
27
|
-
const
|
|
27
|
+
const locale = resolveInterpreterLocale(requestedLocale);
|
|
28
|
+
const cacheKey = getDictionaryTransformCacheKey(locale, process.env.INTLAYER_DICTIONARY_SELECTOR !== "false" ? getDictionarySelectorCacheKey(selector) : "", plugins);
|
|
28
29
|
const cached = readTransformCache(dictionary, cacheKey);
|
|
29
30
|
if (cached.hit) return cached.content;
|
|
30
31
|
const appliedPlugins = plugins ?? getBasePlugins(locale);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getDictionary.mjs","names":[],"sources":["../../../src/interpreter/getDictionary.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"getDictionary.mjs","names":[],"sources":["../../../src/interpreter/getDictionary.ts"],"sourcesContent":["import type {\n Dictionary,\n DictionarySelector,\n QualifiedDictionaryGroup,\n ResolveQualifiedDictionaryContent,\n} from '@intlayer/types/dictionary';\nimport type {\n DeclaredLocales,\n ExtractSelectorLocale,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport {\n getDictionarySelectorCacheKey,\n parseDictionarySelector,\n resolveQualifiedDictionary,\n} from '../dictionaryManipulator/qualifiedDictionary';\nimport {\n getDictionaryTransformCacheKey,\n readTransformCache,\n writeTransformCache,\n} from './dictionaryTransformCache';\nimport type {\n DeepTransformContent,\n IInterpreterPluginState,\n NodeProps,\n Plugins,\n} from './getContent';\nimport { getBasePlugins, getContent } from './getContent/getContent';\nimport { resolveInterpreterLocale } from './resolveInterpreterLocale';\n\n/**\n * Dictionaries whose transform is running. Content is transformed eagerly, so a\n * dictionary reached again through a `nest()` cycle is transformed lazily\n * instead: its nodes then resolve on read, and the cycle unwinds.\n */\nconst transformsInProgress = new WeakSet<object>();\n\n/**\n * Transforms a dictionary in a single pass, applying each plugin as needed.\n *\n * @param dictionary The dictionary (or qualified dictionary group) to transform.\n * @param localeOrSelector The locale, or a selector object (`{ item }`,\n * `{ variant }`, optionally with `locale`).\n * @param plugins An array of NodeTransformer that define how to transform recognized nodes.\n * If omitted, we’ll use a default set of plugins.\n */\nexport const getDictionary = <\n const T extends Dictionary | QualifiedDictionaryGroup,\n const A extends LocalesValues | DictionarySelector = DeclaredLocales,\n>(\n dictionary: T,\n localeOrSelector?: A,\n plugins?: Plugins[]\n): DeepTransformContent<\n ResolveQualifiedDictionaryContent<T, A>,\n IInterpreterPluginState,\n ExtractSelectorLocale<A>\n> => {\n // The selector checks stay inline so bundlers can drop the whole\n // qualified-dictionary module when no dictionary declares a qualifier.\n const { locale: requestedLocale, selector } =\n process.env.INTLAYER_DICTIONARY_SELECTOR !== 'false'\n ? parseDictionarySelector(localeOrSelector)\n : {\n locale: localeOrSelector as LocalesValues | undefined,\n selector: undefined,\n };\n const locale = resolveInterpreterLocale(requestedLocale);\n\n // The base plugins are rebuilt on every call, so they cannot identify\n // themselves — but they are fully determined by the locale, which the key\n // already carries. Only an explicitly passed array needs its own identity.\n const cacheKey = getDictionaryTransformCacheKey(\n locale,\n process.env.INTLAYER_DICTIONARY_SELECTOR !== 'false'\n ? getDictionarySelectorCacheKey(selector)\n : '',\n plugins\n );\n\n const cached = readTransformCache<any>(dictionary, cacheKey);\n if (cached.hit) return cached.content;\n\n const appliedPlugins = plugins ?? getBasePlugins(locale);\n\n const resolved =\n process.env.INTLAYER_DICTIONARY_SELECTOR !== 'false'\n ? resolveQualifiedDictionary(dictionary, selector)\n : (dictionary as Dictionary);\n\n const transformDictionary = (resolvedDictionary: Dictionary) => {\n const props: NodeProps = {\n dictionaryKey: resolvedDictionary.key,\n dictionaryPath: resolvedDictionary.filePath,\n keyPath: [],\n plugins: appliedPlugins,\n // Attached by the build optimization so `nest()` resolves without the\n // global registry. Undefined in unoptimized builds, where the\n // registry-based resolver is used instead.\n nestedDictionaries: resolvedDictionary.nestedDictionaries,\n eager: !transformsInProgress.has(resolvedDictionary),\n };\n\n transformsInProgress.add(resolvedDictionary);\n\n try {\n return getContent(resolvedDictionary.content, props, appliedPlugins);\n } finally {\n if (props.eager) transformsInProgress.delete(resolvedDictionary);\n }\n };\n\n if (resolved === null)\n return writeTransformCache(dictionary, cacheKey, null)!;\n\n if (Array.isArray(resolved)) {\n return writeTransformCache(\n dictionary,\n cacheKey,\n resolved.map(transformDictionary)\n ) as any;\n }\n\n return writeTransformCache(\n dictionary,\n cacheKey,\n transformDictionary(resolved)\n ) as any;\n};\n"],"mappings":";;;;;;;;;;;AAmCA,MAAM,uCAAuB,IAAI,QAAgB;;;;;;;;;;AAWjD,MAAa,iBAIX,YACA,kBACA,YAKG;CAGH,MAAM,EAAE,QAAQ,iBAAiB,aAC/B,QAAQ,IAAI,iCAAiC,UACzC,wBAAwB,gBAAgB,IACxC;EACE,QAAQ;EACR,UAAU;CACZ;CACN,MAAM,SAAS,yBAAyB,eAAe;CAKvD,MAAM,WAAW,+BACf,QACA,QAAQ,IAAI,iCAAiC,UACzC,8BAA8B,QAAQ,IACtC,IACJ,OACF;CAEA,MAAM,SAAS,mBAAwB,YAAY,QAAQ;CAC3D,IAAI,OAAO,KAAK,OAAO,OAAO;CAE9B,MAAM,iBAAiB,WAAW,eAAe,MAAM;CAEvD,MAAM,WACJ,QAAQ,IAAI,iCAAiC,UACzC,2BAA2B,YAAY,QAAQ,IAC9C;CAEP,MAAM,uBAAuB,uBAAmC;EAC9D,MAAM,QAAmB;GACvB,eAAe,mBAAmB;GAClC,gBAAgB,mBAAmB;GACnC,SAAS,CAAC;GACV,SAAS;GAIT,oBAAoB,mBAAmB;GACvC,OAAO,CAAC,qBAAqB,IAAI,kBAAkB;EACrD;EAEA,qBAAqB,IAAI,kBAAkB;EAE3C,IAAI;GACF,OAAO,WAAW,mBAAmB,SAAS,OAAO,cAAc;EACrE,UAAU;GACR,IAAI,MAAM,OAAO,qBAAqB,OAAO,kBAAkB;EACjE;CACF;CAEA,IAAI,aAAa,MACf,OAAO,oBAAoB,YAAY,UAAU,IAAI;CAEvD,IAAI,MAAM,QAAQ,QAAQ,GACxB,OAAO,oBACL,YACA,UACA,SAAS,IAAI,mBAAmB,CAClC;CAGF,OAAO,oBACL,YACA,UACA,oBAAoB,QAAQ,CAC9B;AACF"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { getPluginsCacheKey } from "./dictionaryTransformCache.mjs";
|
|
2
2
|
import { getDictionarySelectorCacheKey, parseDictionarySelector } from "../dictionaryManipulator/qualifiedDictionary.mjs";
|
|
3
|
+
import { resolveInterpreterLocaleAsync } from "./resolveInterpreterLocale.mjs";
|
|
3
4
|
import { getDictionary } from "./getDictionary.mjs";
|
|
4
5
|
import { isQualifiedDynamicLoaderMap, resolveQualifiedDynamicContentAsync } from "../dictionaryManipulator/qualifiedDynamicLoader.mjs";
|
|
5
6
|
import { findPlainDynamicLoader } from "../dictionaryManipulator/plainDynamicLoader.mjs";
|
|
6
|
-
import { internationalization } from "@intlayer/config/built";
|
|
7
7
|
|
|
8
8
|
//#region src/interpreter/getDictionaryAsync.ts
|
|
9
9
|
/**
|
|
@@ -56,7 +56,7 @@ const getDictionaryAsync = async (dictionaryLoaders, key, localeOrSelector, plug
|
|
|
56
56
|
locale = parsed.locale;
|
|
57
57
|
selector = parsed.selector;
|
|
58
58
|
} else locale = localeOrSelector;
|
|
59
|
-
const localeTarget = locale ??
|
|
59
|
+
const localeTarget = locale ?? await resolveInterpreterLocaleAsync();
|
|
60
60
|
const cacheKey = `${key}_${localeTarget}_${getDictionarySelectorCacheKey(selector)}_${getPluginsCacheKey(plugins)}`;
|
|
61
61
|
const cachedContent = contentPromiseCache.get(cacheKey);
|
|
62
62
|
if (cachedContent) return cachedContent;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getDictionaryAsync.mjs","names":[],"sources":["../../../src/interpreter/getDictionaryAsync.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"getDictionaryAsync.mjs","names":[],"sources":["../../../src/interpreter/getDictionaryAsync.ts"],"sourcesContent":["import type {\n Dictionary,\n DictionarySelector,\n} from '@intlayer/types/dictionary';\nimport type {\n DeclaredLocales,\n ExtractSelectorLocale,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport {\n findPlainDynamicLoader,\n type PlainDynamicLoaderMap,\n} from '../dictionaryManipulator/plainDynamicLoader';\nimport {\n getDictionarySelectorCacheKey,\n parseDictionarySelector,\n} from '../dictionaryManipulator/qualifiedDictionary';\nimport {\n isQualifiedDynamicLoaderMap,\n type QualifiedDynamicLoaderMap,\n resolveQualifiedDynamicContentAsync,\n} from '../dictionaryManipulator/qualifiedDynamicLoader';\nimport { getPluginsCacheKey } from './dictionaryTransformCache';\nimport type {\n DeepTransformContent,\n IInterpreterPluginState,\n Plugins,\n} from './getContent';\nimport { getDictionary } from './getDictionary';\nimport { resolveInterpreterLocaleAsync } from './resolveInterpreterLocale';\n\n/**\n * Content already resolved for a `key + locale + selector` triple, or the\n * in-flight promise resolving it. Storing the promise itself makes the cache\n * double as an in-flight deduplication table: concurrent calls for the same\n * chunk await one single load.\n */\nconst contentPromiseCache = new Map<string, Promise<unknown>>();\n\n/**\n * Awaits the chunk a plain loader map holds for `locale` — walking the same\n * fallback chain as static mode — and transforms it.\n *\n * Returns `null` when the map emitted no chunk for the locale nor for any of\n * its fallbacks, mirroring how a missing qualified coordinate resolves.\n */\nconst loadPlainChunk = async <T extends Dictionary, Content>(\n dictionaryLoaders: PlainDynamicLoaderMap<T>,\n locale: LocalesValues,\n transform: (dictionary: Dictionary) => Content\n): Promise<Content | null> => {\n const resolved = findPlainDynamicLoader<T>(dictionaryLoaders, locale);\n\n if (!resolved) return null;\n\n return transform(await resolved.loader());\n};\n\n/**\n * Loads a single locale chunk of a dictionary and returns its transformed\n * content.\n *\n * Counterpart of {@link getDictionary} for the per-locale loader maps emitted\n * in `.intlayer/dynamic_dictionaries/`: instead of receiving a dictionary\n * holding every locale, it receives the loader map and awaits only the chunk\n * the requested locale needs.\n *\n * The loader map is either plain (`locale → loader`) or qualified\n * (`locale → qualifierId → loader`, for collections and variants). For a\n * qualified map, only the chunk(s) the selector targets are loaded.\n *\n * Build plugins rewrite every `getIntlayerAsync('key', locale)` call into a\n * `getDictionaryAsync(loaderMap, 'key', locale)` one, so applications call\n * {@link getIntlayerAsync} and never this function directly.\n *\n * @param dictionaryLoaders - Plain or qualified per-locale loader map.\n * @param key - Dictionary key, used to namespace the chunk cache.\n * @param localeOrSelector - The locale, or a selector object (`{ item }`,\n * `{ variant }`, optionally with `locale`).\n * @param plugins - Node transformers. Defaults to the base interpreter set.\n */\nexport const getDictionaryAsync = async <\n const T extends Dictionary,\n const A extends LocalesValues | DictionarySelector = DeclaredLocales,\n>(\n dictionaryLoaders: PlainDynamicLoaderMap<T> | QualifiedDynamicLoaderMap,\n key: string,\n localeOrSelector?: A,\n plugins?: Plugins[]\n): Promise<\n DeepTransformContent<\n T['content'],\n IInterpreterPluginState,\n ExtractSelectorLocale<A>\n >\n> => {\n let locale: LocalesValues | undefined;\n let selector: DictionarySelector | undefined;\n\n if (process.env.INTLAYER_DICTIONARY_SELECTOR !== 'false') {\n const parsed = parseDictionarySelector<LocalesValues>(localeOrSelector);\n locale = parsed.locale;\n selector = parsed.selector;\n } else {\n // Selectors are unused in this project (build-time flag): the argument can\n // only be a locale, so the selector parsing is dead code.\n locale = localeOrSelector as LocalesValues | undefined;\n }\n\n const localeTarget = locale ?? (await resolveInterpreterLocaleAsync());\n\n const cacheKey = `${key}_${localeTarget}_${getDictionarySelectorCacheKey(\n selector\n )}_${getPluginsCacheKey(plugins)}`;\n\n const cachedContent = contentPromiseCache.get(cacheKey);\n if (cachedContent) return cachedContent as Promise<any>;\n\n const transform = (dictionary: Dictionary) =>\n getDictionary(dictionary, localeTarget, plugins);\n\n const contentPromise =\n process.env.INTLAYER_DICTIONARY_SELECTOR !== 'false' &&\n isQualifiedDynamicLoaderMap(dictionaryLoaders)\n ? resolveQualifiedDynamicContentAsync({\n loaderMap: dictionaryLoaders,\n key,\n locale: localeTarget,\n selector,\n transform,\n })\n : loadPlainChunk(\n dictionaryLoaders as PlainDynamicLoaderMap<T>,\n localeTarget,\n transform\n );\n\n contentPromiseCache.set(cacheKey, contentPromise);\n\n // A rejected load must not stay cached, or every later call replays the\n // same failure without ever retrying the chunk.\n contentPromise.catch(() => contentPromiseCache.delete(cacheKey));\n\n return contentPromise as Promise<any>;\n};\n"],"mappings":";;;;;;;;;;;;;;AAqCA,MAAM,sCAAsB,IAAI,IAA8B;;;;;;;;AAS9D,MAAM,iBAAiB,OACrB,mBACA,QACA,cAC4B;CAC5B,MAAM,WAAW,uBAA0B,mBAAmB,MAAM;CAEpE,IAAI,CAAC,UAAU,OAAO;CAEtB,OAAO,UAAU,MAAM,SAAS,OAAO,CAAC;AAC1C;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,MAAa,qBAAqB,OAIhC,mBACA,KACA,kBACA,YAOG;CACH,IAAI;CACJ,IAAI;CAEJ,IAAI,QAAQ,IAAI,iCAAiC,SAAS;EACxD,MAAM,SAAS,wBAAuC,gBAAgB;EACtE,SAAS,OAAO;EAChB,WAAW,OAAO;CACpB,OAGE,SAAS;CAGX,MAAM,eAAe,UAAW,MAAM,8BAA8B;CAEpE,MAAM,WAAW,GAAG,IAAI,GAAG,aAAa,GAAG,8BACzC,QACF,EAAE,GAAG,mBAAmB,OAAO;CAE/B,MAAM,gBAAgB,oBAAoB,IAAI,QAAQ;CACtD,IAAI,eAAe,OAAO;CAE1B,MAAM,aAAa,eACjB,cAAc,YAAY,cAAc,OAAO;CAEjD,MAAM,iBACJ,QAAQ,IAAI,iCAAiC,WAC7C,4BAA4B,iBAAiB,IACzC,oCAAoC;EAClC,WAAW;EACX;EACA,QAAQ;EACR;EACA;CACF,CAAC,IACD,eACE,mBACA,cACA,SACF;CAEN,oBAAoB,IAAI,UAAU,cAAc;CAIhD,eAAe,YAAY,oBAAoB,OAAO,QAAQ,CAAC;CAE/D,OAAO;AACT"}
|
|
@@ -52,7 +52,7 @@ const warnedMissingDictionaries = /* @__PURE__ */ new Set();
|
|
|
52
52
|
*/
|
|
53
53
|
const getIntlayer = (key, localeOrSelector, plugins) => {
|
|
54
54
|
const dictionary = getDictionaries()[key];
|
|
55
|
-
if (!dictionary &&
|
|
55
|
+
if (!dictionary && process.env.NODE_ENV === "development") {
|
|
56
56
|
if (!warnedMissingDictionaries.has(key)) {
|
|
57
57
|
getAppLogger({ log })(typeof window === "undefined" ? `Dictionary ${colorizeKey(key)} was not found. Using fallback proxy.` : `Dictionary ${key} was not found. Using fallback proxy.`, { level: "warn" });
|
|
58
58
|
warnedMissingDictionaries.add(key);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getIntlayer.mjs","names":[],"sources":["../../../src/interpreter/getIntlayer.ts"],"sourcesContent":["import { log } from '@intlayer/config/built';\nimport { colorizeKey, getAppLogger } from '@intlayer/config/logger';\nimport { getDictionaries } from '@intlayer/dictionaries-entry';\nimport type { DictionarySelector } from '@intlayer/types/dictionary';\nimport type {\n DeclaredLocales,\n DictionaryKeys,\n DictionaryRegistryResult,\n ExtractSelectorLocale,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type {\n DeepTransformContent,\n IInterpreterPluginState,\n Plugins,\n} from './getContent';\nimport { getDictionary } from './getDictionary';\n\n/**\n * Object.prototype methods libraries call on arbitrary values while inspecting\n * them — TanStack Router's `isPlainObject` reaches for `hasOwnProperty` on\n * every value it deep-compares. Answering them with another path proxy turns\n * a missing dictionary into `hasOwnProperty is not a function`, thrown deep\n * inside the consumer, so they are forwarded to the real implementations.\n */\nconst PROTOTYPE_METHOD_NAMES = new Set<string | symbol>([\n 'hasOwnProperty',\n 'isPrototypeOf',\n 'propertyIsEnumerable',\n 'toLocaleString',\n]);\n\n/**\n * Creates a Recursive Proxy that returns the path of the accessed key\n * stringified. This prevents the app from crashing on undefined access.\n *\n * The proxy wraps a function so that calling any leaf — `keywords.join(', ')`,\n * `title.trim()` — resolves to the path too, instead of throwing\n * `join is not a function`. Being callable also keeps structural checks\n * (`Object.prototype.toString`) from mistaking it for a plain object worth\n * walking.\n */\nconst createSafeFallback = (path = ''): any => {\n return new Proxy((() => path) as Record<string | symbol, any>, {\n get: (target, prop) => {\n if (\n prop === 'toJSON' ||\n prop === Symbol.toPrimitive ||\n prop === 'toString' ||\n prop === 'valueOf'\n ) {\n return () => path;\n }\n if (prop === 'then') {\n return undefined; // Prevent it from being treated as a Promise\n }\n if (PROTOTYPE_METHOD_NAMES.has(prop)) {\n return (Object.prototype as Record<string | symbol, any>)[prop].bind(\n target\n );\n }\n if (prop === Symbol.iterator) {\n return function* () {\n yield path;\n };\n }\n\n // Recursively build the path (e.g., \"myDictionary.home.title\")\n const nextPath = path ? `${path}.${String(prop)}` : String(prop);\n return createSafeFallback(nextPath);\n },\n });\n};\n\nconst warnedMissingDictionaries = new Set<string>();\n\n/**\n * Picks one dictionary by its key and returns its content for the given\n * locale or selector.\n *\n * The second argument is either a locale (`'fr'`) or a selector object:\n * - `{ item: 2 }` — collection item (omit `item` to get every item as array)\n * - `{ variant: 'black-friday' }` — named variant (omit for the `default` one)\n * - `{ variant: { id: 'prod_abc', userId: '123' } }` — structured variant\n * - `locale` can be combined with any selector: `{ item: 2, locale: 'fr' }`\n */\nexport const getIntlayer = <\n const T extends DictionaryKeys,\n const A extends LocalesValues | DictionarySelector = DeclaredLocales,\n>(\n key: T,\n localeOrSelector?: A,\n plugins?: Plugins[]\n): DeepTransformContent<\n DictionaryRegistryResult<T, A>,\n IInterpreterPluginState,\n ExtractSelectorLocale<A>\n> => {\n const dictionaries = getDictionaries();\n const dictionary = dictionaries[key as T]!;\n\n if (!dictionary && process.env.NODE_ENV === 'development') {\n if (!warnedMissingDictionaries.has(key as string)) {\n // Log a warning instead of throwing (so developers know it's missing)\n const logger = getAppLogger({ log });\n logger(\n typeof window === 'undefined'\n ? `Dictionary ${colorizeKey(key)} was not found. Using fallback proxy.`\n : `Dictionary ${key} was not found. Using fallback proxy.`,\n {\n level: 'warn',\n }\n );\n warnedMissingDictionaries.add(key as string);\n }\n\n return createSafeFallback(key as string);\n }\n\n return getDictionary(dictionary, localeOrSelector, plugins) as any;\n};\n"],"mappings":";;;;;;;;;;;;;AAyBA,MAAM,yCAAyB,IAAI,IAAqB;CACtD;CACA;CACA;CACA;AACF,CAAC;;;;;;;;;;;AAYD,MAAM,sBAAsB,OAAO,OAAY;CAC7C,OAAO,IAAI,aAAa,OAAuC,EAC7D,MAAM,QAAQ,SAAS;EACrB,IACE,SAAS,YACT,SAAS,OAAO,eAChB,SAAS,cACT,SAAS,WAET,aAAa;EAEf,IAAI,SAAS,QACX;EAEF,IAAI,uBAAuB,IAAI,IAAI,GACjC,OAAQ,OAAO,UAA2C,KAAK,CAAC,KAC9D,MACF;EAEF,IAAI,SAAS,OAAO,UAClB,OAAO,aAAa;GAClB,MAAM;EACR;EAIF,MAAM,WAAW,OAAO,GAAG,KAAK,GAAG,OAAO,IAAI,MAAM,OAAO,IAAI;EAC/D,OAAO,mBAAmB,QAAQ;CACpC,EACF,CAAC;AACH;AAEA,MAAM,4CAA4B,IAAI,IAAY;;;;;;;;;;;AAYlD,MAAa,eAIX,KACA,kBACA,YAKG;CAEH,MAAM,aADe,gBACS,CAAC,CAAC;CAEhC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"getIntlayer.mjs","names":[],"sources":["../../../src/interpreter/getIntlayer.ts"],"sourcesContent":["import { log } from '@intlayer/config/built';\nimport { colorizeKey, getAppLogger } from '@intlayer/config/logger';\nimport { getDictionaries } from '@intlayer/dictionaries-entry';\nimport type { DictionarySelector } from '@intlayer/types/dictionary';\nimport type {\n DeclaredLocales,\n DictionaryKeys,\n DictionaryRegistryResult,\n ExtractSelectorLocale,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type {\n DeepTransformContent,\n IInterpreterPluginState,\n Plugins,\n} from './getContent';\nimport { getDictionary } from './getDictionary';\n\n/**\n * Object.prototype methods libraries call on arbitrary values while inspecting\n * them — TanStack Router's `isPlainObject` reaches for `hasOwnProperty` on\n * every value it deep-compares. Answering them with another path proxy turns\n * a missing dictionary into `hasOwnProperty is not a function`, thrown deep\n * inside the consumer, so they are forwarded to the real implementations.\n */\nconst PROTOTYPE_METHOD_NAMES = new Set<string | symbol>([\n 'hasOwnProperty',\n 'isPrototypeOf',\n 'propertyIsEnumerable',\n 'toLocaleString',\n]);\n\n/**\n * Creates a Recursive Proxy that returns the path of the accessed key\n * stringified. This prevents the app from crashing on undefined access.\n *\n * The proxy wraps a function so that calling any leaf — `keywords.join(', ')`,\n * `title.trim()` — resolves to the path too, instead of throwing\n * `join is not a function`. Being callable also keeps structural checks\n * (`Object.prototype.toString`) from mistaking it for a plain object worth\n * walking.\n */\nconst createSafeFallback = (path = ''): any => {\n return new Proxy((() => path) as Record<string | symbol, any>, {\n get: (target, prop) => {\n if (\n prop === 'toJSON' ||\n prop === Symbol.toPrimitive ||\n prop === 'toString' ||\n prop === 'valueOf'\n ) {\n return () => path;\n }\n if (prop === 'then') {\n return undefined; // Prevent it from being treated as a Promise\n }\n if (PROTOTYPE_METHOD_NAMES.has(prop)) {\n return (Object.prototype as Record<string | symbol, any>)[prop].bind(\n target\n );\n }\n if (prop === Symbol.iterator) {\n return function* () {\n yield path;\n };\n }\n\n // Recursively build the path (e.g., \"myDictionary.home.title\")\n const nextPath = path ? `${path}.${String(prop)}` : String(prop);\n return createSafeFallback(nextPath);\n },\n });\n};\n\nconst warnedMissingDictionaries = new Set<string>();\n\n/**\n * Picks one dictionary by its key and returns its content for the given\n * locale or selector.\n *\n * The second argument is either a locale (`'fr'`) or a selector object:\n * - `{ item: 2 }` — collection item (omit `item` to get every item as array)\n * - `{ variant: 'black-friday' }` — named variant (omit for the `default` one)\n * - `{ variant: { id: 'prod_abc', userId: '123' } }` — structured variant\n * - `locale` can be combined with any selector: `{ item: 2, locale: 'fr' }`\n */\nexport const getIntlayer = <\n const T extends DictionaryKeys,\n const A extends LocalesValues | DictionarySelector = DeclaredLocales,\n>(\n key: T,\n localeOrSelector?: A,\n plugins?: Plugins[]\n): DeepTransformContent<\n DictionaryRegistryResult<T, A>,\n IInterpreterPluginState,\n ExtractSelectorLocale<A>\n> => {\n const dictionaries = getDictionaries();\n const dictionary = dictionaries[key as T]!;\n\n if (!dictionary && process.env.NODE_ENV === 'development') {\n if (!warnedMissingDictionaries.has(key as string)) {\n // Log a warning instead of throwing (so developers know it's missing)\n const logger = getAppLogger({ log });\n logger(\n typeof window === 'undefined'\n ? `Dictionary ${colorizeKey(key)} was not found. Using fallback proxy.`\n : `Dictionary ${key} was not found. Using fallback proxy.`,\n {\n level: 'warn',\n }\n );\n warnedMissingDictionaries.add(key as string);\n }\n\n return createSafeFallback(key as string);\n }\n\n return getDictionary(dictionary, localeOrSelector, plugins) as any;\n};\n"],"mappings":";;;;;;;;;;;;;AAyBA,MAAM,yCAAyB,IAAI,IAAqB;CACtD;CACA;CACA;CACA;AACF,CAAC;;;;;;;;;;;AAYD,MAAM,sBAAsB,OAAO,OAAY;CAC7C,OAAO,IAAI,aAAa,OAAuC,EAC7D,MAAM,QAAQ,SAAS;EACrB,IACE,SAAS,YACT,SAAS,OAAO,eAChB,SAAS,cACT,SAAS,WAET,aAAa;EAEf,IAAI,SAAS,QACX;EAEF,IAAI,uBAAuB,IAAI,IAAI,GACjC,OAAQ,OAAO,UAA2C,KAAK,CAAC,KAC9D,MACF;EAEF,IAAI,SAAS,OAAO,UAClB,OAAO,aAAa;GAClB,MAAM;EACR;EAIF,MAAM,WAAW,OAAO,GAAG,KAAK,GAAG,OAAO,IAAI,MAAM,OAAO,IAAI;EAC/D,OAAO,mBAAmB,QAAQ;CACpC,EACF,CAAC;AACH;AAEA,MAAM,4CAA4B,IAAI,IAAY;;;;;;;;;;;AAYlD,MAAa,eAIX,KACA,kBACA,YAKG;CAEH,MAAM,aADe,gBACS,CAAC,CAAC;CAEhC,IAAI,CAAC,uCAAuC,eAAe;EACzD,IAAI,CAAC,0BAA0B,IAAI,GAAa,GAAG;GAGjD,AADe,aAAa,EAAE,IAAI,CAC7B,CAAC,CACJ,OAAO,WAAW,cACd,cAAc,YAAY,GAAG,EAAE,yCAC/B,cAAc,IAAI,wCACtB,EACE,OAAO,OACT,CACF;GACA,0BAA0B,IAAI,GAAa;EAC7C;EAEA,OAAO,mBAAmB,GAAa;CACzC;CAEA,OAAO,cAAc,YAAY,kBAAkB,OAAO;AAC5D"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveInterpreterLocaleAsync } from "./resolveInterpreterLocale.mjs";
|
|
1
2
|
import { getIntlayer } from "./getIntlayer.mjs";
|
|
2
3
|
|
|
3
4
|
//#region src/interpreter/getIntlayerAsync.ts
|
|
@@ -28,7 +29,15 @@ import { getIntlayer } from "./getIntlayer.mjs";
|
|
|
28
29
|
* const { title } = await getIntlayerAsync('home-metadata', locale);
|
|
29
30
|
* ```
|
|
30
31
|
*/
|
|
31
|
-
const getIntlayerAsync = async (key, localeOrSelector, plugins) =>
|
|
32
|
+
const getIntlayerAsync = async (key, localeOrSelector, plugins) => {
|
|
33
|
+
const isSelector = typeof localeOrSelector === "object" && localeOrSelector !== null;
|
|
34
|
+
if (isSelector ? localeOrSelector.locale : localeOrSelector) return getIntlayer(key, localeOrSelector, plugins);
|
|
35
|
+
const locale = await resolveInterpreterLocaleAsync();
|
|
36
|
+
return getIntlayer(key, isSelector ? {
|
|
37
|
+
...localeOrSelector,
|
|
38
|
+
locale
|
|
39
|
+
} : locale, plugins);
|
|
40
|
+
};
|
|
32
41
|
|
|
33
42
|
//#endregion
|
|
34
43
|
export { getIntlayerAsync };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getIntlayerAsync.mjs","names":[],"sources":["../../../src/interpreter/getIntlayerAsync.ts"],"sourcesContent":["import type { DictionarySelector } from '@intlayer/types/dictionary';\nimport type {\n DeclaredLocales,\n DictionaryKeys,\n DictionaryRegistryResult,\n ExtractSelectorLocale,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type {\n DeepTransformContent,\n IInterpreterPluginState,\n Plugins,\n} from './getContent';\nimport { getIntlayer } from './getIntlayer';\n\n/**\n * Picks one dictionary by its key and resolves its content for the given\n * locale or selector, loading that locale alone.\n *\n * Async counterpart of {@link getIntlayer}, meant for the places a dictionary\n * is read outside of rendering — route `head` / metadata builders, loaders,\n * server functions. Where `getIntlayer` pulls in the merged dictionary holding\n * every locale, the build plugins (`@intlayer/babel`, `@intlayer/swc`) rewrite\n * this call into `getDictionaryAsync(loaderMap, key, locale)`, pointing it at\n * the per-locale chunks in `.intlayer/dynamic_dictionaries/`, so the bundle\n * only ever carries the locale actually requested.\n *\n * Without those plugins — an unoptimized build — the call resolves through the\n * synchronous dictionary registry instead: the same content, without the\n * per-locale split.\n *\n * The second argument is either a locale (`'fr'`) or a selector object:\n * - `{ item: 2 }` — collection item (omit `item` to get every item as array)\n * - `{ variant: 'black-friday' }` — named variant (omit for the `default` one)\n * - `{ variant: { id: 'prod_abc', userId: '123' } }` — structured variant\n * - `locale` can be combined with any selector: `{ item: 2, locale: 'fr' }`\n *\n * @example\n * ```ts\n * const { title } = await getIntlayerAsync('home-metadata', locale);\n * ```\n */\nexport const getIntlayerAsync = async <\n const T extends DictionaryKeys,\n const A extends LocalesValues | DictionarySelector = DeclaredLocales,\n>(\n key: T,\n localeOrSelector?: A,\n plugins?: Plugins[]\n): Promise<\n DeepTransformContent<\n DictionaryRegistryResult<T, A>,\n IInterpreterPluginState,\n ExtractSelectorLocale<A>\n >\n> => getIntlayer<T, A>(key, localeOrSelector, plugins);\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"getIntlayerAsync.mjs","names":[],"sources":["../../../src/interpreter/getIntlayerAsync.ts"],"sourcesContent":["import type { DictionarySelector } from '@intlayer/types/dictionary';\nimport type {\n DeclaredLocales,\n DictionaryKeys,\n DictionaryRegistryResult,\n ExtractSelectorLocale,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type {\n DeepTransformContent,\n IInterpreterPluginState,\n Plugins,\n} from './getContent';\nimport { getIntlayer } from './getIntlayer';\nimport { resolveInterpreterLocaleAsync } from './resolveInterpreterLocale';\n\n/**\n * Picks one dictionary by its key and resolves its content for the given\n * locale or selector, loading that locale alone.\n *\n * Async counterpart of {@link getIntlayer}, meant for the places a dictionary\n * is read outside of rendering — route `head` / metadata builders, loaders,\n * server functions. Where `getIntlayer` pulls in the merged dictionary holding\n * every locale, the build plugins (`@intlayer/babel`, `@intlayer/swc`) rewrite\n * this call into `getDictionaryAsync(loaderMap, key, locale)`, pointing it at\n * the per-locale chunks in `.intlayer/dynamic_dictionaries/`, so the bundle\n * only ever carries the locale actually requested.\n *\n * Without those plugins — an unoptimized build — the call resolves through the\n * synchronous dictionary registry instead: the same content, without the\n * per-locale split.\n *\n * The second argument is either a locale (`'fr'`) or a selector object:\n * - `{ item: 2 }` — collection item (omit `item` to get every item as array)\n * - `{ variant: 'black-friday' }` — named variant (omit for the `default` one)\n * - `{ variant: { id: 'prod_abc', userId: '123' } }` — structured variant\n * - `locale` can be combined with any selector: `{ item: 2, locale: 'fr' }`\n *\n * @example\n * ```ts\n * const { title } = await getIntlayerAsync('home-metadata', locale);\n * ```\n */\nexport const getIntlayerAsync = async <\n const T extends DictionaryKeys,\n const A extends LocalesValues | DictionarySelector = DeclaredLocales,\n>(\n key: T,\n localeOrSelector?: A,\n plugins?: Plugins[]\n): Promise<\n DeepTransformContent<\n DictionaryRegistryResult<T, A>,\n IInterpreterPluginState,\n ExtractSelectorLocale<A>\n >\n> => {\n const isSelector =\n typeof localeOrSelector === 'object' && localeOrSelector !== null;\n const requestedLocale = isSelector\n ? (localeOrSelector as DictionarySelector).locale\n : (localeOrSelector as LocalesValues | undefined);\n\n if (requestedLocale) return getIntlayer<T, A>(key, localeOrSelector, plugins);\n\n // Only the async read can await request-bound locale sources\n const locale = await resolveInterpreterLocaleAsync();\n\n return getIntlayer<T, A>(\n key,\n (isSelector ? { ...localeOrSelector, locale } : locale) as A,\n plugins\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CA,MAAa,mBAAmB,OAI9B,KACA,kBACA,YAOG;CACH,MAAM,aACJ,OAAO,qBAAqB,YAAY,qBAAqB;CAK/D,IAJwB,aACnB,iBAAwC,SACxC,kBAEgB,OAAO,YAAkB,KAAK,kBAAkB,OAAO;CAG5E,MAAM,SAAS,MAAM,8BAA8B;CAEnD,OAAO,YACL,KACC,aAAa;EAAE,GAAG;EAAkB;CAAO,IAAI,QAChD,OACF;AACF"}
|
|
@@ -4,6 +4,7 @@ import { deepTransformNode } from "./getContent/deepTransform.mjs";
|
|
|
4
4
|
import { findMatchingCondition, getEnumeration } from "./getEnumeration.mjs";
|
|
5
5
|
import { getGender } from "./getGender.mjs";
|
|
6
6
|
import { getInsertion } from "./getInsertion.mjs";
|
|
7
|
+
import { registerAmbientLocaleResolver, registerAsyncAmbientLocaleResolver, resolveInterpreterLocale, resolveInterpreterLocaleAsync } from "./resolveInterpreterLocale.mjs";
|
|
7
8
|
import { getDictionary } from "./getDictionary.mjs";
|
|
8
9
|
import { getIntlayer } from "./getIntlayer.mjs";
|
|
9
10
|
import { getNesting } from "./getNesting.mjs";
|
|
@@ -18,4 +19,4 @@ import { getHTML } from "./getHTML.mjs";
|
|
|
18
19
|
import { getIntlayerAsync } from "./getIntlayerAsync.mjs";
|
|
19
20
|
import { splitInsertionTemplate } from "./splitAndJoinInsertion.mjs";
|
|
20
21
|
|
|
21
|
-
export { bindInsertedValues, conditionPlugin, deepTransformNode, enumerationPlugin, fallbackPlugin, filePlugin, findMatchingCondition, genderPlugin, getBasePlugins, getCondition, getContent, getDictionary, getDictionaryAsync, getDictionaryTransformCacheKey, getEnumeration, getGender, getHTML, getInsertion, getInterpolableContent, getIntlayer, getIntlayerAsync, getNesting, getPluginsCacheKey, getPlural, getSelect, getTranslation, insertionPlugin, isInterpolableWrapperNode, nestedPlugin, pluralPlugin, readTransformCache, rebuildInterpolableContent, resolveInsertedSelector, selectPlugin, splitInsertionTemplate, transformInterpolableNode, translationPlugin, writeTransformCache };
|
|
22
|
+
export { bindInsertedValues, conditionPlugin, deepTransformNode, enumerationPlugin, fallbackPlugin, filePlugin, findMatchingCondition, genderPlugin, getBasePlugins, getCondition, getContent, getDictionary, getDictionaryAsync, getDictionaryTransformCacheKey, getEnumeration, getGender, getHTML, getInsertion, getInterpolableContent, getIntlayer, getIntlayerAsync, getNesting, getPluginsCacheKey, getPlural, getSelect, getTranslation, insertionPlugin, isInterpolableWrapperNode, nestedPlugin, pluralPlugin, readTransformCache, rebuildInterpolableContent, registerAmbientLocaleResolver, registerAsyncAmbientLocaleResolver, resolveInsertedSelector, resolveInterpreterLocale, resolveInterpreterLocaleAsync, selectPlugin, splitInsertionTemplate, transformInterpolableNode, translationPlugin, writeTransformCache };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { getCachedLocaleFromStorageClient } from "../utils/localeStorage.mjs";
|
|
2
|
+
import { internationalization } from "@intlayer/config/built";
|
|
3
|
+
|
|
4
|
+
//#region src/interpreter/resolveInterpreterLocale.ts
|
|
5
|
+
/**
|
|
6
|
+
* Held on `globalThis` so that every copy of this module (CJS and ESM builds,
|
|
7
|
+
* duplicated installs) shares the resolvers an integration registered.
|
|
8
|
+
*/
|
|
9
|
+
const getGlobalSet = (key) => {
|
|
10
|
+
const globalScope = globalThis;
|
|
11
|
+
globalScope[key] ??= /* @__PURE__ */ new Set();
|
|
12
|
+
return globalScope[key];
|
|
13
|
+
};
|
|
14
|
+
const getAmbientLocaleResolvers = () => getGlobalSet(Symbol.for("intlayer.ambientLocaleResolvers"));
|
|
15
|
+
const getAsyncAmbientLocaleResolvers = () => getGlobalSet(Symbol.for("intlayer.asyncAmbientLocaleResolvers"));
|
|
16
|
+
/**
|
|
17
|
+
* Registers a resolver giving the locale of the current context, consulted by
|
|
18
|
+
* `getIntlayer` / `getDictionary` when the call site passes no locale.
|
|
19
|
+
*
|
|
20
|
+
* Integrations owning a request scope (server middlewares keeping the request
|
|
21
|
+
* in `AsyncLocalStorage`) register one so that a bare `getIntlayer('key')`
|
|
22
|
+
* answers in the request locale.
|
|
23
|
+
*
|
|
24
|
+
* @param resolver - Returns the current locale, or `undefined` when unknown.
|
|
25
|
+
* @returns A function unregistering the resolver.
|
|
26
|
+
*/
|
|
27
|
+
const registerAmbientLocaleResolver = (resolver) => {
|
|
28
|
+
const resolvers = getAmbientLocaleResolvers();
|
|
29
|
+
resolvers.add(resolver);
|
|
30
|
+
return () => {
|
|
31
|
+
resolvers.delete(resolver);
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Registers an {@link AsyncAmbientLocaleResolver}, consulted only by the
|
|
36
|
+
* asynchronous reads (`getIntlayerAsync` / `getDictionaryAsync`), after the
|
|
37
|
+
* synchronous resolvers.
|
|
38
|
+
*
|
|
39
|
+
* Unlike synchronous resolvers, its errors propagate: frameworks rely on them
|
|
40
|
+
* for control flow (Next.js marks a route dynamic by throwing from
|
|
41
|
+
* `headers()`). A resolver returns `undefined` for errors meaning "unknown".
|
|
42
|
+
*
|
|
43
|
+
* @param resolver - Resolves the current locale, or `undefined` when unknown.
|
|
44
|
+
* @returns A function unregistering the resolver.
|
|
45
|
+
*/
|
|
46
|
+
const registerAsyncAmbientLocaleResolver = (resolver) => {
|
|
47
|
+
const resolvers = getAsyncAmbientLocaleResolvers();
|
|
48
|
+
resolvers.add(resolver);
|
|
49
|
+
return () => {
|
|
50
|
+
resolvers.delete(resolver);
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Returns the first locale a registered resolver knows, if any.
|
|
55
|
+
*/
|
|
56
|
+
const getAmbientLocale = () => {
|
|
57
|
+
for (const resolver of getAmbientLocaleResolvers()) try {
|
|
58
|
+
const locale = resolver();
|
|
59
|
+
if (locale) return locale;
|
|
60
|
+
} catch {}
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Resolves the locale a dictionary is read in when the call site gives none:
|
|
64
|
+
*
|
|
65
|
+
* 1. the locale of the current context, from the registered resolvers
|
|
66
|
+
* (e.g. the request being handled by a server middleware);
|
|
67
|
+
* 2. in the browser, the locale persisted in storage (cookie, localStorage,
|
|
68
|
+
* sessionStorage), cached until the next `setLocaleInStorageClient`;
|
|
69
|
+
* 3. the default locale.
|
|
70
|
+
*
|
|
71
|
+
* Browser storage is never read off-browser: the server shares module state
|
|
72
|
+
* across requests, and the request cookie is only known to its integration.
|
|
73
|
+
*
|
|
74
|
+
* @param locale - Locale passed by the call site, if any.
|
|
75
|
+
* @returns The resolved locale.
|
|
76
|
+
*/
|
|
77
|
+
const resolveInterpreterLocale = (locale) => locale ?? getAmbientLocale() ?? (typeof window === "undefined" ? void 0 : getCachedLocaleFromStorageClient()) ?? internationalization.defaultLocale;
|
|
78
|
+
/**
|
|
79
|
+
* Asynchronous twin of {@link resolveInterpreterLocale}: the asynchronous
|
|
80
|
+
* resolvers are awaited after the synchronous ones, before browser storage.
|
|
81
|
+
*
|
|
82
|
+
* @param locale - Locale passed by the call site, if any.
|
|
83
|
+
* @returns The resolved locale.
|
|
84
|
+
*/
|
|
85
|
+
const resolveInterpreterLocaleAsync = async (locale) => {
|
|
86
|
+
const knownLocale = locale ?? getAmbientLocale();
|
|
87
|
+
if (knownLocale) return knownLocale;
|
|
88
|
+
for (const resolver of getAsyncAmbientLocaleResolvers()) {
|
|
89
|
+
const resolvedLocale = await resolver();
|
|
90
|
+
if (resolvedLocale) return resolvedLocale;
|
|
91
|
+
}
|
|
92
|
+
return resolveInterpreterLocale();
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
//#endregion
|
|
96
|
+
export { registerAmbientLocaleResolver, registerAsyncAmbientLocaleResolver, resolveInterpreterLocale, resolveInterpreterLocaleAsync };
|
|
97
|
+
//# sourceMappingURL=resolveInterpreterLocale.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveInterpreterLocale.mjs","names":[],"sources":["../../../src/interpreter/resolveInterpreterLocale.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { getCachedLocaleFromStorageClient } from '../utils/localeStorage';\n\n/**\n * Returns the locale of the context the code runs in (typically the request\n * being handled on the server), or `undefined` outside of such a context.\n */\nexport type AmbientLocaleResolver = () => LocalesValues | undefined;\n\n/**\n * Asynchronous {@link AmbientLocaleResolver}, for sources that can only be read\n * by awaiting them (e.g. Next.js `headers()` / `cookies()`).\n */\nexport type AsyncAmbientLocaleResolver = () => Promise<\n LocalesValues | undefined\n>;\n\n/**\n * Held on `globalThis` so that every copy of this module (CJS and ESM builds,\n * duplicated installs) shares the resolvers an integration registered.\n */\nconst getGlobalSet = <T>(key: symbol): Set<T> => {\n const globalScope = globalThis as typeof globalThis & {\n [key: symbol]: Set<T> | undefined;\n };\n\n globalScope[key] ??= new Set<T>();\n\n return globalScope[key];\n};\n\nconst getAmbientLocaleResolvers = (): Set<AmbientLocaleResolver> =>\n getGlobalSet(Symbol.for('intlayer.ambientLocaleResolvers'));\n\nconst getAsyncAmbientLocaleResolvers = (): Set<AsyncAmbientLocaleResolver> =>\n getGlobalSet(Symbol.for('intlayer.asyncAmbientLocaleResolvers'));\n\n/**\n * Registers a resolver giving the locale of the current context, consulted by\n * `getIntlayer` / `getDictionary` when the call site passes no locale.\n *\n * Integrations owning a request scope (server middlewares keeping the request\n * in `AsyncLocalStorage`) register one so that a bare `getIntlayer('key')`\n * answers in the request locale.\n *\n * @param resolver - Returns the current locale, or `undefined` when unknown.\n * @returns A function unregistering the resolver.\n */\nexport const registerAmbientLocaleResolver = (\n resolver: AmbientLocaleResolver\n): (() => void) => {\n const resolvers = getAmbientLocaleResolvers();\n\n resolvers.add(resolver);\n\n return () => {\n resolvers.delete(resolver);\n };\n};\n\n/**\n * Registers an {@link AsyncAmbientLocaleResolver}, consulted only by the\n * asynchronous reads (`getIntlayerAsync` / `getDictionaryAsync`), after the\n * synchronous resolvers.\n *\n * Unlike synchronous resolvers, its errors propagate: frameworks rely on them\n * for control flow (Next.js marks a route dynamic by throwing from\n * `headers()`). A resolver returns `undefined` for errors meaning \"unknown\".\n *\n * @param resolver - Resolves the current locale, or `undefined` when unknown.\n * @returns A function unregistering the resolver.\n */\nexport const registerAsyncAmbientLocaleResolver = (\n resolver: AsyncAmbientLocaleResolver\n): (() => void) => {\n const resolvers = getAsyncAmbientLocaleResolvers();\n\n resolvers.add(resolver);\n\n return () => {\n resolvers.delete(resolver);\n };\n};\n\n/**\n * Returns the first locale a registered resolver knows, if any.\n */\nconst getAmbientLocale = (): LocalesValues | undefined => {\n for (const resolver of getAmbientLocaleResolvers()) {\n try {\n const locale = resolver();\n if (locale) return locale;\n } catch {}\n }\n};\n\n/**\n * Resolves the locale a dictionary is read in when the call site gives none:\n *\n * 1. the locale of the current context, from the registered resolvers\n * (e.g. the request being handled by a server middleware);\n * 2. in the browser, the locale persisted in storage (cookie, localStorage,\n * sessionStorage), cached until the next `setLocaleInStorageClient`;\n * 3. the default locale.\n *\n * Browser storage is never read off-browser: the server shares module state\n * across requests, and the request cookie is only known to its integration.\n *\n * @param locale - Locale passed by the call site, if any.\n * @returns The resolved locale.\n */\nexport const resolveInterpreterLocale = (\n locale?: LocalesValues\n): LocalesValues =>\n locale ??\n getAmbientLocale() ??\n (typeof window === 'undefined'\n ? undefined\n : getCachedLocaleFromStorageClient()) ??\n internationalization.defaultLocale;\n\n/**\n * Asynchronous twin of {@link resolveInterpreterLocale}: the asynchronous\n * resolvers are awaited after the synchronous ones, before browser storage.\n *\n * @param locale - Locale passed by the call site, if any.\n * @returns The resolved locale.\n */\nexport const resolveInterpreterLocaleAsync = async (\n locale?: LocalesValues\n): Promise<LocalesValues> => {\n const knownLocale = locale ?? getAmbientLocale();\n if (knownLocale) return knownLocale;\n\n for (const resolver of getAsyncAmbientLocaleResolvers()) {\n const resolvedLocale = await resolver();\n if (resolvedLocale) return resolvedLocale;\n }\n\n return resolveInterpreterLocale();\n};\n"],"mappings":";;;;;;;;AAsBA,MAAM,gBAAmB,QAAwB;CAC/C,MAAM,cAAc;CAIpB,YAAY,yBAAS,IAAI,IAAO;CAEhC,OAAO,YAAY;AACrB;AAEA,MAAM,kCACJ,aAAa,OAAO,IAAI,iCAAiC,CAAC;AAE5D,MAAM,uCACJ,aAAa,OAAO,IAAI,sCAAsC,CAAC;;;;;;;;;;;;AAajE,MAAa,iCACX,aACiB;CACjB,MAAM,YAAY,0BAA0B;CAE5C,UAAU,IAAI,QAAQ;CAEtB,aAAa;EACX,UAAU,OAAO,QAAQ;CAC3B;AACF;;;;;;;;;;;;;AAcA,MAAa,sCACX,aACiB;CACjB,MAAM,YAAY,+BAA+B;CAEjD,UAAU,IAAI,QAAQ;CAEtB,aAAa;EACX,UAAU,OAAO,QAAQ;CAC3B;AACF;;;;AAKA,MAAM,yBAAoD;CACxD,KAAK,MAAM,YAAY,0BAA0B,GAC/C,IAAI;EACF,MAAM,SAAS,SAAS;EACxB,IAAI,QAAQ,OAAO;CACrB,QAAQ,CAAC;AAEb;;;;;;;;;;;;;;;;AAiBA,MAAa,4BACX,WAEA,UACA,iBAAiB,MAChB,OAAO,WAAW,cACf,SACA,iCAAiC,MACrC,qBAAqB;;;;;;;;AASvB,MAAa,gCAAgC,OAC3C,WAC2B;CAC3B,MAAM,cAAc,UAAU,iBAAiB;CAC/C,IAAI,aAAa,OAAO;CAExB,KAAK,MAAM,YAAY,+BAA+B,GAAG;EACvD,MAAM,iBAAiB,MAAM,SAAS;EACtC,IAAI,gBAAgB,OAAO;CAC7B;CAEA,OAAO,yBAAyB;AAClC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isDeclaredLocale } from "./getPrefix.mjs";
|
|
2
1
|
import { getCookie } from "../utils/getCookie.mjs";
|
|
2
|
+
import { isDeclaredLocale } from "./getPrefix.mjs";
|
|
3
3
|
import { getLocale } from "./getLocale.mjs";
|
|
4
4
|
import { getLocaleFromPath } from "./getLocaleFromPath.mjs";
|
|
5
5
|
import { routing } from "@intlayer/config/built";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { getLocaleFromStorageClient } from "../utils/localeStorage.mjs";
|
|
1
2
|
import { getLocaleFromDomain } from "./domainUtils.mjs";
|
|
2
3
|
import { resolveRoutingConfig } from "./getPrefix.mjs";
|
|
3
|
-
import { getLocaleFromStorageClient } from "../utils/localeStorage.mjs";
|
|
4
4
|
import { getLocaleFromPath } from "./getLocaleFromPath.mjs";
|
|
5
5
|
|
|
6
6
|
//#region src/localization/resolveBrowserLocale.ts
|
|
@@ -17,6 +17,12 @@ const getRewriteRules = (rewrite, context = "url") => {
|
|
|
17
17
|
})) };
|
|
18
18
|
};
|
|
19
19
|
/**
|
|
20
|
+
* Compiled regexes by pattern. Patterns come from the finite set of rewrite
|
|
21
|
+
* rules, while URL localization runs per link, so compiling once pays off.
|
|
22
|
+
* The regexes have no `g` flag, so sharing them is stateless.
|
|
23
|
+
*/
|
|
24
|
+
const patternRegexCache = /* @__PURE__ */ new Map();
|
|
25
|
+
/**
|
|
20
26
|
* Converts normalized pattern to Regex.
|
|
21
27
|
* Internal syntax supports:
|
|
22
28
|
* - :param -> ([^/]+) (one segment)
|
|
@@ -25,8 +31,12 @@ const getRewriteRules = (rewrite, context = "url") => {
|
|
|
25
31
|
* - :param? -> ([^/]*) (zero or one segment)
|
|
26
32
|
*/
|
|
27
33
|
const patternToRegex = (pattern) => {
|
|
34
|
+
const cachedRegex = patternRegexCache.get(pattern);
|
|
35
|
+
if (cachedRegex) return cachedRegex;
|
|
28
36
|
const regexString = pattern.replace(/\//g, "\\/").replace(/\\\/:(?:[^/\\*+?]+)\*/g, "(?:\\/(.*))?").replace(/\\\/:(?:[^/\\*+?]+)\?/g, "(?:\\/([^\\/]+))?").replace(/:([^/\\*+?]+)\*/g, "(.*)").replace(/:([^/\\*+?]+)\?/g, "([^\\/]*)").replace(/:([^/\\*+?]+)\+/g, "(.+)").replace(/:([^/\\*+?]+)/g, "([^\\/]+)");
|
|
29
|
-
|
|
37
|
+
const regex = new RegExp(`^${regexString}$`);
|
|
38
|
+
patternRegexCache.set(pattern, regex);
|
|
39
|
+
return regex;
|
|
30
40
|
};
|
|
31
41
|
/**
|
|
32
42
|
* Replaces route parameters in a path with provided values.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rewriteMatch.mjs","names":["legacyRules"],"sources":["../../../src/localization/rewriteMatch.ts"],"sourcesContent":["import type {\n RewriteObject,\n RewriteRules,\n RoutingConfig,\n} from '@intlayer/types/config';\n\n/**\n * Normalizes legacy Record format or extracts specialized rules from RewriteObject.\n *\n * Idempotent: already-normalized rules are handed back untouched, so a caller\n * holding resolved rules can pass them on without re-normalizing.\n */\nexport const getRewriteRules = <\n const Context extends keyof RewriteObject = 'url',\n>(\n rewrite: RoutingConfig['rewrite'] | RewriteRules,\n context: Context = 'url' as Context\n): RewriteRules | undefined => {\n if (\n !rewrite ||\n (process.env.INTLAYER_ROUTING_REWRITE_RULES &&\n process.env.INTLAYER_ROUTING_REWRITE_RULES === 'false')\n )\n return undefined;\n\n if (Array.isArray((rewrite as RewriteRules).rules)) {\n return rewrite as RewriteRules;\n }\n\n if ('url' in rewrite) {\n return (rewrite as RewriteObject)[context];\n }\n\n // Normalize legacy format\n const legacyRules = rewrite as Record<string, Record<string, string>>;\n\n return {\n rules: Object.entries(legacyRules).map(([canonical, localized]) => ({\n // Normalize canonical path\n canonical: canonical.startsWith('/')\n ? canonical.replace(/\\[([^\\]]+)\\]/g, ':$1')\n : `/${canonical.replace(/\\[([^\\]]+)\\]/g, ':$1')}`,\n\n // Normalize localized path\n localized: Object.fromEntries(\n Object.entries(localized).map(([locale, pattern]) => {\n const normalizedPattern = pattern?.startsWith('/')\n ? pattern.replace(/\\[([^\\]]+)\\]/g, ':$1')\n : `/${(pattern || '').replace(/\\[([^\\]]+)\\]/g, ':$1')}`;\n return [locale, normalizedPattern];\n })\n ),\n })),\n };\n};\n\n/**\n * Converts normalized pattern to Regex.\n * Internal syntax supports:\n * - :param -> ([^/]+) (one segment)\n * - :param* -> (.*) (zero or more segments)\n * - :param+ -> (.+) (one or more segments)\n * - :param? -> ([^/]*) (zero or one segment)\n */\nconst patternToRegex = (pattern: string) => {\n const regexString = pattern\n .replace(/\\//g, '\\\\/') // Escape slashes\n .replace(/\\\\\\/:(?:[^/\\\\*+?]+)\\*/g, '(?:\\\\/(.*))?') // /:param*\n .replace(/\\\\\\/:(?:[^/\\\\*+?]+)\\?/g, '(?:\\\\/([^\\\\/]+))?') // /:param?\n .replace(/:([^/\\\\*+?]+)\\*/g, '(.*)') // :param* (if no leading slash)\n .replace(/:([^/\\\\*+?]+)\\?/g, '([^\\\\/]*)') // :param? (if no leading slash)\n .replace(/:([^/\\\\*+?]+)\\+/g, '(.+)') // :param+\n .replace(/:([^/\\\\*+?]+)/g, '([^\\\\/]+)'); // :param\n\n
|
|
1
|
+
{"version":3,"file":"rewriteMatch.mjs","names":["legacyRules"],"sources":["../../../src/localization/rewriteMatch.ts"],"sourcesContent":["import type {\n RewriteObject,\n RewriteRules,\n RoutingConfig,\n} from '@intlayer/types/config';\n\n/**\n * Normalizes legacy Record format or extracts specialized rules from RewriteObject.\n *\n * Idempotent: already-normalized rules are handed back untouched, so a caller\n * holding resolved rules can pass them on without re-normalizing.\n */\nexport const getRewriteRules = <\n const Context extends keyof RewriteObject = 'url',\n>(\n rewrite: RoutingConfig['rewrite'] | RewriteRules,\n context: Context = 'url' as Context\n): RewriteRules | undefined => {\n if (\n !rewrite ||\n (process.env.INTLAYER_ROUTING_REWRITE_RULES &&\n process.env.INTLAYER_ROUTING_REWRITE_RULES === 'false')\n )\n return undefined;\n\n if (Array.isArray((rewrite as RewriteRules).rules)) {\n return rewrite as RewriteRules;\n }\n\n if ('url' in rewrite) {\n return (rewrite as RewriteObject)[context];\n }\n\n // Normalize legacy format\n const legacyRules = rewrite as Record<string, Record<string, string>>;\n\n return {\n rules: Object.entries(legacyRules).map(([canonical, localized]) => ({\n // Normalize canonical path\n canonical: canonical.startsWith('/')\n ? canonical.replace(/\\[([^\\]]+)\\]/g, ':$1')\n : `/${canonical.replace(/\\[([^\\]]+)\\]/g, ':$1')}`,\n\n // Normalize localized path\n localized: Object.fromEntries(\n Object.entries(localized).map(([locale, pattern]) => {\n const normalizedPattern = pattern?.startsWith('/')\n ? pattern.replace(/\\[([^\\]]+)\\]/g, ':$1')\n : `/${(pattern || '').replace(/\\[([^\\]]+)\\]/g, ':$1')}`;\n return [locale, normalizedPattern];\n })\n ),\n })),\n };\n};\n\n/**\n * Compiled regexes by pattern. Patterns come from the finite set of rewrite\n * rules, while URL localization runs per link, so compiling once pays off.\n * The regexes have no `g` flag, so sharing them is stateless.\n */\nconst patternRegexCache = new Map<string, RegExp>();\n\n/**\n * Converts normalized pattern to Regex.\n * Internal syntax supports:\n * - :param -> ([^/]+) (one segment)\n * - :param* -> (.*) (zero or more segments)\n * - :param+ -> (.+) (one or more segments)\n * - :param? -> ([^/]*) (zero or one segment)\n */\nconst patternToRegex = (pattern: string): RegExp => {\n const cachedRegex = patternRegexCache.get(pattern);\n\n if (cachedRegex) return cachedRegex;\n\n const regexString = pattern\n .replace(/\\//g, '\\\\/') // Escape slashes\n .replace(/\\\\\\/:(?:[^/\\\\*+?]+)\\*/g, '(?:\\\\/(.*))?') // /:param*\n .replace(/\\\\\\/:(?:[^/\\\\*+?]+)\\?/g, '(?:\\\\/([^\\\\/]+))?') // /:param?\n .replace(/:([^/\\\\*+?]+)\\*/g, '(.*)') // :param* (if no leading slash)\n .replace(/:([^/\\\\*+?]+)\\?/g, '([^\\\\/]*)') // :param? (if no leading slash)\n .replace(/:([^/\\\\*+?]+)\\+/g, '(.+)') // :param+\n .replace(/:([^/\\\\*+?]+)/g, '([^\\\\/]+)'); // :param\n\n const regex = new RegExp(`^${regexString}$`);\n patternRegexCache.set(pattern, regex);\n\n return regex;\n};\n\n/**\n * Replaces route parameters in a path with provided values.\n */\nexport const fillPath = (pattern: string, params: string[]) => {\n let index = 0;\n return (\n pattern\n .replace(/:([^/\\\\*+?]+)[*+?]?/g, () => params[index++] ?? '')\n .replace(/\\/+/g, '/')\n .replace(/\\/$/, '') || '/'\n );\n};\n\n/**\n * Extract values from a URL based on a pattern.\n */\nexport const extractParams = (\n url: string,\n pattern: string\n): string[] | null => {\n const regex = patternToRegex(pattern);\n const match = url.match(regex);\n return match ? match.slice(1) : null;\n};\n"],"mappings":";;;;;;;AAYA,MAAa,mBAGX,SACA,UAAmB,UACU;CAC7B,IACE,CAAC,WACA,QAAQ,IAAI,kCACX,QAAQ,IAAI,mCAAmC,SAEjD,OAAO;CAET,IAAI,MAAM,QAAS,QAAyB,KAAK,GAC/C,OAAO;CAGT,IAAI,SAAS,SACX,OAAQ,QAA0B;CAMpC,OAAO,EACL,OAAO,OAAO,QAAQA,OAAW,CAAC,CAAC,KAAK,CAAC,WAAW,gBAAgB;EAElE,WAAW,UAAU,WAAW,GAAG,IAC/B,UAAU,QAAQ,iBAAiB,KAAK,IACxC,IAAI,UAAU,QAAQ,iBAAiB,KAAK;EAGhD,WAAW,OAAO,YAChB,OAAO,QAAQ,SAAS,CAAC,CAAC,KAAK,CAAC,QAAQ,aAAa;GAInD,OAAO,CAAC,QAHkB,SAAS,WAAW,GAAG,IAC7C,QAAQ,QAAQ,iBAAiB,KAAK,IACtC,KAAK,WAAW,GAAE,CAAE,QAAQ,iBAAiB,KAAK,GACrB;EACnC,CAAC,CACH;CACF,EAAE,EACJ;AACF;;;;;;AAOA,MAAM,oCAAoB,IAAI,IAAoB;;;;;;;;;AAUlD,MAAM,kBAAkB,YAA4B;CAClD,MAAM,cAAc,kBAAkB,IAAI,OAAO;CAEjD,IAAI,aAAa,OAAO;CAExB,MAAM,cAAc,QACjB,QAAQ,OAAO,KAAK,CAAC,CACrB,QAAQ,0BAA0B,cAAc,CAAC,CACjD,QAAQ,0BAA0B,mBAAmB,CAAC,CACtD,QAAQ,oBAAoB,MAAM,CAAC,CACnC,QAAQ,oBAAoB,WAAW,CAAC,CACxC,QAAQ,oBAAoB,MAAM,CAAC,CACnC,QAAQ,kBAAkB,WAAW;CAExC,MAAM,QAAQ,IAAI,OAAO,IAAI,YAAY,EAAE;CAC3C,kBAAkB,IAAI,SAAS,KAAK;CAEpC,OAAO;AACT;;;;AAKA,MAAa,YAAY,SAAiB,WAAqB;CAC7D,IAAI,QAAQ;CACZ,OACE,QACG,QAAQ,8BAA8B,OAAO,YAAY,EAAE,CAAC,CAC5D,QAAQ,QAAQ,GAAG,CAAC,CACpB,QAAQ,OAAO,EAAE,KAAK;AAE7B;;;;AAKA,MAAa,iBACX,KACA,YACoB;CACpB,MAAM,QAAQ,eAAe,OAAO;CACpC,MAAM,QAAQ,IAAI,MAAM,KAAK;CAC7B,OAAO,QAAQ,MAAM,MAAM,CAAC,IAAI;AAClC"}
|
|
@@ -1091,7 +1091,7 @@ const renderMarkdownAst = (parsed, ctx, options = {}) => {
|
|
|
1091
1091
|
};
|
|
1092
1092
|
const compile = (markdown = "", ctx, options = {}) => {
|
|
1093
1093
|
if (typeof markdown !== "string") {
|
|
1094
|
-
console.error("intlayer: the first argument must be a string. Received", typeof markdown);
|
|
1094
|
+
if (process.env.NODE_ENV !== "production") console.error("intlayer: the first argument must be a string. Received", typeof markdown);
|
|
1095
1095
|
throw new Error("intlayer: the first argument must be a string");
|
|
1096
1096
|
}
|
|
1097
1097
|
const { parse, emit, createElement, scope } = getRuleSet(ctx, options, false);
|