@cocoar/vue-localization 1.6.4 → 1.6.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +584 -650
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1,651 +1,585 @@
1
- import { ref as g, computed as d, inject as v } from "vue";
2
- class P {
3
- data = /* @__PURE__ */ new Map();
4
- _version = g(0);
5
- /** Reactive version counter — watch this to react to data changes */
6
- version = this._version;
7
- setLocaleData(t, n) {
8
- this.data.set(t, n), this._version.value++;
9
- }
10
- getLocaleData(t) {
11
- return this._version.value, this.data.get(t);
12
- }
13
- hasLocaleData(t) {
14
- return this._version.value, this.data.has(t);
15
- }
16
- removeLocaleData(t) {
17
- this.data.delete(t), this._version.value++;
18
- }
19
- clear() {
20
- this.data.clear(), this._version.value++;
21
- }
22
- }
23
- class $ {
24
- async load(t) {
25
- return {
26
- code: t,
27
- date: _(t),
28
- number: U(t),
29
- currency: z(t),
30
- percent: N(t)
31
- };
32
- }
33
- }
34
- function _(r) {
35
- const t = [], n = [], e = [], a = [], o = new Intl.DateTimeFormat(r, { month: "long" }), s = new Intl.DateTimeFormat(r, { month: "short" });
36
- for (let f = 0; f < 12; f++) {
37
- const y = new Date(2024, f, 1);
38
- t.push(o.format(y)), n.push(s.format(y));
39
- }
40
- const c = new Intl.DateTimeFormat(r, { weekday: "long" }), i = new Intl.DateTimeFormat(r, { weekday: "short" });
41
- for (let f = 0; f < 7; f++) {
42
- const y = new Date(2024, 0, 7 + f);
43
- e.push(c.format(y)), a.push(i.format(y));
44
- }
45
- const { pattern: m, zeroPad: u } = R(r), h = b(r), l = F(r);
46
- return {
47
- pattern: m,
48
- firstDayOfWeek: h,
49
- monthNames: t,
50
- monthNamesShort: n,
51
- dayNames: e,
52
- dayNamesShort: a,
53
- amPm: l,
54
- zeroPad: u
55
- };
56
- }
57
- function R(r) {
58
- const n = new Intl.DateTimeFormat(r, {
59
- year: "numeric",
60
- month: "2-digit",
61
- day: "2-digit"
62
- }).formatToParts(new Date(2024, 11, 25)), e = n.filter((u) => u.type === "month" || u.type === "day" || u.type === "year").map((u) => u.type), a = n.find((u) => u.type === "literal")?.value ?? "/";
63
- let o;
64
- e[0] === "year" ? o = a === "-" ? "yyyy-mm-dd" : "yyyy/mm/dd" : e[0] === "month" ? o = "mm/dd/yyyy" : a === "." ? o = "dd.mm.yyyy" : o = "dd/mm/yyyy";
65
- const m = new Intl.DateTimeFormat(r, {
66
- year: "numeric",
67
- month: "numeric",
68
- day: "numeric"
69
- }).formatToParts(new Date(2024, 2, 5)).find((u) => u.type === "day")?.value === "05";
70
- return { pattern: o, zeroPad: m };
71
- }
72
- function b(r) {
73
- try {
74
- const e = new Intl.Locale(r), a = e.getWeekInfo?.() ?? e.weekInfo;
75
- if (a?.firstDay != null)
76
- return a.firstDay === 7 ? 0 : a.firstDay;
77
- } catch {
78
- }
79
- const t = L(r);
80
- return ["US", "CA", "JP", "KR", "TW", "PH", "IL"].includes(t) ? 0 : 1;
81
- }
82
- function L(r) {
83
- const t = r.split("-");
84
- if (t.length > 1)
85
- return t[t.length - 1].toUpperCase();
86
- try {
87
- return new Intl.Locale(r).maximize().region?.toUpperCase() ?? "";
88
- } catch {
89
- return "";
90
- }
91
- }
92
- function F(r) {
93
- try {
94
- const t = new Intl.DateTimeFormat(r, { hour: "numeric", hour12: !0 }), n = t.formatToParts(new Date(2024, 0, 1, 9)), e = t.formatToParts(new Date(2024, 0, 1, 15)), a = n.find((s) => s.type === "dayPeriod")?.value ?? "AM", o = e.find((s) => s.type === "dayPeriod")?.value ?? "PM";
95
- return [a, o];
96
- } catch {
97
- return ["AM", "PM"];
98
- }
99
- }
100
- function U(r) {
101
- const n = new Intl.NumberFormat(r, { useGrouping: !0 }).formatToParts(123456789e-2), e = n.find((o) => o.type === "decimal")?.value ?? ".", a = n.find((o) => o.type === "group")?.value ?? ",";
102
- return { decimal: e, group: a, grouping: [3] };
103
- }
104
- function z(r) {
105
- const t = L(r), n = x(t);
106
- try {
107
- const a = new Intl.NumberFormat(r, {
108
- style: "currency",
109
- currency: n
110
- }).formatToParts(1234.56), s = a.find((l) => l.type === "currency")?.value ?? n, c = a.findIndex((l) => l.type === "currency"), i = a.findIndex((l) => l.type === "integer"), m = c < i ? "before" : "after", h = (m === "before" ? a.slice(c + 1, i) : a.slice(i, c)).some((l) => l.type === "literal" && /\s/.test(l.value));
111
- return {
112
- default: n,
113
- symbols: { [n]: s },
114
- position: m,
115
- spacing: h,
116
- decimals: 2
117
- };
118
- } catch {
119
- return {
120
- default: n,
121
- symbols: {},
122
- position: "before",
123
- spacing: !1,
124
- decimals: 2
125
- };
126
- }
127
- }
128
- function N(r) {
129
- try {
130
- const n = new Intl.NumberFormat(r, { style: "percent" }).formatToParts(0.25), e = n.find((i) => i.type === "percentSign")?.value ?? "%", a = n.findIndex((i) => i.type === "percentSign"), o = n.findIndex((i) => i.type === "integer"), c = (a > o ? n.slice(o + 1, a) : n.slice(a + 1, o)).some((i) => i.type === "literal" && /\s/.test(i.value));
131
- return { symbol: e, spacing: c, decimals: 0 };
132
- } catch {
133
- return { symbol: "%", spacing: !1, decimals: 0 };
134
- }
135
- }
136
- function x(r) {
137
- return {
138
- US: "USD",
139
- GB: "GBP",
140
- EU: "EUR",
141
- DE: "EUR",
142
- FR: "EUR",
143
- IT: "EUR",
144
- ES: "EUR",
145
- NL: "EUR",
146
- AT: "EUR",
147
- BE: "EUR",
148
- FI: "EUR",
149
- IE: "EUR",
150
- PT: "EUR",
151
- GR: "EUR",
152
- LU: "EUR",
153
- JP: "JPY",
154
- CN: "CNY",
155
- KR: "KRW",
156
- CA: "CAD",
157
- AU: "AUD",
158
- CH: "CHF",
159
- SE: "SEK",
160
- NO: "NOK",
161
- DK: "DKK",
162
- PL: "PLN",
163
- CZ: "CZK",
164
- HU: "HUF",
165
- RO: "RON",
166
- BG: "BGN",
167
- HR: "EUR",
168
- IN: "INR",
169
- BR: "BRL",
170
- MX: "MXN",
171
- RU: "RUB",
172
- TR: "TRY",
173
- ZA: "ZAR",
174
- IL: "ILS",
175
- TW: "TWD",
176
- SG: "SGD",
177
- HK: "HKD",
178
- NZ: "NZD",
179
- PH: "PHP",
180
- TH: "THB",
181
- MY: "MYR",
182
- ID: "IDR",
183
- VN: "VND",
184
- AE: "AED",
185
- SA: "SAR"
186
- }[r] ?? "USD";
187
- }
188
- function I(r, t) {
189
- return {
190
- code: t.code ?? r.code,
191
- date: t.date ? { ...r.date, ...t.date } : r.date,
192
- number: t.number ? { ...r.number, ...t.number } : r.number,
193
- currency: t.currency ? {
194
- ...r.currency,
195
- ...t.currency,
196
- symbols: { ...r.currency.symbols, ...t.currency.symbols }
197
- } : r.currency,
198
- percent: t.percent ? { ...r.percent, ...t.percent } : r.percent
199
- };
200
- }
201
- class C {
202
- data = /* @__PURE__ */ new Map();
203
- _version = g(0);
204
- /** Reactive version counter — use in computed() to react to changes */
205
- version = this._version;
206
- /** Reactive set of loaded language codes */
207
- loadedLanguages = d(() => (this._version.value, new Set(this.data.keys())));
208
- /**
209
- * Set translations for a language. Replaces any existing translations.
210
- * Nested objects are flattened to dot-separated keys.
211
- */
212
- setTranslations(t, n) {
213
- const e = /* @__PURE__ */ new Map();
214
- S(n, "", e), this.data.set(t, e), this._version.value++;
215
- }
216
- /**
217
- * Merge additional translations into existing ones for a language.
218
- */
219
- updateTranslations(t, n) {
220
- const e = this.data.get(t) ?? /* @__PURE__ */ new Map();
221
- S(n, "", e), this.data.set(t, e), this._version.value++;
222
- }
223
- /**
224
- * Get a single translation by key.
225
- */
226
- getTranslation(t, n) {
227
- return this._version.value, this.data.get(t)?.get(n);
228
- }
229
- /**
230
- * Get all translations for a language.
231
- */
232
- getTranslations(t) {
233
- return this._version.value, this.data.get(t);
234
- }
235
- /**
236
- * Set a single translation.
237
- */
238
- setTranslation(t, n, e) {
239
- let a = this.data.get(t);
240
- a || (a = /* @__PURE__ */ new Map(), this.data.set(t, a)), a.set(n, e), this._version.value++;
241
- }
242
- hasLanguage(t) {
243
- return this._version.value, this.data.has(t);
244
- }
245
- /**
246
- * Remove all translations for a specific language.
247
- */
248
- clearLanguage(t) {
249
- this.data.delete(t), this._version.value++;
250
- }
251
- /**
252
- * Bump version to trigger reactivity without changing data.
253
- * Useful after external data updates.
254
- */
255
- touch() {
256
- this._version.value++;
257
- }
258
- clear() {
259
- this.data.clear(), this._version.value++;
260
- }
261
- }
262
- function S(r, t, n) {
263
- for (const [e, a] of Object.entries(r)) {
264
- const o = t ? `${t}.${e}` : e;
265
- typeof a == "string" ? n.set(o, a) : S(a, o, n);
266
- }
267
- }
268
- function E(r, t) {
269
- return t ? r.replace(/\{(\w+)\}/g, (n, e) => {
270
- const a = t[e];
271
- return a == null ? "" : String(a);
272
- }) : r;
273
- }
274
- function Y(r, t) {
275
- return t == null || t.trim() === "" ? !0 : r === t;
276
- }
277
- class M {
278
- async load(t) {
279
- const n = {};
280
- try {
281
- const e = new Intl.RelativeTimeFormat(t, { numeric: "auto" });
282
- n["common.today"] = e.format(0, "day"), n["common.yesterday"] = e.format(-1, "day"), n["common.tomorrow"] = e.format(1, "day");
283
- } catch {
284
- }
285
- try {
286
- const e = new Intl.DateTimeFormat(t, { month: "long" }), a = new Intl.DateTimeFormat(t, { month: "short" });
287
- for (let o = 0; o < 12; o++) {
288
- const s = new Date(2024, o, 1);
289
- n[`common.month.${o + 1}`] = e.format(s), n[`common.month.short.${o + 1}`] = a.format(s);
290
- }
291
- } catch {
292
- }
293
- try {
294
- const e = new Intl.DateTimeFormat(t, { weekday: "long" }), a = new Intl.DateTimeFormat(t, { weekday: "short" });
295
- for (let o = 0; o < 7; o++) {
296
- const s = new Date(2024, 0, 8 + o);
297
- n[`common.weekday.${o + 1}`] = e.format(s), n[`common.weekday.short.${o + 1}`] = a.format(s);
298
- }
299
- } catch {
300
- }
301
- return n;
302
- }
303
- }
304
- class k {
305
- getTimezone() {
306
- try {
307
- return Intl.DateTimeFormat().resolvedOptions().timeZone;
308
- } catch {
309
- return null;
310
- }
311
- }
312
- }
313
- class A {
314
- providers;
315
- _timezone;
316
- /** Reactive current timezone (IANA identifier) */
317
- get timezone() {
318
- return this._timezone;
319
- }
320
- constructor(t = []) {
321
- this.providers = [...t, new k()], this._timezone = g(this.resolve());
322
- }
323
- /** Re-resolve the timezone from providers and update the reactive value */
324
- refresh() {
325
- this._timezone.value = this.resolve();
326
- }
327
- resolve() {
328
- for (const t of this.providers) {
329
- const n = t.getTimezone();
330
- if (n) return n;
331
- }
332
- return "UTC";
333
- }
334
- }
335
- class B {
336
- defaultLanguage;
337
- _language;
338
- _loading;
339
- l10nStore;
340
- i18nStore;
341
- timezoneService;
342
- l10nSources;
343
- i18nSources;
344
- /** Reactive current language */
345
- get language() {
346
- return this._language;
347
- }
348
- /** Reactive loading state */
349
- get loading() {
350
- return this._loading;
351
- }
352
- /** Computed current locale data — reactive, updates on language change */
353
- localeData;
354
- constructor(t = {}) {
355
- this.defaultLanguage = t.defaultLanguage ?? "en", this._language = g(this.defaultLanguage), this._loading = g(!1), this.l10nStore = new P(), this.i18nStore = new C(), this.timezoneService = new A(t.timezoneProviders);
356
- const n = new $();
357
- this.l10nSources = [n];
358
- const e = new M();
359
- this.i18nSources = [e], t.l10nUrl && this.l10nSources.push(new w(t.l10nUrl)), t.i18nUrl && this.i18nSources.push(new H(t.i18nUrl)), this.localeData = d(() => this.l10nStore.getLocaleData(this._language.value));
360
- }
361
- /** Get the configured default language */
362
- getDefaultLanguage() {
363
- return this.defaultLanguage;
364
- }
365
- /**
366
- * Change the current language.
367
- * Loads locale data and translations if not already cached.
368
- */
369
- async setLanguage(t) {
370
- this._loading.value = !0;
371
- try {
372
- await this.loadDataForLanguage(t), this._language.value = t;
373
- } finally {
374
- this._loading.value = !1;
375
- }
376
- }
377
- /**
378
- * Preload data for a language without switching to it.
379
- */
380
- async preloadLanguage(t) {
381
- await this.loadDataForLanguage(t);
382
- }
383
- /**
384
- * Force reload data for a language from all sources, clearing the cache.
385
- * Useful when external data changes at runtime (e.g. SignalR push, user profile update).
386
- * If no language is specified, reloads the current language.
387
- */
388
- async reloadLanguage(t) {
389
- const n = t ?? this._language.value;
390
- this._loading.value = !0;
391
- try {
392
- this.l10nStore.removeLocaleData(n), this.i18nStore.clearLanguage(n), await this.loadDataForLanguage(n), this.i18nStore.touch();
393
- } finally {
394
- this._loading.value = !1;
395
- }
396
- }
397
- /**
398
- * Translate a key using the current language.
399
- * For regional locales (e.g. de-AT), falls back to the base language (de).
400
- * Returns the key itself if no translation is found.
401
- */
402
- t(t, n, e) {
403
- const a = this._language.value;
404
- let o = this.i18nStore.getTranslation(a, t);
405
- if (o === void 0 && a.includes("-")) {
406
- const c = a.split("-")[0];
407
- o = this.i18nStore.getTranslation(c, t);
408
- }
409
- return E(o ?? e ?? t, n);
410
- }
411
- /**
412
- * Add a custom locale data source (loaded after Intl, before HTTP).
413
- */
414
- addLocaleDataSource(t) {
415
- const n = this.l10nSources.findIndex((e) => e instanceof w);
416
- n >= 0 ? this.l10nSources.splice(n, 0, t) : this.l10nSources.push(t);
417
- }
418
- /**
419
- * Add a custom translation source.
420
- */
421
- addTranslationSource(t) {
422
- this.i18nSources.push(t);
423
- }
424
- async loadDataForLanguage(t) {
425
- const n = [];
426
- this.l10nStore.hasLocaleData(t) || n.push(this.loadLocaleData(t)), this.i18nStore.hasLanguage(t) || n.push(this.loadTranslations(t)), await Promise.all(n);
427
- }
428
- async loadLocaleData(t) {
429
- let n = null;
430
- for (const e of this.l10nSources)
431
- try {
432
- const a = await e.load(t);
433
- a && (n ? n = I(n, a) : n = a);
434
- } catch {
435
- }
436
- n && this.l10nStore.setLocaleData(t, n);
437
- }
438
- async loadTranslations(t) {
439
- for (const n of this.i18nSources)
440
- try {
441
- const e = await n.load(t);
442
- e && (this.i18nStore.hasLanguage(t) ? this.i18nStore.updateTranslations(t, e) : this.i18nStore.setTranslations(t, e));
443
- } catch {
444
- }
445
- this.i18nStore.hasLanguage(t) || this.i18nStore.setTranslations(t, {});
446
- }
447
- }
448
- class w {
449
- constructor(t) {
450
- this.urlBuilder = t;
451
- }
452
- async load(t) {
453
- const n = t.includes("-") ? t.split("-")[0] : null;
454
- let e = null;
455
- if (n)
456
- try {
457
- const a = await fetch(this.urlBuilder(n));
458
- a.ok && (e = await a.json());
459
- } catch {
460
- }
461
- try {
462
- const a = await fetch(this.urlBuilder(t));
463
- if (a.ok) {
464
- const o = await a.json();
465
- e ? e = I(e, o) : e = o;
466
- }
467
- } catch {
468
- }
469
- return e;
470
- }
471
- }
472
- class H {
473
- constructor(t) {
474
- this.urlBuilder = t;
475
- }
476
- async load(t) {
477
- const n = t.includes("-") ? t.split("-")[0] : null;
478
- let e = null;
479
- if (n)
480
- try {
481
- const a = await fetch(this.urlBuilder(n));
482
- a.ok && (e = await a.json());
483
- } catch {
484
- }
485
- try {
486
- const a = await fetch(this.urlBuilder(t));
487
- if (a.ok) {
488
- const o = await a.json();
489
- e ? e = { ...e, ...o } : e = o;
490
- }
491
- } catch {
492
- }
493
- return e;
494
- }
495
- }
496
- function D(r, t, n) {
497
- const e = n ?? 2, a = Math.abs(r).toFixed(e), [o, s] = a.split(".");
498
- let c = "";
499
- const i = o, m = t.grouping[0] ?? 3;
500
- let u = i.length;
501
- for (; u > 0; ) {
502
- const l = Math.max(0, u - m);
503
- c = i.slice(l, u) + (c ? t.group + c : ""), u = l;
504
- }
505
- const h = r < 0 ? "-" : "";
506
- return e > 0 && s ? `${h}${c}${t.decimal}${s}` : `${h}${c}`;
507
- }
508
- function K(r, t, n) {
509
- const e = t.currency, a = n ?? e.default, o = e.symbols[a] ?? O(t.code, a), s = D(r, t.number, e.decimals), c = e.spacing ? " " : "";
510
- return e.position === "before" ? `${o}${c}${s}` : `${s}${c}${o}`;
511
- }
512
- const T = /* @__PURE__ */ new Map();
513
- function O(r, t) {
514
- const n = `${r}:${t}`;
515
- let e = T.get(n);
516
- if (e != null) return e;
517
- try {
518
- e = new Intl.NumberFormat(r, { style: "currency", currency: t }).formatToParts(0).find((o) => o.type === "currency")?.value ?? t;
519
- } catch {
520
- e = t;
521
- }
522
- return T.set(n, e), e;
523
- }
524
- function Z(r, t, n) {
525
- const e = t.percent, a = n ?? e.decimals, o = D(r * 100, t.number, a), s = e.spacing ? " " : "";
526
- return `${o}${s}${e.symbol}`;
527
- }
528
- function G(r, t, n = !1) {
529
- const e = typeof r == "string" ? new Date(r) : r;
530
- if (isNaN(e.getTime())) return String(r);
531
- const a = t.zeroPad !== !1, o = a ? String(e.getDate()).padStart(2, "0") : String(e.getDate()), s = a ? String(e.getMonth() + 1).padStart(2, "0") : String(e.getMonth() + 1), c = String(e.getFullYear());
532
- let i;
533
- switch (t.pattern) {
534
- case "mm/dd/yyyy":
535
- i = `${s}/${o}/${c}`;
536
- break;
537
- case "yyyy-mm-dd":
538
- i = `${c}-${s}-${o}`;
539
- break;
540
- case "yyyy/mm/dd":
541
- i = `${c}/${s}/${o}`;
542
- break;
543
- case "dd/mm/yyyy":
544
- i = `${o}/${s}/${c}`;
545
- break;
546
- default:
547
- i = `${o}.${s}.${c}`;
548
- break;
549
- }
550
- if (n) {
551
- const m = String(e.getHours()).padStart(2, "0"), u = String(e.getMinutes()).padStart(2, "0");
552
- i += ` ${m}:${u}`;
553
- }
554
- return i;
555
- }
556
- const p = /* @__PURE__ */ Symbol("coar-localization");
557
- function j(r = {}) {
558
- const t = new B(r);
559
- return {
560
- service: t,
561
- install(e) {
562
- e.provide(p, t), t.setLanguage(t.getDefaultLanguage());
563
- }
564
- };
565
- }
566
- function J() {
567
- return v(p, null);
568
- }
569
- function V() {
570
- const r = v(p, null), t = r ? r.language : d(() => navigator.language || "en"), n = r ? r.localeData : d(() => {
571
- });
572
- return {
573
- /** Current language (reactive) */
574
- language: t,
575
- /** Current locale data (reactive) */
576
- localeData: n,
577
- /** Format a number */
578
- fmtNumber: (e, a) => {
579
- const o = n.value;
580
- return o ? D(e, o.number, a) : e.toFixed(a ?? 2);
581
- },
582
- /** Format a currency value */
583
- fmtCurrency: (e, a) => {
584
- const o = n.value;
585
- return o ? K(e, o, a) : e.toFixed(2);
586
- },
587
- /** Format a percentage (0.25 → "25%") */
588
- fmtPercent: (e, a) => {
589
- const o = n.value;
590
- return o ? Z(e, o, a) : `${(e * 100).toFixed(a ?? 0)}%`;
591
- },
592
- /** Format a date */
593
- fmtDate: (e, a = !1) => {
594
- const o = n.value;
595
- return o ? G(e, o.date, a) : String(e);
596
- }
597
- };
598
- }
599
- function X() {
600
- const r = v(p, null);
601
- return {
602
- /** Current language (reactive) */
603
- language: r ? r.language : d(() => navigator.language || "en"),
604
- /**
605
- * Translate a key. Returns the key if no translation found.
606
- * Reactive — updates when language changes.
607
- */
608
- t: (t, n, e) => r ? r.t(t, n, e) : e ?? t,
609
- /**
610
- * Create a computed translation ref that reacts to language changes.
611
- */
612
- tRef: (t, n, e) => r ? d(() => r.t(t, n, e)) : d(() => e ?? t)
613
- };
614
- }
615
- function q() {
616
- const r = v(p, null);
617
- return {
618
- /** Current timezone (reactive IANA identifier) */
619
- timezone: r ? r.timezoneService.timezone : d(() => {
620
- try {
621
- return Intl.DateTimeFormat().resolvedOptions().timeZone;
622
- } catch {
623
- return "UTC";
624
- }
625
- }),
626
- /** Re-resolve timezone from providers */
627
- refresh: () => r?.timezoneService.refresh()
628
- };
629
- }
630
- export {
631
- k as BrowserTimezoneProvider,
632
- p as COAR_LOCALIZATION_KEY,
633
- P as CoarLocalizationDataStore,
634
- B as CoarLocalizationService,
635
- A as CoarTimezoneService,
636
- C as CoarTranslationStore,
637
- $ as IntlLocaleDataSource,
638
- M as IntlTranslationSource,
639
- j as createCoarLocalization,
640
- K as formatCurrency,
641
- G as formatDate,
642
- D as formatNumber,
643
- Z as formatPercent,
644
- E as interpolate,
645
- Y as isMissingTranslation,
646
- I as mergeLocalizationData,
647
- X as useI18n,
648
- V as useL10n,
649
- J as useLocalization,
650
- q as useTimezone
1
+ import { computed as e, inject as t, ref as n } from "vue";
2
+ //#region src/l10n/localization-data-store.ts
3
+ var r = class {
4
+ data = /* @__PURE__ */ new Map();
5
+ _version = n(0);
6
+ version = this._version;
7
+ setLocaleData(e, t) {
8
+ this.data.set(e, t), this._version.value++;
9
+ }
10
+ getLocaleData(e) {
11
+ return this._version.value, this.data.get(e);
12
+ }
13
+ hasLocaleData(e) {
14
+ return this._version.value, this.data.has(e);
15
+ }
16
+ removeLocaleData(e) {
17
+ this.data.delete(e), this._version.value++;
18
+ }
19
+ clear() {
20
+ this.data.clear(), this._version.value++;
21
+ }
22
+ }, i = class {
23
+ async load(e) {
24
+ return {
25
+ code: e,
26
+ date: a(e),
27
+ number: u(e),
28
+ currency: d(e),
29
+ percent: f(e)
30
+ };
31
+ }
32
+ };
33
+ function a(e) {
34
+ let t = [], n = [], r = [], i = [], a = new Intl.DateTimeFormat(e, { month: "long" }), c = new Intl.DateTimeFormat(e, { month: "short" });
35
+ for (let e = 0; e < 12; e++) {
36
+ let r = new Date(2024, e, 1);
37
+ t.push(a.format(r)), n.push(c.format(r));
38
+ }
39
+ let u = new Intl.DateTimeFormat(e, { weekday: "long" }), d = new Intl.DateTimeFormat(e, { weekday: "short" });
40
+ for (let e = 0; e < 7; e++) {
41
+ let t = new Date(2024, 0, 7 + e);
42
+ r.push(u.format(t)), i.push(d.format(t));
43
+ }
44
+ let { pattern: f, zeroPad: p } = o(e);
45
+ return {
46
+ pattern: f,
47
+ firstDayOfWeek: s(e),
48
+ monthNames: t,
49
+ monthNamesShort: n,
50
+ dayNames: r,
51
+ dayNamesShort: i,
52
+ amPm: l(e),
53
+ zeroPad: p
54
+ };
55
+ }
56
+ function o(e) {
57
+ let t = new Intl.DateTimeFormat(e, {
58
+ year: "numeric",
59
+ month: "2-digit",
60
+ day: "2-digit"
61
+ }).formatToParts(new Date(2024, 11, 25)), n = t.filter((e) => e.type === "month" || e.type === "day" || e.type === "year").map((e) => e.type), r = t.find((e) => e.type === "literal")?.value ?? "/", i;
62
+ i = n[0] === "year" ? r === "-" ? "yyyy-mm-dd" : "yyyy/mm/dd" : n[0] === "month" ? "mm/dd/yyyy" : r === "." ? "dd.mm.yyyy" : "dd/mm/yyyy";
63
+ let a = new Intl.DateTimeFormat(e, {
64
+ year: "numeric",
65
+ month: "numeric",
66
+ day: "numeric"
67
+ }).formatToParts(new Date(2024, 2, 5)).find((e) => e.type === "day")?.value === "05";
68
+ return {
69
+ pattern: i,
70
+ zeroPad: a
71
+ };
72
+ }
73
+ function s(e) {
74
+ try {
75
+ let t = new Intl.Locale(e), n = t.getWeekInfo?.() ?? t.weekInfo;
76
+ if (n?.firstDay != null) return n.firstDay === 7 ? 0 : n.firstDay;
77
+ } catch {}
78
+ let t = c(e);
79
+ return +![
80
+ "US",
81
+ "CA",
82
+ "JP",
83
+ "KR",
84
+ "TW",
85
+ "PH",
86
+ "IL"
87
+ ].includes(t);
88
+ }
89
+ function c(e) {
90
+ let t = e.split("-");
91
+ if (t.length > 1) return t[t.length - 1].toUpperCase();
92
+ try {
93
+ return new Intl.Locale(e).maximize().region?.toUpperCase() ?? "";
94
+ } catch {
95
+ return "";
96
+ }
97
+ }
98
+ function l(e) {
99
+ try {
100
+ let t = new Intl.DateTimeFormat(e, {
101
+ hour: "numeric",
102
+ hour12: !0
103
+ }), n = t.formatToParts(new Date(2024, 0, 1, 9)), r = t.formatToParts(new Date(2024, 0, 1, 15));
104
+ return [n.find((e) => e.type === "dayPeriod")?.value ?? "AM", r.find((e) => e.type === "dayPeriod")?.value ?? "PM"];
105
+ } catch {
106
+ return ["AM", "PM"];
107
+ }
108
+ }
109
+ function u(e) {
110
+ let t = new Intl.NumberFormat(e, { useGrouping: !0 }).formatToParts(1234567.89);
111
+ return {
112
+ decimal: t.find((e) => e.type === "decimal")?.value ?? ".",
113
+ group: t.find((e) => e.type === "group")?.value ?? ",",
114
+ grouping: [3]
115
+ };
116
+ }
117
+ function d(e) {
118
+ let t = p(c(e));
119
+ try {
120
+ let n = new Intl.NumberFormat(e, {
121
+ style: "currency",
122
+ currency: t
123
+ }).formatToParts(1234.56), r = n.find((e) => e.type === "currency")?.value ?? t, i = n.findIndex((e) => e.type === "currency"), a = n.findIndex((e) => e.type === "integer"), o = i < a ? "before" : "after", s = (o === "before" ? n.slice(i + 1, a) : n.slice(a, i)).some((e) => e.type === "literal" && /\s/.test(e.value));
124
+ return {
125
+ default: t,
126
+ symbols: { [t]: r },
127
+ position: o,
128
+ spacing: s,
129
+ decimals: 2
130
+ };
131
+ } catch {
132
+ return {
133
+ default: t,
134
+ symbols: {},
135
+ position: "before",
136
+ spacing: !1,
137
+ decimals: 2
138
+ };
139
+ }
140
+ }
141
+ function f(e) {
142
+ try {
143
+ let t = new Intl.NumberFormat(e, { style: "percent" }).formatToParts(.25), n = t.find((e) => e.type === "percentSign")?.value ?? "%", r = t.findIndex((e) => e.type === "percentSign"), i = t.findIndex((e) => e.type === "integer");
144
+ return {
145
+ symbol: n,
146
+ spacing: (r > i ? t.slice(i + 1, r) : t.slice(r + 1, i)).some((e) => e.type === "literal" && /\s/.test(e.value)),
147
+ decimals: 0
148
+ };
149
+ } catch {
150
+ return {
151
+ symbol: "%",
152
+ spacing: !1,
153
+ decimals: 0
154
+ };
155
+ }
156
+ }
157
+ function p(e) {
158
+ return {
159
+ US: "USD",
160
+ GB: "GBP",
161
+ EU: "EUR",
162
+ DE: "EUR",
163
+ FR: "EUR",
164
+ IT: "EUR",
165
+ ES: "EUR",
166
+ NL: "EUR",
167
+ AT: "EUR",
168
+ BE: "EUR",
169
+ FI: "EUR",
170
+ IE: "EUR",
171
+ PT: "EUR",
172
+ GR: "EUR",
173
+ LU: "EUR",
174
+ JP: "JPY",
175
+ CN: "CNY",
176
+ KR: "KRW",
177
+ CA: "CAD",
178
+ AU: "AUD",
179
+ CH: "CHF",
180
+ SE: "SEK",
181
+ NO: "NOK",
182
+ DK: "DKK",
183
+ PL: "PLN",
184
+ CZ: "CZK",
185
+ HU: "HUF",
186
+ RO: "RON",
187
+ BG: "BGN",
188
+ HR: "EUR",
189
+ IN: "INR",
190
+ BR: "BRL",
191
+ MX: "MXN",
192
+ RU: "RUB",
193
+ TR: "TRY",
194
+ ZA: "ZAR",
195
+ IL: "ILS",
196
+ TW: "TWD",
197
+ SG: "SGD",
198
+ HK: "HKD",
199
+ NZ: "NZD",
200
+ PH: "PHP",
201
+ TH: "THB",
202
+ MY: "MYR",
203
+ ID: "IDR",
204
+ VN: "VND",
205
+ AE: "AED",
206
+ SA: "SAR"
207
+ }[e] ?? "USD";
208
+ }
209
+ //#endregion
210
+ //#region src/l10n/merge-localization-data.ts
211
+ function m(e, t) {
212
+ return {
213
+ code: t.code ?? e.code,
214
+ date: t.date ? {
215
+ ...e.date,
216
+ ...t.date
217
+ } : e.date,
218
+ number: t.number ? {
219
+ ...e.number,
220
+ ...t.number
221
+ } : e.number,
222
+ currency: t.currency ? {
223
+ ...e.currency,
224
+ ...t.currency,
225
+ symbols: {
226
+ ...e.currency.symbols,
227
+ ...t.currency.symbols
228
+ }
229
+ } : e.currency,
230
+ percent: t.percent ? {
231
+ ...e.percent,
232
+ ...t.percent
233
+ } : e.percent
234
+ };
235
+ }
236
+ //#endregion
237
+ //#region src/i18n/translation-store.ts
238
+ var h = class {
239
+ data = /* @__PURE__ */ new Map();
240
+ _version = n(0);
241
+ version = this._version;
242
+ loadedLanguages = e(() => (this._version.value, new Set(this.data.keys())));
243
+ setTranslations(e, t) {
244
+ let n = /* @__PURE__ */ new Map();
245
+ g(t, "", n), this.data.set(e, n), this._version.value++;
246
+ }
247
+ updateTranslations(e, t) {
248
+ let n = this.data.get(e) ?? /* @__PURE__ */ new Map();
249
+ g(t, "", n), this.data.set(e, n), this._version.value++;
250
+ }
251
+ getTranslation(e, t) {
252
+ return this._version.value, this.data.get(e)?.get(t);
253
+ }
254
+ getTranslations(e) {
255
+ return this._version.value, this.data.get(e);
256
+ }
257
+ setTranslation(e, t, n) {
258
+ let r = this.data.get(e);
259
+ r || (r = /* @__PURE__ */ new Map(), this.data.set(e, r)), r.set(t, n), this._version.value++;
260
+ }
261
+ hasLanguage(e) {
262
+ return this._version.value, this.data.has(e);
263
+ }
264
+ clearLanguage(e) {
265
+ this.data.delete(e), this._version.value++;
266
+ }
267
+ touch() {
268
+ this._version.value++;
269
+ }
270
+ clear() {
271
+ this.data.clear(), this._version.value++;
272
+ }
273
+ };
274
+ function g(e, t, n) {
275
+ for (let [r, i] of Object.entries(e)) {
276
+ let e = t ? `${t}.${r}` : r;
277
+ typeof i == "string" ? n.set(e, i) : g(i, e, n);
278
+ }
279
+ }
280
+ //#endregion
281
+ //#region src/i18n/interpolate.ts
282
+ function _(e, t) {
283
+ return t ? e.replace(/\{(\w+)\}/g, (e, n) => {
284
+ let r = t[n];
285
+ return r == null ? "" : String(r);
286
+ }) : e;
287
+ }
288
+ function v(e, t) {
289
+ return t == null || t.trim() === "" ? !0 : e === t;
290
+ }
291
+ //#endregion
292
+ //#region src/i18n/intl-translation-source.ts
293
+ var y = class {
294
+ async load(e) {
295
+ let t = {};
296
+ try {
297
+ let n = new Intl.RelativeTimeFormat(e, { numeric: "auto" });
298
+ t["common.today"] = n.format(0, "day"), t["common.yesterday"] = n.format(-1, "day"), t["common.tomorrow"] = n.format(1, "day");
299
+ } catch {}
300
+ try {
301
+ let n = new Intl.DateTimeFormat(e, { month: "long" }), r = new Intl.DateTimeFormat(e, { month: "short" });
302
+ for (let e = 0; e < 12; e++) {
303
+ let i = new Date(2024, e, 1);
304
+ t[`common.month.${e + 1}`] = n.format(i), t[`common.month.short.${e + 1}`] = r.format(i);
305
+ }
306
+ } catch {}
307
+ try {
308
+ let n = new Intl.DateTimeFormat(e, { weekday: "long" }), r = new Intl.DateTimeFormat(e, { weekday: "short" });
309
+ for (let e = 0; e < 7; e++) {
310
+ let i = new Date(2024, 0, 8 + e);
311
+ t[`common.weekday.${e + 1}`] = n.format(i), t[`common.weekday.short.${e + 1}`] = r.format(i);
312
+ }
313
+ } catch {}
314
+ return t;
315
+ }
316
+ }, b = class {
317
+ getTimezone() {
318
+ try {
319
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
320
+ } catch {
321
+ return null;
322
+ }
323
+ }
324
+ }, x = class {
325
+ providers;
326
+ _timezone;
327
+ get timezone() {
328
+ return this._timezone;
329
+ }
330
+ constructor(e = []) {
331
+ this.providers = [...e, new b()], this._timezone = n(this.resolve());
332
+ }
333
+ refresh() {
334
+ this._timezone.value = this.resolve();
335
+ }
336
+ resolve() {
337
+ for (let e of this.providers) {
338
+ let t = e.getTimezone();
339
+ if (t) return t;
340
+ }
341
+ return "UTC";
342
+ }
343
+ }, S = class {
344
+ defaultLanguage;
345
+ _language;
346
+ _loading;
347
+ l10nStore;
348
+ i18nStore;
349
+ timezoneService;
350
+ l10nSources;
351
+ i18nSources;
352
+ get language() {
353
+ return this._language;
354
+ }
355
+ get loading() {
356
+ return this._loading;
357
+ }
358
+ localeData;
359
+ constructor(t = {}) {
360
+ this.defaultLanguage = t.defaultLanguage ?? "en", this._language = n(this.defaultLanguage), this._loading = n(!1), this.l10nStore = new r(), this.i18nStore = new h(), this.timezoneService = new x(t.timezoneProviders), this.l10nSources = [new i()], this.i18nSources = [new y()], t.l10nUrl && this.l10nSources.push(new C(t.l10nUrl)), t.i18nUrl && this.i18nSources.push(new w(t.i18nUrl)), this.localeData = e(() => this.l10nStore.getLocaleData(this._language.value));
361
+ }
362
+ getDefaultLanguage() {
363
+ return this.defaultLanguage;
364
+ }
365
+ async setLanguage(e) {
366
+ this._loading.value = !0;
367
+ try {
368
+ await this.loadDataForLanguage(e), this._language.value = e;
369
+ } finally {
370
+ this._loading.value = !1;
371
+ }
372
+ }
373
+ async preloadLanguage(e) {
374
+ await this.loadDataForLanguage(e);
375
+ }
376
+ async reloadLanguage(e) {
377
+ let t = e ?? this._language.value;
378
+ this._loading.value = !0;
379
+ try {
380
+ this.l10nStore.removeLocaleData(t), this.i18nStore.clearLanguage(t), await this.loadDataForLanguage(t), this.i18nStore.touch();
381
+ } finally {
382
+ this._loading.value = !1;
383
+ }
384
+ }
385
+ t(e, t, n) {
386
+ let r = this._language.value, i = this.i18nStore.getTranslation(r, e);
387
+ if (i === void 0 && r.includes("-")) {
388
+ let t = r.split("-")[0];
389
+ i = this.i18nStore.getTranslation(t, e);
390
+ }
391
+ return _(i ?? n ?? e, t);
392
+ }
393
+ addLocaleDataSource(e) {
394
+ let t = this.l10nSources.findIndex((e) => e instanceof C);
395
+ t >= 0 ? this.l10nSources.splice(t, 0, e) : this.l10nSources.push(e);
396
+ }
397
+ addTranslationSource(e) {
398
+ this.i18nSources.push(e);
399
+ }
400
+ async loadDataForLanguage(e) {
401
+ let t = [];
402
+ this.l10nStore.hasLocaleData(e) || t.push(this.loadLocaleData(e)), this.i18nStore.hasLanguage(e) || t.push(this.loadTranslations(e)), await Promise.all(t);
403
+ }
404
+ async loadLocaleData(e) {
405
+ let t = null;
406
+ for (let n of this.l10nSources) try {
407
+ let r = await n.load(e);
408
+ r && (t = t ? m(t, r) : r);
409
+ } catch {}
410
+ t && this.l10nStore.setLocaleData(e, t);
411
+ }
412
+ async loadTranslations(e) {
413
+ for (let t of this.i18nSources) try {
414
+ let n = await t.load(e);
415
+ n && (this.i18nStore.hasLanguage(e) ? this.i18nStore.updateTranslations(e, n) : this.i18nStore.setTranslations(e, n));
416
+ } catch {}
417
+ this.i18nStore.hasLanguage(e) || this.i18nStore.setTranslations(e, {});
418
+ }
419
+ }, C = class {
420
+ constructor(e) {
421
+ this.urlBuilder = e;
422
+ }
423
+ async load(e) {
424
+ let t = e.includes("-") ? e.split("-")[0] : null, n = null;
425
+ if (t) try {
426
+ let e = await fetch(this.urlBuilder(t));
427
+ e.ok && (n = await e.json());
428
+ } catch {}
429
+ try {
430
+ let t = await fetch(this.urlBuilder(e));
431
+ if (t.ok) {
432
+ let e = await t.json();
433
+ n = n ? m(n, e) : e;
434
+ }
435
+ } catch {}
436
+ return n;
437
+ }
438
+ }, w = class {
439
+ constructor(e) {
440
+ this.urlBuilder = e;
441
+ }
442
+ async load(e) {
443
+ let t = e.includes("-") ? e.split("-")[0] : null, n = null;
444
+ if (t) try {
445
+ let e = await fetch(this.urlBuilder(t));
446
+ e.ok && (n = await e.json());
447
+ } catch {}
448
+ try {
449
+ let t = await fetch(this.urlBuilder(e));
450
+ if (t.ok) {
451
+ let e = await t.json();
452
+ n = n ? {
453
+ ...n,
454
+ ...e
455
+ } : e;
456
+ }
457
+ } catch {}
458
+ return n;
459
+ }
651
460
  };
461
+ //#endregion
462
+ //#region src/l10n/formatters.ts
463
+ function T(e, t, n) {
464
+ let r = n ?? 2, [i, a] = Math.abs(e).toFixed(r).split("."), o = "", s = i, c = t.grouping[0] ?? 3, l = s.length;
465
+ for (; l > 0;) {
466
+ let e = Math.max(0, l - c);
467
+ o = s.slice(e, l) + (o ? t.group + o : ""), l = e;
468
+ }
469
+ let u = e < 0 ? "-" : "";
470
+ return r > 0 && a ? `${u}${o}${t.decimal}${a}` : `${u}${o}`;
471
+ }
472
+ function E(e, t, n) {
473
+ let r = t.currency, i = n ?? r.default, a = r.symbols[i] ?? O(t.code, i), o = T(e, t.number, r.decimals), s = r.spacing ? "\xA0" : "";
474
+ return r.position === "before" ? `${a}${s}${o}` : `${o}${s}${a}`;
475
+ }
476
+ var D = /* @__PURE__ */ new Map();
477
+ function O(e, t) {
478
+ let n = `${e}:${t}`, r = D.get(n);
479
+ if (r != null) return r;
480
+ try {
481
+ r = new Intl.NumberFormat(e, {
482
+ style: "currency",
483
+ currency: t
484
+ }).formatToParts(0).find((e) => e.type === "currency")?.value ?? t;
485
+ } catch {
486
+ r = t;
487
+ }
488
+ return D.set(n, r), r;
489
+ }
490
+ function k(e, t, n) {
491
+ let r = t.percent, i = n ?? r.decimals;
492
+ return `${T(e * 100, t.number, i)}${r.spacing ? "\xA0" : ""}${r.symbol}`;
493
+ }
494
+ function A(e, t, n = !1) {
495
+ let r = typeof e == "string" ? new Date(e) : e;
496
+ if (isNaN(r.getTime())) return String(e);
497
+ let i = t.zeroPad !== !1, a = i ? String(r.getDate()).padStart(2, "0") : String(r.getDate()), o = i ? String(r.getMonth() + 1).padStart(2, "0") : String(r.getMonth() + 1), s = String(r.getFullYear()), c;
498
+ switch (t.pattern) {
499
+ case "mm/dd/yyyy":
500
+ c = `${o}/${a}/${s}`;
501
+ break;
502
+ case "yyyy-mm-dd":
503
+ c = `${s}-${o}-${a}`;
504
+ break;
505
+ case "yyyy/mm/dd":
506
+ c = `${s}/${o}/${a}`;
507
+ break;
508
+ case "dd/mm/yyyy":
509
+ c = `${a}/${o}/${s}`;
510
+ break;
511
+ default:
512
+ c = `${a}.${o}.${s}`;
513
+ break;
514
+ }
515
+ if (n) {
516
+ let e = String(r.getHours()).padStart(2, "0"), t = String(r.getMinutes()).padStart(2, "0");
517
+ c += ` ${e}:${t}`;
518
+ }
519
+ return c;
520
+ }
521
+ //#endregion
522
+ //#region src/injection-keys.ts
523
+ var j = Symbol("coar-localization");
524
+ //#endregion
525
+ //#region src/plugin.ts
526
+ function M(e = {}) {
527
+ let t = new S(e);
528
+ return {
529
+ service: t,
530
+ install(e) {
531
+ e.provide(j, t), t.setLanguage(t.getDefaultLanguage());
532
+ }
533
+ };
534
+ }
535
+ //#endregion
536
+ //#region src/composables.ts
537
+ function N() {
538
+ return t(j, null);
539
+ }
540
+ function P() {
541
+ let n = t(j, null), r = n ? n.language : e(() => navigator.language || "en"), i = n ? n.localeData : e(() => void 0);
542
+ return {
543
+ language: r,
544
+ localeData: i,
545
+ fmtNumber: (e, t) => {
546
+ let n = i.value;
547
+ return n ? T(e, n.number, t) : e.toFixed(t ?? 2);
548
+ },
549
+ fmtCurrency: (e, t) => {
550
+ let n = i.value;
551
+ return n ? E(e, n, t) : e.toFixed(2);
552
+ },
553
+ fmtPercent: (e, t) => {
554
+ let n = i.value;
555
+ return n ? k(e, n, t) : `${(e * 100).toFixed(t ?? 0)}%`;
556
+ },
557
+ fmtDate: (e, t = !1) => {
558
+ let n = i.value;
559
+ return n ? A(e, n.date, t) : String(e);
560
+ }
561
+ };
562
+ }
563
+ function F() {
564
+ let n = t(j, null);
565
+ return {
566
+ language: n ? n.language : e(() => navigator.language || "en"),
567
+ t: (e, t, r) => n ? n.t(e, t, r) : r ?? e,
568
+ tRef: (t, r, i) => e(n ? () => n.t(t, r, i) : () => i ?? t)
569
+ };
570
+ }
571
+ function I() {
572
+ let n = t(j, null);
573
+ return {
574
+ timezone: n ? n.timezoneService.timezone : e(() => {
575
+ try {
576
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
577
+ } catch {
578
+ return "UTC";
579
+ }
580
+ }),
581
+ refresh: () => n?.timezoneService.refresh()
582
+ };
583
+ }
584
+ //#endregion
585
+ export { b as BrowserTimezoneProvider, j as COAR_LOCALIZATION_KEY, r as CoarLocalizationDataStore, S as CoarLocalizationService, x as CoarTimezoneService, h as CoarTranslationStore, i as IntlLocaleDataSource, y as IntlTranslationSource, M as createCoarLocalization, E as formatCurrency, A as formatDate, T as formatNumber, k as formatPercent, _ as interpolate, v as isMissingTranslation, m as mergeLocalizationData, F as useI18n, P as useL10n, N as useLocalization, I as useTimezone };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocoar/vue-localization",
3
- "version": "1.6.4",
3
+ "version": "1.6.6",
4
4
  "description": "Locale-aware formatting (l10n), translations (i18n), and timezone detection for Vue 3",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -42,6 +42,6 @@
42
42
  "vue": "^3.5.0"
43
43
  },
44
44
  "devDependencies": {
45
- "vue": "^3.5.0"
45
+ "vue": "^3.5.32"
46
46
  }
47
47
  }