@intlayer/core 8.7.11 → 8.7.13
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/README.md +27 -1
- package/dist/cjs/deepTransformPlugins/getMissingLocalesContent.cjs +2 -1
- package/dist/cjs/deepTransformPlugins/getMissingLocalesContent.cjs.map +1 -1
- package/dist/cjs/interpreter/getContent/deepTransform.cjs +26 -20
- package/dist/cjs/interpreter/getContent/deepTransform.cjs.map +1 -1
- package/dist/cjs/interpreter/getContent/plugins.cjs +7 -35
- package/dist/cjs/interpreter/getContent/plugins.cjs.map +1 -1
- package/dist/cjs/localization/getLocalizedUrl.cjs +4 -17
- package/dist/cjs/localization/getLocalizedUrl.cjs.map +1 -1
- package/dist/cjs/localization/getPrefix.cjs +2 -12
- package/dist/cjs/localization/getPrefix.cjs.map +1 -1
- package/dist/esm/deepTransformPlugins/getMissingLocalesContent.mjs +2 -1
- package/dist/esm/deepTransformPlugins/getMissingLocalesContent.mjs.map +1 -1
- package/dist/esm/interpreter/getContent/deepTransform.mjs +26 -20
- package/dist/esm/interpreter/getContent/deepTransform.mjs.map +1 -1
- package/dist/esm/interpreter/getContent/plugins.mjs +7 -35
- package/dist/esm/interpreter/getContent/plugins.mjs.map +1 -1
- package/dist/esm/localization/getLocalizedUrl.mjs +4 -17
- package/dist/esm/localization/getLocalizedUrl.mjs.map +1 -1
- package/dist/esm/localization/getPrefix.mjs +2 -12
- package/dist/esm/localization/getPrefix.mjs.map +1 -1
- package/dist/types/deepTransformPlugins/getMissingLocalesContent.d.ts.map +1 -1
- package/dist/types/interpreter/getContent/plugins.d.ts +7 -0
- package/dist/types/interpreter/getContent/plugins.d.ts.map +1 -1
- package/dist/types/localization/getLocalizedUrl.d.ts.map +1 -1
- package/dist/types/localization/getPrefix.d.ts.map +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -190,7 +190,22 @@ Explore our comprehensive documentation to get started with Intlayer and learn h
|
|
|
190
190
|
<li><a href="https://intlayer.org/doc/environment/vite-and-react" rel=''>Vite + React</a></li>
|
|
191
191
|
<li><a href="https://intlayer.org/doc/environment/vite-and-react" rel=''>Vite + React using Compiler</a></li>
|
|
192
192
|
<li><a href="https://intlayer.org/doc/environment/vite-and-react/compiler" rel=''>React-router-v7</a></li>
|
|
193
|
-
<li><a href="https://intlayer.org/doc/environment/
|
|
193
|
+
<li><a href="https://intlayer.org/doc/environment/tanstack-start" rel=''>Tanstack start</a>
|
|
194
|
+
<ul>
|
|
195
|
+
<li><a href="https://intlayer.org/doc/environment/tanstack-start/solid" rel=''>Solid</a></li>
|
|
196
|
+
</ul>
|
|
197
|
+
</li>
|
|
198
|
+
<li><a href="https://intlayer.org/doc/environment/astro" rel=''>Astro</a>
|
|
199
|
+
<ul>
|
|
200
|
+
<li><a href="https://intlayer.org/doc/environment/astro/react" rel=''>React</a></li>
|
|
201
|
+
<li><a href="https://intlayer.org/doc/environment/astro/vue" rel=''>Vue</a></li>
|
|
202
|
+
<li><a href="https://intlayer.org/doc/environment/astro/svelte" rel=''>Svelte</a></li>
|
|
203
|
+
<li><a href="https://intlayer.org/doc/environment/astro/solid" rel=''>Solid</a></li>
|
|
204
|
+
<li><a href="https://intlayer.org/doc/environment/astro/vanilla" rel=''>Vanilla JS</a></li>
|
|
205
|
+
<li><a href="https://intlayer.org/doc/environment/astro/lit" rel=''>Lit</a></li>
|
|
206
|
+
</ul>
|
|
207
|
+
</li>
|
|
208
|
+
|
|
194
209
|
<li><a href="https://intlayer.org/doc/environment/react-native-and-expo" rel=''>React Native</a></li>
|
|
195
210
|
<li><a href="https://intlayer.org/doc/environment/vite-and-svelte" rel=''>Vite + Svelte</a></li>
|
|
196
211
|
<li><a href="https://intlayer.org/doc/environment/sveltekit" rel=''>SvelteKit</a></li>
|
|
@@ -212,6 +227,17 @@ Explore our comprehensive documentation to get started with Intlayer and learn h
|
|
|
212
227
|
</ul>
|
|
213
228
|
</details>
|
|
214
229
|
|
|
230
|
+
<details>
|
|
231
|
+
<summary style="font-size:16px; font-weight:bold;">📊 Benchmark</summary>
|
|
232
|
+
<ul>
|
|
233
|
+
<li><a href="https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/benchmark/nextjs.md" rel=''>Next.js</a></li>
|
|
234
|
+
<li><a href="https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/benchmark/tanstack.md" rel=''>TanStack Start</a></li>
|
|
235
|
+
<li><a href="https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/benchmark/vue.md" rel=''>Vue</a></li>
|
|
236
|
+
<li><a href="https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/benchmark/solid.md" rel=''>Solid</a></li>
|
|
237
|
+
<li><a href="https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/benchmark/svelte.md" rel=''>Svelte</a></li>
|
|
238
|
+
</ul>
|
|
239
|
+
</details>
|
|
240
|
+
|
|
215
241
|
<details>
|
|
216
242
|
<summary style="font-size:16px; font-weight:bold;">📰 Blog</summary>
|
|
217
243
|
<ul>
|
|
@@ -135,7 +135,8 @@ const getMissingLocalesContent = (node, locales = _intlayer_config_built.interna
|
|
|
135
135
|
const plugins = [checkMissingLocalesPlugin(locales, (locale) => missingLocales.add(locale)), ...nodeProps.plugins ?? []];
|
|
136
136
|
require_interpreter_getContent_deepTransform.deepTransformNode(node, {
|
|
137
137
|
...nodeProps,
|
|
138
|
-
plugins
|
|
138
|
+
plugins,
|
|
139
|
+
eager: true
|
|
139
140
|
});
|
|
140
141
|
return Array.from(missingLocales);
|
|
141
142
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getMissingLocalesContent.cjs","names":["NodeTypes","internationalization"],"sources":["../../../src/deepTransformPlugins/getMissingLocalesContent.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { ContentNode, Dictionary } from '@intlayer/types/dictionary';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type { DeepTransformContent, NodeProps, Plugins } from '../interpreter';\nimport { deepTransformNode } from '../interpreter/getContent/deepTransform';\nimport type { TranslationContent } from '../transpiler';\n\n/**\n * Returns all key paths present in obj, INCLUDING those whose leaf value is null.\n * Used for structural presence checks (a locale must have every key another locale has,\n * even if the value is a null placeholder).\n */\nconst getAllKeyPaths = (obj: any, prefix: string[] = []): string[][] => {\n if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {\n return [];\n }\n\n return Object.keys(obj).flatMap((key) => {\n const newPath = [...prefix, key];\n const value = obj[key];\n // Stop recursing into null — include the path but don't descend further\n if (value === null) {\n return [newPath];\n }\n return [newPath, ...getAllKeyPaths(value, newPath)];\n });\n};\n\n/**\n * Returns key paths whose leaf value is non-null.\n * Used for translation value checks (a locale must not have null where another locale\n * already has a real translated value).\n */\nconst getNonNullKeyPaths = (obj: any, prefix: string[] = []): string[][] => {\n if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {\n return [];\n }\n\n return Object.keys(obj).flatMap((key) => {\n const newPath = [...prefix, key];\n const value = obj[key];\n // Skip null-valued keys entirely\n if (value === null) {\n return [];\n }\n return [newPath, ...getNonNullKeyPaths(value, newPath)];\n });\n};\n\n/**\n * Returns true if the key path EXISTS in obj (even if the terminal value is null).\n * Used for the structural presence check.\n */\nconst hasKey = (obj: any, keyPath: string[]): boolean => {\n let current = obj;\n for (const key of keyPath) {\n if (\n current === undefined ||\n current === null ||\n typeof current !== 'object'\n ) {\n return false;\n }\n if (!(key in current)) {\n return false;\n }\n current = current[key];\n }\n return true; // key exists; value may be null\n};\n\n/**\n * Returns true if the key path exists in obj AND the terminal value is non-null.\n * Used for the translation value check.\n */\nconst hasNonNullValue = (obj: any, keyPath: string[]): boolean => {\n let current = obj;\n for (const key of keyPath) {\n if (\n current === undefined ||\n current === null ||\n typeof current !== 'object'\n ) {\n return false;\n }\n if (!(key in current)) {\n return false;\n }\n current = current[key];\n }\n // null is treated as a missing translation (e.g., i18next-scanner sets null for untranslated keys)\n return current !== null;\n};\n\n/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */\nexport const checkMissingLocalesPlugin = (\n locales: Locale[],\n onMissingLocale: (locale: Locale) => void\n): Plugins => ({\n id: 'check-missing-locales-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.TRANSLATION,\n transform: (node: TranslationContent, props, deepTransformNode) => {\n const translations = node[NodeTypes.TRANSLATION] as Record<string, any>;\n\n /**\n * Two path sets built from all locales' content:\n *\n * presentPaths — every key path that exists in ANY locale, even those whose value\n * is null. A locale that is missing a path from this set is structurally incomplete\n * (the key doesn't exist at all).\n *\n * nonNullPaths — every key path that has a non-null value in at least one locale.\n * A locale that has the key but with null, when another locale already has a real\n * value, needs translation.\n */\n const presentPaths = new Set<string>();\n const nonNullPaths = new Set<string>();\n\n for (const locale of locales) {\n const value = translations[locale];\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n getAllKeyPaths(value).forEach((path) => {\n presentPaths.add(JSON.stringify(path));\n });\n\n getNonNullKeyPaths(value).forEach((path) => {\n nonNullPaths.add(JSON.stringify(path));\n });\n }\n }\n\n // If no locale has any content at all (all are null/undefined), the key is\n // universally pending — don't flag anyone.\n const hasAnyDefinedValue = locales.some(\n (locale) =>\n translations[locale] !== undefined && translations[locale] !== null\n );\n\n for (const locale of locales) {\n const value = translations[locale];\n\n if (value === null) {\n // Entire locale content is a null placeholder.\n // Flag only when some other locale already has real content.\n if (hasAnyDefinedValue) {\n onMissingLocale(locale);\n }\n continue;\n }\n\n if (!value) {\n // undefined / entirely absent\n onMissingLocale(locale);\n continue;\n }\n\n let flagged = false;\n\n // Structural check: every key that exists in any locale must also exist here\n // (even if the local value is null — at least the key must be present).\n for (const pathStr of presentPaths) {\n if (!hasKey(value, JSON.parse(pathStr))) {\n onMissingLocale(locale);\n flagged = true;\n break;\n }\n }\n\n if (!flagged) {\n // Value check: every key that has a non-null value in some locale must also\n // be non-null here (null = untranslated, needs filling).\n for (const pathStr of nonNullPaths) {\n if (!hasNonNullValue(value, JSON.parse(pathStr))) {\n onMissingLocale(locale);\n break;\n }\n }\n }\n }\n\n // Continue traversal inside the translation values\n for (const key in translations) {\n const child = translations[key];\n deepTransformNode(child, {\n ...props,\n children: child,\n });\n }\n\n // Return the original node; the return value is ignored by the caller\n return node;\n },\n});\n\n/**\n * Return the content of a node with only the translation plugin.\n *\n * @param node The node to transform.\n * @param locales The locales to check for missing translations.\n */\nexport const getMissingLocalesContent = <T extends ContentNode>(\n node: T,\n locales: LocalesValues[] = internationalization?.locales,\n\n nodeProps: NodeProps\n): Locale[] => {\n const missingLocales = new Set<Locale>();\n\n const plugins: Plugins[] = [\n checkMissingLocalesPlugin(locales as Locale[], (locale) =>\n missingLocales.add(locale)\n ),\n ...(nodeProps.plugins ?? []),\n ];\n\n deepTransformNode(node, {\n ...nodeProps,\n plugins,\n }) as DeepTransformContent<T>;\n\n return Array.from(missingLocales);\n};\n\nexport const getMissingLocalesContentFromDictionary = (\n dictionary: Dictionary,\n locales: LocalesValues[] = internationalization?.locales\n) =>\n getMissingLocalesContent(dictionary.content, locales, {\n dictionaryKey: dictionary.key,\n keyPath: [],\n });\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"getMissingLocalesContent.cjs","names":["NodeTypes","internationalization"],"sources":["../../../src/deepTransformPlugins/getMissingLocalesContent.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { ContentNode, Dictionary } from '@intlayer/types/dictionary';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type { DeepTransformContent, NodeProps, Plugins } from '../interpreter';\nimport { deepTransformNode } from '../interpreter/getContent/deepTransform';\nimport type { TranslationContent } from '../transpiler';\n\n/**\n * Returns all key paths present in obj, INCLUDING those whose leaf value is null.\n * Used for structural presence checks (a locale must have every key another locale has,\n * even if the value is a null placeholder).\n */\nconst getAllKeyPaths = (obj: any, prefix: string[] = []): string[][] => {\n if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {\n return [];\n }\n\n return Object.keys(obj).flatMap((key) => {\n const newPath = [...prefix, key];\n const value = obj[key];\n // Stop recursing into null — include the path but don't descend further\n if (value === null) {\n return [newPath];\n }\n return [newPath, ...getAllKeyPaths(value, newPath)];\n });\n};\n\n/**\n * Returns key paths whose leaf value is non-null.\n * Used for translation value checks (a locale must not have null where another locale\n * already has a real translated value).\n */\nconst getNonNullKeyPaths = (obj: any, prefix: string[] = []): string[][] => {\n if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {\n return [];\n }\n\n return Object.keys(obj).flatMap((key) => {\n const newPath = [...prefix, key];\n const value = obj[key];\n // Skip null-valued keys entirely\n if (value === null) {\n return [];\n }\n return [newPath, ...getNonNullKeyPaths(value, newPath)];\n });\n};\n\n/**\n * Returns true if the key path EXISTS in obj (even if the terminal value is null).\n * Used for the structural presence check.\n */\nconst hasKey = (obj: any, keyPath: string[]): boolean => {\n let current = obj;\n for (const key of keyPath) {\n if (\n current === undefined ||\n current === null ||\n typeof current !== 'object'\n ) {\n return false;\n }\n if (!(key in current)) {\n return false;\n }\n current = current[key];\n }\n return true; // key exists; value may be null\n};\n\n/**\n * Returns true if the key path exists in obj AND the terminal value is non-null.\n * Used for the translation value check.\n */\nconst hasNonNullValue = (obj: any, keyPath: string[]): boolean => {\n let current = obj;\n for (const key of keyPath) {\n if (\n current === undefined ||\n current === null ||\n typeof current !== 'object'\n ) {\n return false;\n }\n if (!(key in current)) {\n return false;\n }\n current = current[key];\n }\n // null is treated as a missing translation (e.g., i18next-scanner sets null for untranslated keys)\n return current !== null;\n};\n\n/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */\nexport const checkMissingLocalesPlugin = (\n locales: Locale[],\n onMissingLocale: (locale: Locale) => void\n): Plugins => ({\n id: 'check-missing-locales-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.TRANSLATION,\n transform: (node: TranslationContent, props, deepTransformNode) => {\n const translations = node[NodeTypes.TRANSLATION] as Record<string, any>;\n\n /**\n * Two path sets built from all locales' content:\n *\n * presentPaths — every key path that exists in ANY locale, even those whose value\n * is null. A locale that is missing a path from this set is structurally incomplete\n * (the key doesn't exist at all).\n *\n * nonNullPaths — every key path that has a non-null value in at least one locale.\n * A locale that has the key but with null, when another locale already has a real\n * value, needs translation.\n */\n const presentPaths = new Set<string>();\n const nonNullPaths = new Set<string>();\n\n for (const locale of locales) {\n const value = translations[locale];\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n getAllKeyPaths(value).forEach((path) => {\n presentPaths.add(JSON.stringify(path));\n });\n\n getNonNullKeyPaths(value).forEach((path) => {\n nonNullPaths.add(JSON.stringify(path));\n });\n }\n }\n\n // If no locale has any content at all (all are null/undefined), the key is\n // universally pending — don't flag anyone.\n const hasAnyDefinedValue = locales.some(\n (locale) =>\n translations[locale] !== undefined && translations[locale] !== null\n );\n\n for (const locale of locales) {\n const value = translations[locale];\n\n if (value === null) {\n // Entire locale content is a null placeholder.\n // Flag only when some other locale already has real content.\n if (hasAnyDefinedValue) {\n onMissingLocale(locale);\n }\n continue;\n }\n\n if (!value) {\n // undefined / entirely absent\n onMissingLocale(locale);\n continue;\n }\n\n let flagged = false;\n\n // Structural check: every key that exists in any locale must also exist here\n // (even if the local value is null — at least the key must be present).\n for (const pathStr of presentPaths) {\n if (!hasKey(value, JSON.parse(pathStr))) {\n onMissingLocale(locale);\n flagged = true;\n break;\n }\n }\n\n if (!flagged) {\n // Value check: every key that has a non-null value in some locale must also\n // be non-null here (null = untranslated, needs filling).\n for (const pathStr of nonNullPaths) {\n if (!hasNonNullValue(value, JSON.parse(pathStr))) {\n onMissingLocale(locale);\n break;\n }\n }\n }\n }\n\n // Continue traversal inside the translation values\n for (const key in translations) {\n const child = translations[key];\n deepTransformNode(child, {\n ...props,\n children: child,\n });\n }\n\n // Return the original node; the return value is ignored by the caller\n return node;\n },\n});\n\n/**\n * Return the content of a node with only the translation plugin.\n *\n * @param node The node to transform.\n * @param locales The locales to check for missing translations.\n */\nexport const getMissingLocalesContent = <T extends ContentNode>(\n node: T,\n locales: LocalesValues[] = internationalization?.locales,\n\n nodeProps: NodeProps\n): Locale[] => {\n const missingLocales = new Set<Locale>();\n\n const plugins: Plugins[] = [\n checkMissingLocalesPlugin(locales as Locale[], (locale) =>\n missingLocales.add(locale)\n ),\n ...(nodeProps.plugins ?? []),\n ];\n\n // eager: traversal of plain objects must run immediately. Without it the\n // returned tree is a proxy of lazy getters; we discard the tree, so nested\n // translation nodes inside plain objects (the typical dictionary shape) are\n // never visited and their missing locales go undetected.\n deepTransformNode(node, {\n ...nodeProps,\n plugins,\n eager: true,\n }) as DeepTransformContent<T>;\n\n return Array.from(missingLocales);\n};\n\nexport const getMissingLocalesContentFromDictionary = (\n dictionary: Dictionary,\n locales: LocalesValues[] = internationalization?.locales\n) =>\n getMissingLocalesContent(dictionary.content, locales, {\n dictionaryKey: dictionary.key,\n keyPath: [],\n });\n"],"mappings":"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"}
|
|
@@ -24,27 +24,33 @@ const deepTransformNode = (node, props) => {
|
|
|
24
24
|
});
|
|
25
25
|
});
|
|
26
26
|
const result = {};
|
|
27
|
-
for (const key in node)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const transformed = deepTransformNode(node[key], childProps);
|
|
40
|
-
Object.defineProperty(this, key, {
|
|
41
|
-
value: transformed,
|
|
42
|
-
enumerable: true,
|
|
43
|
-
configurable: true
|
|
44
|
-
});
|
|
45
|
-
return transformed;
|
|
27
|
+
for (const key in node) {
|
|
28
|
+
const childProps = {
|
|
29
|
+
...props,
|
|
30
|
+
children: node[key],
|
|
31
|
+
keyPath: [...props.keyPath, {
|
|
32
|
+
type: _intlayer_types_nodeType.OBJECT,
|
|
33
|
+
key
|
|
34
|
+
}]
|
|
35
|
+
};
|
|
36
|
+
if (props.eager) {
|
|
37
|
+
result[key] = deepTransformNode(node[key], childProps);
|
|
38
|
+
continue;
|
|
46
39
|
}
|
|
47
|
-
|
|
40
|
+
Object.defineProperty(result, key, {
|
|
41
|
+
enumerable: true,
|
|
42
|
+
configurable: true,
|
|
43
|
+
get: function() {
|
|
44
|
+
const transformed = deepTransformNode(node[key], childProps);
|
|
45
|
+
Object.defineProperty(this, key, {
|
|
46
|
+
value: transformed,
|
|
47
|
+
enumerable: true,
|
|
48
|
+
configurable: true
|
|
49
|
+
});
|
|
50
|
+
return transformed;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
48
54
|
return result;
|
|
49
55
|
};
|
|
50
56
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deepTransform.cjs","names":["NodeTypes"],"sources":["../../../../src/interpreter/getContent/deepTransform.ts"],"sourcesContent":["import type { KeyPath } from '@intlayer/types/keyPath';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type { NodeProps } from './plugins';\n\n/**\n * Recursively traverses a node (object/array/primitive).\n * Applies the *first* plugin that can transform a node, then stops descending further.\n * If no plugin transforms it, it recurses into its children.\n */\nexport const deepTransformNode = (node: any, props: NodeProps): any => {\n // Otherwise, if it's an object, check if any plugin can handle it:\n for (const plugin of props.plugins ?? []) {\n if (plugin.canHandle(node)) {\n // Return the transformed node => do NOT recurse further\n return plugin.transform(node, props, (node: any, props: any) =>\n deepTransformNode(node, props)\n );\n }\n }\n\n // If it's null/undefined or not an object, just return it directly:\n if (node === null || typeof node !== 'object') {\n return node;\n }\n\n // If it's a framework-specific virtual node or already a transformed Proxy,\n // return it directly to avoid re-transforming its internal properties.\n if (\n (node as any).$$typeof !== undefined ||\n (node as any).__v_isVNode !== undefined ||\n (node as any)._isVNode !== undefined ||\n (node as any).isJSX !== undefined ||\n typeof node === 'function' // Proxies for html/markdown are functions\n ) {\n return node;\n }\n\n // If it's an array, transform each element:\n if (Array.isArray(node)) {\n return node.map((child, index) => {\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.ARRAY, key: index } as KeyPath,\n ],\n };\n return deepTransformNode(child, childProps);\n });\n }\n\n // If no plugin transforms it, we keep traversing its properties.\n const result: Record<string, any> = {};\n for (const key in node) {\n
|
|
1
|
+
{"version":3,"file":"deepTransform.cjs","names":["NodeTypes"],"sources":["../../../../src/interpreter/getContent/deepTransform.ts"],"sourcesContent":["import type { KeyPath } from '@intlayer/types/keyPath';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type { NodeProps } from './plugins';\n\n/**\n * Recursively traverses a node (object/array/primitive).\n * Applies the *first* plugin that can transform a node, then stops descending further.\n * If no plugin transforms it, it recurses into its children.\n */\nexport const deepTransformNode = (node: any, props: NodeProps): any => {\n // Otherwise, if it's an object, check if any plugin can handle it:\n for (const plugin of props.plugins ?? []) {\n if (plugin.canHandle(node)) {\n // Return the transformed node => do NOT recurse further\n return plugin.transform(node, props, (node: any, props: any) =>\n deepTransformNode(node, props)\n );\n }\n }\n\n // If it's null/undefined or not an object, just return it directly:\n if (node === null || typeof node !== 'object') {\n return node;\n }\n\n // If it's a framework-specific virtual node or already a transformed Proxy,\n // return it directly to avoid re-transforming its internal properties.\n if (\n (node as any).$$typeof !== undefined ||\n (node as any).__v_isVNode !== undefined ||\n (node as any)._isVNode !== undefined ||\n (node as any).isJSX !== undefined ||\n typeof node === 'function' // Proxies for html/markdown are functions\n ) {\n return node;\n }\n\n // If it's an array, transform each element:\n if (Array.isArray(node)) {\n return node.map((child, index) => {\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.ARRAY, key: index } as KeyPath,\n ],\n };\n return deepTransformNode(child, childProps);\n });\n }\n\n // If no plugin transforms it, we keep traversing its properties.\n const result: Record<string, any> = {};\n for (const key in node) {\n const childProps = {\n ...props,\n children: node[key],\n keyPath: [...props.keyPath, { type: NodeTypes.OBJECT, key } as KeyPath],\n };\n\n if (props.eager) {\n // Eager mode: recurse immediately so plugins fire on every node, even\n // when the caller discards the returned tree (e.g. side-effect-only\n // plugins like missing-locale detection).\n result[key] = deepTransformNode(node[key], childProps);\n continue;\n }\n\n Object.defineProperty(result, key, {\n enumerable: true,\n configurable: true,\n get: function () {\n const transformed = deepTransformNode(node[key], childProps);\n\n // Memoize the result onto the property to avoid re-calculating on next read\n Object.defineProperty(this, key, {\n value: transformed,\n enumerable: true,\n configurable: true,\n });\n return transformed;\n },\n });\n }\n\n return result;\n};\n"],"mappings":";;;;;;;;;;;AASA,MAAa,qBAAqB,MAAW,UAA0B;AAErE,MAAK,MAAM,UAAU,MAAM,WAAW,EAAE,CACtC,KAAI,OAAO,UAAU,KAAK,CAExB,QAAO,OAAO,UAAU,MAAM,QAAQ,MAAW,UAC/C,kBAAkB,MAAM,MAAM,CAC/B;AAKL,KAAI,SAAS,QAAQ,OAAO,SAAS,SACnC,QAAO;AAKT,KACG,KAAa,aAAa,UAC1B,KAAa,gBAAgB,UAC7B,KAAa,aAAa,UAC1B,KAAa,UAAU,UACxB,OAAO,SAAS,WAEhB,QAAO;AAIT,KAAI,MAAM,QAAQ,KAAK,CACrB,QAAO,KAAK,KAAK,OAAO,UAAU;AAShC,SAAO,kBAAkB,OAAO;GAP9B,GAAG;GACH,UAAU;GACV,SAAS,CACP,GAAG,MAAM,SACT;IAAE,MAAMA,yBAAU;IAAO,KAAK;IAAO,CACtC;GAEuC,CAAC;GAC3C;CAIJ,MAAM,SAA8B,EAAE;AACtC,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,aAAa;GACjB,GAAG;GACH,UAAU,KAAK;GACf,SAAS,CAAC,GAAG,MAAM,SAAS;IAAE,MAAMA,yBAAU;IAAQ;IAAK,CAAY;GACxE;AAED,MAAI,MAAM,OAAO;AAIf,UAAO,OAAO,kBAAkB,KAAK,MAAM,WAAW;AACtD;;AAGF,SAAO,eAAe,QAAQ,KAAK;GACjC,YAAY;GACZ,cAAc;GACd,KAAK,WAAY;IACf,MAAM,cAAc,kBAAkB,KAAK,MAAM,WAAW;AAG5D,WAAO,eAAe,MAAM,KAAK;KAC/B,OAAO;KACP,YAAY;KACZ,cAAc;KACf,CAAC;AACF,WAAO;;GAEV,CAAC;;AAGJ,QAAO"}
|
|
@@ -10,34 +10,6 @@ let _intlayer_types_nodeType = require("@intlayer/types/nodeType");
|
|
|
10
10
|
_intlayer_types_nodeType = require_runtime.__toESM(_intlayer_types_nodeType);
|
|
11
11
|
|
|
12
12
|
//#region src/interpreter/getContent/plugins.ts
|
|
13
|
-
/**
|
|
14
|
-
* True when the translation node type is explicitly disabled at build time.
|
|
15
|
-
*/
|
|
16
|
-
const TREE_SHAKE_TRANSLATION = process.env["INTLAYER_NODE_TYPE_TRANSLATION"] === "false";
|
|
17
|
-
/**
|
|
18
|
-
* True when the enumeration node type is explicitly disabled at build time.
|
|
19
|
-
*/
|
|
20
|
-
const TREE_SHAKE_ENUMERATION = process.env["INTLAYER_NODE_TYPE_ENUMERATION"] === "false";
|
|
21
|
-
/**
|
|
22
|
-
* True when the condition node type is explicitly disabled at build time.
|
|
23
|
-
*/
|
|
24
|
-
const TREE_SHAKE_CONDITION = process.env["INTLAYER_NODE_TYPE_CONDITION"] === "false";
|
|
25
|
-
/**
|
|
26
|
-
* True when the insertion node type is explicitly disabled at build time.
|
|
27
|
-
*/
|
|
28
|
-
const TREE_SHAKE_INSERTION = process.env["INTLAYER_NODE_TYPE_INSERTION"] === "false";
|
|
29
|
-
/**
|
|
30
|
-
* True when the gender node type is explicitly disabled at build time.
|
|
31
|
-
*/
|
|
32
|
-
const TREE_SHAKE_GENDER = process.env["INTLAYER_NODE_TYPE_GENDER"] === "false";
|
|
33
|
-
/**
|
|
34
|
-
* True when the nested node type is explicitly disabled at build time.
|
|
35
|
-
*/
|
|
36
|
-
const TREE_SHAKE_NESTED = process.env["INTLAYER_NODE_TYPE_NESTED"] === "false";
|
|
37
|
-
/**
|
|
38
|
-
* True when the file node type is explicitly disabled at build time.
|
|
39
|
-
*/
|
|
40
|
-
const TREE_SHAKE_FILE = process.env["INTLAYER_NODE_TYPE_FILE"] === "false";
|
|
41
13
|
/** ---------------------------------------------
|
|
42
14
|
* FALLBACK PLUGIN
|
|
43
15
|
*
|
|
@@ -49,7 +21,7 @@ const fallbackPlugin = {
|
|
|
49
21
|
transform: (node) => node
|
|
50
22
|
};
|
|
51
23
|
/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */
|
|
52
|
-
const translationPlugin = (locale, fallback) =>
|
|
24
|
+
const translationPlugin = (locale, fallback) => process.env["INTLAYER_NODE_TYPE_TRANSLATION"] === "false" ? fallbackPlugin : {
|
|
53
25
|
id: "translation-plugin",
|
|
54
26
|
canHandle: (node) => typeof node === "object" && node?.nodeType === _intlayer_types_nodeType.TRANSLATION,
|
|
55
27
|
transform: (node, props, deepTransformNode) => {
|
|
@@ -70,7 +42,7 @@ const translationPlugin = (locale, fallback) => TREE_SHAKE_TRANSLATION ? fallbac
|
|
|
70
42
|
}
|
|
71
43
|
};
|
|
72
44
|
/** Enumeration plugin. Replaces node with a function that takes quantity => string. */
|
|
73
|
-
const enumerationPlugin =
|
|
45
|
+
const enumerationPlugin = process.env["INTLAYER_NODE_TYPE_ENUMERATION"] === "false" ? fallbackPlugin : {
|
|
74
46
|
id: "enumeration-plugin",
|
|
75
47
|
canHandle: (node) => typeof node === "object" && node?.nodeType === _intlayer_types_nodeType.ENUMERATION,
|
|
76
48
|
transform: (node, props, deepTransformNode) => {
|
|
@@ -95,7 +67,7 @@ const enumerationPlugin = TREE_SHAKE_ENUMERATION ? fallbackPlugin : {
|
|
|
95
67
|
}
|
|
96
68
|
};
|
|
97
69
|
/** Condition plugin. Replaces node with a function that takes boolean => string. */
|
|
98
|
-
const conditionPlugin =
|
|
70
|
+
const conditionPlugin = process.env["INTLAYER_NODE_TYPE_CONDITION"] === "false" ? fallbackPlugin : {
|
|
99
71
|
id: "condition-plugin",
|
|
100
72
|
canHandle: (node) => typeof node === "object" && node?.nodeType === _intlayer_types_nodeType.CONDITION,
|
|
101
73
|
transform: (node, props, deepTransformNode) => {
|
|
@@ -120,7 +92,7 @@ const conditionPlugin = TREE_SHAKE_CONDITION ? fallbackPlugin : {
|
|
|
120
92
|
}
|
|
121
93
|
};
|
|
122
94
|
/** Insertion plugin. Replaces node with a function that takes quantity => string. */
|
|
123
|
-
const insertionPlugin =
|
|
95
|
+
const insertionPlugin = process.env["INTLAYER_NODE_TYPE_INSERTION"] === "false" ? fallbackPlugin : {
|
|
124
96
|
id: "insertion-plugin",
|
|
125
97
|
canHandle: (node) => typeof node === "object" && node?.nodeType === _intlayer_types_nodeType.INSERTION,
|
|
126
98
|
transform: (node, props, deepTransformNode) => {
|
|
@@ -155,7 +127,7 @@ const insertionPlugin = TREE_SHAKE_INSERTION ? fallbackPlugin : {
|
|
|
155
127
|
}
|
|
156
128
|
};
|
|
157
129
|
/** Gender plugin. Replaces node with a function that takes gender => string. */
|
|
158
|
-
const genderPlugin =
|
|
130
|
+
const genderPlugin = process.env["INTLAYER_NODE_TYPE_GENDER"] === "false" ? fallbackPlugin : {
|
|
159
131
|
id: "gender-plugin",
|
|
160
132
|
canHandle: (node) => typeof node === "object" && node?.nodeType === _intlayer_types_nodeType.GENDER,
|
|
161
133
|
transform: (node, props, deepTransformNode) => {
|
|
@@ -176,7 +148,7 @@ const genderPlugin = TREE_SHAKE_GENDER ? fallbackPlugin : {
|
|
|
176
148
|
}
|
|
177
149
|
};
|
|
178
150
|
/** Nested plugin. Replaces node with the result of `getNesting`. */
|
|
179
|
-
const nestedPlugin = (locale) =>
|
|
151
|
+
const nestedPlugin = (locale) => process.env["INTLAYER_NODE_TYPE_NESTED"] === "false" ? fallbackPlugin : {
|
|
180
152
|
id: "nested-plugin",
|
|
181
153
|
canHandle: (node) => typeof node === "object" && (node?.nodeType === _intlayer_types_nodeType.NESTED || node?.nodeType === "n"),
|
|
182
154
|
transform: (node, props) => require_interpreter_getNesting.getNesting(node[_intlayer_types_nodeType.NESTED].dictionaryKey, node[_intlayer_types_nodeType.NESTED].path, {
|
|
@@ -185,7 +157,7 @@ const nestedPlugin = (locale) => TREE_SHAKE_NESTED ? fallbackPlugin : {
|
|
|
185
157
|
})
|
|
186
158
|
};
|
|
187
159
|
/** File plugin. Replaces node with the result of `getNesting`. */
|
|
188
|
-
const filePlugin =
|
|
160
|
+
const filePlugin = process.env["INTLAYER_NODE_TYPE_FILE"] === "false" ? fallbackPlugin : {
|
|
189
161
|
id: "file-plugin",
|
|
190
162
|
canHandle: (node) => typeof node === "object" && node?.nodeType === _intlayer_types_nodeType.FILE,
|
|
191
163
|
transform: (node, props, deepTransform) => deepTransform(node.content, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugins.cjs","names":["NodeTypes","getTranslation","getEnumeration","getCondition","getInsertion","getGender","getNesting"],"sources":["../../../../src/interpreter/getContent/plugins.ts"],"sourcesContent":["import type { Locale } from '@intlayer/types/allLocales';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type {\n DeclaredLocales,\n DictionaryKeys,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type { NodeType } from '@intlayer/types/nodeType';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type {\n ConditionContent,\n EnumerationContent,\n FileContent,\n Gender,\n GenderContent,\n InsertionContent,\n NestedContent,\n TranslationContent,\n} from '../../transpiler';\nimport { getCondition } from '../getCondition';\nimport { getEnumeration } from '../getEnumeration';\nimport { getGender } from '../getGender';\nimport { getInsertion } from '../getInsertion';\nimport { type GetNestingResult, getNesting } from '../getNesting';\nimport { getTranslation } from '../getTranslation';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\n/**\n * True when the translation node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_TRANSLATION =\n process.env['INTLAYER_NODE_TYPE_TRANSLATION'] === 'false';\n\n/**\n * True when the enumeration node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_ENUMERATION =\n process.env['INTLAYER_NODE_TYPE_ENUMERATION'] === 'false';\n\n/**\n * True when the condition node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_CONDITION =\n process.env['INTLAYER_NODE_TYPE_CONDITION'] === 'false';\n\n/**\n * True when the insertion node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_INSERTION =\n process.env['INTLAYER_NODE_TYPE_INSERTION'] === 'false';\n\n/**\n * True when the gender node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_GENDER = process.env['INTLAYER_NODE_TYPE_GENDER'] === 'false';\n\n/**\n * True when the nested node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_NESTED = process.env['INTLAYER_NODE_TYPE_NESTED'] === 'false';\n\n/**\n * True when the file node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_FILE = process.env['INTLAYER_NODE_TYPE_FILE'] === 'false';\n\n/** ---------------------------------------------\n * PLUGIN DEFINITION\n * --------------------------------------------- */\n\n/**\n * A plugin/transformer that can optionally transform a node during a single DFS pass.\n * - `canHandle` decides if the node is transformable by this plugin.\n * - `transform` returns the transformed node (and does not recurse further).\n *\n * > `transformFn` is a function that can be used to deeply transform inside the plugin.\n */\nexport type Plugins = {\n id: string;\n canHandle: (node: any) => boolean;\n transform: (\n node: any,\n props: NodeProps,\n transformFn: (node: any, props: NodeProps) => any\n ) => any;\n};\n\n/** ---------------------------------------------\n * FALLBACK PLUGIN\n *\n * Used to fallback a tree-shaken plugin\n * --------------------------------------------- */\n\nexport const fallbackPlugin: Plugins = {\n id: 'fallback-plugin',\n canHandle: () => false,\n transform: (node) => node,\n};\n\n/** ---------------------------------------------\n * TRANSLATION PLUGIN\n * --------------------------------------------- */\n\nexport type UnionKeys<T> = T extends unknown ? keyof T : never;\nexport type ValueAtKey<T, K> = T extends unknown\n ? K extends keyof T\n ? T[K]\n : never\n : never;\n\nexport type TranslationCond<T, S, L extends LocalesValues> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.TRANSLATION]: infer U;\n}\n ? U extends Record<PropertyKey, unknown>\n ? U[keyof U] extends Record<PropertyKey, unknown>\n ? {\n [K in UnionKeys<U[keyof U]>]: L extends keyof U\n ? K extends keyof U[L]\n ? U[L][K]\n : ValueAtKey<U[keyof U], K>\n : ValueAtKey<U[keyof U], K>;\n } extends infer Content\n ? DeepTransformContent<Content, S>\n : never\n : (L extends keyof U ? U[L] : U[keyof U]) extends infer Content\n ? DeepTransformContent<Content, S>\n : never\n : never\n : never;\n\n/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */\nexport const translationPlugin = (\n locale: LocalesValues,\n fallback?: LocalesValues\n): Plugins =>\n TREE_SHAKE_TRANSLATION\n ? fallbackPlugin\n : {\n id: 'translation-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.TRANSLATION,\n transform: (node: TranslationContent, props, deepTransformNode) => {\n const original = node[NodeTypes.TRANSLATION] ?? {};\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const childProps = {\n ...props,\n children: original[key as keyof typeof original],\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.TRANSLATION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(\n original[key as keyof typeof original],\n childProps\n );\n }\n\n return getTranslation(result, locale, fallback);\n },\n };\n\n/** ---------------------------------------------\n * ENUMERATION PLUGIN\n * --------------------------------------------- */\n\nexport type EnumerationCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.ENUMERATION]: object;\n}\n ? (\n quantity: number\n ) => DeepTransformContent<\n T[typeof NodeTypes.ENUMERATION][keyof T[typeof NodeTypes.ENUMERATION]],\n S\n >\n : never;\n\n/** Enumeration plugin. Replaces node with a function that takes quantity => string. */\nexport const enumerationPlugin: Plugins = TREE_SHAKE_ENUMERATION\n ? fallbackPlugin\n : {\n id: 'enumeration-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.ENUMERATION,\n transform: (node: EnumerationContent, props, deepTransformNode) => {\n const original = node[NodeTypes.ENUMERATION];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as unknown as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.ENUMERATION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (arg: number | { count: number }) => {\n const quantity = typeof arg === 'number' ? arg : arg.count;\n const subResult = getEnumeration(result, quantity);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * CONDITION PLUGIN\n * --------------------------------------------- */\n\nexport type ConditionCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.CONDITION]: object;\n}\n ? (\n value: boolean | { value: boolean }\n ) => DeepTransformContent<\n T[typeof NodeTypes.CONDITION][keyof T[typeof NodeTypes.CONDITION]],\n S\n >\n : never;\n\n/** Condition plugin. Replaces node with a function that takes boolean => string. */\nexport const conditionPlugin: Plugins = TREE_SHAKE_CONDITION\n ? fallbackPlugin\n : {\n id: 'condition-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.CONDITION,\n transform: (node: ConditionContent, props, deepTransformNode) => {\n const original = node[NodeTypes.CONDITION];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.CONDITION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (arg: boolean | { value: boolean }) => {\n const value = typeof arg === 'boolean' ? arg : arg.value;\n const subResult = getCondition(result as any, value);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * INSERTION PLUGIN\n * --------------------------------------------- */\n\nexport type InsertionCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.INSERTION]: infer I;\n fields: readonly string[];\n}\n ? (\n values: {\n [K in T['fields'][number]]: string | number;\n }\n ) => I extends string\n ? DeepTransformContent<string, S>\n : DeepTransformContent<I, S>\n : never;\n\n/** Insertion plugin. Replaces node with a function that takes quantity => string. */\nexport const insertionPlugin: Plugins = TREE_SHAKE_INSERTION\n ? fallbackPlugin\n : {\n id: 'insertion-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.INSERTION,\n transform: (node: InsertionContent, props, deepTransformNode) => {\n const newKeyPath: KeyPath[] = [\n ...props.keyPath,\n {\n type: NodeTypes.INSERTION,\n },\n ];\n\n const children = node[NodeTypes.INSERTION];\n\n /** Insertion string plugin. Replaces string node with a component that render the insertion. */\n const insertionStringPlugin: Plugins = {\n id: 'insertion-string-plugin',\n canHandle: (node) => typeof node === 'string',\n transform: (node: string, subProps, deepTransformNode) => {\n const transformedResult = deepTransformNode(node, {\n ...subProps,\n children: node,\n plugins: [\n ...(props.plugins ?? ([] as Plugins[])).filter(\n (plugin) => plugin.id !== 'intlayer-node-plugin'\n ),\n ],\n });\n\n return (\n values: {\n [K in InsertionContent['fields'][number]]: string | number;\n }\n ) => {\n const children = getInsertion(transformedResult, values);\n\n return deepTransformNode(children, {\n ...subProps,\n plugins: props.plugins,\n children,\n });\n };\n },\n };\n\n return deepTransformNode(children, {\n ...props,\n children,\n keyPath: newKeyPath,\n plugins: [insertionStringPlugin, ...(props.plugins ?? [])],\n });\n },\n };\n\n/** ---------------------------------------------\n * GENDER PLUGIN\n * --------------------------------------------- */\n\nexport type GenderCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.GENDER]: object;\n}\n ? (\n value: Gender\n ) => DeepTransformContent<\n T[typeof NodeTypes.GENDER][keyof T[typeof NodeTypes.GENDER]],\n S\n >\n : never;\n\n/** Gender plugin. Replaces node with a function that takes gender => string. */\nexport const genderPlugin: Plugins = TREE_SHAKE_GENDER\n ? fallbackPlugin\n : {\n id: 'gender-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.GENDER,\n transform: (node: GenderContent, props, deepTransformNode) => {\n const original = node[NodeTypes.GENDER];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.GENDER, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (value: Gender) => getGender(result as any, value);\n },\n };\n\n/** ---------------------------------------------\n * NESTED PLUGIN\n * --------------------------------------------- */\n\nexport type NestedCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.NESTED]: infer U;\n}\n ? U extends {\n dictionaryKey: infer K extends DictionaryKeys;\n path?: infer P;\n }\n ? GetNestingResult<K, P, S>\n : never\n : never;\n\n/** Nested plugin. Replaces node with the result of `getNesting`. */\nexport const nestedPlugin = (locale?: LocalesValues): Plugins =>\n TREE_SHAKE_NESTED\n ? fallbackPlugin\n : {\n id: 'nested-plugin',\n canHandle: (node) =>\n typeof node === 'object' &&\n (node?.nodeType === NodeTypes.NESTED || node?.nodeType === 'n'),\n transform: (node: NestedContent, props) =>\n getNesting(\n node[NodeTypes.NESTED].dictionaryKey,\n node[NodeTypes.NESTED].path,\n {\n ...props,\n locale: (locale ?? props.locale) as Locale,\n }\n ),\n };\n\n/** ---------------------------------------------\n * FILE PLUGIN\n * --------------------------------------------- */\n\nexport type FileCond<T> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.FILE]: string;\n content?: string;\n}\n ? string\n : never;\n\n/** File plugin. Replaces node with the result of `getNesting`. */\nexport const filePlugin: Plugins = TREE_SHAKE_FILE\n ? fallbackPlugin\n : {\n id: 'file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.FILE,\n transform: (node: FileContent, props, deepTransform) =>\n deepTransform(node.content, {\n ...props,\n children: node.content,\n }),\n };\n\n/**\n * PLUGIN RESULT\n */\n\n/**\n * Interface that defines the properties of a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface NodeProps {\n dictionaryKey: string;\n keyPath: KeyPath[];\n plugins?: Plugins[];\n locale?: Locale;\n dictionaryPath?: string;\n children?: any;\n}\n\n/**\n * Interface that defines the plugins that can be used to transform a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface IInterpreterPlugin<T, S, L extends LocalesValues> {\n translation: TranslationCond<T, S, L>;\n enumeration: EnumerationCond<T, S, L>;\n condition: ConditionCond<T, S, L>;\n insertion: InsertionCond<T, S, L>;\n gender: GenderCond<T, S, L>;\n nested: NestedCond<T, S, L>;\n file: FileCond<T>;\n}\n\n/**\n * Allow to avoid overwriting import from `intlayer` package when `IInterpreterPlugin<T>` interface is augmented in another package, such as `react-intlayer`.\n */\nexport type IInterpreterPluginState = {\n translation: true;\n enumeration: true;\n condition: true;\n insertion: true;\n gender: true;\n nested: true;\n file: true;\n};\n\n/**\n * Utility type to check if a plugin can be applied to a node.\n */\ntype CheckApplyPlugin<\n T,\n K extends keyof IInterpreterPlugin<T, S, L>,\n S,\n L extends LocalesValues = DeclaredLocales,\n> = K extends keyof S // Test if the key is a key of S.\n ? // Test if the key of S is true. Then the plugin can be applied.\n S[K] extends true\n ? // Test if the key of S exist\n IInterpreterPlugin<T, S, L>[K] extends never\n ? never\n : // Test if the plugin condition is true (if it's not, the plugin is skipped for this node)\n IInterpreterPlugin<T, S, L>[K]\n : never\n : never;\n\n/**\n * Traverse recursively through an object or array, applying each plugin as needed.\n */\ntype Traverse<T, S, L extends LocalesValues = DeclaredLocales> =\n T extends ReadonlyArray<infer U> // Turn any read-only array into a plain mutable array\n ? Array<DeepTransformContent<U, S, L>>\n : T extends object\n ? { [K in keyof T]: DeepTransformContent<T[K], S, L> }\n : T;\n\nexport type IsAny<T> = 0 extends 1 & T ? true : false;\n\n/**\n * Traverse recursively through an object or array, applying each plugin as needed.\n */\nexport type DeepTransformContent<\n T,\n S = IInterpreterPluginState,\n L extends LocalesValues = DeclaredLocales,\n> =\n IsAny<T> extends true\n ? T\n : CheckApplyPlugin<T, keyof IInterpreterPlugin<T, S, L>, S, L> extends never // Check if there is a plugin for T:\n ? // No plugin was found, so try to transform T recursively:\n Traverse<T, S, L>\n : // A plugin was found – use the plugin's transformation.\n CheckApplyPlugin<T, keyof IInterpreterPlugin<T, S, L>, S, L>;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"plugins.cjs","names":["NodeTypes","getTranslation","getEnumeration","getCondition","getInsertion","getGender","getNesting"],"sources":["../../../../src/interpreter/getContent/plugins.ts"],"sourcesContent":["import type { Locale } from '@intlayer/types/allLocales';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type {\n DeclaredLocales,\n DictionaryKeys,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type { NodeType } from '@intlayer/types/nodeType';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type {\n ConditionContent,\n EnumerationContent,\n FileContent,\n Gender,\n GenderContent,\n InsertionContent,\n NestedContent,\n TranslationContent,\n} from '../../transpiler';\nimport { getCondition } from '../getCondition';\nimport { getEnumeration } from '../getEnumeration';\nimport { getGender } from '../getGender';\nimport { getInsertion } from '../getInsertion';\nimport { type GetNestingResult, getNesting } from '../getNesting';\nimport { getTranslation } from '../getTranslation';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\n/** ---------------------------------------------\n * PLUGIN DEFINITION\n * --------------------------------------------- */\n\n/**\n * A plugin/transformer that can optionally transform a node during a single DFS pass.\n * - `canHandle` decides if the node is transformable by this plugin.\n * - `transform` returns the transformed node (and does not recurse further).\n *\n * > `transformFn` is a function that can be used to deeply transform inside the plugin.\n */\nexport type Plugins = {\n id: string;\n canHandle: (node: any) => boolean;\n transform: (\n node: any,\n props: NodeProps,\n transformFn: (node: any, props: NodeProps) => any\n ) => any;\n};\n\n/** ---------------------------------------------\n * FALLBACK PLUGIN\n *\n * Used to fallback a tree-shaken plugin\n * --------------------------------------------- */\n\nexport const fallbackPlugin: Plugins = {\n id: 'fallback-plugin',\n canHandle: () => false,\n transform: (node) => node,\n};\n\n/** ---------------------------------------------\n * TRANSLATION PLUGIN\n * --------------------------------------------- */\n\nexport type UnionKeys<T> = T extends unknown ? keyof T : never;\nexport type ValueAtKey<T, K> = T extends unknown\n ? K extends keyof T\n ? T[K]\n : never\n : never;\n\nexport type TranslationCond<T, S, L extends LocalesValues> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.TRANSLATION]: infer U;\n}\n ? U extends Record<PropertyKey, unknown>\n ? U[keyof U] extends Record<PropertyKey, unknown>\n ? {\n [K in UnionKeys<U[keyof U]>]: L extends keyof U\n ? K extends keyof U[L]\n ? U[L][K]\n : ValueAtKey<U[keyof U], K>\n : ValueAtKey<U[keyof U], K>;\n } extends infer Content\n ? DeepTransformContent<Content, S>\n : never\n : (L extends keyof U ? U[L] : U[keyof U]) extends infer Content\n ? DeepTransformContent<Content, S>\n : never\n : never\n : never;\n\n/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */\nexport const translationPlugin = (\n locale: LocalesValues,\n fallback?: LocalesValues\n): Plugins =>\n process.env['INTLAYER_NODE_TYPE_TRANSLATION'] === 'false'\n ? fallbackPlugin\n : {\n id: 'translation-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.TRANSLATION,\n transform: (node: TranslationContent, props, deepTransformNode) => {\n const original = node[NodeTypes.TRANSLATION] ?? {};\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const childProps = {\n ...props,\n children: original[key as keyof typeof original],\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.TRANSLATION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(\n original[key as keyof typeof original],\n childProps\n );\n }\n\n return getTranslation(result, locale, fallback);\n },\n };\n\n/** ---------------------------------------------\n * ENUMERATION PLUGIN\n * --------------------------------------------- */\n\nexport type EnumerationCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.ENUMERATION]: object;\n}\n ? (\n quantity: number\n ) => DeepTransformContent<\n T[typeof NodeTypes.ENUMERATION][keyof T[typeof NodeTypes.ENUMERATION]],\n S\n >\n : never;\n\n/** Enumeration plugin. Replaces node with a function that takes quantity => string. */\nexport const enumerationPlugin: Plugins =\n process.env['INTLAYER_NODE_TYPE_ENUMERATION'] === 'false'\n ? fallbackPlugin\n : {\n id: 'enumeration-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.ENUMERATION,\n transform: (node: EnumerationContent, props, deepTransformNode) => {\n const original = node[NodeTypes.ENUMERATION];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as unknown as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.ENUMERATION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (arg: number | { count: number }) => {\n const quantity = typeof arg === 'number' ? arg : arg.count;\n const subResult = getEnumeration(result, quantity);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * CONDITION PLUGIN\n * --------------------------------------------- */\n\nexport type ConditionCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.CONDITION]: object;\n}\n ? (\n value: boolean | { value: boolean }\n ) => DeepTransformContent<\n T[typeof NodeTypes.CONDITION][keyof T[typeof NodeTypes.CONDITION]],\n S\n >\n : never;\n\n/** Condition plugin. Replaces node with a function that takes boolean => string. */\nexport const conditionPlugin: Plugins =\n process.env['INTLAYER_NODE_TYPE_CONDITION'] === 'false'\n ? fallbackPlugin\n : {\n id: 'condition-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.CONDITION,\n transform: (node: ConditionContent, props, deepTransformNode) => {\n const original = node[NodeTypes.CONDITION];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.CONDITION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (arg: boolean | { value: boolean }) => {\n const value = typeof arg === 'boolean' ? arg : arg.value;\n const subResult = getCondition(result as any, value);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * INSERTION PLUGIN\n * --------------------------------------------- */\n\nexport type InsertionCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.INSERTION]: infer I;\n fields: readonly string[];\n}\n ? (\n values: {\n [K in T['fields'][number]]: string | number;\n }\n ) => I extends string\n ? DeepTransformContent<string, S>\n : DeepTransformContent<I, S>\n : never;\n\n/** Insertion plugin. Replaces node with a function that takes quantity => string. */\nexport const insertionPlugin: Plugins =\n process.env['INTLAYER_NODE_TYPE_INSERTION'] === 'false'\n ? fallbackPlugin\n : {\n id: 'insertion-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.INSERTION,\n transform: (node: InsertionContent, props, deepTransformNode) => {\n const newKeyPath: KeyPath[] = [\n ...props.keyPath,\n {\n type: NodeTypes.INSERTION,\n },\n ];\n\n const children = node[NodeTypes.INSERTION];\n\n /** Insertion string plugin. Replaces string node with a component that render the insertion. */\n const insertionStringPlugin: Plugins = {\n id: 'insertion-string-plugin',\n canHandle: (node) => typeof node === 'string',\n transform: (node: string, subProps, deepTransformNode) => {\n const transformedResult = deepTransformNode(node, {\n ...subProps,\n children: node,\n plugins: [\n ...(props.plugins ?? ([] as Plugins[])).filter(\n (plugin) => plugin.id !== 'intlayer-node-plugin'\n ),\n ],\n });\n\n return (\n values: {\n [K in InsertionContent['fields'][number]]: string | number;\n }\n ) => {\n const children = getInsertion(transformedResult, values);\n\n return deepTransformNode(children, {\n ...subProps,\n plugins: props.plugins,\n children,\n });\n };\n },\n };\n\n return deepTransformNode(children, {\n ...props,\n children,\n keyPath: newKeyPath,\n plugins: [insertionStringPlugin, ...(props.plugins ?? [])],\n });\n },\n };\n\n/** ---------------------------------------------\n * GENDER PLUGIN\n * --------------------------------------------- */\n\nexport type GenderCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.GENDER]: object;\n}\n ? (\n value: Gender\n ) => DeepTransformContent<\n T[typeof NodeTypes.GENDER][keyof T[typeof NodeTypes.GENDER]],\n S\n >\n : never;\n\n/** Gender plugin. Replaces node with a function that takes gender => string. */\nexport const genderPlugin: Plugins =\n process.env['INTLAYER_NODE_TYPE_GENDER'] === 'false'\n ? fallbackPlugin\n : {\n id: 'gender-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.GENDER,\n transform: (node: GenderContent, props, deepTransformNode) => {\n const original = node[NodeTypes.GENDER];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.GENDER, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (value: Gender) => getGender(result as any, value);\n },\n };\n\n/** ---------------------------------------------\n * NESTED PLUGIN\n * --------------------------------------------- */\n\nexport type NestedCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.NESTED]: infer U;\n}\n ? U extends {\n dictionaryKey: infer K extends DictionaryKeys;\n path?: infer P;\n }\n ? GetNestingResult<K, P, S>\n : never\n : never;\n\n/** Nested plugin. Replaces node with the result of `getNesting`. */\nexport const nestedPlugin = (locale?: LocalesValues): Plugins =>\n process.env['INTLAYER_NODE_TYPE_NESTED'] === 'false'\n ? fallbackPlugin\n : {\n id: 'nested-plugin',\n canHandle: (node) =>\n typeof node === 'object' &&\n (node?.nodeType === NodeTypes.NESTED || node?.nodeType === 'n'),\n transform: (node: NestedContent, props) =>\n getNesting(\n node[NodeTypes.NESTED].dictionaryKey,\n node[NodeTypes.NESTED].path,\n {\n ...props,\n locale: (locale ?? props.locale) as Locale,\n }\n ),\n };\n\n/** ---------------------------------------------\n * FILE PLUGIN\n * --------------------------------------------- */\n\nexport type FileCond<T> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.FILE]: string;\n content?: string;\n}\n ? string\n : never;\n\n/** File plugin. Replaces node with the result of `getNesting`. */\nexport const filePlugin: Plugins =\n process.env['INTLAYER_NODE_TYPE_FILE'] === 'false'\n ? fallbackPlugin\n : {\n id: 'file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.FILE,\n transform: (node: FileContent, props, deepTransform) =>\n deepTransform(node.content, {\n ...props,\n children: node.content,\n }),\n };\n\n/**\n * PLUGIN RESULT\n */\n\n/**\n * Interface that defines the properties of a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface NodeProps {\n dictionaryKey: string;\n keyPath: KeyPath[];\n plugins?: Plugins[];\n locale?: Locale;\n dictionaryPath?: string;\n children?: any;\n /**\n * Forces eager traversal of plain objects in `deepTransformNode`. By default\n * traversal is lazy (property getters), so callers that discard the returned\n * value never trigger plugins on nested nodes. Set this when running plugins\n * for their side effects only (e.g. missing-locale detection).\n */\n eager?: boolean;\n}\n\n/**\n * Interface that defines the plugins that can be used to transform a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface IInterpreterPlugin<T, S, L extends LocalesValues> {\n translation: TranslationCond<T, S, L>;\n enumeration: EnumerationCond<T, S, L>;\n condition: ConditionCond<T, S, L>;\n insertion: InsertionCond<T, S, L>;\n gender: GenderCond<T, S, L>;\n nested: NestedCond<T, S, L>;\n file: FileCond<T>;\n}\n\n/**\n * Allow to avoid overwriting import from `intlayer` package when `IInterpreterPlugin<T>` interface is augmented in another package, such as `react-intlayer`.\n */\nexport type IInterpreterPluginState = {\n translation: true;\n enumeration: true;\n condition: true;\n insertion: true;\n gender: true;\n nested: true;\n file: true;\n};\n\n/**\n * Utility type to check if a plugin can be applied to a node.\n */\ntype CheckApplyPlugin<\n T,\n K extends keyof IInterpreterPlugin<T, S, L>,\n S,\n L extends LocalesValues = DeclaredLocales,\n> = K extends keyof S // Test if the key is a key of S.\n ? // Test if the key of S is true. Then the plugin can be applied.\n S[K] extends true\n ? // Test if the key of S exist\n IInterpreterPlugin<T, S, L>[K] extends never\n ? never\n : // Test if the plugin condition is true (if it's not, the plugin is skipped for this node)\n IInterpreterPlugin<T, S, L>[K]\n : never\n : never;\n\n/**\n * Traverse recursively through an object or array, applying each plugin as needed.\n */\ntype Traverse<T, S, L extends LocalesValues = DeclaredLocales> =\n T extends ReadonlyArray<infer U> // Turn any read-only array into a plain mutable array\n ? Array<DeepTransformContent<U, S, L>>\n : T extends object\n ? { [K in keyof T]: DeepTransformContent<T[K], S, L> }\n : T;\n\nexport type IsAny<T> = 0 extends 1 & T ? true : false;\n\n/**\n * Traverse recursively through an object or array, applying each plugin as needed.\n */\nexport type DeepTransformContent<\n T,\n S = IInterpreterPluginState,\n L extends LocalesValues = DeclaredLocales,\n> =\n IsAny<T> extends true\n ? T\n : CheckApplyPlugin<T, keyof IInterpreterPlugin<T, S, L>, S, L> extends never // Check if there is a plugin for T:\n ? // No plugin was found, so try to transform T recursively:\n Traverse<T, S, L>\n : // A plugin was found – use the plugin's transformation.\n CheckApplyPlugin<T, keyof IInterpreterPlugin<T, S, L>, S, L>;\n"],"mappings":"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"}
|
|
@@ -7,19 +7,6 @@ const require_localization_rewriteUtils = require('./rewriteUtils.cjs');
|
|
|
7
7
|
let _intlayer_config_built = require("@intlayer/config/built");
|
|
8
8
|
|
|
9
9
|
//#region src/localization/getLocalizedUrl.ts
|
|
10
|
-
/**
|
|
11
|
-
* True when the build-time routing mode is known and is NOT 'no-prefix'.
|
|
12
|
-
*/
|
|
13
|
-
const TREE_SHAKE_NO_PREFIX = process.env["INTLAYER_ROUTING_MODE"] && process.env["INTLAYER_ROUTING_MODE"] !== "no-prefix";
|
|
14
|
-
/**
|
|
15
|
-
* True when the build-time routing mode is known and is NOT 'search-params'.
|
|
16
|
-
*/
|
|
17
|
-
const TREE_SHAKE_SEARCH_PARAMS = process.env["INTLAYER_ROUTING_MODE"] && process.env["INTLAYER_ROUTING_MODE"] !== "search-params";
|
|
18
|
-
/**
|
|
19
|
-
* True when no domain routing is configured at build time
|
|
20
|
-
* (INTLAYER_ROUTING_DOMAINS === 'false').
|
|
21
|
-
*/
|
|
22
|
-
const TREE_SHAKE_DOMAINS = process.env["INTLAYER_ROUTING_DOMAINS"] === "false";
|
|
23
10
|
/** Strips the protocol and returns the bare hostname of a domain string. */
|
|
24
11
|
const extractHostname = (domain) => {
|
|
25
12
|
try {
|
|
@@ -71,16 +58,16 @@ const getLocalizedUrl = (url, currentLocale = _intlayer_config_built.internation
|
|
|
71
58
|
const { defaultLocale, mode, locales, rewrite, domains, currentDomain } = require_localization_getPrefix.resolveRoutingConfig(options);
|
|
72
59
|
const urlWithoutLocale = require_localization_getPathWithoutLocale.getPathWithoutLocale(url, locales);
|
|
73
60
|
const rewriteRules = require_localization_rewriteUtils.getRewriteRules(rewrite, "url");
|
|
74
|
-
if (!
|
|
61
|
+
if (!(process.env["INTLAYER_ROUTING_MODE"] && process.env["INTLAYER_ROUTING_MODE"] !== "no-prefix") && mode === "no-prefix") return require_localization_rewriteUtils.getLocalizedPath(require_localization_rewriteUtils.getCanonicalPath(urlWithoutLocale, void 0, rewriteRules), currentLocale, rewriteRules).path;
|
|
75
62
|
const isAbsoluteUrl = require_utils_checkIsURLAbsolute.checkIsURLAbsolute(urlWithoutLocale);
|
|
76
63
|
const parsedUrl = isAbsoluteUrl ? new URL(urlWithoutLocale) : new URL(urlWithoutLocale, "http://example.com");
|
|
77
64
|
const translatedPathname = require_localization_rewriteUtils.getLocalizedPath(require_localization_rewriteUtils.getCanonicalPath(parsedUrl.pathname, void 0, rewriteRules), currentLocale, rewriteRules).path;
|
|
78
|
-
const detectedCurrentHostname =
|
|
79
|
-
const localeDomain =
|
|
65
|
+
const detectedCurrentHostname = process.env["INTLAYER_ROUTING_DOMAINS"] !== "false" ? extractHostname(currentDomain ?? (isAbsoluteUrl ? parsedUrl.hostname : void 0) ?? (typeof window !== "undefined" ? window?.location?.hostname : void 0) ?? "") || null : null;
|
|
66
|
+
const localeDomain = process.env["INTLAYER_ROUTING_DOMAINS"] !== "false" ? domains?.[currentLocale] : void 0;
|
|
80
67
|
const localeDomainHostname = localeDomain ? extractHostname(localeDomain) : null;
|
|
81
68
|
const normalizedDomain = localeDomainHostname !== null && detectedCurrentHostname !== null && localeDomainHostname !== detectedCurrentHostname && localeDomain ? /^https?:\/\//.test(localeDomain) ? localeDomain : `https://${localeDomain}` : null;
|
|
82
69
|
const baseUrl = normalizedDomain ? normalizedDomain : isAbsoluteUrl ? `${parsedUrl.protocol}//${parsedUrl.host}` : "";
|
|
83
|
-
if (!
|
|
70
|
+
if (!(process.env["INTLAYER_ROUTING_MODE"] && process.env["INTLAYER_ROUTING_MODE"] !== "search-params") && mode === "search-params") {
|
|
84
71
|
const searchParams = new URLSearchParams(parsedUrl.search);
|
|
85
72
|
searchParams.set("locale", currentLocale.toString());
|
|
86
73
|
const queryParams = searchParams.toString();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getLocalizedUrl.cjs","names":["internationalization","resolveRoutingConfig","getPathWithoutLocale","getRewriteRules","getLocalizedPath","getCanonicalPath","checkIsURLAbsolute","getPrefix"],"sources":["../../../src/localization/getLocalizedUrl.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\
|
|
1
|
+
{"version":3,"file":"getLocalizedUrl.cjs","names":["internationalization","resolveRoutingConfig","getPathWithoutLocale","getRewriteRules","getLocalizedPath","getCanonicalPath","checkIsURLAbsolute","getPrefix"],"sources":["../../../src/localization/getLocalizedUrl.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { checkIsURLAbsolute } from '../utils/checkIsURLAbsolute';\nimport { getPathWithoutLocale } from './getPathWithoutLocale';\nimport {\n getPrefix,\n type RoutingOptions,\n resolveRoutingConfig,\n} from './getPrefix';\nimport {\n getCanonicalPath,\n getLocalizedPath,\n getRewriteRules,\n} from './rewriteUtils';\n\nexport type { RoutingOptions };\n\n/** Strips the protocol and returns the bare hostname of a domain string. */\nconst extractHostname = (domain: string): string => {\n try {\n return /^https?:\\/\\//.test(domain) ? new URL(domain).hostname : domain;\n } catch {\n return domain;\n }\n};\n\n/**\n * Generate URL by prefixing the given URL with the referenced locale or adding search parameters\n * based on the routing mode. Handles both absolute and relative URLs appropriately.\n *\n * This function gets the locales, default locale, and routing mode from the configuration if not provided.\n *\n * Example:\n *\n * ```ts\n * // prefix-no-default mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'prefix-no-default' });\n * // Returns '/fr/about' for the French locale\n * // Returns '/about' for the English locale (default)\n *\n * // prefix-all mode\n * getLocalizedUrl('/about', 'en', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'prefix-all' });\n * // Returns '/en/about' for the English locale\n * // Returns '/fr/about' for the French locale\n *\n * // search-params mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'search-params' });\n * // Returns '/about?locale=fr' for the French locale\n *\n * // no-prefix mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'no-prefix' });\n * // Returns '/about' for any locale\n * ```\n *\n * @param url - The original URL string to be processed.\n * @param currentLocale - The current locale.\n * @param options - Configuration options\n * @param options.locales - Optional array of supported locales. Defaults to configured locales.\n * @param options.defaultLocale - The default locale. Defaults to configured default locale.\n * @param options.mode - URL routing mode for locale handling. Defaults to configured mode.\n * @param options.currentDomain - Hostname of the page being rendered. Used to decide\n * whether to emit a relative URL (same domain) or an absolute URL (cross-domain).\n * Auto-detected from the input URL or `window.location` when omitted.\n * @returns The localized URL for the current locale.\n */\nexport const getLocalizedUrl = (\n url: string,\n currentLocale: LocalesValues = internationalization?.defaultLocale,\n options: RoutingOptions = {}\n): string => {\n const { defaultLocale, mode, locales, rewrite, domains, currentDomain } =\n resolveRoutingConfig(options);\n\n const urlWithoutLocale = getPathWithoutLocale(url, locales);\n const rewriteRules = getRewriteRules(rewrite, 'url');\n\n if (\n !(\n process.env['INTLAYER_ROUTING_MODE'] &&\n process.env['INTLAYER_ROUTING_MODE'] !== 'no-prefix'\n ) &&\n mode === 'no-prefix'\n ) {\n return getLocalizedPath(\n getCanonicalPath(urlWithoutLocale, undefined, rewriteRules),\n currentLocale as Locale,\n rewriteRules\n ).path;\n }\n\n const isAbsoluteUrl = checkIsURLAbsolute(urlWithoutLocale);\n const parsedUrl = isAbsoluteUrl\n ? new URL(urlWithoutLocale)\n : new URL(urlWithoutLocale, 'http://example.com');\n\n const translatedPathname = getLocalizedPath(\n getCanonicalPath(parsedUrl.pathname, undefined, rewriteRules),\n currentLocale as Locale,\n rewriteRules\n ).path;\n\n // ── Domain routing ────────────────────────────────────────────────────────\n // Resolve the \"current\" hostname so we can choose between a relative URL\n // (same domain) and an absolute URL (cross-domain).\n //\n // Detection priority:\n // 1. Explicit `currentDomain` option passed by the caller.\n // 2. Hostname extracted from an absolute input URL.\n // 3. `window.location.hostname` in browser environments.\n // When none of these is available we fall back to always generating an\n // absolute URL (the previous behaviour, safe for SSR/static generation).\n const detectedCurrentHostname =\n process.env['INTLAYER_ROUTING_DOMAINS'] !== 'false'\n ? extractHostname(\n currentDomain ??\n (isAbsoluteUrl ? parsedUrl.hostname : undefined) ??\n (typeof window !== 'undefined'\n ? window?.location?.hostname\n : undefined) ??\n ''\n ) || null\n : null;\n\n const localeDomain =\n process.env['INTLAYER_ROUTING_DOMAINS'] !== 'false'\n ? domains?.[currentLocale as LocalesValues]\n : undefined;\n\n const localeDomainHostname = localeDomain\n ? extractHostname(localeDomain)\n : null;\n\n // Only prepend the locale's domain when it differs from the current hostname.\n const isCrossDomain =\n localeDomainHostname !== null &&\n detectedCurrentHostname !== null &&\n localeDomainHostname !== detectedCurrentHostname;\n\n const normalizedDomain =\n isCrossDomain && localeDomain\n ? /^https?:\\/\\//.test(localeDomain)\n ? localeDomain\n : `https://${localeDomain}`\n : null;\n\n const baseUrl = normalizedDomain\n ? normalizedDomain\n : isAbsoluteUrl\n ? `${parsedUrl.protocol}//${parsedUrl.host}`\n : '';\n // ─────────────────────────────────────────────────────────────────────────\n\n if (\n !(\n process.env['INTLAYER_ROUTING_MODE'] &&\n process.env['INTLAYER_ROUTING_MODE'] !== 'search-params'\n ) &&\n mode === 'search-params'\n ) {\n const searchParams = new URLSearchParams(parsedUrl.search);\n\n searchParams.set('locale', currentLocale.toString());\n\n const queryParams = searchParams.toString();\n const path = queryParams\n ? `${translatedPathname}?${queryParams}`\n : translatedPathname;\n\n return `${baseUrl}${path}${parsedUrl.hash}`;\n }\n\n const { prefix } = getPrefix(currentLocale, {\n defaultLocale,\n mode,\n locales,\n domains,\n });\n\n let localizedPath = `/${prefix}${translatedPathname}`.replace(/\\/+/g, '/');\n\n if (localizedPath.length > 1 && localizedPath.endsWith('/')) {\n localizedPath = localizedPath.slice(0, -1);\n }\n\n return `${baseUrl}${localizedPath}${parsedUrl.search}${parsedUrl.hash}`;\n};\n"],"mappings":";;;;;;;;;;AAwBA,MAAM,mBAAmB,WAA2B;AAClD,KAAI;AACF,SAAO,eAAe,KAAK,OAAO,GAAG,IAAI,IAAI,OAAO,CAAC,WAAW;SAC1D;AACN,SAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CX,MAAa,mBACX,KACA,gBAA+BA,6CAAsB,eACrD,UAA0B,EAAE,KACjB;CACX,MAAM,EAAE,eAAe,MAAM,SAAS,SAAS,SAAS,kBACtDC,oDAAqB,QAAQ;CAE/B,MAAM,mBAAmBC,+DAAqB,KAAK,QAAQ;CAC3D,MAAM,eAAeC,kDAAgB,SAAS,MAAM;AAEpD,KACE,EACE,QAAQ,IAAI,4BACZ,QAAQ,IAAI,6BAA6B,gBAE3C,SAAS,YAET,QAAOC,mDACLC,mDAAiB,kBAAkB,QAAW,aAAa,EAC3D,eACA,aACD,CAAC;CAGJ,MAAM,gBAAgBC,oDAAmB,iBAAiB;CAC1D,MAAM,YAAY,gBACd,IAAI,IAAI,iBAAiB,GACzB,IAAI,IAAI,kBAAkB,qBAAqB;CAEnD,MAAM,qBAAqBF,mDACzBC,mDAAiB,UAAU,UAAU,QAAW,aAAa,EAC7D,eACA,aACD,CAAC;CAYF,MAAM,0BACJ,QAAQ,IAAI,gCAAgC,UACxC,gBACE,kBACG,gBAAgB,UAAU,WAAW,YACrC,OAAO,WAAW,cACf,QAAQ,UAAU,WAClB,WACJ,GACH,IAAI,OACL;CAEN,MAAM,eACJ,QAAQ,IAAI,gCAAgC,UACxC,UAAU,iBACV;CAEN,MAAM,uBAAuB,eACzB,gBAAgB,aAAa,GAC7B;CAQJ,MAAM,mBAJJ,yBAAyB,QACzB,4BAA4B,QAC5B,yBAAyB,2BAGR,eACb,eAAe,KAAK,aAAa,GAC/B,eACA,WAAW,iBACb;CAEN,MAAM,UAAU,mBACZ,mBACA,gBACE,GAAG,UAAU,SAAS,IAAI,UAAU,SACpC;AAGN,KACE,EACE,QAAQ,IAAI,4BACZ,QAAQ,IAAI,6BAA6B,oBAE3C,SAAS,iBACT;EACA,MAAM,eAAe,IAAI,gBAAgB,UAAU,OAAO;AAE1D,eAAa,IAAI,UAAU,cAAc,UAAU,CAAC;EAEpD,MAAM,cAAc,aAAa,UAAU;AAK3C,SAAO,GAAG,UAJG,cACT,GAAG,mBAAmB,GAAG,gBACzB,qBAEuB,UAAU;;CAGvC,MAAM,EAAE,WAAWE,yCAAU,eAAe;EAC1C;EACA;EACA;EACA;EACD,CAAC;CAEF,IAAI,gBAAgB,IAAI,SAAS,qBAAqB,QAAQ,QAAQ,IAAI;AAE1E,KAAI,cAAc,SAAS,KAAK,cAAc,SAAS,IAAI,CACzD,iBAAgB,cAAc,MAAM,GAAG,GAAG;AAG5C,QAAO,GAAG,UAAU,gBAAgB,UAAU,SAAS,UAAU"}
|
|
@@ -5,16 +5,6 @@ let _intlayer_config_defaultValues = require("@intlayer/config/defaultValues");
|
|
|
5
5
|
|
|
6
6
|
//#region src/localization/getPrefix.ts
|
|
7
7
|
/**
|
|
8
|
-
* True when the build-time routing mode is known and is not a prefix-based
|
|
9
|
-
* mode (neither 'prefix-all' nor 'prefix-no-default').
|
|
10
|
-
*/
|
|
11
|
-
const TREE_SHAKE_PREFIX_MODES = process.env["INTLAYER_ROUTING_MODE"] && process.env["INTLAYER_ROUTING_MODE"] !== "prefix-all" && process.env["INTLAYER_ROUTING_MODE"] !== "prefix-no-default";
|
|
12
|
-
/**
|
|
13
|
-
* True when no domain routing is configured at build time
|
|
14
|
-
* (INTLAYER_ROUTING_DOMAINS === 'false').
|
|
15
|
-
*/
|
|
16
|
-
const TREE_SHAKE_DOMAINS = process.env["INTLAYER_ROUTING_DOMAINS"] === "false";
|
|
17
|
-
/**
|
|
18
8
|
* Resolves routing configuration by merging provided options with configuration defaults.
|
|
19
9
|
* Single source of truth for default routing config resolution across all localization functions.
|
|
20
10
|
*/
|
|
@@ -61,11 +51,11 @@ const resolveRoutingConfig = (options = {}) => ({
|
|
|
61
51
|
*/
|
|
62
52
|
const getPrefix = (locale, options = {}) => {
|
|
63
53
|
const { defaultLocale, mode, locales, domains } = resolveRoutingConfig(options);
|
|
64
|
-
if (
|
|
54
|
+
if (process.env["INTLAYER_ROUTING_MODE"] && process.env["INTLAYER_ROUTING_MODE"] !== "prefix-all" && process.env["INTLAYER_ROUTING_MODE"] !== "prefix-no-default" || !locale || !locales.includes(locale)) return {
|
|
65
55
|
prefix: "",
|
|
66
56
|
localePrefix: void 0
|
|
67
57
|
};
|
|
68
|
-
if (
|
|
58
|
+
if (process.env["INTLAYER_ROUTING_DOMAINS"] !== "false" && domains) {
|
|
69
59
|
const localeDomain = domains[locale];
|
|
70
60
|
if (localeDomain) {
|
|
71
61
|
if (Object.values(domains).filter((domain) => domain === localeDomain).length === 1) return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getPrefix.cjs","names":["internationalization","DEFAULT_LOCALE","routing","ROUTING_MODE","LOCALES"],"sources":["../../../src/localization/getPrefix.ts"],"sourcesContent":["import { internationalization, routing } from '@intlayer/config/built';\nimport {\n DEFAULT_LOCALE,\n LOCALES,\n ROUTING_MODE,\n} from '@intlayer/config/defaultValues';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\
|
|
1
|
+
{"version":3,"file":"getPrefix.cjs","names":["internationalization","DEFAULT_LOCALE","routing","ROUTING_MODE","LOCALES"],"sources":["../../../src/localization/getPrefix.ts"],"sourcesContent":["import { internationalization, routing } from '@intlayer/config/built';\nimport {\n DEFAULT_LOCALE,\n LOCALES,\n ROUTING_MODE,\n} from '@intlayer/config/defaultValues';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { RoutingConfig } from '@intlayer/types/config';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\n\n/**\n * Shared routing options used across all URL localization functions.\n */\nexport type RoutingOptions = {\n locales?: LocalesValues[];\n defaultLocale?: LocalesValues;\n mode?: RoutingConfig['mode'];\n rewrite?: RoutingConfig['rewrite'];\n domains?: RoutingConfig['domains'];\n /**\n * The hostname of the page currently being rendered (e.g. `'intlayer.org'`).\n * When provided, `getLocalizedUrl` returns a relative URL for locales whose\n * configured domain matches `currentDomain`, and an absolute URL only when\n * the target locale lives on a different domain.\n *\n * When omitted the function tries to infer it from:\n * 1. The domain of an absolute input URL.\n * 2. `window.location.hostname` in browser environments.\n * Falls back to always generating absolute URLs when neither is available.\n */\n currentDomain?: string;\n};\n\n/**\n * Resolves routing configuration by merging provided options with configuration defaults.\n * Single source of truth for default routing config resolution across all localization functions.\n */\nexport const resolveRoutingConfig = (options: RoutingOptions = {}) => ({\n defaultLocale: internationalization?.defaultLocale ?? DEFAULT_LOCALE,\n mode: routing?.mode ?? ROUTING_MODE,\n locales: internationalization?.locales ?? LOCALES,\n rewrite: routing?.rewrite,\n domains: routing?.domains,\n ...options,\n});\n\nexport type GetPrefixOptions = {\n defaultLocale?: LocalesValues;\n mode?: RoutingConfig['mode'];\n};\n\nexport type GetPrefixResult = {\n /**\n * The complete base URL path with leading and trailing slashes.\n *\n * @example\n * // https://example.com/fr/about -> '/fr'\n * // https://example.com/about -> ''\n */\n prefix: string;\n /**\n * The locale identifier without slashes.\n *\n * @example\n * // https://example.com/fr/about -> 'fr'\n * // https://example.com/about -> undefined\n */\n localePrefix: Locale | undefined;\n};\n\n/**\n * Determines the URL prefix for a given locale based on the routing mode configuration.\n *\n * Example:\n *\n * ```ts\n * // prefix-no-default mode with default locale\n * getPrefix('en', { defaultLocale: 'en', mode: 'prefix-no-default' })\n * // Returns { prefix: '', localePrefix: undefined }\n *\n * // prefix-no-default mode with non-default locale\n * getPrefix('fr', { defaultLocale: 'en', mode: 'prefix-no-default' })\n * // Returns { prefix: '/fr', localePrefix: 'fr' }\n *\n * // prefix-all mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'prefix-all' })\n * // Returns { prefix: '/en', localePrefix: locale }\n *\n * // search-params mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'search-params' })\n * // Returns { prefix: '', localePrefix: undefined }\n *\n * // no-prefix mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'no-prefix' })\n * // Returns { prefix: '', localePrefix: undefined }\n * ```\n *\n * @param locale - The locale to check for prefix. If not provided, uses configured default locale.\n * @param options - Configuration options\n * @param options.defaultLocale - The default locale. Defaults to configured default locale.\n * @param options.mode - URL routing mode for locale handling. Defaults to configured mode.\n * @returns An object containing pathPrefix, prefix, and localePrefix for the given locale.\n */\nexport const getPrefix = (\n locale: LocalesValues | undefined,\n options: RoutingOptions = {}\n): GetPrefixResult => {\n const { defaultLocale, mode, locales, domains } =\n resolveRoutingConfig(options);\n\n if (\n (process.env['INTLAYER_ROUTING_MODE'] &&\n process.env['INTLAYER_ROUTING_MODE'] !== 'prefix-all' &&\n process.env['INTLAYER_ROUTING_MODE'] !== 'prefix-no-default') ||\n !locale ||\n !locales.includes(locale)\n ) {\n return {\n prefix: '',\n localePrefix: undefined,\n };\n }\n\n // If this locale is the only one assigned to its domain, no URL prefix is needed\n // (the domain itself identifies the locale). Shared domains use normal prefix logic.\n if (process.env['INTLAYER_ROUTING_DOMAINS'] !== 'false' && domains) {\n const localeDomain = domains[locale as LocalesValues];\n\n if (localeDomain) {\n const localesOnSameDomain = Object.values(domains).filter(\n (domain) => domain === localeDomain\n ).length;\n\n if (localesOnSameDomain === 1) {\n return {\n prefix: '',\n localePrefix: undefined,\n };\n }\n }\n }\n\n // Handle prefix-based modes (prefix-all or prefix-no-default)\n const shouldPrefix =\n mode === 'prefix-all' ||\n (mode === 'prefix-no-default' && defaultLocale !== locale);\n\n if (shouldPrefix) {\n return {\n prefix: `${locale}/`,\n localePrefix: locale as Locale,\n };\n }\n\n return {\n prefix: '',\n localePrefix: undefined,\n };\n};\n"],"mappings":";;;;;;;;;;AA0CA,MAAa,wBAAwB,UAA0B,EAAE,MAAM;CACrE,eAAeA,6CAAsB,iBAAiBC;CACtD,MAAMC,gCAAS,QAAQC;CACvB,SAASH,6CAAsB,WAAWI;CAC1C,SAASF,gCAAS;CAClB,SAASA,gCAAS;CAClB,GAAG;CACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2DD,MAAa,aACX,QACA,UAA0B,EAAE,KACR;CACpB,MAAM,EAAE,eAAe,MAAM,SAAS,YACpC,qBAAqB,QAAQ;AAE/B,KACG,QAAQ,IAAI,4BACX,QAAQ,IAAI,6BAA6B,gBACzC,QAAQ,IAAI,6BAA6B,uBAC3C,CAAC,UACD,CAAC,QAAQ,SAAS,OAAO,CAEzB,QAAO;EACL,QAAQ;EACR,cAAc;EACf;AAKH,KAAI,QAAQ,IAAI,gCAAgC,WAAW,SAAS;EAClE,MAAM,eAAe,QAAQ;AAE7B,MAAI,cAKF;OAJ4B,OAAO,OAAO,QAAQ,CAAC,QAChD,WAAW,WAAW,aACxB,CAAC,WAE0B,EAC1B,QAAO;IACL,QAAQ;IACR,cAAc;IACf;;;AAUP,KAHE,SAAS,gBACR,SAAS,uBAAuB,kBAAkB,OAGnD,QAAO;EACL,QAAQ,GAAG,OAAO;EAClB,cAAc;EACf;AAGH,QAAO;EACL,QAAQ;EACR,cAAc;EACf"}
|
|
@@ -132,7 +132,8 @@ const getMissingLocalesContent = (node, locales = internationalization?.locales,
|
|
|
132
132
|
const plugins = [checkMissingLocalesPlugin(locales, (locale) => missingLocales.add(locale)), ...nodeProps.plugins ?? []];
|
|
133
133
|
deepTransformNode(node, {
|
|
134
134
|
...nodeProps,
|
|
135
|
-
plugins
|
|
135
|
+
plugins,
|
|
136
|
+
eager: true
|
|
136
137
|
});
|
|
137
138
|
return Array.from(missingLocales);
|
|
138
139
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getMissingLocalesContent.mjs","names":[],"sources":["../../../src/deepTransformPlugins/getMissingLocalesContent.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { ContentNode, Dictionary } from '@intlayer/types/dictionary';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type { DeepTransformContent, NodeProps, Plugins } from '../interpreter';\nimport { deepTransformNode } from '../interpreter/getContent/deepTransform';\nimport type { TranslationContent } from '../transpiler';\n\n/**\n * Returns all key paths present in obj, INCLUDING those whose leaf value is null.\n * Used for structural presence checks (a locale must have every key another locale has,\n * even if the value is a null placeholder).\n */\nconst getAllKeyPaths = (obj: any, prefix: string[] = []): string[][] => {\n if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {\n return [];\n }\n\n return Object.keys(obj).flatMap((key) => {\n const newPath = [...prefix, key];\n const value = obj[key];\n // Stop recursing into null — include the path but don't descend further\n if (value === null) {\n return [newPath];\n }\n return [newPath, ...getAllKeyPaths(value, newPath)];\n });\n};\n\n/**\n * Returns key paths whose leaf value is non-null.\n * Used for translation value checks (a locale must not have null where another locale\n * already has a real translated value).\n */\nconst getNonNullKeyPaths = (obj: any, prefix: string[] = []): string[][] => {\n if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {\n return [];\n }\n\n return Object.keys(obj).flatMap((key) => {\n const newPath = [...prefix, key];\n const value = obj[key];\n // Skip null-valued keys entirely\n if (value === null) {\n return [];\n }\n return [newPath, ...getNonNullKeyPaths(value, newPath)];\n });\n};\n\n/**\n * Returns true if the key path EXISTS in obj (even if the terminal value is null).\n * Used for the structural presence check.\n */\nconst hasKey = (obj: any, keyPath: string[]): boolean => {\n let current = obj;\n for (const key of keyPath) {\n if (\n current === undefined ||\n current === null ||\n typeof current !== 'object'\n ) {\n return false;\n }\n if (!(key in current)) {\n return false;\n }\n current = current[key];\n }\n return true; // key exists; value may be null\n};\n\n/**\n * Returns true if the key path exists in obj AND the terminal value is non-null.\n * Used for the translation value check.\n */\nconst hasNonNullValue = (obj: any, keyPath: string[]): boolean => {\n let current = obj;\n for (const key of keyPath) {\n if (\n current === undefined ||\n current === null ||\n typeof current !== 'object'\n ) {\n return false;\n }\n if (!(key in current)) {\n return false;\n }\n current = current[key];\n }\n // null is treated as a missing translation (e.g., i18next-scanner sets null for untranslated keys)\n return current !== null;\n};\n\n/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */\nexport const checkMissingLocalesPlugin = (\n locales: Locale[],\n onMissingLocale: (locale: Locale) => void\n): Plugins => ({\n id: 'check-missing-locales-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.TRANSLATION,\n transform: (node: TranslationContent, props, deepTransformNode) => {\n const translations = node[NodeTypes.TRANSLATION] as Record<string, any>;\n\n /**\n * Two path sets built from all locales' content:\n *\n * presentPaths — every key path that exists in ANY locale, even those whose value\n * is null. A locale that is missing a path from this set is structurally incomplete\n * (the key doesn't exist at all).\n *\n * nonNullPaths — every key path that has a non-null value in at least one locale.\n * A locale that has the key but with null, when another locale already has a real\n * value, needs translation.\n */\n const presentPaths = new Set<string>();\n const nonNullPaths = new Set<string>();\n\n for (const locale of locales) {\n const value = translations[locale];\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n getAllKeyPaths(value).forEach((path) => {\n presentPaths.add(JSON.stringify(path));\n });\n\n getNonNullKeyPaths(value).forEach((path) => {\n nonNullPaths.add(JSON.stringify(path));\n });\n }\n }\n\n // If no locale has any content at all (all are null/undefined), the key is\n // universally pending — don't flag anyone.\n const hasAnyDefinedValue = locales.some(\n (locale) =>\n translations[locale] !== undefined && translations[locale] !== null\n );\n\n for (const locale of locales) {\n const value = translations[locale];\n\n if (value === null) {\n // Entire locale content is a null placeholder.\n // Flag only when some other locale already has real content.\n if (hasAnyDefinedValue) {\n onMissingLocale(locale);\n }\n continue;\n }\n\n if (!value) {\n // undefined / entirely absent\n onMissingLocale(locale);\n continue;\n }\n\n let flagged = false;\n\n // Structural check: every key that exists in any locale must also exist here\n // (even if the local value is null — at least the key must be present).\n for (const pathStr of presentPaths) {\n if (!hasKey(value, JSON.parse(pathStr))) {\n onMissingLocale(locale);\n flagged = true;\n break;\n }\n }\n\n if (!flagged) {\n // Value check: every key that has a non-null value in some locale must also\n // be non-null here (null = untranslated, needs filling).\n for (const pathStr of nonNullPaths) {\n if (!hasNonNullValue(value, JSON.parse(pathStr))) {\n onMissingLocale(locale);\n break;\n }\n }\n }\n }\n\n // Continue traversal inside the translation values\n for (const key in translations) {\n const child = translations[key];\n deepTransformNode(child, {\n ...props,\n children: child,\n });\n }\n\n // Return the original node; the return value is ignored by the caller\n return node;\n },\n});\n\n/**\n * Return the content of a node with only the translation plugin.\n *\n * @param node The node to transform.\n * @param locales The locales to check for missing translations.\n */\nexport const getMissingLocalesContent = <T extends ContentNode>(\n node: T,\n locales: LocalesValues[] = internationalization?.locales,\n\n nodeProps: NodeProps\n): Locale[] => {\n const missingLocales = new Set<Locale>();\n\n const plugins: Plugins[] = [\n checkMissingLocalesPlugin(locales as Locale[], (locale) =>\n missingLocales.add(locale)\n ),\n ...(nodeProps.plugins ?? []),\n ];\n\n deepTransformNode(node, {\n ...nodeProps,\n plugins,\n }) as DeepTransformContent<T>;\n\n return Array.from(missingLocales);\n};\n\nexport const getMissingLocalesContentFromDictionary = (\n dictionary: Dictionary,\n locales: LocalesValues[] = internationalization?.locales\n) =>\n getMissingLocalesContent(dictionary.content, locales, {\n dictionaryKey: dictionary.key,\n keyPath: [],\n });\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"getMissingLocalesContent.mjs","names":[],"sources":["../../../src/deepTransformPlugins/getMissingLocalesContent.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { ContentNode, Dictionary } from '@intlayer/types/dictionary';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type { DeepTransformContent, NodeProps, Plugins } from '../interpreter';\nimport { deepTransformNode } from '../interpreter/getContent/deepTransform';\nimport type { TranslationContent } from '../transpiler';\n\n/**\n * Returns all key paths present in obj, INCLUDING those whose leaf value is null.\n * Used for structural presence checks (a locale must have every key another locale has,\n * even if the value is a null placeholder).\n */\nconst getAllKeyPaths = (obj: any, prefix: string[] = []): string[][] => {\n if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {\n return [];\n }\n\n return Object.keys(obj).flatMap((key) => {\n const newPath = [...prefix, key];\n const value = obj[key];\n // Stop recursing into null — include the path but don't descend further\n if (value === null) {\n return [newPath];\n }\n return [newPath, ...getAllKeyPaths(value, newPath)];\n });\n};\n\n/**\n * Returns key paths whose leaf value is non-null.\n * Used for translation value checks (a locale must not have null where another locale\n * already has a real translated value).\n */\nconst getNonNullKeyPaths = (obj: any, prefix: string[] = []): string[][] => {\n if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {\n return [];\n }\n\n return Object.keys(obj).flatMap((key) => {\n const newPath = [...prefix, key];\n const value = obj[key];\n // Skip null-valued keys entirely\n if (value === null) {\n return [];\n }\n return [newPath, ...getNonNullKeyPaths(value, newPath)];\n });\n};\n\n/**\n * Returns true if the key path EXISTS in obj (even if the terminal value is null).\n * Used for the structural presence check.\n */\nconst hasKey = (obj: any, keyPath: string[]): boolean => {\n let current = obj;\n for (const key of keyPath) {\n if (\n current === undefined ||\n current === null ||\n typeof current !== 'object'\n ) {\n return false;\n }\n if (!(key in current)) {\n return false;\n }\n current = current[key];\n }\n return true; // key exists; value may be null\n};\n\n/**\n * Returns true if the key path exists in obj AND the terminal value is non-null.\n * Used for the translation value check.\n */\nconst hasNonNullValue = (obj: any, keyPath: string[]): boolean => {\n let current = obj;\n for (const key of keyPath) {\n if (\n current === undefined ||\n current === null ||\n typeof current !== 'object'\n ) {\n return false;\n }\n if (!(key in current)) {\n return false;\n }\n current = current[key];\n }\n // null is treated as a missing translation (e.g., i18next-scanner sets null for untranslated keys)\n return current !== null;\n};\n\n/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */\nexport const checkMissingLocalesPlugin = (\n locales: Locale[],\n onMissingLocale: (locale: Locale) => void\n): Plugins => ({\n id: 'check-missing-locales-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.TRANSLATION,\n transform: (node: TranslationContent, props, deepTransformNode) => {\n const translations = node[NodeTypes.TRANSLATION] as Record<string, any>;\n\n /**\n * Two path sets built from all locales' content:\n *\n * presentPaths — every key path that exists in ANY locale, even those whose value\n * is null. A locale that is missing a path from this set is structurally incomplete\n * (the key doesn't exist at all).\n *\n * nonNullPaths — every key path that has a non-null value in at least one locale.\n * A locale that has the key but with null, when another locale already has a real\n * value, needs translation.\n */\n const presentPaths = new Set<string>();\n const nonNullPaths = new Set<string>();\n\n for (const locale of locales) {\n const value = translations[locale];\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n getAllKeyPaths(value).forEach((path) => {\n presentPaths.add(JSON.stringify(path));\n });\n\n getNonNullKeyPaths(value).forEach((path) => {\n nonNullPaths.add(JSON.stringify(path));\n });\n }\n }\n\n // If no locale has any content at all (all are null/undefined), the key is\n // universally pending — don't flag anyone.\n const hasAnyDefinedValue = locales.some(\n (locale) =>\n translations[locale] !== undefined && translations[locale] !== null\n );\n\n for (const locale of locales) {\n const value = translations[locale];\n\n if (value === null) {\n // Entire locale content is a null placeholder.\n // Flag only when some other locale already has real content.\n if (hasAnyDefinedValue) {\n onMissingLocale(locale);\n }\n continue;\n }\n\n if (!value) {\n // undefined / entirely absent\n onMissingLocale(locale);\n continue;\n }\n\n let flagged = false;\n\n // Structural check: every key that exists in any locale must also exist here\n // (even if the local value is null — at least the key must be present).\n for (const pathStr of presentPaths) {\n if (!hasKey(value, JSON.parse(pathStr))) {\n onMissingLocale(locale);\n flagged = true;\n break;\n }\n }\n\n if (!flagged) {\n // Value check: every key that has a non-null value in some locale must also\n // be non-null here (null = untranslated, needs filling).\n for (const pathStr of nonNullPaths) {\n if (!hasNonNullValue(value, JSON.parse(pathStr))) {\n onMissingLocale(locale);\n break;\n }\n }\n }\n }\n\n // Continue traversal inside the translation values\n for (const key in translations) {\n const child = translations[key];\n deepTransformNode(child, {\n ...props,\n children: child,\n });\n }\n\n // Return the original node; the return value is ignored by the caller\n return node;\n },\n});\n\n/**\n * Return the content of a node with only the translation plugin.\n *\n * @param node The node to transform.\n * @param locales The locales to check for missing translations.\n */\nexport const getMissingLocalesContent = <T extends ContentNode>(\n node: T,\n locales: LocalesValues[] = internationalization?.locales,\n\n nodeProps: NodeProps\n): Locale[] => {\n const missingLocales = new Set<Locale>();\n\n const plugins: Plugins[] = [\n checkMissingLocalesPlugin(locales as Locale[], (locale) =>\n missingLocales.add(locale)\n ),\n ...(nodeProps.plugins ?? []),\n ];\n\n // eager: traversal of plain objects must run immediately. Without it the\n // returned tree is a proxy of lazy getters; we discard the tree, so nested\n // translation nodes inside plain objects (the typical dictionary shape) are\n // never visited and their missing locales go undetected.\n deepTransformNode(node, {\n ...nodeProps,\n plugins,\n eager: true,\n }) as DeepTransformContent<T>;\n\n return Array.from(missingLocales);\n};\n\nexport const getMissingLocalesContentFromDictionary = (\n dictionary: Dictionary,\n locales: LocalesValues[] = internationalization?.locales\n) =>\n getMissingLocalesContent(dictionary.content, locales, {\n dictionaryKey: dictionary.key,\n keyPath: [],\n });\n"],"mappings":"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"}
|
|
@@ -21,27 +21,33 @@ const deepTransformNode = (node, props) => {
|
|
|
21
21
|
});
|
|
22
22
|
});
|
|
23
23
|
const result = {};
|
|
24
|
-
for (const key in node)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const transformed = deepTransformNode(node[key], childProps);
|
|
37
|
-
Object.defineProperty(this, key, {
|
|
38
|
-
value: transformed,
|
|
39
|
-
enumerable: true,
|
|
40
|
-
configurable: true
|
|
41
|
-
});
|
|
42
|
-
return transformed;
|
|
24
|
+
for (const key in node) {
|
|
25
|
+
const childProps = {
|
|
26
|
+
...props,
|
|
27
|
+
children: node[key],
|
|
28
|
+
keyPath: [...props.keyPath, {
|
|
29
|
+
type: NodeTypes.OBJECT,
|
|
30
|
+
key
|
|
31
|
+
}]
|
|
32
|
+
};
|
|
33
|
+
if (props.eager) {
|
|
34
|
+
result[key] = deepTransformNode(node[key], childProps);
|
|
35
|
+
continue;
|
|
43
36
|
}
|
|
44
|
-
|
|
37
|
+
Object.defineProperty(result, key, {
|
|
38
|
+
enumerable: true,
|
|
39
|
+
configurable: true,
|
|
40
|
+
get: function() {
|
|
41
|
+
const transformed = deepTransformNode(node[key], childProps);
|
|
42
|
+
Object.defineProperty(this, key, {
|
|
43
|
+
value: transformed,
|
|
44
|
+
enumerable: true,
|
|
45
|
+
configurable: true
|
|
46
|
+
});
|
|
47
|
+
return transformed;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
45
51
|
return result;
|
|
46
52
|
};
|
|
47
53
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deepTransform.mjs","names":[],"sources":["../../../../src/interpreter/getContent/deepTransform.ts"],"sourcesContent":["import type { KeyPath } from '@intlayer/types/keyPath';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type { NodeProps } from './plugins';\n\n/**\n * Recursively traverses a node (object/array/primitive).\n * Applies the *first* plugin that can transform a node, then stops descending further.\n * If no plugin transforms it, it recurses into its children.\n */\nexport const deepTransformNode = (node: any, props: NodeProps): any => {\n // Otherwise, if it's an object, check if any plugin can handle it:\n for (const plugin of props.plugins ?? []) {\n if (plugin.canHandle(node)) {\n // Return the transformed node => do NOT recurse further\n return plugin.transform(node, props, (node: any, props: any) =>\n deepTransformNode(node, props)\n );\n }\n }\n\n // If it's null/undefined or not an object, just return it directly:\n if (node === null || typeof node !== 'object') {\n return node;\n }\n\n // If it's a framework-specific virtual node or already a transformed Proxy,\n // return it directly to avoid re-transforming its internal properties.\n if (\n (node as any).$$typeof !== undefined ||\n (node as any).__v_isVNode !== undefined ||\n (node as any)._isVNode !== undefined ||\n (node as any).isJSX !== undefined ||\n typeof node === 'function' // Proxies for html/markdown are functions\n ) {\n return node;\n }\n\n // If it's an array, transform each element:\n if (Array.isArray(node)) {\n return node.map((child, index) => {\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.ARRAY, key: index } as KeyPath,\n ],\n };\n return deepTransformNode(child, childProps);\n });\n }\n\n // If no plugin transforms it, we keep traversing its properties.\n const result: Record<string, any> = {};\n for (const key in node) {\n
|
|
1
|
+
{"version":3,"file":"deepTransform.mjs","names":[],"sources":["../../../../src/interpreter/getContent/deepTransform.ts"],"sourcesContent":["import type { KeyPath } from '@intlayer/types/keyPath';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type { NodeProps } from './plugins';\n\n/**\n * Recursively traverses a node (object/array/primitive).\n * Applies the *first* plugin that can transform a node, then stops descending further.\n * If no plugin transforms it, it recurses into its children.\n */\nexport const deepTransformNode = (node: any, props: NodeProps): any => {\n // Otherwise, if it's an object, check if any plugin can handle it:\n for (const plugin of props.plugins ?? []) {\n if (plugin.canHandle(node)) {\n // Return the transformed node => do NOT recurse further\n return plugin.transform(node, props, (node: any, props: any) =>\n deepTransformNode(node, props)\n );\n }\n }\n\n // If it's null/undefined or not an object, just return it directly:\n if (node === null || typeof node !== 'object') {\n return node;\n }\n\n // If it's a framework-specific virtual node or already a transformed Proxy,\n // return it directly to avoid re-transforming its internal properties.\n if (\n (node as any).$$typeof !== undefined ||\n (node as any).__v_isVNode !== undefined ||\n (node as any)._isVNode !== undefined ||\n (node as any).isJSX !== undefined ||\n typeof node === 'function' // Proxies for html/markdown are functions\n ) {\n return node;\n }\n\n // If it's an array, transform each element:\n if (Array.isArray(node)) {\n return node.map((child, index) => {\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.ARRAY, key: index } as KeyPath,\n ],\n };\n return deepTransformNode(child, childProps);\n });\n }\n\n // If no plugin transforms it, we keep traversing its properties.\n const result: Record<string, any> = {};\n for (const key in node) {\n const childProps = {\n ...props,\n children: node[key],\n keyPath: [...props.keyPath, { type: NodeTypes.OBJECT, key } as KeyPath],\n };\n\n if (props.eager) {\n // Eager mode: recurse immediately so plugins fire on every node, even\n // when the caller discards the returned tree (e.g. side-effect-only\n // plugins like missing-locale detection).\n result[key] = deepTransformNode(node[key], childProps);\n continue;\n }\n\n Object.defineProperty(result, key, {\n enumerable: true,\n configurable: true,\n get: function () {\n const transformed = deepTransformNode(node[key], childProps);\n\n // Memoize the result onto the property to avoid re-calculating on next read\n Object.defineProperty(this, key, {\n value: transformed,\n enumerable: true,\n configurable: true,\n });\n return transformed;\n },\n });\n }\n\n return result;\n};\n"],"mappings":";;;;;;;;AASA,MAAa,qBAAqB,MAAW,UAA0B;AAErE,MAAK,MAAM,UAAU,MAAM,WAAW,EAAE,CACtC,KAAI,OAAO,UAAU,KAAK,CAExB,QAAO,OAAO,UAAU,MAAM,QAAQ,MAAW,UAC/C,kBAAkB,MAAM,MAAM,CAC/B;AAKL,KAAI,SAAS,QAAQ,OAAO,SAAS,SACnC,QAAO;AAKT,KACG,KAAa,aAAa,UAC1B,KAAa,gBAAgB,UAC7B,KAAa,aAAa,UAC1B,KAAa,UAAU,UACxB,OAAO,SAAS,WAEhB,QAAO;AAIT,KAAI,MAAM,QAAQ,KAAK,CACrB,QAAO,KAAK,KAAK,OAAO,UAAU;AAShC,SAAO,kBAAkB,OAAO;GAP9B,GAAG;GACH,UAAU;GACV,SAAS,CACP,GAAG,MAAM,SACT;IAAE,MAAM,UAAU;IAAO,KAAK;IAAO,CACtC;GAEuC,CAAC;GAC3C;CAIJ,MAAM,SAA8B,EAAE;AACtC,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,aAAa;GACjB,GAAG;GACH,UAAU,KAAK;GACf,SAAS,CAAC,GAAG,MAAM,SAAS;IAAE,MAAM,UAAU;IAAQ;IAAK,CAAY;GACxE;AAED,MAAI,MAAM,OAAO;AAIf,UAAO,OAAO,kBAAkB,KAAK,MAAM,WAAW;AACtD;;AAGF,SAAO,eAAe,QAAQ,KAAK;GACjC,YAAY;GACZ,cAAc;GACd,KAAK,WAAY;IACf,MAAM,cAAc,kBAAkB,KAAK,MAAM,WAAW;AAG5D,WAAO,eAAe,MAAM,KAAK;KAC/B,OAAO;KACP,YAAY;KACZ,cAAc;KACf,CAAC;AACF,WAAO;;GAEV,CAAC;;AAGJ,QAAO"}
|
|
@@ -7,34 +7,6 @@ import { getTranslation } from "../getTranslation.mjs";
|
|
|
7
7
|
import * as NodeTypes from "@intlayer/types/nodeType";
|
|
8
8
|
|
|
9
9
|
//#region src/interpreter/getContent/plugins.ts
|
|
10
|
-
/**
|
|
11
|
-
* True when the translation node type is explicitly disabled at build time.
|
|
12
|
-
*/
|
|
13
|
-
const TREE_SHAKE_TRANSLATION = process.env["INTLAYER_NODE_TYPE_TRANSLATION"] === "false";
|
|
14
|
-
/**
|
|
15
|
-
* True when the enumeration node type is explicitly disabled at build time.
|
|
16
|
-
*/
|
|
17
|
-
const TREE_SHAKE_ENUMERATION = process.env["INTLAYER_NODE_TYPE_ENUMERATION"] === "false";
|
|
18
|
-
/**
|
|
19
|
-
* True when the condition node type is explicitly disabled at build time.
|
|
20
|
-
*/
|
|
21
|
-
const TREE_SHAKE_CONDITION = process.env["INTLAYER_NODE_TYPE_CONDITION"] === "false";
|
|
22
|
-
/**
|
|
23
|
-
* True when the insertion node type is explicitly disabled at build time.
|
|
24
|
-
*/
|
|
25
|
-
const TREE_SHAKE_INSERTION = process.env["INTLAYER_NODE_TYPE_INSERTION"] === "false";
|
|
26
|
-
/**
|
|
27
|
-
* True when the gender node type is explicitly disabled at build time.
|
|
28
|
-
*/
|
|
29
|
-
const TREE_SHAKE_GENDER = process.env["INTLAYER_NODE_TYPE_GENDER"] === "false";
|
|
30
|
-
/**
|
|
31
|
-
* True when the nested node type is explicitly disabled at build time.
|
|
32
|
-
*/
|
|
33
|
-
const TREE_SHAKE_NESTED = process.env["INTLAYER_NODE_TYPE_NESTED"] === "false";
|
|
34
|
-
/**
|
|
35
|
-
* True when the file node type is explicitly disabled at build time.
|
|
36
|
-
*/
|
|
37
|
-
const TREE_SHAKE_FILE = process.env["INTLAYER_NODE_TYPE_FILE"] === "false";
|
|
38
10
|
/** ---------------------------------------------
|
|
39
11
|
* FALLBACK PLUGIN
|
|
40
12
|
*
|
|
@@ -46,7 +18,7 @@ const fallbackPlugin = {
|
|
|
46
18
|
transform: (node) => node
|
|
47
19
|
};
|
|
48
20
|
/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */
|
|
49
|
-
const translationPlugin = (locale, fallback) =>
|
|
21
|
+
const translationPlugin = (locale, fallback) => process.env["INTLAYER_NODE_TYPE_TRANSLATION"] === "false" ? fallbackPlugin : {
|
|
50
22
|
id: "translation-plugin",
|
|
51
23
|
canHandle: (node) => typeof node === "object" && node?.nodeType === NodeTypes.TRANSLATION,
|
|
52
24
|
transform: (node, props, deepTransformNode) => {
|
|
@@ -67,7 +39,7 @@ const translationPlugin = (locale, fallback) => TREE_SHAKE_TRANSLATION ? fallbac
|
|
|
67
39
|
}
|
|
68
40
|
};
|
|
69
41
|
/** Enumeration plugin. Replaces node with a function that takes quantity => string. */
|
|
70
|
-
const enumerationPlugin =
|
|
42
|
+
const enumerationPlugin = process.env["INTLAYER_NODE_TYPE_ENUMERATION"] === "false" ? fallbackPlugin : {
|
|
71
43
|
id: "enumeration-plugin",
|
|
72
44
|
canHandle: (node) => typeof node === "object" && node?.nodeType === NodeTypes.ENUMERATION,
|
|
73
45
|
transform: (node, props, deepTransformNode) => {
|
|
@@ -92,7 +64,7 @@ const enumerationPlugin = TREE_SHAKE_ENUMERATION ? fallbackPlugin : {
|
|
|
92
64
|
}
|
|
93
65
|
};
|
|
94
66
|
/** Condition plugin. Replaces node with a function that takes boolean => string. */
|
|
95
|
-
const conditionPlugin =
|
|
67
|
+
const conditionPlugin = process.env["INTLAYER_NODE_TYPE_CONDITION"] === "false" ? fallbackPlugin : {
|
|
96
68
|
id: "condition-plugin",
|
|
97
69
|
canHandle: (node) => typeof node === "object" && node?.nodeType === NodeTypes.CONDITION,
|
|
98
70
|
transform: (node, props, deepTransformNode) => {
|
|
@@ -117,7 +89,7 @@ const conditionPlugin = TREE_SHAKE_CONDITION ? fallbackPlugin : {
|
|
|
117
89
|
}
|
|
118
90
|
};
|
|
119
91
|
/** Insertion plugin. Replaces node with a function that takes quantity => string. */
|
|
120
|
-
const insertionPlugin =
|
|
92
|
+
const insertionPlugin = process.env["INTLAYER_NODE_TYPE_INSERTION"] === "false" ? fallbackPlugin : {
|
|
121
93
|
id: "insertion-plugin",
|
|
122
94
|
canHandle: (node) => typeof node === "object" && node?.nodeType === NodeTypes.INSERTION,
|
|
123
95
|
transform: (node, props, deepTransformNode) => {
|
|
@@ -152,7 +124,7 @@ const insertionPlugin = TREE_SHAKE_INSERTION ? fallbackPlugin : {
|
|
|
152
124
|
}
|
|
153
125
|
};
|
|
154
126
|
/** Gender plugin. Replaces node with a function that takes gender => string. */
|
|
155
|
-
const genderPlugin =
|
|
127
|
+
const genderPlugin = process.env["INTLAYER_NODE_TYPE_GENDER"] === "false" ? fallbackPlugin : {
|
|
156
128
|
id: "gender-plugin",
|
|
157
129
|
canHandle: (node) => typeof node === "object" && node?.nodeType === NodeTypes.GENDER,
|
|
158
130
|
transform: (node, props, deepTransformNode) => {
|
|
@@ -173,7 +145,7 @@ const genderPlugin = TREE_SHAKE_GENDER ? fallbackPlugin : {
|
|
|
173
145
|
}
|
|
174
146
|
};
|
|
175
147
|
/** Nested plugin. Replaces node with the result of `getNesting`. */
|
|
176
|
-
const nestedPlugin = (locale) =>
|
|
148
|
+
const nestedPlugin = (locale) => process.env["INTLAYER_NODE_TYPE_NESTED"] === "false" ? fallbackPlugin : {
|
|
177
149
|
id: "nested-plugin",
|
|
178
150
|
canHandle: (node) => typeof node === "object" && (node?.nodeType === NodeTypes.NESTED || node?.nodeType === "n"),
|
|
179
151
|
transform: (node, props) => getNesting(node[NodeTypes.NESTED].dictionaryKey, node[NodeTypes.NESTED].path, {
|
|
@@ -182,7 +154,7 @@ const nestedPlugin = (locale) => TREE_SHAKE_NESTED ? fallbackPlugin : {
|
|
|
182
154
|
})
|
|
183
155
|
};
|
|
184
156
|
/** File plugin. Replaces node with the result of `getNesting`. */
|
|
185
|
-
const filePlugin =
|
|
157
|
+
const filePlugin = process.env["INTLAYER_NODE_TYPE_FILE"] === "false" ? fallbackPlugin : {
|
|
186
158
|
id: "file-plugin",
|
|
187
159
|
canHandle: (node) => typeof node === "object" && node?.nodeType === NodeTypes.FILE,
|
|
188
160
|
transform: (node, props, deepTransform) => deepTransform(node.content, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugins.mjs","names":[],"sources":["../../../../src/interpreter/getContent/plugins.ts"],"sourcesContent":["import type { Locale } from '@intlayer/types/allLocales';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type {\n DeclaredLocales,\n DictionaryKeys,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type { NodeType } from '@intlayer/types/nodeType';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type {\n ConditionContent,\n EnumerationContent,\n FileContent,\n Gender,\n GenderContent,\n InsertionContent,\n NestedContent,\n TranslationContent,\n} from '../../transpiler';\nimport { getCondition } from '../getCondition';\nimport { getEnumeration } from '../getEnumeration';\nimport { getGender } from '../getGender';\nimport { getInsertion } from '../getInsertion';\nimport { type GetNestingResult, getNesting } from '../getNesting';\nimport { getTranslation } from '../getTranslation';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\n/**\n * True when the translation node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_TRANSLATION =\n process.env['INTLAYER_NODE_TYPE_TRANSLATION'] === 'false';\n\n/**\n * True when the enumeration node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_ENUMERATION =\n process.env['INTLAYER_NODE_TYPE_ENUMERATION'] === 'false';\n\n/**\n * True when the condition node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_CONDITION =\n process.env['INTLAYER_NODE_TYPE_CONDITION'] === 'false';\n\n/**\n * True when the insertion node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_INSERTION =\n process.env['INTLAYER_NODE_TYPE_INSERTION'] === 'false';\n\n/**\n * True when the gender node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_GENDER = process.env['INTLAYER_NODE_TYPE_GENDER'] === 'false';\n\n/**\n * True when the nested node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_NESTED = process.env['INTLAYER_NODE_TYPE_NESTED'] === 'false';\n\n/**\n * True when the file node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_FILE = process.env['INTLAYER_NODE_TYPE_FILE'] === 'false';\n\n/** ---------------------------------------------\n * PLUGIN DEFINITION\n * --------------------------------------------- */\n\n/**\n * A plugin/transformer that can optionally transform a node during a single DFS pass.\n * - `canHandle` decides if the node is transformable by this plugin.\n * - `transform` returns the transformed node (and does not recurse further).\n *\n * > `transformFn` is a function that can be used to deeply transform inside the plugin.\n */\nexport type Plugins = {\n id: string;\n canHandle: (node: any) => boolean;\n transform: (\n node: any,\n props: NodeProps,\n transformFn: (node: any, props: NodeProps) => any\n ) => any;\n};\n\n/** ---------------------------------------------\n * FALLBACK PLUGIN\n *\n * Used to fallback a tree-shaken plugin\n * --------------------------------------------- */\n\nexport const fallbackPlugin: Plugins = {\n id: 'fallback-plugin',\n canHandle: () => false,\n transform: (node) => node,\n};\n\n/** ---------------------------------------------\n * TRANSLATION PLUGIN\n * --------------------------------------------- */\n\nexport type UnionKeys<T> = T extends unknown ? keyof T : never;\nexport type ValueAtKey<T, K> = T extends unknown\n ? K extends keyof T\n ? T[K]\n : never\n : never;\n\nexport type TranslationCond<T, S, L extends LocalesValues> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.TRANSLATION]: infer U;\n}\n ? U extends Record<PropertyKey, unknown>\n ? U[keyof U] extends Record<PropertyKey, unknown>\n ? {\n [K in UnionKeys<U[keyof U]>]: L extends keyof U\n ? K extends keyof U[L]\n ? U[L][K]\n : ValueAtKey<U[keyof U], K>\n : ValueAtKey<U[keyof U], K>;\n } extends infer Content\n ? DeepTransformContent<Content, S>\n : never\n : (L extends keyof U ? U[L] : U[keyof U]) extends infer Content\n ? DeepTransformContent<Content, S>\n : never\n : never\n : never;\n\n/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */\nexport const translationPlugin = (\n locale: LocalesValues,\n fallback?: LocalesValues\n): Plugins =>\n TREE_SHAKE_TRANSLATION\n ? fallbackPlugin\n : {\n id: 'translation-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.TRANSLATION,\n transform: (node: TranslationContent, props, deepTransformNode) => {\n const original = node[NodeTypes.TRANSLATION] ?? {};\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const childProps = {\n ...props,\n children: original[key as keyof typeof original],\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.TRANSLATION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(\n original[key as keyof typeof original],\n childProps\n );\n }\n\n return getTranslation(result, locale, fallback);\n },\n };\n\n/** ---------------------------------------------\n * ENUMERATION PLUGIN\n * --------------------------------------------- */\n\nexport type EnumerationCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.ENUMERATION]: object;\n}\n ? (\n quantity: number\n ) => DeepTransformContent<\n T[typeof NodeTypes.ENUMERATION][keyof T[typeof NodeTypes.ENUMERATION]],\n S\n >\n : never;\n\n/** Enumeration plugin. Replaces node with a function that takes quantity => string. */\nexport const enumerationPlugin: Plugins = TREE_SHAKE_ENUMERATION\n ? fallbackPlugin\n : {\n id: 'enumeration-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.ENUMERATION,\n transform: (node: EnumerationContent, props, deepTransformNode) => {\n const original = node[NodeTypes.ENUMERATION];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as unknown as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.ENUMERATION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (arg: number | { count: number }) => {\n const quantity = typeof arg === 'number' ? arg : arg.count;\n const subResult = getEnumeration(result, quantity);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * CONDITION PLUGIN\n * --------------------------------------------- */\n\nexport type ConditionCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.CONDITION]: object;\n}\n ? (\n value: boolean | { value: boolean }\n ) => DeepTransformContent<\n T[typeof NodeTypes.CONDITION][keyof T[typeof NodeTypes.CONDITION]],\n S\n >\n : never;\n\n/** Condition plugin. Replaces node with a function that takes boolean => string. */\nexport const conditionPlugin: Plugins = TREE_SHAKE_CONDITION\n ? fallbackPlugin\n : {\n id: 'condition-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.CONDITION,\n transform: (node: ConditionContent, props, deepTransformNode) => {\n const original = node[NodeTypes.CONDITION];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.CONDITION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (arg: boolean | { value: boolean }) => {\n const value = typeof arg === 'boolean' ? arg : arg.value;\n const subResult = getCondition(result as any, value);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * INSERTION PLUGIN\n * --------------------------------------------- */\n\nexport type InsertionCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.INSERTION]: infer I;\n fields: readonly string[];\n}\n ? (\n values: {\n [K in T['fields'][number]]: string | number;\n }\n ) => I extends string\n ? DeepTransformContent<string, S>\n : DeepTransformContent<I, S>\n : never;\n\n/** Insertion plugin. Replaces node with a function that takes quantity => string. */\nexport const insertionPlugin: Plugins = TREE_SHAKE_INSERTION\n ? fallbackPlugin\n : {\n id: 'insertion-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.INSERTION,\n transform: (node: InsertionContent, props, deepTransformNode) => {\n const newKeyPath: KeyPath[] = [\n ...props.keyPath,\n {\n type: NodeTypes.INSERTION,\n },\n ];\n\n const children = node[NodeTypes.INSERTION];\n\n /** Insertion string plugin. Replaces string node with a component that render the insertion. */\n const insertionStringPlugin: Plugins = {\n id: 'insertion-string-plugin',\n canHandle: (node) => typeof node === 'string',\n transform: (node: string, subProps, deepTransformNode) => {\n const transformedResult = deepTransformNode(node, {\n ...subProps,\n children: node,\n plugins: [\n ...(props.plugins ?? ([] as Plugins[])).filter(\n (plugin) => plugin.id !== 'intlayer-node-plugin'\n ),\n ],\n });\n\n return (\n values: {\n [K in InsertionContent['fields'][number]]: string | number;\n }\n ) => {\n const children = getInsertion(transformedResult, values);\n\n return deepTransformNode(children, {\n ...subProps,\n plugins: props.plugins,\n children,\n });\n };\n },\n };\n\n return deepTransformNode(children, {\n ...props,\n children,\n keyPath: newKeyPath,\n plugins: [insertionStringPlugin, ...(props.plugins ?? [])],\n });\n },\n };\n\n/** ---------------------------------------------\n * GENDER PLUGIN\n * --------------------------------------------- */\n\nexport type GenderCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.GENDER]: object;\n}\n ? (\n value: Gender\n ) => DeepTransformContent<\n T[typeof NodeTypes.GENDER][keyof T[typeof NodeTypes.GENDER]],\n S\n >\n : never;\n\n/** Gender plugin. Replaces node with a function that takes gender => string. */\nexport const genderPlugin: Plugins = TREE_SHAKE_GENDER\n ? fallbackPlugin\n : {\n id: 'gender-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.GENDER,\n transform: (node: GenderContent, props, deepTransformNode) => {\n const original = node[NodeTypes.GENDER];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.GENDER, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (value: Gender) => getGender(result as any, value);\n },\n };\n\n/** ---------------------------------------------\n * NESTED PLUGIN\n * --------------------------------------------- */\n\nexport type NestedCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.NESTED]: infer U;\n}\n ? U extends {\n dictionaryKey: infer K extends DictionaryKeys;\n path?: infer P;\n }\n ? GetNestingResult<K, P, S>\n : never\n : never;\n\n/** Nested plugin. Replaces node with the result of `getNesting`. */\nexport const nestedPlugin = (locale?: LocalesValues): Plugins =>\n TREE_SHAKE_NESTED\n ? fallbackPlugin\n : {\n id: 'nested-plugin',\n canHandle: (node) =>\n typeof node === 'object' &&\n (node?.nodeType === NodeTypes.NESTED || node?.nodeType === 'n'),\n transform: (node: NestedContent, props) =>\n getNesting(\n node[NodeTypes.NESTED].dictionaryKey,\n node[NodeTypes.NESTED].path,\n {\n ...props,\n locale: (locale ?? props.locale) as Locale,\n }\n ),\n };\n\n/** ---------------------------------------------\n * FILE PLUGIN\n * --------------------------------------------- */\n\nexport type FileCond<T> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.FILE]: string;\n content?: string;\n}\n ? string\n : never;\n\n/** File plugin. Replaces node with the result of `getNesting`. */\nexport const filePlugin: Plugins = TREE_SHAKE_FILE\n ? fallbackPlugin\n : {\n id: 'file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.FILE,\n transform: (node: FileContent, props, deepTransform) =>\n deepTransform(node.content, {\n ...props,\n children: node.content,\n }),\n };\n\n/**\n * PLUGIN RESULT\n */\n\n/**\n * Interface that defines the properties of a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface NodeProps {\n dictionaryKey: string;\n keyPath: KeyPath[];\n plugins?: Plugins[];\n locale?: Locale;\n dictionaryPath?: string;\n children?: any;\n}\n\n/**\n * Interface that defines the plugins that can be used to transform a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface IInterpreterPlugin<T, S, L extends LocalesValues> {\n translation: TranslationCond<T, S, L>;\n enumeration: EnumerationCond<T, S, L>;\n condition: ConditionCond<T, S, L>;\n insertion: InsertionCond<T, S, L>;\n gender: GenderCond<T, S, L>;\n nested: NestedCond<T, S, L>;\n file: FileCond<T>;\n}\n\n/**\n * Allow to avoid overwriting import from `intlayer` package when `IInterpreterPlugin<T>` interface is augmented in another package, such as `react-intlayer`.\n */\nexport type IInterpreterPluginState = {\n translation: true;\n enumeration: true;\n condition: true;\n insertion: true;\n gender: true;\n nested: true;\n file: true;\n};\n\n/**\n * Utility type to check if a plugin can be applied to a node.\n */\ntype CheckApplyPlugin<\n T,\n K extends keyof IInterpreterPlugin<T, S, L>,\n S,\n L extends LocalesValues = DeclaredLocales,\n> = K extends keyof S // Test if the key is a key of S.\n ? // Test if the key of S is true. Then the plugin can be applied.\n S[K] extends true\n ? // Test if the key of S exist\n IInterpreterPlugin<T, S, L>[K] extends never\n ? never\n : // Test if the plugin condition is true (if it's not, the plugin is skipped for this node)\n IInterpreterPlugin<T, S, L>[K]\n : never\n : never;\n\n/**\n * Traverse recursively through an object or array, applying each plugin as needed.\n */\ntype Traverse<T, S, L extends LocalesValues = DeclaredLocales> =\n T extends ReadonlyArray<infer U> // Turn any read-only array into a plain mutable array\n ? Array<DeepTransformContent<U, S, L>>\n : T extends object\n ? { [K in keyof T]: DeepTransformContent<T[K], S, L> }\n : T;\n\nexport type IsAny<T> = 0 extends 1 & T ? true : false;\n\n/**\n * Traverse recursively through an object or array, applying each plugin as needed.\n */\nexport type DeepTransformContent<\n T,\n S = IInterpreterPluginState,\n L extends LocalesValues = DeclaredLocales,\n> =\n IsAny<T> extends true\n ? T\n : CheckApplyPlugin<T, keyof IInterpreterPlugin<T, S, L>, S, L> extends never // Check if there is a plugin for T:\n ? // No plugin was found, so try to transform T recursively:\n Traverse<T, S, L>\n : // A plugin was found – use the plugin's transformation.\n CheckApplyPlugin<T, keyof IInterpreterPlugin<T, S, L>, S, L>;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"plugins.mjs","names":[],"sources":["../../../../src/interpreter/getContent/plugins.ts"],"sourcesContent":["import type { Locale } from '@intlayer/types/allLocales';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type {\n DeclaredLocales,\n DictionaryKeys,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type { NodeType } from '@intlayer/types/nodeType';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type {\n ConditionContent,\n EnumerationContent,\n FileContent,\n Gender,\n GenderContent,\n InsertionContent,\n NestedContent,\n TranslationContent,\n} from '../../transpiler';\nimport { getCondition } from '../getCondition';\nimport { getEnumeration } from '../getEnumeration';\nimport { getGender } from '../getGender';\nimport { getInsertion } from '../getInsertion';\nimport { type GetNestingResult, getNesting } from '../getNesting';\nimport { getTranslation } from '../getTranslation';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\n/** ---------------------------------------------\n * PLUGIN DEFINITION\n * --------------------------------------------- */\n\n/**\n * A plugin/transformer that can optionally transform a node during a single DFS pass.\n * - `canHandle` decides if the node is transformable by this plugin.\n * - `transform` returns the transformed node (and does not recurse further).\n *\n * > `transformFn` is a function that can be used to deeply transform inside the plugin.\n */\nexport type Plugins = {\n id: string;\n canHandle: (node: any) => boolean;\n transform: (\n node: any,\n props: NodeProps,\n transformFn: (node: any, props: NodeProps) => any\n ) => any;\n};\n\n/** ---------------------------------------------\n * FALLBACK PLUGIN\n *\n * Used to fallback a tree-shaken plugin\n * --------------------------------------------- */\n\nexport const fallbackPlugin: Plugins = {\n id: 'fallback-plugin',\n canHandle: () => false,\n transform: (node) => node,\n};\n\n/** ---------------------------------------------\n * TRANSLATION PLUGIN\n * --------------------------------------------- */\n\nexport type UnionKeys<T> = T extends unknown ? keyof T : never;\nexport type ValueAtKey<T, K> = T extends unknown\n ? K extends keyof T\n ? T[K]\n : never\n : never;\n\nexport type TranslationCond<T, S, L extends LocalesValues> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.TRANSLATION]: infer U;\n}\n ? U extends Record<PropertyKey, unknown>\n ? U[keyof U] extends Record<PropertyKey, unknown>\n ? {\n [K in UnionKeys<U[keyof U]>]: L extends keyof U\n ? K extends keyof U[L]\n ? U[L][K]\n : ValueAtKey<U[keyof U], K>\n : ValueAtKey<U[keyof U], K>;\n } extends infer Content\n ? DeepTransformContent<Content, S>\n : never\n : (L extends keyof U ? U[L] : U[keyof U]) extends infer Content\n ? DeepTransformContent<Content, S>\n : never\n : never\n : never;\n\n/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */\nexport const translationPlugin = (\n locale: LocalesValues,\n fallback?: LocalesValues\n): Plugins =>\n process.env['INTLAYER_NODE_TYPE_TRANSLATION'] === 'false'\n ? fallbackPlugin\n : {\n id: 'translation-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.TRANSLATION,\n transform: (node: TranslationContent, props, deepTransformNode) => {\n const original = node[NodeTypes.TRANSLATION] ?? {};\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const childProps = {\n ...props,\n children: original[key as keyof typeof original],\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.TRANSLATION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(\n original[key as keyof typeof original],\n childProps\n );\n }\n\n return getTranslation(result, locale, fallback);\n },\n };\n\n/** ---------------------------------------------\n * ENUMERATION PLUGIN\n * --------------------------------------------- */\n\nexport type EnumerationCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.ENUMERATION]: object;\n}\n ? (\n quantity: number\n ) => DeepTransformContent<\n T[typeof NodeTypes.ENUMERATION][keyof T[typeof NodeTypes.ENUMERATION]],\n S\n >\n : never;\n\n/** Enumeration plugin. Replaces node with a function that takes quantity => string. */\nexport const enumerationPlugin: Plugins =\n process.env['INTLAYER_NODE_TYPE_ENUMERATION'] === 'false'\n ? fallbackPlugin\n : {\n id: 'enumeration-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.ENUMERATION,\n transform: (node: EnumerationContent, props, deepTransformNode) => {\n const original = node[NodeTypes.ENUMERATION];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as unknown as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.ENUMERATION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (arg: number | { count: number }) => {\n const quantity = typeof arg === 'number' ? arg : arg.count;\n const subResult = getEnumeration(result, quantity);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * CONDITION PLUGIN\n * --------------------------------------------- */\n\nexport type ConditionCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.CONDITION]: object;\n}\n ? (\n value: boolean | { value: boolean }\n ) => DeepTransformContent<\n T[typeof NodeTypes.CONDITION][keyof T[typeof NodeTypes.CONDITION]],\n S\n >\n : never;\n\n/** Condition plugin. Replaces node with a function that takes boolean => string. */\nexport const conditionPlugin: Plugins =\n process.env['INTLAYER_NODE_TYPE_CONDITION'] === 'false'\n ? fallbackPlugin\n : {\n id: 'condition-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.CONDITION,\n transform: (node: ConditionContent, props, deepTransformNode) => {\n const original = node[NodeTypes.CONDITION];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.CONDITION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (arg: boolean | { value: boolean }) => {\n const value = typeof arg === 'boolean' ? arg : arg.value;\n const subResult = getCondition(result as any, value);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * INSERTION PLUGIN\n * --------------------------------------------- */\n\nexport type InsertionCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.INSERTION]: infer I;\n fields: readonly string[];\n}\n ? (\n values: {\n [K in T['fields'][number]]: string | number;\n }\n ) => I extends string\n ? DeepTransformContent<string, S>\n : DeepTransformContent<I, S>\n : never;\n\n/** Insertion plugin. Replaces node with a function that takes quantity => string. */\nexport const insertionPlugin: Plugins =\n process.env['INTLAYER_NODE_TYPE_INSERTION'] === 'false'\n ? fallbackPlugin\n : {\n id: 'insertion-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.INSERTION,\n transform: (node: InsertionContent, props, deepTransformNode) => {\n const newKeyPath: KeyPath[] = [\n ...props.keyPath,\n {\n type: NodeTypes.INSERTION,\n },\n ];\n\n const children = node[NodeTypes.INSERTION];\n\n /** Insertion string plugin. Replaces string node with a component that render the insertion. */\n const insertionStringPlugin: Plugins = {\n id: 'insertion-string-plugin',\n canHandle: (node) => typeof node === 'string',\n transform: (node: string, subProps, deepTransformNode) => {\n const transformedResult = deepTransformNode(node, {\n ...subProps,\n children: node,\n plugins: [\n ...(props.plugins ?? ([] as Plugins[])).filter(\n (plugin) => plugin.id !== 'intlayer-node-plugin'\n ),\n ],\n });\n\n return (\n values: {\n [K in InsertionContent['fields'][number]]: string | number;\n }\n ) => {\n const children = getInsertion(transformedResult, values);\n\n return deepTransformNode(children, {\n ...subProps,\n plugins: props.plugins,\n children,\n });\n };\n },\n };\n\n return deepTransformNode(children, {\n ...props,\n children,\n keyPath: newKeyPath,\n plugins: [insertionStringPlugin, ...(props.plugins ?? [])],\n });\n },\n };\n\n/** ---------------------------------------------\n * GENDER PLUGIN\n * --------------------------------------------- */\n\nexport type GenderCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.GENDER]: object;\n}\n ? (\n value: Gender\n ) => DeepTransformContent<\n T[typeof NodeTypes.GENDER][keyof T[typeof NodeTypes.GENDER]],\n S\n >\n : never;\n\n/** Gender plugin. Replaces node with a function that takes gender => string. */\nexport const genderPlugin: Plugins =\n process.env['INTLAYER_NODE_TYPE_GENDER'] === 'false'\n ? fallbackPlugin\n : {\n id: 'gender-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.GENDER,\n transform: (node: GenderContent, props, deepTransformNode) => {\n const original = node[NodeTypes.GENDER];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.GENDER, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (value: Gender) => getGender(result as any, value);\n },\n };\n\n/** ---------------------------------------------\n * NESTED PLUGIN\n * --------------------------------------------- */\n\nexport type NestedCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.NESTED]: infer U;\n}\n ? U extends {\n dictionaryKey: infer K extends DictionaryKeys;\n path?: infer P;\n }\n ? GetNestingResult<K, P, S>\n : never\n : never;\n\n/** Nested plugin. Replaces node with the result of `getNesting`. */\nexport const nestedPlugin = (locale?: LocalesValues): Plugins =>\n process.env['INTLAYER_NODE_TYPE_NESTED'] === 'false'\n ? fallbackPlugin\n : {\n id: 'nested-plugin',\n canHandle: (node) =>\n typeof node === 'object' &&\n (node?.nodeType === NodeTypes.NESTED || node?.nodeType === 'n'),\n transform: (node: NestedContent, props) =>\n getNesting(\n node[NodeTypes.NESTED].dictionaryKey,\n node[NodeTypes.NESTED].path,\n {\n ...props,\n locale: (locale ?? props.locale) as Locale,\n }\n ),\n };\n\n/** ---------------------------------------------\n * FILE PLUGIN\n * --------------------------------------------- */\n\nexport type FileCond<T> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.FILE]: string;\n content?: string;\n}\n ? string\n : never;\n\n/** File plugin. Replaces node with the result of `getNesting`. */\nexport const filePlugin: Plugins =\n process.env['INTLAYER_NODE_TYPE_FILE'] === 'false'\n ? fallbackPlugin\n : {\n id: 'file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.FILE,\n transform: (node: FileContent, props, deepTransform) =>\n deepTransform(node.content, {\n ...props,\n children: node.content,\n }),\n };\n\n/**\n * PLUGIN RESULT\n */\n\n/**\n * Interface that defines the properties of a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface NodeProps {\n dictionaryKey: string;\n keyPath: KeyPath[];\n plugins?: Plugins[];\n locale?: Locale;\n dictionaryPath?: string;\n children?: any;\n /**\n * Forces eager traversal of plain objects in `deepTransformNode`. By default\n * traversal is lazy (property getters), so callers that discard the returned\n * value never trigger plugins on nested nodes. Set this when running plugins\n * for their side effects only (e.g. missing-locale detection).\n */\n eager?: boolean;\n}\n\n/**\n * Interface that defines the plugins that can be used to transform a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface IInterpreterPlugin<T, S, L extends LocalesValues> {\n translation: TranslationCond<T, S, L>;\n enumeration: EnumerationCond<T, S, L>;\n condition: ConditionCond<T, S, L>;\n insertion: InsertionCond<T, S, L>;\n gender: GenderCond<T, S, L>;\n nested: NestedCond<T, S, L>;\n file: FileCond<T>;\n}\n\n/**\n * Allow to avoid overwriting import from `intlayer` package when `IInterpreterPlugin<T>` interface is augmented in another package, such as `react-intlayer`.\n */\nexport type IInterpreterPluginState = {\n translation: true;\n enumeration: true;\n condition: true;\n insertion: true;\n gender: true;\n nested: true;\n file: true;\n};\n\n/**\n * Utility type to check if a plugin can be applied to a node.\n */\ntype CheckApplyPlugin<\n T,\n K extends keyof IInterpreterPlugin<T, S, L>,\n S,\n L extends LocalesValues = DeclaredLocales,\n> = K extends keyof S // Test if the key is a key of S.\n ? // Test if the key of S is true. Then the plugin can be applied.\n S[K] extends true\n ? // Test if the key of S exist\n IInterpreterPlugin<T, S, L>[K] extends never\n ? never\n : // Test if the plugin condition is true (if it's not, the plugin is skipped for this node)\n IInterpreterPlugin<T, S, L>[K]\n : never\n : never;\n\n/**\n * Traverse recursively through an object or array, applying each plugin as needed.\n */\ntype Traverse<T, S, L extends LocalesValues = DeclaredLocales> =\n T extends ReadonlyArray<infer U> // Turn any read-only array into a plain mutable array\n ? Array<DeepTransformContent<U, S, L>>\n : T extends object\n ? { [K in keyof T]: DeepTransformContent<T[K], S, L> }\n : T;\n\nexport type IsAny<T> = 0 extends 1 & T ? true : false;\n\n/**\n * Traverse recursively through an object or array, applying each plugin as needed.\n */\nexport type DeepTransformContent<\n T,\n S = IInterpreterPluginState,\n L extends LocalesValues = DeclaredLocales,\n> =\n IsAny<T> extends true\n ? T\n : CheckApplyPlugin<T, keyof IInterpreterPlugin<T, S, L>, S, L> extends never // Check if there is a plugin for T:\n ? // No plugin was found, so try to transform T recursively:\n Traverse<T, S, L>\n : // A plugin was found – use the plugin's transformation.\n CheckApplyPlugin<T, keyof IInterpreterPlugin<T, S, L>, S, L>;\n"],"mappings":"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"}
|
|
@@ -5,19 +5,6 @@ import { getCanonicalPath, getLocalizedPath, getRewriteRules } from "./rewriteUt
|
|
|
5
5
|
import { internationalization } from "@intlayer/config/built";
|
|
6
6
|
|
|
7
7
|
//#region src/localization/getLocalizedUrl.ts
|
|
8
|
-
/**
|
|
9
|
-
* True when the build-time routing mode is known and is NOT 'no-prefix'.
|
|
10
|
-
*/
|
|
11
|
-
const TREE_SHAKE_NO_PREFIX = process.env["INTLAYER_ROUTING_MODE"] && process.env["INTLAYER_ROUTING_MODE"] !== "no-prefix";
|
|
12
|
-
/**
|
|
13
|
-
* True when the build-time routing mode is known and is NOT 'search-params'.
|
|
14
|
-
*/
|
|
15
|
-
const TREE_SHAKE_SEARCH_PARAMS = process.env["INTLAYER_ROUTING_MODE"] && process.env["INTLAYER_ROUTING_MODE"] !== "search-params";
|
|
16
|
-
/**
|
|
17
|
-
* True when no domain routing is configured at build time
|
|
18
|
-
* (INTLAYER_ROUTING_DOMAINS === 'false').
|
|
19
|
-
*/
|
|
20
|
-
const TREE_SHAKE_DOMAINS = process.env["INTLAYER_ROUTING_DOMAINS"] === "false";
|
|
21
8
|
/** Strips the protocol and returns the bare hostname of a domain string. */
|
|
22
9
|
const extractHostname = (domain) => {
|
|
23
10
|
try {
|
|
@@ -69,16 +56,16 @@ const getLocalizedUrl = (url, currentLocale = internationalization?.defaultLocal
|
|
|
69
56
|
const { defaultLocale, mode, locales, rewrite, domains, currentDomain } = resolveRoutingConfig(options);
|
|
70
57
|
const urlWithoutLocale = getPathWithoutLocale(url, locales);
|
|
71
58
|
const rewriteRules = getRewriteRules(rewrite, "url");
|
|
72
|
-
if (!
|
|
59
|
+
if (!(process.env["INTLAYER_ROUTING_MODE"] && process.env["INTLAYER_ROUTING_MODE"] !== "no-prefix") && mode === "no-prefix") return getLocalizedPath(getCanonicalPath(urlWithoutLocale, void 0, rewriteRules), currentLocale, rewriteRules).path;
|
|
73
60
|
const isAbsoluteUrl = checkIsURLAbsolute(urlWithoutLocale);
|
|
74
61
|
const parsedUrl = isAbsoluteUrl ? new URL(urlWithoutLocale) : new URL(urlWithoutLocale, "http://example.com");
|
|
75
62
|
const translatedPathname = getLocalizedPath(getCanonicalPath(parsedUrl.pathname, void 0, rewriteRules), currentLocale, rewriteRules).path;
|
|
76
|
-
const detectedCurrentHostname =
|
|
77
|
-
const localeDomain =
|
|
63
|
+
const detectedCurrentHostname = process.env["INTLAYER_ROUTING_DOMAINS"] !== "false" ? extractHostname(currentDomain ?? (isAbsoluteUrl ? parsedUrl.hostname : void 0) ?? (typeof window !== "undefined" ? window?.location?.hostname : void 0) ?? "") || null : null;
|
|
64
|
+
const localeDomain = process.env["INTLAYER_ROUTING_DOMAINS"] !== "false" ? domains?.[currentLocale] : void 0;
|
|
78
65
|
const localeDomainHostname = localeDomain ? extractHostname(localeDomain) : null;
|
|
79
66
|
const normalizedDomain = localeDomainHostname !== null && detectedCurrentHostname !== null && localeDomainHostname !== detectedCurrentHostname && localeDomain ? /^https?:\/\//.test(localeDomain) ? localeDomain : `https://${localeDomain}` : null;
|
|
80
67
|
const baseUrl = normalizedDomain ? normalizedDomain : isAbsoluteUrl ? `${parsedUrl.protocol}//${parsedUrl.host}` : "";
|
|
81
|
-
if (!
|
|
68
|
+
if (!(process.env["INTLAYER_ROUTING_MODE"] && process.env["INTLAYER_ROUTING_MODE"] !== "search-params") && mode === "search-params") {
|
|
82
69
|
const searchParams = new URLSearchParams(parsedUrl.search);
|
|
83
70
|
searchParams.set("locale", currentLocale.toString());
|
|
84
71
|
const queryParams = searchParams.toString();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getLocalizedUrl.mjs","names":[],"sources":["../../../src/localization/getLocalizedUrl.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\
|
|
1
|
+
{"version":3,"file":"getLocalizedUrl.mjs","names":[],"sources":["../../../src/localization/getLocalizedUrl.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { checkIsURLAbsolute } from '../utils/checkIsURLAbsolute';\nimport { getPathWithoutLocale } from './getPathWithoutLocale';\nimport {\n getPrefix,\n type RoutingOptions,\n resolveRoutingConfig,\n} from './getPrefix';\nimport {\n getCanonicalPath,\n getLocalizedPath,\n getRewriteRules,\n} from './rewriteUtils';\n\nexport type { RoutingOptions };\n\n/** Strips the protocol and returns the bare hostname of a domain string. */\nconst extractHostname = (domain: string): string => {\n try {\n return /^https?:\\/\\//.test(domain) ? new URL(domain).hostname : domain;\n } catch {\n return domain;\n }\n};\n\n/**\n * Generate URL by prefixing the given URL with the referenced locale or adding search parameters\n * based on the routing mode. Handles both absolute and relative URLs appropriately.\n *\n * This function gets the locales, default locale, and routing mode from the configuration if not provided.\n *\n * Example:\n *\n * ```ts\n * // prefix-no-default mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'prefix-no-default' });\n * // Returns '/fr/about' for the French locale\n * // Returns '/about' for the English locale (default)\n *\n * // prefix-all mode\n * getLocalizedUrl('/about', 'en', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'prefix-all' });\n * // Returns '/en/about' for the English locale\n * // Returns '/fr/about' for the French locale\n *\n * // search-params mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'search-params' });\n * // Returns '/about?locale=fr' for the French locale\n *\n * // no-prefix mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'no-prefix' });\n * // Returns '/about' for any locale\n * ```\n *\n * @param url - The original URL string to be processed.\n * @param currentLocale - The current locale.\n * @param options - Configuration options\n * @param options.locales - Optional array of supported locales. Defaults to configured locales.\n * @param options.defaultLocale - The default locale. Defaults to configured default locale.\n * @param options.mode - URL routing mode for locale handling. Defaults to configured mode.\n * @param options.currentDomain - Hostname of the page being rendered. Used to decide\n * whether to emit a relative URL (same domain) or an absolute URL (cross-domain).\n * Auto-detected from the input URL or `window.location` when omitted.\n * @returns The localized URL for the current locale.\n */\nexport const getLocalizedUrl = (\n url: string,\n currentLocale: LocalesValues = internationalization?.defaultLocale,\n options: RoutingOptions = {}\n): string => {\n const { defaultLocale, mode, locales, rewrite, domains, currentDomain } =\n resolveRoutingConfig(options);\n\n const urlWithoutLocale = getPathWithoutLocale(url, locales);\n const rewriteRules = getRewriteRules(rewrite, 'url');\n\n if (\n !(\n process.env['INTLAYER_ROUTING_MODE'] &&\n process.env['INTLAYER_ROUTING_MODE'] !== 'no-prefix'\n ) &&\n mode === 'no-prefix'\n ) {\n return getLocalizedPath(\n getCanonicalPath(urlWithoutLocale, undefined, rewriteRules),\n currentLocale as Locale,\n rewriteRules\n ).path;\n }\n\n const isAbsoluteUrl = checkIsURLAbsolute(urlWithoutLocale);\n const parsedUrl = isAbsoluteUrl\n ? new URL(urlWithoutLocale)\n : new URL(urlWithoutLocale, 'http://example.com');\n\n const translatedPathname = getLocalizedPath(\n getCanonicalPath(parsedUrl.pathname, undefined, rewriteRules),\n currentLocale as Locale,\n rewriteRules\n ).path;\n\n // ── Domain routing ────────────────────────────────────────────────────────\n // Resolve the \"current\" hostname so we can choose between a relative URL\n // (same domain) and an absolute URL (cross-domain).\n //\n // Detection priority:\n // 1. Explicit `currentDomain` option passed by the caller.\n // 2. Hostname extracted from an absolute input URL.\n // 3. `window.location.hostname` in browser environments.\n // When none of these is available we fall back to always generating an\n // absolute URL (the previous behaviour, safe for SSR/static generation).\n const detectedCurrentHostname =\n process.env['INTLAYER_ROUTING_DOMAINS'] !== 'false'\n ? extractHostname(\n currentDomain ??\n (isAbsoluteUrl ? parsedUrl.hostname : undefined) ??\n (typeof window !== 'undefined'\n ? window?.location?.hostname\n : undefined) ??\n ''\n ) || null\n : null;\n\n const localeDomain =\n process.env['INTLAYER_ROUTING_DOMAINS'] !== 'false'\n ? domains?.[currentLocale as LocalesValues]\n : undefined;\n\n const localeDomainHostname = localeDomain\n ? extractHostname(localeDomain)\n : null;\n\n // Only prepend the locale's domain when it differs from the current hostname.\n const isCrossDomain =\n localeDomainHostname !== null &&\n detectedCurrentHostname !== null &&\n localeDomainHostname !== detectedCurrentHostname;\n\n const normalizedDomain =\n isCrossDomain && localeDomain\n ? /^https?:\\/\\//.test(localeDomain)\n ? localeDomain\n : `https://${localeDomain}`\n : null;\n\n const baseUrl = normalizedDomain\n ? normalizedDomain\n : isAbsoluteUrl\n ? `${parsedUrl.protocol}//${parsedUrl.host}`\n : '';\n // ─────────────────────────────────────────────────────────────────────────\n\n if (\n !(\n process.env['INTLAYER_ROUTING_MODE'] &&\n process.env['INTLAYER_ROUTING_MODE'] !== 'search-params'\n ) &&\n mode === 'search-params'\n ) {\n const searchParams = new URLSearchParams(parsedUrl.search);\n\n searchParams.set('locale', currentLocale.toString());\n\n const queryParams = searchParams.toString();\n const path = queryParams\n ? `${translatedPathname}?${queryParams}`\n : translatedPathname;\n\n return `${baseUrl}${path}${parsedUrl.hash}`;\n }\n\n const { prefix } = getPrefix(currentLocale, {\n defaultLocale,\n mode,\n locales,\n domains,\n });\n\n let localizedPath = `/${prefix}${translatedPathname}`.replace(/\\/+/g, '/');\n\n if (localizedPath.length > 1 && localizedPath.endsWith('/')) {\n localizedPath = localizedPath.slice(0, -1);\n }\n\n return `${baseUrl}${localizedPath}${parsedUrl.search}${parsedUrl.hash}`;\n};\n"],"mappings":";;;;;;;;AAwBA,MAAM,mBAAmB,WAA2B;AAClD,KAAI;AACF,SAAO,eAAe,KAAK,OAAO,GAAG,IAAI,IAAI,OAAO,CAAC,WAAW;SAC1D;AACN,SAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CX,MAAa,mBACX,KACA,gBAA+B,sBAAsB,eACrD,UAA0B,EAAE,KACjB;CACX,MAAM,EAAE,eAAe,MAAM,SAAS,SAAS,SAAS,kBACtD,qBAAqB,QAAQ;CAE/B,MAAM,mBAAmB,qBAAqB,KAAK,QAAQ;CAC3D,MAAM,eAAe,gBAAgB,SAAS,MAAM;AAEpD,KACE,EACE,QAAQ,IAAI,4BACZ,QAAQ,IAAI,6BAA6B,gBAE3C,SAAS,YAET,QAAO,iBACL,iBAAiB,kBAAkB,QAAW,aAAa,EAC3D,eACA,aACD,CAAC;CAGJ,MAAM,gBAAgB,mBAAmB,iBAAiB;CAC1D,MAAM,YAAY,gBACd,IAAI,IAAI,iBAAiB,GACzB,IAAI,IAAI,kBAAkB,qBAAqB;CAEnD,MAAM,qBAAqB,iBACzB,iBAAiB,UAAU,UAAU,QAAW,aAAa,EAC7D,eACA,aACD,CAAC;CAYF,MAAM,0BACJ,QAAQ,IAAI,gCAAgC,UACxC,gBACE,kBACG,gBAAgB,UAAU,WAAW,YACrC,OAAO,WAAW,cACf,QAAQ,UAAU,WAClB,WACJ,GACH,IAAI,OACL;CAEN,MAAM,eACJ,QAAQ,IAAI,gCAAgC,UACxC,UAAU,iBACV;CAEN,MAAM,uBAAuB,eACzB,gBAAgB,aAAa,GAC7B;CAQJ,MAAM,mBAJJ,yBAAyB,QACzB,4BAA4B,QAC5B,yBAAyB,2BAGR,eACb,eAAe,KAAK,aAAa,GAC/B,eACA,WAAW,iBACb;CAEN,MAAM,UAAU,mBACZ,mBACA,gBACE,GAAG,UAAU,SAAS,IAAI,UAAU,SACpC;AAGN,KACE,EACE,QAAQ,IAAI,4BACZ,QAAQ,IAAI,6BAA6B,oBAE3C,SAAS,iBACT;EACA,MAAM,eAAe,IAAI,gBAAgB,UAAU,OAAO;AAE1D,eAAa,IAAI,UAAU,cAAc,UAAU,CAAC;EAEpD,MAAM,cAAc,aAAa,UAAU;AAK3C,SAAO,GAAG,UAJG,cACT,GAAG,mBAAmB,GAAG,gBACzB,qBAEuB,UAAU;;CAGvC,MAAM,EAAE,WAAW,UAAU,eAAe;EAC1C;EACA;EACA;EACA;EACD,CAAC;CAEF,IAAI,gBAAgB,IAAI,SAAS,qBAAqB,QAAQ,QAAQ,IAAI;AAE1E,KAAI,cAAc,SAAS,KAAK,cAAc,SAAS,IAAI,CACzD,iBAAgB,cAAc,MAAM,GAAG,GAAG;AAG5C,QAAO,GAAG,UAAU,gBAAgB,UAAU,SAAS,UAAU"}
|
|
@@ -3,16 +3,6 @@ import { DEFAULT_LOCALE, LOCALES, ROUTING_MODE } from "@intlayer/config/defaultV
|
|
|
3
3
|
|
|
4
4
|
//#region src/localization/getPrefix.ts
|
|
5
5
|
/**
|
|
6
|
-
* True when the build-time routing mode is known and is not a prefix-based
|
|
7
|
-
* mode (neither 'prefix-all' nor 'prefix-no-default').
|
|
8
|
-
*/
|
|
9
|
-
const TREE_SHAKE_PREFIX_MODES = process.env["INTLAYER_ROUTING_MODE"] && process.env["INTLAYER_ROUTING_MODE"] !== "prefix-all" && process.env["INTLAYER_ROUTING_MODE"] !== "prefix-no-default";
|
|
10
|
-
/**
|
|
11
|
-
* True when no domain routing is configured at build time
|
|
12
|
-
* (INTLAYER_ROUTING_DOMAINS === 'false').
|
|
13
|
-
*/
|
|
14
|
-
const TREE_SHAKE_DOMAINS = process.env["INTLAYER_ROUTING_DOMAINS"] === "false";
|
|
15
|
-
/**
|
|
16
6
|
* Resolves routing configuration by merging provided options with configuration defaults.
|
|
17
7
|
* Single source of truth for default routing config resolution across all localization functions.
|
|
18
8
|
*/
|
|
@@ -59,11 +49,11 @@ const resolveRoutingConfig = (options = {}) => ({
|
|
|
59
49
|
*/
|
|
60
50
|
const getPrefix = (locale, options = {}) => {
|
|
61
51
|
const { defaultLocale, mode, locales, domains } = resolveRoutingConfig(options);
|
|
62
|
-
if (
|
|
52
|
+
if (process.env["INTLAYER_ROUTING_MODE"] && process.env["INTLAYER_ROUTING_MODE"] !== "prefix-all" && process.env["INTLAYER_ROUTING_MODE"] !== "prefix-no-default" || !locale || !locales.includes(locale)) return {
|
|
63
53
|
prefix: "",
|
|
64
54
|
localePrefix: void 0
|
|
65
55
|
};
|
|
66
|
-
if (
|
|
56
|
+
if (process.env["INTLAYER_ROUTING_DOMAINS"] !== "false" && domains) {
|
|
67
57
|
const localeDomain = domains[locale];
|
|
68
58
|
if (localeDomain) {
|
|
69
59
|
if (Object.values(domains).filter((domain) => domain === localeDomain).length === 1) return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getPrefix.mjs","names":[],"sources":["../../../src/localization/getPrefix.ts"],"sourcesContent":["import { internationalization, routing } from '@intlayer/config/built';\nimport {\n DEFAULT_LOCALE,\n LOCALES,\n ROUTING_MODE,\n} from '@intlayer/config/defaultValues';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\
|
|
1
|
+
{"version":3,"file":"getPrefix.mjs","names":[],"sources":["../../../src/localization/getPrefix.ts"],"sourcesContent":["import { internationalization, routing } from '@intlayer/config/built';\nimport {\n DEFAULT_LOCALE,\n LOCALES,\n ROUTING_MODE,\n} from '@intlayer/config/defaultValues';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { RoutingConfig } from '@intlayer/types/config';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\n\n/**\n * Shared routing options used across all URL localization functions.\n */\nexport type RoutingOptions = {\n locales?: LocalesValues[];\n defaultLocale?: LocalesValues;\n mode?: RoutingConfig['mode'];\n rewrite?: RoutingConfig['rewrite'];\n domains?: RoutingConfig['domains'];\n /**\n * The hostname of the page currently being rendered (e.g. `'intlayer.org'`).\n * When provided, `getLocalizedUrl` returns a relative URL for locales whose\n * configured domain matches `currentDomain`, and an absolute URL only when\n * the target locale lives on a different domain.\n *\n * When omitted the function tries to infer it from:\n * 1. The domain of an absolute input URL.\n * 2. `window.location.hostname` in browser environments.\n * Falls back to always generating absolute URLs when neither is available.\n */\n currentDomain?: string;\n};\n\n/**\n * Resolves routing configuration by merging provided options with configuration defaults.\n * Single source of truth for default routing config resolution across all localization functions.\n */\nexport const resolveRoutingConfig = (options: RoutingOptions = {}) => ({\n defaultLocale: internationalization?.defaultLocale ?? DEFAULT_LOCALE,\n mode: routing?.mode ?? ROUTING_MODE,\n locales: internationalization?.locales ?? LOCALES,\n rewrite: routing?.rewrite,\n domains: routing?.domains,\n ...options,\n});\n\nexport type GetPrefixOptions = {\n defaultLocale?: LocalesValues;\n mode?: RoutingConfig['mode'];\n};\n\nexport type GetPrefixResult = {\n /**\n * The complete base URL path with leading and trailing slashes.\n *\n * @example\n * // https://example.com/fr/about -> '/fr'\n * // https://example.com/about -> ''\n */\n prefix: string;\n /**\n * The locale identifier without slashes.\n *\n * @example\n * // https://example.com/fr/about -> 'fr'\n * // https://example.com/about -> undefined\n */\n localePrefix: Locale | undefined;\n};\n\n/**\n * Determines the URL prefix for a given locale based on the routing mode configuration.\n *\n * Example:\n *\n * ```ts\n * // prefix-no-default mode with default locale\n * getPrefix('en', { defaultLocale: 'en', mode: 'prefix-no-default' })\n * // Returns { prefix: '', localePrefix: undefined }\n *\n * // prefix-no-default mode with non-default locale\n * getPrefix('fr', { defaultLocale: 'en', mode: 'prefix-no-default' })\n * // Returns { prefix: '/fr', localePrefix: 'fr' }\n *\n * // prefix-all mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'prefix-all' })\n * // Returns { prefix: '/en', localePrefix: locale }\n *\n * // search-params mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'search-params' })\n * // Returns { prefix: '', localePrefix: undefined }\n *\n * // no-prefix mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'no-prefix' })\n * // Returns { prefix: '', localePrefix: undefined }\n * ```\n *\n * @param locale - The locale to check for prefix. If not provided, uses configured default locale.\n * @param options - Configuration options\n * @param options.defaultLocale - The default locale. Defaults to configured default locale.\n * @param options.mode - URL routing mode for locale handling. Defaults to configured mode.\n * @returns An object containing pathPrefix, prefix, and localePrefix for the given locale.\n */\nexport const getPrefix = (\n locale: LocalesValues | undefined,\n options: RoutingOptions = {}\n): GetPrefixResult => {\n const { defaultLocale, mode, locales, domains } =\n resolveRoutingConfig(options);\n\n if (\n (process.env['INTLAYER_ROUTING_MODE'] &&\n process.env['INTLAYER_ROUTING_MODE'] !== 'prefix-all' &&\n process.env['INTLAYER_ROUTING_MODE'] !== 'prefix-no-default') ||\n !locale ||\n !locales.includes(locale)\n ) {\n return {\n prefix: '',\n localePrefix: undefined,\n };\n }\n\n // If this locale is the only one assigned to its domain, no URL prefix is needed\n // (the domain itself identifies the locale). Shared domains use normal prefix logic.\n if (process.env['INTLAYER_ROUTING_DOMAINS'] !== 'false' && domains) {\n const localeDomain = domains[locale as LocalesValues];\n\n if (localeDomain) {\n const localesOnSameDomain = Object.values(domains).filter(\n (domain) => domain === localeDomain\n ).length;\n\n if (localesOnSameDomain === 1) {\n return {\n prefix: '',\n localePrefix: undefined,\n };\n }\n }\n }\n\n // Handle prefix-based modes (prefix-all or prefix-no-default)\n const shouldPrefix =\n mode === 'prefix-all' ||\n (mode === 'prefix-no-default' && defaultLocale !== locale);\n\n if (shouldPrefix) {\n return {\n prefix: `${locale}/`,\n localePrefix: locale as Locale,\n };\n }\n\n return {\n prefix: '',\n localePrefix: undefined,\n };\n};\n"],"mappings":";;;;;;;;AA0CA,MAAa,wBAAwB,UAA0B,EAAE,MAAM;CACrE,eAAe,sBAAsB,iBAAiB;CACtD,MAAM,SAAS,QAAQ;CACvB,SAAS,sBAAsB,WAAW;CAC1C,SAAS,SAAS;CAClB,SAAS,SAAS;CAClB,GAAG;CACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2DD,MAAa,aACX,QACA,UAA0B,EAAE,KACR;CACpB,MAAM,EAAE,eAAe,MAAM,SAAS,YACpC,qBAAqB,QAAQ;AAE/B,KACG,QAAQ,IAAI,4BACX,QAAQ,IAAI,6BAA6B,gBACzC,QAAQ,IAAI,6BAA6B,uBAC3C,CAAC,UACD,CAAC,QAAQ,SAAS,OAAO,CAEzB,QAAO;EACL,QAAQ;EACR,cAAc;EACf;AAKH,KAAI,QAAQ,IAAI,gCAAgC,WAAW,SAAS;EAClE,MAAM,eAAe,QAAQ;AAE7B,MAAI,cAKF;OAJ4B,OAAO,OAAO,QAAQ,CAAC,QAChD,WAAW,WAAW,aACxB,CAAC,WAE0B,EAC1B,QAAO;IACL,QAAQ;IACR,cAAc;IACf;;;AAUP,KAHE,SAAS,gBACR,SAAS,uBAAuB,kBAAkB,OAGnD,QAAO;EACL,QAAQ,GAAG,OAAO;EAClB,cAAc;EACf;AAGH,QAAO;EACL,QAAQ;EACR,cAAc;EACf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getMissingLocalesContent.d.ts","names":[],"sources":["../../../src/deepTransformPlugins/getMissingLocalesContent.ts"],"mappings":";;;;;;;cAiGa,yBAAA,GACX,OAAA,EAAS,MAAA,IACT,eAAA,GAAkB,MAAA,EAAQ,MAAA,cACzB,OAAA;;AAHH;;;;;cA0Ga,wBAAA,aAAsC,WAAA,EACjD,IAAA,EAAM,CAAA,EACN,OAAA,EAAS,aAAA,IAET,SAAA,EAAW,SAAA,KACV,MAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"getMissingLocalesContent.d.ts","names":[],"sources":["../../../src/deepTransformPlugins/getMissingLocalesContent.ts"],"mappings":";;;;;;;cAiGa,yBAAA,GACX,OAAA,EAAS,MAAA,IACT,eAAA,GAAkB,MAAA,EAAQ,MAAA,cACzB,OAAA;;AAHH;;;;;cA0Ga,wBAAA,aAAsC,WAAA,EACjD,IAAA,EAAM,CAAA,EACN,OAAA,EAAS,aAAA,IAET,SAAA,EAAW,SAAA,KACV,MAAA;AAAA,cAuBU,sCAAA,GACX,UAAA,EAAY,UAAA,EACZ,OAAA,GAAS,aAAA,OAA+C,MAAA"}
|
|
@@ -114,6 +114,13 @@ interface NodeProps {
|
|
|
114
114
|
locale?: Locale;
|
|
115
115
|
dictionaryPath?: string;
|
|
116
116
|
children?: any;
|
|
117
|
+
/**
|
|
118
|
+
* Forces eager traversal of plain objects in `deepTransformNode`. By default
|
|
119
|
+
* traversal is lazy (property getters), so callers that discard the returned
|
|
120
|
+
* value never trigger plugins on nested nodes. Set this when running plugins
|
|
121
|
+
* for their side effects only (e.g. missing-locale detection).
|
|
122
|
+
*/
|
|
123
|
+
eager?: boolean;
|
|
117
124
|
}
|
|
118
125
|
/**
|
|
119
126
|
* Interface that defines the plugins that can be used to transform a node.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugins.d.ts","names":[],"sources":["../../../../src/interpreter/getContent/plugins.ts"],"mappings":";;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"plugins.d.ts","names":[],"sources":["../../../../src/interpreter/getContent/plugins.ts"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getLocalizedUrl.d.ts","names":[],"sources":["../../../src/localization/getLocalizedUrl.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"getLocalizedUrl.d.ts","names":[],"sources":["../../../src/localization/getLocalizedUrl.ts"],"mappings":";;;;;AAuEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAAa,eAAA,GACX,GAAA,UACA,aAAA,GAAe,aAAA,EACf,OAAA,GAAS,cAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getPrefix.d.ts","names":[],"sources":["../../../src/localization/getPrefix.ts"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"getPrefix.d.ts","names":[],"sources":["../../../src/localization/getPrefix.ts"],"mappings":";;;;;;;AAkBA;KAAY,cAAA;EACV,OAAA,GAAU,aAAA;EACV,aAAA,GAAgB,aAAA;EAChB,IAAA,GAAO,aAAA;EACP,OAAA,GAAU,aAAA;EACV,OAAA,GAAU,aAAA;EAAA;;;;;;;;;;;EAYV,aAAA;AAAA;;;;AAOF;cAAa,oBAAA,GAAwB,OAAA,GAAS,cAAA;WAvBlC,aAAA;;QAEH,aAAA;WACG,aAAA;WACA,aAAA;EAAA;;;;;;;;;;;;;KA4BA,gBAAA;EACV,aAAA,GAAgB,aAAA;EAChB,IAAA,GAAO,aAAA;AAAA;AAAA,KAGG,eAAA;EALgB;;;;;;;EAa1B,MAAA;EAXoB;AAGtB;;;;;;EAgBE,YAAA,EAAc,MAAA;AAAA;;AAoChB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAAa,SAAA,GACX,MAAA,EAAQ,aAAA,cACR,OAAA,GAAS,cAAA,KACR,eAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intlayer/core",
|
|
3
|
-
"version": "8.7.
|
|
3
|
+
"version": "8.7.13",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Includes core Intlayer functions like translation, dictionary, and utility functions shared across multiple packages.",
|
|
6
6
|
"keywords": [
|
|
@@ -168,11 +168,11 @@
|
|
|
168
168
|
"typecheck": "tsc --noEmit --project tsconfig.types.json"
|
|
169
169
|
},
|
|
170
170
|
"dependencies": {
|
|
171
|
-
"@intlayer/api": "8.7.
|
|
172
|
-
"@intlayer/config": "8.7.
|
|
173
|
-
"@intlayer/dictionaries-entry": "8.7.
|
|
174
|
-
"@intlayer/types": "8.7.
|
|
175
|
-
"@intlayer/unmerged-dictionaries-entry": "8.7.
|
|
171
|
+
"@intlayer/api": "8.7.13",
|
|
172
|
+
"@intlayer/config": "8.7.13",
|
|
173
|
+
"@intlayer/dictionaries-entry": "8.7.13",
|
|
174
|
+
"@intlayer/types": "8.7.13",
|
|
175
|
+
"@intlayer/unmerged-dictionaries-entry": "8.7.13",
|
|
176
176
|
"defu": "6.1.7"
|
|
177
177
|
},
|
|
178
178
|
"devDependencies": {
|