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/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 `{${el.value}}`;
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 `{${el.value}}`;
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 `{${el.value}}`;
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 `{${el.value}}`;
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 `{${el.value}}`;
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 `{${el.value}}`;
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 `{${variableName}}`;
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 `{${variableName}}`;
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 `{${variableName}}`;
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: afterRelTime, replacements: relTimeReplacements } = preprocessRelativeTime(template);
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
- return value !== void 0 ? String(value) : `{${el.value}}`;
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 `{${el.value}}`;
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 `{${el.value}}`;
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 `{${el.value}}`;
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
- if (!vars) return template;
280
- if (hasICUPattern(template)) {
281
- return interpolateICU(template, vars, locale || "en");
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
- return value !== void 0 ? String(value) : `{${key}}`;
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 false;
308
- } catch {
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
- export { __i18n_lookup, clearDictionaries, configure, en_de, en_es, en_fr, en_ja, en_zh, getConfig, getDictionary, getLoadedLocales, getLoadedNamespaces, getLocale, hasTranslation, it, it_de, it_es, it_fr, it_ja, it_zh, ja_es, ja_zh, loadDictionaries, loadDictionary, resetConfig, setLocale, t, zh_es };
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