@pure-ds/core 0.7.30 → 0.7.33

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.
Files changed (86) hide show
  1. package/.github/copilot-instructions.md +20 -11
  2. package/LOCALIZATION.md +197 -0
  3. package/dist/types/pds.config.d.ts +1 -1
  4. package/dist/types/pds.config.d.ts.map +1 -1
  5. package/dist/types/pds.d.ts +150 -0
  6. package/dist/types/public/assets/pds/components/pds-form.d.ts +2 -2
  7. package/dist/types/public/assets/pds/components/pds-form.d.ts.map +1 -1
  8. package/dist/types/public/assets/pds/components/pds-omnibox.d.ts +2 -2
  9. package/dist/types/public/assets/pds/components/pds-omnibox.d.ts.map +1 -1
  10. package/dist/types/public/assets/pds/components/pds-rating.d.ts +1 -119
  11. package/dist/types/public/assets/pds/components/pds-rating.d.ts.map +1 -1
  12. package/dist/types/public/assets/pds/components/pds-treeview.d.ts.map +1 -1
  13. package/dist/types/public/assets/pds/components/pds-upload.d.ts.map +1 -1
  14. package/dist/types/src/js/common/ask.d.ts.map +1 -1
  15. package/dist/types/src/js/common/font-loader.d.ts.map +1 -1
  16. package/dist/types/src/js/common/localization-resource-provider.d.ts +49 -0
  17. package/dist/types/src/js/common/localization-resource-provider.d.ts.map +1 -0
  18. package/dist/types/src/js/common/localization.d.ts +25 -0
  19. package/dist/types/src/js/common/localization.d.ts.map +1 -0
  20. package/dist/types/src/js/common/msg.d.ts +1 -2
  21. package/dist/types/src/js/common/msg.d.ts.map +1 -1
  22. package/dist/types/src/js/common/pds-log.d.ts +3 -0
  23. package/dist/types/src/js/common/pds-log.d.ts.map +1 -0
  24. package/dist/types/src/js/lit.d.ts +0 -7
  25. package/dist/types/src/js/lit.d.ts.map +1 -1
  26. package/dist/types/src/js/pds-core/pds-config.d.ts +51 -0
  27. package/dist/types/src/js/pds-core/pds-config.d.ts.map +1 -1
  28. package/dist/types/src/js/pds-core/pds-enhancers.d.ts.map +1 -1
  29. package/dist/types/src/js/pds-core/pds-live.d.ts.map +1 -1
  30. package/dist/types/src/js/pds-core/pds-registry.d.ts.map +1 -1
  31. package/dist/types/src/js/pds-core/pds-runtime.d.ts.map +1 -1
  32. package/dist/types/src/js/pds-core/pds-start-helpers.d.ts.map +1 -1
  33. package/dist/types/src/js/pds-localization.d.ts +3 -0
  34. package/dist/types/src/js/pds-localization.d.ts.map +1 -0
  35. package/dist/types/src/js/pds-singleton.d.ts +13 -0
  36. package/dist/types/src/js/pds-singleton.d.ts.map +1 -0
  37. package/dist/types/src/js/pds.d.ts +9 -1
  38. package/dist/types/src/js/pds.d.ts.map +1 -1
  39. package/package.json +10 -4
  40. package/packages/pds-cli/README.md +2 -0
  41. package/packages/pds-cli/lib/pds-mcp-core.js +2 -2
  42. package/public/assets/js/app.js +9 -11
  43. package/public/assets/js/lit.js +3 -94
  44. package/public/assets/js/pds-ask.js +4 -4
  45. package/public/assets/js/pds-enhancers.js +1 -1
  46. package/public/assets/js/pds-localization.js +1 -0
  47. package/public/assets/js/pds-manager.js +118 -118
  48. package/public/assets/js/pds.js +2 -2
  49. package/public/assets/pds/components/pds-calendar.js +4 -4
  50. package/public/assets/pds/components/pds-daterange.js +11 -8
  51. package/public/assets/pds/components/pds-form.js +22 -22
  52. package/public/assets/pds/components/pds-live-edit.js +503 -42
  53. package/public/assets/pds/components/pds-live-importer.js +66 -66
  54. package/public/assets/pds/components/pds-live-template-canvas.js +3 -3
  55. package/public/assets/pds/components/pds-omnibox.js +4 -4
  56. package/public/assets/pds/components/pds-rating.js +5 -3
  57. package/public/assets/pds/components/pds-tags.js +5 -5
  58. package/public/assets/pds/components/pds-theme.js +4 -4
  59. package/public/assets/pds/components/pds-toaster.js +6 -6
  60. package/public/assets/pds/components/pds-treeview.js +8 -4
  61. package/public/assets/pds/components/pds-upload.js +7 -6
  62. package/public/assets/pds/core/pds-ask.js +4 -4
  63. package/public/assets/pds/core/pds-enhancers.js +1 -1
  64. package/public/assets/pds/core/pds-localization.js +1 -0
  65. package/public/assets/pds/core/pds-manager.js +118 -118
  66. package/public/assets/pds/core.js +2 -2
  67. package/public/assets/pds/external/lit.js +3 -94
  68. package/readme.md +34 -6
  69. package/src/js/common/ask.js +530 -0
  70. package/src/js/common/common.js +122 -0
  71. package/src/js/common/font-loader.js +202 -0
  72. package/src/js/common/localization-resource-provider.js +274 -0
  73. package/src/js/common/localization.js +839 -0
  74. package/src/js/common/msg.js +9 -0
  75. package/src/js/common/pds-core/pds.d.ts +128 -0
  76. package/src/js/common/pds-log.js +144 -0
  77. package/src/js/common/toast.js +122 -0
  78. package/src/js/pds-core/pds-config.js +51 -10
  79. package/src/js/pds-core/pds-enhancers.js +5 -3
  80. package/src/js/pds-core/pds-live.js +7 -5
  81. package/src/js/pds-core/pds-registry.js +6 -4
  82. package/src/js/pds-core/pds-runtime.js +12 -8
  83. package/src/js/pds-core/pds-start-helpers.js +9 -4
  84. package/src/js/pds-singleton.js +49 -0
  85. package/src/js/pds.d.ts +150 -0
  86. package/src/js/pds.js +420 -40
