inline-i18n-multi 0.5.0 → 0.7.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 +333 -27
- package/dist/index.d.mts +68 -5
- package/dist/index.d.ts +68 -5
- package/dist/index.js +392 -124
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +388 -125
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,14 +2,232 @@
|
|
|
2
2
|
|
|
3
3
|
var icuMessageformatParser = require('@formatjs/icu-messageformat-parser');
|
|
4
4
|
|
|
5
|
+
// src/config.ts
|
|
6
|
+
function defaultWarningHandler(warning) {
|
|
7
|
+
const parts = [`[inline-i18n] Missing translation for locale "${warning.requestedLocale}"`];
|
|
8
|
+
if (warning.key) {
|
|
9
|
+
parts.push(`key: "${warning.key}"`);
|
|
10
|
+
}
|
|
11
|
+
parts.push(`Available: [${warning.availableLocales.join(", ")}]`);
|
|
12
|
+
if (warning.fallbackUsed) {
|
|
13
|
+
parts.push(`Using fallback: "${warning.fallbackUsed}"`);
|
|
14
|
+
}
|
|
15
|
+
console.warn(parts.join(" | "));
|
|
16
|
+
}
|
|
17
|
+
function isDevMode() {
|
|
18
|
+
try {
|
|
19
|
+
if (typeof globalThis !== "undefined" && "process" in globalThis) {
|
|
20
|
+
const proc = globalThis.process;
|
|
21
|
+
return proc?.env?.NODE_ENV !== "production";
|
|
22
|
+
}
|
|
23
|
+
return false;
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
var defaultConfig = {
|
|
29
|
+
defaultLocale: "en",
|
|
30
|
+
fallbackLocale: "en",
|
|
31
|
+
autoParentLocale: true,
|
|
32
|
+
fallbackChain: {},
|
|
33
|
+
warnOnMissing: isDevMode(),
|
|
34
|
+
onMissingTranslation: defaultWarningHandler,
|
|
35
|
+
debugMode: false,
|
|
36
|
+
loader: void 0,
|
|
37
|
+
icuCacheSize: 500
|
|
38
|
+
};
|
|
39
|
+
var config = { ...defaultConfig };
|
|
40
|
+
function configure(options) {
|
|
41
|
+
config = { ...config, ...options };
|
|
42
|
+
}
|
|
43
|
+
function getConfig() {
|
|
44
|
+
return {
|
|
45
|
+
...defaultConfig,
|
|
46
|
+
...config
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function resetConfig() {
|
|
50
|
+
config = { ...defaultConfig };
|
|
51
|
+
}
|
|
52
|
+
function getParentLocale(locale) {
|
|
53
|
+
const dashIndex = locale.indexOf("-");
|
|
54
|
+
if (dashIndex > 0) {
|
|
55
|
+
return locale.substring(0, dashIndex);
|
|
56
|
+
}
|
|
57
|
+
return void 0;
|
|
58
|
+
}
|
|
59
|
+
function buildFallbackChain(locale) {
|
|
60
|
+
const cfg = getConfig();
|
|
61
|
+
if (cfg.fallbackChain[locale]) {
|
|
62
|
+
return [locale, ...cfg.fallbackChain[locale]];
|
|
63
|
+
}
|
|
64
|
+
const chain = [locale];
|
|
65
|
+
if (cfg.autoParentLocale) {
|
|
66
|
+
let current = locale;
|
|
67
|
+
while (true) {
|
|
68
|
+
const parent = getParentLocale(current);
|
|
69
|
+
if (parent && !chain.includes(parent)) {
|
|
70
|
+
chain.push(parent);
|
|
71
|
+
current = parent;
|
|
72
|
+
} else {
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const finalFallback = cfg.fallbackLocale;
|
|
78
|
+
if (finalFallback && !chain.includes(finalFallback)) {
|
|
79
|
+
chain.push(finalFallback);
|
|
80
|
+
}
|
|
81
|
+
return chain;
|
|
82
|
+
}
|
|
83
|
+
function emitWarning(warning) {
|
|
84
|
+
const cfg = getConfig();
|
|
85
|
+
if (cfg.warnOnMissing && cfg.onMissingTranslation) {
|
|
86
|
+
cfg.onMissingTranslation(warning);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function applyDebugFormat(output, debugInfo) {
|
|
90
|
+
const cfg = getConfig();
|
|
91
|
+
if (!cfg.debugMode) {
|
|
92
|
+
return output;
|
|
93
|
+
}
|
|
94
|
+
const options = typeof cfg.debugMode === "object" ? cfg.debugMode : { showMissingPrefix: true, showFallbackPrefix: true };
|
|
95
|
+
if (debugInfo.isMissing && options.showMissingPrefix !== false) {
|
|
96
|
+
const prefix = options.missingPrefixFormat ? options.missingPrefixFormat(debugInfo.requestedLocale, debugInfo.key) : `[MISSING: ${debugInfo.requestedLocale}] `;
|
|
97
|
+
return prefix + output;
|
|
98
|
+
}
|
|
99
|
+
if (debugInfo.isFallback && options.showFallbackPrefix !== false && debugInfo.usedLocale) {
|
|
100
|
+
const prefix = options.fallbackPrefixFormat ? options.fallbackPrefixFormat(debugInfo.requestedLocale, debugInfo.usedLocale, debugInfo.key) : `[${debugInfo.requestedLocale} -> ${debugInfo.usedLocale}] `;
|
|
101
|
+
return prefix + output;
|
|
102
|
+
}
|
|
103
|
+
return output;
|
|
104
|
+
}
|
|
105
|
+
|
|
5
106
|
// src/context.ts
|
|
6
107
|
var currentLocale = "en";
|
|
108
|
+
function setCookie(name, value, days) {
|
|
109
|
+
if (typeof document === "undefined") return;
|
|
110
|
+
const expires = new Date(Date.now() + days * 864e5).toUTCString();
|
|
111
|
+
document.cookie = `${name}=${value}; expires=${expires}; path=/; SameSite=Lax`;
|
|
112
|
+
}
|
|
113
|
+
function getCookie(name) {
|
|
114
|
+
if (typeof document === "undefined") return void 0;
|
|
115
|
+
const match = document.cookie.match(new RegExp(`(?:^|;\\s*)${name}=([^;]*)`));
|
|
116
|
+
return match?.[1];
|
|
117
|
+
}
|
|
118
|
+
function persistLocaleToStorage(locale) {
|
|
119
|
+
const cfg = getConfig();
|
|
120
|
+
if (!cfg.persistLocale) return;
|
|
121
|
+
const { storage, key = "LOCALE", expires = 365 } = cfg.persistLocale;
|
|
122
|
+
if (storage === "cookie") {
|
|
123
|
+
setCookie(key, locale, expires);
|
|
124
|
+
} else if (storage === "localStorage") {
|
|
125
|
+
if (typeof localStorage !== "undefined") {
|
|
126
|
+
try {
|
|
127
|
+
localStorage.setItem(key, locale);
|
|
128
|
+
} catch {
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
7
133
|
function setLocale(locale) {
|
|
8
134
|
currentLocale = locale;
|
|
135
|
+
persistLocaleToStorage(locale);
|
|
9
136
|
}
|
|
10
137
|
function getLocale() {
|
|
11
138
|
return currentLocale;
|
|
12
139
|
}
|
|
140
|
+
function restoreLocale() {
|
|
141
|
+
const cfg = getConfig();
|
|
142
|
+
if (!cfg.persistLocale) return void 0;
|
|
143
|
+
const { storage, key = "LOCALE" } = cfg.persistLocale;
|
|
144
|
+
let stored;
|
|
145
|
+
if (storage === "cookie") {
|
|
146
|
+
stored = getCookie(key);
|
|
147
|
+
} else if (storage === "localStorage") {
|
|
148
|
+
if (typeof localStorage !== "undefined") {
|
|
149
|
+
try {
|
|
150
|
+
stored = localStorage.getItem(key) ?? void 0;
|
|
151
|
+
} catch {
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (stored) {
|
|
156
|
+
currentLocale = stored;
|
|
157
|
+
return stored;
|
|
158
|
+
}
|
|
159
|
+
return void 0;
|
|
160
|
+
}
|
|
161
|
+
var icuCache = /* @__PURE__ */ new Map();
|
|
162
|
+
function clearICUCache() {
|
|
163
|
+
icuCache.clear();
|
|
164
|
+
}
|
|
165
|
+
function cachedParse(template) {
|
|
166
|
+
const cached = icuCache.get(template);
|
|
167
|
+
if (cached) return cached;
|
|
168
|
+
const ast = icuMessageformatParser.parse(template);
|
|
169
|
+
const cfg = getConfig();
|
|
170
|
+
if (cfg.icuCacheSize > 0) {
|
|
171
|
+
if (icuCache.size >= cfg.icuCacheSize) {
|
|
172
|
+
const firstKey = icuCache.keys().next().value;
|
|
173
|
+
if (firstKey !== void 0) {
|
|
174
|
+
icuCache.delete(firstKey);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
icuCache.set(template, ast);
|
|
178
|
+
}
|
|
179
|
+
return ast;
|
|
180
|
+
}
|
|
181
|
+
function handleMissingVar(varName, locale) {
|
|
182
|
+
const cfg = getConfig();
|
|
183
|
+
if (cfg.missingVarHandler) {
|
|
184
|
+
return cfg.missingVarHandler(varName, locale);
|
|
185
|
+
}
|
|
186
|
+
return `{${varName}}`;
|
|
187
|
+
}
|
|
188
|
+
var customFormatters = /* @__PURE__ */ new Map();
|
|
189
|
+
var RESERVED_FORMATTER_NAMES = /* @__PURE__ */ new Set([
|
|
190
|
+
"plural",
|
|
191
|
+
"select",
|
|
192
|
+
"selectordinal",
|
|
193
|
+
"number",
|
|
194
|
+
"date",
|
|
195
|
+
"time",
|
|
196
|
+
"relativeTime",
|
|
197
|
+
"list",
|
|
198
|
+
"currency"
|
|
199
|
+
]);
|
|
200
|
+
function registerFormatter(name, formatter) {
|
|
201
|
+
if (RESERVED_FORMATTER_NAMES.has(name)) {
|
|
202
|
+
throw new Error(`Cannot register formatter "${name}": reserved ICU type name`);
|
|
203
|
+
}
|
|
204
|
+
customFormatters.set(name, formatter);
|
|
205
|
+
}
|
|
206
|
+
function clearFormatters() {
|
|
207
|
+
customFormatters.clear();
|
|
208
|
+
}
|
|
209
|
+
function buildCustomFormatterPattern() {
|
|
210
|
+
if (customFormatters.size === 0) return null;
|
|
211
|
+
const names = [...customFormatters.keys()].map((n) => n.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
212
|
+
return new RegExp(`\\{(\\w+),\\s*(${names})(?:,\\s*(\\w+))?\\}`, "g");
|
|
213
|
+
}
|
|
214
|
+
function preprocessCustomFormatters(template) {
|
|
215
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
216
|
+
const pattern = buildCustomFormatterPattern();
|
|
217
|
+
if (!pattern) return { processed: template, replacements };
|
|
218
|
+
let counter = 0;
|
|
219
|
+
const processed = template.replace(pattern, (_, variable, formatterName, style) => {
|
|
220
|
+
const placeholder = `__CUSTOM_${counter++}__`;
|
|
221
|
+
replacements.set(placeholder, { variable, formatterName, style });
|
|
222
|
+
return `{${placeholder}}`;
|
|
223
|
+
});
|
|
224
|
+
return { processed, replacements };
|
|
225
|
+
}
|
|
226
|
+
function hasCustomFormatter(template) {
|
|
227
|
+
const pattern = buildCustomFormatterPattern();
|
|
228
|
+
if (!pattern) return false;
|
|
229
|
+
return pattern.test(template);
|
|
230
|
+
}
|
|
13
231
|
var DATE_STYLES = {
|
|
14
232
|
short: { dateStyle: "short" },
|
|
15
233
|
medium: { dateStyle: "medium" },
|
|
@@ -51,11 +269,11 @@ function toDate(value) {
|
|
|
51
269
|
function formatNumberElement(el, vars, locale) {
|
|
52
270
|
const value = vars[el.value];
|
|
53
271
|
if (value === void 0) {
|
|
54
|
-
return
|
|
272
|
+
return handleMissingVar(el.value, locale);
|
|
55
273
|
}
|
|
56
274
|
const num = typeof value === "number" ? value : Number(value);
|
|
57
275
|
if (isNaN(num)) {
|
|
58
|
-
return
|
|
276
|
+
return handleMissingVar(el.value, locale);
|
|
59
277
|
}
|
|
60
278
|
let options = {};
|
|
61
279
|
if (el.style) {
|
|
@@ -78,7 +296,7 @@ function formatNumberElement(el, vars, locale) {
|
|
|
78
296
|
function formatDateElement(el, vars, locale) {
|
|
79
297
|
const value = vars[el.value];
|
|
80
298
|
if (value === void 0) {
|
|
81
|
-
return
|
|
299
|
+
return handleMissingVar(el.value, locale);
|
|
82
300
|
}
|
|
83
301
|
let options = {};
|
|
84
302
|
if (el.style) {
|
|
@@ -92,13 +310,13 @@ function formatDateElement(el, vars, locale) {
|
|
|
92
310
|
const date = toDate(value);
|
|
93
311
|
return new Intl.DateTimeFormat(locale, options).format(date);
|
|
94
312
|
} catch {
|
|
95
|
-
return
|
|
313
|
+
return handleMissingVar(el.value, locale);
|
|
96
314
|
}
|
|
97
315
|
}
|
|
98
316
|
function formatTimeElement(el, vars, locale) {
|
|
99
317
|
const value = vars[el.value];
|
|
100
318
|
if (value === void 0) {
|
|
101
|
-
return
|
|
319
|
+
return handleMissingVar(el.value, locale);
|
|
102
320
|
}
|
|
103
321
|
let options = {};
|
|
104
322
|
if (el.style) {
|
|
@@ -112,7 +330,7 @@ function formatTimeElement(el, vars, locale) {
|
|
|
112
330
|
const date = toDate(value);
|
|
113
331
|
return new Intl.DateTimeFormat(locale, options).format(date);
|
|
114
332
|
} catch {
|
|
115
|
-
return
|
|
333
|
+
return handleMissingVar(el.value, locale);
|
|
116
334
|
}
|
|
117
335
|
}
|
|
118
336
|
var CURRENCY_PATTERN = /\{(\w+),\s*currency(?:,\s*(\w+))?\}/g;
|
|
@@ -129,11 +347,11 @@ function preprocessCurrency(template) {
|
|
|
129
347
|
function formatCurrencyValue(variableName, currencyCode, vars, locale) {
|
|
130
348
|
const value = vars[variableName];
|
|
131
349
|
if (value === void 0) {
|
|
132
|
-
return
|
|
350
|
+
return handleMissingVar(variableName, locale);
|
|
133
351
|
}
|
|
134
352
|
const num = typeof value === "number" ? value : Number(value);
|
|
135
353
|
if (isNaN(num)) {
|
|
136
|
-
return
|
|
354
|
+
return handleMissingVar(variableName, locale);
|
|
137
355
|
}
|
|
138
356
|
try {
|
|
139
357
|
return new Intl.NumberFormat(locale, {
|
|
@@ -161,11 +379,11 @@ function preprocessCompactNumber(template) {
|
|
|
161
379
|
function formatCompactNumber(variableName, display, vars, locale) {
|
|
162
380
|
const value = vars[variableName];
|
|
163
381
|
if (value === void 0) {
|
|
164
|
-
return
|
|
382
|
+
return handleMissingVar(variableName, locale);
|
|
165
383
|
}
|
|
166
384
|
const num = typeof value === "number" ? value : Number(value);
|
|
167
385
|
if (isNaN(num)) {
|
|
168
|
-
return
|
|
386
|
+
return handleMissingVar(variableName, locale);
|
|
169
387
|
}
|
|
170
388
|
try {
|
|
171
389
|
return new Intl.NumberFormat(locale, {
|
|
@@ -207,7 +425,7 @@ function preprocessRelativeTime(template) {
|
|
|
207
425
|
function formatRelativeTimeValue(variableName, style, vars, locale) {
|
|
208
426
|
const value = vars[variableName];
|
|
209
427
|
if (value === void 0) {
|
|
210
|
-
return
|
|
428
|
+
return handleMissingVar(variableName, locale);
|
|
211
429
|
}
|
|
212
430
|
try {
|
|
213
431
|
const date = toDate(value);
|
|
@@ -215,7 +433,7 @@ function formatRelativeTimeValue(variableName, style, vars, locale) {
|
|
|
215
433
|
const options = style && RELATIVE_TIME_STYLES[style] || RELATIVE_TIME_STYLES.long;
|
|
216
434
|
return new Intl.RelativeTimeFormat(locale, options).format(relValue, unit);
|
|
217
435
|
} catch {
|
|
218
|
-
return
|
|
436
|
+
return handleMissingVar(variableName, locale);
|
|
219
437
|
}
|
|
220
438
|
}
|
|
221
439
|
var LIST_PATTERN = /\{(\w+),\s*list(?:,\s*(\w+))?(?:,\s*(\w+))?\}/g;
|
|
@@ -242,7 +460,7 @@ function preprocessList(template) {
|
|
|
242
460
|
function formatListValue(variableName, type, style, vars, locale) {
|
|
243
461
|
const value = vars[variableName];
|
|
244
462
|
if (value === void 0 || !Array.isArray(value)) {
|
|
245
|
-
return
|
|
463
|
+
return handleMissingVar(variableName, locale);
|
|
246
464
|
}
|
|
247
465
|
const options = {
|
|
248
466
|
type: type || "conjunction",
|
|
@@ -254,13 +472,46 @@ function formatListValue(variableName, type, style, vars, locale) {
|
|
|
254
472
|
return value.join(", ");
|
|
255
473
|
}
|
|
256
474
|
}
|
|
475
|
+
var PLURAL_SHORTHAND_PATTERN = /\{(\w+),\s*p,\s*([^}]+)\}/g;
|
|
476
|
+
function hasPluralShorthand(template) {
|
|
477
|
+
PLURAL_SHORTHAND_PATTERN.lastIndex = 0;
|
|
478
|
+
return PLURAL_SHORTHAND_PATTERN.test(template);
|
|
479
|
+
}
|
|
480
|
+
function preprocessPluralShorthand(template) {
|
|
481
|
+
PLURAL_SHORTHAND_PATTERN.lastIndex = 0;
|
|
482
|
+
return template.replace(PLURAL_SHORTHAND_PATTERN, (_, variable, args) => {
|
|
483
|
+
const parts = args.split("|").map((s) => s.trim());
|
|
484
|
+
if (parts.length === 2) {
|
|
485
|
+
const [singular, plural] = parts;
|
|
486
|
+
return `{${variable}, plural, one {# ${singular}} other {# ${plural}}}`;
|
|
487
|
+
}
|
|
488
|
+
if (parts.length === 3) {
|
|
489
|
+
const [zero, singular, plural] = parts;
|
|
490
|
+
return `{${variable}, plural, =0 {${zero}} one {# ${singular}} other {# ${plural}}}`;
|
|
491
|
+
}
|
|
492
|
+
return `{${variable}, p, ${args}}`;
|
|
493
|
+
});
|
|
494
|
+
}
|
|
257
495
|
function interpolateICU(template, vars, locale) {
|
|
258
|
-
const
|
|
496
|
+
const afterPluralShorthand = preprocessPluralShorthand(template);
|
|
497
|
+
const { processed: afterCustom, replacements: customReplacements } = preprocessCustomFormatters(afterPluralShorthand);
|
|
498
|
+
const { processed: afterCurrency, replacements: currencyReplacements } = preprocessCurrency(afterCustom);
|
|
259
499
|
const { processed: afterCompact, replacements: compactReplacements } = preprocessCompactNumber(afterCurrency);
|
|
260
500
|
const { processed: afterRelTime, replacements: relTimeReplacements } = preprocessRelativeTime(afterCompact);
|
|
261
501
|
const { processed: afterList, replacements: listReplacements } = preprocessList(afterRelTime);
|
|
262
|
-
const ast =
|
|
502
|
+
const ast = cachedParse(afterList);
|
|
263
503
|
let result = formatElements(ast, vars, locale, null);
|
|
504
|
+
for (const [placeholder, { variable, formatterName, style }] of customReplacements) {
|
|
505
|
+
const value = vars[variable];
|
|
506
|
+
let formatted;
|
|
507
|
+
if (value === void 0) {
|
|
508
|
+
formatted = handleMissingVar(variable, locale);
|
|
509
|
+
} else {
|
|
510
|
+
const formatter = customFormatters.get(formatterName);
|
|
511
|
+
formatted = formatter ? formatter(value, locale, style) : String(value);
|
|
512
|
+
}
|
|
513
|
+
result = result.replace(`{${placeholder}}`, formatted);
|
|
514
|
+
}
|
|
264
515
|
for (const [placeholder, { variable, currencyCode }] of currencyReplacements) {
|
|
265
516
|
const formatted = formatCurrencyValue(variable, currencyCode, vars, locale);
|
|
266
517
|
result = result.replace(`{${placeholder}}`, formatted);
|
|
@@ -288,7 +539,11 @@ function formatElement(el, vars, locale, currentPluralValue) {
|
|
|
288
539
|
}
|
|
289
540
|
if (icuMessageformatParser.isArgumentElement(el)) {
|
|
290
541
|
const value = vars[el.value];
|
|
291
|
-
|
|
542
|
+
if (value !== void 0) return String(value);
|
|
543
|
+
if (el.value.startsWith("__") && el.value.endsWith("__")) {
|
|
544
|
+
return `{${el.value}}`;
|
|
545
|
+
}
|
|
546
|
+
return handleMissingVar(el.value, locale);
|
|
292
547
|
}
|
|
293
548
|
if (icuMessageformatParser.isPoundElement(el)) {
|
|
294
549
|
return currentPluralValue !== null ? String(currentPluralValue) : "#";
|
|
@@ -313,7 +568,7 @@ function formatElement(el, vars, locale, currentPluralValue) {
|
|
|
313
568
|
function formatPlural(el, vars, locale) {
|
|
314
569
|
const value = vars[el.value];
|
|
315
570
|
if (typeof value !== "number") {
|
|
316
|
-
return
|
|
571
|
+
return handleMissingVar(el.value, locale);
|
|
317
572
|
}
|
|
318
573
|
const adjustedValue = value - el.offset;
|
|
319
574
|
const pluralRules = new Intl.PluralRules(locale, { type: el.pluralType });
|
|
@@ -328,7 +583,7 @@ function formatPlural(el, vars, locale) {
|
|
|
328
583
|
if (el.options.other) {
|
|
329
584
|
return formatElements(el.options.other.value, vars, locale, adjustedValue);
|
|
330
585
|
}
|
|
331
|
-
return
|
|
586
|
+
return handleMissingVar(el.value, locale);
|
|
332
587
|
}
|
|
333
588
|
function formatSelect(el, vars, locale) {
|
|
334
589
|
const value = vars[el.value];
|
|
@@ -339,9 +594,9 @@ function formatSelect(el, vars, locale) {
|
|
|
339
594
|
if (el.options.other) {
|
|
340
595
|
return formatElements(el.options.other.value, vars, locale, null);
|
|
341
596
|
}
|
|
342
|
-
return
|
|
597
|
+
return handleMissingVar(el.value, locale);
|
|
343
598
|
}
|
|
344
|
-
var ICU_PATTERN = /\{[^}]+,\s*(plural|select|selectordinal|number|date|time|relativeTime|list|currency)\s*[,}]/;
|
|
599
|
+
var ICU_PATTERN = /\{[^}]+,\s*(plural|select|selectordinal|number|date|time|relativeTime|list|currency|p)\s*[,}]/;
|
|
345
600
|
function hasICUPattern(template) {
|
|
346
601
|
return ICU_PATTERN.test(template);
|
|
347
602
|
}
|
|
@@ -349,114 +604,35 @@ function hasICUPattern(template) {
|
|
|
349
604
|
// src/interpolation.ts
|
|
350
605
|
var VARIABLE_PATTERN = /\{(\w+)\}/g;
|
|
351
606
|
function interpolate(template, vars, locale) {
|
|
352
|
-
|
|
353
|
-
if (hasICUPattern(template)) {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
return value !== void 0 ? String(value) : `{${key}}`;
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// src/config.ts
|
|
363
|
-
function defaultWarningHandler(warning) {
|
|
364
|
-
const parts = [`[inline-i18n] Missing translation for locale "${warning.requestedLocale}"`];
|
|
365
|
-
if (warning.key) {
|
|
366
|
-
parts.push(`key: "${warning.key}"`);
|
|
367
|
-
}
|
|
368
|
-
parts.push(`Available: [${warning.availableLocales.join(", ")}]`);
|
|
369
|
-
if (warning.fallbackUsed) {
|
|
370
|
-
parts.push(`Using fallback: "${warning.fallbackUsed}"`);
|
|
371
|
-
}
|
|
372
|
-
console.warn(parts.join(" | "));
|
|
373
|
-
}
|
|
374
|
-
function isDevMode() {
|
|
375
|
-
try {
|
|
376
|
-
if (typeof globalThis !== "undefined" && "process" in globalThis) {
|
|
377
|
-
const proc = globalThis.process;
|
|
378
|
-
return proc?.env?.NODE_ENV !== "production";
|
|
379
|
-
}
|
|
380
|
-
return false;
|
|
381
|
-
} catch {
|
|
382
|
-
return false;
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
var defaultConfig = {
|
|
386
|
-
defaultLocale: "en",
|
|
387
|
-
fallbackLocale: "en",
|
|
388
|
-
autoParentLocale: true,
|
|
389
|
-
fallbackChain: {},
|
|
390
|
-
warnOnMissing: isDevMode(),
|
|
391
|
-
onMissingTranslation: defaultWarningHandler,
|
|
392
|
-
debugMode: false,
|
|
393
|
-
loader: void 0
|
|
394
|
-
};
|
|
395
|
-
var config = { ...defaultConfig };
|
|
396
|
-
function configure(options) {
|
|
397
|
-
config = { ...config, ...options };
|
|
398
|
-
}
|
|
399
|
-
function getConfig() {
|
|
400
|
-
return {
|
|
401
|
-
...defaultConfig,
|
|
402
|
-
...config
|
|
403
|
-
};
|
|
404
|
-
}
|
|
405
|
-
function resetConfig() {
|
|
406
|
-
config = { ...defaultConfig };
|
|
407
|
-
}
|
|
408
|
-
function getParentLocale(locale) {
|
|
409
|
-
const dashIndex = locale.indexOf("-");
|
|
410
|
-
if (dashIndex > 0) {
|
|
411
|
-
return locale.substring(0, dashIndex);
|
|
412
|
-
}
|
|
413
|
-
return void 0;
|
|
414
|
-
}
|
|
415
|
-
function buildFallbackChain(locale) {
|
|
416
|
-
const cfg = getConfig();
|
|
417
|
-
if (cfg.fallbackChain[locale]) {
|
|
418
|
-
return [locale, ...cfg.fallbackChain[locale]];
|
|
419
|
-
}
|
|
420
|
-
const chain = [locale];
|
|
421
|
-
if (cfg.autoParentLocale) {
|
|
422
|
-
let current = locale;
|
|
423
|
-
while (true) {
|
|
424
|
-
const parent = getParentLocale(current);
|
|
425
|
-
if (parent && !chain.includes(parent)) {
|
|
426
|
-
chain.push(parent);
|
|
427
|
-
current = parent;
|
|
428
|
-
} else {
|
|
429
|
-
break;
|
|
607
|
+
const resolvedLocale = locale || "en";
|
|
608
|
+
if (hasICUPattern(template) || hasCustomFormatter(template) || hasPluralShorthand(template)) {
|
|
609
|
+
if (!vars) {
|
|
610
|
+
const cfg = getConfig();
|
|
611
|
+
if (cfg.missingVarHandler) {
|
|
612
|
+
return interpolateICU(template, {}, resolvedLocale);
|
|
430
613
|
}
|
|
614
|
+
return template;
|
|
431
615
|
}
|
|
616
|
+
return interpolateICU(template, vars, resolvedLocale);
|
|
432
617
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
if (cfg.warnOnMissing && cfg.onMissingTranslation) {
|
|
442
|
-
cfg.onMissingTranslation(warning);
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
function applyDebugFormat(output, debugInfo) {
|
|
446
|
-
const cfg = getConfig();
|
|
447
|
-
if (!cfg.debugMode) {
|
|
448
|
-
return output;
|
|
449
|
-
}
|
|
450
|
-
const options = typeof cfg.debugMode === "object" ? cfg.debugMode : { showMissingPrefix: true, showFallbackPrefix: true };
|
|
451
|
-
if (debugInfo.isMissing && options.showMissingPrefix !== false) {
|
|
452
|
-
const prefix = options.missingPrefixFormat ? options.missingPrefixFormat(debugInfo.requestedLocale, debugInfo.key) : `[MISSING: ${debugInfo.requestedLocale}] `;
|
|
453
|
-
return prefix + output;
|
|
454
|
-
}
|
|
455
|
-
if (debugInfo.isFallback && options.showFallbackPrefix !== false && debugInfo.usedLocale) {
|
|
456
|
-
const prefix = options.fallbackPrefixFormat ? options.fallbackPrefixFormat(debugInfo.requestedLocale, debugInfo.usedLocale, debugInfo.key) : `[${debugInfo.requestedLocale} -> ${debugInfo.usedLocale}] `;
|
|
457
|
-
return prefix + output;
|
|
618
|
+
if (!vars) {
|
|
619
|
+
const cfg = getConfig();
|
|
620
|
+
if (cfg.missingVarHandler) {
|
|
621
|
+
return template.replace(VARIABLE_PATTERN, (_, key) => {
|
|
622
|
+
return cfg.missingVarHandler(key, resolvedLocale);
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
return template;
|
|
458
626
|
}
|
|
459
|
-
return
|
|
627
|
+
return template.replace(VARIABLE_PATTERN, (_, key) => {
|
|
628
|
+
const value = vars[key];
|
|
629
|
+
if (value !== void 0) return String(value);
|
|
630
|
+
const cfg = getConfig();
|
|
631
|
+
if (cfg.missingVarHandler) {
|
|
632
|
+
return cfg.missingVarHandler(key, resolvedLocale);
|
|
633
|
+
}
|
|
634
|
+
return `{${key}}`;
|
|
635
|
+
});
|
|
460
636
|
}
|
|
461
637
|
|
|
462
638
|
// src/translate.ts
|
|
@@ -787,6 +963,93 @@ function getLoadedNamespaces() {
|
|
|
787
963
|
return Object.keys(namespacedDictionaries);
|
|
788
964
|
}
|
|
789
965
|
|
|
966
|
+
// src/detect.ts
|
|
967
|
+
function matchLocale(candidate, supportedLocales) {
|
|
968
|
+
const normalized = candidate.trim().toLowerCase();
|
|
969
|
+
const exact = supportedLocales.find((l) => l.toLowerCase() === normalized);
|
|
970
|
+
if (exact) return exact;
|
|
971
|
+
const parent = getParentLocale(candidate);
|
|
972
|
+
if (parent) {
|
|
973
|
+
const parentMatch = supportedLocales.find((l) => l.toLowerCase() === parent.toLowerCase());
|
|
974
|
+
if (parentMatch) return parentMatch;
|
|
975
|
+
}
|
|
976
|
+
return void 0;
|
|
977
|
+
}
|
|
978
|
+
function detectFromNavigator(supportedLocales) {
|
|
979
|
+
if (typeof globalThis === "undefined") return void 0;
|
|
980
|
+
const nav = globalThis.navigator;
|
|
981
|
+
if (!nav) return void 0;
|
|
982
|
+
const languages = nav.languages || (nav.language ? [nav.language] : []);
|
|
983
|
+
for (const lang of languages) {
|
|
984
|
+
const match = matchLocale(lang, supportedLocales);
|
|
985
|
+
if (match) return match;
|
|
986
|
+
}
|
|
987
|
+
return void 0;
|
|
988
|
+
}
|
|
989
|
+
function detectFromCookie(supportedLocales, cookieName) {
|
|
990
|
+
if (typeof document === "undefined") return void 0;
|
|
991
|
+
const cookies = document.cookie.split(";");
|
|
992
|
+
for (const cookie of cookies) {
|
|
993
|
+
const [key, value] = cookie.split("=").map((s) => s.trim());
|
|
994
|
+
if (key === cookieName && value) {
|
|
995
|
+
return matchLocale(value, supportedLocales);
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
return void 0;
|
|
999
|
+
}
|
|
1000
|
+
function detectFromUrl(supportedLocales) {
|
|
1001
|
+
if (typeof location === "undefined") return void 0;
|
|
1002
|
+
const pathname = location.pathname;
|
|
1003
|
+
const match = pathname.match(/^\/([a-zA-Z]{2}(?:-[a-zA-Z]{2,})?)(?:\/|$)/);
|
|
1004
|
+
if (match?.[1]) {
|
|
1005
|
+
return matchLocale(match[1], supportedLocales);
|
|
1006
|
+
}
|
|
1007
|
+
return void 0;
|
|
1008
|
+
}
|
|
1009
|
+
function detectFromHeader(supportedLocales, headerValue) {
|
|
1010
|
+
if (!headerValue) return void 0;
|
|
1011
|
+
const entries = headerValue.split(",").map((part) => {
|
|
1012
|
+
const parts = part.trim().split(";");
|
|
1013
|
+
const lang = parts[0]?.trim() || "";
|
|
1014
|
+
const qStr = parts[1];
|
|
1015
|
+
const q = qStr ? parseFloat(qStr.replace(/q=/, "")) : 1;
|
|
1016
|
+
return { lang, q };
|
|
1017
|
+
}).sort((a, b) => b.q - a.q);
|
|
1018
|
+
for (const { lang } of entries) {
|
|
1019
|
+
const match = matchLocale(lang, supportedLocales);
|
|
1020
|
+
if (match) return match;
|
|
1021
|
+
}
|
|
1022
|
+
return void 0;
|
|
1023
|
+
}
|
|
1024
|
+
function detectLocale(options) {
|
|
1025
|
+
const {
|
|
1026
|
+
supportedLocales,
|
|
1027
|
+
defaultLocale,
|
|
1028
|
+
sources = ["navigator"],
|
|
1029
|
+
cookieName = "NEXT_LOCALE",
|
|
1030
|
+
headerValue
|
|
1031
|
+
} = options;
|
|
1032
|
+
for (const source of sources) {
|
|
1033
|
+
let detected;
|
|
1034
|
+
switch (source) {
|
|
1035
|
+
case "navigator":
|
|
1036
|
+
detected = detectFromNavigator(supportedLocales);
|
|
1037
|
+
break;
|
|
1038
|
+
case "cookie":
|
|
1039
|
+
detected = detectFromCookie(supportedLocales, cookieName);
|
|
1040
|
+
break;
|
|
1041
|
+
case "url":
|
|
1042
|
+
detected = detectFromUrl(supportedLocales);
|
|
1043
|
+
break;
|
|
1044
|
+
case "header":
|
|
1045
|
+
detected = detectFromHeader(supportedLocales, headerValue);
|
|
1046
|
+
break;
|
|
1047
|
+
}
|
|
1048
|
+
if (detected) return detected;
|
|
1049
|
+
}
|
|
1050
|
+
return defaultLocale;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
790
1053
|
// src/richtext.ts
|
|
791
1054
|
function escapeRegExp(str) {
|
|
792
1055
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -825,7 +1088,10 @@ function parseRichText(template, componentNames) {
|
|
|
825
1088
|
|
|
826
1089
|
exports.__i18n_lookup = __i18n_lookup;
|
|
827
1090
|
exports.clearDictionaries = clearDictionaries;
|
|
1091
|
+
exports.clearFormatters = clearFormatters;
|
|
1092
|
+
exports.clearICUCache = clearICUCache;
|
|
828
1093
|
exports.configure = configure;
|
|
1094
|
+
exports.detectLocale = detectLocale;
|
|
829
1095
|
exports.en_de = en_de;
|
|
830
1096
|
exports.en_es = en_es;
|
|
831
1097
|
exports.en_fr = en_fr;
|
|
@@ -850,7 +1116,9 @@ exports.loadAsync = loadAsync;
|
|
|
850
1116
|
exports.loadDictionaries = loadDictionaries;
|
|
851
1117
|
exports.loadDictionary = loadDictionary;
|
|
852
1118
|
exports.parseRichText = parseRichText;
|
|
1119
|
+
exports.registerFormatter = registerFormatter;
|
|
853
1120
|
exports.resetConfig = resetConfig;
|
|
1121
|
+
exports.restoreLocale = restoreLocale;
|
|
854
1122
|
exports.setLocale = setLocale;
|
|
855
1123
|
exports.t = t;
|
|
856
1124
|
exports.zh_es = zh_es;
|