@gears-frontx/i18n 0.1.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.cjs ADDED
@@ -0,0 +1,901 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ HTML_DIR_ATTRIBUTE: () => HTML_DIR_ATTRIBUTE,
24
+ HTML_LANG_ATTRIBUTE: () => HTML_LANG_ATTRIBUTE,
25
+ I18N_DEFAULT_NAMESPACE: () => I18N_DEFAULT_NAMESPACE,
26
+ I18N_NAMESPACE_SEPARATOR: () => I18N_NAMESPACE_SEPARATOR,
27
+ I18N_PATH_SEPARATOR: () => I18N_PATH_SEPARATOR,
28
+ I18nRegistryImpl: () => I18nRegistryImpl,
29
+ Language: () => Language,
30
+ LanguageDisplayMode: () => LanguageDisplayMode,
31
+ SUPPORTED_LANGUAGES: () => SUPPORTED_LANGUAGES,
32
+ TextDirection: () => TextDirection,
33
+ compareStrings: () => compareStrings,
34
+ createCollator: () => createCollator,
35
+ createI18nRegistry: () => createI18nRegistry,
36
+ formatCompact: () => formatCompact,
37
+ formatCurrency: () => formatCurrency,
38
+ formatDate: () => formatDate,
39
+ formatDateTime: () => formatDateTime,
40
+ formatNumber: () => formatNumber,
41
+ formatPercent: () => formatPercent,
42
+ formatRelative: () => formatRelative,
43
+ formatTime: () => formatTime,
44
+ getLanguageMetadata: () => getLanguageMetadata,
45
+ getRTLLanguages: () => getRTLLanguages,
46
+ i18nRegistry: () => i18nRegistry,
47
+ isValidLanguage: () => isValidLanguage
48
+ });
49
+ module.exports = __toCommonJS(src_exports);
50
+
51
+ // src/types.ts
52
+ var TextDirection = /* @__PURE__ */ ((TextDirection2) => {
53
+ TextDirection2["LeftToRight"] = "ltr";
54
+ TextDirection2["RightToLeft"] = "rtl";
55
+ return TextDirection2;
56
+ })(TextDirection || {});
57
+ var Language = /* @__PURE__ */ ((Language2) => {
58
+ Language2["English"] = "en";
59
+ Language2["Spanish"] = "es";
60
+ Language2["French"] = "fr";
61
+ Language2["German"] = "de";
62
+ Language2["Italian"] = "it";
63
+ Language2["Portuguese"] = "pt";
64
+ Language2["Dutch"] = "nl";
65
+ Language2["Russian"] = "ru";
66
+ Language2["Polish"] = "pl";
67
+ Language2["Ukrainian"] = "uk";
68
+ Language2["Czech"] = "cs";
69
+ Language2["Arabic"] = "ar";
70
+ Language2["Hebrew"] = "he";
71
+ Language2["Persian"] = "fa";
72
+ Language2["Urdu"] = "ur";
73
+ Language2["Turkish"] = "tr";
74
+ Language2["ChineseSimplified"] = "zh";
75
+ Language2["ChineseTraditional"] = "zh-TW";
76
+ Language2["Japanese"] = "ja";
77
+ Language2["Korean"] = "ko";
78
+ Language2["Vietnamese"] = "vi";
79
+ Language2["Thai"] = "th";
80
+ Language2["Indonesian"] = "id";
81
+ Language2["Hindi"] = "hi";
82
+ Language2["Bengali"] = "bn";
83
+ Language2["Swedish"] = "sv";
84
+ Language2["Danish"] = "da";
85
+ Language2["Norwegian"] = "no";
86
+ Language2["Finnish"] = "fi";
87
+ Language2["Greek"] = "el";
88
+ Language2["Romanian"] = "ro";
89
+ Language2["Hungarian"] = "hu";
90
+ Language2["Malay"] = "ms";
91
+ Language2["Tagalog"] = "tl";
92
+ Language2["Tamil"] = "ta";
93
+ Language2["Swahili"] = "sw";
94
+ return Language2;
95
+ })(Language || {});
96
+ var LanguageDisplayMode = /* @__PURE__ */ ((LanguageDisplayMode2) => {
97
+ LanguageDisplayMode2["Native"] = "native";
98
+ LanguageDisplayMode2["English"] = "english";
99
+ return LanguageDisplayMode2;
100
+ })(LanguageDisplayMode || {});
101
+ var I18N_NAMESPACE_SEPARATOR = ":";
102
+ var I18N_PATH_SEPARATOR = ".";
103
+ var I18N_DEFAULT_NAMESPACE = "app";
104
+ var HTML_LANG_ATTRIBUTE = "lang";
105
+ var HTML_DIR_ATTRIBUTE = "dir";
106
+
107
+ // src/languages.ts
108
+ var SUPPORTED_LANGUAGES = [
109
+ // Western European
110
+ {
111
+ code: "en" /* English */,
112
+ name: "English",
113
+ englishName: "English",
114
+ direction: "ltr" /* LeftToRight */
115
+ },
116
+ {
117
+ code: "es" /* Spanish */,
118
+ name: "Espa\xF1ol",
119
+ englishName: "Spanish",
120
+ direction: "ltr" /* LeftToRight */
121
+ },
122
+ {
123
+ code: "fr" /* French */,
124
+ name: "Fran\xE7ais",
125
+ englishName: "French",
126
+ direction: "ltr" /* LeftToRight */
127
+ },
128
+ {
129
+ code: "de" /* German */,
130
+ name: "Deutsch",
131
+ englishName: "German",
132
+ direction: "ltr" /* LeftToRight */
133
+ },
134
+ {
135
+ code: "it" /* Italian */,
136
+ name: "Italiano",
137
+ englishName: "Italian",
138
+ direction: "ltr" /* LeftToRight */
139
+ },
140
+ {
141
+ code: "pt" /* Portuguese */,
142
+ name: "Portugu\xEAs",
143
+ englishName: "Portuguese",
144
+ direction: "ltr" /* LeftToRight */
145
+ },
146
+ {
147
+ code: "nl" /* Dutch */,
148
+ name: "Nederlands",
149
+ englishName: "Dutch",
150
+ direction: "ltr" /* LeftToRight */
151
+ },
152
+ // Eastern European
153
+ {
154
+ code: "ru" /* Russian */,
155
+ name: "\u0420\u0443\u0441\u0441\u043A\u0438\u0439",
156
+ englishName: "Russian",
157
+ direction: "ltr" /* LeftToRight */
158
+ },
159
+ {
160
+ code: "pl" /* Polish */,
161
+ name: "Polski",
162
+ englishName: "Polish",
163
+ direction: "ltr" /* LeftToRight */
164
+ },
165
+ {
166
+ code: "uk" /* Ukrainian */,
167
+ name: "\u0423\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u0430",
168
+ englishName: "Ukrainian",
169
+ direction: "ltr" /* LeftToRight */
170
+ },
171
+ {
172
+ code: "cs" /* Czech */,
173
+ name: "\u010Ce\u0161tina",
174
+ englishName: "Czech",
175
+ direction: "ltr" /* LeftToRight */
176
+ },
177
+ // Middle East & North Africa (RTL)
178
+ {
179
+ code: "ar" /* Arabic */,
180
+ name: "\u0627\u0644\u0639\u0631\u0628\u064A\u0629",
181
+ englishName: "Arabic",
182
+ direction: "rtl" /* RightToLeft */
183
+ },
184
+ {
185
+ code: "he" /* Hebrew */,
186
+ name: "\u05E2\u05D1\u05E8\u05D9\u05EA",
187
+ englishName: "Hebrew",
188
+ direction: "rtl" /* RightToLeft */
189
+ },
190
+ {
191
+ code: "fa" /* Persian */,
192
+ name: "\u0641\u0627\u0631\u0633\u06CC",
193
+ englishName: "Persian",
194
+ direction: "rtl" /* RightToLeft */
195
+ },
196
+ {
197
+ code: "ur" /* Urdu */,
198
+ name: "\u0627\u0631\u062F\u0648",
199
+ englishName: "Urdu",
200
+ direction: "rtl" /* RightToLeft */
201
+ },
202
+ {
203
+ code: "tr" /* Turkish */,
204
+ name: "T\xFCrk\xE7e",
205
+ englishName: "Turkish",
206
+ direction: "ltr" /* LeftToRight */
207
+ },
208
+ // Asian
209
+ {
210
+ code: "zh" /* ChineseSimplified */,
211
+ name: "\u7B80\u4F53\u4E2D\u6587",
212
+ englishName: "Chinese (Simplified)",
213
+ direction: "ltr" /* LeftToRight */
214
+ },
215
+ {
216
+ code: "zh-TW" /* ChineseTraditional */,
217
+ name: "\u7E41\u9AD4\u4E2D\u6587",
218
+ englishName: "Chinese (Traditional)",
219
+ direction: "ltr" /* LeftToRight */,
220
+ region: "TW"
221
+ },
222
+ {
223
+ code: "ja" /* Japanese */,
224
+ name: "\u65E5\u672C\u8A9E",
225
+ englishName: "Japanese",
226
+ direction: "ltr" /* LeftToRight */
227
+ },
228
+ {
229
+ code: "ko" /* Korean */,
230
+ name: "\uD55C\uAD6D\uC5B4",
231
+ englishName: "Korean",
232
+ direction: "ltr" /* LeftToRight */
233
+ },
234
+ {
235
+ code: "vi" /* Vietnamese */,
236
+ name: "Ti\u1EBFng Vi\u1EC7t",
237
+ englishName: "Vietnamese",
238
+ direction: "ltr" /* LeftToRight */
239
+ },
240
+ {
241
+ code: "th" /* Thai */,
242
+ name: "\u0E44\u0E17\u0E22",
243
+ englishName: "Thai",
244
+ direction: "ltr" /* LeftToRight */
245
+ },
246
+ {
247
+ code: "id" /* Indonesian */,
248
+ name: "Bahasa Indonesia",
249
+ englishName: "Indonesian",
250
+ direction: "ltr" /* LeftToRight */
251
+ },
252
+ {
253
+ code: "hi" /* Hindi */,
254
+ name: "\u0939\u093F\u0928\u094D\u0926\u0940",
255
+ englishName: "Hindi",
256
+ direction: "ltr" /* LeftToRight */
257
+ },
258
+ {
259
+ code: "bn" /* Bengali */,
260
+ name: "\u09AC\u09BE\u0982\u09B2\u09BE",
261
+ englishName: "Bengali",
262
+ direction: "ltr" /* LeftToRight */
263
+ },
264
+ // Nordic
265
+ {
266
+ code: "sv" /* Swedish */,
267
+ name: "Svenska",
268
+ englishName: "Swedish",
269
+ direction: "ltr" /* LeftToRight */
270
+ },
271
+ {
272
+ code: "da" /* Danish */,
273
+ name: "Dansk",
274
+ englishName: "Danish",
275
+ direction: "ltr" /* LeftToRight */
276
+ },
277
+ {
278
+ code: "no" /* Norwegian */,
279
+ name: "Norsk",
280
+ englishName: "Norwegian",
281
+ direction: "ltr" /* LeftToRight */
282
+ },
283
+ {
284
+ code: "fi" /* Finnish */,
285
+ name: "Suomi",
286
+ englishName: "Finnish",
287
+ direction: "ltr" /* LeftToRight */
288
+ },
289
+ // Other
290
+ {
291
+ code: "el" /* Greek */,
292
+ name: "\u0395\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC",
293
+ englishName: "Greek",
294
+ direction: "ltr" /* LeftToRight */
295
+ },
296
+ {
297
+ code: "ro" /* Romanian */,
298
+ name: "Rom\xE2n\u0103",
299
+ englishName: "Romanian",
300
+ direction: "ltr" /* LeftToRight */
301
+ },
302
+ {
303
+ code: "hu" /* Hungarian */,
304
+ name: "Magyar",
305
+ englishName: "Hungarian",
306
+ direction: "ltr" /* LeftToRight */
307
+ },
308
+ // Additional major languages
309
+ {
310
+ code: "ms" /* Malay */,
311
+ name: "Bahasa Melayu",
312
+ englishName: "Malay",
313
+ direction: "ltr" /* LeftToRight */
314
+ },
315
+ {
316
+ code: "tl" /* Tagalog */,
317
+ name: "Tagalog",
318
+ englishName: "Tagalog",
319
+ direction: "ltr" /* LeftToRight */
320
+ },
321
+ {
322
+ code: "ta" /* Tamil */,
323
+ name: "\u0BA4\u0BAE\u0BBF\u0BB4\u0BCD",
324
+ englishName: "Tamil",
325
+ direction: "ltr" /* LeftToRight */
326
+ },
327
+ {
328
+ code: "sw" /* Swahili */,
329
+ name: "Kiswahili",
330
+ englishName: "Swahili",
331
+ direction: "ltr" /* LeftToRight */
332
+ }
333
+ ];
334
+ function getLanguageMetadata(code) {
335
+ return SUPPORTED_LANGUAGES.find((lang) => lang.code === code);
336
+ }
337
+ function getRTLLanguages() {
338
+ return SUPPORTED_LANGUAGES.filter((lang) => lang.direction === "rtl" /* RightToLeft */).map((lang) => lang.code);
339
+ }
340
+ function isValidLanguage(code) {
341
+ return SUPPORTED_LANGUAGES.some((lang) => lang.code === code);
342
+ }
343
+
344
+ // src/I18nRegistry.ts
345
+ var I18nRegistryImpl = class _I18nRegistryImpl {
346
+ /** Configuration */
347
+ config;
348
+ /** Current language */
349
+ currentLanguage = null;
350
+ /** Translation dictionaries: namespace -> language -> dictionary */
351
+ dictionaries = /* @__PURE__ */ new Map();
352
+ /** Translation loaders: namespace -> loader function */
353
+ loaders = /* @__PURE__ */ new Map();
354
+ /** Subscribers for translation changes */
355
+ subscribers = /* @__PURE__ */ new Set();
356
+ /** Version counter for React re-rendering */
357
+ version = 0;
358
+ // @cpt-begin:cpt-hai3-algo-i18n-infrastructure-language-file-map:p1:inst-1
359
+ /** Language file mapping */
360
+ static LANGUAGE_FILE_MAP = {
361
+ ["en" /* English */]: "en.json",
362
+ ["es" /* Spanish */]: "es.json",
363
+ ["fr" /* French */]: "fr.json",
364
+ ["de" /* German */]: "de.json",
365
+ ["it" /* Italian */]: "it.json",
366
+ ["pt" /* Portuguese */]: "pt.json",
367
+ ["nl" /* Dutch */]: "nl.json",
368
+ ["ru" /* Russian */]: "ru.json",
369
+ ["pl" /* Polish */]: "pl.json",
370
+ ["uk" /* Ukrainian */]: "uk.json",
371
+ ["cs" /* Czech */]: "cs.json",
372
+ ["ar" /* Arabic */]: "ar.json",
373
+ ["he" /* Hebrew */]: "he.json",
374
+ ["fa" /* Persian */]: "fa.json",
375
+ ["ur" /* Urdu */]: "ur.json",
376
+ ["tr" /* Turkish */]: "tr.json",
377
+ ["zh" /* ChineseSimplified */]: "zh.json",
378
+ ["zh-TW" /* ChineseTraditional */]: "zh-TW.json",
379
+ ["ja" /* Japanese */]: "ja.json",
380
+ ["ko" /* Korean */]: "ko.json",
381
+ ["vi" /* Vietnamese */]: "vi.json",
382
+ ["th" /* Thai */]: "th.json",
383
+ ["id" /* Indonesian */]: "id.json",
384
+ ["hi" /* Hindi */]: "hi.json",
385
+ ["bn" /* Bengali */]: "bn.json",
386
+ ["sv" /* Swedish */]: "sv.json",
387
+ ["da" /* Danish */]: "da.json",
388
+ ["no" /* Norwegian */]: "no.json",
389
+ ["fi" /* Finnish */]: "fi.json",
390
+ ["el" /* Greek */]: "el.json",
391
+ ["ro" /* Romanian */]: "ro.json",
392
+ ["hu" /* Hungarian */]: "hu.json",
393
+ ["ms" /* Malay */]: "ms.json",
394
+ ["tl" /* Tagalog */]: "tl.json",
395
+ ["ta" /* Tamil */]: "ta.json",
396
+ ["sw" /* Swahili */]: "sw.json"
397
+ };
398
+ // @cpt-end:cpt-hai3-algo-i18n-infrastructure-language-file-map:p1:inst-1
399
+ constructor(config) {
400
+ this.config = config;
401
+ }
402
+ // ============================================================================
403
+ // Registration
404
+ // ============================================================================
405
+ // @cpt-begin:cpt-hai3-state-i18n-infrastructure-namespace-cache:p1:inst-1
406
+ /**
407
+ * Register translations for a namespace.
408
+ */
409
+ register(namespace, language, translations) {
410
+ if (!this.dictionaries.has(namespace)) {
411
+ this.dictionaries.set(namespace, /* @__PURE__ */ new Map());
412
+ }
413
+ this.dictionaries.get(namespace).set(language, translations);
414
+ this.notifySubscribers();
415
+ }
416
+ // @cpt-end:cpt-hai3-state-i18n-infrastructure-namespace-cache:p1:inst-1
417
+ /**
418
+ * Subscribe to translation changes.
419
+ * Returns an unsubscribe function.
420
+ */
421
+ subscribe(callback) {
422
+ this.subscribers.add(callback);
423
+ return () => {
424
+ this.subscribers.delete(callback);
425
+ };
426
+ }
427
+ /**
428
+ * Notify all subscribers of a change.
429
+ */
430
+ notifySubscribers() {
431
+ this.version++;
432
+ this.subscribers.forEach((callback) => callback());
433
+ }
434
+ /**
435
+ * Get the current version number.
436
+ * Used by React to detect changes.
437
+ */
438
+ getVersion() {
439
+ return this.version;
440
+ }
441
+ // @cpt-begin:cpt-hai3-flow-i18n-infrastructure-screenset-registration:p1:inst-1
442
+ // @cpt-begin:cpt-hai3-flow-i18n-infrastructure-screen-lazy-load:p1:inst-1
443
+ /**
444
+ * Register a translation loader for a namespace.
445
+ */
446
+ registerLoader(namespace, loader) {
447
+ this.loaders.set(namespace, loader);
448
+ }
449
+ // @cpt-end:cpt-hai3-flow-i18n-infrastructure-screenset-registration:p1:inst-1
450
+ // @cpt-end:cpt-hai3-flow-i18n-infrastructure-screen-lazy-load:p1:inst-1
451
+ /**
452
+ * Check if namespace is registered.
453
+ */
454
+ hasNamespace(namespace) {
455
+ return this.dictionaries.has(namespace) || this.loaders.has(namespace);
456
+ }
457
+ /**
458
+ * Get all registered namespaces.
459
+ */
460
+ getNamespaces() {
461
+ const namespaces = /* @__PURE__ */ new Set();
462
+ this.dictionaries.forEach((_, key) => namespaces.add(key));
463
+ this.loaders.forEach((_, key) => namespaces.add(key));
464
+ return Array.from(namespaces);
465
+ }
466
+ // ============================================================================
467
+ // Translation
468
+ // ============================================================================
469
+ // @cpt-begin:cpt-hai3-flow-i18n-infrastructure-key-resolution:p1:inst-1
470
+ /**
471
+ * Translate a key.
472
+ * Format: 'namespace:key.subkey' or just 'key' for default namespace
473
+ */
474
+ t(key, params) {
475
+ const { namespace, path } = this.parseKey(key);
476
+ const translation = this.getTranslation(namespace, path);
477
+ if (translation === void 0) {
478
+ return key;
479
+ }
480
+ return this.interpolate(translation, params);
481
+ }
482
+ // @cpt-end:cpt-hai3-flow-i18n-infrastructure-key-resolution:p1:inst-1
483
+ // @cpt-begin:cpt-hai3-flow-i18n-infrastructure-key-resolution:p1:inst-2
484
+ /**
485
+ * Parse a translation key into namespace and path.
486
+ */
487
+ parseKey(key) {
488
+ const separatorIndex = key.indexOf(I18N_NAMESPACE_SEPARATOR);
489
+ if (separatorIndex === -1) {
490
+ return {
491
+ namespace: I18N_DEFAULT_NAMESPACE,
492
+ path: key
493
+ };
494
+ }
495
+ return {
496
+ namespace: key.slice(0, separatorIndex),
497
+ path: key.slice(separatorIndex + 1)
498
+ };
499
+ }
500
+ // @cpt-end:cpt-hai3-flow-i18n-infrastructure-key-resolution:p1:inst-2
501
+ // @cpt-begin:cpt-hai3-flow-i18n-infrastructure-key-resolution:p1:inst-3
502
+ /**
503
+ * Get a translation from the dictionary.
504
+ */
505
+ getTranslation(namespace, path) {
506
+ const language = this.currentLanguage ?? this.config.defaultLanguage;
507
+ const fallback = this.config.fallbackLanguage;
508
+ let translation = this.findTranslation(namespace, language, path);
509
+ if (translation !== void 0) {
510
+ return translation;
511
+ }
512
+ if (language !== fallback) {
513
+ translation = this.findTranslation(namespace, fallback, path);
514
+ if (translation !== void 0) {
515
+ return translation;
516
+ }
517
+ }
518
+ return void 0;
519
+ }
520
+ // @cpt-end:cpt-hai3-flow-i18n-infrastructure-key-resolution:p1:inst-3
521
+ // @cpt-begin:cpt-hai3-flow-i18n-infrastructure-key-resolution:p1:inst-4
522
+ // @cpt-begin:cpt-hai3-algo-i18n-infrastructure-path-traversal:p1:inst-1
523
+ /**
524
+ * Find a translation in the dictionary.
525
+ */
526
+ findTranslation(namespace, language, path) {
527
+ const namespaceDicts = this.dictionaries.get(namespace);
528
+ if (!namespaceDicts) {
529
+ return void 0;
530
+ }
531
+ const dict = namespaceDicts.get(language);
532
+ if (!dict) {
533
+ return void 0;
534
+ }
535
+ const parts = path.split(I18N_PATH_SEPARATOR);
536
+ let current = dict;
537
+ for (const part of parts) {
538
+ if (typeof current !== "object" || current === null) {
539
+ return void 0;
540
+ }
541
+ current = current[part];
542
+ if (current === void 0) {
543
+ return void 0;
544
+ }
545
+ }
546
+ return typeof current === "string" ? current : void 0;
547
+ }
548
+ // @cpt-end:cpt-hai3-flow-i18n-infrastructure-key-resolution:p1:inst-4
549
+ // @cpt-end:cpt-hai3-algo-i18n-infrastructure-path-traversal:p1:inst-1
550
+ // @cpt-begin:cpt-hai3-flow-i18n-infrastructure-key-resolution:p1:inst-5
551
+ /**
552
+ * Interpolate parameters into a translation string.
553
+ */
554
+ interpolate(text, params) {
555
+ if (!params) {
556
+ return text;
557
+ }
558
+ return text.replace(/\{(\w+)\}/g, (match, key) => {
559
+ const value = params[key];
560
+ return value !== void 0 ? String(value) : match;
561
+ });
562
+ }
563
+ // @cpt-end:cpt-hai3-flow-i18n-infrastructure-key-resolution:p1:inst-5
564
+ // ============================================================================
565
+ // Language Management
566
+ // ============================================================================
567
+ // @cpt-begin:cpt-hai3-flow-i18n-infrastructure-language-activation:p1:inst-1
568
+ // @cpt-begin:cpt-hai3-state-i18n-infrastructure-registry:p1:inst-1
569
+ /**
570
+ * Set current language and load translations.
571
+ */
572
+ async setLanguage(language) {
573
+ this.currentLanguage = language;
574
+ this.updateHtmlAttributes(language);
575
+ await this.loadLanguage(language);
576
+ }
577
+ // @cpt-end:cpt-hai3-flow-i18n-infrastructure-language-activation:p1:inst-1
578
+ // @cpt-end:cpt-hai3-state-i18n-infrastructure-registry:p1:inst-1
579
+ /**
580
+ * Get current language.
581
+ */
582
+ getLanguage() {
583
+ return this.currentLanguage;
584
+ }
585
+ // @cpt-begin:cpt-hai3-algo-i18n-infrastructure-html-attrs:p1:inst-1
586
+ /**
587
+ * Update HTML lang and dir attributes.
588
+ */
589
+ updateHtmlAttributes(language) {
590
+ if (typeof document === "undefined") {
591
+ return;
592
+ }
593
+ const htmlElement = document.documentElement;
594
+ htmlElement.setAttribute(HTML_LANG_ATTRIBUTE, language);
595
+ htmlElement.setAttribute(
596
+ HTML_DIR_ATTRIBUTE,
597
+ this.isRTL(language) ? "rtl" /* RightToLeft */ : "ltr" /* LeftToRight */
598
+ );
599
+ }
600
+ // @cpt-end:cpt-hai3-algo-i18n-infrastructure-html-attrs:p1:inst-1
601
+ // ============================================================================
602
+ // Language Metadata
603
+ // ============================================================================
604
+ /**
605
+ * Get language metadata.
606
+ */
607
+ getLanguageMetadata(code) {
608
+ const targetCode = code ?? this.currentLanguage;
609
+ if (!targetCode) {
610
+ return void 0;
611
+ }
612
+ return SUPPORTED_LANGUAGES.find((lang) => lang.code === targetCode);
613
+ }
614
+ /**
615
+ * Get all supported languages.
616
+ */
617
+ getSupportedLanguages() {
618
+ return [...SUPPORTED_LANGUAGES];
619
+ }
620
+ /**
621
+ * Check if a language is RTL.
622
+ */
623
+ isRTL(code) {
624
+ const targetCode = code ?? this.currentLanguage;
625
+ if (!targetCode) {
626
+ return false;
627
+ }
628
+ const metadata = this.getLanguageMetadata(targetCode);
629
+ return metadata?.direction === "rtl" /* RightToLeft */;
630
+ }
631
+ // ============================================================================
632
+ // Translation Loading
633
+ // ============================================================================
634
+ // @cpt-begin:cpt-hai3-algo-i18n-infrastructure-lazy-exclusion:p1:inst-1
635
+ // @cpt-begin:cpt-hai3-flow-i18n-infrastructure-language-activation:p1:inst-2
636
+ /**
637
+ * Load translations for a language.
638
+ * Excludes screen.* and screenset.* namespaces which are lazy-loaded:
639
+ * - screen.* namespaces: loaded when screen mounts
640
+ * - screenset.* namespaces: loaded when screenset is activated
641
+ */
642
+ async loadLanguage(language) {
643
+ const loadPromises = [];
644
+ this.loaders.forEach((_loader, namespace) => {
645
+ if (namespace.startsWith("screen.") || namespace.startsWith("screenset.")) {
646
+ return;
647
+ }
648
+ loadPromises.push(this.loadNamespace(namespace, language));
649
+ });
650
+ await Promise.all(loadPromises);
651
+ }
652
+ // @cpt-end:cpt-hai3-algo-i18n-infrastructure-lazy-exclusion:p1:inst-1
653
+ // @cpt-end:cpt-hai3-flow-i18n-infrastructure-language-activation:p1:inst-2
654
+ // @cpt-begin:cpt-hai3-flow-i18n-infrastructure-screen-lazy-load:p1:inst-2
655
+ /**
656
+ * Load translations for a specific namespace.
657
+ */
658
+ async loadNamespace(namespace, language) {
659
+ const loader = this.loaders.get(namespace);
660
+ if (!loader) {
661
+ return;
662
+ }
663
+ try {
664
+ const translations = await loader(language);
665
+ this.register(namespace, language, translations);
666
+ } catch (error) {
667
+ console.warn(`Failed to load translations for ${namespace}/${language}:`, error);
668
+ }
669
+ }
670
+ // @cpt-end:cpt-hai3-flow-i18n-infrastructure-screen-lazy-load:p1:inst-2
671
+ // @cpt-begin:cpt-hai3-flow-i18n-infrastructure-screenset-registration:p1:inst-2
672
+ /**
673
+ * Load translations for a specific screenset.
674
+ */
675
+ async loadScreensetTranslations(screensetId, language) {
676
+ const targetLanguage = language ?? this.currentLanguage ?? this.config.defaultLanguage;
677
+ const namespace = `screenset.${screensetId}`;
678
+ await this.loadNamespace(namespace, targetLanguage);
679
+ }
680
+ // @cpt-end:cpt-hai3-flow-i18n-infrastructure-screenset-registration:p1:inst-2
681
+ /**
682
+ * Preload translations for multiple languages.
683
+ */
684
+ async preloadLanguages(languages) {
685
+ const loadPromises = languages.map((language) => this.loadLanguage(language));
686
+ await Promise.all(loadPromises);
687
+ }
688
+ // ============================================================================
689
+ // Static Helpers
690
+ // ============================================================================
691
+ /**
692
+ * Create a translation loader from a translation map.
693
+ *
694
+ * @example
695
+ * ```typescript
696
+ * const loader = I18nRegistry.createLoader({
697
+ * [Language.English]: () => import('./i18n/en.json'),
698
+ * [Language.Spanish]: () => import('./i18n/es.json'),
699
+ * });
700
+ * ```
701
+ */
702
+ // @cpt-begin:cpt-hai3-algo-i18n-infrastructure-create-loader:p1:inst-1
703
+ // @cpt-begin:cpt-hai3-dod-i18n-infrastructure-lazy-chunks:p1:inst-1
704
+ static createLoader(translationMap) {
705
+ return async (language) => {
706
+ const importFn = translationMap[language];
707
+ if (!importFn) {
708
+ throw new Error(`No translation found for language: ${language}`);
709
+ }
710
+ const module2 = await importFn();
711
+ return module2.default;
712
+ };
713
+ }
714
+ // @cpt-end:cpt-hai3-algo-i18n-infrastructure-create-loader:p1:inst-1
715
+ // @cpt-end:cpt-hai3-dod-i18n-infrastructure-lazy-chunks:p1:inst-1
716
+ /**
717
+ * Create a translation loader from a directory.
718
+ * Maps Language enum values to file names automatically.
719
+ *
720
+ * @param basePath - Base path for translation files
721
+ * @param importFn - Dynamic import function
722
+ */
723
+ static createLoaderFromDirectory(importFn) {
724
+ return async (language) => {
725
+ const filename = _I18nRegistryImpl.LANGUAGE_FILE_MAP[language];
726
+ const module2 = await importFn(filename);
727
+ return module2.default;
728
+ };
729
+ }
730
+ };
731
+ var i18nRegistry = new I18nRegistryImpl({
732
+ defaultLanguage: "en" /* English */,
733
+ fallbackLanguage: "en" /* English */
734
+ });
735
+ function createI18nRegistry(config) {
736
+ return new I18nRegistryImpl(config);
737
+ }
738
+
739
+ // src/formatters/utils.ts
740
+ function getLocale() {
741
+ return i18nRegistry.getLanguage() ?? "en" /* English */;
742
+ }
743
+ function toNumber(value) {
744
+ if (value === null || value === void 0) return null;
745
+ const n = Number(value);
746
+ return Number.isNaN(n) ? null : n;
747
+ }
748
+
749
+ // src/formatters/dateFormatter.ts
750
+ function toDate(value) {
751
+ if (value === null || value === void 0) return null;
752
+ const d = new Date(value);
753
+ return Number.isNaN(d.getTime()) ? null : d;
754
+ }
755
+ function formatDate(date, format) {
756
+ const d = toDate(date);
757
+ if (!d) return "";
758
+ const locale = getLocale();
759
+ return new Intl.DateTimeFormat(locale, { dateStyle: format }).format(d);
760
+ }
761
+ function formatTime(date, format) {
762
+ const d = toDate(date);
763
+ if (!d) return "";
764
+ const locale = getLocale();
765
+ return new Intl.DateTimeFormat(locale, { timeStyle: format }).format(d);
766
+ }
767
+ function formatDateTime(date, dateFormat, timeFormat) {
768
+ const d = toDate(date);
769
+ if (!d) return "";
770
+ const locale = getLocale();
771
+ return new Intl.DateTimeFormat(locale, {
772
+ dateStyle: dateFormat,
773
+ timeStyle: timeFormat
774
+ }).format(d);
775
+ }
776
+ var MS_PER_SECOND = 1e3;
777
+ var MS_PER_MINUTE = 60 * MS_PER_SECOND;
778
+ var MS_PER_HOUR = 60 * MS_PER_MINUTE;
779
+ var MS_PER_DAY = 24 * MS_PER_HOUR;
780
+ function getRelativeUnit(date, base) {
781
+ const diffMs = date.getTime() - base.getTime();
782
+ const absMs = Math.abs(diffMs);
783
+ const sign = diffMs < 0 ? -1 : 1;
784
+ if (absMs < 60 * MS_PER_SECOND) {
785
+ const value = Math.round(diffMs / MS_PER_SECOND);
786
+ return { value: value === 0 ? 0 : value, unit: "second" };
787
+ }
788
+ if (absMs < 60 * MS_PER_MINUTE) {
789
+ return { value: sign * Math.round(absMs / MS_PER_MINUTE), unit: "minute" };
790
+ }
791
+ if (absMs < MS_PER_DAY) {
792
+ return { value: sign * Math.round(absMs / MS_PER_HOUR), unit: "hour" };
793
+ }
794
+ const baseY = base.getUTCFullYear();
795
+ const baseM = base.getUTCMonth();
796
+ const baseD = base.getUTCDate();
797
+ const dateY = date.getUTCFullYear();
798
+ const dateM = date.getUTCMonth();
799
+ const dateD = date.getUTCDate();
800
+ const totalMonths = (dateY - baseY) * 12 + (dateM - baseM);
801
+ const baseUTC = Date.UTC(baseY, baseM, baseD);
802
+ const dateUTC = Date.UTC(dateY, dateM, dateD);
803
+ const diffDays = Math.round((dateUTC - baseUTC) / MS_PER_DAY);
804
+ if (Math.abs(totalMonths) >= 12) {
805
+ const value = Math.round(totalMonths / 12);
806
+ return { value, unit: "year" };
807
+ }
808
+ if (Math.abs(totalMonths) >= 1) {
809
+ return { value: totalMonths, unit: "month" };
810
+ }
811
+ return { value: diffDays === 0 ? sign * 1 : diffDays, unit: "day" };
812
+ }
813
+ function formatRelative(date, base) {
814
+ const d = toDate(date);
815
+ if (!d) return "";
816
+ const baseDate = base !== void 0 ? toDate(base) : /* @__PURE__ */ new Date();
817
+ if (!baseDate) return "";
818
+ const locale = getLocale();
819
+ const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
820
+ const { value, unit } = getRelativeUnit(d, baseDate);
821
+ return rtf.format(value, unit);
822
+ }
823
+
824
+ // src/formatters/numberFormatter.ts
825
+ function formatNumber(value, options) {
826
+ const n = toNumber(value);
827
+ if (n === null) return "";
828
+ const locale = getLocale();
829
+ return new Intl.NumberFormat(locale, options).format(n);
830
+ }
831
+ function formatPercent(value, decimals) {
832
+ const n = toNumber(value);
833
+ if (n === null) return "";
834
+ const locale = getLocale();
835
+ const opts = {
836
+ style: "percent",
837
+ ...decimals !== void 0 && { minimumFractionDigits: decimals, maximumFractionDigits: decimals }
838
+ };
839
+ return new Intl.NumberFormat(locale, opts).format(n);
840
+ }
841
+ function formatCompact(value) {
842
+ const n = toNumber(value);
843
+ if (n === null) return "";
844
+ const locale = getLocale();
845
+ return new Intl.NumberFormat(locale, { notation: "compact" }).format(n);
846
+ }
847
+
848
+ // src/formatters/currencyFormatter.ts
849
+ function formatCurrency(value, currencyCode) {
850
+ const n = toNumber(value);
851
+ if (n === null) return "";
852
+ if (!currencyCode || typeof currencyCode !== "string") return "";
853
+ const locale = getLocale();
854
+ try {
855
+ return new Intl.NumberFormat(locale, {
856
+ style: "currency",
857
+ currency: currencyCode
858
+ }).format(n);
859
+ } catch {
860
+ return "";
861
+ }
862
+ }
863
+
864
+ // src/formatters/sortUtils.ts
865
+ function compareStrings(a, b, options) {
866
+ const locale = getLocale();
867
+ return new Intl.Collator(locale, options).compare(a, b);
868
+ }
869
+ function createCollator(options) {
870
+ const locale = getLocale();
871
+ return new Intl.Collator(locale, options);
872
+ }
873
+ // Annotate the CommonJS export names for ESM import in node:
874
+ 0 && (module.exports = {
875
+ HTML_DIR_ATTRIBUTE,
876
+ HTML_LANG_ATTRIBUTE,
877
+ I18N_DEFAULT_NAMESPACE,
878
+ I18N_NAMESPACE_SEPARATOR,
879
+ I18N_PATH_SEPARATOR,
880
+ I18nRegistryImpl,
881
+ Language,
882
+ LanguageDisplayMode,
883
+ SUPPORTED_LANGUAGES,
884
+ TextDirection,
885
+ compareStrings,
886
+ createCollator,
887
+ createI18nRegistry,
888
+ formatCompact,
889
+ formatCurrency,
890
+ formatDate,
891
+ formatDateTime,
892
+ formatNumber,
893
+ formatPercent,
894
+ formatRelative,
895
+ formatTime,
896
+ getLanguageMetadata,
897
+ getRTLLanguages,
898
+ i18nRegistry,
899
+ isValidLanguage
900
+ });
901
+ //# sourceMappingURL=index.cjs.map