@@ -0,0 +1,839 @@
1
+ import { pdsLog } from "./pds-log.js";
2
+
3
+ const __DEFAULT_LOCALE__ = "en";
4
+
5
+ const __localizationState = {
6
+ defaultLocale: __DEFAULT_LOCALE__,
7
+ provider: null,
8
+ messagesByLocale: new Map(),
9
+ loadingByLocale: new Map(),
10
+ observer: null,
11
+ reconcileTimer: null,
12
+ requestedKeys: new Set(),
13
+ textNodeKeyMap: new WeakMap(),
14
+ valueToKeys: new Map(),
15
+ missingWarnings: new Set(),
16
+ };
17
+
18
+ const __isStrTagged = (val) =>
19
+ Boolean(val) && typeof val !== "string" && typeof val === "object" && "strTag" in val;
20
+
21
+ function __normalizeLocale(locale) {
22
+ return String(locale || "").trim().toLowerCase();
23
+ }
24
+
25
+ function __toBaseLocale(locale) {
26
+ const normalized = __normalizeLocale(locale);
27
+ if (!normalized) return "";
28
+ return normalized.split("-")[0] || normalized;
29
+ }
30
+
31
+ function __resolveLocaleCandidate(locale) {
32
+ const normalized = __normalizeLocale(locale);
33
+ if (!normalized) {
34
+ return __localizationState.defaultLocale;
35
+ }
36
+ return normalized;
37
+ }
38
+
39
+ function __collateStrings(strings) {
40
+ let result = "";
41
+ for (let index = 0; index <= strings.length - 1; index += 1) {
42
+ result += strings[index];
43
+ if (index < strings.length - 1) {
44
+ result += `{${index}}`;
45
+ }
46
+ }
47
+ return result;
48
+ }
49
+
50
+ function __replacePlaceholders(input, callback) {
51
+ return String(input).replace(/\{(\d+)\}/g, (_match, index) => callback(Number(index)));
52
+ }
53
+
54
+ function __normalizeMessages(messages) {
55
+ if (!messages || typeof messages !== "object") {
56
+ return {};
57
+ }
58
+
59
+ const normalized = {};
60
+ for (const [key, value] of Object.entries(messages)) {
61
+ if (typeof value === "string") {
62
+ normalized[key] = value;
63
+ continue;
64
+ }
65
+
66
+ if (value && typeof value === "object" && typeof value.content === "string") {
67
+ normalized[key] = value.content;
68
+ }
69
+ }
70
+
71
+ return normalized;
72
+ }
73
+
74
+ function __resolveProvider(config) {
75
+ const provider =
76
+ config && typeof config.provider === "object" && config.provider
77
+ ? config.provider
78
+ : null;
79
+
80
+ const translate =
81
+ typeof config?.translate === "function"
82
+ ? config.translate
83
+ : typeof provider?.translate === "function"
84
+ ? provider.translate
85
+ : null;
86
+
87
+ const loadLocale =
88
+ typeof config?.loadLocale === "function"
89
+ ? config.loadLocale
90
+ : typeof provider?.loadLocale === "function"
91
+ ? provider.loadLocale
92
+ : null;
93
+
94
+ const setLocale =
95
+ typeof config?.setLocale === "function"
96
+ ? config.setLocale
97
+ : typeof provider?.setLocale === "function"
98
+ ? provider.setLocale
99
+ : null;
100
+
101
+ if (!translate && !loadLocale && !setLocale) {
102
+ return null;
103
+ }
104
+
105
+ return {
106
+ translate,
107
+ loadLocale,
108
+ setLocale,
109
+ };
110
+ }
111
+
112
+ function __localeVariants(locale) {
113
+ const normalized = __normalizeLocale(locale);
114
+ if (!normalized) {
115
+ return [__localizationState.defaultLocale];
116
+ }
117
+ const base = __toBaseLocale(normalized);
118
+ if (!base || base === normalized) {
119
+ return [normalized];
120
+ }
121
+ return [normalized, base];
122
+ }
123
+
124
+ function __setLocaleMessages(locale, messages) {
125
+ const normalizedLocale = __resolveLocaleCandidate(locale);
126
+ __localizationState.messagesByLocale.set(
127
+ normalizedLocale,
128
+ __normalizeMessages(messages)
129
+ );
130
+ }
131
+
132
+ function __registerRequestedKey(key) {
133
+ if (typeof key === "string" && key.length > 0) {
134
+ __localizationState.requestedKeys.add(key);
135
+ }
136
+ }
137
+
138
+ function __indexTranslatedValue(key, value) {
139
+ if (typeof key !== "string" || !key.length) {
140
+ return;
141
+ }
142
+
143
+ const translatedValue = typeof value === "string" ? value : String(value || "");
144
+ if (!translatedValue.length) {
145
+ return;
146
+ }
147
+
148
+ if (!__localizationState.valueToKeys.has(translatedValue)) {
149
+ __localizationState.valueToKeys.set(translatedValue, new Set());
150
+ }
151
+
152
+ __localizationState.valueToKeys.get(translatedValue).add(key);
153
+ }
154
+
155
+ function __getLocaleMessages(locale) {
156
+ const variants = __localeVariants(locale);
157
+ for (const candidate of variants) {
158
+ if (__localizationState.messagesByLocale.has(candidate)) {
159
+ return {
160
+ locale: candidate,
161
+ messages: __localizationState.messagesByLocale.get(candidate),
162
+ };
163
+ }
164
+ }
165
+ return null;
166
+ }
167
+
168
+ async function __loadLocaleInternal(locale, reason = "explicit") {
169
+ const targetLocale = __resolveLocaleCandidate(locale);
170
+ const existing = __getLocaleMessages(targetLocale);
171
+ if (existing) {
172
+ return existing.messages;
173
+ }
174
+
175
+ const loadingKey = targetLocale;
176
+ if (__localizationState.loadingByLocale.has(loadingKey)) {
177
+ return __localizationState.loadingByLocale.get(loadingKey);
178
+ }
179
+
180
+ if (!__localizationState.provider) {
181
+ return {};
182
+ }
183
+
184
+ const loader =
185
+ __localizationState.provider.loadLocale ||
186
+ __localizationState.provider.setLocale ||
187
+ null;
188
+
189
+ if (typeof loader !== "function") {
190
+ return {};
191
+ }
192
+
193
+ const context = {
194
+ locale: targetLocale,
195
+ defaultLocale: __localizationState.defaultLocale,
196
+ reason,
197
+ loadedLocales: Array.from(__localizationState.messagesByLocale.keys()),
198
+ messages: {
199
+ ...(__getLocaleMessages(targetLocale)?.messages || {}),
200
+ },
201
+ load: reason === "set-default" || reason === "explicit-load",
202
+ };
203
+
204
+ let result;
205
+ try {
206
+ result = loader(context);
207
+ } catch {
208
+ return {};
209
+ }
210
+
211
+ if (result && typeof result.then === "function") {
212
+ const promise = result
213
+ .then((value) => {
214
+ const normalized = __normalizeMessages(value);
215
+ __setLocaleMessages(targetLocale, normalized);
216
+ return normalized;
217
+ })
218
+ .catch(() => ({}))
219
+ .finally(() => {
220
+ __localizationState.loadingByLocale.delete(loadingKey);
221
+ });
222
+
223
+ __localizationState.loadingByLocale.set(loadingKey, promise);
224
+ return promise;
225
+ }
226
+
227
+ const normalized = __normalizeMessages(result);
228
+ __setLocaleMessages(targetLocale, normalized);
229
+ return normalized;
230
+ }
231
+
232
+ function __resolveLocaleFromElementScope(element) {
233
+ if (!element || typeof element !== "object") {
234
+ return "";
235
+ }
236
+
237
+ const canUseElementCtor = typeof Element !== "undefined";
238
+ const el =
239
+ canUseElementCtor && element instanceof Element
240
+ ? element
241
+ : element?.nodeType === 1
242
+ ? element
243
+ : null;
244
+
245
+ if (!el) {
246
+ return "";
247
+ }
248
+
249
+ if (el.hasAttribute?.("lang")) {
250
+ return __normalizeLocale(el.getAttribute("lang"));
251
+ }
252
+
253
+ const scoped = el.closest?.("[lang]");
254
+ if (scoped && scoped.getAttribute) {
255
+ return __normalizeLocale(scoped.getAttribute("lang"));
256
+ }
257
+
258
+ return "";
259
+ }
260
+
261
+ function __resolveContextLocale(options = {}) {
262
+ if (typeof options?.lang === "string" && options.lang.trim()) {
263
+ return __resolveLocaleCandidate(options.lang);
264
+ }
265
+
266
+ const scopeElement =
267
+ options?.element || options?.scope || options?.host || options?.contextElement || null;
268
+ const scopedLocale = __resolveLocaleFromElementScope(scopeElement);
269
+ if (scopedLocale) {
270
+ return __resolveLocaleCandidate(scopedLocale);
271
+ }
272
+
273
+ if (typeof document !== "undefined" && document.documentElement) {
274
+ const rootLocale = __normalizeLocale(document.documentElement.getAttribute("lang"));
275
+ if (rootLocale) {
276
+ return __resolveLocaleCandidate(rootLocale);
277
+ }
278
+ }
279
+
280
+ return __localizationState.defaultLocale;
281
+ }
282
+
283
+ function __collectDetectedLocales() {
284
+ const detected = new Set([__localizationState.defaultLocale]);
285
+
286
+ if (typeof document === "undefined") {
287
+ return detected;
288
+ }
289
+
290
+ const rootLang = __normalizeLocale(document.documentElement?.getAttribute?.("lang"));
291
+ if (rootLang) {
292
+ detected.add(__resolveLocaleCandidate(rootLang));
293
+ }
294
+
295
+ const nodes = document.querySelectorAll?.("[lang]") || [];
296
+ for (const node of nodes) {
297
+ const lang = __normalizeLocale(node.getAttribute("lang"));
298
+ if (lang) {
299
+ detected.add(__resolveLocaleCandidate(lang));
300
+ }
301
+ }
302
+
303
+ return detected;
304
+ }
305
+
306
+ async function __ensureDetectedLocalesLoaded(detectedLocales) {
307
+ for (const locale of detectedLocales) {
308
+ await __loadLocaleInternal(locale, "lang-detected");
309
+ }
310
+ }
311
+
312
+ function __pruneUndetectedLocales(detectedLocales) {
313
+ for (const loadedLocale of Array.from(__localizationState.messagesByLocale.keys())) {
314
+ if (!detectedLocales.has(loadedLocale)) {
315
+ __localizationState.messagesByLocale.delete(loadedLocale);
316
+ }
317
+ }
318
+ }
319
+
320
+ function __splitTextWhitespace(value) {
321
+ const input = String(value || "");
322
+ const leading = (input.match(/^\s*/) || [""])[0];
323
+ const trailing = (input.match(/\s*$/) || [""])[0];
324
+ const start = leading.length;
325
+ const end = input.length - trailing.length;
326
+ const core = end >= start ? input.slice(start, end) : "";
327
+
328
+ return { leading, core, trailing };
329
+ }
330
+
331
+ function __escapeRegExp(value) {
332
+ return String(value || "").replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
333
+ }
334
+
335
+ function __extractValuesFromTemplate(template, text) {
336
+ const inputTemplate = typeof template === "string" ? template : String(template || "");
337
+ const inputText = typeof text === "string" ? text : String(text || "");
338
+ const placeholderPattern = /\{(\d+)\}/g;
339
+
340
+ const matches = Array.from(inputTemplate.matchAll(placeholderPattern));
341
+ if (!matches.length) {
342
+ return inputTemplate === inputText ? [] : null;
343
+ }
344
+
345
+ const placeholderOrder = [];
346
+ let pattern = "^";
347
+ let lastIndex = 0;
348
+
349
+ for (const match of matches) {
350
+ const matchIndex = match.index ?? 0;
351
+ pattern += __escapeRegExp(inputTemplate.slice(lastIndex, matchIndex));
352
+ pattern += "([\\s\\S]*?)";
353
+ placeholderOrder.push(Number(match[1]));
354
+ lastIndex = matchIndex + match[0].length;
355
+ }
356
+
357
+ pattern += __escapeRegExp(inputTemplate.slice(lastIndex));
358
+ pattern += "$";
359
+
360
+ const result = new RegExp(pattern).exec(inputText);
361
+ if (!result) {
362
+ return null;
363
+ }
364
+
365
+ const values = [];
366
+ for (let groupIndex = 1; groupIndex < result.length; groupIndex += 1) {
367
+ const placeholderIndex = placeholderOrder[groupIndex - 1];
368
+ const extractedValue = result[groupIndex];
369
+
370
+ if (
371
+ Object.prototype.hasOwnProperty.call(values, placeholderIndex) &&
372
+ values[placeholderIndex] !== extractedValue
373
+ ) {
374
+ return null;
375
+ }
376
+
377
+ values[placeholderIndex] = extractedValue;
378
+ }
379
+
380
+ return values;
381
+ }
382
+
383
+ function __resolveTemplateValuesForText(key, text) {
384
+ if (typeof key !== "string" || !key.length) {
385
+ return [];
386
+ }
387
+
388
+ const templates = [key];
389
+ for (const [, messages] of __localizationState.messagesByLocale.entries()) {
390
+ const candidate = messages?.[key];
391
+ if (typeof candidate === "string" && candidate.length) {
392
+ templates.push(candidate);
393
+ }
394
+ }
395
+
396
+ for (const template of templates) {
397
+ const extracted = __extractValuesFromTemplate(template, text);
398
+ if (extracted) {
399
+ return extracted;
400
+ }
401
+ }
402
+
403
+ return [];
404
+ }
405
+
406
+ function __findRequestedKeyForText(coreText) {
407
+ if (!coreText) {
408
+ return null;
409
+ }
410
+
411
+ const indexedKeys = __localizationState.valueToKeys.get(coreText);
412
+ if (indexedKeys && indexedKeys.size > 0) {
413
+ for (const key of indexedKeys) {
414
+ if (__localizationState.requestedKeys.has(key)) {
415
+ return key;
416
+ }
417
+ }
418
+ }
419
+
420
+ if (__localizationState.requestedKeys.has(coreText)) {
421
+ return coreText;
422
+ }
423
+
424
+ const loadedEntries = Array.from(__localizationState.messagesByLocale.entries());
425
+ for (const key of __localizationState.requestedKeys) {
426
+ for (const [, messages] of loadedEntries) {
427
+ if (messages && messages[key] === coreText) {
428
+ return key;
429
+ }
430
+ }
431
+ }
432
+
433
+ return null;
434
+ }
435
+
436
+ function __findRequestedSubsegmentForText(coreText) {
437
+ if (!coreText) {
438
+ return null;
439
+ }
440
+
441
+ let bestMatch = null;
442
+
443
+ for (const [indexedValue, indexedKeys] of __localizationState.valueToKeys.entries()) {
444
+ if (typeof indexedValue !== "string" || !indexedValue.length) {
445
+ continue;
446
+ }
447
+
448
+ if (indexedValue === coreText) {
449
+ continue;
450
+ }
451
+
452
+ const start = coreText.indexOf(indexedValue);
453
+ if (start === -1) {
454
+ continue;
455
+ }
456
+
457
+ for (const key of indexedKeys) {
458
+ if (!__localizationState.requestedKeys.has(key)) {
459
+ continue;
460
+ }
461
+
462
+ const values = __resolveTemplateValuesForText(key, indexedValue);
463
+ const candidate = {
464
+ key,
465
+ matchedText: indexedValue,
466
+ start,
467
+ end: start + indexedValue.length,
468
+ values,
469
+ };
470
+
471
+ if (!bestMatch || candidate.matchedText.length > bestMatch.matchedText.length) {
472
+ bestMatch = candidate;
473
+ }
474
+
475
+ break;
476
+ }
477
+ }
478
+
479
+ return bestMatch;
480
+ }
481
+
482
+ async function __localizeTextNode(textNode) {
483
+ if (!textNode || textNode.nodeType !== 3) {
484
+ return;
485
+ }
486
+
487
+ const parentElement = textNode.parentElement || null;
488
+ if (!parentElement) {
489
+ return;
490
+ }
491
+
492
+ const { leading, core, trailing } = __splitTextWhitespace(textNode.nodeValue);
493
+ if (!core) {
494
+ return;
495
+ }
496
+
497
+ let key = __localizationState.textNodeKeyMap.get(textNode) || null;
498
+ if (!key || !__localizationState.requestedKeys.has(key)) {
499
+ key = __findRequestedKeyForText(core);
500
+ }
501
+
502
+ if (!key) {
503
+ const segmentMatch = __findRequestedSubsegmentForText(core);
504
+ if (!segmentMatch) {
505
+ return;
506
+ }
507
+
508
+ const scopedLocale = __resolveContextLocale({ element: parentElement });
509
+ await __loadLocaleInternal(scopedLocale, "text-node");
510
+
511
+ const translated = __resolveTranslation(
512
+ segmentMatch.key,
513
+ segmentMatch.values,
514
+ { element: parentElement },
515
+ null
516
+ );
517
+ const translatedText = segmentMatch.values.length
518
+ ? __replacePlaceholders(translated, (index) => segmentMatch.values[index])
519
+ : translated;
520
+ const localizedCore =
521
+ core.slice(0, segmentMatch.start) +
522
+ translatedText +
523
+ core.slice(segmentMatch.end);
524
+ const localizedText = `${leading}${localizedCore}${trailing}`;
525
+
526
+ if (localizedText !== textNode.nodeValue) {
527
+ textNode.nodeValue = localizedText;
528
+ }
529
+ return;
530
+ }
531
+
532
+ __localizationState.textNodeKeyMap.set(textNode, key);
533
+
534
+ const scopedLocale = __resolveContextLocale({ element: parentElement });
535
+ await __loadLocaleInternal(scopedLocale, "text-node");
536
+
537
+ const values = __resolveTemplateValuesForText(key, core);
538
+ const translated = __resolveTranslation(key, values, { element: parentElement }, null);
539
+ const translatedText = values.length
540
+ ? __replacePlaceholders(translated, (index) => values[index])
541
+ : translated;
542
+ const nextText = `${leading}${translatedText}${trailing}`;
543
+
544
+ if (nextText !== textNode.nodeValue) {
545
+ textNode.nodeValue = nextText;
546
+ }
547
+ }
548
+
549
+ async function __localizeRequestedTextNodes() {
550
+ if (typeof document === "undefined" || __localizationState.requestedKeys.size === 0) {
551
+ return;
552
+ }
553
+
554
+ const root = document.body || document.documentElement;
555
+ if (!root || typeof document.createTreeWalker !== "function") {
556
+ return;
557
+ }
558
+
559
+ const roots = [];
560
+ const seenRoots = new Set();
561
+
562
+ const addRoot = (candidateRoot) => {
563
+ if (!candidateRoot || seenRoots.has(candidateRoot)) {
564
+ return;
565
+ }
566
+
567
+ seenRoots.add(candidateRoot);
568
+ roots.push(candidateRoot);
569
+ };
570
+
571
+ addRoot(root);
572
+
573
+ for (let index = 0; index < roots.length; index += 1) {
574
+ const currentRoot = roots[index];
575
+ if (!currentRoot || typeof currentRoot.querySelectorAll !== "function") {
576
+ continue;
577
+ }
578
+
579
+ const elements = currentRoot.querySelectorAll("*");
580
+ for (const element of elements) {
581
+ const shadowRoot = element?.shadowRoot;
582
+ if (shadowRoot) {
583
+ addRoot(shadowRoot);
584
+ }
585
+ }
586
+ }
587
+
588
+ const nodes = [];
589
+
590
+ for (const scanRoot of roots) {
591
+ const walker = document.createTreeWalker(scanRoot, NodeFilter.SHOW_TEXT);
592
+ while (walker.nextNode()) {
593
+ nodes.push(walker.currentNode);
594
+ }
595
+ }
596
+
597
+ for (const node of nodes) {
598
+ await __localizeTextNode(node);
599
+ }
600
+ }
601
+
602
+ async function __reconcileLocalization() {
603
+ const detectedLocales = __collectDetectedLocales();
604
+ await __ensureDetectedLocalesLoaded(detectedLocales);
605
+ await __localizeRequestedTextNodes();
606
+ __pruneUndetectedLocales(detectedLocales);
607
+ }
608
+
609
+ function __scheduleReconcile() {
610
+ if (typeof window === "undefined") {
611
+ return;
612
+ }
613
+
614
+ if (__localizationState.reconcileTimer) {
615
+ clearTimeout(__localizationState.reconcileTimer);
616
+ }
617
+
618
+ __localizationState.reconcileTimer = setTimeout(() => {
619
+ __localizationState.reconcileTimer = null;
620
+ __reconcileLocalization();
621
+ }, 16);
622
+ }
623
+
624
+ function __attachLangObserver() {
625
+ if (typeof window === "undefined" || typeof document === "undefined") {
626
+ return;
627
+ }
628
+
629
+ if (__localizationState.observer) {
630
+ __localizationState.observer.disconnect();
631
+ __localizationState.observer = null;
632
+ }
633
+
634
+ if (typeof MutationObserver !== "function") {
635
+ return;
636
+ }
637
+
638
+ const observer = new MutationObserver(() => {
639
+ __scheduleReconcile();
640
+ });
641
+
642
+ observer.observe(document.documentElement, {
643
+ attributes: true,
644
+ attributeFilter: ["lang"],
645
+ childList: true,
646
+ characterData: true,
647
+ subtree: true,
648
+ });
649
+
650
+ __localizationState.observer = observer;
651
+ }
652
+
653
+ function __resolveTranslation(key, values = [], options = {}, template = null) {
654
+ const requestedLocale = __resolveContextLocale(options);
655
+ const resolvedMessages = __getLocaleMessages(requestedLocale);
656
+
657
+ if (!resolvedMessages) {
658
+ __loadLocaleInternal(requestedLocale, "msg");
659
+ }
660
+
661
+ const targetMessages = __getLocaleMessages(requestedLocale)?.messages || {};
662
+ const defaultMessages =
663
+ __getLocaleMessages(__localizationState.defaultLocale)?.messages || {};
664
+
665
+ const context = {
666
+ key,
667
+ values,
668
+ options,
669
+ locale: requestedLocale,
670
+ defaultLocale: __localizationState.defaultLocale,
671
+ messages: targetMessages,
672
+ messagesByLocale: Object.fromEntries(
673
+ Array.from(__localizationState.messagesByLocale.entries())
674
+ ),
675
+ template,
676
+ };
677
+
678
+ let translated;
679
+ const localeLoaded = Boolean(resolvedMessages);
680
+ const isDefaultLocale = requestedLocale === __localizationState.defaultLocale;
681
+ if (typeof __localizationState.provider?.translate === "function") {
682
+ translated = __localizationState.provider.translate(context);
683
+ }
684
+
685
+ let fallbackKind = null;
686
+
687
+ if (translated === undefined || translated === null) {
688
+ translated = targetMessages[key];
689
+ }
690
+
691
+ if (translated === undefined || translated === null) {
692
+ translated = defaultMessages[key];
693
+ fallbackKind = translated === undefined || translated === null ? null : "default";
694
+ }
695
+
696
+ if (translated === undefined || translated === null) {
697
+ translated = key;
698
+ fallbackKind = "key";
699
+ }
700
+
701
+ if (localeLoaded && !isDefaultLocale && fallbackKind) {
702
+ const warningKey = `${requestedLocale}::${key}`;
703
+ if (!__localizationState.missingWarnings.has(warningKey)) {
704
+ __localizationState.missingWarnings.add(warningKey);
705
+ pdsLog(
706
+ "warn",
707
+ `[i18n] Missing translation for locale "${requestedLocale}" and key "${key}"; using ${fallbackKind} fallback.`
708
+ );
709
+ }
710
+ }
711
+
712
+ const resolved = typeof translated === "string" ? translated : String(translated);
713
+ __indexTranslatedValue(key, resolved);
714
+
715
+ if (Array.isArray(values) && values.length > 0) {
716
+ const materialized = __replacePlaceholders(resolved, (index) => values[index]);
717
+ if (materialized !== resolved) {
718
+ __indexTranslatedValue(key, materialized);
719
+ }
720
+ }
721
+
722
+ return resolved;
723
+ }
724
+
725
+ export function getLocalizationState() {
726
+ const defaultBundle = __getLocaleMessages(__localizationState.defaultLocale);
727
+ return {
728
+ locale: __localizationState.defaultLocale,
729
+ messages: { ...(defaultBundle?.messages || {}) },
730
+ loadedLocales: Array.from(__localizationState.messagesByLocale.keys()),
731
+ hasProvider: Boolean(__localizationState.provider),
732
+ };
733
+ }
734
+
735
+ export function configureLocalization(config = null) {
736
+ if (__localizationState.observer) {
737
+ __localizationState.observer.disconnect();
738
+ __localizationState.observer = null;
739
+ }
740
+ if (__localizationState.reconcileTimer) {
741
+ clearTimeout(__localizationState.reconcileTimer);
742
+ __localizationState.reconcileTimer = null;
743
+ }
744
+
745
+ __localizationState.defaultLocale = __DEFAULT_LOCALE__;
746
+ __localizationState.provider = null;
747
+ __localizationState.messagesByLocale.clear();
748
+ __localizationState.loadingByLocale.clear();
749
+ __localizationState.requestedKeys.clear();
750
+ __localizationState.textNodeKeyMap = new WeakMap();
751
+ __localizationState.valueToKeys.clear();
752
+ __localizationState.missingWarnings.clear();
753
+
754
+ if (!config || typeof config !== "object") {
755
+ return getLocalizationState();
756
+ }
757
+
758
+ if (typeof config.locale === "string" && config.locale.trim()) {
759
+ __localizationState.defaultLocale = __resolveLocaleCandidate(config.locale);
760
+ }
761
+
762
+ if (Object.prototype.hasOwnProperty.call(config, "messages")) {
763
+ __setLocaleMessages(__localizationState.defaultLocale, config.messages);
764
+ }
765
+
766
+ if (
767
+ Object.prototype.hasOwnProperty.call(config, "provider") ||
768
+ Object.prototype.hasOwnProperty.call(config, "translate") ||
769
+ Object.prototype.hasOwnProperty.call(config, "loadLocale") ||
770
+ Object.prototype.hasOwnProperty.call(config, "setLocale")
771
+ ) {
772
+ __localizationState.provider = __resolveProvider(config);
773
+ }
774
+
775
+ __attachLangObserver();
776
+ __scheduleReconcile();
777
+
778
+ return getLocalizationState();
779
+ }
780
+
781
+ export async function loadLocale(locale) {
782
+ const targetLocale = __resolveLocaleCandidate(locale);
783
+ await __loadLocaleInternal(targetLocale, "explicit-load");
784
+ const bundle = __getLocaleMessages(targetLocale)?.messages || {};
785
+ return { ...bundle };
786
+ }
787
+
788
+ export async function setLocale(locale, { load = true } = {}) {
789
+ __localizationState.defaultLocale = __resolveLocaleCandidate(locale);
790
+ if (load) {
791
+ await __loadLocaleInternal(__localizationState.defaultLocale, "set-default");
792
+ }
793
+ __scheduleReconcile();
794
+ return __localizationState.defaultLocale;
795
+ }
796
+
797
+ export const joinStringsAndValues = (strings, values, options = {}) => {
798
+ const messageKey = __collateStrings(strings);
799
+ __registerRequestedKey(messageKey);
800
+ const translated = __resolveTranslation(messageKey, values, options, {
801
+ strings,
802
+ values,
803
+ });
804
+
805
+ return __replacePlaceholders(translated, (index) => values[index]);
806
+ };
807
+
808
+ export const str = (strings, ...values) => ({
809
+ strTag: true,
810
+ strings: Array.from(strings),
811
+ values,
812
+ raw: Array.from(strings?.raw || []),
813
+ });
814
+
815
+ export const msg = (template, options = {}) => {
816
+ if (!template) {
817
+ return "";
818
+ }
819
+
820
+ if (__isStrTagged(template)) {
821
+ return joinStringsAndValues(template.strings, template.values, options);
822
+ }
823
+
824
+ const key = String(template);
825
+ __registerRequestedKey(key);
826
+ const translated = __resolveTranslation(key, [], options, null);
827
+
828
+ if (
829
+ !options?.element &&
830
+ !options?.scope &&
831
+ !options?.host &&
832
+ !options?.contextElement &&
833
+ !options?.lang
834
+ ) {
835
+ __scheduleReconcile();
836
+ }
837
+
838
+ return translated;
839
+ };