@intlayer/core 7.4.0 → 7.5.0-canary.0
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/localization/getLocale.cjs +3 -4
- package/dist/cjs/localization/getLocale.cjs.map +1 -1
- package/dist/cjs/localization/getLocalizedUrl.cjs +2 -1
- package/dist/cjs/localization/getLocalizedUrl.cjs.map +1 -1
- package/dist/cjs/messageFormat/ICU.cjs +309 -0
- package/dist/cjs/messageFormat/ICU.cjs.map +1 -0
- package/dist/cjs/messageFormat/i18next.cjs +320 -0
- package/dist/cjs/messageFormat/i18next.cjs.map +1 -0
- package/dist/cjs/messageFormat/index.cjs +10 -0
- package/dist/cjs/messageFormat/vue-i18n.cjs +166 -0
- package/dist/cjs/messageFormat/vue-i18n.cjs.map +1 -0
- package/dist/esm/localization/getLocale.mjs +1 -2
- package/dist/esm/localization/getLocale.mjs.map +1 -1
- package/dist/esm/localization/getLocalizedUrl.mjs +2 -1
- package/dist/esm/localization/getLocalizedUrl.mjs.map +1 -1
- package/dist/esm/messageFormat/ICU.mjs +307 -0
- package/dist/esm/messageFormat/ICU.mjs.map +1 -0
- package/dist/esm/messageFormat/i18next.mjs +318 -0
- package/dist/esm/messageFormat/i18next.mjs.map +1 -0
- package/dist/esm/messageFormat/index.mjs +5 -0
- package/dist/esm/messageFormat/vue-i18n.mjs +164 -0
- package/dist/esm/messageFormat/vue-i18n.mjs.map +1 -0
- package/dist/types/deepTransformPlugins/getFilterMissingTranslationsContent.d.ts +8 -7
- package/dist/types/deepTransformPlugins/getFilterMissingTranslationsContent.d.ts.map +1 -1
- package/dist/types/deepTransformPlugins/getFilterTranslationsOnlyContent.d.ts +8 -7
- package/dist/types/deepTransformPlugins/getFilterTranslationsOnlyContent.d.ts.map +1 -1
- package/dist/types/deepTransformPlugins/getFilteredLocalesContent.d.ts +8 -7
- package/dist/types/deepTransformPlugins/getFilteredLocalesContent.d.ts.map +1 -1
- package/dist/types/dictionaryManipulator/orderDictionaries.d.ts +2 -2
- package/dist/types/dictionaryManipulator/orderDictionaries.d.ts.map +1 -1
- package/dist/types/interpreter/getContent/plugins.d.ts.map +1 -1
- package/dist/types/messageFormat/ICU.d.ts +11 -0
- package/dist/types/messageFormat/ICU.d.ts.map +1 -0
- package/dist/types/messageFormat/i18next.d.ts +9 -0
- package/dist/types/messageFormat/i18next.d.ts.map +1 -0
- package/dist/types/messageFormat/index.d.ts +4 -0
- package/dist/types/messageFormat/vue-i18n.d.ts +9 -0
- package/dist/types/messageFormat/vue-i18n.d.ts.map +1 -0
- package/dist/types/transpiler/translation/translation.d.ts +1 -1
- package/dist/types/transpiler/translation/translation.d.ts.map +1 -1
- package/package.json +11 -6
- package/dist/cjs/dist/esm/getStorageAttributes.cjs +0 -134
- package/dist/cjs/dist/esm/getStorageAttributes.cjs.map +0 -1
- package/dist/cjs/dist/esm/localization/localeResolver.cjs +0 -28
- package/dist/cjs/dist/esm/localization/localeResolver.cjs.map +0 -1
- package/dist/cjs/dist/esm/utils/getCookie.cjs +0 -32
- package/dist/cjs/dist/esm/utils/getCookie.cjs.map +0 -1
- package/dist/cjs/dist/esm/utils/localeStorage.cjs +0 -61
- package/dist/cjs/dist/esm/utils/localeStorage.cjs.map +0 -1
- package/dist/cjs/localization/isValidLocale.cjs +0 -54
- package/dist/cjs/localization/isValidLocale.cjs.map +0 -1
- package/dist/esm/dist/esm/getStorageAttributes.mjs +0 -133
- package/dist/esm/dist/esm/getStorageAttributes.mjs.map +0 -1
- package/dist/esm/dist/esm/localization/localeResolver.mjs +0 -26
- package/dist/esm/dist/esm/localization/localeResolver.mjs.map +0 -1
- package/dist/esm/dist/esm/utils/getCookie.mjs +0 -31
- package/dist/esm/dist/esm/utils/getCookie.mjs.map +0 -1
- package/dist/esm/dist/esm/utils/localeStorage.mjs +0 -59
- package/dist/esm/dist/esm/utils/localeStorage.mjs.map +0 -1
- package/dist/esm/localization/isValidLocale.mjs +0 -52
- package/dist/esm/localization/isValidLocale.mjs.map +0 -1
- package/dist/types/localization/isValidLocale.d.ts +0 -35
- package/dist/types/localization/isValidLocale.d.ts.map +0 -1
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_interpreter_getContent_deepTransform = require('../interpreter/getContent/deepTransform.cjs');
|
|
3
|
+
const require_transpiler_enumeration_enumeration = require('../transpiler/enumeration/enumeration.cjs');
|
|
4
|
+
const require_transpiler_gender_gender = require('../transpiler/gender/gender.cjs');
|
|
5
|
+
const require_transpiler_insertion_insertion = require('../transpiler/insertion/insertion.cjs');
|
|
6
|
+
let __intlayer_types = require("@intlayer/types");
|
|
7
|
+
|
|
8
|
+
//#region src/messageFormat/i18next.ts
|
|
9
|
+
const parseI18Next = (text) => {
|
|
10
|
+
let index = 0;
|
|
11
|
+
const parseNodes = () => {
|
|
12
|
+
const nodes = [];
|
|
13
|
+
let currentText = "";
|
|
14
|
+
while (index < text.length) {
|
|
15
|
+
const char = text[index];
|
|
16
|
+
if (char === "{" && text[index + 1] === "{") {
|
|
17
|
+
if (currentText) {
|
|
18
|
+
nodes.push(currentText);
|
|
19
|
+
currentText = "";
|
|
20
|
+
}
|
|
21
|
+
index += 2;
|
|
22
|
+
nodes.push(parseStandardArgument());
|
|
23
|
+
} else if (char === "{") {
|
|
24
|
+
if (currentText) {
|
|
25
|
+
nodes.push(currentText);
|
|
26
|
+
currentText = "";
|
|
27
|
+
}
|
|
28
|
+
index++;
|
|
29
|
+
nodes.push(parseICUArgument());
|
|
30
|
+
} else if (char === "}") break;
|
|
31
|
+
else {
|
|
32
|
+
currentText += char;
|
|
33
|
+
index++;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (currentText) nodes.push(currentText);
|
|
37
|
+
return nodes;
|
|
38
|
+
};
|
|
39
|
+
const parseStandardArgument = () => {
|
|
40
|
+
let name = "";
|
|
41
|
+
while (index < text.length) {
|
|
42
|
+
if (text[index] === "}" && text[index + 1] === "}") {
|
|
43
|
+
index += 2;
|
|
44
|
+
return {
|
|
45
|
+
type: "argument",
|
|
46
|
+
name: name.trim()
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
name += text[index];
|
|
50
|
+
index++;
|
|
51
|
+
}
|
|
52
|
+
throw new Error("Unclosed i18next variable");
|
|
53
|
+
};
|
|
54
|
+
const parseICUArgument = () => {
|
|
55
|
+
let name = "";
|
|
56
|
+
while (index < text.length && /[^,}]/.test(text[index])) {
|
|
57
|
+
name += text[index];
|
|
58
|
+
index++;
|
|
59
|
+
}
|
|
60
|
+
name = name.trim();
|
|
61
|
+
if (index >= text.length) throw new Error("Unclosed argument");
|
|
62
|
+
if (text[index] === "}") {
|
|
63
|
+
index++;
|
|
64
|
+
return {
|
|
65
|
+
type: "argument",
|
|
66
|
+
name
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (text[index] === ",") {
|
|
70
|
+
index++;
|
|
71
|
+
let type = "";
|
|
72
|
+
while (index < text.length && /[^,}]/.test(text[index])) {
|
|
73
|
+
type += text[index];
|
|
74
|
+
index++;
|
|
75
|
+
}
|
|
76
|
+
type = type.trim();
|
|
77
|
+
if (index >= text.length) throw new Error("Unclosed argument");
|
|
78
|
+
if (text[index] === "}") {
|
|
79
|
+
index++;
|
|
80
|
+
return {
|
|
81
|
+
type: "argument",
|
|
82
|
+
name,
|
|
83
|
+
format: { type }
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
if (text[index] === ",") {
|
|
87
|
+
index++;
|
|
88
|
+
if (type === "plural" || type === "select") {
|
|
89
|
+
const options = {};
|
|
90
|
+
while (index < text.length && text[index] !== "}") {
|
|
91
|
+
while (index < text.length && /\s/.test(text[index])) index++;
|
|
92
|
+
let key = "";
|
|
93
|
+
while (index < text.length && /[^{\s]/.test(text[index])) {
|
|
94
|
+
key += text[index];
|
|
95
|
+
index++;
|
|
96
|
+
}
|
|
97
|
+
while (index < text.length && /\s/.test(text[index])) index++;
|
|
98
|
+
if (text[index] !== "{") throw new Error("Expected { after option key");
|
|
99
|
+
index++;
|
|
100
|
+
const value = parseNodes();
|
|
101
|
+
if (text[index] !== "}") throw new Error("Expected } after option value");
|
|
102
|
+
index++;
|
|
103
|
+
options[key] = value;
|
|
104
|
+
while (index < text.length && /\s/.test(text[index])) index++;
|
|
105
|
+
}
|
|
106
|
+
index++;
|
|
107
|
+
if (type === "plural") return {
|
|
108
|
+
type: "plural",
|
|
109
|
+
name,
|
|
110
|
+
options
|
|
111
|
+
};
|
|
112
|
+
else if (type === "select") return {
|
|
113
|
+
type: "select",
|
|
114
|
+
name,
|
|
115
|
+
options
|
|
116
|
+
};
|
|
117
|
+
} else {
|
|
118
|
+
let style = "";
|
|
119
|
+
while (index < text.length && text[index] !== "}") {
|
|
120
|
+
style += text[index];
|
|
121
|
+
index++;
|
|
122
|
+
}
|
|
123
|
+
if (index >= text.length) throw new Error("Unclosed argument");
|
|
124
|
+
style = style.trim();
|
|
125
|
+
index++;
|
|
126
|
+
return {
|
|
127
|
+
type: "argument",
|
|
128
|
+
name,
|
|
129
|
+
format: {
|
|
130
|
+
type,
|
|
131
|
+
style
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
throw new Error("Malformed argument");
|
|
138
|
+
};
|
|
139
|
+
return parseNodes();
|
|
140
|
+
};
|
|
141
|
+
const i18nextNodesToIntlayer = (nodes) => {
|
|
142
|
+
if (nodes.length === 0) return "";
|
|
143
|
+
if (nodes.length === 1 && typeof nodes[0] === "string") return nodes[0];
|
|
144
|
+
if (nodes.every((node) => typeof node === "string" || node.type === "argument")) {
|
|
145
|
+
let str = "";
|
|
146
|
+
for (const node of nodes) if (typeof node === "string") str += node;
|
|
147
|
+
else if (typeof node !== "string" && node.type === "argument") if (node.format) str += `{${node.name}, ${node.format.type}${node.format.style ? `, ${node.format.style}` : ""}}`;
|
|
148
|
+
else str += `{{${node.name}}}`;
|
|
149
|
+
return require_transpiler_insertion_insertion.insert(str);
|
|
150
|
+
}
|
|
151
|
+
if (nodes.length === 1) {
|
|
152
|
+
const node = nodes[0];
|
|
153
|
+
if (typeof node === "string") return node;
|
|
154
|
+
if (node.type === "argument") {
|
|
155
|
+
if (node.format) return require_transpiler_insertion_insertion.insert(`{${node.name}, ${node.format.type}${node.format.style ? `, ${node.format.style}` : ""}}`);
|
|
156
|
+
return require_transpiler_insertion_insertion.insert(`{{${node.name}}}`);
|
|
157
|
+
}
|
|
158
|
+
if (node.type === "plural") {
|
|
159
|
+
const options = {};
|
|
160
|
+
for (const [key, val] of Object.entries(node.options)) {
|
|
161
|
+
let newKey = key;
|
|
162
|
+
if (key.startsWith("=")) newKey = key.substring(1);
|
|
163
|
+
else if (key === "one") newKey = "1";
|
|
164
|
+
else if (key === "two") newKey = "2";
|
|
165
|
+
else if (key === "few") newKey = "<=3";
|
|
166
|
+
else if (key === "many") newKey = ">=4";
|
|
167
|
+
else if (key === "other") newKey = "fallback";
|
|
168
|
+
options[newKey] = i18nextNodesToIntlayer(val.map((v) => {
|
|
169
|
+
if (typeof v === "string") return v.replace(/#/g, `{{${node.name}}}`);
|
|
170
|
+
return v;
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
173
|
+
options.__intlayer_icu_var = node.name;
|
|
174
|
+
return require_transpiler_enumeration_enumeration.enu(options);
|
|
175
|
+
}
|
|
176
|
+
if (node.type === "select") {
|
|
177
|
+
const options = {};
|
|
178
|
+
for (const [key, val] of Object.entries(node.options)) options[key] = i18nextNodesToIntlayer(val);
|
|
179
|
+
const optionKeys = Object.keys(options);
|
|
180
|
+
if ((options.male || options.female) && optionKeys.every((k) => [
|
|
181
|
+
"male",
|
|
182
|
+
"female",
|
|
183
|
+
"other",
|
|
184
|
+
"fallback"
|
|
185
|
+
].includes(k))) return require_transpiler_gender_gender.gender({
|
|
186
|
+
fallback: options.other,
|
|
187
|
+
male: options.male,
|
|
188
|
+
female: options.female
|
|
189
|
+
});
|
|
190
|
+
options.__intlayer_icu_var = node.name;
|
|
191
|
+
return require_transpiler_enumeration_enumeration.enu(options);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return nodes.map((node) => i18nextNodesToIntlayer([node]));
|
|
195
|
+
};
|
|
196
|
+
const i18nextToIntlayerPlugin = {
|
|
197
|
+
canHandle: (node) => typeof node === "string" && (node.includes("{") || node.includes("}")),
|
|
198
|
+
transform: (node) => {
|
|
199
|
+
try {
|
|
200
|
+
return i18nextNodesToIntlayer(parseI18Next(node));
|
|
201
|
+
} catch {
|
|
202
|
+
return node;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
const intlayerToI18nextPlugin = {
|
|
207
|
+
canHandle: (node) => typeof node === "string" || node && typeof node === "object" && (node.nodeType === __intlayer_types.NodeType.Insertion || node.nodeType === __intlayer_types.NodeType.Enumeration || node.nodeType === __intlayer_types.NodeType.Gender || node.nodeType === "composite") || Array.isArray(node),
|
|
208
|
+
transform: (node, props, next) => {
|
|
209
|
+
if (typeof node === "string") return node;
|
|
210
|
+
if (node.nodeType === __intlayer_types.NodeType.Insertion) {
|
|
211
|
+
if (node.insertion.match(/\{[^}]*,[^}]*\}/)) return node.insertion;
|
|
212
|
+
return node.insertion;
|
|
213
|
+
}
|
|
214
|
+
if (node.nodeType === __intlayer_types.NodeType.Enumeration) {
|
|
215
|
+
const options = node.enumeration;
|
|
216
|
+
const transformedOptions = {};
|
|
217
|
+
for (const [key, val] of Object.entries(options)) {
|
|
218
|
+
if (key === "__intlayer_icu_var") continue;
|
|
219
|
+
const childVal = next(val, props);
|
|
220
|
+
transformedOptions[key] = typeof childVal === "string" ? childVal : JSON.stringify(childVal);
|
|
221
|
+
}
|
|
222
|
+
let varName = options.__intlayer_icu_var || "count";
|
|
223
|
+
if (!options.__intlayer_icu_var) {
|
|
224
|
+
const fallbackVal = transformedOptions.fallback || transformedOptions.other || Object.values(transformedOptions)[0];
|
|
225
|
+
const match = fallbackVal.match(/\{\{([a-zA-Z0-9_]+)\}\}/) || fallbackVal.match(/\{([a-zA-Z0-9_]+)\}(?!,)/);
|
|
226
|
+
if (match) varName = match[1];
|
|
227
|
+
}
|
|
228
|
+
const keys = Object.keys(transformedOptions);
|
|
229
|
+
const pluralKeys = [
|
|
230
|
+
"1",
|
|
231
|
+
"2",
|
|
232
|
+
"<=3",
|
|
233
|
+
">=4",
|
|
234
|
+
"fallback",
|
|
235
|
+
"other",
|
|
236
|
+
"zero",
|
|
237
|
+
"one",
|
|
238
|
+
"two",
|
|
239
|
+
"few",
|
|
240
|
+
"many"
|
|
241
|
+
];
|
|
242
|
+
const isPlural = keys.every((k) => pluralKeys.includes(k) || /^[<>=]?\d+(\.\d+)?$/.test(k));
|
|
243
|
+
const parts = [];
|
|
244
|
+
if (isPlural) {
|
|
245
|
+
for (const [key, val] of Object.entries(transformedOptions)) {
|
|
246
|
+
let icuKey = key;
|
|
247
|
+
if (key === "fallback") icuKey = "other";
|
|
248
|
+
else if (key === "<=3") icuKey = "few";
|
|
249
|
+
else if (key === ">=4") icuKey = "many";
|
|
250
|
+
else if (/^\d+$/.test(key)) icuKey = `=${key}`;
|
|
251
|
+
let strVal = val;
|
|
252
|
+
strVal = strVal.replace(/\{\{([^}]+)\}\}/g, "{$1}");
|
|
253
|
+
strVal = strVal.replace(new RegExp(`\\{${varName}\\}`, "g"), "#");
|
|
254
|
+
parts.push(`${icuKey} {${strVal}}`);
|
|
255
|
+
}
|
|
256
|
+
return `{${varName}, plural, ${parts.join(" ")}}`;
|
|
257
|
+
} else {
|
|
258
|
+
const entries = Object.entries(transformedOptions).sort(([keyA], [keyB]) => {
|
|
259
|
+
if (keyA === "fallback" || keyA === "other") return 1;
|
|
260
|
+
if (keyB === "fallback" || keyB === "other") return -1;
|
|
261
|
+
return 0;
|
|
262
|
+
});
|
|
263
|
+
for (const [key, val] of entries) {
|
|
264
|
+
let icuKey = key;
|
|
265
|
+
if (key === "fallback") icuKey = "other";
|
|
266
|
+
let strVal = val;
|
|
267
|
+
strVal = strVal.replace(/\{\{([^}]+)\}\}/g, "{$1}");
|
|
268
|
+
parts.push(`${icuKey} {${strVal}}`);
|
|
269
|
+
}
|
|
270
|
+
return `{${varName}, select, ${parts.join(" ")}}`;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (node.nodeType === __intlayer_types.NodeType.Gender) {
|
|
274
|
+
const options = node.gender;
|
|
275
|
+
const varName = "gender";
|
|
276
|
+
const parts = [];
|
|
277
|
+
const entries = Object.entries(options).sort(([keyA], [keyB]) => {
|
|
278
|
+
if (keyA === "fallback") return 1;
|
|
279
|
+
if (keyB === "fallback") return -1;
|
|
280
|
+
return 0;
|
|
281
|
+
});
|
|
282
|
+
for (const [key, val] of entries) {
|
|
283
|
+
let icuKey = key;
|
|
284
|
+
if (key === "fallback") icuKey = "other";
|
|
285
|
+
const childVal = next(val, props);
|
|
286
|
+
let strVal = typeof childVal === "string" ? childVal : JSON.stringify(childVal);
|
|
287
|
+
strVal = strVal.replace(/\{\{([^}]+)\}\}/g, "{$1}");
|
|
288
|
+
parts.push(`${icuKey} {${strVal}}`);
|
|
289
|
+
}
|
|
290
|
+
return `{${varName}, select, ${parts.join(" ")}}`;
|
|
291
|
+
}
|
|
292
|
+
if (Array.isArray(node) || node.nodeType === "composite" && Array.isArray(node.composite)) return (Array.isArray(node) ? node : node.composite).map((item) => next(item, props)).join("");
|
|
293
|
+
return next(node, props);
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
const intlayerToI18nextFormatter = (message) => {
|
|
297
|
+
return require_interpreter_getContent_deepTransform.deepTransformNode(message, {
|
|
298
|
+
dictionaryKey: "i18next",
|
|
299
|
+
keyPath: [],
|
|
300
|
+
plugins: [{
|
|
301
|
+
id: "i18next",
|
|
302
|
+
...intlayerToI18nextPlugin
|
|
303
|
+
}]
|
|
304
|
+
});
|
|
305
|
+
};
|
|
306
|
+
const i18nextToIntlayerFormatter = (message) => {
|
|
307
|
+
return require_interpreter_getContent_deepTransform.deepTransformNode(message, {
|
|
308
|
+
dictionaryKey: "i18next",
|
|
309
|
+
keyPath: [],
|
|
310
|
+
plugins: [{
|
|
311
|
+
id: "i18next",
|
|
312
|
+
...i18nextToIntlayerPlugin
|
|
313
|
+
}]
|
|
314
|
+
});
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
//#endregion
|
|
318
|
+
exports.i18nextToIntlayerFormatter = i18nextToIntlayerFormatter;
|
|
319
|
+
exports.intlayerToI18nextFormatter = intlayerToI18nextFormatter;
|
|
320
|
+
//# sourceMappingURL=i18next.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18next.cjs","names":["nodes: I18NextNode[]","options: Record<string, I18NextNode[]>","insert","options: Record<string, any>","enu","gender","NodeType","transformedOptions: Record<string, string>","deepTransformNode"],"sources":["../../../src/messageFormat/i18next.ts"],"sourcesContent":["import type { Dictionary } from '@intlayer/types';\nimport { NodeType } from '@intlayer/types';\nimport { deepTransformNode } from '../interpreter';\nimport { enu, gender, insert } from '../transpiler';\nimport type { JsonValue } from './ICU';\n\n// Types for our AST\ntype I18NextNode =\n | string\n | {\n type: 'argument';\n name: string;\n format?: { type: string; style?: string };\n }\n | { type: 'plural'; name: string; options: Record<string, I18NextNode[]> }\n | { type: 'select'; name: string; options: Record<string, I18NextNode[]> };\n\nconst parseI18Next = (text: string): I18NextNode[] => {\n let index = 0;\n\n const parseNodes = (): I18NextNode[] => {\n const nodes: I18NextNode[] = [];\n let currentText = '';\n\n while (index < text.length) {\n const char = text[index];\n\n // Standard i18next variable: {{var}}\n if (char === '{' && text[index + 1] === '{') {\n if (currentText) {\n nodes.push(currentText);\n currentText = '';\n }\n index += 2; // skip {{\n nodes.push(parseStandardArgument());\n }\n // ICU syntax: {var} or {var, plural, ...}\n else if (char === '{') {\n if (currentText) {\n nodes.push(currentText);\n currentText = '';\n }\n index++; // skip {\n nodes.push(parseICUArgument());\n } else if (char === '}') {\n // End of current block (likely ICU block end)\n break;\n } else {\n currentText += char;\n index++;\n }\n }\n\n if (currentText) {\n nodes.push(currentText);\n }\n return nodes;\n };\n\n const parseStandardArgument = (): I18NextNode => {\n // We are past '{{'\n let name = '';\n while (index < text.length) {\n // Check for closing }}\n if (text[index] === '}' && text[index + 1] === '}') {\n index += 2; // skip }}\n return { type: 'argument', name: name.trim() };\n }\n name += text[index];\n index++;\n }\n throw new Error('Unclosed i18next variable');\n };\n\n const parseICUArgument = (): I18NextNode => {\n // We are past '{'\n let name = '';\n while (index < text.length && /[^,}]/.test(text[index])) {\n name += text[index];\n index++;\n }\n name = name.trim();\n\n if (index >= text.length) throw new Error('Unclosed argument');\n\n if (text[index] === '}') {\n index++;\n return { type: 'argument', name };\n }\n\n // Must be comma\n if (text[index] === ',') {\n index++;\n // Parse type\n let type = '';\n while (index < text.length && /[^,}]/.test(text[index])) {\n type += text[index];\n index++;\n }\n type = type.trim();\n\n if (index >= text.length) throw new Error('Unclosed argument');\n\n if (text[index] === '}') {\n index++;\n return { type: 'argument', name, format: { type } };\n }\n\n if (text[index] === ',') {\n index++;\n\n // If plural or select, parse options\n if (type === 'plural' || type === 'select') {\n const options: Record<string, I18NextNode[]> = {};\n\n while (index < text.length && text[index] !== '}') {\n while (index < text.length && /\\s/.test(text[index])) index++;\n\n let key = '';\n while (index < text.length && /[^{\\s]/.test(text[index])) {\n key += text[index];\n index++;\n }\n\n while (index < text.length && /\\s/.test(text[index])) index++;\n\n if (text[index] !== '{')\n throw new Error('Expected { after option key');\n index++; // skip {\n\n const value = parseNodes();\n\n if (text[index] !== '}')\n throw new Error('Expected } after option value');\n index++; // skip }\n\n options[key] = value;\n\n while (index < text.length && /\\s/.test(text[index])) index++;\n }\n\n index++; // skip closing argument }\n\n if (type === 'plural') {\n return { type: 'plural', name, options };\n } else if (type === 'select') {\n return { type: 'select', name, options };\n }\n } else {\n // Parse style for number/date/time\n let style = '';\n while (index < text.length && text[index] !== '}') {\n style += text[index];\n index++;\n }\n if (index >= text.length) throw new Error('Unclosed argument');\n\n style = style.trim();\n index++; // skip }\n\n return { type: 'argument', name, format: { type, style } };\n }\n }\n }\n\n throw new Error('Malformed argument');\n };\n\n return parseNodes();\n};\n\nconst i18nextNodesToIntlayer = (nodes: I18NextNode[]): any => {\n if (nodes.length === 0) return '';\n if (nodes.length === 1 && typeof nodes[0] === 'string') return nodes[0];\n\n const canFlatten = nodes.every(\n (node) => typeof node === 'string' || node.type === 'argument'\n );\n\n if (canFlatten) {\n let str = '';\n for (const node of nodes) {\n if (typeof node === 'string') {\n str += node;\n } else if (typeof node !== 'string' && node.type === 'argument') {\n if (node.format) {\n // For formatted arguments, use ICU syntax: {name, type, style}\n str += `{${node.name}, ${node.format.type}${\n node.format.style ? `, ${node.format.style}` : ''\n }}`;\n } else {\n // For simple arguments, use standard i18next: {{name}}\n str += `{{${node.name}}}`;\n }\n }\n }\n return insert(str);\n }\n\n if (nodes.length === 1) {\n const node = nodes[0];\n if (typeof node === 'string') return node;\n\n if (node.type === 'argument') {\n if (node.format) {\n return insert(\n `{${node.name}, ${node.format.type}${\n node.format.style ? `, ${node.format.style}` : ''\n }}`\n );\n }\n return insert(`{{${node.name}}}`);\n }\n\n if (node.type === 'plural') {\n const options: Record<string, any> = {};\n for (const [key, val] of Object.entries(node.options)) {\n let newKey = key;\n if (key.startsWith('=')) {\n newKey = key.substring(1);\n } else if (key === 'one') {\n newKey = '1';\n } else if (key === 'two') {\n newKey = '2';\n } else if (key === 'few') {\n newKey = '<=3';\n } else if (key === 'many') {\n newKey = '>=4';\n } else if (key === 'other') {\n newKey = 'fallback';\n }\n // Handle # replacement\n const replacedVal = val.map((v) => {\n if (typeof v === 'string') {\n // In ICU plural, # is replaced by the number\n // In i18next, if using ICU plugin, it behaves same.\n // We map it to {{varName}} in Intlayer\n return v.replace(/#/g, `{{${node.name}}}`);\n }\n return v;\n });\n\n options[newKey] = i18nextNodesToIntlayer(replacedVal);\n }\n\n // Preserve variable name\n options.__intlayer_icu_var = node.name;\n\n return enu(options);\n }\n\n if (node.type === 'select') {\n const options: Record<string, any> = {};\n for (const [key, val] of Object.entries(node.options)) {\n options[key] = i18nextNodesToIntlayer(val);\n }\n\n // Check for gender\n const optionKeys = Object.keys(options);\n const isGender =\n (options.male || options.female) &&\n optionKeys.every((k) =>\n ['male', 'female', 'other', 'fallback'].includes(k)\n );\n\n if (isGender) {\n return gender({\n fallback: options.other,\n male: options.male,\n female: options.female,\n });\n }\n\n // Preserve variable name for generic select\n options.__intlayer_icu_var = node.name;\n\n return enu(options);\n }\n }\n\n return nodes.map((node) => i18nextNodesToIntlayer([node]));\n};\n\nconst i18nextToIntlayerPlugin = {\n canHandle: (node: any) =>\n typeof node === 'string' && (node.includes('{') || node.includes('}')),\n transform: (node: any) => {\n try {\n const ast = parseI18Next(node);\n return i18nextNodesToIntlayer(ast);\n } catch {\n return node;\n }\n },\n};\n\nconst intlayerToI18nextPlugin = {\n canHandle: (node: any) =>\n typeof node === 'string' ||\n (node &&\n typeof node === 'object' &&\n (node.nodeType === NodeType.Insertion ||\n node.nodeType === NodeType.Enumeration ||\n node.nodeType === NodeType.Gender ||\n node.nodeType === 'composite')) ||\n Array.isArray(node),\n transform: (node: any, props: any, next: any) => {\n if (typeof node === 'string') {\n return node;\n }\n\n if (node.nodeType === NodeType.Insertion) {\n // If it contains ICU format syntax (curly braces but not double curly), keep it as is\n // But standard insert creates {{var}}.\n // Check if the original string was formatted (e.g. {val, number})\n if (node.insertion.match(/\\{[^}]*,[^}]*\\}/)) {\n // It's likely an ICU format string like {val, number}\n // We might need to ensure variables inside are not double-braced if they are part of the format\n // But wait, our parser outputs {val, number} as string for insertion.\n return node.insertion;\n }\n\n // Otherwise keep {{name}} for i18next\n return node.insertion;\n }\n\n if (node.nodeType === NodeType.Enumeration) {\n const options = node.enumeration;\n\n const transformedOptions: Record<string, string> = {};\n for (const [key, val] of Object.entries(options)) {\n if (key === '__intlayer_icu_var') continue;\n const childVal = next(val, props);\n transformedOptions[key] =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n }\n\n // Infer variable name\n let varName = options.__intlayer_icu_var || 'count';\n\n if (!options.__intlayer_icu_var) {\n const fallbackVal =\n transformedOptions.fallback ||\n transformedOptions.other ||\n Object.values(transformedOptions)[0];\n\n // Search for {{var}} or {var}\n // Match {variable} but avoid {variable, ...} (which are nested ICUs)\n const match =\n fallbackVal.match(/\\{\\{([a-zA-Z0-9_]+)\\}\\}/) ||\n fallbackVal.match(/\\{([a-zA-Z0-9_]+)\\}(?!,)/);\n if (match) {\n varName = match[1];\n }\n }\n\n const keys = Object.keys(transformedOptions);\n const pluralKeys = [\n '1',\n '2',\n '<=3',\n '>=4',\n 'fallback',\n 'other',\n 'zero',\n 'one',\n 'two',\n 'few',\n 'many',\n ];\n // Check if it is a plural\n const isPlural = keys.every(\n (k) => pluralKeys.includes(k) || /^[<>=]?\\d+(\\.\\d+)?$/.test(k)\n );\n\n const parts = [];\n\n if (isPlural) {\n for (const [key, val] of Object.entries(transformedOptions)) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n else if (key === '<=3') icuKey = 'few';\n else if (key === '>=4') icuKey = 'many';\n else if (/^\\d+$/.test(key)) icuKey = `=${key}`;\n\n let strVal = val;\n\n // Convert {{var}} to {var} inside ICU string\n // Also replace {varName} with # if it matches\n strVal = strVal.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n strVal = strVal.replace(new RegExp(`\\\\{${varName}\\\\}`, 'g'), '#');\n\n parts.push(`${icuKey} {${strVal}}`);\n }\n return `{${varName}, plural, ${parts.join(' ')}}`;\n } else {\n // Select\n const entries = Object.entries(transformedOptions).sort(\n ([keyA], [keyB]) => {\n if (keyA === 'fallback' || keyA === 'other') return 1;\n if (keyB === 'fallback' || keyB === 'other') return -1;\n return 0;\n }\n );\n\n for (const [key, val] of entries) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n\n let strVal = val;\n strVal = strVal.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n\n parts.push(`${icuKey} {${strVal}}`);\n }\n return `{${varName}, select, ${parts.join(' ')}}`;\n }\n }\n\n if (node.nodeType === NodeType.Gender) {\n const options = node.gender;\n const varName = 'gender';\n const parts = [];\n\n const entries = Object.entries(options).sort(([keyA], [keyB]) => {\n if (keyA === 'fallback') return 1;\n if (keyB === 'fallback') return -1;\n return 0;\n });\n\n for (const [key, val] of entries) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n\n const childVal = next(val, props);\n let strVal =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n\n strVal = strVal.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n parts.push(`${icuKey} {${strVal}}`);\n }\n return `{${varName}, select, ${parts.join(' ')}}`;\n }\n\n if (\n Array.isArray(node) ||\n (node.nodeType === 'composite' && Array.isArray(node.composite))\n ) {\n const arr = Array.isArray(node) ? node : node.composite;\n const items = arr.map((item: any) => next(item, props));\n return items.join('');\n }\n\n return next(node, props);\n },\n};\n\nexport const intlayerToI18nextFormatter = (\n message: Dictionary['content']\n): JsonValue => {\n return deepTransformNode(message, {\n dictionaryKey: 'i18next',\n keyPath: [],\n plugins: [{ id: 'i18next', ...intlayerToI18nextPlugin }],\n });\n};\n\nexport const i18nextToIntlayerFormatter = (\n message: JsonValue\n): Dictionary['content'] => {\n return deepTransformNode(message, {\n dictionaryKey: 'i18next',\n keyPath: [],\n plugins: [{ id: 'i18next', ...i18nextToIntlayerPlugin }],\n });\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const require_messageFormat_ICU = require('./ICU.cjs');
|
|
2
|
+
const require_messageFormat_i18next = require('./i18next.cjs');
|
|
3
|
+
const require_messageFormat_vue_i18n = require('./vue-i18n.cjs');
|
|
4
|
+
|
|
5
|
+
exports.i18nextToIntlayerFormatter = require_messageFormat_i18next.i18nextToIntlayerFormatter;
|
|
6
|
+
exports.icuToIntlayerFormatter = require_messageFormat_ICU.icuToIntlayerFormatter;
|
|
7
|
+
exports.intlayerToI18nextFormatter = require_messageFormat_i18next.intlayerToI18nextFormatter;
|
|
8
|
+
exports.intlayerToICUFormatter = require_messageFormat_ICU.intlayerToICUFormatter;
|
|
9
|
+
exports.intlayerToVueI18nFormatter = require_messageFormat_vue_i18n.intlayerToVueI18nFormatter;
|
|
10
|
+
exports.vueI18nToIntlayerFormatter = require_messageFormat_vue_i18n.vueI18nToIntlayerFormatter;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_interpreter_getContent_deepTransform = require('../interpreter/getContent/deepTransform.cjs');
|
|
3
|
+
const require_transpiler_enumeration_enumeration = require('../transpiler/enumeration/enumeration.cjs');
|
|
4
|
+
const require_transpiler_insertion_insertion = require('../transpiler/insertion/insertion.cjs');
|
|
5
|
+
let __intlayer_types = require("@intlayer/types");
|
|
6
|
+
|
|
7
|
+
//#region src/messageFormat/vue-i18n.ts
|
|
8
|
+
const parseVueI18nPart = (text) => {
|
|
9
|
+
let index = 0;
|
|
10
|
+
const nodes = [];
|
|
11
|
+
let currentText = "";
|
|
12
|
+
while (index < text.length) {
|
|
13
|
+
const char = text[index];
|
|
14
|
+
if (char === "{") {
|
|
15
|
+
if (currentText) {
|
|
16
|
+
nodes.push(currentText);
|
|
17
|
+
currentText = "";
|
|
18
|
+
}
|
|
19
|
+
index++;
|
|
20
|
+
let name = "";
|
|
21
|
+
while (index < text.length && text[index] !== "}") {
|
|
22
|
+
name += text[index];
|
|
23
|
+
index++;
|
|
24
|
+
}
|
|
25
|
+
if (index < text.length) index++;
|
|
26
|
+
nodes.push({
|
|
27
|
+
type: "argument",
|
|
28
|
+
name: name.trim()
|
|
29
|
+
});
|
|
30
|
+
} else {
|
|
31
|
+
currentText += char;
|
|
32
|
+
index++;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (currentText) nodes.push(currentText);
|
|
36
|
+
return nodes;
|
|
37
|
+
};
|
|
38
|
+
const parseVueI18n = (text) => {
|
|
39
|
+
const parts = [];
|
|
40
|
+
let currentPart = "";
|
|
41
|
+
let index = 0;
|
|
42
|
+
while (index < text.length) {
|
|
43
|
+
const char = text[index];
|
|
44
|
+
if (char === "\\" && index + 1 < text.length && text[index + 1] === "|") {
|
|
45
|
+
currentPart += "|";
|
|
46
|
+
index += 2;
|
|
47
|
+
} else if (char === "|") {
|
|
48
|
+
parts.push(currentPart.trim());
|
|
49
|
+
currentPart = "";
|
|
50
|
+
index++;
|
|
51
|
+
} else {
|
|
52
|
+
currentPart += char;
|
|
53
|
+
index++;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
parts.push(currentPart.trim());
|
|
57
|
+
return parts.map(parseVueI18nPart);
|
|
58
|
+
};
|
|
59
|
+
const vueI18nPartToIntlayer = (nodes) => {
|
|
60
|
+
if (nodes.length === 0) return "";
|
|
61
|
+
if (nodes.length === 1 && typeof nodes[0] === "string") return nodes[0];
|
|
62
|
+
let str = "";
|
|
63
|
+
for (const node of nodes) if (typeof node === "string") str += node;
|
|
64
|
+
else str += `{{${node.name}}}`;
|
|
65
|
+
return require_transpiler_insertion_insertion.insert(str);
|
|
66
|
+
};
|
|
67
|
+
const vueI18nNodesToIntlayer = (parts) => {
|
|
68
|
+
if (parts.length === 1) return vueI18nPartToIntlayer(parts[0]);
|
|
69
|
+
const options = {};
|
|
70
|
+
const varName = "count";
|
|
71
|
+
if (parts.length === 2) {
|
|
72
|
+
options["1"] = vueI18nPartToIntlayer(parts[0]);
|
|
73
|
+
options.fallback = vueI18nPartToIntlayer(parts[1]);
|
|
74
|
+
} else if (parts.length === 3) {
|
|
75
|
+
options["0"] = vueI18nPartToIntlayer(parts[0]);
|
|
76
|
+
options["1"] = vueI18nPartToIntlayer(parts[1]);
|
|
77
|
+
options.fallback = vueI18nPartToIntlayer(parts[2]);
|
|
78
|
+
} else parts.forEach((part, index) => {
|
|
79
|
+
if (index === parts.length - 1) options.fallback = vueI18nPartToIntlayer(part);
|
|
80
|
+
else options[index.toString()] = vueI18nPartToIntlayer(part);
|
|
81
|
+
});
|
|
82
|
+
options.__intlayer_vue_i18n_var = varName;
|
|
83
|
+
return require_transpiler_enumeration_enumeration.enu(options);
|
|
84
|
+
};
|
|
85
|
+
const vueI18nToIntlayerPlugin = {
|
|
86
|
+
canHandle: (node) => typeof node === "string" && (node.includes("{") || node.includes("|")),
|
|
87
|
+
transform: (node) => {
|
|
88
|
+
try {
|
|
89
|
+
return vueI18nNodesToIntlayer(parseVueI18n(node));
|
|
90
|
+
} catch {
|
|
91
|
+
return node;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const intlayerToVueI18nPlugin = {
|
|
96
|
+
canHandle: (node) => typeof node === "string" || node && typeof node === "object" && (node.nodeType === __intlayer_types.NodeType.Insertion || node.nodeType === __intlayer_types.NodeType.Enumeration || node.nodeType === __intlayer_types.NodeType.Gender || node.nodeType === "composite") || Array.isArray(node),
|
|
97
|
+
transform: (node, props, next) => {
|
|
98
|
+
if (typeof node === "string") return node.replace(/\{\{([^}]+)\}\}/g, "{$1}");
|
|
99
|
+
if (node.nodeType === __intlayer_types.NodeType.Insertion) return node.insertion.replace(/\{\{([^}]+)\}\}/g, "{$1}");
|
|
100
|
+
if (node.nodeType === __intlayer_types.NodeType.Enumeration) {
|
|
101
|
+
const options = node.enumeration;
|
|
102
|
+
const transformedOptions = {};
|
|
103
|
+
for (const [key, val] of Object.entries(options)) {
|
|
104
|
+
if (key === "__intlayer_vue_i18n_var") continue;
|
|
105
|
+
const childVal = next(val, props);
|
|
106
|
+
transformedOptions[key] = typeof childVal === "string" ? childVal : JSON.stringify(childVal);
|
|
107
|
+
}
|
|
108
|
+
const keys = Object.keys(transformedOptions);
|
|
109
|
+
if (keys.includes("0")) {
|
|
110
|
+
const indices = keys.filter((key) => /^\d+$/.test(key)).map(Number);
|
|
111
|
+
const maxIndex = Math.max(...indices);
|
|
112
|
+
const fallback = transformedOptions.fallback || transformedOptions.other;
|
|
113
|
+
const resultParts = [];
|
|
114
|
+
if (maxIndex <= 1 && !keys.includes("2")) return `${transformedOptions["0"] || ""} | ${transformedOptions["1"] || ""} | ${fallback}`;
|
|
115
|
+
const limit = Math.max(1, maxIndex);
|
|
116
|
+
for (let i = 0; i <= limit; i++) {
|
|
117
|
+
const key = i.toString();
|
|
118
|
+
if (transformedOptions[key]) resultParts.push(transformedOptions[key]);
|
|
119
|
+
else resultParts.push("");
|
|
120
|
+
}
|
|
121
|
+
resultParts.push(fallback);
|
|
122
|
+
return resultParts.join(" | ").replace(/ \| {2}\| /g, " | | ");
|
|
123
|
+
}
|
|
124
|
+
if (keys.includes("1") && (keys.includes("fallback") || keys.includes("other"))) return `${transformedOptions["1"]} | ${transformedOptions.fallback || transformedOptions.other}`;
|
|
125
|
+
if (keys.length === 1 && (keys.includes("fallback") || keys.includes("other"))) return transformedOptions.fallback || transformedOptions.other;
|
|
126
|
+
return transformedOptions.fallback || Object.values(transformedOptions)[0];
|
|
127
|
+
}
|
|
128
|
+
if (node.nodeType === __intlayer_types.NodeType.Gender) {
|
|
129
|
+
const options = node.gender;
|
|
130
|
+
const transformedOptions = {};
|
|
131
|
+
for (const [key, val] of Object.entries(options)) {
|
|
132
|
+
let newKey = key;
|
|
133
|
+
if (key === "fallback") newKey = "other";
|
|
134
|
+
transformedOptions[newKey] = next(val, props);
|
|
135
|
+
}
|
|
136
|
+
return transformedOptions;
|
|
137
|
+
}
|
|
138
|
+
if (Array.isArray(node) || node.nodeType === "composite" && Array.isArray(node.composite)) return (Array.isArray(node) ? node : node.composite).map((item) => next(item, props)).join("");
|
|
139
|
+
return next(node, props);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
const intlayerToVueI18nFormatter = (message) => {
|
|
143
|
+
return require_interpreter_getContent_deepTransform.deepTransformNode(message, {
|
|
144
|
+
dictionaryKey: "vue-i18n",
|
|
145
|
+
keyPath: [],
|
|
146
|
+
plugins: [{
|
|
147
|
+
id: "vue-i18n",
|
|
148
|
+
...intlayerToVueI18nPlugin
|
|
149
|
+
}]
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
const vueI18nToIntlayerFormatter = (message) => {
|
|
153
|
+
return require_interpreter_getContent_deepTransform.deepTransformNode(message, {
|
|
154
|
+
dictionaryKey: "vue-i18n",
|
|
155
|
+
keyPath: [],
|
|
156
|
+
plugins: [{
|
|
157
|
+
id: "vue-i18n",
|
|
158
|
+
...vueI18nToIntlayerPlugin
|
|
159
|
+
}]
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
//#endregion
|
|
164
|
+
exports.intlayerToVueI18nFormatter = intlayerToVueI18nFormatter;
|
|
165
|
+
exports.vueI18nToIntlayerFormatter = vueI18nToIntlayerFormatter;
|
|
166
|
+
//# sourceMappingURL=vue-i18n.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vue-i18n.cjs","names":["nodes: VueI18nNode[]","parts: string[]","insert","options: Record<string, any>","enu","NodeType","transformedOptions: Record<string, string>","transformedOptions: Record<string, any>","deepTransformNode"],"sources":["../../../src/messageFormat/vue-i18n.ts"],"sourcesContent":["import { type Dictionary, NodeType } from '@intlayer/types';\nimport { deepTransformNode } from '../interpreter';\nimport { enu, insert } from '../transpiler';\nimport type { JsonValue } from './ICU';\n\n// Types for our AST\ntype VueI18nNode =\n | string\n | {\n type: 'argument';\n name: string;\n };\n\nconst parseVueI18nPart = (text: string): VueI18nNode[] => {\n let index = 0;\n const nodes: VueI18nNode[] = [];\n let currentText = '';\n\n while (index < text.length) {\n const char = text[index];\n\n if (char === '{') {\n if (currentText) {\n nodes.push(currentText);\n currentText = '';\n }\n index++; // skip {\n let name = '';\n while (index < text.length && text[index] !== '}') {\n name += text[index];\n index++;\n }\n if (index < text.length) {\n index++; // skip }\n }\n nodes.push({ type: 'argument', name: name.trim() });\n } else {\n currentText += char;\n index++;\n }\n }\n\n if (currentText) {\n nodes.push(currentText);\n }\n\n return nodes;\n};\n\nconst parseVueI18n = (text: string): VueI18nNode[][] => {\n // Split by | but handle escaped \\|\n const parts: string[] = [];\n let currentPart = '';\n let index = 0;\n\n while (index < text.length) {\n const char = text[index];\n if (char === '\\\\' && index + 1 < text.length && text[index + 1] === '|') {\n currentPart += '|';\n index += 2;\n } else if (char === '|') {\n parts.push(currentPart.trim()); // Trim to remove surrounding spaces\n currentPart = '';\n index++;\n } else {\n currentPart += char;\n index++;\n }\n }\n parts.push(currentPart.trim()); // Trim last part too\n\n return parts.map(parseVueI18nPart);\n};\n\nconst vueI18nPartToIntlayer = (nodes: VueI18nNode[]): any => {\n if (nodes.length === 0) return '';\n if (nodes.length === 1 && typeof nodes[0] === 'string') return nodes[0];\n\n let str = '';\n for (const node of nodes) {\n if (typeof node === 'string') {\n str += node;\n } else {\n str += `{{${node.name}}}`;\n }\n }\n return insert(str);\n};\n\nconst vueI18nNodesToIntlayer = (parts: VueI18nNode[][]): any => {\n if (parts.length === 1) {\n return vueI18nPartToIntlayer(parts[0]);\n }\n\n // Handle pluralization (choice)\n const options: Record<string, any> = {};\n const varName = 'count'; // Default variable for vue-i18n choices\n\n if (parts.length === 2) {\n // 2 choices: 1 | other\n options['1'] = vueI18nPartToIntlayer(parts[0]);\n options.fallback = vueI18nPartToIntlayer(parts[1]);\n } else if (parts.length === 3) {\n // 3 choices: 0 | 1 | other\n options['0'] = vueI18nPartToIntlayer(parts[0]);\n options['1'] = vueI18nPartToIntlayer(parts[1]);\n options.fallback = vueI18nPartToIntlayer(parts[2]);\n } else {\n // > 3 choices: 0 | 1 | 2 | ... | other\n parts.forEach((part, index) => {\n if (index === parts.length - 1) {\n options.fallback = vueI18nPartToIntlayer(part);\n } else {\n options[index.toString()] = vueI18nPartToIntlayer(part);\n }\n });\n }\n\n // Preserve variable name\n options.__intlayer_vue_i18n_var = varName;\n\n return enu(options);\n};\n\nconst vueI18nToIntlayerPlugin = {\n canHandle: (node: any) =>\n typeof node === 'string' && (node.includes('{') || node.includes('|')),\n transform: (node: any) => {\n try {\n const ast = parseVueI18n(node);\n return vueI18nNodesToIntlayer(ast);\n } catch {\n return node;\n }\n },\n};\n\nconst intlayerToVueI18nPlugin = {\n canHandle: (node: any) =>\n typeof node === 'string' ||\n (node &&\n typeof node === 'object' &&\n (node.nodeType === NodeType.Insertion ||\n node.nodeType === NodeType.Enumeration ||\n node.nodeType === NodeType.Gender ||\n node.nodeType === 'composite')) ||\n Array.isArray(node),\n transform: (node: any, props: any, next: any) => {\n if (typeof node === 'string') {\n // replace {{...}} with {...} even in strings\n return node.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n }\n\n if (node.nodeType === NodeType.Insertion) {\n // {{name}} -> {name}\n return node.insertion.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n }\n\n if (node.nodeType === NodeType.Enumeration) {\n const options = node.enumeration;\n\n const transformedOptions: Record<string, string> = {};\n for (const [key, val] of Object.entries(options)) {\n if (key === '__intlayer_vue_i18n_var') continue;\n const childVal = next(val, props);\n transformedOptions[key] =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n }\n\n // We need to reconstruct the pipe-separated string.\n // 2 parts: 1, fallback\n // 3 parts: 0, 1, fallback\n\n const keys = Object.keys(transformedOptions);\n\n // Heuristic to decide format\n // Use loose condition for 3 parts: if 0 exists, OR if 2 exists, etc.\n // But typically 0, 1, 2...\n // If '0' is present, we likely want the 3+ parts format.\n if (keys.includes('0')) {\n const indices = keys.filter((key) => /^\\d+$/.test(key)).map(Number);\n const maxIndex = Math.max(...indices);\n\n const fallback =\n transformedOptions.fallback || transformedOptions.other;\n const resultParts = [];\n\n // Check if we can use simple 3-part: 0 | 1 | fallback\n // Only if maxIndex <= 1\n if (maxIndex <= 1 && !keys.includes('2')) {\n const zero = transformedOptions['0'] || '';\n const one = transformedOptions['1'] || ''; // Gap handling?\n return `${zero} | ${one} | ${fallback}`;\n }\n\n // General case: loop until maxIndex\n const limit = Math.max(1, maxIndex);\n\n for (let i = 0; i <= limit; i++) {\n const key = i.toString();\n if (transformedOptions[key]) {\n resultParts.push(transformedOptions[key]);\n } else {\n resultParts.push(''); // Empty string for gaps\n }\n }\n resultParts.push(fallback);\n return resultParts.join(' | ').replace(/ \\| {2}\\| /g, ' | | ');\n }\n\n // 2 parts: 1 | fallback\n if (\n keys.includes('1') &&\n (keys.includes('fallback') || keys.includes('other'))\n ) {\n return `${transformedOptions['1']} | ${transformedOptions.fallback || transformedOptions.other}`;\n }\n\n // Fallback for only fallback?\n if (\n keys.length === 1 &&\n (keys.includes('fallback') || keys.includes('other'))\n ) {\n return transformedOptions.fallback || transformedOptions.other;\n }\n\n // Default fallback\n return (\n transformedOptions.fallback || Object.values(transformedOptions)[0]\n );\n }\n\n // Gender not supported by vue-i18n string format, return object\n if (node.nodeType === NodeType.Gender) {\n const options = node.gender;\n const transformedOptions: Record<string, any> = {};\n\n // Just map values\n for (const [key, val] of Object.entries(options)) {\n let newKey = key;\n if (key === 'fallback') newKey = 'other'; // vue-i18n doesn't strictly have 'other' for gender objects but standard convention often uses similar keys\n\n const childVal = next(val, props);\n transformedOptions[newKey] = childVal;\n }\n return transformedOptions;\n }\n\n if (\n Array.isArray(node) ||\n (node.nodeType === 'composite' && Array.isArray(node.composite))\n ) {\n const arr = Array.isArray(node) ? node : node.composite;\n const items = arr.map((item: any) => next(item, props));\n return items.join('');\n }\n\n return next(node, props);\n },\n};\n\nexport const intlayerToVueI18nFormatter = (\n message: Dictionary['content']\n): JsonValue => {\n return deepTransformNode(message, {\n dictionaryKey: 'vue-i18n',\n keyPath: [],\n plugins: [{ id: 'vue-i18n', ...intlayerToVueI18nPlugin }],\n });\n};\n\nexport const vueI18nToIntlayerFormatter = (\n message: JsonValue\n): Dictionary['content'] => {\n return deepTransformNode(message, {\n dictionaryKey: 'vue-i18n',\n keyPath: [],\n plugins: [{ id: 'vue-i18n', ...vueI18nToIntlayerPlugin }],\n });\n};\n"],"mappings":"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"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { localeResolver } from "../dist/esm/localization/localeResolver.mjs";
|
|
2
|
-
import { getLocaleFromStorage } from "../dist/esm/utils/localeStorage.mjs";
|
|
3
1
|
import { getPreferredLanguages } from "./localeDetector.mjs";
|
|
4
2
|
import { DefaultValues } from "@intlayer/config/client";
|
|
5
3
|
import configuration from "@intlayer/config/built";
|
|
4
|
+
import { getLocaleFromStorage, localeResolver } from "@intlayer/core";
|
|
6
5
|
|
|
7
6
|
//#region src/localization/getLocale.ts
|
|
8
7
|
const getLocale = async (ctx = {}) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getLocale.mjs","names":[],"sources":["../../../src/localization/getLocale.ts"],"sourcesContent":["import configuration from '@intlayer/config/built';\nimport { DefaultValues } from '@intlayer/config/client';\nimport { getLocaleFromStorage, localeResolver } from '@intlayer/core';\nimport type { Locale } from '@intlayer/types';\nimport { getPreferredLanguages } from './localeDetector';\n\nexport type RequestContext = {\n getHeader?: (name: string) => string | null | undefined;\n getCookie?: (name: string) => string | null | undefined;\n};\n\nexport const getLocale = async (ctx: RequestContext = {}): Promise<Locale> => {\n const defaultLocale =\n configuration?.internationalization?.defaultLocale ??\n DefaultValues.Internationalization.DEFAULT_LOCALE;\n const availableLocales =\n configuration?.internationalization?.locales ??\n DefaultValues.Internationalization.LOCALES;\n\n // Try locale from storage (cookie or header)\n const storedLocale = getLocaleFromStorage({\n getCookie: ctx.getCookie,\n getHeader: ctx.getHeader,\n });\n\n if (storedLocale) {\n return storedLocale;\n }\n\n // Fallback to Accept-Language negotiation\n const acceptLanguageHeader = ctx.getHeader?.('accept-language');\n\n if (!acceptLanguageHeader) {\n return defaultLocale;\n }\n\n const preferredLocaleStrings = getPreferredLanguages(\n acceptLanguageHeader,\n availableLocales\n );\n\n const userFallbackLocale = localeResolver(\n preferredLocaleStrings,\n availableLocales,\n defaultLocale\n );\n\n if (userFallbackLocale) {\n return userFallbackLocale;\n }\n\n // Default locale\n return defaultLocale;\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"getLocale.mjs","names":[],"sources":["../../../src/localization/getLocale.ts"],"sourcesContent":["import configuration from '@intlayer/config/built';\nimport { DefaultValues } from '@intlayer/config/client';\nimport { getLocaleFromStorage, localeResolver } from '@intlayer/core';\nimport type { Locale } from '@intlayer/types';\nimport { getPreferredLanguages } from './localeDetector';\n\nexport type RequestContext = {\n getHeader?: (name: string) => string | null | undefined;\n getCookie?: (name: string) => string | null | undefined;\n};\n\nexport const getLocale = async (ctx: RequestContext = {}): Promise<Locale> => {\n const defaultLocale =\n configuration?.internationalization?.defaultLocale ??\n DefaultValues.Internationalization.DEFAULT_LOCALE;\n const availableLocales =\n configuration?.internationalization?.locales ??\n DefaultValues.Internationalization.LOCALES;\n\n // Try locale from storage (cookie or header)\n const storedLocale = getLocaleFromStorage({\n getCookie: ctx.getCookie,\n getHeader: ctx.getHeader,\n });\n\n if (storedLocale) {\n return storedLocale;\n }\n\n // Fallback to Accept-Language negotiation\n const acceptLanguageHeader = ctx.getHeader?.('accept-language');\n\n if (!acceptLanguageHeader) {\n return defaultLocale;\n }\n\n const preferredLocaleStrings = getPreferredLanguages(\n acceptLanguageHeader,\n availableLocales\n );\n\n const userFallbackLocale = localeResolver(\n preferredLocaleStrings,\n availableLocales,\n defaultLocale\n );\n\n if (userFallbackLocale) {\n return userFallbackLocale;\n }\n\n // Default locale\n return defaultLocale;\n};\n"],"mappings":";;;;;;AAWA,MAAa,YAAY,OAAO,MAAsB,EAAE,KAAsB;CAC5E,MAAM,gBACJ,eAAe,sBAAsB,iBACrC,cAAc,qBAAqB;CACrC,MAAM,mBACJ,eAAe,sBAAsB,WACrC,cAAc,qBAAqB;CAGrC,MAAM,eAAe,qBAAqB;EACxC,WAAW,IAAI;EACf,WAAW,IAAI;EAChB,CAAC;AAEF,KAAI,aACF,QAAO;CAIT,MAAM,uBAAuB,IAAI,YAAY,kBAAkB;AAE/D,KAAI,CAAC,qBACH,QAAO;CAQT,MAAM,qBAAqB,eALI,sBAC7B,sBACA,iBACD,EAIC,kBACA,cACD;AAED,KAAI,mBACF,QAAO;AAIT,QAAO"}
|
|
@@ -63,7 +63,8 @@ const getLocalizedUrl = (url, currentLocale, options = {}) => {
|
|
|
63
63
|
}
|
|
64
64
|
const { prefix } = getPrefix(currentLocale, {
|
|
65
65
|
defaultLocale,
|
|
66
|
-
mode
|
|
66
|
+
mode,
|
|
67
|
+
locales
|
|
67
68
|
});
|
|
68
69
|
let localizedPath = `/${prefix}${parsedUrl.pathname}`;
|
|
69
70
|
localizedPath = localizedPath.replaceAll(/\/+/g, "/");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getLocalizedUrl.mjs","names":[],"sources":["../../../src/localization/getLocalizedUrl.ts"],"sourcesContent":["import configuration from '@intlayer/config/built';\nimport { DefaultValues } from '@intlayer/config/client';\nimport type { LocalesValues } from '@intlayer/types';\nimport { checkIsURLAbsolute } from '../utils/checkIsURLAbsolute';\nimport { getPathWithoutLocale } from './getPathWithoutLocale';\nimport { getPrefix } from './getPrefix';\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,\n options: {\n locales?: LocalesValues[];\n defaultLocale?: LocalesValues;\n mode?: 'prefix-no-default' | 'prefix-all' | 'no-prefix' | 'search-params';\n } = {}\n): string => {\n const { defaultLocale, mode, locales } = {\n defaultLocale:\n configuration?.internationalization?.defaultLocale ??\n DefaultValues.Internationalization.DEFAULT_LOCALE,\n mode: configuration?.routing?.mode ?? DefaultValues.Routing.ROUTING_MODE,\n locales:\n configuration?.internationalization?.locales ??\n DefaultValues.Internationalization.LOCALES,\n ...options,\n };\n\n // Remove any existing locale segment from the URL\n const urlWithoutLocale = getPathWithoutLocale(url, locales);\n\n if (mode === 'no-prefix') {\n // No locale prefixing\n return urlWithoutLocale;\n }\n\n // Determine if the original URL is absolute (includes protocol)\n const isAbsoluteUrl = checkIsURLAbsolute(urlWithoutLocale);\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 parsedUrl = isAbsoluteUrl\n ? new URL(urlWithoutLocale)\n : new URL(urlWithoutLocale, 'http://example.com');\n\n // Prepare the base URL (protocol + host) if it's absolute\n const baseUrl = isAbsoluteUrl\n ? `${parsedUrl.protocol}//${parsedUrl.host}`\n : '';\n\n if (mode === 'search-params') {\n // Use search parameters for locale handling\n const searchParams = new URLSearchParams(parsedUrl.search);\n searchParams.set('locale', currentLocale.toString());\n\n const queryString = searchParams.toString();\n const pathWithQuery = queryString\n ? `${parsedUrl.pathname}?${queryString}`\n : parsedUrl.pathname;\n\n if (isAbsoluteUrl) {\n return `${baseUrl}${pathWithQuery}${parsedUrl.hash}`;\n }\n\n return `${pathWithQuery}${parsedUrl.hash}`;\n }\n\n const { prefix } = getPrefix(currentLocale, {\n defaultLocale,\n mode,\n });\n\n // Construct the new pathname with or without the locale prefix\n let localizedPath = `/${prefix}${parsedUrl.pathname}`;\n\n // Remove double slashes\n localizedPath = localizedPath.replaceAll(/\\/+/g, '/');\n\n // Remove trailing slash for non-root paths\n if (localizedPath.length > 1 && localizedPath.endsWith('/')) {\n localizedPath = localizedPath.slice(0, -1);\n }\n\n // Combine with the base URL if the original URL was absolute\n if (isAbsoluteUrl) {\n return `${baseUrl}${localizedPath}${parsedUrl.search}${parsedUrl.hash}`;\n }\n\n return `${localizedPath}${parsedUrl.search}${parsedUrl.hash}`;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CA,MAAa,mBACX,KACA,eACA,UAII,EAAE,KACK;CACX,MAAM,EAAE,eAAe,MAAM,YAAY;EACvC,eACE,eAAe,sBAAsB,iBACrC,cAAc,qBAAqB;EACrC,MAAM,eAAe,SAAS,QAAQ,cAAc,QAAQ;EAC5D,SACE,eAAe,sBAAsB,WACrC,cAAc,qBAAqB;EACrC,GAAG;EACJ;CAGD,MAAM,mBAAmB,qBAAqB,KAAK,QAAQ;AAE3D,KAAI,SAAS,YAEX,QAAO;CAIT,MAAM,gBAAgB,mBAAmB,iBAAiB;CAI1D,MAAM,YAAY,gBACd,IAAI,IAAI,iBAAiB,GACzB,IAAI,IAAI,kBAAkB,qBAAqB;CAGnD,MAAM,UAAU,gBACZ,GAAG,UAAU,SAAS,IAAI,UAAU,SACpC;AAEJ,KAAI,SAAS,iBAAiB;EAE5B,MAAM,eAAe,IAAI,gBAAgB,UAAU,OAAO;AAC1D,eAAa,IAAI,UAAU,cAAc,UAAU,CAAC;EAEpD,MAAM,cAAc,aAAa,UAAU;EAC3C,MAAM,gBAAgB,cAClB,GAAG,UAAU,SAAS,GAAG,gBACzB,UAAU;AAEd,MAAI,cACF,QAAO,GAAG,UAAU,gBAAgB,UAAU;AAGhD,SAAO,GAAG,gBAAgB,UAAU;;CAGtC,MAAM,EAAE,WAAW,UAAU,eAAe;EAC1C;EACA;EACD,CAAC;CAGF,IAAI,gBAAgB,IAAI,SAAS,UAAU;AAG3C,iBAAgB,cAAc,WAAW,QAAQ,IAAI;AAGrD,KAAI,cAAc,SAAS,KAAK,cAAc,SAAS,IAAI,CACzD,iBAAgB,cAAc,MAAM,GAAG,GAAG;AAI5C,KAAI,cACF,QAAO,GAAG,UAAU,gBAAgB,UAAU,SAAS,UAAU;AAGnE,QAAO,GAAG,gBAAgB,UAAU,SAAS,UAAU"}
|
|
1
|
+
{"version":3,"file":"getLocalizedUrl.mjs","names":[],"sources":["../../../src/localization/getLocalizedUrl.ts"],"sourcesContent":["import configuration from '@intlayer/config/built';\nimport { DefaultValues } from '@intlayer/config/client';\nimport type { LocalesValues } from '@intlayer/types';\nimport { checkIsURLAbsolute } from '../utils/checkIsURLAbsolute';\nimport { getPathWithoutLocale } from './getPathWithoutLocale';\nimport { getPrefix } from './getPrefix';\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,\n options: {\n locales?: LocalesValues[];\n defaultLocale?: LocalesValues;\n mode?: 'prefix-no-default' | 'prefix-all' | 'no-prefix' | 'search-params';\n } = {}\n): string => {\n const { defaultLocale, mode, locales } = {\n defaultLocale:\n configuration?.internationalization?.defaultLocale ??\n DefaultValues.Internationalization.DEFAULT_LOCALE,\n mode: configuration?.routing?.mode ?? DefaultValues.Routing.ROUTING_MODE,\n locales:\n configuration?.internationalization?.locales ??\n DefaultValues.Internationalization.LOCALES,\n ...options,\n };\n\n // Remove any existing locale segment from the URL\n const urlWithoutLocale = getPathWithoutLocale(url, locales);\n\n if (mode === 'no-prefix') {\n // No locale prefixing\n return urlWithoutLocale;\n }\n\n // Determine if the original URL is absolute (includes protocol)\n const isAbsoluteUrl = checkIsURLAbsolute(urlWithoutLocale);\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 parsedUrl = isAbsoluteUrl\n ? new URL(urlWithoutLocale)\n : new URL(urlWithoutLocale, 'http://example.com');\n\n // Prepare the base URL (protocol + host) if it's absolute\n const baseUrl = isAbsoluteUrl\n ? `${parsedUrl.protocol}//${parsedUrl.host}`\n : '';\n\n if (mode === 'search-params') {\n // Use search parameters for locale handling\n const searchParams = new URLSearchParams(parsedUrl.search);\n searchParams.set('locale', currentLocale.toString());\n\n const queryString = searchParams.toString();\n const pathWithQuery = queryString\n ? `${parsedUrl.pathname}?${queryString}`\n : parsedUrl.pathname;\n\n if (isAbsoluteUrl) {\n return `${baseUrl}${pathWithQuery}${parsedUrl.hash}`;\n }\n\n return `${pathWithQuery}${parsedUrl.hash}`;\n }\n\n const { prefix } = getPrefix(currentLocale, {\n defaultLocale,\n mode,\n locales,\n });\n\n // Construct the new pathname with or without the locale prefix\n let localizedPath = `/${prefix}${parsedUrl.pathname}`;\n\n // Remove double slashes\n localizedPath = localizedPath.replaceAll(/\\/+/g, '/');\n\n // Remove trailing slash for non-root paths\n if (localizedPath.length > 1 && localizedPath.endsWith('/')) {\n localizedPath = localizedPath.slice(0, -1);\n }\n\n // Combine with the base URL if the original URL was absolute\n if (isAbsoluteUrl) {\n return `${baseUrl}${localizedPath}${parsedUrl.search}${parsedUrl.hash}`;\n }\n\n return `${localizedPath}${parsedUrl.search}${parsedUrl.hash}`;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CA,MAAa,mBACX,KACA,eACA,UAII,EAAE,KACK;CACX,MAAM,EAAE,eAAe,MAAM,YAAY;EACvC,eACE,eAAe,sBAAsB,iBACrC,cAAc,qBAAqB;EACrC,MAAM,eAAe,SAAS,QAAQ,cAAc,QAAQ;EAC5D,SACE,eAAe,sBAAsB,WACrC,cAAc,qBAAqB;EACrC,GAAG;EACJ;CAGD,MAAM,mBAAmB,qBAAqB,KAAK,QAAQ;AAE3D,KAAI,SAAS,YAEX,QAAO;CAIT,MAAM,gBAAgB,mBAAmB,iBAAiB;CAI1D,MAAM,YAAY,gBACd,IAAI,IAAI,iBAAiB,GACzB,IAAI,IAAI,kBAAkB,qBAAqB;CAGnD,MAAM,UAAU,gBACZ,GAAG,UAAU,SAAS,IAAI,UAAU,SACpC;AAEJ,KAAI,SAAS,iBAAiB;EAE5B,MAAM,eAAe,IAAI,gBAAgB,UAAU,OAAO;AAC1D,eAAa,IAAI,UAAU,cAAc,UAAU,CAAC;EAEpD,MAAM,cAAc,aAAa,UAAU;EAC3C,MAAM,gBAAgB,cAClB,GAAG,UAAU,SAAS,GAAG,gBACzB,UAAU;AAEd,MAAI,cACF,QAAO,GAAG,UAAU,gBAAgB,UAAU;AAGhD,SAAO,GAAG,gBAAgB,UAAU;;CAGtC,MAAM,EAAE,WAAW,UAAU,eAAe;EAC1C;EACA;EACA;EACD,CAAC;CAGF,IAAI,gBAAgB,IAAI,SAAS,UAAU;AAG3C,iBAAgB,cAAc,WAAW,QAAQ,IAAI;AAGrD,KAAI,cAAc,SAAS,KAAK,cAAc,SAAS,IAAI,CACzD,iBAAgB,cAAc,MAAM,GAAG,GAAG;AAI5C,KAAI,cACF,QAAO,GAAG,UAAU,gBAAgB,UAAU,SAAS,UAAU;AAGnE,QAAO,GAAG,gBAAgB,UAAU,SAAS,UAAU"}
|