inline-i18n-multi 0.4.0 → 0.6.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/README.md +325 -28
- package/dist/index.d.mts +97 -5
- package/dist/index.d.ts +97 -5
- package/dist/index.js +451 -118
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +446 -119
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -8,6 +8,156 @@ function setLocale(locale) {
|
|
|
8
8
|
function getLocale() {
|
|
9
9
|
return currentLocale;
|
|
10
10
|
}
|
|
11
|
+
|
|
12
|
+
// src/config.ts
|
|
13
|
+
function defaultWarningHandler(warning) {
|
|
14
|
+
const parts = [`[inline-i18n] Missing translation for locale "${warning.requestedLocale}"`];
|
|
15
|
+
if (warning.key) {
|
|
16
|
+
parts.push(`key: "${warning.key}"`);
|
|
17
|
+
}
|
|
18
|
+
parts.push(`Available: [${warning.availableLocales.join(", ")}]`);
|
|
19
|
+
if (warning.fallbackUsed) {
|
|
20
|
+
parts.push(`Using fallback: "${warning.fallbackUsed}"`);
|
|
21
|
+
}
|
|
22
|
+
console.warn(parts.join(" | "));
|
|
23
|
+
}
|
|
24
|
+
function isDevMode() {
|
|
25
|
+
try {
|
|
26
|
+
if (typeof globalThis !== "undefined" && "process" in globalThis) {
|
|
27
|
+
const proc = globalThis.process;
|
|
28
|
+
return proc?.env?.NODE_ENV !== "production";
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
} catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
var defaultConfig = {
|
|
36
|
+
defaultLocale: "en",
|
|
37
|
+
fallbackLocale: "en",
|
|
38
|
+
autoParentLocale: true,
|
|
39
|
+
fallbackChain: {},
|
|
40
|
+
warnOnMissing: isDevMode(),
|
|
41
|
+
onMissingTranslation: defaultWarningHandler,
|
|
42
|
+
debugMode: false,
|
|
43
|
+
loader: void 0
|
|
44
|
+
};
|
|
45
|
+
var config = { ...defaultConfig };
|
|
46
|
+
function configure(options) {
|
|
47
|
+
config = { ...config, ...options };
|
|
48
|
+
}
|
|
49
|
+
function getConfig() {
|
|
50
|
+
return {
|
|
51
|
+
...defaultConfig,
|
|
52
|
+
...config
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function resetConfig() {
|
|
56
|
+
config = { ...defaultConfig };
|
|
57
|
+
}
|
|
58
|
+
function getParentLocale(locale) {
|
|
59
|
+
const dashIndex = locale.indexOf("-");
|
|
60
|
+
if (dashIndex > 0) {
|
|
61
|
+
return locale.substring(0, dashIndex);
|
|
62
|
+
}
|
|
63
|
+
return void 0;
|
|
64
|
+
}
|
|
65
|
+
function buildFallbackChain(locale) {
|
|
66
|
+
const cfg = getConfig();
|
|
67
|
+
if (cfg.fallbackChain[locale]) {
|
|
68
|
+
return [locale, ...cfg.fallbackChain[locale]];
|
|
69
|
+
}
|
|
70
|
+
const chain = [locale];
|
|
71
|
+
if (cfg.autoParentLocale) {
|
|
72
|
+
let current = locale;
|
|
73
|
+
while (true) {
|
|
74
|
+
const parent = getParentLocale(current);
|
|
75
|
+
if (parent && !chain.includes(parent)) {
|
|
76
|
+
chain.push(parent);
|
|
77
|
+
current = parent;
|
|
78
|
+
} else {
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const finalFallback = cfg.fallbackLocale;
|
|
84
|
+
if (finalFallback && !chain.includes(finalFallback)) {
|
|
85
|
+
chain.push(finalFallback);
|
|
86
|
+
}
|
|
87
|
+
return chain;
|
|
88
|
+
}
|
|
89
|
+
function emitWarning(warning) {
|
|
90
|
+
const cfg = getConfig();
|
|
91
|
+
if (cfg.warnOnMissing && cfg.onMissingTranslation) {
|
|
92
|
+
cfg.onMissingTranslation(warning);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function applyDebugFormat(output, debugInfo) {
|
|
96
|
+
const cfg = getConfig();
|
|
97
|
+
if (!cfg.debugMode) {
|
|
98
|
+
return output;
|
|
99
|
+
}
|
|
100
|
+
const options = typeof cfg.debugMode === "object" ? cfg.debugMode : { showMissingPrefix: true, showFallbackPrefix: true };
|
|
101
|
+
if (debugInfo.isMissing && options.showMissingPrefix !== false) {
|
|
102
|
+
const prefix = options.missingPrefixFormat ? options.missingPrefixFormat(debugInfo.requestedLocale, debugInfo.key) : `[MISSING: ${debugInfo.requestedLocale}] `;
|
|
103
|
+
return prefix + output;
|
|
104
|
+
}
|
|
105
|
+
if (debugInfo.isFallback && options.showFallbackPrefix !== false && debugInfo.usedLocale) {
|
|
106
|
+
const prefix = options.fallbackPrefixFormat ? options.fallbackPrefixFormat(debugInfo.requestedLocale, debugInfo.usedLocale, debugInfo.key) : `[${debugInfo.requestedLocale} -> ${debugInfo.usedLocale}] `;
|
|
107
|
+
return prefix + output;
|
|
108
|
+
}
|
|
109
|
+
return output;
|
|
110
|
+
}
|
|
111
|
+
function handleMissingVar(varName, locale) {
|
|
112
|
+
const cfg = getConfig();
|
|
113
|
+
if (cfg.missingVarHandler) {
|
|
114
|
+
return cfg.missingVarHandler(varName, locale);
|
|
115
|
+
}
|
|
116
|
+
return `{${varName}}`;
|
|
117
|
+
}
|
|
118
|
+
var customFormatters = /* @__PURE__ */ new Map();
|
|
119
|
+
var RESERVED_FORMATTER_NAMES = /* @__PURE__ */ new Set([
|
|
120
|
+
"plural",
|
|
121
|
+
"select",
|
|
122
|
+
"selectordinal",
|
|
123
|
+
"number",
|
|
124
|
+
"date",
|
|
125
|
+
"time",
|
|
126
|
+
"relativeTime",
|
|
127
|
+
"list",
|
|
128
|
+
"currency"
|
|
129
|
+
]);
|
|
130
|
+
function registerFormatter(name, formatter) {
|
|
131
|
+
if (RESERVED_FORMATTER_NAMES.has(name)) {
|
|
132
|
+
throw new Error(`Cannot register formatter "${name}": reserved ICU type name`);
|
|
133
|
+
}
|
|
134
|
+
customFormatters.set(name, formatter);
|
|
135
|
+
}
|
|
136
|
+
function clearFormatters() {
|
|
137
|
+
customFormatters.clear();
|
|
138
|
+
}
|
|
139
|
+
function buildCustomFormatterPattern() {
|
|
140
|
+
if (customFormatters.size === 0) return null;
|
|
141
|
+
const names = [...customFormatters.keys()].map((n) => n.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
142
|
+
return new RegExp(`\\{(\\w+),\\s*(${names})(?:,\\s*(\\w+))?\\}`, "g");
|
|
143
|
+
}
|
|
144
|
+
function preprocessCustomFormatters(template) {
|
|
145
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
146
|
+
const pattern = buildCustomFormatterPattern();
|
|
147
|
+
if (!pattern) return { processed: template, replacements };
|
|
148
|
+
let counter = 0;
|
|
149
|
+
const processed = template.replace(pattern, (_, variable, formatterName, style) => {
|
|
150
|
+
const placeholder = `__CUSTOM_${counter++}__`;
|
|
151
|
+
replacements.set(placeholder, { variable, formatterName, style });
|
|
152
|
+
return `{${placeholder}}`;
|
|
153
|
+
});
|
|
154
|
+
return { processed, replacements };
|
|
155
|
+
}
|
|
156
|
+
function hasCustomFormatter(template) {
|
|
157
|
+
const pattern = buildCustomFormatterPattern();
|
|
158
|
+
if (!pattern) return false;
|
|
159
|
+
return pattern.test(template);
|
|
160
|
+
}
|
|
11
161
|
var DATE_STYLES = {
|
|
12
162
|
short: { dateStyle: "short" },
|
|
13
163
|
medium: { dateStyle: "medium" },
|
|
@@ -49,11 +199,11 @@ function toDate(value) {
|
|
|
49
199
|
function formatNumberElement(el, vars, locale) {
|
|
50
200
|
const value = vars[el.value];
|
|
51
201
|
if (value === void 0) {
|
|
52
|
-
return
|
|
202
|
+
return handleMissingVar(el.value, locale);
|
|
53
203
|
}
|
|
54
204
|
const num = typeof value === "number" ? value : Number(value);
|
|
55
205
|
if (isNaN(num)) {
|
|
56
|
-
return
|
|
206
|
+
return handleMissingVar(el.value, locale);
|
|
57
207
|
}
|
|
58
208
|
let options = {};
|
|
59
209
|
if (el.style) {
|
|
@@ -76,7 +226,7 @@ function formatNumberElement(el, vars, locale) {
|
|
|
76
226
|
function formatDateElement(el, vars, locale) {
|
|
77
227
|
const value = vars[el.value];
|
|
78
228
|
if (value === void 0) {
|
|
79
|
-
return
|
|
229
|
+
return handleMissingVar(el.value, locale);
|
|
80
230
|
}
|
|
81
231
|
let options = {};
|
|
82
232
|
if (el.style) {
|
|
@@ -90,13 +240,13 @@ function formatDateElement(el, vars, locale) {
|
|
|
90
240
|
const date = toDate(value);
|
|
91
241
|
return new Intl.DateTimeFormat(locale, options).format(date);
|
|
92
242
|
} catch {
|
|
93
|
-
return
|
|
243
|
+
return handleMissingVar(el.value, locale);
|
|
94
244
|
}
|
|
95
245
|
}
|
|
96
246
|
function formatTimeElement(el, vars, locale) {
|
|
97
247
|
const value = vars[el.value];
|
|
98
248
|
if (value === void 0) {
|
|
99
|
-
return
|
|
249
|
+
return handleMissingVar(el.value, locale);
|
|
100
250
|
}
|
|
101
251
|
let options = {};
|
|
102
252
|
if (el.style) {
|
|
@@ -110,7 +260,68 @@ function formatTimeElement(el, vars, locale) {
|
|
|
110
260
|
const date = toDate(value);
|
|
111
261
|
return new Intl.DateTimeFormat(locale, options).format(date);
|
|
112
262
|
} catch {
|
|
113
|
-
return
|
|
263
|
+
return handleMissingVar(el.value, locale);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
var CURRENCY_PATTERN = /\{(\w+),\s*currency(?:,\s*(\w+))?\}/g;
|
|
267
|
+
function preprocessCurrency(template) {
|
|
268
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
269
|
+
let counter = 0;
|
|
270
|
+
const processed = template.replace(CURRENCY_PATTERN, (_, variable, currencyCode) => {
|
|
271
|
+
const placeholder = `__CURRENCY_${counter++}__`;
|
|
272
|
+
replacements.set(placeholder, { variable, currencyCode: currencyCode || "USD" });
|
|
273
|
+
return `{${placeholder}}`;
|
|
274
|
+
});
|
|
275
|
+
return { processed, replacements };
|
|
276
|
+
}
|
|
277
|
+
function formatCurrencyValue(variableName, currencyCode, vars, locale) {
|
|
278
|
+
const value = vars[variableName];
|
|
279
|
+
if (value === void 0) {
|
|
280
|
+
return handleMissingVar(variableName, locale);
|
|
281
|
+
}
|
|
282
|
+
const num = typeof value === "number" ? value : Number(value);
|
|
283
|
+
if (isNaN(num)) {
|
|
284
|
+
return handleMissingVar(variableName, locale);
|
|
285
|
+
}
|
|
286
|
+
try {
|
|
287
|
+
return new Intl.NumberFormat(locale, {
|
|
288
|
+
style: "currency",
|
|
289
|
+
currency: currencyCode
|
|
290
|
+
}).format(num);
|
|
291
|
+
} catch {
|
|
292
|
+
return String(num);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
var COMPACT_NUMBER_PATTERN = /\{(\w+),\s*number,\s*(compact|compactLong)\}/g;
|
|
296
|
+
function preprocessCompactNumber(template) {
|
|
297
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
298
|
+
let counter = 0;
|
|
299
|
+
const processed = template.replace(COMPACT_NUMBER_PATTERN, (_, variable, style) => {
|
|
300
|
+
const placeholder = `__COMPACT_${counter++}__`;
|
|
301
|
+
replacements.set(placeholder, {
|
|
302
|
+
variable,
|
|
303
|
+
display: style === "compactLong" ? "long" : "short"
|
|
304
|
+
});
|
|
305
|
+
return `{${placeholder}}`;
|
|
306
|
+
});
|
|
307
|
+
return { processed, replacements };
|
|
308
|
+
}
|
|
309
|
+
function formatCompactNumber(variableName, display, vars, locale) {
|
|
310
|
+
const value = vars[variableName];
|
|
311
|
+
if (value === void 0) {
|
|
312
|
+
return handleMissingVar(variableName, locale);
|
|
313
|
+
}
|
|
314
|
+
const num = typeof value === "number" ? value : Number(value);
|
|
315
|
+
if (isNaN(num)) {
|
|
316
|
+
return handleMissingVar(variableName, locale);
|
|
317
|
+
}
|
|
318
|
+
try {
|
|
319
|
+
return new Intl.NumberFormat(locale, {
|
|
320
|
+
notation: "compact",
|
|
321
|
+
compactDisplay: display
|
|
322
|
+
}).format(num);
|
|
323
|
+
} catch {
|
|
324
|
+
return String(num);
|
|
114
325
|
}
|
|
115
326
|
}
|
|
116
327
|
function getRelativeTimeUnit(date, now = /* @__PURE__ */ new Date()) {
|
|
@@ -144,7 +355,7 @@ function preprocessRelativeTime(template) {
|
|
|
144
355
|
function formatRelativeTimeValue(variableName, style, vars, locale) {
|
|
145
356
|
const value = vars[variableName];
|
|
146
357
|
if (value === void 0) {
|
|
147
|
-
return
|
|
358
|
+
return handleMissingVar(variableName, locale);
|
|
148
359
|
}
|
|
149
360
|
try {
|
|
150
361
|
const date = toDate(value);
|
|
@@ -152,7 +363,7 @@ function formatRelativeTimeValue(variableName, style, vars, locale) {
|
|
|
152
363
|
const options = style && RELATIVE_TIME_STYLES[style] || RELATIVE_TIME_STYLES.long;
|
|
153
364
|
return new Intl.RelativeTimeFormat(locale, options).format(relValue, unit);
|
|
154
365
|
} catch {
|
|
155
|
-
return
|
|
366
|
+
return handleMissingVar(variableName, locale);
|
|
156
367
|
}
|
|
157
368
|
}
|
|
158
369
|
var LIST_PATTERN = /\{(\w+),\s*list(?:,\s*(\w+))?(?:,\s*(\w+))?\}/g;
|
|
@@ -179,7 +390,7 @@ function preprocessList(template) {
|
|
|
179
390
|
function formatListValue(variableName, type, style, vars, locale) {
|
|
180
391
|
const value = vars[variableName];
|
|
181
392
|
if (value === void 0 || !Array.isArray(value)) {
|
|
182
|
-
return
|
|
393
|
+
return handleMissingVar(variableName, locale);
|
|
183
394
|
}
|
|
184
395
|
const options = {
|
|
185
396
|
type: type || "conjunction",
|
|
@@ -192,10 +403,32 @@ function formatListValue(variableName, type, style, vars, locale) {
|
|
|
192
403
|
}
|
|
193
404
|
}
|
|
194
405
|
function interpolateICU(template, vars, locale) {
|
|
195
|
-
const { processed:
|
|
406
|
+
const { processed: afterCustom, replacements: customReplacements } = preprocessCustomFormatters(template);
|
|
407
|
+
const { processed: afterCurrency, replacements: currencyReplacements } = preprocessCurrency(afterCustom);
|
|
408
|
+
const { processed: afterCompact, replacements: compactReplacements } = preprocessCompactNumber(afterCurrency);
|
|
409
|
+
const { processed: afterRelTime, replacements: relTimeReplacements } = preprocessRelativeTime(afterCompact);
|
|
196
410
|
const { processed: afterList, replacements: listReplacements } = preprocessList(afterRelTime);
|
|
197
411
|
const ast = parse(afterList);
|
|
198
412
|
let result = formatElements(ast, vars, locale, null);
|
|
413
|
+
for (const [placeholder, { variable, formatterName, style }] of customReplacements) {
|
|
414
|
+
const value = vars[variable];
|
|
415
|
+
let formatted;
|
|
416
|
+
if (value === void 0) {
|
|
417
|
+
formatted = handleMissingVar(variable, locale);
|
|
418
|
+
} else {
|
|
419
|
+
const formatter = customFormatters.get(formatterName);
|
|
420
|
+
formatted = formatter ? formatter(value, locale, style) : String(value);
|
|
421
|
+
}
|
|
422
|
+
result = result.replace(`{${placeholder}}`, formatted);
|
|
423
|
+
}
|
|
424
|
+
for (const [placeholder, { variable, currencyCode }] of currencyReplacements) {
|
|
425
|
+
const formatted = formatCurrencyValue(variable, currencyCode, vars, locale);
|
|
426
|
+
result = result.replace(`{${placeholder}}`, formatted);
|
|
427
|
+
}
|
|
428
|
+
for (const [placeholder, { variable, display }] of compactReplacements) {
|
|
429
|
+
const formatted = formatCompactNumber(variable, display, vars, locale);
|
|
430
|
+
result = result.replace(`{${placeholder}}`, formatted);
|
|
431
|
+
}
|
|
199
432
|
for (const [placeholder, { variable, style }] of relTimeReplacements) {
|
|
200
433
|
const formatted = formatRelativeTimeValue(variable, style, vars, locale);
|
|
201
434
|
result = result.replace(`{${placeholder}}`, formatted);
|
|
@@ -215,7 +448,11 @@ function formatElement(el, vars, locale, currentPluralValue) {
|
|
|
215
448
|
}
|
|
216
449
|
if (isArgumentElement(el)) {
|
|
217
450
|
const value = vars[el.value];
|
|
218
|
-
|
|
451
|
+
if (value !== void 0) return String(value);
|
|
452
|
+
if (el.value.startsWith("__") && el.value.endsWith("__")) {
|
|
453
|
+
return `{${el.value}}`;
|
|
454
|
+
}
|
|
455
|
+
return handleMissingVar(el.value, locale);
|
|
219
456
|
}
|
|
220
457
|
if (isPoundElement(el)) {
|
|
221
458
|
return currentPluralValue !== null ? String(currentPluralValue) : "#";
|
|
@@ -240,7 +477,7 @@ function formatElement(el, vars, locale, currentPluralValue) {
|
|
|
240
477
|
function formatPlural(el, vars, locale) {
|
|
241
478
|
const value = vars[el.value];
|
|
242
479
|
if (typeof value !== "number") {
|
|
243
|
-
return
|
|
480
|
+
return handleMissingVar(el.value, locale);
|
|
244
481
|
}
|
|
245
482
|
const adjustedValue = value - el.offset;
|
|
246
483
|
const pluralRules = new Intl.PluralRules(locale, { type: el.pluralType });
|
|
@@ -255,7 +492,7 @@ function formatPlural(el, vars, locale) {
|
|
|
255
492
|
if (el.options.other) {
|
|
256
493
|
return formatElements(el.options.other.value, vars, locale, adjustedValue);
|
|
257
494
|
}
|
|
258
|
-
return
|
|
495
|
+
return handleMissingVar(el.value, locale);
|
|
259
496
|
}
|
|
260
497
|
function formatSelect(el, vars, locale) {
|
|
261
498
|
const value = vars[el.value];
|
|
@@ -266,9 +503,9 @@ function formatSelect(el, vars, locale) {
|
|
|
266
503
|
if (el.options.other) {
|
|
267
504
|
return formatElements(el.options.other.value, vars, locale, null);
|
|
268
505
|
}
|
|
269
|
-
return
|
|
506
|
+
return handleMissingVar(el.value, locale);
|
|
270
507
|
}
|
|
271
|
-
var ICU_PATTERN = /\{[^}]+,\s*(plural|select|selectordinal|number|date|time|relativeTime|list)\s*[,}]/;
|
|
508
|
+
var ICU_PATTERN = /\{[^}]+,\s*(plural|select|selectordinal|number|date|time|relativeTime|list|currency)\s*[,}]/;
|
|
272
509
|
function hasICUPattern(template) {
|
|
273
510
|
return ICU_PATTERN.test(template);
|
|
274
511
|
}
|
|
@@ -276,113 +513,35 @@ function hasICUPattern(template) {
|
|
|
276
513
|
// src/interpolation.ts
|
|
277
514
|
var VARIABLE_PATTERN = /\{(\w+)\}/g;
|
|
278
515
|
function interpolate(template, vars, locale) {
|
|
279
|
-
|
|
280
|
-
if (hasICUPattern(template)) {
|
|
281
|
-
|
|
516
|
+
const resolvedLocale = locale || "en";
|
|
517
|
+
if (hasICUPattern(template) || hasCustomFormatter(template)) {
|
|
518
|
+
if (!vars) {
|
|
519
|
+
const cfg = getConfig();
|
|
520
|
+
if (cfg.missingVarHandler) {
|
|
521
|
+
return interpolateICU(template, {}, resolvedLocale);
|
|
522
|
+
}
|
|
523
|
+
return template;
|
|
524
|
+
}
|
|
525
|
+
return interpolateICU(template, vars, resolvedLocale);
|
|
526
|
+
}
|
|
527
|
+
if (!vars) {
|
|
528
|
+
const cfg = getConfig();
|
|
529
|
+
if (cfg.missingVarHandler) {
|
|
530
|
+
return template.replace(VARIABLE_PATTERN, (_, key) => {
|
|
531
|
+
return cfg.missingVarHandler(key, resolvedLocale);
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
return template;
|
|
282
535
|
}
|
|
283
536
|
return template.replace(VARIABLE_PATTERN, (_, key) => {
|
|
284
537
|
const value = vars[key];
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
// src/config.ts
|
|
290
|
-
function defaultWarningHandler(warning) {
|
|
291
|
-
const parts = [`[inline-i18n] Missing translation for locale "${warning.requestedLocale}"`];
|
|
292
|
-
if (warning.key) {
|
|
293
|
-
parts.push(`key: "${warning.key}"`);
|
|
294
|
-
}
|
|
295
|
-
parts.push(`Available: [${warning.availableLocales.join(", ")}]`);
|
|
296
|
-
if (warning.fallbackUsed) {
|
|
297
|
-
parts.push(`Using fallback: "${warning.fallbackUsed}"`);
|
|
298
|
-
}
|
|
299
|
-
console.warn(parts.join(" | "));
|
|
300
|
-
}
|
|
301
|
-
function isDevMode() {
|
|
302
|
-
try {
|
|
303
|
-
if (typeof globalThis !== "undefined" && "process" in globalThis) {
|
|
304
|
-
const proc = globalThis.process;
|
|
305
|
-
return proc?.env?.NODE_ENV !== "production";
|
|
538
|
+
if (value !== void 0) return String(value);
|
|
539
|
+
const cfg = getConfig();
|
|
540
|
+
if (cfg.missingVarHandler) {
|
|
541
|
+
return cfg.missingVarHandler(key, resolvedLocale);
|
|
306
542
|
}
|
|
307
|
-
return
|
|
308
|
-
}
|
|
309
|
-
return false;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
var defaultConfig = {
|
|
313
|
-
defaultLocale: "en",
|
|
314
|
-
fallbackLocale: "en",
|
|
315
|
-
autoParentLocale: true,
|
|
316
|
-
fallbackChain: {},
|
|
317
|
-
warnOnMissing: isDevMode(),
|
|
318
|
-
onMissingTranslation: defaultWarningHandler,
|
|
319
|
-
debugMode: false
|
|
320
|
-
};
|
|
321
|
-
var config = { ...defaultConfig };
|
|
322
|
-
function configure(options) {
|
|
323
|
-
config = { ...config, ...options };
|
|
324
|
-
}
|
|
325
|
-
function getConfig() {
|
|
326
|
-
return {
|
|
327
|
-
...defaultConfig,
|
|
328
|
-
...config
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
function resetConfig() {
|
|
332
|
-
config = { ...defaultConfig };
|
|
333
|
-
}
|
|
334
|
-
function getParentLocale(locale) {
|
|
335
|
-
const dashIndex = locale.indexOf("-");
|
|
336
|
-
if (dashIndex > 0) {
|
|
337
|
-
return locale.substring(0, dashIndex);
|
|
338
|
-
}
|
|
339
|
-
return void 0;
|
|
340
|
-
}
|
|
341
|
-
function buildFallbackChain(locale) {
|
|
342
|
-
const cfg = getConfig();
|
|
343
|
-
if (cfg.fallbackChain[locale]) {
|
|
344
|
-
return [locale, ...cfg.fallbackChain[locale]];
|
|
345
|
-
}
|
|
346
|
-
const chain = [locale];
|
|
347
|
-
if (cfg.autoParentLocale) {
|
|
348
|
-
let current = locale;
|
|
349
|
-
while (true) {
|
|
350
|
-
const parent = getParentLocale(current);
|
|
351
|
-
if (parent && !chain.includes(parent)) {
|
|
352
|
-
chain.push(parent);
|
|
353
|
-
current = parent;
|
|
354
|
-
} else {
|
|
355
|
-
break;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
const finalFallback = cfg.fallbackLocale;
|
|
360
|
-
if (finalFallback && !chain.includes(finalFallback)) {
|
|
361
|
-
chain.push(finalFallback);
|
|
362
|
-
}
|
|
363
|
-
return chain;
|
|
364
|
-
}
|
|
365
|
-
function emitWarning(warning) {
|
|
366
|
-
const cfg = getConfig();
|
|
367
|
-
if (cfg.warnOnMissing && cfg.onMissingTranslation) {
|
|
368
|
-
cfg.onMissingTranslation(warning);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
function applyDebugFormat(output, debugInfo) {
|
|
372
|
-
const cfg = getConfig();
|
|
373
|
-
if (!cfg.debugMode) {
|
|
374
|
-
return output;
|
|
375
|
-
}
|
|
376
|
-
const options = typeof cfg.debugMode === "object" ? cfg.debugMode : { showMissingPrefix: true, showFallbackPrefix: true };
|
|
377
|
-
if (debugInfo.isMissing && options.showMissingPrefix !== false) {
|
|
378
|
-
const prefix = options.missingPrefixFormat ? options.missingPrefixFormat(debugInfo.requestedLocale, debugInfo.key) : `[MISSING: ${debugInfo.requestedLocale}] `;
|
|
379
|
-
return prefix + output;
|
|
380
|
-
}
|
|
381
|
-
if (debugInfo.isFallback && options.showFallbackPrefix !== false && debugInfo.usedLocale) {
|
|
382
|
-
const prefix = options.fallbackPrefixFormat ? options.fallbackPrefixFormat(debugInfo.requestedLocale, debugInfo.usedLocale, debugInfo.key) : `[${debugInfo.requestedLocale} -> ${debugInfo.usedLocale}] `;
|
|
383
|
-
return prefix + output;
|
|
384
|
-
}
|
|
385
|
-
return output;
|
|
543
|
+
return `{${key}}`;
|
|
544
|
+
});
|
|
386
545
|
}
|
|
387
546
|
|
|
388
547
|
// src/translate.ts
|
|
@@ -519,6 +678,11 @@ var zh_es = createPair("zh", "es");
|
|
|
519
678
|
var DEFAULT_NAMESPACE = "default";
|
|
520
679
|
var NAMESPACE_SEPARATOR = ":";
|
|
521
680
|
var namespacedDictionaries = {};
|
|
681
|
+
var loadingState = {};
|
|
682
|
+
var loadingPromises = /* @__PURE__ */ new Map();
|
|
683
|
+
function getLoadingKey(locale, namespace) {
|
|
684
|
+
return `${namespace}:${locale}`;
|
|
685
|
+
}
|
|
522
686
|
function parseKey(fullKey) {
|
|
523
687
|
const separatorIndex = fullKey.indexOf(NAMESPACE_SEPARATOR);
|
|
524
688
|
if (separatorIndex > 0) {
|
|
@@ -555,10 +719,50 @@ function loadDictionary(locale, dict, namespace) {
|
|
|
555
719
|
function clearDictionaries(namespace) {
|
|
556
720
|
if (namespace) {
|
|
557
721
|
delete namespacedDictionaries[namespace];
|
|
722
|
+
for (const key of Object.keys(loadingState)) {
|
|
723
|
+
if (key.startsWith(`${namespace}:`)) {
|
|
724
|
+
delete loadingState[key];
|
|
725
|
+
loadingPromises.delete(key);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
558
728
|
} else {
|
|
559
729
|
namespacedDictionaries = {};
|
|
730
|
+
loadingState = {};
|
|
731
|
+
loadingPromises.clear();
|
|
560
732
|
}
|
|
561
733
|
}
|
|
734
|
+
async function loadAsync(locale, namespace) {
|
|
735
|
+
const ns = namespace || DEFAULT_NAMESPACE;
|
|
736
|
+
const cfg = getConfig();
|
|
737
|
+
if (!cfg.loader) {
|
|
738
|
+
throw new Error("No loader configured. Call configure({ loader: ... }) first.");
|
|
739
|
+
}
|
|
740
|
+
const key = getLoadingKey(locale, ns);
|
|
741
|
+
if (loadingState[key] === "loaded") return;
|
|
742
|
+
if (loadingPromises.has(key)) {
|
|
743
|
+
return loadingPromises.get(key);
|
|
744
|
+
}
|
|
745
|
+
const promise = (async () => {
|
|
746
|
+
loadingState[key] = "loading";
|
|
747
|
+
try {
|
|
748
|
+
const dict = await cfg.loader(locale, ns);
|
|
749
|
+
loadDictionary(locale, dict, ns);
|
|
750
|
+
loadingState[key] = "loaded";
|
|
751
|
+
} catch (error) {
|
|
752
|
+
loadingState[key] = "error";
|
|
753
|
+
throw error;
|
|
754
|
+
} finally {
|
|
755
|
+
loadingPromises.delete(key);
|
|
756
|
+
}
|
|
757
|
+
})();
|
|
758
|
+
loadingPromises.set(key, promise);
|
|
759
|
+
return promise;
|
|
760
|
+
}
|
|
761
|
+
function isLoaded(locale, namespace) {
|
|
762
|
+
const ns = namespace || DEFAULT_NAMESPACE;
|
|
763
|
+
const key = getLoadingKey(locale, ns);
|
|
764
|
+
return loadingState[key] === "loaded";
|
|
765
|
+
}
|
|
562
766
|
function getNestedValue(dict, key) {
|
|
563
767
|
const parts = key.split(".");
|
|
564
768
|
let current = dict;
|
|
@@ -668,6 +872,129 @@ function getLoadedNamespaces() {
|
|
|
668
872
|
return Object.keys(namespacedDictionaries);
|
|
669
873
|
}
|
|
670
874
|
|
|
671
|
-
|
|
875
|
+
// src/detect.ts
|
|
876
|
+
function matchLocale(candidate, supportedLocales) {
|
|
877
|
+
const normalized = candidate.trim().toLowerCase();
|
|
878
|
+
const exact = supportedLocales.find((l) => l.toLowerCase() === normalized);
|
|
879
|
+
if (exact) return exact;
|
|
880
|
+
const parent = getParentLocale(candidate);
|
|
881
|
+
if (parent) {
|
|
882
|
+
const parentMatch = supportedLocales.find((l) => l.toLowerCase() === parent.toLowerCase());
|
|
883
|
+
if (parentMatch) return parentMatch;
|
|
884
|
+
}
|
|
885
|
+
return void 0;
|
|
886
|
+
}
|
|
887
|
+
function detectFromNavigator(supportedLocales) {
|
|
888
|
+
if (typeof globalThis === "undefined") return void 0;
|
|
889
|
+
const nav = globalThis.navigator;
|
|
890
|
+
if (!nav) return void 0;
|
|
891
|
+
const languages = nav.languages || (nav.language ? [nav.language] : []);
|
|
892
|
+
for (const lang of languages) {
|
|
893
|
+
const match = matchLocale(lang, supportedLocales);
|
|
894
|
+
if (match) return match;
|
|
895
|
+
}
|
|
896
|
+
return void 0;
|
|
897
|
+
}
|
|
898
|
+
function detectFromCookie(supportedLocales, cookieName) {
|
|
899
|
+
if (typeof document === "undefined") return void 0;
|
|
900
|
+
const cookies = document.cookie.split(";");
|
|
901
|
+
for (const cookie of cookies) {
|
|
902
|
+
const [key, value] = cookie.split("=").map((s) => s.trim());
|
|
903
|
+
if (key === cookieName && value) {
|
|
904
|
+
return matchLocale(value, supportedLocales);
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
return void 0;
|
|
908
|
+
}
|
|
909
|
+
function detectFromUrl(supportedLocales) {
|
|
910
|
+
if (typeof location === "undefined") return void 0;
|
|
911
|
+
const pathname = location.pathname;
|
|
912
|
+
const match = pathname.match(/^\/([a-zA-Z]{2}(?:-[a-zA-Z]{2,})?)(?:\/|$)/);
|
|
913
|
+
if (match?.[1]) {
|
|
914
|
+
return matchLocale(match[1], supportedLocales);
|
|
915
|
+
}
|
|
916
|
+
return void 0;
|
|
917
|
+
}
|
|
918
|
+
function detectFromHeader(supportedLocales, headerValue) {
|
|
919
|
+
if (!headerValue) return void 0;
|
|
920
|
+
const entries = headerValue.split(",").map((part) => {
|
|
921
|
+
const parts = part.trim().split(";");
|
|
922
|
+
const lang = parts[0]?.trim() || "";
|
|
923
|
+
const qStr = parts[1];
|
|
924
|
+
const q = qStr ? parseFloat(qStr.replace(/q=/, "")) : 1;
|
|
925
|
+
return { lang, q };
|
|
926
|
+
}).sort((a, b) => b.q - a.q);
|
|
927
|
+
for (const { lang } of entries) {
|
|
928
|
+
const match = matchLocale(lang, supportedLocales);
|
|
929
|
+
if (match) return match;
|
|
930
|
+
}
|
|
931
|
+
return void 0;
|
|
932
|
+
}
|
|
933
|
+
function detectLocale(options) {
|
|
934
|
+
const {
|
|
935
|
+
supportedLocales,
|
|
936
|
+
defaultLocale,
|
|
937
|
+
sources = ["navigator"],
|
|
938
|
+
cookieName = "NEXT_LOCALE",
|
|
939
|
+
headerValue
|
|
940
|
+
} = options;
|
|
941
|
+
for (const source of sources) {
|
|
942
|
+
let detected;
|
|
943
|
+
switch (source) {
|
|
944
|
+
case "navigator":
|
|
945
|
+
detected = detectFromNavigator(supportedLocales);
|
|
946
|
+
break;
|
|
947
|
+
case "cookie":
|
|
948
|
+
detected = detectFromCookie(supportedLocales, cookieName);
|
|
949
|
+
break;
|
|
950
|
+
case "url":
|
|
951
|
+
detected = detectFromUrl(supportedLocales);
|
|
952
|
+
break;
|
|
953
|
+
case "header":
|
|
954
|
+
detected = detectFromHeader(supportedLocales, headerValue);
|
|
955
|
+
break;
|
|
956
|
+
}
|
|
957
|
+
if (detected) return detected;
|
|
958
|
+
}
|
|
959
|
+
return defaultLocale;
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
// src/richtext.ts
|
|
963
|
+
function escapeRegExp(str) {
|
|
964
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
965
|
+
}
|
|
966
|
+
function parseRichText(template, componentNames) {
|
|
967
|
+
if (componentNames.length === 0) {
|
|
968
|
+
return [{ type: "text", content: template }];
|
|
969
|
+
}
|
|
970
|
+
const segments = [];
|
|
971
|
+
const namesPattern = componentNames.map(escapeRegExp).join("|");
|
|
972
|
+
const regex = new RegExp(`<(${namesPattern})>(.*?)</\\1>`, "gs");
|
|
973
|
+
let lastIndex = 0;
|
|
974
|
+
let match;
|
|
975
|
+
while ((match = regex.exec(template)) !== null) {
|
|
976
|
+
if (match.index > lastIndex) {
|
|
977
|
+
segments.push({
|
|
978
|
+
type: "text",
|
|
979
|
+
content: template.slice(lastIndex, match.index)
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
segments.push({
|
|
983
|
+
type: "component",
|
|
984
|
+
content: match[2] ?? "",
|
|
985
|
+
componentName: match[1]
|
|
986
|
+
});
|
|
987
|
+
lastIndex = match.index + match[0].length;
|
|
988
|
+
}
|
|
989
|
+
if (lastIndex < template.length) {
|
|
990
|
+
segments.push({
|
|
991
|
+
type: "text",
|
|
992
|
+
content: template.slice(lastIndex)
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
return segments;
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
export { __i18n_lookup, clearDictionaries, clearFormatters, configure, detectLocale, en_de, en_es, en_fr, en_ja, en_zh, getConfig, getDictionary, getLoadedLocales, getLoadedNamespaces, getLocale, hasTranslation, isLoaded, it, it_de, it_es, it_fr, it_ja, it_zh, ja_es, ja_zh, loadAsync, loadDictionaries, loadDictionary, parseRichText, registerFormatter, resetConfig, setLocale, t, zh_es };
|
|
672
999
|
//# sourceMappingURL=index.mjs.map
|
|
673
1000
|
//# sourceMappingURL=index.mjs.map
|