@intlayer/core 8.6.2 → 8.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/interpreter/getContent/plugins.cjs +35 -7
- package/dist/cjs/interpreter/getContent/plugins.cjs.map +1 -1
- package/dist/cjs/localization/getLocalizedUrl.cjs +10 -3
- package/dist/cjs/localization/getLocalizedUrl.cjs.map +1 -1
- package/dist/cjs/localization/getPathWithoutLocale.cjs +11 -3
- package/dist/cjs/localization/getPathWithoutLocale.cjs.map +1 -1
- package/dist/cjs/localization/getPrefix.cjs +6 -2
- package/dist/cjs/localization/getPrefix.cjs.map +1 -1
- package/dist/cjs/localization/rewriteUtils.cjs +9 -6
- package/dist/cjs/localization/rewriteUtils.cjs.map +1 -1
- package/dist/cjs/localization/validatePrefix.cjs +9 -3
- package/dist/cjs/localization/validatePrefix.cjs.map +1 -1
- package/dist/cjs/utils/localeStorage.cjs +34 -19
- package/dist/cjs/utils/localeStorage.cjs.map +1 -1
- package/dist/esm/interpreter/getContent/plugins.mjs +35 -7
- package/dist/esm/interpreter/getContent/plugins.mjs.map +1 -1
- package/dist/esm/localization/getLocalizedUrl.mjs +8 -1
- package/dist/esm/localization/getLocalizedUrl.mjs.map +1 -1
- package/dist/esm/localization/getPathWithoutLocale.mjs +9 -1
- package/dist/esm/localization/getPathWithoutLocale.mjs.map +1 -1
- package/dist/esm/localization/getPrefix.mjs +5 -1
- package/dist/esm/localization/getPrefix.mjs.map +1 -1
- package/dist/esm/localization/rewriteUtils.mjs +5 -2
- package/dist/esm/localization/rewriteUtils.mjs.map +1 -1
- package/dist/esm/localization/validatePrefix.mjs +8 -1
- package/dist/esm/localization/validatePrefix.mjs.map +1 -1
- package/dist/esm/utils/localeStorage.mjs +16 -1
- package/dist/esm/utils/localeStorage.mjs.map +1 -1
- 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/getPathWithoutLocale.d.ts.map +1 -1
- package/dist/types/localization/getPrefix.d.ts.map +1 -1
- package/dist/types/localization/rewriteUtils.d.ts.map +1 -1
- package/dist/types/localization/validatePrefix.d.ts.map +1 -1
- package/dist/types/utils/localeStorage.d.ts.map +1 -1
- package/package.json +6 -6
|
@@ -3,9 +3,24 @@ const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
|
|
|
3
3
|
const require_utils_getCookie = require('./getCookie.cjs');
|
|
4
4
|
let _intlayer_config_built = require("@intlayer/config/built");
|
|
5
5
|
_intlayer_config_built = require_runtime.__toESM(_intlayer_config_built);
|
|
6
|
-
let _intlayer_config_envVars = require("@intlayer/config/envVars");
|
|
7
6
|
|
|
8
7
|
//#region src/utils/localeStorage.ts
|
|
8
|
+
/**
|
|
9
|
+
* True when cookie storage is explicitly disabled at build time.
|
|
10
|
+
*/
|
|
11
|
+
const TREE_SHAKE_STORAGE_COOKIES = process.env["INTLAYER_ROUTING_STORAGE_COOKIES"] === "false";
|
|
12
|
+
/**
|
|
13
|
+
* True when localStorage is explicitly disabled at build time.
|
|
14
|
+
*/
|
|
15
|
+
const TREE_SHAKE_STORAGE_LOCAL_STORAGE = process.env["INTLAYER_ROUTING_STORAGE_LOCALSTORAGE"] === "false";
|
|
16
|
+
/**
|
|
17
|
+
* True when sessionStorage is explicitly disabled at build time.
|
|
18
|
+
*/
|
|
19
|
+
const TREE_SHAKE_STORAGE_SESSION_STORAGE = process.env["INTLAYER_ROUTING_STORAGE_SESSIONSTORAGE"] === "false";
|
|
20
|
+
/**
|
|
21
|
+
* True when header storage is explicitly disabled at build time.
|
|
22
|
+
*/
|
|
23
|
+
const TREE_SHAKE_STORAGE_HEADERS = process.env["INTLAYER_ROUTING_STORAGE_HEADERS"] === "false";
|
|
9
24
|
const buildCookieString = (name, value, attributes) => {
|
|
10
25
|
const parts = [`${name}=${encodeURIComponent(value)}`];
|
|
11
26
|
if (attributes.path) parts.push(`Path=${attributes.path}`);
|
|
@@ -26,15 +41,15 @@ const getLocaleFromStorageClient = (options) => {
|
|
|
26
41
|
const storageAttributes = routing.storage;
|
|
27
42
|
if (options?.isCookieEnabled === false) return void 0;
|
|
28
43
|
const isValidLocale = (value) => !!value && locales.includes(value);
|
|
29
|
-
if (!
|
|
44
|
+
if (!TREE_SHAKE_STORAGE_COOKIES) for (let i = 0; i < storageAttributes.cookies.length; i++) try {
|
|
30
45
|
const value = options?.getCookie?.(storageAttributes.cookies[i].name);
|
|
31
46
|
if (isValidLocale(value)) return value;
|
|
32
47
|
} catch {}
|
|
33
|
-
if (!
|
|
48
|
+
if (!TREE_SHAKE_STORAGE_LOCAL_STORAGE) for (let i = 0; i < storageAttributes.localStorage.length; i++) try {
|
|
34
49
|
const value = options?.getLocaleStorage?.(storageAttributes.localStorage[i].name);
|
|
35
50
|
if (isValidLocale(value)) return value;
|
|
36
51
|
} catch {}
|
|
37
|
-
if (!
|
|
52
|
+
if (!TREE_SHAKE_STORAGE_SESSION_STORAGE) for (let i = 0; i < storageAttributes.sessionStorage.length; i++) try {
|
|
38
53
|
const value = options?.getSessionStorage?.(storageAttributes.sessionStorage[i].name);
|
|
39
54
|
if (isValidLocale(value)) return value;
|
|
40
55
|
} catch {}
|
|
@@ -48,7 +63,7 @@ const setLocaleInStorageClient = (locale, options) => {
|
|
|
48
63
|
const { routing } = _intlayer_config_built.default;
|
|
49
64
|
const storageAttributes = routing.storage;
|
|
50
65
|
if (options?.isCookieEnabled === false) return;
|
|
51
|
-
if (!
|
|
66
|
+
if (!TREE_SHAKE_STORAGE_COOKIES) for (let i = 0; i < storageAttributes.cookies.length; i++) {
|
|
52
67
|
const { name, attributes } = storageAttributes.cookies[i];
|
|
53
68
|
try {
|
|
54
69
|
if (options?.setCookieStore) options.setCookieStore(name, locale, {
|
|
@@ -61,7 +76,7 @@ const setLocaleInStorageClient = (locale, options) => {
|
|
|
61
76
|
} catch {}
|
|
62
77
|
}
|
|
63
78
|
}
|
|
64
|
-
if (!
|
|
79
|
+
if (!TREE_SHAKE_STORAGE_LOCAL_STORAGE && options?.setLocaleStorage) for (let i = 0; i < storageAttributes.localStorage.length; i++) {
|
|
65
80
|
const { name } = storageAttributes.localStorage[i];
|
|
66
81
|
try {
|
|
67
82
|
if (!(options?.overwrite ?? true) && options?.getLocaleStorage) {
|
|
@@ -70,7 +85,7 @@ const setLocaleInStorageClient = (locale, options) => {
|
|
|
70
85
|
options.setLocaleStorage(name, locale);
|
|
71
86
|
} catch {}
|
|
72
87
|
}
|
|
73
|
-
if (!
|
|
88
|
+
if (!TREE_SHAKE_STORAGE_SESSION_STORAGE && options?.setSessionStorage) for (let i = 0; i < storageAttributes.sessionStorage.length; i++) {
|
|
74
89
|
const { name } = storageAttributes.sessionStorage[i];
|
|
75
90
|
try {
|
|
76
91
|
if (!(options?.overwrite ?? true) && options?.getSessionStorage) {
|
|
@@ -107,11 +122,11 @@ const getLocaleFromStorageServer = (options) => {
|
|
|
107
122
|
const storageAttributes = routing.storage;
|
|
108
123
|
if (options?.isCookieEnabled === false) return void 0;
|
|
109
124
|
const isValidLocale = (value) => !!value && locales.includes(value);
|
|
110
|
-
if (!
|
|
125
|
+
if (!TREE_SHAKE_STORAGE_COOKIES) for (let i = 0; i < storageAttributes.cookies.length; i++) try {
|
|
111
126
|
const value = options?.getCookie?.(storageAttributes.cookies[i].name);
|
|
112
127
|
if (isValidLocale(value)) return value;
|
|
113
128
|
} catch {}
|
|
114
|
-
if (!
|
|
129
|
+
if (!TREE_SHAKE_STORAGE_HEADERS) for (let i = 0; i < storageAttributes.headers.length; i++) try {
|
|
115
130
|
const value = options?.getHeader?.(storageAttributes.headers[i].name);
|
|
116
131
|
if (isValidLocale(value)) return value;
|
|
117
132
|
} catch {}
|
|
@@ -124,7 +139,7 @@ const setLocaleInStorageServer = (locale, options) => {
|
|
|
124
139
|
const { routing } = _intlayer_config_built.default;
|
|
125
140
|
const storageAttributes = routing.storage;
|
|
126
141
|
if (options?.isCookieEnabled === false) return;
|
|
127
|
-
if (!
|
|
142
|
+
if (!TREE_SHAKE_STORAGE_COOKIES) for (let i = 0; i < storageAttributes.cookies.length; i++) {
|
|
128
143
|
const { name, attributes } = storageAttributes.cookies[i];
|
|
129
144
|
try {
|
|
130
145
|
if (options?.setCookieStore) options.setCookieStore(name, locale, {
|
|
@@ -137,7 +152,7 @@ const setLocaleInStorageServer = (locale, options) => {
|
|
|
137
152
|
} catch {}
|
|
138
153
|
}
|
|
139
154
|
}
|
|
140
|
-
if (!
|
|
155
|
+
if (!TREE_SHAKE_STORAGE_HEADERS && options?.setHeader) for (let i = 0; i < storageAttributes.headers.length; i++) try {
|
|
141
156
|
options.setHeader(storageAttributes.headers[i].name, locale);
|
|
142
157
|
} catch {}
|
|
143
158
|
};
|
|
@@ -182,19 +197,19 @@ const getLocaleFromStorage = (options) => {
|
|
|
182
197
|
} catch {}
|
|
183
198
|
return require_utils_getCookie.getCookie(name);
|
|
184
199
|
};
|
|
185
|
-
if (!
|
|
200
|
+
if (!TREE_SHAKE_STORAGE_COOKIES) for (let i = 0; i < storageAttributes.cookies.length; i++) {
|
|
186
201
|
const value = readCookie(storageAttributes.cookies[i].name);
|
|
187
202
|
if (isValidLocale(value)) return value;
|
|
188
203
|
}
|
|
189
|
-
if (!
|
|
204
|
+
if (!TREE_SHAKE_STORAGE_LOCAL_STORAGE) for (let i = 0; i < storageAttributes.localStorage.length; i++) try {
|
|
190
205
|
const value = options?.getLocaleStorage?.(storageAttributes.localStorage[i].name);
|
|
191
206
|
if (isValidLocale(value)) return value;
|
|
192
207
|
} catch {}
|
|
193
|
-
if (!
|
|
208
|
+
if (!TREE_SHAKE_STORAGE_SESSION_STORAGE) for (let i = 0; i < storageAttributes.sessionStorage.length; i++) try {
|
|
194
209
|
const value = options?.getSessionStorage?.(storageAttributes.sessionStorage[i].name);
|
|
195
210
|
if (isValidLocale(value)) return value;
|
|
196
211
|
} catch {}
|
|
197
|
-
if (!
|
|
212
|
+
if (!TREE_SHAKE_STORAGE_HEADERS) for (let i = 0; i < storageAttributes.headers.length; i++) try {
|
|
198
213
|
const value = options?.getHeader?.(storageAttributes.headers[i].name);
|
|
199
214
|
if (isValidLocale(value)) return value;
|
|
200
215
|
} catch {}
|
|
@@ -210,7 +225,7 @@ const setLocaleInStorage = (locale, options) => {
|
|
|
210
225
|
const { routing } = _intlayer_config_built.default;
|
|
211
226
|
const storageAttributes = routing.storage;
|
|
212
227
|
if (options?.isCookieEnabled === false) return;
|
|
213
|
-
if (!
|
|
228
|
+
if (!TREE_SHAKE_STORAGE_COOKIES) for (let i = 0; i < storageAttributes.cookies.length; i++) {
|
|
214
229
|
const { name, attributes } = storageAttributes.cookies[i];
|
|
215
230
|
try {
|
|
216
231
|
if (options?.setCookieStore) options.setCookieStore(name, locale, {
|
|
@@ -223,7 +238,7 @@ const setLocaleInStorage = (locale, options) => {
|
|
|
223
238
|
} catch {}
|
|
224
239
|
}
|
|
225
240
|
}
|
|
226
|
-
if (!
|
|
241
|
+
if (!TREE_SHAKE_STORAGE_LOCAL_STORAGE && options?.setLocaleStorage) for (let i = 0; i < storageAttributes.localStorage.length; i++) {
|
|
227
242
|
const { name } = storageAttributes.localStorage[i];
|
|
228
243
|
try {
|
|
229
244
|
if (!(options?.overwrite ?? true) && options?.getLocaleStorage) {
|
|
@@ -232,7 +247,7 @@ const setLocaleInStorage = (locale, options) => {
|
|
|
232
247
|
options.setLocaleStorage(name, locale);
|
|
233
248
|
} catch {}
|
|
234
249
|
}
|
|
235
|
-
if (!
|
|
250
|
+
if (!TREE_SHAKE_STORAGE_SESSION_STORAGE && options?.setSessionStorage) for (let i = 0; i < storageAttributes.sessionStorage.length; i++) {
|
|
236
251
|
const { name } = storageAttributes.sessionStorage[i];
|
|
237
252
|
try {
|
|
238
253
|
if (!(options?.overwrite ?? true) && options?.getSessionStorage) {
|
|
@@ -241,7 +256,7 @@ const setLocaleInStorage = (locale, options) => {
|
|
|
241
256
|
options.setSessionStorage(name, locale);
|
|
242
257
|
} catch {}
|
|
243
258
|
}
|
|
244
|
-
if (!
|
|
259
|
+
if (!TREE_SHAKE_STORAGE_HEADERS && options?.setHeader) for (let i = 0; i < storageAttributes.headers.length; i++) try {
|
|
245
260
|
options.setHeader(storageAttributes.headers[i].name, locale);
|
|
246
261
|
} catch {}
|
|
247
262
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localeStorage.cjs","names":["configuration","TREE_SHAKE_STORAGE_COOKIES","TREE_SHAKE_STORAGE_LOCAL_STORAGE","TREE_SHAKE_STORAGE_SESSION_STORAGE","TREE_SHAKE_STORAGE_HEADERS","getCookie"],"sources":["../../../src/utils/localeStorage.ts"],"sourcesContent":["import configuration from '@intlayer/config/built';\nimport {\n TREE_SHAKE_STORAGE_COOKIES,\n TREE_SHAKE_STORAGE_HEADERS,\n TREE_SHAKE_STORAGE_LOCAL_STORAGE,\n TREE_SHAKE_STORAGE_SESSION_STORAGE,\n} from '@intlayer/config/envVars';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { CookiesAttributes } from '@intlayer/types/config';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { getCookie } from './getCookie';\n\n// ============================================================================\n// Shared types\n// ============================================================================\n\nexport type CookieBuildAttributes = {\n domain?: string;\n path?: string;\n secure?: boolean;\n httpOnly?: boolean;\n sameSite?: 'strict' | 'lax' | 'none';\n /** Expiry as milliseconds since epoch (Date.getTime()) or number of days */\n expires?: number | undefined;\n};\n\n// ============================================================================\n// Shared helpers\n// ============================================================================\n\nconst buildCookieString = (\n name: string,\n value: string,\n attributes: Omit<CookiesAttributes, 'name' | 'type'>\n): string => {\n const encodedValue = encodeURIComponent(value);\n const parts: string[] = [`${name}=${encodedValue}`];\n\n if (attributes.path) parts.push(`Path=${attributes.path}`);\n if (attributes.domain) parts.push(`Domain=${attributes.domain}`);\n if (attributes.expires instanceof Date)\n parts.push(`Expires=${attributes.expires.toUTCString()}`);\n if (attributes.secure) parts.push('Secure');\n if (attributes.sameSite) parts.push(`SameSite=${attributes.sameSite}`);\n return parts.join('; ');\n};\n\n// ============================================================================\n// Client-specific types and functions\n// (cookies via browser APIs, localStorage, sessionStorage — no headers)\n// ============================================================================\n\nexport type LocaleStorageClientOptions = {\n overwrite?: boolean;\n isCookieEnabled?: boolean;\n setCookieStore?: (\n name: string,\n value: string,\n cookie: CookieBuildAttributes\n ) => void;\n setCookieString?: (name: string, cookie: string) => void;\n getCookie?: (name: string) => string | undefined | null;\n setSessionStorage?: (name: string, value: string) => void;\n getSessionStorage?: (name: string) => string | undefined | null;\n setLocaleStorage?: (name: string, value: string) => void;\n getLocaleStorage?: (name: string) => string | undefined | null;\n};\n\n/**\n * Retrieves the locale from browser storage mechanisms\n * (cookies, localStorage, sessionStorage).\n * Does not read from headers — use `getLocaleFromStorageServer` for that.\n */\nexport const getLocaleFromStorageClient = (\n options: LocaleStorageClientOptions\n): Locale | undefined => {\n const { routing, internationalization } = configuration;\n const { locales } = internationalization;\n const storageAttributes = routing.storage;\n\n if (options?.isCookieEnabled === false) return undefined;\n\n const isValidLocale = (value: string | null | undefined): value is Locale =>\n !!value && locales.includes(value as Locale);\n\n if (!TREE_SHAKE_STORAGE_COOKIES) {\n for (let i = 0; i < storageAttributes.cookies.length; i++) {\n try {\n const value = options?.getCookie?.(storageAttributes.cookies[i].name);\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_LOCAL_STORAGE) {\n for (let i = 0; i < storageAttributes.localStorage.length; i++) {\n try {\n const value = options?.getLocaleStorage?.(\n storageAttributes.localStorage[i].name\n );\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_SESSION_STORAGE) {\n for (let i = 0; i < storageAttributes.sessionStorage.length; i++) {\n try {\n const value = options?.getSessionStorage?.(\n storageAttributes.sessionStorage[i].name\n );\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n};\n\n/**\n * Stores the locale in browser storage mechanisms\n * (cookies, localStorage, sessionStorage).\n * Does not write to headers — use `setLocaleInStorageServer` for that.\n */\nexport const setLocaleInStorageClient = (\n locale: LocalesValues,\n options?: LocaleStorageClientOptions\n): void => {\n const { routing } = configuration;\n const storageAttributes = routing.storage;\n\n if (options?.isCookieEnabled === false) return;\n\n if (!TREE_SHAKE_STORAGE_COOKIES) {\n for (let i = 0; i < storageAttributes.cookies.length; i++) {\n const { name, attributes } = storageAttributes.cookies[i];\n try {\n if (options?.setCookieStore) {\n options.setCookieStore(name, locale, {\n ...attributes,\n expires:\n attributes.expires instanceof Date\n ? attributes.expires.getTime()\n : attributes.expires,\n });\n }\n } catch {\n try {\n if (options?.setCookieString) {\n options.setCookieString(\n name,\n buildCookieString(name, locale, attributes)\n );\n }\n } catch {}\n }\n }\n }\n\n if (!TREE_SHAKE_STORAGE_LOCAL_STORAGE && options?.setLocaleStorage) {\n for (let i = 0; i < storageAttributes.localStorage.length; i++) {\n const { name } = storageAttributes.localStorage[i];\n try {\n if (!(options?.overwrite ?? true) && options?.getLocaleStorage) {\n if (options.getLocaleStorage(name)) continue;\n }\n options.setLocaleStorage(name, locale);\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_SESSION_STORAGE && options?.setSessionStorage) {\n for (let i = 0; i < storageAttributes.sessionStorage.length; i++) {\n const { name } = storageAttributes.sessionStorage[i];\n try {\n if (!(options?.overwrite ?? true) && options?.getSessionStorage) {\n if (options.getSessionStorage(name)) continue;\n }\n options.setSessionStorage(name, locale);\n } catch {}\n }\n }\n};\n\n/**\n * Client-side locale storage utility.\n * Handles cookies (browser), localStorage and sessionStorage.\n * Does not access headers.\n *\n * @example\n * ```ts\n * const storage = LocaleStorageClient(localeStorageOptions);\n * const locale = storage.getLocale();\n * storage.setLocale('fr');\n * ```\n */\nexport const LocaleStorageClient = (options: LocaleStorageClientOptions) => ({\n getLocale: () => getLocaleFromStorageClient(options),\n setLocale: (locale: LocalesValues) =>\n setLocaleInStorageClient(locale, options),\n});\n\n// ============================================================================\n// Server-specific types and functions\n// (cookies via injected getter/setter, headers — no localStorage/sessionStorage)\n// ============================================================================\n\nexport type LocaleStorageServerOptions = {\n overwrite?: boolean;\n isCookieEnabled?: boolean;\n setCookieStore?: (\n name: string,\n value: string,\n cookie: CookieBuildAttributes\n ) => void;\n setCookieString?: (name: string, cookie: string) => void;\n getCookie?: (name: string) => string | undefined | null;\n getHeader?: (name: string) => string | undefined | null;\n setHeader?: (name: string, value: string) => void;\n};\n\n/**\n * Retrieves the locale from server-side storage mechanisms (cookies, headers).\n * Does not access localStorage or sessionStorage.\n * No browser cookie fallback — the caller must provide `getCookie`.\n */\nexport const getLocaleFromStorageServer = (\n options: LocaleStorageServerOptions\n): Locale | undefined => {\n const { routing, internationalization } = configuration;\n const { locales } = internationalization;\n const storageAttributes = routing.storage;\n\n if (options?.isCookieEnabled === false) return undefined;\n\n const isValidLocale = (value: string | null | undefined): value is Locale =>\n !!value && locales.includes(value as Locale);\n\n if (!TREE_SHAKE_STORAGE_COOKIES) {\n for (let i = 0; i < storageAttributes.cookies.length; i++) {\n try {\n const value = options?.getCookie?.(storageAttributes.cookies[i].name);\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_HEADERS) {\n for (let i = 0; i < storageAttributes.headers.length; i++) {\n try {\n const value = options?.getHeader?.(storageAttributes.headers[i].name);\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n};\n\n/**\n * Stores the locale in server-side storage mechanisms (cookies, headers).\n * Does not write to localStorage or sessionStorage.\n */\nexport const setLocaleInStorageServer = (\n locale: LocalesValues,\n options?: LocaleStorageServerOptions\n): void => {\n const { routing } = configuration;\n const storageAttributes = routing.storage;\n\n if (options?.isCookieEnabled === false) return;\n\n if (!TREE_SHAKE_STORAGE_COOKIES) {\n for (let i = 0; i < storageAttributes.cookies.length; i++) {\n const { name, attributes } = storageAttributes.cookies[i];\n try {\n if (options?.setCookieStore) {\n options.setCookieStore(name, locale, {\n ...attributes,\n expires:\n attributes.expires instanceof Date\n ? attributes.expires.getTime()\n : attributes.expires,\n });\n }\n } catch {\n try {\n if (options?.setCookieString) {\n options.setCookieString(\n name,\n buildCookieString(name, locale, attributes)\n );\n }\n } catch {}\n }\n }\n }\n\n if (!TREE_SHAKE_STORAGE_HEADERS && options?.setHeader) {\n for (let i = 0; i < storageAttributes.headers.length; i++) {\n try {\n options.setHeader(storageAttributes.headers[i].name, locale);\n } catch {}\n }\n }\n};\n\n/**\n * Server-side locale storage utility.\n * Handles cookies (via injected getter/setter) and headers.\n * Does not access localStorage or sessionStorage.\n *\n * @example\n * ```ts\n * const storage = LocaleStorageServer({\n * getCookie: (name) => req.cookies[name],\n * setCookieStore: (name, value, attrs) => res.cookie(name, value, attrs),\n * getHeader: (name) => req.headers[name],\n * setHeader: (name, value) => res.setHeader(name, value),\n * });\n * const locale = storage.getLocale();\n * storage.setLocale('fr');\n * ```\n */\nexport const LocaleStorageServer = (options: LocaleStorageServerOptions) => ({\n getLocale: () => getLocaleFromStorageServer(options),\n setLocale: (locale: LocalesValues) =>\n setLocaleInStorageServer(locale, options),\n});\n\n// ============================================================================\n// Deprecated: combined LocaleStorage\n// Use LocaleStorageClient or LocaleStorageServer instead\n// ============================================================================\n\n/**\n * @deprecated Use {@link LocaleStorageClientOptions} or {@link LocaleStorageServerOptions} instead.\n */\nexport type LocaleStorageOptions = LocaleStorageClientOptions &\n LocaleStorageServerOptions;\n\n/**\n * Retrieves the locale from all storage mechanisms\n * (cookies, localStorage, sessionStorage, headers).\n *\n * @deprecated Use {@link getLocaleFromStorageClient} (browser) or\n * {@link getLocaleFromStorageServer} (server) instead.\n */\nexport const getLocaleFromStorage = (\n options: Pick<\n LocaleStorageOptions,\n | 'getCookie'\n | 'getSessionStorage'\n | 'getLocaleStorage'\n | 'getHeader'\n | 'isCookieEnabled'\n >\n): Locale | undefined => {\n const { routing, internationalization } = configuration;\n const { locales } = internationalization;\n const storageAttributes = routing.storage;\n\n if (options?.isCookieEnabled === false) return undefined;\n\n const isValidLocale = (value: string | null | undefined): value is Locale =>\n !!value && locales.includes(value as Locale);\n\n const readCookie = (name: string): string | undefined => {\n try {\n const fromOption = options?.getCookie?.(name);\n if (fromOption !== null && fromOption !== undefined) return fromOption;\n } catch {}\n // Browser fallback kept for backward compatibility\n return getCookie(name);\n };\n\n if (!TREE_SHAKE_STORAGE_COOKIES) {\n for (let i = 0; i < storageAttributes.cookies.length; i++) {\n const value = readCookie(storageAttributes.cookies[i].name);\n if (isValidLocale(value)) return value;\n }\n }\n\n if (!TREE_SHAKE_STORAGE_LOCAL_STORAGE) {\n for (let i = 0; i < storageAttributes.localStorage.length; i++) {\n try {\n const value = options?.getLocaleStorage?.(\n storageAttributes.localStorage[i].name\n );\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_SESSION_STORAGE) {\n for (let i = 0; i < storageAttributes.sessionStorage.length; i++) {\n try {\n const value = options?.getSessionStorage?.(\n storageAttributes.sessionStorage[i].name\n );\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_HEADERS) {\n for (let i = 0; i < storageAttributes.headers.length; i++) {\n try {\n const value = options?.getHeader?.(storageAttributes.headers[i].name);\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n};\n\n/**\n * Stores the locale in all configured storage mechanisms\n * (cookies, localStorage, sessionStorage, headers).\n *\n * @deprecated Use {@link setLocaleInStorageClient} (browser) or\n * {@link setLocaleInStorageServer} (server) instead.\n */\nexport const setLocaleInStorage = (\n locale: LocalesValues,\n options?: LocaleStorageOptions\n): void => {\n const { routing } = configuration;\n const storageAttributes = routing.storage;\n\n if (options?.isCookieEnabled === false) return;\n\n if (!TREE_SHAKE_STORAGE_COOKIES) {\n for (let i = 0; i < storageAttributes.cookies.length; i++) {\n const { name, attributes } = storageAttributes.cookies[i];\n try {\n if (options?.setCookieStore) {\n options.setCookieStore(name, locale, {\n ...attributes,\n expires:\n attributes.expires instanceof Date\n ? attributes.expires.getTime()\n : attributes.expires,\n });\n }\n } catch {\n try {\n if (options?.setCookieString) {\n options.setCookieString(\n name,\n buildCookieString(name, locale, attributes)\n );\n }\n } catch {}\n }\n }\n }\n\n if (!TREE_SHAKE_STORAGE_LOCAL_STORAGE && options?.setLocaleStorage) {\n for (let i = 0; i < storageAttributes.localStorage.length; i++) {\n const { name } = storageAttributes.localStorage[i];\n try {\n if (!(options?.overwrite ?? true) && options?.getLocaleStorage) {\n if (options.getLocaleStorage(name)) continue;\n }\n options.setLocaleStorage(name, locale);\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_SESSION_STORAGE && options?.setSessionStorage) {\n for (let i = 0; i < storageAttributes.sessionStorage.length; i++) {\n const { name } = storageAttributes.sessionStorage[i];\n try {\n if (!(options?.overwrite ?? true) && options?.getSessionStorage) {\n if (options.getSessionStorage(name)) continue;\n }\n options.setSessionStorage(name, locale);\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_HEADERS && options?.setHeader) {\n for (let i = 0; i < storageAttributes.headers.length; i++) {\n try {\n options.setHeader(storageAttributes.headers[i].name, locale);\n } catch {}\n }\n }\n};\n\n/**\n * Utility object to get and set the locale in storage based on configuration.\n *\n * @deprecated Use {@link LocaleStorageClient} (browser) or\n * {@link LocaleStorageServer} (server) instead.\n */\nexport const LocaleStorage = (options: LocaleStorageOptions) => ({\n getLocale: () => getLocaleFromStorage(options),\n setLocale: (locale: LocalesValues) => setLocaleInStorage(locale, options),\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"localeStorage.cjs","names":["configuration","getCookie"],"sources":["../../../src/utils/localeStorage.ts"],"sourcesContent":["import configuration from '@intlayer/config/built';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { CookiesAttributes } from '@intlayer/types/config';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { getCookie } from './getCookie';\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 cookie storage is explicitly disabled at build time.\n */\nconst TREE_SHAKE_STORAGE_COOKIES =\n process.env['INTLAYER_ROUTING_STORAGE_COOKIES'] === 'false';\n\n/**\n * True when localStorage is explicitly disabled at build time.\n */\nconst TREE_SHAKE_STORAGE_LOCAL_STORAGE =\n process.env['INTLAYER_ROUTING_STORAGE_LOCALSTORAGE'] === 'false';\n\n/**\n * True when sessionStorage is explicitly disabled at build time.\n */\nconst TREE_SHAKE_STORAGE_SESSION_STORAGE =\n process.env['INTLAYER_ROUTING_STORAGE_SESSIONSTORAGE'] === 'false';\n\n/**\n * True when header storage is explicitly disabled at build time.\n */\nconst TREE_SHAKE_STORAGE_HEADERS =\n process.env['INTLAYER_ROUTING_STORAGE_HEADERS'] === 'false';\n\n// ============================================================================\n// Shared types\n// ============================================================================\n\nexport type CookieBuildAttributes = {\n domain?: string;\n path?: string;\n secure?: boolean;\n httpOnly?: boolean;\n sameSite?: 'strict' | 'lax' | 'none';\n /** Expiry as milliseconds since epoch (Date.getTime()) or number of days */\n expires?: number | undefined;\n};\n\n// ============================================================================\n// Shared helpers\n// ============================================================================\n\nconst buildCookieString = (\n name: string,\n value: string,\n attributes: Omit<CookiesAttributes, 'name' | 'type'>\n): string => {\n const encodedValue = encodeURIComponent(value);\n const parts: string[] = [`${name}=${encodedValue}`];\n\n if (attributes.path) parts.push(`Path=${attributes.path}`);\n if (attributes.domain) parts.push(`Domain=${attributes.domain}`);\n if (attributes.expires instanceof Date)\n parts.push(`Expires=${attributes.expires.toUTCString()}`);\n if (attributes.secure) parts.push('Secure');\n if (attributes.sameSite) parts.push(`SameSite=${attributes.sameSite}`);\n return parts.join('; ');\n};\n\n// ============================================================================\n// Client-specific types and functions\n// (cookies via browser APIs, localStorage, sessionStorage — no headers)\n// ============================================================================\n\nexport type LocaleStorageClientOptions = {\n overwrite?: boolean;\n isCookieEnabled?: boolean;\n setCookieStore?: (\n name: string,\n value: string,\n cookie: CookieBuildAttributes\n ) => void;\n setCookieString?: (name: string, cookie: string) => void;\n getCookie?: (name: string) => string | undefined | null;\n setSessionStorage?: (name: string, value: string) => void;\n getSessionStorage?: (name: string) => string | undefined | null;\n setLocaleStorage?: (name: string, value: string) => void;\n getLocaleStorage?: (name: string) => string | undefined | null;\n};\n\n/**\n * Retrieves the locale from browser storage mechanisms\n * (cookies, localStorage, sessionStorage).\n * Does not read from headers — use `getLocaleFromStorageServer` for that.\n */\nexport const getLocaleFromStorageClient = (\n options: LocaleStorageClientOptions\n): Locale | undefined => {\n const { routing, internationalization } = configuration;\n const { locales } = internationalization;\n const storageAttributes = routing.storage;\n\n if (options?.isCookieEnabled === false) return undefined;\n\n const isValidLocale = (value: string | null | undefined): value is Locale =>\n !!value && locales.includes(value as Locale);\n\n if (!TREE_SHAKE_STORAGE_COOKIES) {\n for (let i = 0; i < storageAttributes.cookies.length; i++) {\n try {\n const value = options?.getCookie?.(storageAttributes.cookies[i].name);\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_LOCAL_STORAGE) {\n for (let i = 0; i < storageAttributes.localStorage.length; i++) {\n try {\n const value = options?.getLocaleStorage?.(\n storageAttributes.localStorage[i].name\n );\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_SESSION_STORAGE) {\n for (let i = 0; i < storageAttributes.sessionStorage.length; i++) {\n try {\n const value = options?.getSessionStorage?.(\n storageAttributes.sessionStorage[i].name\n );\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n};\n\n/**\n * Stores the locale in browser storage mechanisms\n * (cookies, localStorage, sessionStorage).\n * Does not write to headers — use `setLocaleInStorageServer` for that.\n */\nexport const setLocaleInStorageClient = (\n locale: LocalesValues,\n options?: LocaleStorageClientOptions\n): void => {\n const { routing } = configuration;\n const storageAttributes = routing.storage;\n\n if (options?.isCookieEnabled === false) return;\n\n if (!TREE_SHAKE_STORAGE_COOKIES) {\n for (let i = 0; i < storageAttributes.cookies.length; i++) {\n const { name, attributes } = storageAttributes.cookies[i];\n try {\n if (options?.setCookieStore) {\n options.setCookieStore(name, locale, {\n ...attributes,\n expires:\n attributes.expires instanceof Date\n ? attributes.expires.getTime()\n : attributes.expires,\n });\n }\n } catch {\n try {\n if (options?.setCookieString) {\n options.setCookieString(\n name,\n buildCookieString(name, locale, attributes)\n );\n }\n } catch {}\n }\n }\n }\n\n if (!TREE_SHAKE_STORAGE_LOCAL_STORAGE && options?.setLocaleStorage) {\n for (let i = 0; i < storageAttributes.localStorage.length; i++) {\n const { name } = storageAttributes.localStorage[i];\n try {\n if (!(options?.overwrite ?? true) && options?.getLocaleStorage) {\n if (options.getLocaleStorage(name)) continue;\n }\n options.setLocaleStorage(name, locale);\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_SESSION_STORAGE && options?.setSessionStorage) {\n for (let i = 0; i < storageAttributes.sessionStorage.length; i++) {\n const { name } = storageAttributes.sessionStorage[i];\n try {\n if (!(options?.overwrite ?? true) && options?.getSessionStorage) {\n if (options.getSessionStorage(name)) continue;\n }\n options.setSessionStorage(name, locale);\n } catch {}\n }\n }\n};\n\n/**\n * Client-side locale storage utility.\n * Handles cookies (browser), localStorage and sessionStorage.\n * Does not access headers.\n *\n * @example\n * ```ts\n * const storage = LocaleStorageClient(localeStorageOptions);\n * const locale = storage.getLocale();\n * storage.setLocale('fr');\n * ```\n */\nexport const LocaleStorageClient = (options: LocaleStorageClientOptions) => ({\n getLocale: () => getLocaleFromStorageClient(options),\n setLocale: (locale: LocalesValues) =>\n setLocaleInStorageClient(locale, options),\n});\n\n// ============================================================================\n// Server-specific types and functions\n// (cookies via injected getter/setter, headers — no localStorage/sessionStorage)\n// ============================================================================\n\nexport type LocaleStorageServerOptions = {\n overwrite?: boolean;\n isCookieEnabled?: boolean;\n setCookieStore?: (\n name: string,\n value: string,\n cookie: CookieBuildAttributes\n ) => void;\n setCookieString?: (name: string, cookie: string) => void;\n getCookie?: (name: string) => string | undefined | null;\n getHeader?: (name: string) => string | undefined | null;\n setHeader?: (name: string, value: string) => void;\n};\n\n/**\n * Retrieves the locale from server-side storage mechanisms (cookies, headers).\n * Does not access localStorage or sessionStorage.\n * No browser cookie fallback — the caller must provide `getCookie`.\n */\nexport const getLocaleFromStorageServer = (\n options: LocaleStorageServerOptions\n): Locale | undefined => {\n const { routing, internationalization } = configuration;\n const { locales } = internationalization;\n const storageAttributes = routing.storage;\n\n if (options?.isCookieEnabled === false) return undefined;\n\n const isValidLocale = (value: string | null | undefined): value is Locale =>\n !!value && locales.includes(value as Locale);\n\n if (!TREE_SHAKE_STORAGE_COOKIES) {\n for (let i = 0; i < storageAttributes.cookies.length; i++) {\n try {\n const value = options?.getCookie?.(storageAttributes.cookies[i].name);\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_HEADERS) {\n for (let i = 0; i < storageAttributes.headers.length; i++) {\n try {\n const value = options?.getHeader?.(storageAttributes.headers[i].name);\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n};\n\n/**\n * Stores the locale in server-side storage mechanisms (cookies, headers).\n * Does not write to localStorage or sessionStorage.\n */\nexport const setLocaleInStorageServer = (\n locale: LocalesValues,\n options?: LocaleStorageServerOptions\n): void => {\n const { routing } = configuration;\n const storageAttributes = routing.storage;\n\n if (options?.isCookieEnabled === false) return;\n\n if (!TREE_SHAKE_STORAGE_COOKIES) {\n for (let i = 0; i < storageAttributes.cookies.length; i++) {\n const { name, attributes } = storageAttributes.cookies[i];\n try {\n if (options?.setCookieStore) {\n options.setCookieStore(name, locale, {\n ...attributes,\n expires:\n attributes.expires instanceof Date\n ? attributes.expires.getTime()\n : attributes.expires,\n });\n }\n } catch {\n try {\n if (options?.setCookieString) {\n options.setCookieString(\n name,\n buildCookieString(name, locale, attributes)\n );\n }\n } catch {}\n }\n }\n }\n\n if (!TREE_SHAKE_STORAGE_HEADERS && options?.setHeader) {\n for (let i = 0; i < storageAttributes.headers.length; i++) {\n try {\n options.setHeader(storageAttributes.headers[i].name, locale);\n } catch {}\n }\n }\n};\n\n/**\n * Server-side locale storage utility.\n * Handles cookies (via injected getter/setter) and headers.\n * Does not access localStorage or sessionStorage.\n *\n * @example\n * ```ts\n * const storage = LocaleStorageServer({\n * getCookie: (name) => req.cookies[name],\n * setCookieStore: (name, value, attrs) => res.cookie(name, value, attrs),\n * getHeader: (name) => req.headers[name],\n * setHeader: (name, value) => res.setHeader(name, value),\n * });\n * const locale = storage.getLocale();\n * storage.setLocale('fr');\n * ```\n */\nexport const LocaleStorageServer = (options: LocaleStorageServerOptions) => ({\n getLocale: () => getLocaleFromStorageServer(options),\n setLocale: (locale: LocalesValues) =>\n setLocaleInStorageServer(locale, options),\n});\n\n// ============================================================================\n// Deprecated: combined LocaleStorage\n// Use LocaleStorageClient or LocaleStorageServer instead\n// ============================================================================\n\n/**\n * @deprecated Use {@link LocaleStorageClientOptions} or {@link LocaleStorageServerOptions} instead.\n */\nexport type LocaleStorageOptions = LocaleStorageClientOptions &\n LocaleStorageServerOptions;\n\n/**\n * Retrieves the locale from all storage mechanisms\n * (cookies, localStorage, sessionStorage, headers).\n *\n * @deprecated Use {@link getLocaleFromStorageClient} (browser) or\n * {@link getLocaleFromStorageServer} (server) instead.\n */\nexport const getLocaleFromStorage = (\n options: Pick<\n LocaleStorageOptions,\n | 'getCookie'\n | 'getSessionStorage'\n | 'getLocaleStorage'\n | 'getHeader'\n | 'isCookieEnabled'\n >\n): Locale | undefined => {\n const { routing, internationalization } = configuration;\n const { locales } = internationalization;\n const storageAttributes = routing.storage;\n\n if (options?.isCookieEnabled === false) return undefined;\n\n const isValidLocale = (value: string | null | undefined): value is Locale =>\n !!value && locales.includes(value as Locale);\n\n const readCookie = (name: string): string | undefined => {\n try {\n const fromOption = options?.getCookie?.(name);\n if (fromOption !== null && fromOption !== undefined) return fromOption;\n } catch {}\n // Browser fallback kept for backward compatibility\n return getCookie(name);\n };\n\n if (!TREE_SHAKE_STORAGE_COOKIES) {\n for (let i = 0; i < storageAttributes.cookies.length; i++) {\n const value = readCookie(storageAttributes.cookies[i].name);\n if (isValidLocale(value)) return value;\n }\n }\n\n if (!TREE_SHAKE_STORAGE_LOCAL_STORAGE) {\n for (let i = 0; i < storageAttributes.localStorage.length; i++) {\n try {\n const value = options?.getLocaleStorage?.(\n storageAttributes.localStorage[i].name\n );\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_SESSION_STORAGE) {\n for (let i = 0; i < storageAttributes.sessionStorage.length; i++) {\n try {\n const value = options?.getSessionStorage?.(\n storageAttributes.sessionStorage[i].name\n );\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_HEADERS) {\n for (let i = 0; i < storageAttributes.headers.length; i++) {\n try {\n const value = options?.getHeader?.(storageAttributes.headers[i].name);\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n};\n\n/**\n * Stores the locale in all configured storage mechanisms\n * (cookies, localStorage, sessionStorage, headers).\n *\n * @deprecated Use {@link setLocaleInStorageClient} (browser) or\n * {@link setLocaleInStorageServer} (server) instead.\n */\nexport const setLocaleInStorage = (\n locale: LocalesValues,\n options?: LocaleStorageOptions\n): void => {\n const { routing } = configuration;\n const storageAttributes = routing.storage;\n\n if (options?.isCookieEnabled === false) return;\n\n if (!TREE_SHAKE_STORAGE_COOKIES) {\n for (let i = 0; i < storageAttributes.cookies.length; i++) {\n const { name, attributes } = storageAttributes.cookies[i];\n try {\n if (options?.setCookieStore) {\n options.setCookieStore(name, locale, {\n ...attributes,\n expires:\n attributes.expires instanceof Date\n ? attributes.expires.getTime()\n : attributes.expires,\n });\n }\n } catch {\n try {\n if (options?.setCookieString) {\n options.setCookieString(\n name,\n buildCookieString(name, locale, attributes)\n );\n }\n } catch {}\n }\n }\n }\n\n if (!TREE_SHAKE_STORAGE_LOCAL_STORAGE && options?.setLocaleStorage) {\n for (let i = 0; i < storageAttributes.localStorage.length; i++) {\n const { name } = storageAttributes.localStorage[i];\n try {\n if (!(options?.overwrite ?? true) && options?.getLocaleStorage) {\n if (options.getLocaleStorage(name)) continue;\n }\n options.setLocaleStorage(name, locale);\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_SESSION_STORAGE && options?.setSessionStorage) {\n for (let i = 0; i < storageAttributes.sessionStorage.length; i++) {\n const { name } = storageAttributes.sessionStorage[i];\n try {\n if (!(options?.overwrite ?? true) && options?.getSessionStorage) {\n if (options.getSessionStorage(name)) continue;\n }\n options.setSessionStorage(name, locale);\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_HEADERS && options?.setHeader) {\n for (let i = 0; i < storageAttributes.headers.length; i++) {\n try {\n options.setHeader(storageAttributes.headers[i].name, locale);\n } catch {}\n }\n }\n};\n\n/**\n * Utility object to get and set the locale in storage based on configuration.\n *\n * @deprecated Use {@link LocaleStorageClient} (browser) or\n * {@link LocaleStorageServer} (server) instead.\n */\nexport const LocaleStorage = (options: LocaleStorageOptions) => ({\n getLocale: () => getLocaleFromStorage(options),\n setLocale: (locale: LocalesValues) => setLocaleInStorage(locale, options),\n});\n"],"mappings":"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"}
|
|
@@ -7,6 +7,34 @@ 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";
|
|
10
38
|
/** ---------------------------------------------
|
|
11
39
|
* FALLBACK PLUGIN
|
|
12
40
|
*
|
|
@@ -18,7 +46,7 @@ const fallbackPlugin = {
|
|
|
18
46
|
transform: (node) => node
|
|
19
47
|
};
|
|
20
48
|
/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */
|
|
21
|
-
const translationPlugin = (locale, fallback) =>
|
|
49
|
+
const translationPlugin = (locale, fallback) => TREE_SHAKE_TRANSLATION ? fallbackPlugin : {
|
|
22
50
|
id: "translation-plugin",
|
|
23
51
|
canHandle: (node) => typeof node === "object" && node?.nodeType === NodeTypes.TRANSLATION,
|
|
24
52
|
transform: (node, props, deepTransformNode) => {
|
|
@@ -38,7 +66,7 @@ const translationPlugin = (locale, fallback) => process.env.INTLAYER_NODE_TYPE_T
|
|
|
38
66
|
}
|
|
39
67
|
};
|
|
40
68
|
/** Enumeration plugin. Replaces node with a function that takes quantity => string. */
|
|
41
|
-
const enumerationPlugin =
|
|
69
|
+
const enumerationPlugin = TREE_SHAKE_ENUMERATION ? fallbackPlugin : {
|
|
42
70
|
id: "enumeration-plugin",
|
|
43
71
|
canHandle: (node) => typeof node === "object" && node?.nodeType === NodeTypes.ENUMERATION,
|
|
44
72
|
transform: (node, props, deepTransformNode) => {
|
|
@@ -62,7 +90,7 @@ const enumerationPlugin = process.env.INTLAYER_NODE_TYPE_ENUMERATION === "false"
|
|
|
62
90
|
}
|
|
63
91
|
};
|
|
64
92
|
/** Condition plugin. Replaces node with a function that takes boolean => string. */
|
|
65
|
-
const conditionPlugin =
|
|
93
|
+
const conditionPlugin = TREE_SHAKE_CONDITION ? fallbackPlugin : {
|
|
66
94
|
id: "condition-plugin",
|
|
67
95
|
canHandle: (node) => typeof node === "object" && node?.nodeType === NodeTypes.CONDITION,
|
|
68
96
|
transform: (node, props, deepTransformNode) => {
|
|
@@ -86,7 +114,7 @@ const conditionPlugin = process.env.INTLAYER_NODE_TYPE_CONDITION === "false" ? f
|
|
|
86
114
|
}
|
|
87
115
|
};
|
|
88
116
|
/** Insertion plugin. Replaces node with a function that takes quantity => string. */
|
|
89
|
-
const insertionPlugin =
|
|
117
|
+
const insertionPlugin = TREE_SHAKE_INSERTION ? fallbackPlugin : {
|
|
90
118
|
id: "insertion-plugin",
|
|
91
119
|
canHandle: (node) => typeof node === "object" && node?.nodeType === NodeTypes.INSERTION,
|
|
92
120
|
transform: (node, props, deepTransformNode) => {
|
|
@@ -121,7 +149,7 @@ const insertionPlugin = process.env.INTLAYER_NODE_TYPE_INSERTION === "false" ? f
|
|
|
121
149
|
}
|
|
122
150
|
};
|
|
123
151
|
/** Gender plugin. Replaces node with a function that takes gender => string. */
|
|
124
|
-
const genderPlugin =
|
|
152
|
+
const genderPlugin = TREE_SHAKE_GENDER ? fallbackPlugin : {
|
|
125
153
|
id: "gender-plugin",
|
|
126
154
|
canHandle: (node) => typeof node === "object" && node?.nodeType === NodeTypes.GENDER,
|
|
127
155
|
transform: (node, props, deepTransformNode) => {
|
|
@@ -141,7 +169,7 @@ const genderPlugin = process.env.INTLAYER_NODE_TYPE_GENDER === "false" ? fallbac
|
|
|
141
169
|
}
|
|
142
170
|
};
|
|
143
171
|
/** Nested plugin. Replaces node with the result of `getNesting`. */
|
|
144
|
-
const nestedPlugin = (locale) =>
|
|
172
|
+
const nestedPlugin = (locale) => TREE_SHAKE_NESTED ? fallbackPlugin : {
|
|
145
173
|
id: "nested-plugin",
|
|
146
174
|
canHandle: (node) => typeof node === "object" && (node?.nodeType === NodeTypes.NESTED || node?.nodeType === "n"),
|
|
147
175
|
transform: (node, props) => getNesting(node[NodeTypes.NESTED].dictionaryKey, node[NodeTypes.NESTED].path, {
|
|
@@ -150,7 +178,7 @@ const nestedPlugin = (locale) => process.env.INTLAYER_NODE_TYPE_NESTED === "fals
|
|
|
150
178
|
})
|
|
151
179
|
};
|
|
152
180
|
/** File plugin. Replaces node with the result of `getNesting`. */
|
|
153
|
-
const filePlugin =
|
|
181
|
+
const filePlugin = TREE_SHAKE_FILE ? fallbackPlugin : {
|
|
154
182
|
id: "file-plugin",
|
|
155
183
|
canHandle: (node) => typeof node === "object" && node?.nodeType === NodeTypes.FILE,
|
|
156
184
|
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/** ---------------------------------------------\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 result = {\n ...(node[NodeTypes.TRANSLATION] ?? {}),\n };\n\n for (const key in result) {\n const childProps = {\n ...props,\n children: result[key as keyof typeof result],\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.TRANSLATION, key } as KeyPath,\n ],\n };\n result[key as keyof typeof result] = deepTransformNode(\n result[key as keyof typeof result],\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 result = { ...node[NodeTypes.ENUMERATION] };\n\n for (const key in result) {\n const child = result[key as unknown as keyof typeof result];\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 as unknown as keyof typeof result] = deepTransformNode(\n child,\n childProps\n );\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 result = { ...node[NodeTypes.CONDITION] };\n\n for (const key in result) {\n const child = result[key as keyof typeof result];\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 as unknown as keyof typeof result] = deepTransformNode(\n child,\n childProps\n );\n }\n\n return (arg: boolean | { value: boolean }) => {\n const value = typeof arg === 'boolean' ? arg : arg.value;\n const subResult = getCondition(result, 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]: string;\n fields: readonly string[];\n}\n ? (\n values: {\n [K in T['fields'][number]]: string | number;\n }\n ) => DeepTransformContent<string, 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 result = { ...node[NodeTypes.GENDER] };\n\n for (const key in result) {\n const child = result[key as keyof typeof result];\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 as keyof typeof result] = deepTransformNode(\n child,\n childProps\n );\n }\n\n return (value: Gender) => getGender(result, 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\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":";;;;;;;;;;;;;;AAqDA,MAAa,iBAA0B;CACrC,IAAI;CACJ,iBAAiB;CACjB,YAAY,SAAS;CACtB;;AAmCD,MAAa,qBACX,QACA,aAEA,QAAQ,IAAI,mCAAmC,UAC3C,iBACA;CACE,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAa,UAAU;CAC3D,YAAY,MAA0B,OAAO,sBAAsB;EACjE,MAAM,SAAS,EACb,GAAI,KAAK,UAAU,gBAAgB,EAAE,EACtC;AAED,OAAK,MAAM,OAAO,QAAQ;GACxB,MAAM,aAAa;IACjB,GAAG;IACH,UAAU,OAAO;IACjB,SAAS,CACP,GAAG,MAAM,SACT;KAAE,MAAM,UAAU;KAAa;KAAK,CACrC;IACF;AACD,UAAO,OAA8B,kBACnC,OAAO,MACP,WACD;;AAGH,SAAO,eAAe,QAAQ,QAAQ,SAAS;;CAElD;;AAmBP,MAAa,oBACX,QAAQ,IAAI,mCAAmC,UAC3C,iBACA;CACE,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAa,UAAU;CAC3D,YAAY,MAA0B,OAAO,sBAAsB;EACjE,MAAM,SAAS,EAAE,GAAG,KAAK,UAAU,cAAc;AAEjD,OAAK,MAAM,OAAO,QAAQ;GACxB,MAAM,QAAQ,OAAO;AASrB,UAAO,OAAyC,kBAC9C,OATiB;IACjB,GAAG;IACH,UAAU;IACV,SAAS,CACP,GAAG,MAAM,SACT;KAAE,MAAM,UAAU;KAAa;KAAK,CACrC;IACF,CAIA;;AAGH,UAAQ,QAAoC;GAE1C,MAAM,YAAY,eAAe,QADhB,OAAO,QAAQ,WAAW,MAAM,IAAI,MACH;AAElD,OAAI,OAAO,cAAc,cAAc,OAAO,QAAQ,SACpD,QAAO,UAAU,IAAI;AAGvB,UAAO;;;CAGZ;;AAmBP,MAAa,kBACX,QAAQ,IAAI,iCAAiC,UACzC,iBACA;CACE,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAa,UAAU;CAC3D,YAAY,MAAwB,OAAO,sBAAsB;EAC/D,MAAM,SAAS,EAAE,GAAG,KAAK,UAAU,YAAY;AAE/C,OAAK,MAAM,OAAO,QAAQ;GACxB,MAAM,QAAQ,OAAO;AASrB,UAAO,OAAyC,kBAC9C,OATiB;IACjB,GAAG;IACH,UAAU;IACV,SAAS,CACP,GAAG,MAAM,SACT;KAAE,MAAM,UAAU;KAAW;KAAK,CACnC;IACF,CAIA;;AAGH,UAAQ,QAAsC;GAE5C,MAAM,YAAY,aAAa,QADjB,OAAO,QAAQ,YAAY,MAAM,IAAI,MACN;AAE7C,OAAI,OAAO,cAAc,cAAc,OAAO,QAAQ,SACpD,QAAO,UAAU,IAAI;AAGvB,UAAO;;;CAGZ;;AAmBP,MAAa,kBACX,QAAQ,IAAI,iCAAiC,UACzC,iBACA;CACE,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAa,UAAU;CAC3D,YAAY,MAAwB,OAAO,sBAAsB;EAC/D,MAAM,aAAwB,CAC5B,GAAG,MAAM,SACT,EACE,MAAM,UAAU,WACjB,CACF;EAED,MAAM,WAAW,KAAK,UAAU;;EAGhC,MAAM,wBAAiC;GACrC,IAAI;GACJ,YAAY,SAAS,OAAO,SAAS;GACrC,YAAY,MAAc,UAAU,sBAAsB;IACxD,MAAM,oBAAoB,kBAAkB,MAAM;KAChD,GAAG;KACH,UAAU;KACV,SAAS,CACP,IAAI,MAAM,WAAY,EAAE,EAAgB,QACrC,WAAW,OAAO,OAAO,uBAC3B,CACF;KACF,CAAC;AAEF,YACE,WAGG;KACH,MAAM,WAAW,aAAa,mBAAmB,OAAO;AAExD,YAAO,kBAAkB,UAAU;MACjC,GAAG;MACH,SAAS,MAAM;MACf;MACD,CAAC;;;GAGP;AAED,SAAO,kBAAkB,UAAU;GACjC,GAAG;GACH;GACA,SAAS;GACT,SAAS,CAAC,uBAAuB,GAAI,MAAM,WAAW,EAAE,CAAE;GAC3D,CAAC;;CAEL;;AAmBP,MAAa,eACX,QAAQ,IAAI,8BAA8B,UACtC,iBACA;CACE,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAa,UAAU;CAC3D,YAAY,MAAqB,OAAO,sBAAsB;EAC5D,MAAM,SAAS,EAAE,GAAG,KAAK,UAAU,SAAS;AAE5C,OAAK,MAAM,OAAO,QAAQ;GACxB,MAAM,QAAQ,OAAO;AASrB,UAAO,OAA8B,kBACnC,OATiB;IACjB,GAAG;IACH,UAAU;IACV,SAAS,CACP,GAAG,MAAM,SACT;KAAE,MAAM,UAAU;KAAQ;KAAK,CAChC;IACF,CAIA;;AAGH,UAAQ,UAAkB,UAAU,QAAQ,MAAM;;CAErD;;AAmBP,MAAa,gBAAgB,WAC3B,QAAQ,IAAI,8BAA8B,UACtC,iBACA;CACE,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,aACf,MAAM,aAAa,UAAU,UAAU,MAAM,aAAa;CAC7D,YAAY,MAAqB,UAC/B,WACE,KAAK,UAAU,QAAQ,eACvB,KAAK,UAAU,QAAQ,MACvB;EACE,GAAG;EACH,QAAS,UAAU,MAAM;EAC1B,CACF;CACJ;;AAeP,MAAa,aACX,QAAQ,IAAI,4BAA4B,UACpC,iBACA;CACE,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAa,UAAU;CAC3D,YAAY,MAAmB,OAAO,kBACpC,cAAc,KAAK,SAAS;EAC1B,GAAG;EACH,UAAU,KAAK;EAChB,CAAC;CACL"}
|
|
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 result = {\n ...(node[NodeTypes.TRANSLATION] ?? {}),\n };\n\n for (const key in result) {\n const childProps = {\n ...props,\n children: result[key as keyof typeof result],\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.TRANSLATION, key } as KeyPath,\n ],\n };\n result[key as keyof typeof result] = deepTransformNode(\n result[key as keyof typeof result],\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 result = { ...node[NodeTypes.ENUMERATION] };\n\n for (const key in result) {\n const child = result[key as unknown as keyof typeof result];\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 as unknown as keyof typeof result] = deepTransformNode(\n child,\n childProps\n );\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 result = { ...node[NodeTypes.CONDITION] };\n\n for (const key in result) {\n const child = result[key as keyof typeof result];\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 as unknown as keyof typeof result] = deepTransformNode(\n child,\n childProps\n );\n }\n\n return (arg: boolean | { value: boolean }) => {\n const value = typeof arg === 'boolean' ? arg : arg.value;\n const subResult = getCondition(result, 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]: string;\n fields: readonly string[];\n}\n ? (\n values: {\n [K in T['fields'][number]]: string | number;\n }\n ) => DeepTransformContent<string, 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 result = { ...node[NodeTypes.GENDER] };\n\n for (const key in result) {\n const child = result[key as keyof typeof result];\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 as keyof typeof result] = deepTransformNode(\n child,\n childProps\n );\n }\n\n return (value: Gender) => getGender(result, 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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"}
|
|
@@ -3,10 +3,17 @@ import { getPathWithoutLocale } from "./getPathWithoutLocale.mjs";
|
|
|
3
3
|
import { getPrefix, resolveRoutingConfig } from "./getPrefix.mjs";
|
|
4
4
|
import { getCanonicalPath, getLocalizedPath, getRewriteRules } from "./rewriteUtils.mjs";
|
|
5
5
|
import configuration from "@intlayer/config/built";
|
|
6
|
-
import { TREE_SHAKE_NO_PREFIX, TREE_SHAKE_SEARCH_PARAMS } from "@intlayer/config/envVars";
|
|
7
6
|
|
|
8
7
|
//#region src/localization/getLocalizedUrl.ts
|
|
9
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
|
+
/**
|
|
10
17
|
* Generate URL by prefixing the given URL with the referenced locale or adding search parameters
|
|
11
18
|
* based on the routing mode. Handles both absolute and relative URLs appropriately.
|
|
12
19
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getLocalizedUrl.mjs","names":[],"sources":["../../../src/localization/getLocalizedUrl.ts"],"sourcesContent":["import configuration from '@intlayer/config/built';\
|
|
1
|
+
{"version":3,"file":"getLocalizedUrl.mjs","names":[],"sources":["../../../src/localization/getLocalizedUrl.ts"],"sourcesContent":["import configuration 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\n/**\n * True when the build-time routing mode is known and is NOT 'no-prefix'.\n */\nconst TREE_SHAKE_NO_PREFIX =\n process.env['INTLAYER_ROUTING_MODE'] &&\n process.env['INTLAYER_ROUTING_MODE'] !== 'no-prefix';\n\n/**\n * True when the build-time routing mode is known and is NOT 'search-params'.\n */\nconst TREE_SHAKE_SEARCH_PARAMS =\n process.env['INTLAYER_ROUTING_MODE'] &&\n process.env['INTLAYER_ROUTING_MODE'] !== 'search-params';\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/**\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 * @returns The localized URL for the current locale.\n */\nexport const getLocalizedUrl = (\n url: string,\n currentLocale: LocalesValues = configuration?.internationalization\n ?.defaultLocale,\n options: RoutingOptions = {}\n): string => {\n const { defaultLocale, mode, locales, rewrite } =\n resolveRoutingConfig(options);\n\n const urlWithoutLocale = getPathWithoutLocale(url, locales);\n const rewriteRules = getRewriteRules(rewrite, 'url');\n\n if (!TREE_SHAKE_NO_PREFIX && mode === 'no-prefix') {\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 const baseUrl = isAbsoluteUrl\n ? `${parsedUrl.protocol}//${parsedUrl.host}`\n : '';\n\n if (!TREE_SHAKE_SEARCH_PARAMS && mode === 'search-params') {\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, { defaultLocale, mode, locales });\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":";;;;;;;;;;AASA,MAAM,uBACJ,QAAQ,IAAI,4BACZ,QAAQ,IAAI,6BAA6B;;;;AAK3C,MAAM,2BACJ,QAAQ,IAAI,4BACZ,QAAQ,IAAI,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuD3C,MAAa,mBACX,KACA,gBAA+B,eAAe,sBAC1C,eACJ,UAA0B,EAAE,KACjB;CACX,MAAM,EAAE,eAAe,MAAM,SAAS,YACpC,qBAAqB,QAAQ;CAE/B,MAAM,mBAAmB,qBAAqB,KAAK,QAAQ;CAC3D,MAAM,eAAe,gBAAgB,SAAS,MAAM;AAEpD,KAAI,CAAC,wBAAwB,SAAS,YACpC,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;CAEF,MAAM,UAAU,gBACZ,GAAG,UAAU,SAAS,IAAI,UAAU,SACpC;AAEJ,KAAI,CAAC,4BAA4B,SAAS,iBAAiB;EACzD,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;EAAE;EAAe;EAAM;EAAS,CAAC;CAE7E,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"}
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import { checkIsURLAbsolute } from "../utils/checkIsURLAbsolute.mjs";
|
|
2
2
|
import configuration from "@intlayer/config/built";
|
|
3
|
-
import { TREE_SHAKE_PREFIX_MODES, TREE_SHAKE_SEARCH_PARAMS } from "@intlayer/config/envVars";
|
|
4
3
|
|
|
5
4
|
//#region src/localization/getPathWithoutLocale.ts
|
|
6
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 the build-time routing mode is known and is NOT 'search-params'.
|
|
12
|
+
*/
|
|
13
|
+
const TREE_SHAKE_SEARCH_PARAMS = process.env["INTLAYER_ROUTING_MODE"] && process.env["INTLAYER_ROUTING_MODE"] !== "search-params";
|
|
14
|
+
/**
|
|
7
15
|
* Removes the locale segment from the given URL or pathname if present.
|
|
8
16
|
* Also removes locale from search parameters if present.
|
|
9
17
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getPathWithoutLocale.mjs","names":[],"sources":["../../../src/localization/getPathWithoutLocale.ts"],"sourcesContent":["import configuration from '@intlayer/config/built';\
|
|
1
|
+
{"version":3,"file":"getPathWithoutLocale.mjs","names":[],"sources":["../../../src/localization/getPathWithoutLocale.ts"],"sourcesContent":["import configuration 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\n/**\n * True when the build-time routing mode is known and is not a prefix-based\n * mode (neither 'prefix-all' nor 'prefix-no-default').\n */\nconst TREE_SHAKE_PREFIX_MODES =\n process.env['INTLAYER_ROUTING_MODE'] &&\n process.env['INTLAYER_ROUTING_MODE'] !== 'prefix-all' &&\n process.env['INTLAYER_ROUTING_MODE'] !== 'prefix-no-default';\n\n/**\n * True when the build-time routing mode is known and is NOT 'search-params'.\n */\nconst TREE_SHAKE_SEARCH_PARAMS =\n process.env['INTLAYER_ROUTING_MODE'] &&\n process.env['INTLAYER_ROUTING_MODE'] !== 'search-params';\n\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { checkIsURLAbsolute } from '../utils/checkIsURLAbsolute';\n\n/**\n * Removes the locale segment from the given URL or pathname if present.\n * Also removes locale from search parameters if present.\n *\n * This function get the locales from the configuration if not provided.\n *\n * Example:\n *\n * ```ts\n * getPathWithoutLocale('/en/dashboard') // Returns '/dashboard'\n * getPathWithoutLocale('/fr/dashboard') // Returns '/dashboard'\n * getPathWithoutLocale('/dashboard') // Returns '/dashboard'\n * getPathWithoutLocale('dashboard') // Returns 'dashboard'\n * getPathWithoutLocale('/dashboard?locale=fr') // Returns '/dashboard'\n * getPathWithoutLocale('https://example.com/en/dashboard') // Returns 'https://example.com/dashboard'\n * getPathWithoutLocale('https://example.com/fr/dashboard') // Returns 'https://example.com/dashboard'\n * getPathWithoutLocale('https://example.com/dashboard') // Returns 'https://example.com/dashboard'\n * getPathWithoutLocale('https://example.com/dashboard?locale=fr') // Returns 'https://example.com/dashboard'\n * ```\n *\n * @param inputUrl - The complete URL string or pathname to process.\n * @param locales - Optional array of supported locales. Defaults to `localesDefault`.\n * @returns The URL string or pathname without the locale segment or locale search parameter.\n */\nexport const getPathWithoutLocale = (\n inputUrl: string,\n locales: LocalesValues[] = configuration?.internationalization?.locales\n): string => {\n // Determine if the original URL is absolute (includes protocol)\n const isAbsoluteUrl = checkIsURLAbsolute(inputUrl);\n\n let fixedInputUrl = inputUrl;\n\n if (inputUrl?.endsWith('/')) {\n fixedInputUrl = inputUrl.slice(0, -1);\n }\n\n // Initialize a URL object if the URL is absolute\n // For relative URLs, use a dummy base to leverage the URL API\n const url = isAbsoluteUrl\n ? new URL(fixedInputUrl)\n : new URL(fixedInputUrl, 'http://example.com');\n\n const pathname = url.pathname;\n\n // Ensure the pathname starts with '/'\n if (!pathname.startsWith('/')) {\n // If not, return the URL as is\n url.pathname = `/${pathname}`;\n }\n\n // Only strip locale path prefix in prefix-based routing modes\n if (!TREE_SHAKE_PREFIX_MODES) {\n // Split the pathname to extract the first segment\n const pathSegments = pathname.split('/');\n const firstSegment = pathSegments[1]; // The segment after the first '/'\n\n // Check if the first segment is a supported locale\n if (locales?.includes(firstSegment as LocalesValues)) {\n // Remove the locale segment from the pathname\n pathSegments.splice(1, 1); // Remove the first segment\n\n // Reconstruct the pathname\n const newPathname = pathSegments.join('/') ?? '/';\n url.pathname = newPathname;\n }\n }\n\n // Only strip locale from search parameters in search-params routing mode\n if (!TREE_SHAKE_SEARCH_PARAMS) {\n const searchParams = new URLSearchParams(url.search);\n if (searchParams.has('locale')) {\n searchParams.delete('locale');\n url.search = searchParams.toString();\n }\n }\n\n if (isAbsoluteUrl) {\n // Return the modified URL as a string\n return url.toString();\n }\n\n // Return the modified URL as a string\n return url.toString().replace('http://example.com', '');\n};\n"],"mappings":";;;;;;;;AAUA,MAAM,0BACJ,QAAQ,IAAI,4BACZ,QAAQ,IAAI,6BAA6B,gBACzC,QAAQ,IAAI,6BAA6B;;;;AAK3C,MAAM,2BACJ,QAAQ,IAAI,4BACZ,QAAQ,IAAI,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;AA6B3C,MAAa,wBACX,UACA,UAA2B,eAAe,sBAAsB,YACrD;CAEX,MAAM,gBAAgB,mBAAmB,SAAS;CAElD,IAAI,gBAAgB;AAEpB,KAAI,UAAU,SAAS,IAAI,CACzB,iBAAgB,SAAS,MAAM,GAAG,GAAG;CAKvC,MAAM,MAAM,gBACR,IAAI,IAAI,cAAc,GACtB,IAAI,IAAI,eAAe,qBAAqB;CAEhD,MAAM,WAAW,IAAI;AAGrB,KAAI,CAAC,SAAS,WAAW,IAAI,CAE3B,KAAI,WAAW,IAAI;AAIrB,KAAI,CAAC,yBAAyB;EAE5B,MAAM,eAAe,SAAS,MAAM,IAAI;EACxC,MAAM,eAAe,aAAa;AAGlC,MAAI,SAAS,SAAS,aAA8B,EAAE;AAEpD,gBAAa,OAAO,GAAG,EAAE;AAIzB,OAAI,WADgB,aAAa,KAAK,IAAI,IAAI;;;AAMlD,KAAI,CAAC,0BAA0B;EAC7B,MAAM,eAAe,IAAI,gBAAgB,IAAI,OAAO;AACpD,MAAI,aAAa,IAAI,SAAS,EAAE;AAC9B,gBAAa,OAAO,SAAS;AAC7B,OAAI,SAAS,aAAa,UAAU;;;AAIxC,KAAI,cAEF,QAAO,IAAI,UAAU;AAIvB,QAAO,IAAI,UAAU,CAAC,QAAQ,sBAAsB,GAAG"}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import configuration from "@intlayer/config/built";
|
|
2
|
-
import { TREE_SHAKE_PREFIX_MODES } from "@intlayer/config/envVars";
|
|
3
2
|
import { DEFAULT_LOCALE, LOCALES, ROUTING_MODE } from "@intlayer/config/defaultValues";
|
|
4
3
|
|
|
5
4
|
//#region src/localization/getPrefix.ts
|
|
6
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
|
+
/**
|
|
7
11
|
* Resolves routing configuration by merging provided options with configuration defaults.
|
|
8
12
|
* Single source of truth for default routing config resolution across all localization functions.
|
|
9
13
|
*/
|