inline-i18n-multi 0.2.0 → 0.4.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 +166 -6
- package/dist/index.d.mts +96 -11
- package/dist/index.d.ts +96 -11
- package/dist/index.js +499 -47
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +497 -49
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10,9 +10,203 @@ function setLocale(locale) {
|
|
|
10
10
|
function getLocale() {
|
|
11
11
|
return currentLocale;
|
|
12
12
|
}
|
|
13
|
+
var DATE_STYLES = {
|
|
14
|
+
short: { dateStyle: "short" },
|
|
15
|
+
medium: { dateStyle: "medium" },
|
|
16
|
+
long: { dateStyle: "long" },
|
|
17
|
+
full: { dateStyle: "full" }
|
|
18
|
+
};
|
|
19
|
+
var TIME_STYLES = {
|
|
20
|
+
short: { timeStyle: "short" },
|
|
21
|
+
medium: { timeStyle: "medium" },
|
|
22
|
+
long: { timeStyle: "long" },
|
|
23
|
+
full: { timeStyle: "full" }
|
|
24
|
+
};
|
|
25
|
+
var NUMBER_STYLES = {
|
|
26
|
+
decimal: { style: "decimal" },
|
|
27
|
+
percent: { style: "percent" },
|
|
28
|
+
integer: { style: "decimal", maximumFractionDigits: 0 }
|
|
29
|
+
};
|
|
30
|
+
var RELATIVE_TIME_STYLES = {
|
|
31
|
+
long: { style: "long", numeric: "auto" },
|
|
32
|
+
short: { style: "short", numeric: "auto" },
|
|
33
|
+
narrow: { style: "narrow", numeric: "auto" }
|
|
34
|
+
};
|
|
35
|
+
var LIST_TYPES = {
|
|
36
|
+
conjunction: "conjunction",
|
|
37
|
+
disjunction: "disjunction",
|
|
38
|
+
unit: "unit"
|
|
39
|
+
};
|
|
40
|
+
var LIST_STYLES = {
|
|
41
|
+
long: "long",
|
|
42
|
+
short: "short",
|
|
43
|
+
narrow: "narrow"
|
|
44
|
+
};
|
|
45
|
+
function toDate(value) {
|
|
46
|
+
if (value instanceof Date) {
|
|
47
|
+
return value;
|
|
48
|
+
}
|
|
49
|
+
return new Date(value);
|
|
50
|
+
}
|
|
51
|
+
function formatNumberElement(el, vars, locale) {
|
|
52
|
+
const value = vars[el.value];
|
|
53
|
+
if (value === void 0) {
|
|
54
|
+
return `{${el.value}}`;
|
|
55
|
+
}
|
|
56
|
+
const num = typeof value === "number" ? value : Number(value);
|
|
57
|
+
if (isNaN(num)) {
|
|
58
|
+
return `{${el.value}}`;
|
|
59
|
+
}
|
|
60
|
+
let options = {};
|
|
61
|
+
if (el.style) {
|
|
62
|
+
if (typeof el.style === "string") {
|
|
63
|
+
if (el.style === "currency") {
|
|
64
|
+
options = { style: "currency", currency: "USD" };
|
|
65
|
+
} else if (NUMBER_STYLES[el.style]) {
|
|
66
|
+
options = NUMBER_STYLES[el.style];
|
|
67
|
+
}
|
|
68
|
+
} else if ("parsedOptions" in el.style) {
|
|
69
|
+
options = el.style.parsedOptions;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
return new Intl.NumberFormat(locale, options).format(num);
|
|
74
|
+
} catch {
|
|
75
|
+
return String(num);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function formatDateElement(el, vars, locale) {
|
|
79
|
+
const value = vars[el.value];
|
|
80
|
+
if (value === void 0) {
|
|
81
|
+
return `{${el.value}}`;
|
|
82
|
+
}
|
|
83
|
+
let options = {};
|
|
84
|
+
if (el.style) {
|
|
85
|
+
if (typeof el.style === "string") {
|
|
86
|
+
options = DATE_STYLES[el.style] || {};
|
|
87
|
+
} else if ("parsedOptions" in el.style) {
|
|
88
|
+
options = el.style.parsedOptions;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
const date = toDate(value);
|
|
93
|
+
return new Intl.DateTimeFormat(locale, options).format(date);
|
|
94
|
+
} catch {
|
|
95
|
+
return `{${el.value}}`;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function formatTimeElement(el, vars, locale) {
|
|
99
|
+
const value = vars[el.value];
|
|
100
|
+
if (value === void 0) {
|
|
101
|
+
return `{${el.value}}`;
|
|
102
|
+
}
|
|
103
|
+
let options = {};
|
|
104
|
+
if (el.style) {
|
|
105
|
+
if (typeof el.style === "string") {
|
|
106
|
+
options = TIME_STYLES[el.style] || {};
|
|
107
|
+
} else if ("parsedOptions" in el.style) {
|
|
108
|
+
options = el.style.parsedOptions;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
const date = toDate(value);
|
|
113
|
+
return new Intl.DateTimeFormat(locale, options).format(date);
|
|
114
|
+
} catch {
|
|
115
|
+
return `{${el.value}}`;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function getRelativeTimeUnit(date, now = /* @__PURE__ */ new Date()) {
|
|
119
|
+
const diffMs = date.getTime() - now.getTime();
|
|
120
|
+
const diffSeconds = Math.round(diffMs / 1e3);
|
|
121
|
+
const diffMinutes = Math.round(diffSeconds / 60);
|
|
122
|
+
const diffHours = Math.round(diffMinutes / 60);
|
|
123
|
+
const diffDays = Math.round(diffHours / 24);
|
|
124
|
+
const diffWeeks = Math.round(diffDays / 7);
|
|
125
|
+
const diffMonths = Math.round(diffDays / 30);
|
|
126
|
+
const diffYears = Math.round(diffDays / 365);
|
|
127
|
+
if (Math.abs(diffSeconds) < 60) return { value: diffSeconds, unit: "second" };
|
|
128
|
+
if (Math.abs(diffMinutes) < 60) return { value: diffMinutes, unit: "minute" };
|
|
129
|
+
if (Math.abs(diffHours) < 24) return { value: diffHours, unit: "hour" };
|
|
130
|
+
if (Math.abs(diffDays) < 7) return { value: diffDays, unit: "day" };
|
|
131
|
+
if (Math.abs(diffWeeks) < 4) return { value: diffWeeks, unit: "week" };
|
|
132
|
+
if (Math.abs(diffMonths) < 12) return { value: diffMonths, unit: "month" };
|
|
133
|
+
return { value: diffYears, unit: "year" };
|
|
134
|
+
}
|
|
135
|
+
var RELATIVE_TIME_PATTERN = /\{(\w+),\s*relativeTime(?:,\s*(\w+))?\}/g;
|
|
136
|
+
function preprocessRelativeTime(template) {
|
|
137
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
138
|
+
let counter = 0;
|
|
139
|
+
const processed = template.replace(RELATIVE_TIME_PATTERN, (_, variable, style) => {
|
|
140
|
+
const placeholder = `__RELTIME_${counter++}__`;
|
|
141
|
+
replacements.set(placeholder, { variable, style });
|
|
142
|
+
return `{${placeholder}}`;
|
|
143
|
+
});
|
|
144
|
+
return { processed, replacements };
|
|
145
|
+
}
|
|
146
|
+
function formatRelativeTimeValue(variableName, style, vars, locale) {
|
|
147
|
+
const value = vars[variableName];
|
|
148
|
+
if (value === void 0) {
|
|
149
|
+
return `{${variableName}}`;
|
|
150
|
+
}
|
|
151
|
+
try {
|
|
152
|
+
const date = toDate(value);
|
|
153
|
+
const { value: relValue, unit } = getRelativeTimeUnit(date);
|
|
154
|
+
const options = style && RELATIVE_TIME_STYLES[style] || RELATIVE_TIME_STYLES.long;
|
|
155
|
+
return new Intl.RelativeTimeFormat(locale, options).format(relValue, unit);
|
|
156
|
+
} catch {
|
|
157
|
+
return `{${variableName}}`;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
var LIST_PATTERN = /\{(\w+),\s*list(?:,\s*(\w+))?(?:,\s*(\w+))?\}/g;
|
|
161
|
+
function preprocessList(template) {
|
|
162
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
163
|
+
let counter = 0;
|
|
164
|
+
const processed = template.replace(LIST_PATTERN, (_, variable, arg1, arg2) => {
|
|
165
|
+
const placeholder = `__LIST_${counter++}__`;
|
|
166
|
+
let type;
|
|
167
|
+
let style;
|
|
168
|
+
if (arg1) {
|
|
169
|
+
if (LIST_TYPES[arg1]) {
|
|
170
|
+
type = arg1;
|
|
171
|
+
style = arg2;
|
|
172
|
+
} else if (LIST_STYLES[arg1]) {
|
|
173
|
+
style = arg1;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
replacements.set(placeholder, { variable, type, style });
|
|
177
|
+
return `{${placeholder}}`;
|
|
178
|
+
});
|
|
179
|
+
return { processed, replacements };
|
|
180
|
+
}
|
|
181
|
+
function formatListValue(variableName, type, style, vars, locale) {
|
|
182
|
+
const value = vars[variableName];
|
|
183
|
+
if (value === void 0 || !Array.isArray(value)) {
|
|
184
|
+
return `{${variableName}}`;
|
|
185
|
+
}
|
|
186
|
+
const options = {
|
|
187
|
+
type: type || "conjunction",
|
|
188
|
+
style: style || "long"
|
|
189
|
+
};
|
|
190
|
+
try {
|
|
191
|
+
return new Intl.ListFormat(locale, options).format(value);
|
|
192
|
+
} catch {
|
|
193
|
+
return value.join(", ");
|
|
194
|
+
}
|
|
195
|
+
}
|
|
13
196
|
function interpolateICU(template, vars, locale) {
|
|
14
|
-
const
|
|
15
|
-
|
|
197
|
+
const { processed: afterRelTime, replacements: relTimeReplacements } = preprocessRelativeTime(template);
|
|
198
|
+
const { processed: afterList, replacements: listReplacements } = preprocessList(afterRelTime);
|
|
199
|
+
const ast = icuMessageformatParser.parse(afterList);
|
|
200
|
+
let result = formatElements(ast, vars, locale, null);
|
|
201
|
+
for (const [placeholder, { variable, style }] of relTimeReplacements) {
|
|
202
|
+
const formatted = formatRelativeTimeValue(variable, style, vars, locale);
|
|
203
|
+
result = result.replace(`{${placeholder}}`, formatted);
|
|
204
|
+
}
|
|
205
|
+
for (const [placeholder, { variable, type, style }] of listReplacements) {
|
|
206
|
+
const formatted = formatListValue(variable, type, style, vars, locale);
|
|
207
|
+
result = result.replace(`{${placeholder}}`, formatted);
|
|
208
|
+
}
|
|
209
|
+
return result;
|
|
16
210
|
}
|
|
17
211
|
function formatElements(elements, vars, locale, currentPluralValue) {
|
|
18
212
|
return elements.map((el) => formatElement(el, vars, locale, currentPluralValue)).join("");
|
|
@@ -34,6 +228,15 @@ function formatElement(el, vars, locale, currentPluralValue) {
|
|
|
34
228
|
if (icuMessageformatParser.isSelectElement(el)) {
|
|
35
229
|
return formatSelect(el, vars, locale);
|
|
36
230
|
}
|
|
231
|
+
if (icuMessageformatParser.isNumberElement(el)) {
|
|
232
|
+
return formatNumberElement(el, vars, locale);
|
|
233
|
+
}
|
|
234
|
+
if (icuMessageformatParser.isDateElement(el)) {
|
|
235
|
+
return formatDateElement(el, vars, locale);
|
|
236
|
+
}
|
|
237
|
+
if (icuMessageformatParser.isTimeElement(el)) {
|
|
238
|
+
return formatTimeElement(el, vars, locale);
|
|
239
|
+
}
|
|
37
240
|
return "";
|
|
38
241
|
}
|
|
39
242
|
function formatPlural(el, vars, locale) {
|
|
@@ -67,7 +270,7 @@ function formatSelect(el, vars, locale) {
|
|
|
67
270
|
}
|
|
68
271
|
return `{${el.value}}`;
|
|
69
272
|
}
|
|
70
|
-
var ICU_PATTERN = /\{[^}]+,\s*(plural|select|selectordinal)\s
|
|
273
|
+
var ICU_PATTERN = /\{[^}]+,\s*(plural|select|selectordinal|number|date|time|relativeTime|list)\s*[,}]/;
|
|
71
274
|
function hasICUPattern(template) {
|
|
72
275
|
return ICU_PATTERN.test(template);
|
|
73
276
|
}
|
|
@@ -85,45 +288,205 @@ function interpolate(template, vars, locale) {
|
|
|
85
288
|
});
|
|
86
289
|
}
|
|
87
290
|
|
|
291
|
+
// src/config.ts
|
|
292
|
+
function defaultWarningHandler(warning) {
|
|
293
|
+
const parts = [`[inline-i18n] Missing translation for locale "${warning.requestedLocale}"`];
|
|
294
|
+
if (warning.key) {
|
|
295
|
+
parts.push(`key: "${warning.key}"`);
|
|
296
|
+
}
|
|
297
|
+
parts.push(`Available: [${warning.availableLocales.join(", ")}]`);
|
|
298
|
+
if (warning.fallbackUsed) {
|
|
299
|
+
parts.push(`Using fallback: "${warning.fallbackUsed}"`);
|
|
300
|
+
}
|
|
301
|
+
console.warn(parts.join(" | "));
|
|
302
|
+
}
|
|
303
|
+
function isDevMode() {
|
|
304
|
+
try {
|
|
305
|
+
if (typeof globalThis !== "undefined" && "process" in globalThis) {
|
|
306
|
+
const proc = globalThis.process;
|
|
307
|
+
return proc?.env?.NODE_ENV !== "production";
|
|
308
|
+
}
|
|
309
|
+
return false;
|
|
310
|
+
} catch {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
var defaultConfig = {
|
|
315
|
+
defaultLocale: "en",
|
|
316
|
+
fallbackLocale: "en",
|
|
317
|
+
autoParentLocale: true,
|
|
318
|
+
fallbackChain: {},
|
|
319
|
+
warnOnMissing: isDevMode(),
|
|
320
|
+
onMissingTranslation: defaultWarningHandler,
|
|
321
|
+
debugMode: false
|
|
322
|
+
};
|
|
323
|
+
var config = { ...defaultConfig };
|
|
324
|
+
function configure(options) {
|
|
325
|
+
config = { ...config, ...options };
|
|
326
|
+
}
|
|
327
|
+
function getConfig() {
|
|
328
|
+
return {
|
|
329
|
+
...defaultConfig,
|
|
330
|
+
...config
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
function resetConfig() {
|
|
334
|
+
config = { ...defaultConfig };
|
|
335
|
+
}
|
|
336
|
+
function getParentLocale(locale) {
|
|
337
|
+
const dashIndex = locale.indexOf("-");
|
|
338
|
+
if (dashIndex > 0) {
|
|
339
|
+
return locale.substring(0, dashIndex);
|
|
340
|
+
}
|
|
341
|
+
return void 0;
|
|
342
|
+
}
|
|
343
|
+
function buildFallbackChain(locale) {
|
|
344
|
+
const cfg = getConfig();
|
|
345
|
+
if (cfg.fallbackChain[locale]) {
|
|
346
|
+
return [locale, ...cfg.fallbackChain[locale]];
|
|
347
|
+
}
|
|
348
|
+
const chain = [locale];
|
|
349
|
+
if (cfg.autoParentLocale) {
|
|
350
|
+
let current = locale;
|
|
351
|
+
while (true) {
|
|
352
|
+
const parent = getParentLocale(current);
|
|
353
|
+
if (parent && !chain.includes(parent)) {
|
|
354
|
+
chain.push(parent);
|
|
355
|
+
current = parent;
|
|
356
|
+
} else {
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
const finalFallback = cfg.fallbackLocale;
|
|
362
|
+
if (finalFallback && !chain.includes(finalFallback)) {
|
|
363
|
+
chain.push(finalFallback);
|
|
364
|
+
}
|
|
365
|
+
return chain;
|
|
366
|
+
}
|
|
367
|
+
function emitWarning(warning) {
|
|
368
|
+
const cfg = getConfig();
|
|
369
|
+
if (cfg.warnOnMissing && cfg.onMissingTranslation) {
|
|
370
|
+
cfg.onMissingTranslation(warning);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
function applyDebugFormat(output, debugInfo) {
|
|
374
|
+
const cfg = getConfig();
|
|
375
|
+
if (!cfg.debugMode) {
|
|
376
|
+
return output;
|
|
377
|
+
}
|
|
378
|
+
const options = typeof cfg.debugMode === "object" ? cfg.debugMode : { showMissingPrefix: true, showFallbackPrefix: true };
|
|
379
|
+
if (debugInfo.isMissing && options.showMissingPrefix !== false) {
|
|
380
|
+
const prefix = options.missingPrefixFormat ? options.missingPrefixFormat(debugInfo.requestedLocale, debugInfo.key) : `[MISSING: ${debugInfo.requestedLocale}] `;
|
|
381
|
+
return prefix + output;
|
|
382
|
+
}
|
|
383
|
+
if (debugInfo.isFallback && options.showFallbackPrefix !== false && debugInfo.usedLocale) {
|
|
384
|
+
const prefix = options.fallbackPrefixFormat ? options.fallbackPrefixFormat(debugInfo.requestedLocale, debugInfo.usedLocale, debugInfo.key) : `[${debugInfo.requestedLocale} -> ${debugInfo.usedLocale}] `;
|
|
385
|
+
return prefix + output;
|
|
386
|
+
}
|
|
387
|
+
return output;
|
|
388
|
+
}
|
|
389
|
+
|
|
88
390
|
// src/translate.ts
|
|
89
391
|
function resolveTemplate(translations) {
|
|
90
392
|
const locale = getLocale();
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
|
|
393
|
+
const availableLocales = Object.keys(translations);
|
|
394
|
+
const fallbackChain = buildFallbackChain(locale);
|
|
395
|
+
for (const tryLocale of fallbackChain) {
|
|
396
|
+
const template = translations[tryLocale];
|
|
397
|
+
if (template) {
|
|
398
|
+
const isFallback = tryLocale !== locale;
|
|
399
|
+
if (isFallback) {
|
|
400
|
+
emitWarning({
|
|
401
|
+
type: "missing_translation",
|
|
402
|
+
requestedLocale: locale,
|
|
403
|
+
availableLocales,
|
|
404
|
+
fallbackUsed: tryLocale
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
return {
|
|
408
|
+
template,
|
|
409
|
+
locale: tryLocale,
|
|
410
|
+
debugInfo: {
|
|
411
|
+
isMissing: false,
|
|
412
|
+
isFallback,
|
|
413
|
+
requestedLocale: locale,
|
|
414
|
+
usedLocale: tryLocale
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
const firstAvailable = Object.entries(translations)[0];
|
|
420
|
+
if (firstAvailable) {
|
|
421
|
+
emitWarning({
|
|
422
|
+
type: "missing_translation",
|
|
423
|
+
requestedLocale: locale,
|
|
424
|
+
availableLocales,
|
|
425
|
+
fallbackUsed: firstAvailable[0]
|
|
426
|
+
});
|
|
427
|
+
return {
|
|
428
|
+
template: firstAvailable[1],
|
|
429
|
+
locale: firstAvailable[0],
|
|
430
|
+
debugInfo: {
|
|
431
|
+
isMissing: false,
|
|
432
|
+
isFallback: true,
|
|
433
|
+
requestedLocale: locale,
|
|
434
|
+
usedLocale: firstAvailable[0]
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
}
|
|
95
438
|
throw new Error(
|
|
96
|
-
`No translation found for locale "${locale}". Available: ${
|
|
439
|
+
`No translation found for locale "${locale}". Available: ${availableLocales.join(", ")}`
|
|
97
440
|
);
|
|
98
441
|
}
|
|
99
442
|
function it(first, second, third) {
|
|
100
443
|
if (typeof first === "object") {
|
|
101
444
|
const translations2 = first;
|
|
102
445
|
const vars2 = second;
|
|
103
|
-
const { template: template2, locale: locale2 } = resolveTemplate(translations2);
|
|
104
|
-
|
|
446
|
+
const { template: template2, locale: locale2, debugInfo: debugInfo2 } = resolveTemplate(translations2);
|
|
447
|
+
const result2 = interpolate(template2, vars2, locale2);
|
|
448
|
+
return applyDebugFormat(result2, debugInfo2);
|
|
105
449
|
}
|
|
106
450
|
const ko = first;
|
|
107
451
|
const en = second;
|
|
108
452
|
const vars = third;
|
|
109
453
|
const translations = { ko, en };
|
|
110
|
-
const { template, locale } = resolveTemplate(translations);
|
|
111
|
-
|
|
454
|
+
const { template, locale, debugInfo } = resolveTemplate(translations);
|
|
455
|
+
const result = interpolate(template, vars, locale);
|
|
456
|
+
return applyDebugFormat(result, debugInfo);
|
|
112
457
|
}
|
|
113
458
|
|
|
114
459
|
// src/runtime.ts
|
|
115
460
|
function __i18n_lookup(_hash, translations, vars) {
|
|
116
461
|
const locale = getLocale();
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
462
|
+
const availableLocales = Object.keys(translations);
|
|
463
|
+
const fallbackChain = buildFallbackChain(locale);
|
|
464
|
+
for (const tryLocale of fallbackChain) {
|
|
465
|
+
const template = translations[tryLocale];
|
|
466
|
+
if (template) {
|
|
467
|
+
if (tryLocale !== locale) {
|
|
468
|
+
emitWarning({
|
|
469
|
+
type: "missing_translation",
|
|
470
|
+
requestedLocale: locale,
|
|
471
|
+
availableLocales,
|
|
472
|
+
fallbackUsed: tryLocale
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
return interpolate(template, vars, tryLocale);
|
|
476
|
+
}
|
|
120
477
|
}
|
|
121
|
-
const
|
|
122
|
-
if (
|
|
123
|
-
|
|
478
|
+
const firstAvailable = Object.entries(translations)[0];
|
|
479
|
+
if (firstAvailable) {
|
|
480
|
+
emitWarning({
|
|
481
|
+
type: "missing_translation",
|
|
482
|
+
requestedLocale: locale,
|
|
483
|
+
availableLocales,
|
|
484
|
+
fallbackUsed: firstAvailable[0]
|
|
485
|
+
});
|
|
486
|
+
return interpolate(firstAvailable[1], vars, firstAvailable[0]);
|
|
124
487
|
}
|
|
125
488
|
throw new Error(
|
|
126
|
-
`No translation found for locale "${locale}". Available: ${
|
|
489
|
+
`No translation found for locale "${locale}". Available: ${availableLocales.join(", ")}`
|
|
127
490
|
);
|
|
128
491
|
}
|
|
129
492
|
if (typeof globalThis !== "undefined") {
|
|
@@ -155,15 +518,48 @@ var ja_es = createPair("ja", "es");
|
|
|
155
518
|
var zh_es = createPair("zh", "es");
|
|
156
519
|
|
|
157
520
|
// src/dictionary.ts
|
|
158
|
-
var
|
|
159
|
-
|
|
160
|
-
|
|
521
|
+
var DEFAULT_NAMESPACE = "default";
|
|
522
|
+
var NAMESPACE_SEPARATOR = ":";
|
|
523
|
+
var namespacedDictionaries = {};
|
|
524
|
+
function parseKey(fullKey) {
|
|
525
|
+
const separatorIndex = fullKey.indexOf(NAMESPACE_SEPARATOR);
|
|
526
|
+
if (separatorIndex > 0) {
|
|
527
|
+
return {
|
|
528
|
+
namespace: fullKey.substring(0, separatorIndex),
|
|
529
|
+
key: fullKey.substring(separatorIndex + 1)
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
return {
|
|
533
|
+
namespace: DEFAULT_NAMESPACE,
|
|
534
|
+
key: fullKey
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
function loadDictionaries(dicts, namespace) {
|
|
538
|
+
const ns = namespace || DEFAULT_NAMESPACE;
|
|
539
|
+
if (!namespacedDictionaries[ns]) {
|
|
540
|
+
namespacedDictionaries[ns] = {};
|
|
541
|
+
}
|
|
542
|
+
namespacedDictionaries[ns] = {
|
|
543
|
+
...namespacedDictionaries[ns],
|
|
544
|
+
...dicts
|
|
545
|
+
};
|
|
161
546
|
}
|
|
162
|
-
function loadDictionary(locale, dict) {
|
|
163
|
-
|
|
547
|
+
function loadDictionary(locale, dict, namespace) {
|
|
548
|
+
const ns = namespace || DEFAULT_NAMESPACE;
|
|
549
|
+
if (!namespacedDictionaries[ns]) {
|
|
550
|
+
namespacedDictionaries[ns] = {};
|
|
551
|
+
}
|
|
552
|
+
namespacedDictionaries[ns][locale] = {
|
|
553
|
+
...namespacedDictionaries[ns][locale],
|
|
554
|
+
...dict
|
|
555
|
+
};
|
|
164
556
|
}
|
|
165
|
-
function clearDictionaries() {
|
|
166
|
-
|
|
557
|
+
function clearDictionaries(namespace) {
|
|
558
|
+
if (namespace) {
|
|
559
|
+
delete namespacedDictionaries[namespace];
|
|
560
|
+
} else {
|
|
561
|
+
namespacedDictionaries = {};
|
|
562
|
+
}
|
|
167
563
|
}
|
|
168
564
|
function getNestedValue(dict, key) {
|
|
169
565
|
const parts = key.split(".");
|
|
@@ -183,54 +579,109 @@ function getPluralCategory(count, locale) {
|
|
|
183
579
|
const rules = new Intl.PluralRules(locale);
|
|
184
580
|
return rules.select(count);
|
|
185
581
|
}
|
|
186
|
-
function
|
|
187
|
-
const currentLocale2 = locale ?? getLocale();
|
|
188
|
-
const dict = dictionaries[currentLocale2];
|
|
189
|
-
if (!dict) {
|
|
190
|
-
console.warn(`[inline-i18n] No dictionary loaded for locale: ${currentLocale2}`);
|
|
191
|
-
return key;
|
|
192
|
-
}
|
|
582
|
+
function findInDictionary(dict, key, vars, locale) {
|
|
193
583
|
let template = getNestedValue(dict, key);
|
|
194
584
|
if (vars && typeof vars.count === "number") {
|
|
195
|
-
const pluralKey = `${key}_${getPluralCategory(vars.count,
|
|
585
|
+
const pluralKey = `${key}_${getPluralCategory(vars.count, locale)}`;
|
|
196
586
|
const pluralTemplate = getNestedValue(dict, pluralKey);
|
|
197
587
|
if (pluralTemplate) {
|
|
198
588
|
template = pluralTemplate;
|
|
199
589
|
}
|
|
200
590
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
591
|
+
return template;
|
|
592
|
+
}
|
|
593
|
+
function t(key, vars, locale) {
|
|
594
|
+
const { namespace, key: actualKey } = parseKey(key);
|
|
595
|
+
const currentLocale2 = locale ?? getLocale();
|
|
596
|
+
const fallbackChain = buildFallbackChain(currentLocale2);
|
|
597
|
+
const nsDictionaries = namespacedDictionaries[namespace] || {};
|
|
598
|
+
const availableLocales = Object.keys(nsDictionaries);
|
|
599
|
+
let template;
|
|
600
|
+
let usedLocale;
|
|
601
|
+
for (const tryLocale of fallbackChain) {
|
|
602
|
+
const dict = nsDictionaries[tryLocale];
|
|
603
|
+
if (!dict) continue;
|
|
604
|
+
const found = findInDictionary(dict, actualKey, vars, tryLocale);
|
|
605
|
+
if (found) {
|
|
606
|
+
template = found;
|
|
607
|
+
usedLocale = tryLocale;
|
|
608
|
+
break;
|
|
205
609
|
}
|
|
206
610
|
}
|
|
207
611
|
if (!template) {
|
|
208
|
-
|
|
209
|
-
|
|
612
|
+
emitWarning({
|
|
613
|
+
type: "missing_translation",
|
|
614
|
+
key,
|
|
615
|
+
requestedLocale: currentLocale2,
|
|
616
|
+
availableLocales
|
|
617
|
+
});
|
|
618
|
+
const debugInfo2 = {
|
|
619
|
+
isMissing: true,
|
|
620
|
+
isFallback: false,
|
|
621
|
+
requestedLocale: currentLocale2,
|
|
622
|
+
key
|
|
623
|
+
};
|
|
624
|
+
return applyDebugFormat(key, debugInfo2);
|
|
210
625
|
}
|
|
211
|
-
|
|
626
|
+
const isFallback = usedLocale !== currentLocale2;
|
|
627
|
+
if (isFallback) {
|
|
628
|
+
emitWarning({
|
|
629
|
+
type: "missing_translation",
|
|
630
|
+
key,
|
|
631
|
+
requestedLocale: currentLocale2,
|
|
632
|
+
availableLocales,
|
|
633
|
+
fallbackUsed: usedLocale
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
const result = interpolate(template, vars, usedLocale || currentLocale2);
|
|
637
|
+
const debugInfo = {
|
|
638
|
+
isMissing: false,
|
|
639
|
+
isFallback,
|
|
640
|
+
requestedLocale: currentLocale2,
|
|
641
|
+
usedLocale,
|
|
642
|
+
key
|
|
643
|
+
};
|
|
644
|
+
return applyDebugFormat(result, debugInfo);
|
|
212
645
|
}
|
|
213
646
|
function hasTranslation(key, locale) {
|
|
647
|
+
const { namespace, key: actualKey } = parseKey(key);
|
|
214
648
|
const currentLocale2 = locale ?? getLocale();
|
|
215
|
-
const
|
|
216
|
-
|
|
649
|
+
const nsDictionaries = namespacedDictionaries[namespace] || {};
|
|
650
|
+
const dict = nsDictionaries[currentLocale2];
|
|
651
|
+
return dict ? getNestedValue(dict, actualKey) !== void 0 : false;
|
|
652
|
+
}
|
|
653
|
+
function getLoadedLocales(namespace) {
|
|
654
|
+
if (namespace) {
|
|
655
|
+
return Object.keys(namespacedDictionaries[namespace] || {});
|
|
656
|
+
}
|
|
657
|
+
const locales = /* @__PURE__ */ new Set();
|
|
658
|
+
for (const ns of Object.values(namespacedDictionaries)) {
|
|
659
|
+
for (const locale of Object.keys(ns)) {
|
|
660
|
+
locales.add(locale);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
return Array.from(locales);
|
|
217
664
|
}
|
|
218
|
-
function
|
|
219
|
-
|
|
665
|
+
function getDictionary(locale, namespace) {
|
|
666
|
+
const ns = namespace || DEFAULT_NAMESPACE;
|
|
667
|
+
return namespacedDictionaries[ns]?.[locale];
|
|
220
668
|
}
|
|
221
|
-
function
|
|
222
|
-
return
|
|
669
|
+
function getLoadedNamespaces() {
|
|
670
|
+
return Object.keys(namespacedDictionaries);
|
|
223
671
|
}
|
|
224
672
|
|
|
225
673
|
exports.__i18n_lookup = __i18n_lookup;
|
|
226
674
|
exports.clearDictionaries = clearDictionaries;
|
|
675
|
+
exports.configure = configure;
|
|
227
676
|
exports.en_de = en_de;
|
|
228
677
|
exports.en_es = en_es;
|
|
229
678
|
exports.en_fr = en_fr;
|
|
230
679
|
exports.en_ja = en_ja;
|
|
231
680
|
exports.en_zh = en_zh;
|
|
681
|
+
exports.getConfig = getConfig;
|
|
232
682
|
exports.getDictionary = getDictionary;
|
|
233
683
|
exports.getLoadedLocales = getLoadedLocales;
|
|
684
|
+
exports.getLoadedNamespaces = getLoadedNamespaces;
|
|
234
685
|
exports.getLocale = getLocale;
|
|
235
686
|
exports.hasTranslation = hasTranslation;
|
|
236
687
|
exports.it = it;
|
|
@@ -243,6 +694,7 @@ exports.ja_es = ja_es;
|
|
|
243
694
|
exports.ja_zh = ja_zh;
|
|
244
695
|
exports.loadDictionaries = loadDictionaries;
|
|
245
696
|
exports.loadDictionary = loadDictionary;
|
|
697
|
+
exports.resetConfig = resetConfig;
|
|
246
698
|
exports.setLocale = setLocale;
|
|
247
699
|
exports.t = t;
|
|
248
700
|
exports.zh_es = zh_es;
|