langie 1.9.25

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,2898 @@
1
+ /**
2
+ * langie v1.9.25
3
+ * (c) 2026 nlit
4
+ * @license Apache-2.0
5
+ *
6
+ * Licensed under the Apache License, Version 2.0
7
+ * http://www.apache.org/licenses/LICENSE-2.0
8
+ */
9
+ "use strict";
10
+ var __create = Object.create;
11
+ var __defProp = Object.defineProperty;
12
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
13
+ var __getOwnPropNames = Object.getOwnPropertyNames;
14
+ var __getProtoOf = Object.getPrototypeOf;
15
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
16
+ var __export = (target, all) => {
17
+ for (var name in all)
18
+ __defProp(target, name, { get: all[name], enumerable: true });
19
+ };
20
+ var __copyProps = (to, from, except, desc) => {
21
+ if (from && typeof from === "object" || typeof from === "function") {
22
+ for (let key of __getOwnPropNames(from))
23
+ if (!__hasOwnProp.call(to, key) && key !== except)
24
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
25
+ }
26
+ return to;
27
+ };
28
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
29
+ // If the importer is in node compatibility mode or this is not an ESM
30
+ // file that has been converted to a CommonJS file using a Babel-
31
+ // compatible transform (i.e. "__esModule" has not been set), then set
32
+ // "default" to the CommonJS "module.exports" for node compatibility.
33
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
34
+ mod
35
+ ));
36
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
37
+
38
+ // src/index.ts
39
+ var src_exports = {};
40
+ __export(src_exports, {
41
+ API_FIELD_CTX: () => API_FIELD_CTX,
42
+ API_FIELD_FROM: () => API_FIELD_FROM,
43
+ API_FIELD_TEXT: () => API_FIELD_TEXT,
44
+ API_FIELD_TO: () => API_FIELD_TO,
45
+ API_FIELD_TRANSLATED: () => API_FIELD_TRANSLATED,
46
+ API_FIELD_TRANSLATIONS: () => API_FIELD_TRANSLATIONS,
47
+ BROWSER_LANGUAGE_MAP: () => BROWSER_LANGUAGE_MAP,
48
+ COLORS: () => COLORS,
49
+ CSS_VARS: () => CSS_VARS,
50
+ DEFAULT_API_HOST: () => DEFAULT_API_HOST,
51
+ DEV_API_HOST: () => DEV_API_HOST,
52
+ InterfaceLanguageSelect: () => InterfaceLanguageSelect_default2,
53
+ LANGUAGE_ALIAS_TABLE: () => LANGUAGE_ALIAS_TABLE,
54
+ LanguageSelect: () => LanguageSelect_default2,
55
+ THEME_COLORS: () => THEME_COLORS,
56
+ cacheManager: () => cacheManager,
57
+ clearCache: () => clearCache,
58
+ clearThemeColors: () => clearThemeColors,
59
+ clearTranslationCache: () => clearTranslationCache,
60
+ detectBrowserLanguage: () => detectBrowserLanguage,
61
+ fetchAvailableLanguages: () => fetchAvailableLanguages,
62
+ getCache: () => getCache,
63
+ getCacheStats: () => getCacheStats,
64
+ getCountryCode: () => getCountryCode,
65
+ getGeoRequestParams: () => getGeoRequestParams,
66
+ getLtDefaults: () => getLtDefaults,
67
+ getRegionForCountry: () => getRegionForCountry,
68
+ getTranslationCacheSize: () => getTranslationCacheSize,
69
+ lt: () => lt_default2,
70
+ removeCache: () => removeCache,
71
+ setCache: () => setCache,
72
+ setLtDefaults: () => setLtDefaults,
73
+ setThemeColors: () => setThemeColors,
74
+ translateBatch: () => translateBatch,
75
+ useLangie: () => useLangie,
76
+ useTranslator: () => useLangie
77
+ });
78
+ module.exports = __toCommonJS(src_exports);
79
+
80
+ // src/useLangie.ts
81
+ var import_vue2 = require("vue");
82
+
83
+ // src/composables/useLangie-core.ts
84
+ var import_vue = require("vue");
85
+
86
+ // src/constants.ts
87
+ var DEFAULT_API_HOST = "https://api.langie.uk/v1";
88
+ var DEV_API_HOST = "http://localhost:8081/v1";
89
+ var API_FIELD_TEXT = "t";
90
+ var API_FIELD_FROM = "from";
91
+ var API_FIELD_TO = "to";
92
+ var API_FIELD_CTX = "ctx";
93
+ var API_FIELD_TRANSLATED = "t";
94
+ var API_FIELD_TRANSLATIONS = "translations";
95
+ var API_FIELD_ERROR = "error";
96
+
97
+ // src/utils/debug.ts
98
+ var import_meta = {};
99
+ function devDebug(...args) {
100
+ if (import_meta.env && import_meta.env.DEV) {
101
+ console.debug(...args);
102
+ }
103
+ }
104
+
105
+ // src/utils/getCountryCode.ts
106
+ var ct = __toESM(require("countries-and-timezones"), 1);
107
+ async function getCountryCode() {
108
+ const localeCountry = getCountryCodeFromBrowser();
109
+ if (localeCountry) return localeCountry;
110
+ const timezoneCountry = getCountryFromTimezone();
111
+ if (timezoneCountry) return timezoneCountry;
112
+ return await getCountryFromIP();
113
+ }
114
+ function getCountryFromTimezone() {
115
+ try {
116
+ const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
117
+ return getCountryFromTimezoneString(timezone);
118
+ } catch (error) {
119
+ return null;
120
+ }
121
+ }
122
+ function getCountryFromTimezoneString(timezone) {
123
+ try {
124
+ const country = ct.getCountryForTimezone(timezone);
125
+ return country?.id || null;
126
+ } catch (error) {
127
+ return null;
128
+ }
129
+ }
130
+ async function getCountryFromIP() {
131
+ try {
132
+ const response = await fetch("https://ipapi.co/json/");
133
+ const data = await response.json();
134
+ return data.country_code || null;
135
+ } catch (error) {
136
+ return null;
137
+ }
138
+ }
139
+ function getCountryCodeFromBrowser() {
140
+ const langs = navigator.languages || [navigator.language];
141
+ for (const locale of langs) {
142
+ const parts = locale.split("-");
143
+ if (parts.length > 1) {
144
+ return parts[1].toUpperCase();
145
+ }
146
+ }
147
+ return null;
148
+ }
149
+
150
+ // src/utils/cache.ts
151
+ var DEFAULT_TTL = 7 * 24 * 60 * 60 * 1e3;
152
+ var DEFAULT_MAX_SIZE = 2 * 1024 * 1024;
153
+ var DEFAULT_MAX_ITEMS = 1e3;
154
+ var CacheManager = class {
155
+ options;
156
+ constructor(options = {}) {
157
+ this.options = {
158
+ ttl: options.ttl || DEFAULT_TTL,
159
+ maxSize: options.maxSize || DEFAULT_MAX_SIZE,
160
+ maxItems: options.maxItems || DEFAULT_MAX_ITEMS
161
+ };
162
+ }
163
+ set(key, data, ttl) {
164
+ if (typeof window === "undefined") return false;
165
+ try {
166
+ const item = {
167
+ data,
168
+ timestamp: Date.now(),
169
+ ttl: ttl || this.options.ttl
170
+ };
171
+ const serialized = JSON.stringify(item);
172
+ const size = new Blob([serialized]).size;
173
+ if (size > this.options.maxSize) {
174
+ console.warn(`[CacheManager] Item size ${size} exceeds max size ${this.options.maxSize}`);
175
+ return false;
176
+ }
177
+ this.cleanup();
178
+ const currentSize = this.getCurrentSize();
179
+ if (currentSize + size > this.options.maxSize) {
180
+ console.warn(`[CacheManager] Cache would exceed max size after adding item`);
181
+ return false;
182
+ }
183
+ localStorage.setItem(key, serialized);
184
+ return true;
185
+ } catch (error) {
186
+ console.warn(`[CacheManager] Failed to set cache item ${key}:`, error);
187
+ return false;
188
+ }
189
+ }
190
+ get(key) {
191
+ if (typeof window === "undefined") return null;
192
+ try {
193
+ const item = localStorage.getItem(key);
194
+ if (!item) return null;
195
+ const cacheItem = JSON.parse(item);
196
+ const now = Date.now();
197
+ if (now - cacheItem.timestamp > cacheItem.ttl) {
198
+ localStorage.removeItem(key);
199
+ return null;
200
+ }
201
+ return cacheItem.data;
202
+ } catch (error) {
203
+ console.warn(`[CacheManager] Failed to get cache item ${key}:`, error);
204
+ localStorage.removeItem(key);
205
+ return null;
206
+ }
207
+ }
208
+ remove(key) {
209
+ if (typeof window === "undefined") return false;
210
+ try {
211
+ localStorage.removeItem(key);
212
+ return true;
213
+ } catch (error) {
214
+ console.warn(`[CacheManager] Failed to remove cache item ${key}:`, error);
215
+ return false;
216
+ }
217
+ }
218
+ clear(pattern) {
219
+ if (typeof window === "undefined") return;
220
+ try {
221
+ if (pattern) {
222
+ Object.keys(localStorage).forEach((key) => {
223
+ if (key.includes(pattern)) {
224
+ localStorage.removeItem(key);
225
+ }
226
+ });
227
+ } else {
228
+ Object.keys(localStorage).forEach((key) => {
229
+ if (key.startsWith("langie_")) {
230
+ localStorage.removeItem(key);
231
+ }
232
+ });
233
+ }
234
+ } catch (error) {
235
+ console.warn("[CacheManager] Failed to clear cache:", error);
236
+ }
237
+ }
238
+ cleanup() {
239
+ if (typeof window === "undefined") return;
240
+ try {
241
+ const now = Date.now();
242
+ const items = [];
243
+ Object.keys(localStorage).forEach((key) => {
244
+ if (key.startsWith("langie_")) {
245
+ try {
246
+ const item = localStorage.getItem(key);
247
+ if (item) {
248
+ const cacheItem = JSON.parse(item);
249
+ const size = new Blob([item]).size;
250
+ if (now - cacheItem.timestamp > cacheItem.ttl) {
251
+ localStorage.removeItem(key);
252
+ return;
253
+ }
254
+ items.push({
255
+ key,
256
+ size,
257
+ timestamp: cacheItem.timestamp
258
+ });
259
+ }
260
+ } catch (error) {
261
+ localStorage.removeItem(key);
262
+ }
263
+ }
264
+ });
265
+ items.sort((a, b) => a.timestamp - b.timestamp);
266
+ while (items.length > this.options.maxItems) {
267
+ const oldest = items.shift();
268
+ if (oldest) {
269
+ localStorage.removeItem(oldest.key);
270
+ }
271
+ }
272
+ let totalSize = items.reduce((sum, item) => sum + item.size, 0);
273
+ while (totalSize > this.options.maxSize && items.length > 0) {
274
+ const oldest = items.shift();
275
+ if (oldest) {
276
+ localStorage.removeItem(oldest.key);
277
+ totalSize -= oldest.size;
278
+ }
279
+ }
280
+ } catch (error) {
281
+ console.warn("[CacheManager] Failed to cleanup cache:", error);
282
+ }
283
+ }
284
+ getCurrentSize() {
285
+ if (typeof window === "undefined") return 0;
286
+ try {
287
+ let totalSize = 0;
288
+ Object.keys(localStorage).forEach((key) => {
289
+ if (key.startsWith("langie_")) {
290
+ const item = localStorage.getItem(key);
291
+ if (item) {
292
+ totalSize += new Blob([item]).size;
293
+ }
294
+ }
295
+ });
296
+ return totalSize;
297
+ } catch (error) {
298
+ console.warn("[CacheManager] Failed to calculate cache size:", error);
299
+ return 0;
300
+ }
301
+ }
302
+ getStats() {
303
+ if (typeof window === "undefined") {
304
+ return { size: 0, items: 0, maxSize: this.options.maxSize, maxItems: this.options.maxItems };
305
+ }
306
+ try {
307
+ let totalSize = 0;
308
+ let itemCount = 0;
309
+ Object.keys(localStorage).forEach((key) => {
310
+ if (key.startsWith("langie_")) {
311
+ const item = localStorage.getItem(key);
312
+ if (item) {
313
+ totalSize += new Blob([item]).size;
314
+ itemCount++;
315
+ }
316
+ }
317
+ });
318
+ return {
319
+ size: totalSize,
320
+ items: itemCount,
321
+ maxSize: this.options.maxSize,
322
+ maxItems: this.options.maxItems
323
+ };
324
+ } catch (error) {
325
+ console.warn("[CacheManager] Failed to get cache stats:", error);
326
+ return { size: 0, items: 0, maxSize: this.options.maxSize, maxItems: this.options.maxItems };
327
+ }
328
+ }
329
+ };
330
+ var cacheManager = new CacheManager();
331
+ var setCache = (key, data, ttl) => {
332
+ return cacheManager.set(key, data, ttl);
333
+ };
334
+ var getCache = (key) => {
335
+ return cacheManager.get(key);
336
+ };
337
+ var removeCache = (key) => {
338
+ return cacheManager.remove(key);
339
+ };
340
+ var clearCache = (pattern) => {
341
+ return cacheManager.clear(pattern);
342
+ };
343
+ var getCacheStats = () => {
344
+ return cacheManager.getStats();
345
+ };
346
+
347
+ // src/composables/useLangie-core.ts
348
+ var availableLanguages = (0, import_vue.ref)([]);
349
+ var translations = (0, import_vue.reactive)({});
350
+ var uiTranslations = (0, import_vue.reactive)({});
351
+ var currentLanguage = (0, import_vue.ref)("en");
352
+ var _translatorHost = DEFAULT_API_HOST;
353
+ var _autoSelected = false;
354
+ var _languagesCache = null;
355
+ var _languagesPromise = null;
356
+ function useLangieCore(options = {}) {
357
+ if (options.translatorHost) {
358
+ _translatorHost = options.translatorHost;
359
+ }
360
+ const translatorHost = _translatorHost;
361
+ const defaultLanguage = options.defaultLanguage || "en";
362
+ const isLoading = (0, import_vue.ref)(false);
363
+ if (defaultLanguage !== "en" && currentLanguage.value === "en") {
364
+ currentLanguage.value = defaultLanguage;
365
+ }
366
+ if (typeof window !== "undefined" && currentLanguage.value === "en") {
367
+ const savedLanguage = localStorage.getItem("interface_language");
368
+ if (savedLanguage) {
369
+ currentLanguage.value = savedLanguage;
370
+ }
371
+ }
372
+ if (typeof window !== "undefined") {
373
+ const cachedLanguages = getCache("langie_languages_cache");
374
+ if (cachedLanguages && availableLanguages.value.length === 0) {
375
+ availableLanguages.value = cachedLanguages;
376
+ _languagesCache = cachedLanguages;
377
+ devDebug("[useLangie] Loaded languages from cache:", cachedLanguages.length);
378
+ } else if (cachedLanguages) {
379
+ devDebug(
380
+ "[useLangie] Cache exists but languages already loaded:",
381
+ availableLanguages.value.length
382
+ );
383
+ } else {
384
+ devDebug("[useLangie] No cached languages found");
385
+ }
386
+ }
387
+ const setLanguage = (lang) => {
388
+ if (lang && lang !== currentLanguage.value) {
389
+ }
390
+ currentLanguage.value = lang;
391
+ if (typeof window !== "undefined") {
392
+ localStorage.setItem("interface_language", lang);
393
+ }
394
+ };
395
+ const fetchLanguages = async (opts = {}) => {
396
+ const { force = false, country: explicitCountry } = opts;
397
+ devDebug("[useLangie] fetchLanguages called:", {
398
+ force,
399
+ hasCache: !!_languagesCache,
400
+ hasPromise: !!_languagesPromise,
401
+ availableLanguagesLength: availableLanguages.value.length
402
+ });
403
+ if (!force) {
404
+ if (_languagesCache) {
405
+ devDebug("[useLangie] Returning cached languages:", _languagesCache.length);
406
+ return _languagesCache;
407
+ }
408
+ if (_languagesPromise) {
409
+ devDebug("[useLangie] Returning existing promise");
410
+ return _languagesPromise;
411
+ }
412
+ }
413
+ try {
414
+ let countryHint = explicitCountry || null;
415
+ if (!countryHint && !_languagesCache && availableLanguages.value && availableLanguages.value.length) {
416
+ const currentLang = currentLanguage.value;
417
+ const entry = availableLanguages.value.find(
418
+ (l) => l.code === currentLang
419
+ );
420
+ if (entry) {
421
+ const c = Array.isArray(entry.flag_country) ? entry.flag_country[0] : typeof entry.flag_country === "string" ? entry.flag_country.split(",")[0] : null;
422
+ if (c) countryHint = c.toUpperCase();
423
+ }
424
+ }
425
+ if (!countryHint && !_languagesCache && typeof window !== "undefined") {
426
+ const cc = await getCountryCode();
427
+ countryHint = cc;
428
+ }
429
+ let url = "/languages";
430
+ const language = typeof navigator !== "undefined" && navigator.languages && navigator.languages[0] || typeof navigator !== "undefined" && navigator.language || "";
431
+ const timezone = typeof Intl !== "undefined" && Intl.DateTimeFormat().resolvedOptions().timeZone || "";
432
+ const params = new URLSearchParams();
433
+ if (countryHint) params.append("country", countryHint);
434
+ if (language) params.append("language", language);
435
+ if (timezone) params.append("timezone", timezone);
436
+ if (Array.from(params).length > 0) url += `?${params.toString()}`;
437
+ _languagesPromise = fetch(`${translatorHost}${url}`).then((res) => res.json());
438
+ const response = await _languagesPromise;
439
+ const rawList = Array.isArray(response) ? response : response.languages || [];
440
+ const mapped = rawList.map(
441
+ (lang) => {
442
+ let flag = lang.flag_country || lang.code;
443
+ if (Array.isArray(flag)) {
444
+ flag = flag[0];
445
+ }
446
+ return {
447
+ ...lang,
448
+ value: lang.code,
449
+ flag_country: flag
450
+ };
451
+ }
452
+ );
453
+ const filtered = mapped.filter((l) => {
454
+ if (l.code.startsWith("sr")) {
455
+ return l.code === "sr-latn" || l.code === "sr-cyrl";
456
+ }
457
+ return true;
458
+ });
459
+ availableLanguages.value = filtered;
460
+ devDebug("[useLangie] Set availableLanguages:", filtered.length);
461
+ if (typeof window !== "undefined") {
462
+ const saved = setCache("langie_languages_cache", filtered, 7 * 24 * 60 * 60 * 1e3);
463
+ devDebug(
464
+ "[useLangie] Saved languages to cache:",
465
+ saved ? "success" : "failed",
466
+ filtered.length
467
+ );
468
+ }
469
+ if (!_autoSelected && !localStorage.getItem("interface_language")) {
470
+ const locale = typeof navigator !== "undefined" ? navigator.languages?.[0] || navigator.language || "" : "";
471
+ const browserCode = locale.split("-")[0];
472
+ if (browserCode) {
473
+ let pick = void 0;
474
+ if (browserCode === "sr") {
475
+ const isLatin = /latn/i.test(locale) || locale === "sr";
476
+ const target = isLatin ? "sr-latn" : "sr-cyrl";
477
+ pick = mapped.find((l) => l.value === target);
478
+ } else if (browserCode === "sh") {
479
+ pick = mapped.find((l) => l.value === "sr-latn") || mapped.find((l) => l.code.startsWith("sr"));
480
+ } else {
481
+ pick = mapped.find((l) => l.value === browserCode);
482
+ if (!pick) {
483
+ pick = mapped.find((l) => l.code.startsWith(browserCode));
484
+ }
485
+ }
486
+ if (pick && pick.value) {
487
+ setLanguage(pick.value);
488
+ }
489
+ }
490
+ _autoSelected = true;
491
+ }
492
+ _languagesCache = filtered;
493
+ _languagesPromise = null;
494
+ return filtered;
495
+ } catch (error) {
496
+ devDebug("[useLangie] Language fetch error:", { error });
497
+ return [];
498
+ }
499
+ };
500
+ const clearTranslations = () => {
501
+ Object.keys(translations).forEach((key) => delete translations[key]);
502
+ Object.keys(uiTranslations).forEach((key) => delete uiTranslations[key]);
503
+ if (typeof window !== "undefined") {
504
+ clearCache("translations_cache");
505
+ clearCache("ui_translations_cache");
506
+ }
507
+ };
508
+ return {
509
+ availableLanguages,
510
+ translations,
511
+ uiTranslations,
512
+ currentLanguage,
513
+ isLoading,
514
+ setLanguage,
515
+ fetchLanguages,
516
+ clearTranslations,
517
+ translatorHost
518
+ };
519
+ }
520
+
521
+ // src/composables/useLangie-batching.ts
522
+ var TranslationBatching = class {
523
+ constructor(options = {}, translatorHost, currentLanguage2, onBatchComplete) {
524
+ this.options = options;
525
+ this.translatorHost = translatorHost;
526
+ this.currentLanguage = currentLanguage2;
527
+ this.onBatchComplete = onBatchComplete;
528
+ }
529
+ pendingRequests = /* @__PURE__ */ new Set();
530
+ queueMap = /* @__PURE__ */ new Map();
531
+ flushTimeout = null;
532
+ queuedThisTick = /* @__PURE__ */ new Set();
533
+ clearQueuedThisTickScheduled = false;
534
+ firstItemTime = null;
535
+ get initialBatchDelay() {
536
+ return this.options.initialBatchDelay ?? 50;
537
+ }
538
+ get followupBatchDelay() {
539
+ return this.options.followupBatchDelay ?? 10;
540
+ }
541
+ get maxBatchSize() {
542
+ return this.options.maxBatchSize ?? 50;
543
+ }
544
+ get maxWaitTime() {
545
+ return this.options.maxWaitTime ?? 1e3;
546
+ }
547
+ scheduleClearQueuedThisTick() {
548
+ if (this.clearQueuedThisTickScheduled) return;
549
+ this.clearQueuedThisTickScheduled = true;
550
+ queueMicrotask(() => {
551
+ this.queuedThisTick.clear();
552
+ this.clearQueuedThisTickScheduled = false;
553
+ });
554
+ }
555
+ flushQueues = async () => {
556
+ const allRequests = [];
557
+ for (const [batchKey, map] of Array.from(this.queueMap.entries())) {
558
+ if (!map || map.size === 0) {
559
+ this.queueMap.delete(batchKey);
560
+ continue;
561
+ }
562
+ const [from, to] = batchKey.split("|");
563
+ for (const [cacheKey, item] of map.entries()) {
564
+ allRequests.push({
565
+ [API_FIELD_TEXT]: item[API_FIELD_TEXT],
566
+ [API_FIELD_CTX]: item[API_FIELD_CTX],
567
+ [API_FIELD_FROM]: from,
568
+ [API_FIELD_TO]: to,
569
+ cacheKey,
570
+ __explicitToLang: item.__explicitToLang
571
+ });
572
+ }
573
+ this.queueMap.delete(batchKey);
574
+ }
575
+ if (allRequests.length > 0) {
576
+ devDebug(
577
+ "[TranslationBatching] Sending batch:",
578
+ allRequests.length,
579
+ "translation items",
580
+ allRequests
581
+ );
582
+ const chunks = this.chunkArray(allRequests, this.maxBatchSize);
583
+ for (const chunk of chunks) {
584
+ try {
585
+ await this.fetchAndCacheBatchMixed(chunk);
586
+ } catch (error) {
587
+ devDebug("[TranslationBatching] Batch translation error:", error);
588
+ chunk.forEach((req) => this.pendingRequests.delete(req.cacheKey));
589
+ }
590
+ }
591
+ }
592
+ this.firstItemTime = null;
593
+ };
594
+ chunkArray(array, size) {
595
+ const chunks = [];
596
+ for (let i = 0; i < array.length; i += size) {
597
+ chunks.push(array.slice(i, i + size));
598
+ }
599
+ return chunks;
600
+ }
601
+ scheduleFlush = () => {
602
+ if (this.flushTimeout) {
603
+ clearTimeout(this.flushTimeout);
604
+ }
605
+ let totalItems = 0;
606
+ for (const map of this.queueMap.values()) {
607
+ totalItems += map.size;
608
+ }
609
+ if (this.firstItemTime && Date.now() - this.firstItemTime >= this.maxWaitTime) {
610
+ devDebug("[TranslationBatching] Flushing due to maximum wait time:", totalItems, "items");
611
+ this.flushQueues();
612
+ return;
613
+ }
614
+ const delay = this.queueMap.size === 1 ? this.initialBatchDelay : this.followupBatchDelay;
615
+ devDebug(
616
+ "[TranslationBatching] Scheduling flush in",
617
+ delay,
618
+ "ms",
619
+ Array.from(this.queueMap.entries())
620
+ );
621
+ this.flushTimeout = setTimeout(() => {
622
+ this.flushQueues();
623
+ this.flushTimeout = null;
624
+ }, delay);
625
+ };
626
+ queueTranslation(text, ctx, from, to, cacheKey, explicitToLang) {
627
+ if (this.pendingRequests.has(cacheKey) || this.queuedThisTick.has(cacheKey)) {
628
+ devDebug("[TranslationBatching] Skipping duplicate:", cacheKey);
629
+ return;
630
+ }
631
+ if (this.firstItemTime === null) {
632
+ this.firstItemTime = Date.now();
633
+ }
634
+ this.queuedThisTick.add(cacheKey);
635
+ this.scheduleClearQueuedThisTick();
636
+ this.pendingRequests.add(cacheKey);
637
+ const batchKey = `${from}|${to}`;
638
+ if (!this.queueMap.has(batchKey)) {
639
+ this.queueMap.set(batchKey, /* @__PURE__ */ new Map());
640
+ }
641
+ this.queueMap.get(batchKey).set(cacheKey, {
642
+ [API_FIELD_TEXT]: text,
643
+ [API_FIELD_CTX]: ctx,
644
+ __explicitToLang: explicitToLang
645
+ });
646
+ devDebug("[TranslationBatching] Queued translation:", {
647
+ text,
648
+ ctx,
649
+ from,
650
+ to,
651
+ cacheKey,
652
+ batchKey,
653
+ explicitToLang
654
+ });
655
+ this.scheduleFlush();
656
+ }
657
+ async fetchAndCacheBatchMixed(requests) {
658
+ const grouped = {};
659
+ requests.forEach((req) => {
660
+ const key = `${req.from}|${req.to}`;
661
+ if (!grouped[key]) grouped[key] = [];
662
+ grouped[key].push(req);
663
+ });
664
+ const allResults = [];
665
+ const allRequests = [];
666
+ for (const [langPair, batchRequests] of Object.entries(grouped)) {
667
+ const [from, to] = langPair.split("|");
668
+ try {
669
+ const contexts = [...new Set(batchRequests.map((req) => req[API_FIELD_CTX]))];
670
+ const useGlobalContext = contexts.length === 1 && contexts[0] === "ui";
671
+ devDebug(
672
+ "[TranslationBatching] Sending batch for",
673
+ langPair,
674
+ "with",
675
+ batchRequests.length,
676
+ "items",
677
+ batchRequests
678
+ );
679
+ const response = await fetch(`${this.translatorHost}/translate`, {
680
+ method: "POST",
681
+ headers: {
682
+ "Content-Type": "application/json"
683
+ },
684
+ body: JSON.stringify({
685
+ translations: batchRequests.map((req) => ({
686
+ [API_FIELD_TEXT]: req[API_FIELD_TEXT],
687
+ ...useGlobalContext ? {} : { [API_FIELD_CTX]: req[API_FIELD_CTX] }
688
+ })),
689
+ [API_FIELD_FROM]: from,
690
+ [API_FIELD_TO]: to,
691
+ ...useGlobalContext ? { [API_FIELD_CTX]: "ui" } : {}
692
+ })
693
+ });
694
+ let result;
695
+ try {
696
+ result = await response.json();
697
+ } catch (parseError) {
698
+ devDebug("[TranslationBatching] Failed to parse response as JSON:", parseError);
699
+ throw new Error(`Translation request failed: ${response.status}`);
700
+ }
701
+ if (!response.ok) {
702
+ devDebug(
703
+ "[TranslationBatching] Translation request failed:",
704
+ response.status,
705
+ response.statusText
706
+ );
707
+ if (result && result[API_FIELD_ERROR]) {
708
+ devDebug(
709
+ "[TranslationBatching] HTTP error with API error message:",
710
+ result[API_FIELD_ERROR]
711
+ );
712
+ const errorResponses = batchRequests.map((req) => ({
713
+ [API_FIELD_TEXT]: req[API_FIELD_TEXT],
714
+ [API_FIELD_ERROR]: result[API_FIELD_ERROR]
715
+ }));
716
+ allResults.push({ [API_FIELD_TRANSLATIONS]: errorResponses });
717
+ allRequests.push(...batchRequests);
718
+ batchRequests.forEach((req) => {
719
+ this.pendingRequests.delete(req.cacheKey);
720
+ });
721
+ this.onBatchComplete(allResults, allRequests);
722
+ return;
723
+ }
724
+ throw new Error(`Translation request failed: ${response.status}`);
725
+ }
726
+ if (result[API_FIELD_ERROR]) {
727
+ devDebug("[TranslationBatching] Top-level API error:", result[API_FIELD_ERROR]);
728
+ const errorResponses = batchRequests.map((req) => ({
729
+ [API_FIELD_TEXT]: req[API_FIELD_TEXT],
730
+ [API_FIELD_ERROR]: result[API_FIELD_ERROR]
731
+ }));
732
+ allResults.push({ [API_FIELD_TRANSLATIONS]: errorResponses });
733
+ allRequests.push(...batchRequests);
734
+ batchRequests.forEach((req) => {
735
+ this.pendingRequests.delete(req.cacheKey);
736
+ });
737
+ } else {
738
+ if (result[API_FIELD_TRANSLATIONS]) {
739
+ result[API_FIELD_TRANSLATIONS].forEach((translation, index) => {
740
+ if (translation[API_FIELD_ERROR]) {
741
+ const originalText = batchRequests[index]?.[API_FIELD_TEXT];
742
+ devDebug(
743
+ "[TranslationBatching] Translation error for",
744
+ originalText,
745
+ ":",
746
+ translation[API_FIELD_ERROR]
747
+ );
748
+ }
749
+ });
750
+ }
751
+ allResults.push(result);
752
+ allRequests.push(...batchRequests);
753
+ batchRequests.forEach((req) => {
754
+ this.pendingRequests.delete(req.cacheKey);
755
+ });
756
+ }
757
+ } catch (error) {
758
+ devDebug("[TranslationBatching] Batch request failed for", langPair, ":", error);
759
+ batchRequests.forEach((req) => {
760
+ this.pendingRequests.delete(req.cacheKey);
761
+ });
762
+ throw error;
763
+ }
764
+ }
765
+ this.onBatchComplete(allResults, allRequests);
766
+ }
767
+ clearPending(cacheKey) {
768
+ this.pendingRequests.delete(cacheKey);
769
+ }
770
+ clearAllPending() {
771
+ this.pendingRequests.clear();
772
+ }
773
+ cleanup() {
774
+ this.clearAllPending();
775
+ this.queueMap.clear();
776
+ this.queuedThisTick.clear();
777
+ if (this.flushTimeout) {
778
+ clearTimeout(this.flushTimeout);
779
+ this.flushTimeout = null;
780
+ }
781
+ this.clearQueuedThisTickScheduled = false;
782
+ this.firstItemTime = null;
783
+ }
784
+ getStats() {
785
+ return {
786
+ pendingRequests: this.pendingRequests.size,
787
+ queuedBatches: this.queueMap.size,
788
+ queuedThisTick: this.queuedThisTick.size,
789
+ hasFlushTimeout: !!this.flushTimeout
790
+ };
791
+ }
792
+ };
793
+
794
+ // src/useLangie.ts
795
+ var globalLangieInstance = null;
796
+ if (typeof window !== "undefined" && window.__LANGIE_SINGLETON__) {
797
+ globalLangieInstance = window.__LANGIE_SINGLETON__;
798
+ }
799
+ function safeLocalStorageAccess(operation) {
800
+ if (typeof window === "undefined") return void 0;
801
+ try {
802
+ return operation();
803
+ } catch (e) {
804
+ devDebug("[useLangie] localStorage error:", e);
805
+ return void 0;
806
+ }
807
+ }
808
+ if (!globalLangieInstance && typeof window !== "undefined") {
809
+ const stored = safeLocalStorageAccess(() => localStorage.getItem("__LANGIE_SINGLETON_URL__"));
810
+ if (stored) {
811
+ const storedOptions = { translatorHost: stored };
812
+ globalLangieInstance = createLangieInstance(storedOptions);
813
+ }
814
+ }
815
+ function createLangieInstance(options = {}) {
816
+ const core = useLangieCore(options);
817
+ const {
818
+ availableLanguages: availableLanguages2,
819
+ translations: translations2,
820
+ uiTranslations: uiTranslations2,
821
+ currentLanguage: currentLanguage2,
822
+ isLoading,
823
+ setLanguage,
824
+ fetchLanguages,
825
+ translatorHost,
826
+ clearTranslations
827
+ } = core;
828
+ const ltDefaults = {
829
+ ctx: "ui",
830
+ orig: ""
831
+ };
832
+ const setLtDefaults2 = (defaults) => {
833
+ Object.assign(ltDefaults, defaults);
834
+ };
835
+ const getLtDefaults2 = () => ({ ...ltDefaults });
836
+ const CACHE_KEY = "langie_translations_cache";
837
+ const UI_CACHE_KEY = "langie_ui_translations_cache";
838
+ const LANGUAGES_CACHE_KEY = "langie_languages_cache";
839
+ const loadCachedTranslations = () => {
840
+ if (typeof window === "undefined") return;
841
+ const cachedTranslations = getCache(CACHE_KEY);
842
+ const cachedUiTranslations = getCache(UI_CACHE_KEY);
843
+ if (cachedTranslations) {
844
+ const currentLang = currentLanguage2.value;
845
+ const langTranslations = cachedTranslations[currentLang] || {};
846
+ Object.assign(translations2, langTranslations);
847
+ }
848
+ if (cachedUiTranslations) {
849
+ const currentLang = currentLanguage2.value;
850
+ const langUiTranslations = cachedUiTranslations[currentLang] || {};
851
+ Object.assign(uiTranslations2, langUiTranslations);
852
+ }
853
+ };
854
+ const saveCachedTranslations = () => {
855
+ if (typeof window === "undefined") return;
856
+ const existingTranslations = getCache(CACHE_KEY) || {};
857
+ const existingUiTranslations = getCache(UI_CACHE_KEY) || {};
858
+ const currentLang = currentLanguage2.value;
859
+ existingTranslations[currentLang] = { ...translations2 };
860
+ existingUiTranslations[currentLang] = { ...uiTranslations2 };
861
+ setCache(CACHE_KEY, existingTranslations, 7 * 24 * 60 * 60 * 1e3);
862
+ setCache(UI_CACHE_KEY, existingUiTranslations, 7 * 24 * 60 * 60 * 1e3);
863
+ };
864
+ const loadCachedLanguages = () => {
865
+ if (typeof window === "undefined") return;
866
+ const cachedLanguages = getCache(LANGUAGES_CACHE_KEY);
867
+ if (cachedLanguages) {
868
+ availableLanguages2.value = cachedLanguages;
869
+ }
870
+ };
871
+ loadCachedTranslations();
872
+ loadCachedLanguages();
873
+ (0, import_vue2.watch)(currentLanguage2, () => {
874
+ Object.keys(translations2).forEach((key) => delete translations2[key]);
875
+ Object.keys(uiTranslations2).forEach((key) => delete uiTranslations2[key]);
876
+ loadCachedTranslations();
877
+ });
878
+ const batching = new TranslationBatching(
879
+ {
880
+ initialBatchDelay: options.initialBatchDelay,
881
+ followupBatchDelay: options.followupBatchDelay,
882
+ maxBatchSize: options.maxBatchSize,
883
+ maxWaitTime: options.maxWaitTime
884
+ },
885
+ translatorHost,
886
+ () => currentLanguage2.value,
887
+ (results, requests) => {
888
+ requests.forEach((req) => {
889
+ const cacheKey = `${req[API_FIELD_TEXT]}|${req[API_FIELD_CTX]}`;
890
+ const languageCacheKey = `${cacheKey}|${req[API_FIELD_FROM]}|${req[API_FIELD_TO]}`;
891
+ recentlyQueued.delete(languageCacheKey);
892
+ });
893
+ let translationsArray = [];
894
+ results.forEach((result) => {
895
+ if (Array.isArray(result)) {
896
+ translationsArray = translationsArray.concat(result);
897
+ } else if (result.translations && Array.isArray(result.translations)) {
898
+ translationsArray = translationsArray.concat(result.translations);
899
+ }
900
+ });
901
+ translationsArray.forEach((translation, idx) => {
902
+ const request = requests[idx];
903
+ if (!request) {
904
+ devDebug("[useLangie] No matching request for translation:", translation);
905
+ return;
906
+ }
907
+ const originalText = request[API_FIELD_TEXT];
908
+ const originalCtx = request[API_FIELD_CTX] ?? (ltDefaults.ctx || "ui");
909
+ if (translation[API_FIELD_ERROR]) {
910
+ devDebug(
911
+ "[useLangie] Translation error for",
912
+ originalText,
913
+ ":",
914
+ translation[API_FIELD_ERROR]
915
+ );
916
+ const errorKey = `${originalText}|${originalCtx}|${request[API_FIELD_FROM]}|${request[API_FIELD_TO]}`;
917
+ translationErrors.set(errorKey, translation[API_FIELD_ERROR]);
918
+ return;
919
+ }
920
+ if (translation[API_FIELD_FROM] && !translation[API_FIELD_TEXT]) {
921
+ return;
922
+ }
923
+ const translatedText = translation[API_FIELD_TEXT];
924
+ if (translatedText) {
925
+ const requestedLanguage = request[API_FIELD_TO];
926
+ const explicitToLang = request.__explicitToLang;
927
+ if (!explicitToLang && requestedLanguage !== currentLanguage2.value) {
928
+ devDebug("[useLangie] Skipping outdated translation:", {
929
+ original: originalText,
930
+ translated: translatedText,
931
+ requestedLanguage,
932
+ currentLanguage: currentLanguage2.value
933
+ });
934
+ return;
935
+ }
936
+ if (translatedText === originalText) {
937
+ devDebug("[useLangie] Skipping cache for identical translation:", {
938
+ original: originalText,
939
+ translated: translatedText,
940
+ context: originalCtx
941
+ });
942
+ return;
943
+ }
944
+ const effectiveCtx = originalCtx;
945
+ const cacheKey = `${originalText}|${effectiveCtx}`;
946
+ const cache = effectiveCtx === "ui" ? uiTranslations2 : translations2;
947
+ cache[cacheKey] = translatedText;
948
+ devDebug("[useLangie] Cached translation:", {
949
+ original: originalText,
950
+ translated: translatedText,
951
+ context: effectiveCtx,
952
+ cacheKey,
953
+ language: requestedLanguage
954
+ });
955
+ saveCachedTranslations();
956
+ }
957
+ });
958
+ }
959
+ );
960
+ const recentlyQueued = /* @__PURE__ */ new Set();
961
+ const pendingTimeouts = /* @__PURE__ */ new Set();
962
+ const translationErrors = /* @__PURE__ */ new Map();
963
+ const translateInternal = (text, ctx, originalLang, toLang, reactive2 = false) => {
964
+ if (reactive2) {
965
+ void currentLanguage2.value;
966
+ }
967
+ const from = originalLang || ltDefaults.orig || "";
968
+ const to = toLang || currentLanguage2.value;
969
+ if (from === to) {
970
+ return text;
971
+ }
972
+ const effectiveCtx = ctx !== void 0 ? ctx : ltDefaults.ctx || "ui";
973
+ const cacheKey = `${text}|${effectiveCtx}`;
974
+ const cache = effectiveCtx === "ui" ? uiTranslations2 : translations2;
975
+ if (cache[cacheKey]) {
976
+ return cache[cacheKey];
977
+ }
978
+ const errorKey = `${text}|${effectiveCtx}|${from}|${to}`;
979
+ if (translationErrors.has(errorKey)) {
980
+ return text;
981
+ }
982
+ const languageCacheKey = `${cacheKey}|${from}|${to}`;
983
+ if (recentlyQueued.has(languageCacheKey)) {
984
+ return text;
985
+ }
986
+ batching.queueTranslation(text, effectiveCtx, from, to, cacheKey, toLang !== void 0);
987
+ recentlyQueued.add(languageCacheKey);
988
+ const clearDelay = 100;
989
+ const timeoutId = setTimeout(() => {
990
+ recentlyQueued.delete(languageCacheKey);
991
+ pendingTimeouts.delete(timeoutId);
992
+ }, clearDelay);
993
+ pendingTimeouts.add(timeoutId);
994
+ return text;
995
+ };
996
+ const l = (text, ctx, originalLang, toLang) => translateInternal(text, ctx, originalLang, toLang, false);
997
+ const lr = (text, ctx, originalLang, toLang) => translateInternal(text, ctx, originalLang, toLang, true);
998
+ const fetchAndCacheBatch = async (items, from, to = currentLanguage2.value, globalCtx) => {
999
+ if (items.length === 0) return;
1000
+ const effectiveFrom = from || ltDefaults.orig || "";
1001
+ if (effectiveFrom === to) {
1002
+ return;
1003
+ }
1004
+ isLoading.value = true;
1005
+ try {
1006
+ const effectiveCtx = globalCtx || ltDefaults.ctx || "ui";
1007
+ const response = await fetch(`${translatorHost}/translate`, {
1008
+ method: "POST",
1009
+ headers: {
1010
+ "Content-Type": "application/json"
1011
+ },
1012
+ body: JSON.stringify({
1013
+ translations: items.map((item) => ({
1014
+ [API_FIELD_TEXT]: item[API_FIELD_TEXT],
1015
+ [API_FIELD_CTX]: item[API_FIELD_CTX] || effectiveCtx
1016
+ })),
1017
+ [API_FIELD_FROM]: effectiveFrom,
1018
+ [API_FIELD_TO]: to
1019
+ })
1020
+ });
1021
+ if (!response.ok) {
1022
+ throw new Error(`Translation request failed: ${response.status}`);
1023
+ }
1024
+ const result = await response.json();
1025
+ if (result[API_FIELD_ERROR]) {
1026
+ devDebug("[useLangie] Top-level API error:", result[API_FIELD_ERROR]);
1027
+ const errorResponses = items.map((item) => ({
1028
+ [API_FIELD_TEXT]: item[API_FIELD_TEXT],
1029
+ [API_FIELD_ERROR]: result[API_FIELD_ERROR]
1030
+ }));
1031
+ errorResponses.forEach((translation, index) => {
1032
+ const item = items[index];
1033
+ const originalText = item?.[API_FIELD_TEXT];
1034
+ if (!originalText) {
1035
+ return;
1036
+ }
1037
+ if (translation[API_FIELD_ERROR]) {
1038
+ devDebug(
1039
+ "[useLangie] Translation error for",
1040
+ originalText,
1041
+ ":",
1042
+ translation[API_FIELD_ERROR]
1043
+ );
1044
+ const errorKey = `${originalText}|${item[API_FIELD_CTX] || effectiveCtx}|${effectiveFrom}|${to}`;
1045
+ translationErrors.set(errorKey, translation[API_FIELD_ERROR]);
1046
+ return;
1047
+ }
1048
+ });
1049
+ return;
1050
+ }
1051
+ if (result[API_FIELD_TRANSLATIONS]) {
1052
+ result[API_FIELD_TRANSLATIONS].forEach(
1053
+ (translation, index) => {
1054
+ const item = items[index];
1055
+ const originalText = item?.[API_FIELD_TEXT];
1056
+ if (!originalText) {
1057
+ return;
1058
+ }
1059
+ if (translation[API_FIELD_ERROR]) {
1060
+ devDebug(
1061
+ "[useLangie] Translation error for",
1062
+ originalText,
1063
+ ":",
1064
+ translation[API_FIELD_ERROR]
1065
+ );
1066
+ return;
1067
+ }
1068
+ if (translation[API_FIELD_FROM] && !translation[API_FIELD_TEXT]) {
1069
+ return;
1070
+ }
1071
+ const translatedText = translation[API_FIELD_TEXT];
1072
+ if (translatedText) {
1073
+ if (to !== currentLanguage2.value) {
1074
+ devDebug("[useLangie] Skipping outdated translation (batch):", {
1075
+ original: originalText,
1076
+ translated: translatedText,
1077
+ requestedLanguage: to,
1078
+ currentLanguage: currentLanguage2.value
1079
+ });
1080
+ return;
1081
+ }
1082
+ if (translatedText === originalText) {
1083
+ devDebug("[useLangie] Skipping cache for identical translation (batch):", {
1084
+ original: originalText,
1085
+ translated: translatedText,
1086
+ context: item[API_FIELD_CTX] || effectiveCtx
1087
+ });
1088
+ return;
1089
+ }
1090
+ const originalCtx = item[API_FIELD_CTX];
1091
+ const translationCtx = originalCtx !== void 0 ? originalCtx : effectiveCtx;
1092
+ const cacheKey = `${originalText}|${translationCtx}`;
1093
+ const cache = translationCtx === "ui" ? uiTranslations2 : translations2;
1094
+ cache[cacheKey] = translatedText;
1095
+ devDebug("[useLangie] Cached translation (batch):", {
1096
+ original: originalText,
1097
+ translated: translatedText,
1098
+ context: translationCtx,
1099
+ cacheKey,
1100
+ language: to
1101
+ });
1102
+ saveCachedTranslations();
1103
+ }
1104
+ }
1105
+ );
1106
+ }
1107
+ } catch (error) {
1108
+ console.error("[useLangie] Translation error:", error);
1109
+ } finally {
1110
+ isLoading.value = false;
1111
+ }
1112
+ };
1113
+ (0, import_vue2.watch)(currentLanguage2, () => {
1114
+ recentlyQueued.clear();
1115
+ loadCachedTranslations();
1116
+ batching.cleanup();
1117
+ });
1118
+ return {
1119
+ // Core functionality
1120
+ availableLanguages: availableLanguages2,
1121
+ translations: translations2,
1122
+ uiTranslations: uiTranslations2,
1123
+ currentLanguage: currentLanguage2,
1124
+ isLoading,
1125
+ setLanguage,
1126
+ fetchLanguages,
1127
+ translatorHost,
1128
+ // Translation functions
1129
+ l,
1130
+ lr,
1131
+ fetchAndCacheBatch,
1132
+ // Error handling
1133
+ getTranslationError: (text, ctx, from, to) => {
1134
+ const effectiveCtx = ctx !== void 0 ? ctx : ltDefaults.ctx || "ui";
1135
+ const effectiveFrom = from || ltDefaults.orig || "";
1136
+ const effectiveTo = to || currentLanguage2.value;
1137
+ const errorKey = `${text}|${effectiveCtx}|${effectiveFrom}|${effectiveTo}`;
1138
+ return translationErrors.get(errorKey) || null;
1139
+ },
1140
+ // Utility functions
1141
+ cleanup: () => {
1142
+ clearTranslations();
1143
+ batching.cleanup();
1144
+ pendingTimeouts.forEach((id) => clearTimeout(id));
1145
+ pendingTimeouts.clear();
1146
+ translationErrors.clear();
1147
+ },
1148
+ getBatchingStats: () => batching.getStats(),
1149
+ // lt component defaults management
1150
+ setLtDefaults: setLtDefaults2,
1151
+ getLtDefaults: getLtDefaults2
1152
+ };
1153
+ }
1154
+ function getGlobalLangieInstance() {
1155
+ if (typeof window !== "undefined") {
1156
+ return window.__LANGIE_SINGLETON__ || null;
1157
+ }
1158
+ return globalLangieInstance;
1159
+ }
1160
+ function setGlobalLangieInstance(instance, options) {
1161
+ if (typeof window !== "undefined") {
1162
+ ;
1163
+ window.__LANGIE_SINGLETON__ = instance;
1164
+ if (options && options.translatorHost) {
1165
+ safeLocalStorageAccess(
1166
+ () => localStorage.setItem("__LANGIE_SINGLETON_URL__", options.translatorHost)
1167
+ );
1168
+ }
1169
+ }
1170
+ globalLangieInstance = instance;
1171
+ }
1172
+ function useLangie(options = {}) {
1173
+ const globalInstance = getGlobalLangieInstance();
1174
+ if (globalInstance) {
1175
+ const currentHost = globalInstance.translatorHost;
1176
+ const newHost = options.translatorHost;
1177
+ if (!options.translatorHost || currentHost === newHost) {
1178
+ return globalInstance;
1179
+ }
1180
+ }
1181
+ const instance = createLangieInstance(options);
1182
+ setGlobalLangieInstance(instance, options);
1183
+ return instance;
1184
+ }
1185
+ function setLtDefaults(defaults) {
1186
+ const instance = getGlobalLangieInstance();
1187
+ if (instance && instance.setLtDefaults) {
1188
+ instance.setLtDefaults(defaults);
1189
+ }
1190
+ }
1191
+ function getLtDefaults() {
1192
+ const instance = getGlobalLangieInstance();
1193
+ if (instance && instance.getLtDefaults) {
1194
+ return instance.getLtDefaults();
1195
+ }
1196
+ return { ctx: "ui", orig: "" };
1197
+ }
1198
+
1199
+ // src/core.ts
1200
+ var DEFAULT_TRANSLATOR_HOST = "http://localhost:8081";
1201
+ var translationCache = /* @__PURE__ */ new Map();
1202
+ function getTranslationCacheKey(serviceTranslations, options) {
1203
+ return JSON.stringify({
1204
+ translations: serviceTranslations.map((t) => ({
1205
+ [API_FIELD_TEXT]: t[API_FIELD_TEXT],
1206
+ [API_FIELD_FROM]: t[API_FIELD_FROM],
1207
+ [API_FIELD_TO]: t[API_FIELD_TO],
1208
+ [API_FIELD_CTX]: t[API_FIELD_CTX] || options[API_FIELD_CTX] || "ui"
1209
+ })),
1210
+ host: options.translatorHost || DEFAULT_TRANSLATOR_HOST,
1211
+ context: options[API_FIELD_CTX] || "ui"
1212
+ });
1213
+ }
1214
+ async function translateBatch(translations2 = [], options = {}) {
1215
+ if (!Array.isArray(translations2) || translations2.length === 0) {
1216
+ throw new Error("translations must be a non-empty array");
1217
+ }
1218
+ const translatorHost = options.translatorHost || DEFAULT_TRANSLATOR_HOST;
1219
+ const apiKey = options.apiKey || process.env.TRANSLATOR_API_KEY;
1220
+ const serviceTranslations = [];
1221
+ const indexMap = [];
1222
+ translations2.forEach((tr, idx) => {
1223
+ const from = (tr[API_FIELD_FROM] || "").toLowerCase();
1224
+ const to = (tr[API_FIELD_TO] || "").toLowerCase();
1225
+ if (from === to) {
1226
+ return;
1227
+ }
1228
+ serviceTranslations.push(tr);
1229
+ indexMap.push(idx);
1230
+ });
1231
+ let serviceResults = [];
1232
+ if (serviceTranslations.length > 0) {
1233
+ const cacheKey = getTranslationCacheKey(serviceTranslations, options);
1234
+ if (translationCache.has(cacheKey)) {
1235
+ serviceResults = await translationCache.get(cacheKey);
1236
+ } else {
1237
+ const translationPromise = (async () => {
1238
+ try {
1239
+ const controller = new AbortController();
1240
+ const timeoutId = setTimeout(() => controller.abort(), 5e3);
1241
+ const resp = await fetch(`${translatorHost}/translate`, {
1242
+ method: "POST",
1243
+ headers: {
1244
+ "Content-Type": "application/json",
1245
+ ...apiKey ? { Authorization: `Bearer ${apiKey}`, "X-Api-Key": apiKey } : {}
1246
+ },
1247
+ body: JSON.stringify({
1248
+ [API_FIELD_TRANSLATIONS]: serviceTranslations.map((t) => ({
1249
+ [API_FIELD_TEXT]: t[API_FIELD_TEXT],
1250
+ [API_FIELD_FROM]: t[API_FIELD_FROM],
1251
+ [API_FIELD_TO]: t[API_FIELD_TO],
1252
+ [API_FIELD_CTX]: t[API_FIELD_CTX] || options[API_FIELD_CTX] || "ui"
1253
+ })),
1254
+ [API_FIELD_CTX]: options[API_FIELD_CTX] || "ui"
1255
+ }),
1256
+ signal: controller.signal
1257
+ });
1258
+ clearTimeout(timeoutId);
1259
+ if (!resp.ok) {
1260
+ console.error(
1261
+ "[translator-sdk] Translator error response:",
1262
+ resp.status,
1263
+ resp.statusText
1264
+ );
1265
+ throw new Error(`Translator service error: ${resp.status} ${resp.statusText}`);
1266
+ }
1267
+ let parsed;
1268
+ try {
1269
+ parsed = await resp.clone().json();
1270
+ } catch (jsonErr) {
1271
+ console.error("[translator-sdk] Failed to parse JSON response:", jsonErr);
1272
+ throw new Error(`Failed to parse JSON response: ${jsonErr}`);
1273
+ }
1274
+ const data = parsed || {};
1275
+ if (data[API_FIELD_ERROR]) {
1276
+ console.warn(`[translator-sdk] Top-level API error:`, data[API_FIELD_ERROR]);
1277
+ return serviceTranslations.map((translation) => ({
1278
+ [API_FIELD_TEXT]: translation[API_FIELD_TEXT],
1279
+ [API_FIELD_ERROR]: data[API_FIELD_ERROR]
1280
+ }));
1281
+ }
1282
+ const results = Array.isArray(data[API_FIELD_TRANSLATIONS]) ? data[API_FIELD_TRANSLATIONS].map((translation, index) => {
1283
+ const originalText = serviceTranslations[index]?.[API_FIELD_TEXT] || "";
1284
+ if (translation[API_FIELD_ERROR]) {
1285
+ console.warn(
1286
+ `[translator-sdk] Translation error for "${originalText}":`,
1287
+ translation[API_FIELD_ERROR]
1288
+ );
1289
+ return {
1290
+ [API_FIELD_TEXT]: originalText,
1291
+ // Return original text on error
1292
+ [API_FIELD_ERROR]: translation[API_FIELD_ERROR]
1293
+ };
1294
+ }
1295
+ if (translation[API_FIELD_FROM] && !translation[API_FIELD_TEXT]) {
1296
+ return {
1297
+ [API_FIELD_TEXT]: originalText,
1298
+ // For detection, return original text
1299
+ [API_FIELD_FROM]: translation[API_FIELD_FROM]
1300
+ };
1301
+ }
1302
+ return {
1303
+ [API_FIELD_TEXT]: translation[API_FIELD_TEXT] || originalText
1304
+ };
1305
+ }) : data[API_FIELD_TEXT] ? [{ [API_FIELD_TEXT]: data[API_FIELD_TEXT] }] : [];
1306
+ return results;
1307
+ } catch (error) {
1308
+ translationCache.delete(cacheKey);
1309
+ if (error instanceof Error && error.name === "AbortError") {
1310
+ const message2 = `Translator request to ${translatorHost} timed out after 5 seconds.`;
1311
+ console.error(message2);
1312
+ throw new Error(message2);
1313
+ }
1314
+ const message = `Failed to connect to translator at ${translatorHost}. Is the service running?`;
1315
+ console.error(message);
1316
+ throw new Error(message);
1317
+ }
1318
+ })();
1319
+ translationCache.set(cacheKey, translationPromise);
1320
+ serviceResults = await translationPromise;
1321
+ }
1322
+ }
1323
+ const final = translations2.map((tr, idx) => {
1324
+ const from = (tr[API_FIELD_FROM] || "").toLowerCase();
1325
+ const to = (tr[API_FIELD_TO] || "").toLowerCase();
1326
+ if (from === to) return { [API_FIELD_TEXT]: tr[API_FIELD_TEXT] };
1327
+ const svcIdx = indexMap.indexOf(idx);
1328
+ if (svcIdx !== -1) return serviceResults[svcIdx] || { [API_FIELD_TEXT]: tr[API_FIELD_TEXT] };
1329
+ return { [API_FIELD_TEXT]: tr[API_FIELD_TEXT] };
1330
+ });
1331
+ return final;
1332
+ }
1333
+ function clearTranslationCache() {
1334
+ translationCache.clear();
1335
+ }
1336
+ function getTranslationCacheSize() {
1337
+ return translationCache.size;
1338
+ }
1339
+ async function fetchAvailableLanguages(options = {}) {
1340
+ const translatorHost = options.translatorHost || DEFAULT_TRANSLATOR_HOST;
1341
+ const apiKey = options.apiKey || process.env.TRANSLATOR_API_KEY;
1342
+ const minPop = options.minPopularity !== void 0 ? Number(options.minPopularity) : Number.parseFloat(process.env.MIN_LANGUAGE_POPULARITY || "0.1");
1343
+ const queryParams = [];
1344
+ if (options.country) queryParams.push(`country=${encodeURIComponent(options.country)}`);
1345
+ if (options.region) queryParams.push(`region=${encodeURIComponent(options.region)}`);
1346
+ const queryStr = queryParams.length ? `?${queryParams.join("&")}` : "";
1347
+ const requestUrl = `${translatorHost}/languages${queryStr}`;
1348
+ try {
1349
+ const resp = await fetch(requestUrl, {
1350
+ method: "GET",
1351
+ headers: {
1352
+ "Content-Type": "application/json",
1353
+ ...apiKey ? { Authorization: `Bearer ${apiKey}`, "X-Api-Key": apiKey } : {}
1354
+ }
1355
+ });
1356
+ if (!resp.ok) {
1357
+ throw new Error(`Translator languages error: ${resp.status}`);
1358
+ }
1359
+ const data = await resp.json();
1360
+ const languages = Array.isArray(data) ? data : data.languages || [];
1361
+ const filtered = languages.filter((lang) => {
1362
+ if (lang.popularity === void 0 || lang.popularity === null) return true;
1363
+ return Number(lang.popularity) >= minPop;
1364
+ });
1365
+ return filtered;
1366
+ } catch (error) {
1367
+ console.error("[translator-sdk] Languages fetch error:", error);
1368
+ throw error;
1369
+ }
1370
+ }
1371
+
1372
+ // vue-script:/Users/nlit/projects/langie-sdk/src/components/LanguageSelect.vue?type=script
1373
+ var import_vue3 = require("vue");
1374
+ var import_vue4 = require("vue");
1375
+ var import_default = require("@vueform/multiselect/themes/default.css");
1376
+ var import_vue5 = require("vue");
1377
+ var import_multiselect = __toESM(require("@vueform/multiselect"));
1378
+ var import_fuse = __toESM(require("fuse.js"));
1379
+
1380
+ // src/language-aliases/european.ts
1381
+ var EUROPEAN_LANGUAGES = [
1382
+ // Major European Languages
1383
+ {
1384
+ lang: "english",
1385
+ match: [
1386
+ "eng",
1387
+ "en",
1388
+ "united states",
1389
+ "united states of america",
1390
+ "usa",
1391
+ "us",
1392
+ "great britain",
1393
+ "britain",
1394
+ "british",
1395
+ "england",
1396
+ "united kingdom",
1397
+ "uk"
1398
+ ],
1399
+ suggest: ["irish", "scottish", "welsh"]
1400
+ },
1401
+ {
1402
+ lang: "spanish",
1403
+ match: [
1404
+ "spa",
1405
+ "es",
1406
+ "esp",
1407
+ "spain",
1408
+ "espa\xF1ol",
1409
+ "mexico",
1410
+ "mexican",
1411
+ "argentina",
1412
+ "colombia",
1413
+ "venezuela"
1414
+ ],
1415
+ suggest: ["catalan", "galician", "basque"]
1416
+ },
1417
+ {
1418
+ lang: "french",
1419
+ match: [
1420
+ "fra",
1421
+ "fr",
1422
+ "fre",
1423
+ "france",
1424
+ "fran\xE7ais",
1425
+ "canada",
1426
+ "canadian",
1427
+ "quebec",
1428
+ "belgium",
1429
+ "swiss"
1430
+ ],
1431
+ suggest: ["occitan", "breton", "corsican"]
1432
+ },
1433
+ {
1434
+ lang: "german",
1435
+ match: [
1436
+ "ger",
1437
+ "de",
1438
+ "deu",
1439
+ "germany",
1440
+ "deutsch",
1441
+ "austria",
1442
+ "austrian",
1443
+ "switzerland",
1444
+ "swiss"
1445
+ ],
1446
+ suggest: ["bavarian", "saxon", "luxembourgish"]
1447
+ },
1448
+ {
1449
+ lang: "italian",
1450
+ match: ["ita", "it", "italy", "italiano", "swiss italian"],
1451
+ suggest: ["sardinian", "neapolitan", "venetian"]
1452
+ },
1453
+ {
1454
+ lang: "portuguese",
1455
+ match: ["por", "pt", "portugal", "brazil", "brazilian", "braz", "mozambique", "angola"],
1456
+ suggest: ["galician", "mirandese"]
1457
+ },
1458
+ {
1459
+ lang: "dutch",
1460
+ match: ["dut", "nl", "nld", "netherlands", "holland", "flemish", "belgium"],
1461
+ suggest: ["frisian", "afrikaans"]
1462
+ },
1463
+ // Slavic Languages
1464
+ {
1465
+ lang: "russian",
1466
+ match: ["rus", "ru", "russia", "belarus"],
1467
+ suggest: ["kazakh", "tatar", "belarusian", "tajik", "uzbek", "moldovan"]
1468
+ },
1469
+ {
1470
+ lang: "ukrainian",
1471
+ match: ["ukr", "uk", "ukraine"],
1472
+ suggest: ["russian", "belarusian"]
1473
+ },
1474
+ {
1475
+ lang: "polish",
1476
+ match: ["pol", "pl", "poland"],
1477
+ suggest: ["silesian", "kashubian"]
1478
+ },
1479
+ {
1480
+ lang: "czech",
1481
+ match: ["ces", "cs", "cze", "czech republic", "czechia"],
1482
+ suggest: ["slovak", "moravian"]
1483
+ },
1484
+ {
1485
+ lang: "slovak",
1486
+ match: ["slk", "sk", "slovakia"],
1487
+ suggest: ["czech", "rusyn"]
1488
+ },
1489
+ {
1490
+ lang: "croatian",
1491
+ match: ["hrv", "hr", "croatia"],
1492
+ suggest: ["serbian", "bosnian", "montenegrin"]
1493
+ },
1494
+ {
1495
+ lang: "serbian",
1496
+ match: ["srp", "sr", "ser", "serbia", "serbian", "srpski", "\u0441\u0440\u0431\u0438\u0458\u0430", "\u0441\u0440\u043F\u0441\u043A\u0438"],
1497
+ suggest: ["croatian", "bosnian", "montenegrin"]
1498
+ },
1499
+ {
1500
+ lang: "bulgarian",
1501
+ match: ["bul", "bg", "bulgaria"],
1502
+ suggest: ["macedonian"]
1503
+ },
1504
+ {
1505
+ lang: "slovenian",
1506
+ match: ["slv", "sl", "slovenia"],
1507
+ suggest: ["croatian"]
1508
+ },
1509
+ // Nordic Languages
1510
+ {
1511
+ lang: "swedish",
1512
+ match: ["swe", "sv", "sweden"],
1513
+ suggest: ["norwegian", "danish", "finnish"]
1514
+ },
1515
+ {
1516
+ lang: "norwegian",
1517
+ match: ["nor", "no", "norway"],
1518
+ suggest: ["swedish", "danish"]
1519
+ },
1520
+ {
1521
+ lang: "danish",
1522
+ match: ["dan", "da", "denmark"],
1523
+ suggest: ["norwegian", "swedish"]
1524
+ },
1525
+ {
1526
+ lang: "finnish",
1527
+ match: ["fin", "fi", "finland"],
1528
+ suggest: ["estonian", "swedish"]
1529
+ },
1530
+ {
1531
+ lang: "icelandic",
1532
+ match: ["isl", "is", "iceland"],
1533
+ suggest: ["faroese", "norwegian"]
1534
+ },
1535
+ // Other European Languages
1536
+ {
1537
+ lang: "greek",
1538
+ match: ["ell", "el", "gre", "greece", "hellenic"],
1539
+ suggest: ["macedonian", "albanian"]
1540
+ },
1541
+ {
1542
+ lang: "romanian",
1543
+ match: ["ron", "ro", "rum", "romania"],
1544
+ suggest: ["moldovan", "hungarian"]
1545
+ },
1546
+ {
1547
+ lang: "hungarian",
1548
+ match: ["hun", "hu", "hungary", "magyar"],
1549
+ suggest: ["romanian", "slovak"]
1550
+ },
1551
+ {
1552
+ lang: "albanian",
1553
+ match: ["sqi", "sq", "alb", "albania", "kosovo"],
1554
+ suggest: ["greek", "macedonian"]
1555
+ },
1556
+ {
1557
+ lang: "lithuanian",
1558
+ match: ["lit", "lt", "lithuania"],
1559
+ suggest: ["latvian", "polish"]
1560
+ },
1561
+ {
1562
+ lang: "latvian",
1563
+ match: ["lav", "lv", "latvia"],
1564
+ suggest: ["lithuanian", "estonian"]
1565
+ },
1566
+ {
1567
+ lang: "estonian",
1568
+ match: ["est", "et", "estonia"],
1569
+ suggest: ["finnish", "latvian"]
1570
+ },
1571
+ // Celtic Languages
1572
+ {
1573
+ lang: "irish",
1574
+ match: ["gle", "ga", "ireland", "gaelic"],
1575
+ suggest: ["scottish", "welsh"]
1576
+ },
1577
+ {
1578
+ lang: "welsh",
1579
+ match: ["cym", "cy", "wales", "cymru"],
1580
+ suggest: ["irish", "cornish"]
1581
+ },
1582
+ {
1583
+ lang: "scottish",
1584
+ match: ["gla", "gd", "scotland", "scots gaelic"],
1585
+ suggest: ["irish", "english"]
1586
+ },
1587
+ // Additional Languages
1588
+ {
1589
+ lang: "esperanto",
1590
+ match: ["epo", "eo", "esperanto"],
1591
+ suggest: []
1592
+ },
1593
+ {
1594
+ lang: "latin",
1595
+ match: ["lat", "la", "latin"],
1596
+ suggest: ["italian", "spanish", "french"]
1597
+ }
1598
+ ];
1599
+
1600
+ // src/language-aliases/asian.ts
1601
+ var ASIAN_LANGUAGES = [
1602
+ // Asian Languages
1603
+ {
1604
+ lang: "chinese",
1605
+ match: [
1606
+ "chi",
1607
+ "zh",
1608
+ "zho",
1609
+ "zh-cn",
1610
+ "cn",
1611
+ "china",
1612
+ "mandarin",
1613
+ "zhongwen",
1614
+ "simplified",
1615
+ "traditional"
1616
+ ],
1617
+ suggest: ["cantonese", "taiwanese", "hakka"]
1618
+ },
1619
+ {
1620
+ lang: "japanese",
1621
+ match: ["jpn", "ja", "jp", "japan", "nihongo"],
1622
+ suggest: ["okinawan"]
1623
+ },
1624
+ {
1625
+ lang: "korean",
1626
+ match: ["kor", "ko", "kr", "korea", "hangul", "south korea", "north korea"],
1627
+ suggest: ["jeju"]
1628
+ },
1629
+ {
1630
+ lang: "hindi",
1631
+ match: ["hin", "hi", "india", "indian", "devanagari"],
1632
+ suggest: ["urdu", "punjabi", "gujarati", "marathi", "bengali"]
1633
+ },
1634
+ {
1635
+ lang: "arabic",
1636
+ match: ["ara", "ar", "arab", "saudi", "egypt", "egyptian", "gulf", "levantine", "maghreb"],
1637
+ suggest: ["persian", "hebrew", "urdu"]
1638
+ },
1639
+ {
1640
+ lang: "thai",
1641
+ match: ["tha", "th", "thailand", "siam"],
1642
+ suggest: ["lao", "khmer"]
1643
+ },
1644
+ {
1645
+ lang: "vietnamese",
1646
+ match: ["vie", "vi", "vietnam"],
1647
+ suggest: ["khmer", "lao"]
1648
+ },
1649
+ {
1650
+ lang: "indonesian",
1651
+ match: ["ind", "id", "indonesia", "bahasa"],
1652
+ suggest: ["malay", "javanese", "sundanese"]
1653
+ },
1654
+ {
1655
+ lang: "malay",
1656
+ match: ["msa", "ms", "malaysia", "brunei"],
1657
+ suggest: ["indonesian"]
1658
+ },
1659
+ // Central Asian & Turkic Languages
1660
+ {
1661
+ lang: "kazakh",
1662
+ match: ["kaz", "kk", "kazakh", "kazakhstan"],
1663
+ suggest: ["russian", "kyrgyz", "uzbek"]
1664
+ },
1665
+ {
1666
+ lang: "turkish",
1667
+ match: ["tur", "tr", "turkey"],
1668
+ suggest: ["kurdish", "azerbaijani"]
1669
+ },
1670
+ {
1671
+ lang: "uzbek",
1672
+ match: ["uzb", "uz", "uzbekistan"],
1673
+ suggest: ["tajik", "kazakh", "kyrgyz"]
1674
+ },
1675
+ {
1676
+ lang: "kyrgyz",
1677
+ match: ["kir", "ky", "kyrgyzstan"],
1678
+ suggest: ["kazakh", "uzbek"]
1679
+ },
1680
+ {
1681
+ lang: "tajik",
1682
+ match: ["tgk", "tg", "tajikistan"],
1683
+ suggest: ["persian", "uzbek"]
1684
+ },
1685
+ {
1686
+ lang: "azerbaijani",
1687
+ match: ["aze", "az", "azerbaijan"],
1688
+ suggest: ["turkish", "persian"]
1689
+ },
1690
+ // Middle Eastern Languages
1691
+ {
1692
+ lang: "persian",
1693
+ match: ["fas", "fa", "per", "iran", "farsi", "dari", "afghanistan"],
1694
+ suggest: ["tajik", "kurdish", "pashto"]
1695
+ },
1696
+ {
1697
+ lang: "hebrew",
1698
+ match: ["heb", "he", "israel", "israeli"],
1699
+ suggest: ["arabic", "yiddish"]
1700
+ },
1701
+ {
1702
+ lang: "kurdish",
1703
+ match: ["kur", "ku", "kurdistan", "kurmanji", "sorani"],
1704
+ suggest: ["turkish", "persian", "arabic"]
1705
+ },
1706
+ // South Asian Languages
1707
+ {
1708
+ lang: "urdu",
1709
+ match: ["urd", "ur", "pakistan", "pakistani"],
1710
+ suggest: ["hindi", "punjabi"]
1711
+ },
1712
+ {
1713
+ lang: "bengali",
1714
+ match: ["ben", "bn", "bangladesh", "bengal"],
1715
+ suggest: ["hindi", "assamese"]
1716
+ },
1717
+ {
1718
+ lang: "punjabi",
1719
+ match: ["pan", "pa", "punjab"],
1720
+ suggest: ["hindi", "urdu"]
1721
+ },
1722
+ {
1723
+ lang: "gujarati",
1724
+ match: ["guj", "gu", "gujarat"],
1725
+ suggest: ["hindi", "marathi"]
1726
+ },
1727
+ {
1728
+ lang: "marathi",
1729
+ match: ["mar", "mr", "maharashtra"],
1730
+ suggest: ["hindi", "gujarati"]
1731
+ },
1732
+ {
1733
+ lang: "tamil",
1734
+ match: ["tam", "ta", "tamil nadu", "sri lanka"],
1735
+ suggest: ["malayalam", "telugu", "kannada"]
1736
+ },
1737
+ {
1738
+ lang: "telugu",
1739
+ match: ["tel", "te", "andhra pradesh"],
1740
+ suggest: ["tamil", "kannada"]
1741
+ },
1742
+ {
1743
+ lang: "kannada",
1744
+ match: ["kan", "kn", "karnataka"],
1745
+ suggest: ["tamil", "telugu", "malayalam"]
1746
+ },
1747
+ {
1748
+ lang: "malayalam",
1749
+ match: ["mal", "ml", "kerala"],
1750
+ suggest: ["tamil", "kannada"]
1751
+ },
1752
+ {
1753
+ lang: "nepali",
1754
+ match: ["nep", "ne", "nepal"],
1755
+ suggest: ["hindi"]
1756
+ },
1757
+ {
1758
+ lang: "sinhala",
1759
+ match: ["sin", "si", "sri lanka", "ceylon"],
1760
+ suggest: ["tamil"]
1761
+ },
1762
+ // Southeast Asian Languages
1763
+ {
1764
+ lang: "burmese",
1765
+ match: ["mya", "my", "myanmar", "burma"],
1766
+ suggest: ["thai"]
1767
+ },
1768
+ {
1769
+ lang: "khmer",
1770
+ match: ["khm", "km", "cambodia", "cambodian"],
1771
+ suggest: ["vietnamese", "thai"]
1772
+ },
1773
+ {
1774
+ lang: "lao",
1775
+ match: ["lao", "lo", "laos"],
1776
+ suggest: ["thai", "vietnamese"]
1777
+ },
1778
+ {
1779
+ lang: "tagalog",
1780
+ match: ["tgl", "tl", "philippines", "filipino"],
1781
+ suggest: ["cebuano", "ilocano"]
1782
+ }
1783
+ ];
1784
+
1785
+ // src/language-aliases/african.ts
1786
+ var AFRICAN_LANGUAGES = [
1787
+ // African Languages
1788
+ {
1789
+ lang: "swahili",
1790
+ match: ["swa", "sw", "kiswahili", "tanzania", "kenya"],
1791
+ suggest: ["arabic"]
1792
+ },
1793
+ {
1794
+ lang: "amharic",
1795
+ match: ["amh", "am", "ethiopia", "ethiopian"],
1796
+ suggest: ["tigrinya", "oromo"]
1797
+ },
1798
+ {
1799
+ lang: "yoruba",
1800
+ match: ["yor", "yo", "nigeria", "benin"],
1801
+ suggest: ["igbo", "hausa"]
1802
+ },
1803
+ {
1804
+ lang: "zulu",
1805
+ match: ["zul", "zu", "south africa"],
1806
+ suggest: ["xhosa", "afrikaans"]
1807
+ }
1808
+ ];
1809
+
1810
+ // src/language-aliases/index.ts
1811
+ var LANGUAGE_ALIAS_TABLE = [
1812
+ ...EUROPEAN_LANGUAGES,
1813
+ ...ASIAN_LANGUAGES,
1814
+ ...AFRICAN_LANGUAGES
1815
+ ];
1816
+
1817
+ // src/search-utils.ts
1818
+ function applyLanguageAlias(term = "") {
1819
+ const s = term.toLowerCase().trim();
1820
+ if (!s) return { primary: term, suggestions: [] };
1821
+ const isMatch = (alias, input) => {
1822
+ if (input === alias) return true;
1823
+ if (alias.length >= 3 && input.length >= alias.length && input.startsWith(alias)) return true;
1824
+ if (input.length >= 2 && alias.startsWith(input)) return true;
1825
+ return false;
1826
+ };
1827
+ const hits = /* @__PURE__ */ new Set();
1828
+ const suggestions = /* @__PURE__ */ new Set();
1829
+ for (const { lang, match, suggest } of LANGUAGE_ALIAS_TABLE) {
1830
+ for (const m of match) {
1831
+ if (isMatch(m, s)) {
1832
+ hits.add(lang);
1833
+ if (suggest) {
1834
+ suggest.forEach((sug) => suggestions.add(sug));
1835
+ }
1836
+ }
1837
+ }
1838
+ }
1839
+ let primary;
1840
+ if (hits.size === 0) {
1841
+ primary = term;
1842
+ } else if (hits.size === 1) {
1843
+ primary = Array.from(hits)[0];
1844
+ } else {
1845
+ primary = Array.from(hits);
1846
+ }
1847
+ return { primary, suggestions: Array.from(suggestions) };
1848
+ }
1849
+
1850
+ // src/constants/colors.ts
1851
+ var COLORS = {
1852
+ // Primary colors
1853
+ primary: {
1854
+ blue: "#3b82f6",
1855
+ blueLight: "#60a5fa",
1856
+ blueDark: "#2563eb",
1857
+ blueAlpha30: "#3b82f630",
1858
+ blueAlpha50: "#3b82f650"
1859
+ },
1860
+ // Neutral colors
1861
+ neutral: {
1862
+ white: "#fff",
1863
+ gray50: "#f9fafb",
1864
+ gray100: "#f3f4f6",
1865
+ gray200: "#e5e7eb",
1866
+ gray300: "#d1d5db",
1867
+ gray400: "#9ca3af",
1868
+ gray500: "#6b7280",
1869
+ gray600: "#4b5563",
1870
+ gray700: "#374151",
1871
+ gray800: "#1f2937",
1872
+ gray900: "#111827"
1873
+ },
1874
+ // Border colors
1875
+ border: {
1876
+ light: "#d1d5db",
1877
+ dark: "#4b5563",
1878
+ flag: "#eee"
1879
+ },
1880
+ // Text colors
1881
+ text: {
1882
+ primary: "#1f2937",
1883
+ secondary: "#6b7280",
1884
+ placeholder: "#9ca3af",
1885
+ inverse: "#f9fafb"
1886
+ }
1887
+ };
1888
+ var THEME_COLORS = {
1889
+ light: {
1890
+ background: COLORS.neutral.white,
1891
+ backgroundDisabled: COLORS.neutral.gray100,
1892
+ border: COLORS.border.light,
1893
+ placeholder: COLORS.text.placeholder,
1894
+ ring: COLORS.primary.blueAlpha30,
1895
+ optionPointed: COLORS.neutral.gray100,
1896
+ optionPointedText: COLORS.text.primary,
1897
+ optionSelected: COLORS.primary.blue,
1898
+ optionSelectedText: COLORS.neutral.white,
1899
+ dropdownBackground: COLORS.neutral.white,
1900
+ dropdownBorder: COLORS.border.light,
1901
+ dropdownText: COLORS.text.primary,
1902
+ tagBackground: COLORS.primary.blue
1903
+ },
1904
+ dark: {
1905
+ background: COLORS.neutral.gray800,
1906
+ backgroundDisabled: COLORS.neutral.gray700,
1907
+ border: COLORS.border.dark,
1908
+ placeholder: COLORS.text.placeholder,
1909
+ ring: COLORS.primary.blueAlpha50,
1910
+ optionPointed: COLORS.neutral.gray700,
1911
+ optionPointedText: COLORS.neutral.gray50,
1912
+ optionSelected: COLORS.primary.blue,
1913
+ optionSelectedText: COLORS.neutral.white,
1914
+ dropdownBackground: COLORS.neutral.gray800,
1915
+ dropdownBorder: COLORS.border.dark,
1916
+ dropdownText: COLORS.neutral.gray50,
1917
+ tagBackground: COLORS.primary.blue
1918
+ }
1919
+ };
1920
+ var CSS_VARS = {
1921
+ // Multiselect variables
1922
+ multiselect: {
1923
+ bg: "--ms-bg",
1924
+ bgDisabled: "--ms-bg-disabled",
1925
+ borderColor: "--ms-border-color",
1926
+ placeholderColor: "--ms-placeholder-color",
1927
+ ringColor: "--ms-ring-color",
1928
+ optionBgPointed: "--ms-option-bg-pointed",
1929
+ optionColorPointed: "--ms-option-color-pointed",
1930
+ optionBgSelected: "--ms-option-bg-selected",
1931
+ optionColorSelected: "--ms-option-color-selected",
1932
+ dropdownBg: "--ms-dropdown-bg",
1933
+ dropdownBorderColor: "--ms-dropdown-border-color",
1934
+ dropdownColor: "--ms-dropdown-color",
1935
+ tagBg: "--ms-tag-bg"
1936
+ }
1937
+ };
1938
+
1939
+ // vue-script:/Users/nlit/projects/langie-sdk/src/components/LanguageSelect.vue?type=script
1940
+ var _hoisted_1 = {
1941
+ key: 0,
1942
+ class: "multiselect-single-label"
1943
+ };
1944
+ var _hoisted_2 = ["src", "alt"];
1945
+ var _hoisted_3 = { class: "language-text" };
1946
+ var _hoisted_4 = { class: "native-name" };
1947
+ var _hoisted_5 = ["data-lang-code"];
1948
+ var _hoisted_6 = ["src", "alt"];
1949
+ var _hoisted_7 = { class: "language-text" };
1950
+ var _hoisted_8 = { class: "native-name" };
1951
+ var _hoisted_9 = { class: "multiselect-no-options" };
1952
+ var LanguageSelect_default = /* @__PURE__ */ (0, import_vue3.defineComponent)({
1953
+ __name: "LanguageSelect",
1954
+ props: {
1955
+ modelValue: {
1956
+ type: Object,
1957
+ default: void 0
1958
+ },
1959
+ languages: {
1960
+ type: Array,
1961
+ default: () => []
1962
+ },
1963
+ placeholder: {
1964
+ type: String,
1965
+ default: "Select language"
1966
+ },
1967
+ disabled: {
1968
+ type: Boolean,
1969
+ default: false
1970
+ },
1971
+ isDark: {
1972
+ type: Boolean,
1973
+ default: false
1974
+ }
1975
+ },
1976
+ emits: ["update:modelValue"],
1977
+ setup(__props, { emit: __emit }) {
1978
+ (0, import_vue3.useCssVars)((_ctx) => ({
1979
+ "25bc3fde-THEME_COLORS.light.background": (0, import_vue4.unref)(THEME_COLORS).light.background,
1980
+ "25bc3fde-THEME_COLORS.light.backgroundDisabled": (0, import_vue4.unref)(THEME_COLORS).light.backgroundDisabled,
1981
+ "25bc3fde-THEME_COLORS.light.border": (0, import_vue4.unref)(THEME_COLORS).light.border,
1982
+ "25bc3fde-THEME_COLORS.light.ring": (0, import_vue4.unref)(THEME_COLORS).light.ring,
1983
+ "25bc3fde-THEME_COLORS.light.placeholder": (0, import_vue4.unref)(THEME_COLORS).light.placeholder,
1984
+ "25bc3fde-THEME_COLORS.light.optionPointed": (0, import_vue4.unref)(THEME_COLORS).light.optionPointed,
1985
+ "25bc3fde-THEME_COLORS.light.optionPointedText": (0, import_vue4.unref)(THEME_COLORS).light.optionPointedText,
1986
+ "25bc3fde-THEME_COLORS.light.optionSelected": (0, import_vue4.unref)(THEME_COLORS).light.optionSelected,
1987
+ "25bc3fde-THEME_COLORS.light.optionSelectedText": (0, import_vue4.unref)(THEME_COLORS).light.optionSelectedText,
1988
+ "25bc3fde-THEME_COLORS.light.dropdownBackground": (0, import_vue4.unref)(THEME_COLORS).light.dropdownBackground,
1989
+ "25bc3fde-THEME_COLORS.light.dropdownBorder": (0, import_vue4.unref)(THEME_COLORS).light.dropdownBorder,
1990
+ "25bc3fde-THEME_COLORS.light.dropdownText": (0, import_vue4.unref)(THEME_COLORS).light.dropdownText,
1991
+ "25bc3fde-THEME_COLORS.light.tagBackground": (0, import_vue4.unref)(THEME_COLORS).light.tagBackground,
1992
+ "25bc3fde-THEME_COLORS.dark.background": (0, import_vue4.unref)(THEME_COLORS).dark.background,
1993
+ "25bc3fde-THEME_COLORS.dark.backgroundDisabled": (0, import_vue4.unref)(THEME_COLORS).dark.backgroundDisabled,
1994
+ "25bc3fde-THEME_COLORS.dark.border": (0, import_vue4.unref)(THEME_COLORS).dark.border,
1995
+ "25bc3fde-THEME_COLORS.dark.placeholder": (0, import_vue4.unref)(THEME_COLORS).dark.placeholder,
1996
+ "25bc3fde-THEME_COLORS.dark.ring": (0, import_vue4.unref)(THEME_COLORS).dark.ring,
1997
+ "25bc3fde-THEME_COLORS.dark.optionPointed": (0, import_vue4.unref)(THEME_COLORS).dark.optionPointed,
1998
+ "25bc3fde-THEME_COLORS.dark.optionPointedText": (0, import_vue4.unref)(THEME_COLORS).dark.optionPointedText,
1999
+ "25bc3fde-THEME_COLORS.dark.optionSelected": (0, import_vue4.unref)(THEME_COLORS).dark.optionSelected,
2000
+ "25bc3fde-THEME_COLORS.dark.optionSelectedText": (0, import_vue4.unref)(THEME_COLORS).dark.optionSelectedText,
2001
+ "25bc3fde-THEME_COLORS.dark.dropdownBackground": (0, import_vue4.unref)(THEME_COLORS).dark.dropdownBackground,
2002
+ "25bc3fde-THEME_COLORS.dark.dropdownBorder": (0, import_vue4.unref)(THEME_COLORS).dark.dropdownBorder,
2003
+ "25bc3fde-THEME_COLORS.dark.dropdownText": (0, import_vue4.unref)(THEME_COLORS).dark.dropdownText,
2004
+ "25bc3fde-COLORS.border.flag": (0, import_vue4.unref)(COLORS).border.flag,
2005
+ "25bc3fde-COLORS.border.dark": (0, import_vue4.unref)(COLORS).border.dark,
2006
+ "25bc3fde-COLORS.text.secondary": (0, import_vue4.unref)(COLORS).text.secondary,
2007
+ "25bc3fde-COLORS.neutral.gray400": (0, import_vue4.unref)(COLORS).neutral.gray400
2008
+ }));
2009
+ const getFlagCode = (lang) => {
2010
+ const flagCode = lang.flag_country || lang.code;
2011
+ return flagCode;
2012
+ };
2013
+ const getFlagImageUrl = (lang) => {
2014
+ const flagCode = getFlagCode(lang);
2015
+ return `/flags/${flagCode}.svg`;
2016
+ };
2017
+ const props = __props;
2018
+ const emit = __emit;
2019
+ const isLoading = (0, import_vue5.computed)(() => {
2020
+ return props.languages.length <= 0;
2021
+ });
2022
+ const searchQuery = (0, import_vue5.ref)("");
2023
+ const validLanguages = (0, import_vue5.computed)(() => {
2024
+ return props.languages.filter((lang) => lang && lang.code && lang.name && lang.native_name);
2025
+ });
2026
+ const fuse = (0, import_vue5.computed)(() => {
2027
+ if (!validLanguages.value.length) return null;
2028
+ return new import_fuse.default(validLanguages.value, {
2029
+ keys: ["name", "native_name", "code"],
2030
+ includeScore: true,
2031
+ threshold: 0.6,
2032
+ // Use highest threshold to catch all cases
2033
+ isCaseSensitive: false,
2034
+ minMatchCharLength: 1
2035
+ // Allow single character matches
2036
+ });
2037
+ });
2038
+ const multiselectKey = (0, import_vue5.computed)(() => {
2039
+ const hasApiData = props.languages.length > 0 && props.languages[0].flag_country !== null;
2040
+ return hasApiData ? "api-data" : "fallback-data";
2041
+ });
2042
+ const selectedLanguageKey = (0, import_vue5.computed)(() => {
2043
+ if (!props.modelValue || !props.modelValue.code) return "no-selection";
2044
+ const key = `${props.modelValue.code}-${props.modelValue.flag_country || "fallback"}`;
2045
+ return key;
2046
+ });
2047
+ const selectedLanguage = (0, import_vue5.computed)({
2048
+ get: () => props.modelValue || null,
2049
+ set: (value) => {
2050
+ if (value && value.code) {
2051
+ emit("update:modelValue", value);
2052
+ }
2053
+ }
2054
+ });
2055
+ const filteredLanguages = (0, import_vue5.computed)(() => {
2056
+ const query = searchQuery.value.trim();
2057
+ let results;
2058
+ if (!query) {
2059
+ results = validLanguages.value;
2060
+ } else {
2061
+ if (!fuse.value) return [];
2062
+ const aliasResult = applyLanguageAlias(query);
2063
+ const searchTerm = Array.isArray(aliasResult.primary) ? aliasResult.primary[0] : aliasResult.primary;
2064
+ const fuseResults = fuse.value.search(searchTerm);
2065
+ results = fuseResults.map((result) => result.item);
2066
+ if (searchTerm !== query) {
2067
+ const originalResults = fuse.value.search(query);
2068
+ originalResults.forEach((result) => {
2069
+ if (!results.some((r) => r.code === result.item.code)) {
2070
+ results.push(result.item);
2071
+ }
2072
+ });
2073
+ }
2074
+ if (aliasResult.suggestions.length > 0) {
2075
+ aliasResult.suggestions.forEach((suggestion) => {
2076
+ const suggestedLang = validLanguages.value.find((lang) => {
2077
+ const langName = lang.name.toLowerCase();
2078
+ const suggestion_lower = suggestion.toLowerCase();
2079
+ return langName === suggestion_lower || // Exact match
2080
+ langName.includes(suggestion_lower) || // Contains match
2081
+ lang.code.toLowerCase() === suggestion_lower || // Code match
2082
+ langName.startsWith(suggestion_lower) || // Starts with match
2083
+ // Handle common variations
2084
+ suggestion_lower === "tatar" && langName.includes("tatar") || suggestion_lower === "belarusian" && (langName.includes("belarus") || langName.includes("belarusian")) || suggestion_lower === "moldovan" && (langName.includes("moldov") || langName.includes("moldova"));
2085
+ });
2086
+ if (suggestedLang && !results.some((r) => r.code === suggestedLang.code)) {
2087
+ results.push(suggestedLang);
2088
+ }
2089
+ });
2090
+ }
2091
+ if (query.length === 2) {
2092
+ const lowerQuery = query.toLowerCase();
2093
+ const manualResults = validLanguages.value.filter(
2094
+ (lang) => lang.name.toLowerCase().startsWith(lowerQuery) || lang.native_name.toLowerCase().startsWith(lowerQuery)
2095
+ );
2096
+ manualResults.forEach((lang) => {
2097
+ if (!results.some((r) => r.code === lang.code)) {
2098
+ results.push(lang);
2099
+ }
2100
+ });
2101
+ }
2102
+ }
2103
+ const filtered = results.filter(
2104
+ (lang) => !props.modelValue || !props.modelValue.code || lang.code !== props.modelValue.code
2105
+ );
2106
+ return filtered;
2107
+ });
2108
+ function handleSearch(query) {
2109
+ searchQuery.value = query;
2110
+ if (query.trim()) {
2111
+ (0, import_vue5.nextTick)(() => {
2112
+ const dropdown = document.querySelector(".multiselect-dropdown");
2113
+ const firstOption = dropdown?.querySelector(".multiselect-option");
2114
+ if (firstOption) {
2115
+ firstOption.scrollIntoView({ behavior: "smooth", block: "nearest" });
2116
+ firstOption.classList.add("multiselect-option-is-pointed");
2117
+ }
2118
+ });
2119
+ }
2120
+ }
2121
+ function handleKeydown(event) {
2122
+ const keyboardEvent = event;
2123
+ if (keyboardEvent.key === "Tab" || keyboardEvent.key === "Enter") {
2124
+ const dropdown = document.querySelector(".multiselect-dropdown");
2125
+ const firstOption = dropdown?.querySelector(".multiselect-option");
2126
+ if (firstOption && searchQuery.value.trim()) {
2127
+ const langCode = firstOption.getAttribute("data-lang-code");
2128
+ if (langCode) {
2129
+ const language = validLanguages.value.find((lang) => lang.code === langCode);
2130
+ if (language) {
2131
+ selectedLanguage.value = language;
2132
+ searchQuery.value = "";
2133
+ keyboardEvent.preventDefault();
2134
+ }
2135
+ }
2136
+ }
2137
+ }
2138
+ }
2139
+ const onFlagError = (event) => {
2140
+ const target = event.target;
2141
+ const currentSrc = target.src;
2142
+ if (currentSrc && currentSrc.includes("/flags/")) {
2143
+ const match = currentSrc.match(/\/flags\/([a-z]{2})\.svg/);
2144
+ if (match) {
2145
+ const countryCode = match[1];
2146
+ target.src = `https://flagcdn.com/${countryCode}.svg`;
2147
+ target.onerror = () => {
2148
+ target.style.display = "none";
2149
+ };
2150
+ return;
2151
+ }
2152
+ }
2153
+ target.style.display = "none";
2154
+ };
2155
+ return (_ctx, _cache) => {
2156
+ return (0, import_vue4.openBlock)(), (0, import_vue4.createElementBlock)(
2157
+ "div",
2158
+ {
2159
+ class: (0, import_vue4.normalizeClass)(["language-select", { "is-dark": __props.isDark }])
2160
+ },
2161
+ [
2162
+ (0, import_vue4.createCommentVNode)(" Show multiselect when we have languages OR when not loading "),
2163
+ validLanguages.value.length > 0 || !isLoading.value ? ((0, import_vue4.openBlock)(), (0, import_vue4.createBlock)((0, import_vue4.unref)(import_multiselect.default), {
2164
+ key: multiselectKey.value,
2165
+ modelValue: selectedLanguage.value,
2166
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => selectedLanguage.value = $event),
2167
+ options: filteredLanguages.value,
2168
+ searchable: true,
2169
+ onSearchChange: handleSearch,
2170
+ "can-clear": false,
2171
+ "allow-empty": false,
2172
+ object: true,
2173
+ placeholder: validLanguages.value.length === 0 ? "No languages available" : __props.placeholder,
2174
+ disabled: props.disabled || validLanguages.value.length === 0,
2175
+ loading: isLoading.value,
2176
+ "track-by": "name",
2177
+ label: "name",
2178
+ "value-prop": "code",
2179
+ "filter-results": false,
2180
+ onKeydown: handleKeydown
2181
+ }, {
2182
+ singlelabel: (0, import_vue4.withCtx)(({ value }) => [
2183
+ value ? ((0, import_vue4.openBlock)(), (0, import_vue4.createElementBlock)("div", _hoisted_1, [
2184
+ value.code ? ((0, import_vue4.openBlock)(), (0, import_vue4.createElementBlock)("img", {
2185
+ key: selectedLanguageKey.value,
2186
+ src: getFlagImageUrl(value),
2187
+ class: "lang-flag",
2188
+ alt: `${value.native_name || value.name} flag`,
2189
+ onError: onFlagError
2190
+ }, null, 40, _hoisted_2)) : (0, import_vue4.createCommentVNode)("v-if", true),
2191
+ (0, import_vue4.createElementVNode)("span", _hoisted_3, [
2192
+ (0, import_vue4.createTextVNode)(
2193
+ (0, import_vue4.toDisplayString)(value.name) + " ",
2194
+ 1
2195
+ /* TEXT */
2196
+ ),
2197
+ (0, import_vue4.createElementVNode)(
2198
+ "span",
2199
+ _hoisted_4,
2200
+ "(" + (0, import_vue4.toDisplayString)(value.native_name || value.name) + ")",
2201
+ 1
2202
+ /* TEXT */
2203
+ )
2204
+ ])
2205
+ ])) : (0, import_vue4.createCommentVNode)("v-if", true)
2206
+ ]),
2207
+ option: (0, import_vue4.withCtx)(({ option }) => [
2208
+ (0, import_vue4.createElementVNode)("div", {
2209
+ class: "multiselect-option",
2210
+ "data-lang-code": option.code
2211
+ }, [
2212
+ ((0, import_vue4.openBlock)(), (0, import_vue4.createElementBlock)("img", {
2213
+ key: `${option.code}-${option.flag_country || "fallback"}`,
2214
+ src: getFlagImageUrl(option),
2215
+ class: "lang-flag",
2216
+ alt: `${option.name} flag`,
2217
+ onError: onFlagError
2218
+ }, null, 40, _hoisted_6)),
2219
+ (0, import_vue4.createElementVNode)("span", _hoisted_7, [
2220
+ (0, import_vue4.createTextVNode)(
2221
+ (0, import_vue4.toDisplayString)(option.name) + " ",
2222
+ 1
2223
+ /* TEXT */
2224
+ ),
2225
+ (0, import_vue4.createElementVNode)(
2226
+ "span",
2227
+ _hoisted_8,
2228
+ "(" + (0, import_vue4.toDisplayString)(option.native_name || option.name) + ")",
2229
+ 1
2230
+ /* TEXT */
2231
+ )
2232
+ ])
2233
+ ], 8, _hoisted_5)
2234
+ ]),
2235
+ noresults: (0, import_vue4.withCtx)(() => _cache[1] || (_cache[1] = [
2236
+ (0, import_vue4.createElementVNode)(
2237
+ "div",
2238
+ { class: "multiselect-no-results" },
2239
+ "No languages found.",
2240
+ -1
2241
+ /* CACHED */
2242
+ )
2243
+ ])),
2244
+ nooptions: (0, import_vue4.withCtx)(() => [
2245
+ (0, import_vue4.createElementVNode)(
2246
+ "div",
2247
+ _hoisted_9,
2248
+ (0, import_vue4.toDisplayString)(validLanguages.value.length === 0 ? "Please provide languages via the :languages prop" : "No languages available."),
2249
+ 1
2250
+ /* TEXT */
2251
+ )
2252
+ ]),
2253
+ _: 1
2254
+ /* STABLE */
2255
+ }, 8, ["modelValue", "options", "placeholder", "disabled", "loading"])) : isLoading.value && validLanguages.value.length === 0 ? ((0, import_vue4.openBlock)(), (0, import_vue4.createElementBlock)(
2256
+ import_vue4.Fragment,
2257
+ { key: 1 },
2258
+ [
2259
+ (0, import_vue4.createCommentVNode)(" Only show skeleton loader when actually loading AND we have no languages yet "),
2260
+ _cache[2] || (_cache[2] = (0, import_vue4.createElementVNode)(
2261
+ "div",
2262
+ { class: "skeleton-loader" },
2263
+ null,
2264
+ -1
2265
+ /* CACHED */
2266
+ ))
2267
+ ],
2268
+ 2112
2269
+ /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
2270
+ )) : (0, import_vue4.createCommentVNode)("v-if", true)
2271
+ ],
2272
+ 2
2273
+ /* CLASS */
2274
+ );
2275
+ };
2276
+ }
2277
+ });
2278
+
2279
+ // src/components/LanguageSelect.vue
2280
+ var LanguageSelect_default2 = LanguageSelect_default;
2281
+ LanguageSelect_default.__scopeId = "data-v-25bc3fde";
2282
+
2283
+ // vue-script:/Users/nlit/projects/langie-sdk/src/components/InterfaceLanguageSelect.vue?type=script
2284
+ var import_vue6 = require("vue");
2285
+ var import_vue7 = require("vue");
2286
+ var import_vue8 = require("vue");
2287
+ var _hoisted_12 = { class: "interface-language-select-wrapper" };
2288
+ var _hoisted_22 = { class: "loader-text" };
2289
+ var InterfaceLanguageSelect_default = /* @__PURE__ */ (0, import_vue6.defineComponent)({
2290
+ __name: "InterfaceLanguageSelect",
2291
+ props: {
2292
+ placeholder: {
2293
+ type: String,
2294
+ default: "Select interface language"
2295
+ },
2296
+ disabled: {
2297
+ type: Boolean,
2298
+ default: false
2299
+ },
2300
+ isDark: {
2301
+ type: Boolean,
2302
+ default: false
2303
+ },
2304
+ translatorHost: {
2305
+ type: String,
2306
+ default: ""
2307
+ },
2308
+ apiKey: {
2309
+ type: String,
2310
+ default: ""
2311
+ },
2312
+ languages: {
2313
+ type: Array,
2314
+ default: () => []
2315
+ }
2316
+ },
2317
+ emits: ["update:modelValue"],
2318
+ setup(__props, { emit: __emit }) {
2319
+ const isChangingLanguage = (0, import_vue8.ref)(false);
2320
+ const props = __props;
2321
+ const emit = __emit;
2322
+ const { availableLanguages: availableLanguages2, currentLanguage: currentLanguage2, setLanguage, fetchLanguages, lr } = useLangie();
2323
+ const effectiveLanguages = (0, import_vue8.computed)(() => {
2324
+ const languages = props.languages && props.languages.length > 0 ? props.languages : availableLanguages2.value;
2325
+ const processed = languages.map((lang) => ({
2326
+ ...lang,
2327
+ native_name: lang.native_name || lang.name,
2328
+ flag_country: lang.flag_country || lang.code
2329
+ }));
2330
+ return processed;
2331
+ });
2332
+ const currentLanguageObject = (0, import_vue8.computed)(() => {
2333
+ if (!currentLanguage2.value) return null;
2334
+ return effectiveLanguages.value.find((lang) => lang.code === currentLanguage2.value) || null;
2335
+ });
2336
+ function detectBrowserLanguage2(languages) {
2337
+ if (languages.length === 0) return null;
2338
+ const browserLanguages = navigator.languages || [navigator.language || "en"];
2339
+ for (const browserLang of browserLanguages) {
2340
+ const langCode = browserLang.toLowerCase().split("-")[0];
2341
+ const exactMatch = languages.find((lang) => lang.code.toLowerCase() === langCode);
2342
+ if (exactMatch) {
2343
+ return exactMatch.code;
2344
+ }
2345
+ }
2346
+ for (const browserLang of browserLanguages) {
2347
+ const fullLangCode = browserLang.toLowerCase();
2348
+ const localeMatch = languages.find((lang) => lang.code.toLowerCase() === fullLangCode);
2349
+ if (localeMatch) {
2350
+ return localeMatch.code;
2351
+ }
2352
+ }
2353
+ return null;
2354
+ }
2355
+ async function handleLanguageChange(selectedLanguage) {
2356
+ if (selectedLanguage) {
2357
+ isChangingLanguage.value = true;
2358
+ try {
2359
+ setLanguage(selectedLanguage.code);
2360
+ localStorage.setItem("interface_language", selectedLanguage.code);
2361
+ emit("update:modelValue", selectedLanguage);
2362
+ } finally {
2363
+ isChangingLanguage.value = false;
2364
+ }
2365
+ }
2366
+ }
2367
+ (0, import_vue8.watch)(currentLanguage2, (newLangCode) => {
2368
+ if (newLangCode) {
2369
+ localStorage.setItem("interface_language", newLangCode);
2370
+ }
2371
+ });
2372
+ (0, import_vue8.watch)(
2373
+ () => effectiveLanguages.value,
2374
+ (newLanguages) => {
2375
+ if (newLanguages.length > 0 && !currentLanguage2.value) {
2376
+ const savedLanguageCode = localStorage.getItem("interface_language");
2377
+ if (savedLanguageCode) {
2378
+ const savedLangExists = newLanguages.find((lang) => lang.code === savedLanguageCode);
2379
+ if (savedLangExists) {
2380
+ setLanguage(savedLanguageCode);
2381
+ return;
2382
+ }
2383
+ }
2384
+ const browserLang = detectBrowserLanguage2(newLanguages);
2385
+ if (browserLang) {
2386
+ setLanguage(browserLang);
2387
+ }
2388
+ }
2389
+ },
2390
+ { immediate: true }
2391
+ );
2392
+ (0, import_vue8.onMounted)(async () => {
2393
+ if (!props.languages || props.languages.length === 0) {
2394
+ const countryCode = await getCountryCode();
2395
+ await fetchLanguages({ country: countryCode || void 0 });
2396
+ }
2397
+ const savedLanguageCode = localStorage.getItem("interface_language");
2398
+ if (savedLanguageCode && savedLanguageCode !== currentLanguage2.value) {
2399
+ const currentLanguages = effectiveLanguages.value;
2400
+ const savedLangExists = currentLanguages.find((lang) => lang.code === savedLanguageCode);
2401
+ if (savedLangExists) {
2402
+ setLanguage(savedLanguageCode);
2403
+ } else if (currentLanguages.length > 0) {
2404
+ const browserLang = detectBrowserLanguage2(currentLanguages);
2405
+ if (browserLang) {
2406
+ setLanguage(browserLang);
2407
+ }
2408
+ }
2409
+ } else if (!currentLanguage2.value && effectiveLanguages.value.length > 0) {
2410
+ const browserLang = detectBrowserLanguage2(effectiveLanguages.value);
2411
+ if (browserLang) {
2412
+ setLanguage(browserLang);
2413
+ }
2414
+ }
2415
+ });
2416
+ (0, import_vue8.watch)(
2417
+ currentLanguageObject,
2418
+ (newValue) => {
2419
+ if (newValue) {
2420
+ emit("update:modelValue", newValue);
2421
+ }
2422
+ },
2423
+ { immediate: true }
2424
+ );
2425
+ return (_ctx, _cache) => {
2426
+ return (0, import_vue7.openBlock)(), (0, import_vue7.createElementBlock)("div", _hoisted_12, [
2427
+ ((0, import_vue7.openBlock)(), (0, import_vue7.createBlock)(LanguageSelect_default2, {
2428
+ key: `interface-lang-${effectiveLanguages.value.length}-${effectiveLanguages.value[0]?.code || "empty"}`,
2429
+ "model-value": currentLanguageObject.value,
2430
+ languages: effectiveLanguages.value,
2431
+ placeholder: props.placeholder,
2432
+ disabled: props.disabled || isChangingLanguage.value,
2433
+ "is-dark": props.isDark,
2434
+ "onUpdate:modelValue": handleLanguageChange
2435
+ }, null, 8, ["model-value", "languages", "placeholder", "disabled", "is-dark"])),
2436
+ (0, import_vue7.createCommentVNode)(" Loading overlay "),
2437
+ isChangingLanguage.value ? ((0, import_vue7.openBlock)(), (0, import_vue7.createElementBlock)(
2438
+ "div",
2439
+ {
2440
+ key: 0,
2441
+ class: (0, import_vue7.normalizeClass)(["language-change-loader", { "is-dark": props.isDark }])
2442
+ },
2443
+ [
2444
+ _cache[0] || (_cache[0] = (0, import_vue7.createElementVNode)(
2445
+ "div",
2446
+ { class: "loader-spinner" },
2447
+ null,
2448
+ -1
2449
+ /* CACHED */
2450
+ )),
2451
+ (0, import_vue7.createElementVNode)(
2452
+ "span",
2453
+ _hoisted_22,
2454
+ (0, import_vue7.toDisplayString)((0, import_vue7.unref)(lr)("Changing language...", "ui")),
2455
+ 1
2456
+ /* TEXT */
2457
+ )
2458
+ ],
2459
+ 2
2460
+ /* CLASS */
2461
+ )) : (0, import_vue7.createCommentVNode)("v-if", true)
2462
+ ]);
2463
+ };
2464
+ }
2465
+ });
2466
+
2467
+ // src/components/InterfaceLanguageSelect.vue
2468
+ var InterfaceLanguageSelect_default2 = InterfaceLanguageSelect_default;
2469
+ InterfaceLanguageSelect_default.__scopeId = "data-v-7192f8c0";
2470
+
2471
+ // vue-script:/Users/nlit/projects/langie-sdk/src/components/lt.vue?type=script
2472
+ var import_vue9 = require("vue");
2473
+ var import_vue10 = require("vue");
2474
+ var import_vue11 = require("vue");
2475
+ var import_vue12 = require("vue");
2476
+ var lt_default = /* @__PURE__ */ (0, import_vue9.defineComponent)({
2477
+ __name: "lt",
2478
+ props: {
2479
+ // Message key (optional, otherwise slot content is used)
2480
+ msg: {
2481
+ type: String,
2482
+ default: void 0
2483
+ },
2484
+ // Translation context shorthand
2485
+ ctx: {
2486
+ type: String,
2487
+ required: false,
2488
+ default: "ui"
2489
+ },
2490
+ // Original language shorthand
2491
+ orig: {
2492
+ type: String,
2493
+ required: false,
2494
+ default: void 0
2495
+ }
2496
+ },
2497
+ setup(__props) {
2498
+ const isNuxt = (0, import_vue11.computed)(() => {
2499
+ if (typeof window !== "undefined") {
2500
+ return !!window.__NUXT__;
2501
+ }
2502
+ if (typeof process !== "undefined") {
2503
+ return !!process.env.NUXT_SSR_BASE || !!process.env.NUXT_PUBLIC_BASE_URL;
2504
+ }
2505
+ return false;
2506
+ });
2507
+ const props = __props;
2508
+ const slots = (0, import_vue11.useSlots)();
2509
+ const { lr, currentLanguage: currentLanguage2, uiTranslations: uiTranslations2, translations: translations2, getLtDefaults: getLtDefaults2 } = useLangie();
2510
+ const keyStr = (0, import_vue11.computed)(() => {
2511
+ if (props.msg) return props.msg;
2512
+ const slotContent = slots.default ? slots.default().map((n) => n.children).join("") : "";
2513
+ return (slotContent || "").trim();
2514
+ });
2515
+ const forceUpdate = (0, import_vue12.ref)(0);
2516
+ (0, import_vue11.watch)(
2517
+ [uiTranslations2, translations2],
2518
+ () => {
2519
+ (0, import_vue12.nextTick)(() => {
2520
+ forceUpdate.value++;
2521
+ });
2522
+ },
2523
+ { deep: true }
2524
+ );
2525
+ const translated = (0, import_vue11.computed)(() => {
2526
+ if (isNuxt.value && typeof window === "undefined") {
2527
+ return keyStr.value;
2528
+ }
2529
+ const globalDefaults = getLtDefaults2();
2530
+ const effectiveCtx = props.ctx ?? globalDefaults.ctx;
2531
+ const effectiveOrig = props.orig ?? globalDefaults.orig;
2532
+ void currentLanguage2.value;
2533
+ void forceUpdate.value;
2534
+ const cacheKey = `${keyStr.value}|${effectiveCtx}`;
2535
+ const cache = effectiveCtx === "ui" ? uiTranslations2 : translations2;
2536
+ void cache[cacheKey];
2537
+ const result = lr(keyStr.value, effectiveCtx, effectiveOrig);
2538
+ return result;
2539
+ });
2540
+ return (_ctx, _cache) => {
2541
+ return (0, import_vue10.openBlock)(), (0, import_vue10.createBlock)(import_vue10.Transition, {
2542
+ name: "fade",
2543
+ mode: "out-in"
2544
+ }, {
2545
+ default: (0, import_vue10.withCtx)(() => [
2546
+ ((0, import_vue10.openBlock)(), (0, import_vue10.createElementBlock)(
2547
+ "span",
2548
+ { key: translated.value },
2549
+ (0, import_vue10.toDisplayString)(translated.value),
2550
+ 1
2551
+ /* TEXT */
2552
+ ))
2553
+ ]),
2554
+ _: 1
2555
+ /* STABLE */
2556
+ });
2557
+ };
2558
+ }
2559
+ });
2560
+
2561
+ // src/components/lt.vue
2562
+ var lt_default2 = lt_default;
2563
+ lt_default.__scopeId = "data-v-14a7b6f6";
2564
+
2565
+ // src/utils/theme.ts
2566
+ function setThemeColors() {
2567
+ const root = document.documentElement;
2568
+ root.style.setProperty("--langie-flag-border", COLORS.border.flag);
2569
+ root.style.setProperty("--langie-flag-border-dark", COLORS.border.dark);
2570
+ root.style.setProperty("--langie-text-secondary", COLORS.text.secondary);
2571
+ root.style.setProperty("--langie-text-secondary-dark", COLORS.neutral.gray400);
2572
+ root.style.setProperty("--langie-primary-blue", COLORS.primary.blue);
2573
+ root.style.setProperty("--langie-primary-blue-alpha-30", COLORS.primary.blueAlpha30);
2574
+ root.style.setProperty("--langie-primary-blue-alpha-50", COLORS.primary.blueAlpha50);
2575
+ }
2576
+ function clearThemeColors() {
2577
+ const root = document.documentElement;
2578
+ const properties = [
2579
+ "--langie-flag-border",
2580
+ "--langie-flag-border-dark",
2581
+ "--langie-text-secondary",
2582
+ "--langie-text-secondary-dark",
2583
+ "--langie-primary-blue",
2584
+ "--langie-primary-blue-alpha-30",
2585
+ "--langie-primary-blue-alpha-50"
2586
+ ];
2587
+ properties.forEach((prop) => root.style.removeProperty(prop));
2588
+ }
2589
+
2590
+ // src/utils/languageMapping.ts
2591
+ var BROWSER_LANGUAGE_MAP = {
2592
+ // Chinese variants
2593
+ "zh": "zh-cn",
2594
+ // Chinese (Simplified)
2595
+ // Serbian variants
2596
+ "sr": "sr-latn",
2597
+ // Serbian (default to Latin)
2598
+ "me": "sr-latn",
2599
+ // Montenegrin
2600
+ "sh": "sr-latn",
2601
+ // Serbo-Croatian
2602
+ // Kazakh variants
2603
+ "kaz": "kk",
2604
+ // Kazakh (browser 'kaz' or 'kk' → 'kk')
2605
+ "kk": "kk"
2606
+ };
2607
+ function detectBrowserLanguage() {
2608
+ if (typeof navigator === "undefined") {
2609
+ return "en";
2610
+ }
2611
+ const locale = navigator.languages?.[0] || navigator.language || "";
2612
+ const browserCode = locale.split("-")[0];
2613
+ const mappedLanguage = BROWSER_LANGUAGE_MAP[browserCode];
2614
+ if (mappedLanguage) {
2615
+ return mappedLanguage;
2616
+ }
2617
+ return browserCode || "en";
2618
+ }
2619
+
2620
+ // src/utils/regionMapping.ts
2621
+ var COUNTRY_TO_REGION = {
2622
+ // EU
2623
+ DE: "EU",
2624
+ AT: "EU",
2625
+ CH: "EU",
2626
+ NL: "EU",
2627
+ BE: "EU",
2628
+ LU: "EU",
2629
+ DK: "EU",
2630
+ SE: "EU",
2631
+ NO: "EU",
2632
+ IS: "EU",
2633
+ GB: "EU",
2634
+ IE: "EU",
2635
+ FR: "EU",
2636
+ IT: "EU",
2637
+ ES: "EU",
2638
+ PT: "EU",
2639
+ RO: "EU",
2640
+ MT: "EU",
2641
+ PL: "EU",
2642
+ CZ: "EU",
2643
+ SK: "EU",
2644
+ SI: "EU",
2645
+ HR: "EU",
2646
+ BA: "EU",
2647
+ RS: "EU",
2648
+ ME: "EU",
2649
+ MK: "EU",
2650
+ BG: "EU",
2651
+ RU: "EU",
2652
+ BY: "EU",
2653
+ UA: "EU",
2654
+ LT: "EU",
2655
+ LV: "EU",
2656
+ EE: "EU",
2657
+ FI: "EU",
2658
+ HU: "EU",
2659
+ GR: "EU",
2660
+ CY: "EU",
2661
+ AL: "EU",
2662
+ MD: "EU",
2663
+ LI: "EU",
2664
+ AD: "EU",
2665
+ SM: "EU",
2666
+ VA: "EU",
2667
+ MC: "EU",
2668
+ // NA
2669
+ US: "NA",
2670
+ CA: "NA",
2671
+ MX: "NA",
2672
+ GT: "NA",
2673
+ BZ: "NA",
2674
+ SV: "NA",
2675
+ HN: "NA",
2676
+ NI: "NA",
2677
+ CR: "NA",
2678
+ PA: "NA",
2679
+ HT: "NA",
2680
+ JM: "NA",
2681
+ CU: "NA",
2682
+ DO: "NA",
2683
+ TT: "NA",
2684
+ BB: "NA",
2685
+ BS: "NA",
2686
+ GD: "NA",
2687
+ LC: "NA",
2688
+ VC: "NA",
2689
+ AG: "NA",
2690
+ DM: "NA",
2691
+ KN: "NA",
2692
+ // SA
2693
+ AR: "SA",
2694
+ CL: "SA",
2695
+ PE: "SA",
2696
+ CO: "SA",
2697
+ VE: "SA",
2698
+ EC: "SA",
2699
+ BO: "SA",
2700
+ PY: "SA",
2701
+ UY: "SA",
2702
+ BR: "SA",
2703
+ GY: "SA",
2704
+ SR: "SA",
2705
+ GF: "SA",
2706
+ // EA
2707
+ CN: "EA",
2708
+ TW: "EA",
2709
+ HK: "EA",
2710
+ MO: "EA",
2711
+ SG: "EA",
2712
+ JP: "EA",
2713
+ KR: "EA",
2714
+ KP: "EA",
2715
+ MN: "EA",
2716
+ // SEA
2717
+ VN: "SEA",
2718
+ KH: "SEA",
2719
+ TH: "SEA",
2720
+ LA: "SEA",
2721
+ MM: "SEA",
2722
+ ID: "SEA",
2723
+ MY: "SEA",
2724
+ PH: "SEA",
2725
+ BN: "SEA",
2726
+ TL: "SEA",
2727
+ // SAS
2728
+ IN: "SAS",
2729
+ PK: "SAS",
2730
+ BD: "SAS",
2731
+ LK: "SAS",
2732
+ NP: "SAS",
2733
+ BT: "SAS",
2734
+ MV: "SAS",
2735
+ AF: "SAS",
2736
+ // CAS
2737
+ KZ: "CAS",
2738
+ KG: "CAS",
2739
+ UZ: "CAS",
2740
+ TM: "CAS",
2741
+ TR: "CAS",
2742
+ AZ: "CAS",
2743
+ TJ: "CAS",
2744
+ IR: "CAS",
2745
+ // ME
2746
+ SA: "ME",
2747
+ AE: "ME",
2748
+ QA: "ME",
2749
+ KW: "ME",
2750
+ BH: "ME",
2751
+ OM: "ME",
2752
+ YE: "ME",
2753
+ JO: "ME",
2754
+ LB: "ME",
2755
+ SY: "ME",
2756
+ IQ: "ME",
2757
+ PS: "ME",
2758
+ IL: "ME",
2759
+ GE: "ME",
2760
+ AM: "ME",
2761
+ // NAF
2762
+ EG: "NAF",
2763
+ LY: "NAF",
2764
+ TN: "NAF",
2765
+ DZ: "NAF",
2766
+ MA: "NAF",
2767
+ SD: "NAF",
2768
+ SS: "NAF",
2769
+ ET: "NAF",
2770
+ ER: "NAF",
2771
+ DJ: "NAF",
2772
+ SO: "NAF",
2773
+ // WAF
2774
+ NG: "WAF",
2775
+ GH: "WAF",
2776
+ CI: "WAF",
2777
+ BF: "WAF",
2778
+ ML: "WAF",
2779
+ SN: "WAF",
2780
+ GN: "WAF",
2781
+ SL: "WAF",
2782
+ LR: "WAF",
2783
+ GM: "WAF",
2784
+ GW: "WAF",
2785
+ NE: "WAF",
2786
+ TD: "WAF",
2787
+ CF: "WAF",
2788
+ CM: "WAF",
2789
+ MR: "WAF",
2790
+ CV: "WAF",
2791
+ // EAF
2792
+ KE: "EAF",
2793
+ TZ: "EAF",
2794
+ UG: "EAF",
2795
+ RW: "EAF",
2796
+ BI: "EAF",
2797
+ MZ: "EAF",
2798
+ MW: "EAF",
2799
+ ZM: "EAF",
2800
+ ZW: "EAF",
2801
+ MG: "EAF",
2802
+ MU: "EAF",
2803
+ KM: "EAF",
2804
+ SC: "EAF",
2805
+ // SAF
2806
+ ZA: "SAF",
2807
+ NA: "SAF",
2808
+ BW: "SAF",
2809
+ LS: "SAF",
2810
+ SZ: "SAF",
2811
+ AO: "SAF",
2812
+ // CAF
2813
+ CD: "CAF",
2814
+ CG: "CAF",
2815
+ GA: "CAF",
2816
+ GQ: "CAF",
2817
+ ST: "CAF",
2818
+ // OC
2819
+ AU: "OC",
2820
+ NZ: "OC",
2821
+ PG: "OC",
2822
+ FJ: "OC",
2823
+ SB: "OC",
2824
+ VU: "OC",
2825
+ NC: "OC",
2826
+ PF: "OC",
2827
+ WS: "OC",
2828
+ TO: "OC",
2829
+ TV: "OC",
2830
+ KI: "OC",
2831
+ NR: "OC",
2832
+ PW: "OC",
2833
+ MH: "OC",
2834
+ FM: "OC",
2835
+ // CAR
2836
+ PR: "CAR",
2837
+ GP: "CAR",
2838
+ MQ: "CAR",
2839
+ AW: "CAR",
2840
+ CW: "CAR"
2841
+ };
2842
+ function getRegionForCountry(country) {
2843
+ if (!country) return "";
2844
+ return COUNTRY_TO_REGION[country.toUpperCase()] || "";
2845
+ }
2846
+ function getGeoRequestParams(country, language, timezone) {
2847
+ const params = {};
2848
+ if (country) {
2849
+ params.country = country;
2850
+ const region = getRegionForCountry(country);
2851
+ if (region) {
2852
+ params.region = region;
2853
+ }
2854
+ }
2855
+ if (language) params.language = language;
2856
+ if (timezone) params.timezone = timezone;
2857
+ return params;
2858
+ }
2859
+ // Annotate the CommonJS export names for ESM import in node:
2860
+ 0 && (module.exports = {
2861
+ API_FIELD_CTX,
2862
+ API_FIELD_FROM,
2863
+ API_FIELD_TEXT,
2864
+ API_FIELD_TO,
2865
+ API_FIELD_TRANSLATED,
2866
+ API_FIELD_TRANSLATIONS,
2867
+ BROWSER_LANGUAGE_MAP,
2868
+ COLORS,
2869
+ CSS_VARS,
2870
+ DEFAULT_API_HOST,
2871
+ DEV_API_HOST,
2872
+ InterfaceLanguageSelect,
2873
+ LANGUAGE_ALIAS_TABLE,
2874
+ LanguageSelect,
2875
+ THEME_COLORS,
2876
+ cacheManager,
2877
+ clearCache,
2878
+ clearThemeColors,
2879
+ clearTranslationCache,
2880
+ detectBrowserLanguage,
2881
+ fetchAvailableLanguages,
2882
+ getCache,
2883
+ getCacheStats,
2884
+ getCountryCode,
2885
+ getGeoRequestParams,
2886
+ getLtDefaults,
2887
+ getRegionForCountry,
2888
+ getTranslationCacheSize,
2889
+ lt,
2890
+ removeCache,
2891
+ setCache,
2892
+ setLtDefaults,
2893
+ setThemeColors,
2894
+ translateBatch,
2895
+ useLangie,
2896
+ useTranslator
2897
+ });
2898
+ //# sourceMappingURL=index.cjs.map