@manyducks.co/dolla 2.0.0-alpha.67 → 2.0.0-alpha.68
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/README.md +24 -75
- package/dist/core/context.d.ts +11 -25
- package/dist/{hooks/index.d.ts → core/hooks.d.ts} +19 -26
- package/dist/core/index.d.ts +5 -4
- package/dist/core/markup.d.ts +6 -31
- package/dist/core/nodes/dynamic.d.ts +1 -1
- package/dist/core/nodes/element.d.ts +0 -1
- package/dist/core/ref.d.ts +1 -0
- package/dist/core/signals.d.ts +18 -32
- package/dist/core/views/for.d.ts +2 -2
- package/dist/core/views/show.d.ts +3 -3
- package/dist/i18n.js +121 -122
- package/dist/i18n.js.map +1 -1
- package/dist/{index-DKMlSUEt.js → index-BLYt-mrI.js} +22 -23
- package/dist/index-BLYt-mrI.js.map +1 -0
- package/dist/index.js +145 -97
- package/dist/index.js.map +1 -1
- package/dist/jsx-dev-runtime.js +1 -1
- package/dist/jsx-runtime.js +1 -1
- package/dist/{signals-HNnDUJRQ.js → logger-IE5c3t-c.js} +250 -184
- package/dist/logger-IE5c3t-c.js.map +1 -0
- package/dist/markup-8Olu6qoy.js +1063 -0
- package/dist/markup-8Olu6qoy.js.map +1 -0
- package/dist/router.js +1 -1
- package/docs/hooks.md +17 -17
- package/docs/mixins.md +10 -7
- package/docs/ref.md +14 -14
- package/docs/router.md +8 -5
- package/package.json +1 -5
- package/vite.config.js +0 -1
- package/dist/core/scheduler.d.ts +0 -25
- package/dist/hooks.js +0 -68
- package/dist/hooks.js.map +0 -1
- package/dist/index-DKMlSUEt.js.map +0 -1
- package/dist/logger-BcgYqLUO.js +0 -82
- package/dist/logger-BcgYqLUO.js.map +0 -1
- package/dist/markup-BgNq6mZF.js +0 -1182
- package/dist/markup-BgNq6mZF.js.map +0 -1
- package/dist/ref-BD79iqlg.js +0 -15
- package/dist/ref-BD79iqlg.js.map +0 -1
- package/dist/signals-HNnDUJRQ.js.map +0 -1
- /package/dist/{hooks/index.test.d.ts → core/hooks.test.d.ts} +0 -0
package/dist/i18n.js
CHANGED
|
@@ -2,35 +2,34 @@ var B = Object.defineProperty;
|
|
|
2
2
|
var D = (o) => {
|
|
3
3
|
throw TypeError(o);
|
|
4
4
|
};
|
|
5
|
-
var J = (o,
|
|
6
|
-
var
|
|
7
|
-
var
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { i as C, a as j, b as W, t as P } from "./typeChecking-Cw-4pIto.js";
|
|
5
|
+
var J = (o, e, t) => e in o ? B(o, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : o[e] = t;
|
|
6
|
+
var j = (o, e, t) => J(o, typeof e != "symbol" ? e + "" : e, t), O = (o, e, t) => e.has(o) || D("Cannot " + t);
|
|
7
|
+
var i = (o, e, t) => (O(o, e, "read from private field"), t ? t.call(o) : e.get(o)), m = (o, e, t) => e.has(o) ? D("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(o) : e.set(o, t), N = (o, e, t, n) => (O(o, e, "write to private field"), n ? n.call(o, t) : e.set(o, t), t), g = (o, e, t) => (O(o, e, "access private method"), t);
|
|
8
|
+
import { w as K, m as k, j as Q, d as U, g as x } from "./logger-IE5c3t-c.js";
|
|
9
|
+
import { i as C, a as _, b as W, t as P } from "./typeChecking-Cw-4pIto.js";
|
|
11
10
|
var I, F, p, S, G;
|
|
12
11
|
class X {
|
|
13
|
-
constructor(
|
|
12
|
+
constructor(e) {
|
|
14
13
|
m(this, p);
|
|
15
|
-
|
|
14
|
+
j(this, "config");
|
|
16
15
|
m(this, I, !1);
|
|
17
16
|
m(this, F, /* @__PURE__ */ new Map());
|
|
18
|
-
this.config =
|
|
17
|
+
this.config = e;
|
|
19
18
|
}
|
|
20
19
|
async load() {
|
|
21
|
-
let
|
|
22
|
-
if (!
|
|
23
|
-
if (
|
|
24
|
-
|
|
20
|
+
let e;
|
|
21
|
+
if (!i(this, I)) {
|
|
22
|
+
if (_(this.config.strings))
|
|
23
|
+
e = this.config.strings;
|
|
25
24
|
else if (W(this.config.fetch)) {
|
|
26
|
-
if (
|
|
27
|
-
throw new Error(`Fetch function did not return an object of language strings: ${
|
|
25
|
+
if (e = await this.config.fetch(), !_(e))
|
|
26
|
+
throw new Error(`Fetch function did not return an object of language strings: ${e}`);
|
|
28
27
|
} else if (C(this.config.path)) {
|
|
29
|
-
const
|
|
30
|
-
if (
|
|
31
|
-
const n = await
|
|
32
|
-
if (
|
|
33
|
-
|
|
28
|
+
const t = await fetch(this.config.path);
|
|
29
|
+
if (t.ok) {
|
|
30
|
+
const n = await t.json();
|
|
31
|
+
if (_(n))
|
|
32
|
+
e = n;
|
|
34
33
|
else
|
|
35
34
|
throw new Error(
|
|
36
35
|
`Language path '${this.config.path}' did not return an object of language strings: ${n}`
|
|
@@ -39,47 +38,47 @@ class X {
|
|
|
39
38
|
throw new Error("HTTP request failed.");
|
|
40
39
|
}
|
|
41
40
|
}
|
|
42
|
-
if (
|
|
43
|
-
const
|
|
44
|
-
for (const n of
|
|
45
|
-
|
|
41
|
+
if (e) {
|
|
42
|
+
const t = g(this, p, S).call(this, e);
|
|
43
|
+
for (const n of t)
|
|
44
|
+
i(this, F).set(n[0], n[1]);
|
|
46
45
|
} else
|
|
47
46
|
throw new Error("Language could not be loaded.");
|
|
48
47
|
}
|
|
49
|
-
getTemplate(
|
|
50
|
-
return
|
|
51
|
-
segments: [{ type: 0, text: `[MISSING: ${
|
|
48
|
+
getTemplate(e) {
|
|
49
|
+
return i(this, F).get(e) ?? {
|
|
50
|
+
segments: [{ type: 0, text: `[MISSING: ${e}]` }]
|
|
52
51
|
};
|
|
53
52
|
}
|
|
54
|
-
hasTemplate(
|
|
55
|
-
return
|
|
53
|
+
hasTemplate(e) {
|
|
54
|
+
return i(this, F).has(e);
|
|
56
55
|
}
|
|
57
56
|
}
|
|
58
|
-
I = new WeakMap(), F = new WeakMap(), p = new WeakSet(), S = function(
|
|
57
|
+
I = new WeakMap(), F = new WeakMap(), p = new WeakSet(), S = function(e, t = []) {
|
|
59
58
|
const n = [];
|
|
60
|
-
for (const a in
|
|
61
|
-
switch (P(
|
|
59
|
+
for (const a in e)
|
|
60
|
+
switch (P(e[a])) {
|
|
62
61
|
case "string":
|
|
63
|
-
n.push([[...
|
|
62
|
+
n.push([[...t, a].join("."), g(this, p, G).call(this, e[a])]);
|
|
64
63
|
break;
|
|
65
64
|
case "object":
|
|
66
|
-
n.push(...g(this, p, S).call(this,
|
|
65
|
+
n.push(...g(this, p, S).call(this, e[a], [...t, a]));
|
|
67
66
|
break;
|
|
68
67
|
default:
|
|
69
68
|
throw new Error(
|
|
70
|
-
`Expected to find a string or object at ${[...
|
|
69
|
+
`Expected to find a string or object at ${[...t, a].join(".")}. Got: ${P(e[a])}`
|
|
71
70
|
);
|
|
72
71
|
}
|
|
73
72
|
return n;
|
|
74
|
-
}, G = function(
|
|
75
|
-
let
|
|
73
|
+
}, G = function(e) {
|
|
74
|
+
let t;
|
|
76
75
|
((f) => {
|
|
77
76
|
f[f.Static = 0] = "Static", f[f.ValueName = 1] = "ValueName", f[f.FormatName = 2] = "FormatName", f[f.FormatOptionName = 3] = "FormatOptionName", f[f.FormatOptionValue = 4] = "FormatOptionValue", f[f.FormatOptionEnd = 5] = "FormatOptionEnd";
|
|
78
|
-
})(
|
|
77
|
+
})(t || (t = {}));
|
|
79
78
|
const n = {
|
|
80
79
|
segments: []
|
|
81
80
|
};
|
|
82
|
-
let a = "", s = 0,
|
|
81
|
+
let a = "", s = 0, r = 0, c, w, l;
|
|
83
82
|
const $ = () => {
|
|
84
83
|
c = {
|
|
85
84
|
type: 1,
|
|
@@ -92,33 +91,33 @@ I = new WeakMap(), F = new WeakMap(), p = new WeakSet(), S = function(t, e = [])
|
|
|
92
91
|
options: {}
|
|
93
92
|
};
|
|
94
93
|
};
|
|
95
|
-
for (; s <
|
|
96
|
-
if (
|
|
94
|
+
for (; s < e.length; ) {
|
|
95
|
+
if (r !== 0 && e[s] === " ") {
|
|
97
96
|
s++;
|
|
98
97
|
continue;
|
|
99
98
|
}
|
|
100
|
-
switch (
|
|
99
|
+
switch (r) {
|
|
101
100
|
case 0:
|
|
102
|
-
|
|
101
|
+
e[s] === "{" && e[s + 1] === "{" ? (r = 1, s += 2, a.length > 0 && (n.segments.push({ type: 0, text: a }), a = ""), $()) : (a += e[s], s++);
|
|
103
102
|
break;
|
|
104
103
|
case 1:
|
|
105
|
-
|
|
104
|
+
e[s] === "|" ? (r = 2, s += 1, c.name = a, a = "", y()) : e[s] === "}" && e[s + 1] === "}" ? (r = 0, s += 2, c.name = a, a = "", n.segments.push(c)) : (a += e[s], s++);
|
|
106
105
|
break;
|
|
107
106
|
case 2:
|
|
108
|
-
|
|
107
|
+
e[s] === "(" ? (r = 3, s += 1, w.name = a, a = "") : e[s] === "}" && e[s + 1] === "}" ? (r = 0, s += 2, c.formats.push(w), n.segments.push(c)) : (a += e[s], s++);
|
|
109
108
|
break;
|
|
110
109
|
case 3:
|
|
111
|
-
|
|
110
|
+
e[s] === ")" || (e[s] === ":" ? (r = 4, s += 1, l = a, a = "") : e[s] === "}" && e[s + 1] === "}" || (a += e[s], s++));
|
|
112
111
|
break;
|
|
113
112
|
case 4:
|
|
114
|
-
|
|
113
|
+
e[s] === ")" ? (r = 5, s += 1, w.options[l] = a, a = "", c.formats.push(w)) : e[s] === "," ? (r = 3, s += 1, w.options[l] = a, a = "") : e[s] === "}" && e[s + 1] === "}" || (a += e[s], s++);
|
|
115
114
|
break;
|
|
116
115
|
case 5:
|
|
117
|
-
|
|
116
|
+
e[s] === "|" ? (r = 2, s += 1, y()) : e[s] === "}" && e[s + 1] === "}" && (r = 0, s += 2, n.segments.push(c));
|
|
118
117
|
break;
|
|
119
118
|
}
|
|
120
119
|
}
|
|
121
|
-
return
|
|
120
|
+
return r === 0 && a.length > 0 && n.segments.push({ type: 0, text: a }), n;
|
|
122
121
|
};
|
|
123
122
|
var b, h, E, T, v, d, u, H, L, V, M, A;
|
|
124
123
|
class Y {
|
|
@@ -129,49 +128,49 @@ class Y {
|
|
|
129
128
|
m(this, E, []);
|
|
130
129
|
m(this, T, /* @__PURE__ */ new Map());
|
|
131
130
|
m(this, v, "auto");
|
|
132
|
-
m(this, d,
|
|
133
|
-
|
|
134
|
-
N(this, b,
|
|
131
|
+
m(this, d, K("en"));
|
|
132
|
+
j(this, "$locale", k(i(this, d)));
|
|
133
|
+
N(this, b, Q("dolla.i18n")), this.addFormat("number", (e, t, n) => g(this, u, L).call(this, Number(t), n)), this.addFormat("datetime", (e, t, n) => g(this, u, V).call(this, t, n)), this.addFormat("list", (e, t, n) => g(this, u, M).call(this, t, n));
|
|
135
134
|
}
|
|
136
135
|
get locales() {
|
|
137
|
-
return [...
|
|
136
|
+
return [...i(this, h).keys()];
|
|
138
137
|
}
|
|
139
|
-
async setup(
|
|
140
|
-
if (
|
|
141
|
-
|
|
142
|
-
}),
|
|
143
|
-
if (!
|
|
144
|
-
throw new Error(`Initial locale '${
|
|
145
|
-
N(this, v,
|
|
138
|
+
async setup(e) {
|
|
139
|
+
if (e.translations.forEach((t) => {
|
|
140
|
+
i(this, h).set(t.locale, new X(t));
|
|
141
|
+
}), e.locale && e.locale !== "auto") {
|
|
142
|
+
if (!e.translations.some((n) => n.locale === e.locale))
|
|
143
|
+
throw new Error(`Initial locale '${e.locale}' is not registered in the locales array.`);
|
|
144
|
+
N(this, v, e.locale);
|
|
146
145
|
}
|
|
147
|
-
|
|
148
|
-
`${
|
|
149
|
-
),
|
|
146
|
+
i(this, b).info(
|
|
147
|
+
`${i(this, h).size} language${i(this, h).size === 1 ? "" : "s"} supported: '${[...i(this, h).keys()].join("', '")}'`
|
|
148
|
+
), i(this, h).size > 0 && await this.setLocale(i(this, v));
|
|
150
149
|
}
|
|
151
|
-
async setLocale(
|
|
150
|
+
async setLocale(e) {
|
|
152
151
|
var a;
|
|
153
|
-
let
|
|
154
|
-
if (
|
|
152
|
+
let t;
|
|
153
|
+
if (e === "auto") {
|
|
155
154
|
let s = [];
|
|
156
155
|
if (typeof navigator < "u") {
|
|
157
|
-
const
|
|
158
|
-
((a =
|
|
156
|
+
const r = navigator;
|
|
157
|
+
((a = r.languages) == null ? void 0 : a.length) > 0 ? s.push(...r.languages) : r.language ? s.push(r.language) : r.browserLanguage ? s.push(r.browserLanguage) : r.userLanguage && s.push(r.userLanguage);
|
|
159
158
|
}
|
|
160
|
-
for (const
|
|
161
|
-
|
|
159
|
+
for (const r of s)
|
|
160
|
+
i(this, h).has(r) && (t = r);
|
|
162
161
|
} else
|
|
163
|
-
|
|
164
|
-
if (
|
|
165
|
-
const s =
|
|
166
|
-
s && (
|
|
162
|
+
i(this, h).has(e) && (t = e);
|
|
163
|
+
if (t == null) {
|
|
164
|
+
const s = i(this, h).keys().next().value;
|
|
165
|
+
s && (t = s);
|
|
167
166
|
}
|
|
168
|
-
if (!
|
|
169
|
-
throw new Error(`Locale '${
|
|
170
|
-
const n =
|
|
167
|
+
if (!t || !i(this, h).has(t))
|
|
168
|
+
throw new Error(`Locale '${e}' has no translation.`);
|
|
169
|
+
const n = i(this, h).get(t);
|
|
171
170
|
try {
|
|
172
|
-
await n.load(), N(this, E, []),
|
|
171
|
+
await n.load(), N(this, E, []), i(this, d).set(t), i(this, b).info("set language to " + t);
|
|
173
172
|
} catch (s) {
|
|
174
|
-
s instanceof Error &&
|
|
173
|
+
s instanceof Error && i(this, b).crash(s);
|
|
175
174
|
}
|
|
176
175
|
}
|
|
177
176
|
/**
|
|
@@ -183,16 +182,16 @@ class Y {
|
|
|
183
182
|
* @example
|
|
184
183
|
* const $value = t("your.key.here", { count: 5 });
|
|
185
184
|
*/
|
|
186
|
-
t(
|
|
185
|
+
t(e, t) {
|
|
187
186
|
if (this === void 0)
|
|
188
187
|
throw new Error(
|
|
189
188
|
`The 't' function cannot be destructured. If you need a standalone version you can import it like so: 'import { t } from "@manyducks.co/dolla"'`
|
|
190
189
|
);
|
|
191
190
|
return k(() => {
|
|
192
191
|
const n = {};
|
|
193
|
-
for (const a in
|
|
194
|
-
n[a] = x(
|
|
195
|
-
return g(this, u, H).call(this,
|
|
192
|
+
for (const a in t)
|
|
193
|
+
n[a] = x(t[a]);
|
|
194
|
+
return g(this, u, H).call(this, i(this, d).call(this), e, n);
|
|
196
195
|
});
|
|
197
196
|
}
|
|
198
197
|
/**
|
|
@@ -209,8 +208,8 @@ class Y {
|
|
|
209
208
|
*
|
|
210
209
|
* t("greeting", {name: "world"}); // State<"Hello, WORLD!">
|
|
211
210
|
*/
|
|
212
|
-
addFormat(
|
|
213
|
-
|
|
211
|
+
addFormat(e, t) {
|
|
212
|
+
i(this, T).set(e, t);
|
|
214
213
|
}
|
|
215
214
|
/**
|
|
216
215
|
* Creates an `Intl.Collator` configured for the current locale.
|
|
@@ -218,16 +217,16 @@ class Y {
|
|
|
218
217
|
*
|
|
219
218
|
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator/Collator#options
|
|
220
219
|
*/
|
|
221
|
-
collator(
|
|
222
|
-
return new Intl.Collator(
|
|
220
|
+
collator(e) {
|
|
221
|
+
return new Intl.Collator(i(this, d).call(this), e);
|
|
223
222
|
}
|
|
224
223
|
/**
|
|
225
224
|
* Formats a number for the current locale. Uses `Intl.NumberFormat` under the hood.
|
|
226
225
|
*
|
|
227
226
|
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options
|
|
228
227
|
*/
|
|
229
|
-
number(
|
|
230
|
-
return k(() => g(this, u, L).call(this, x(
|
|
228
|
+
number(e, t) {
|
|
229
|
+
return k(() => g(this, u, L).call(this, x(e), t));
|
|
231
230
|
}
|
|
232
231
|
/**
|
|
233
232
|
* Formats a date for the current locale. Uses `Intl.DateTimeFormat` under the hood.
|
|
@@ -238,8 +237,8 @@ class Y {
|
|
|
238
237
|
* const date = new Date();
|
|
239
238
|
* const $formatted = Dolla.i18n.dateTime(date, { dateFormat: "short" });
|
|
240
239
|
*/
|
|
241
|
-
dateTime(
|
|
242
|
-
return k(() => g(this, u, V).call(this, x(
|
|
240
|
+
dateTime(e, t) {
|
|
241
|
+
return k(() => g(this, u, V).call(this, x(e), t));
|
|
243
242
|
}
|
|
244
243
|
/**
|
|
245
244
|
* Formats a list for the current locale. Uses `Intl.ListFormat` under the hood.
|
|
@@ -250,26 +249,26 @@ class Y {
|
|
|
250
249
|
* const list = new Date();
|
|
251
250
|
* const $formatted = Dolla.i18n.list(list, { });
|
|
252
251
|
*/
|
|
253
|
-
list(
|
|
254
|
-
return k(() => g(this, u, M).call(this, x(
|
|
252
|
+
list(e, t) {
|
|
253
|
+
return k(() => g(this, u, M).call(this, x(e), t));
|
|
255
254
|
}
|
|
256
255
|
}
|
|
257
|
-
b = new WeakMap(), h = new WeakMap(), E = new WeakMap(), T = new WeakMap(), v = new WeakMap(), d = new WeakMap(), u = new WeakSet(), H = function(
|
|
256
|
+
b = new WeakMap(), h = new WeakMap(), E = new WeakMap(), T = new WeakMap(), v = new WeakMap(), d = new WeakMap(), u = new WeakSet(), H = function(e, t, n) {
|
|
258
257
|
var w;
|
|
259
|
-
const a = g(this, u, A).call(this,
|
|
258
|
+
const a = g(this, u, A).call(this, t, n);
|
|
260
259
|
if (a) return a;
|
|
261
|
-
const s =
|
|
262
|
-
if (n.context != null && (
|
|
260
|
+
const s = i(this, h).get(e);
|
|
261
|
+
if (n.context != null && (t += "_" + n.context), n.count != null)
|
|
263
262
|
if (n.ordinal) {
|
|
264
|
-
const l = `${
|
|
265
|
-
s.hasTemplate(l) ?
|
|
263
|
+
const l = `${t}_ordinal_(=${n.count})`;
|
|
264
|
+
s.hasTemplate(l) ? t = l : t += "_ordinal_" + new Intl.PluralRules(e, { type: "ordinal" }).select(n.count);
|
|
266
265
|
} else {
|
|
267
|
-
const l = `${
|
|
268
|
-
s.hasTemplate(l) ?
|
|
266
|
+
const l = `${t}_(=${n.count})`;
|
|
267
|
+
s.hasTemplate(l) ? t = l : t += "_" + new Intl.PluralRules(e).select(n.count);
|
|
269
268
|
}
|
|
270
|
-
const
|
|
269
|
+
const r = s.getTemplate(t);
|
|
271
270
|
let c = "";
|
|
272
|
-
for (const l of
|
|
271
|
+
for (const l of r.segments)
|
|
273
272
|
if (l.type === 0)
|
|
274
273
|
c += l.text;
|
|
275
274
|
else if (l.type === 1) {
|
|
@@ -277,42 +276,42 @@ b = new WeakMap(), h = new WeakMap(), E = new WeakMap(), T = new WeakMap(), v =
|
|
|
277
276
|
const y = ((w = n.formatOverrides) == null ? void 0 : w[l.name]) ?? [...l.formats];
|
|
278
277
|
l.name === "count" && y.length === 0 && y.push({ name: "number", options: {} });
|
|
279
278
|
for (const f of y) {
|
|
280
|
-
const R =
|
|
279
|
+
const R = i(this, T).get(f.name);
|
|
281
280
|
if (R == null) {
|
|
282
281
|
const z = new Error(
|
|
283
|
-
`Failed to load format '${f.name}' when processing '${
|
|
282
|
+
`Failed to load format '${f.name}' when processing '${t}', template: ${r}`
|
|
284
283
|
);
|
|
285
|
-
throw
|
|
284
|
+
throw i(this, b).crash(z), z;
|
|
286
285
|
}
|
|
287
|
-
$ = R(
|
|
286
|
+
$ = R(e, $, f.options);
|
|
288
287
|
}
|
|
289
288
|
c += $;
|
|
290
289
|
}
|
|
291
290
|
return c;
|
|
292
|
-
}, L = function(
|
|
293
|
-
return new Intl.NumberFormat(
|
|
294
|
-
}, V = function(
|
|
295
|
-
return new Intl.DateTimeFormat(
|
|
296
|
-
}, M = function(
|
|
297
|
-
return new Intl.ListFormat(
|
|
291
|
+
}, L = function(e, t) {
|
|
292
|
+
return new Intl.NumberFormat(i(this, d).call(this), t).format(e);
|
|
293
|
+
}, V = function(e, t) {
|
|
294
|
+
return new Intl.DateTimeFormat(i(this, d).call(this), t).format(C(e) ? new Date(e) : e);
|
|
295
|
+
}, M = function(e, t) {
|
|
296
|
+
return new Intl.ListFormat(i(this, d).call(this), t).format(e);
|
|
298
297
|
}, // relativeTime(date?: MaybeSignal<string | number | Date | undefined>): Signal<string> {}
|
|
299
|
-
A = function(
|
|
300
|
-
for (const n of
|
|
301
|
-
if (n[0] ===
|
|
298
|
+
A = function(e, t) {
|
|
299
|
+
for (const n of i(this, E))
|
|
300
|
+
if (n[0] === e && U(n[1], t))
|
|
302
301
|
return n[2];
|
|
303
302
|
};
|
|
304
|
-
function Z(o,
|
|
305
|
-
const
|
|
303
|
+
function Z(o, e) {
|
|
304
|
+
const t = String(e).split(/[\.\[\]]/).filter((a) => a.trim() !== "");
|
|
306
305
|
let n = o;
|
|
307
|
-
for (;
|
|
308
|
-
const a =
|
|
306
|
+
for (; t.length > 0; ) {
|
|
307
|
+
const a = t.shift();
|
|
309
308
|
n != null ? n = n[a] : n = void 0;
|
|
310
309
|
}
|
|
311
310
|
return n;
|
|
312
311
|
}
|
|
313
|
-
const q = new Y(),
|
|
312
|
+
const q = new Y(), ne = q.t.bind(q);
|
|
314
313
|
export {
|
|
315
314
|
q as i18n,
|
|
316
|
-
|
|
315
|
+
ne as t
|
|
317
316
|
};
|
|
318
317
|
//# sourceMappingURL=i18n.js.map
|
package/dist/i18n.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i18n.js","sources":["../src/i18n/index.ts"],"sourcesContent":["import { createLogger, type Logger } from \"../core/logger.js\";\nimport { writable, get, type MaybeSignal, type Signal, memo } from \"../core/signals.js\";\nimport { isFunction, isObject, isString, typeOf } from \"../typeChecking.js\";\nimport { deepEqual } from \"../utils.js\";\n\n// ----- Types ----- //\n\n/**\n * A JSON object of translated strings. Values can be string templates or nested objects.\n */\ninterface LocalizedStrings extends Record<string, string | LocalizedStrings> {}\n\nenum SegmentType {\n Static,\n Variable,\n}\ntype StringTemplate = { segments: (StaticSegment | VariableSegment)[] };\n/**\n * A string segment with literal text to be appended without processing.\n */\ntype StaticSegment = {\n type: SegmentType.Static;\n text: string;\n};\n/**\n * A variable passed to the t() function. Needs to be formatted before it is appended.\n */\ntype VariableSegment = {\n type: SegmentType.Variable;\n name: string;\n formats: Format[];\n};\n/**\n * A formatter to be applied to a variable.\n */\ntype Format = {\n name: string;\n options: Record<string, any>;\n};\n\nexport interface TranslationConfig {\n /**\n * Name of the locale this translation is for (BCP 47 locale names recommended).\n */\n locale: string;\n\n /**\n * An object with translated strings for this language.\n */\n strings?: LocalizedStrings;\n\n /**\n * A callback function that returns a Promise that resolves to the translation object for this language.\n */\n fetch?: () => Promise<LocalizedStrings>;\n\n /**\n * Path to a JSON file with translated strings for this language.\n */\n path?: string;\n}\n\nexport type I18nSetupOptions = {\n /**\n * Default locale to load on startup\n */\n locale?: string | null;\n\n translations: TranslationConfig[];\n};\n\nexport type TOptions = {\n /**\n *\n */\n count?: MaybeSignal<number>;\n\n /**\n *\n */\n context?: MaybeSignal<string>;\n\n /**\n * Override formats specified in the template with the ones in the array for each named variable.\n *\n * @example\n * t(\"example_key\", {\n * count: 5,\n * formatOverrides: {\n * count: [ { name: \"datetime\", options: { style: \"currency\", currency: \"JPY\" } } ]\n * }\n * });\n */\n formatOverrides?: MaybeSignal<Record<string, Record<string, Format[]>>>;\n\n [value: string]: MaybeSignal<any>;\n};\n\nexport type Formatter = (locale: string, value: unknown, options: Record<string, any>) => string;\n\n// ----- Code ----- //\n\nclass Translation {\n config: TranslationConfig;\n\n #isLoaded = false;\n\n #templates = new Map<string, StringTemplate>();\n\n constructor(config: TranslationConfig) {\n this.config = config;\n }\n\n async load(): Promise<void> {\n let strings: LocalizedStrings | undefined;\n\n if (!this.#isLoaded) {\n if (isObject(this.config.strings)) {\n strings = this.config.strings;\n } else if (isFunction(this.config.fetch)) {\n strings = await this.config.fetch();\n if (!isObject(strings)) {\n throw new Error(`Fetch function did not return an object of language strings: ${strings}`);\n }\n } else if (isString(this.config.path)) {\n const res = await fetch(this.config.path);\n if (res.ok) {\n const body = await res.json();\n if (isObject(body)) {\n strings = body as LocalizedStrings;\n } else {\n throw new Error(\n `Language path '${this.config.path}' did not return an object of language strings: ${body}`,\n );\n }\n } else {\n throw new Error(`HTTP request failed.`);\n }\n }\n }\n\n if (strings) {\n const entries = this.#compile(strings);\n for (const entry of entries) {\n this.#templates.set(entry[0], entry[1]);\n }\n } else {\n throw new Error(`Language could not be loaded.`);\n }\n }\n\n getTemplate(selector: string): StringTemplate {\n return (\n this.#templates.get(selector) ?? {\n segments: [{ type: SegmentType.Static, text: `[MISSING: ${selector}]` }],\n }\n );\n }\n\n hasTemplate(selector: string): boolean {\n return this.#templates.has(selector);\n }\n\n #compile(strings: { [key: string]: any }, path: string[] = []): [string, StringTemplate][] {\n const entries: [string, StringTemplate][] = [];\n\n for (const key in strings) {\n switch (typeOf(strings[key])) {\n case \"string\":\n entries.push([[...path, key].join(\".\"), this.#parseTemplate(strings[key])]);\n break;\n case \"object\":\n entries.push(...this.#compile(strings[key], [...path, key]));\n break;\n default:\n throw new Error(\n `Expected to find a string or object at ${[...path, key].join(\".\")}. Got: ${typeOf(strings[key])}`,\n );\n }\n }\n\n return entries;\n }\n\n #parseTemplate(template: string): StringTemplate {\n // \"{{itemName}} costs {{amount | number(style: currency, currency: USD)}}.\"\n\n enum Loc {\n /**\n * Outside value braces.\n */\n Static,\n /**\n * Inside value braces; currently parsing the name of the value. e.g. `{{ [name] | number(style: currency, currency: USD) }}`\n */\n ValueName,\n /**\n * Inside value braces; currently parsing the name of a format function. e.g. `{{ name | [number](style: currency, currency: USD) }}`\n */\n FormatName,\n /**\n * Inside value braces; currently parsing the name of a format option. e.g. `{{ name | number([style]: currency, currency: USD) }}`\n */\n FormatOptionName,\n /**\n * Inside value braces; currently parsing the value of a format option. e.g. `{{ name | number(style: [currency], currency: USD ) }}`\n */\n FormatOptionValue,\n /**\n * Inside value braces; just reached the closing bracket of a format option. e.g. `{{ name | number(style: [currency], currency: USD) [] }}`\n */\n FormatOptionEnd,\n }\n\n const parsed: StringTemplate = {\n segments: [],\n };\n\n let buffer = \"\";\n let i = 0;\n let loc: Loc = Loc.Static;\n let segment!: VariableSegment;\n let format!: VariableSegment[\"formats\"][0];\n\n let formatOptionName!: string;\n\n const startSegment = () => {\n segment = {\n type: SegmentType.Variable,\n name: \"\",\n formats: [],\n };\n };\n\n const startFormat = () => {\n format = {\n name: \"\",\n options: {},\n };\n };\n\n while (i < template.length) {\n // Skip spaces (unless we're in static)\n if (loc !== Loc.Static && template[i] === \" \") {\n i++;\n continue;\n }\n\n switch (loc) {\n case Loc.Static:\n if (template[i] === \"{\" && template[i + 1] === \"{\") {\n loc = Loc.ValueName;\n i += 2;\n // close static segment\n if (buffer.length > 0) {\n parsed.segments.push({ type: SegmentType.Static, text: buffer });\n buffer = \"\";\n }\n startSegment();\n } else {\n buffer += template[i];\n i++;\n }\n break;\n case Loc.ValueName:\n if (template[i] === \"|\") {\n loc = Loc.FormatName;\n i += 1;\n // add name to value segment\n segment.name = buffer;\n buffer = \"\";\n startFormat();\n } else if (template[i] === \"}\" && template[i + 1] === \"}\") {\n loc = Loc.Static;\n i += 2;\n // close value segment\n segment.name = buffer;\n buffer = \"\";\n parsed.segments.push(segment);\n } else {\n buffer += template[i];\n i++;\n }\n break;\n case Loc.FormatName:\n if (template[i] === \"(\") {\n loc = Loc.FormatOptionName;\n i += 1;\n // add name to format object\n format.name = buffer;\n buffer = \"\";\n } else if (template[i] === \"}\" && template[i + 1] === \"}\") {\n loc = Loc.Static;\n i += 2;\n // close format and value segment\n segment.formats.push(format);\n parsed.segments.push(segment);\n } else {\n buffer += template[i];\n i++;\n }\n break;\n case Loc.FormatOptionName:\n if (template[i] === \")\") {\n // TODO: error - no value provided for option\n } else if (template[i] === \":\") {\n loc = Loc.FormatOptionValue;\n i += 1;\n // add name to format option object\n formatOptionName = buffer;\n buffer = \"\";\n } else if (template[i] === \"}\" && template[i + 1] === \"}\") {\n // TODO: error - format options parenthesis not closed\n } else {\n buffer += template[i];\n i++;\n }\n break;\n case Loc.FormatOptionValue:\n if (template[i] === \")\") {\n loc = Loc.FormatOptionEnd;\n i += 1;\n // add value to format option object\n // add format option to format object; we're done with this format\n format.options[formatOptionName] = buffer;\n buffer = \"\";\n segment.formats.push(format);\n } else if (template[i] === \",\") {\n loc = Loc.FormatOptionName;\n i += 1;\n // add value to format option object\n // add format option to format object; we're adding another option\n format.options[formatOptionName] = buffer;\n buffer = \"\";\n } else if (template[i] === \"}\" && template[i + 1] === \"}\") {\n // TODO: error - format options parenthesis not closed\n } else {\n buffer += template[i];\n i++;\n }\n break;\n case Loc.FormatOptionEnd:\n if (template[i] === \"|\") {\n loc = Loc.FormatName;\n i += 1;\n startFormat();\n } else if (template[i] === \"}\" && template[i + 1] === \"}\") {\n loc = Loc.Static;\n i += 2;\n // add value segment\n parsed.segments.push(segment);\n } else {\n // TODO: error - no other valid characters\n }\n break;\n }\n }\n\n if (loc === Loc.Static && buffer.length > 0) {\n parsed.segments.push({ type: SegmentType.Static, text: buffer });\n }\n\n return parsed;\n }\n}\n\n/**\n * Dolla's I(nternationalizatio)n module. Manages language translations and locale-based formatting.\n */\nclass I18n {\n #logger: Logger;\n #translations = new Map<string, Translation>();\n #cache: [key: string, values: Record<string, any> | undefined, output: string][] = [];\n #formats = new Map<string, Formatter>();\n\n #initialLocale = \"auto\";\n\n #locale = writable<string>(\"en\");\n\n readonly $locale = memo(this.#locale);\n\n constructor() {\n this.#logger = createLogger(\"dolla.i18n\");\n\n this.addFormat(\"number\", (_, value, options) => {\n return this.#formatNumber(Number(value), options);\n });\n this.addFormat(\"datetime\", (_, value, options) => {\n return this.#formatDateTime(value as any, options);\n });\n this.addFormat(\"list\", (_, value, options) => {\n return this.#formatList(value as any, options);\n });\n }\n\n get locales() {\n return [...this.#translations.keys()];\n }\n\n async setup(options: I18nSetupOptions) {\n // Convert languages into Language instances.\n options.translations.forEach((entry) => {\n this.#translations.set(entry.locale, new Translation(entry));\n });\n\n // Check that initialLanguage is actually registered.\n if (options.locale && options.locale !== \"auto\") {\n const isRegistered = options.translations.some((entry) => entry.locale === options.locale);\n if (!isRegistered) {\n throw new Error(`Initial locale '${options.locale}' is not registered in the locales array.`);\n }\n this.#initialLocale = options.locale;\n }\n\n this.#logger.info(\n `${this.#translations.size} language${this.#translations.size === 1 ? \"\" : \"s\"} supported: '${[...this.#translations.keys()].join(\"', '\")}'`,\n );\n\n if (this.#translations.size > 0) {\n await this.setLocale(this.#initialLocale);\n }\n }\n\n async setLocale(name: string) {\n let realName!: string;\n\n if (name === \"auto\") {\n let names = [];\n\n if (typeof navigator !== \"undefined\") {\n const nav = navigator as any;\n\n if (nav.languages?.length > 0) {\n names.push(...nav.languages);\n } else if (nav.language) {\n names.push(nav.language);\n } else if (nav.browserLanguage) {\n names.push(nav.browserLanguage);\n } else if (nav.userLanguage) {\n names.push(nav.userLanguage);\n }\n }\n\n for (const name of names) {\n if (this.#translations.has(name)) {\n // Found a matching language.\n realName = name;\n }\n }\n } else {\n // Tag is the actual tag to set.\n if (this.#translations.has(name)) {\n realName = name;\n }\n }\n\n if (realName == null) {\n const firstLanguage = this.#translations.keys().next().value;\n if (firstLanguage) {\n realName = firstLanguage;\n }\n }\n\n if (!realName || !this.#translations.has(realName)) {\n throw new Error(`Locale '${name}' has no translation.`);\n }\n\n const translation = this.#translations.get(realName)!;\n\n try {\n await translation.load();\n\n this.#cache = [];\n this.#locale.set(realName);\n\n this.#logger.info(\"set language to \" + realName);\n } catch (error) {\n if (error instanceof Error) {\n this.#logger.crash(error);\n }\n }\n }\n\n /**\n * Returns a State containing the value at `key`.\n\n * @param selector - Key to the translated value.\n * @param options - A map of `{{placeholder}}` names and the values to replace them with.\n *\n * @example\n * const $value = t(\"your.key.here\", { count: 5 });\n */\n t(selector: string, options?: TOptions): Signal<string> {\n if (this === undefined) {\n throw new Error(\n `The 't' function cannot be destructured. If you need a standalone version you can import it like so: 'import { t } from \"@manyducks.co/dolla\"'`,\n );\n }\n\n return memo(() => {\n const values: Record<string, any> = {};\n\n // Track all option values.\n for (const key in options) {\n values[key] = get(options[key]);\n }\n\n return this.#getValue(this.#locale(), selector, values);\n });\n }\n\n #getValue(locale: string, selector: string, options: Record<string, any>): string {\n const cached = this.#getCached(selector, options);\n if (cached) return cached;\n\n const translation = this.#translations.get(locale)!;\n\n // Handle count (pluralization) and context. Keys become \"key_context_pluralization\".\n\n if (options.context != null) {\n selector += \"_\" + options.context;\n }\n if (options.count != null) {\n if (options.ordinal) {\n // Try to match the exact number key if there is one (e.g. \"myExampleKey_ordinal_(=2)\" when count is 2).\n const exact = `${selector}_ordinal_(=${options.count})`;\n if (translation.hasTemplate(exact)) {\n selector = exact;\n } else {\n selector += \"_ordinal_\" + new Intl.PluralRules(locale, { type: \"ordinal\" }).select(options.count);\n }\n } else {\n // Try to match the exact number key if there is one (e.g. \"myExampleKey_(=2)\" when count is 2).\n const exact = `${selector}_(=${options.count})`;\n if (translation.hasTemplate(exact)) {\n selector = exact;\n } else {\n selector += \"_\" + new Intl.PluralRules(locale).select(options.count);\n }\n }\n }\n\n const template = translation.getTemplate(selector);\n let output = \"\";\n\n for (const segment of template.segments) {\n if (segment.type === SegmentType.Static) {\n output += segment.text;\n } else if (segment.type === SegmentType.Variable) {\n let value = resolve(options, segment.name);\n\n const formats = options.formatOverrides?.[segment.name] ?? [...segment.formats];\n\n if (segment.name === \"count\" && formats.length === 0) {\n formats.push({ name: \"number\", options: {} });\n }\n\n for (const format of formats) {\n const fn = this.#formats.get(format.name);\n if (fn == null) {\n const error = new Error(\n `Failed to load format '${format.name}' when processing '${selector}', template: ${template}`,\n );\n this.#logger.crash(error);\n throw error;\n }\n value = fn(locale, value, format.options);\n }\n\n output += value;\n }\n }\n\n return output;\n }\n\n /**\n * Add a custom format callback.\n *\n * @example\n * Dolla.i18n.addFormat(\"uppercase\", (locale, value, options) => {\n * return value.toUpperCase();\n * });\n *\n * {\n * \"greeting\": \"Hello, {{name|uppercase}}!\"\n * }\n *\n * t(\"greeting\", {name: \"world\"}); // State<\"Hello, WORLD!\">\n */\n addFormat(name: string, callback: (locale: string, value: unknown, options: Record<string, any>) => string) {\n this.#formats.set(name, callback);\n }\n\n /**\n * Creates an `Intl.Collator` configured for the current locale.\n * NOTE: The locale is tracked if called within a signal tracking context.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator/Collator#options\n */\n collator(options?: Intl.CollatorOptions) {\n return new Intl.Collator(this.#locale(), options);\n }\n\n /**\n * Formats a number for the current locale. Uses `Intl.NumberFormat` under the hood.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options\n */\n number(count: MaybeSignal<number | bigint>, options?: Intl.NumberFormatOptions): Signal<string> {\n return memo(() => this.#formatNumber(get(count), options));\n }\n\n #formatNumber(count: number | bigint, options?: Intl.NumberFormatOptions): string {\n // NOTE: Locale is tracked if called within a tracking context.\n return new Intl.NumberFormat(this.#locale(), options).format(count);\n }\n\n /**\n * Formats a date for the current locale. Uses `Intl.DateTimeFormat` under the hood.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#options\n *\n * @example\n * const date = new Date();\n * const $formatted = Dolla.i18n.dateTime(date, { dateFormat: \"short\" });\n */\n dateTime(\n date?: MaybeSignal<string | number | Date | undefined>,\n options?: Intl.DateTimeFormatOptions,\n ): Signal<string> {\n return memo(() => this.#formatDateTime(get(date), options));\n }\n\n #formatDateTime(date?: string | number | Date, options?: Intl.DateTimeFormatOptions): string {\n // NOTE: Locale is tracked if called within a tracking context.\n return new Intl.DateTimeFormat(this.#locale(), options).format(isString(date) ? new Date(date) : date);\n }\n\n /**\n * Formats a list for the current locale. Uses `Intl.ListFormat` under the hood.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#options\n *\n * @example\n * const list = new Date();\n * const $formatted = Dolla.i18n.list(list, { });\n */\n list(list: MaybeSignal<Iterable<string>>, options?: Intl.ListFormatOptions): Signal<string> {\n return memo(() => this.#formatList(get(list), options));\n }\n\n #formatList(list: Iterable<string>, options?: Intl.ListFormatOptions): string {\n // NOTE: Locale is tracked if called within a tracking context.\n return new Intl.ListFormat(this.#locale(), options).format(list);\n }\n\n // relativeTime(date?: MaybeSignal<string | number | Date | undefined>): Signal<string> {}\n\n #getCached(key: string, values?: Record<string, any>): string | undefined {\n for (const entry of this.#cache) {\n if (entry[0] === key && deepEqual(entry[1], values)) {\n return entry[2];\n }\n }\n }\n}\n\nfunction resolve(object: any, key: string) {\n const parsed = String(key)\n .split(/[\\.\\[\\]]/)\n .filter((part) => part.trim() !== \"\");\n let value = object;\n\n while (parsed.length > 0) {\n const part = parsed.shift()!;\n\n if (value != null) {\n value = value[part];\n } else {\n value = undefined;\n }\n }\n\n return value;\n}\n\nexport const i18n = new I18n();\nexport const t = i18n.t.bind(i18n);\n"],"names":["Translation","config","__privateAdd","_Translation_instances","__publicField","_isLoaded","_templates","strings","__privateGet","isObject","isFunction","isString","res","body","entries","__privateMethod","compile_fn","entry","selector","path","key","typeOf","parseTemplate_fn","template","Loc","Loc2","parsed","buffer","i","loc","segment","format","formatOptionName","startSegment","startFormat","I18n","_I18n_instances","_logger","_translations","_cache","_formats","_initialLocale","_locale","writable","memo","__privateSet","createLogger","_","value","options","formatNumber_fn","formatDateTime_fn","formatList_fn","name","realName","names","nav","_a","firstLanguage","translation","error","values","get","getValue_fn","callback","count","date","list","locale","cached","getCached_fn","exact","output","resolve","formats","fn","deepEqual","object","part","i18n","t"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"i18n.js","sources":["../src/i18n/index.ts"],"sourcesContent":["import { createLogger, type Logger } from \"../core/logger.js\";\nimport { writable, get, type MaybeSignal, type Signal, memo } from \"../core/signals.js\";\nimport { isFunction, isObject, isString, typeOf } from \"../typeChecking.js\";\nimport { deepEqual } from \"../utils.js\";\n\n// ----- Types ----- //\n\n/**\n * A JSON object of translated strings. Values can be string templates or nested objects.\n */\ninterface LocalizedStrings extends Record<string, string | LocalizedStrings> {}\n\nenum SegmentType {\n Static,\n Variable,\n}\ntype StringTemplate = { segments: (StaticSegment | VariableSegment)[] };\n/**\n * A string segment with literal text to be appended without processing.\n */\ntype StaticSegment = {\n type: SegmentType.Static;\n text: string;\n};\n/**\n * A variable passed to the t() function. Needs to be formatted before it is appended.\n */\ntype VariableSegment = {\n type: SegmentType.Variable;\n name: string;\n formats: Format[];\n};\n/**\n * A formatter to be applied to a variable.\n */\ntype Format = {\n name: string;\n options: Record<string, any>;\n};\n\nexport interface TranslationConfig {\n /**\n * Name of the locale this translation is for (BCP 47 locale names recommended).\n */\n locale: string;\n\n /**\n * An object with translated strings for this language.\n */\n strings?: LocalizedStrings;\n\n /**\n * A callback function that returns a Promise that resolves to the translation object for this language.\n */\n fetch?: () => Promise<LocalizedStrings>;\n\n /**\n * Path to a JSON file with translated strings for this language.\n */\n path?: string;\n}\n\nexport type I18nSetupOptions = {\n /**\n * Default locale to load on startup\n */\n locale?: string | null;\n\n translations: TranslationConfig[];\n};\n\nexport type TOptions = {\n /**\n *\n */\n count?: MaybeSignal<number>;\n\n /**\n *\n */\n context?: MaybeSignal<string>;\n\n /**\n * Override formats specified in the template with the ones in the array for each named variable.\n *\n * @example\n * t(\"example_key\", {\n * count: 5,\n * formatOverrides: {\n * count: [ { name: \"datetime\", options: { style: \"currency\", currency: \"JPY\" } } ]\n * }\n * });\n */\n formatOverrides?: MaybeSignal<Record<string, Record<string, Format[]>>>;\n\n [value: string]: MaybeSignal<any>;\n};\n\nexport type Formatter = (locale: string, value: unknown, options: Record<string, any>) => string;\n\n// ----- Code ----- //\n\nclass Translation {\n config: TranslationConfig;\n\n #isLoaded = false;\n\n #templates = new Map<string, StringTemplate>();\n\n constructor(config: TranslationConfig) {\n this.config = config;\n }\n\n async load(): Promise<void> {\n let strings: LocalizedStrings | undefined;\n\n if (!this.#isLoaded) {\n if (isObject(this.config.strings)) {\n strings = this.config.strings;\n } else if (isFunction(this.config.fetch)) {\n strings = await this.config.fetch();\n if (!isObject(strings)) {\n throw new Error(`Fetch function did not return an object of language strings: ${strings}`);\n }\n } else if (isString(this.config.path)) {\n const res = await fetch(this.config.path);\n if (res.ok) {\n const body = await res.json();\n if (isObject(body)) {\n strings = body as LocalizedStrings;\n } else {\n throw new Error(\n `Language path '${this.config.path}' did not return an object of language strings: ${body}`,\n );\n }\n } else {\n throw new Error(`HTTP request failed.`);\n }\n }\n }\n\n if (strings) {\n const entries = this.#compile(strings);\n for (const entry of entries) {\n this.#templates.set(entry[0], entry[1]);\n }\n } else {\n throw new Error(`Language could not be loaded.`);\n }\n }\n\n getTemplate(selector: string): StringTemplate {\n return (\n this.#templates.get(selector) ?? {\n segments: [{ type: SegmentType.Static, text: `[MISSING: ${selector}]` }],\n }\n );\n }\n\n hasTemplate(selector: string): boolean {\n return this.#templates.has(selector);\n }\n\n #compile(strings: { [key: string]: any }, path: string[] = []): [string, StringTemplate][] {\n const entries: [string, StringTemplate][] = [];\n\n for (const key in strings) {\n switch (typeOf(strings[key])) {\n case \"string\":\n entries.push([[...path, key].join(\".\"), this.#parseTemplate(strings[key])]);\n break;\n case \"object\":\n entries.push(...this.#compile(strings[key], [...path, key]));\n break;\n default:\n throw new Error(\n `Expected to find a string or object at ${[...path, key].join(\".\")}. Got: ${typeOf(strings[key])}`,\n );\n }\n }\n\n return entries;\n }\n\n #parseTemplate(template: string): StringTemplate {\n // \"{{itemName}} costs {{amount | number(style: currency, currency: USD)}}.\"\n\n enum Loc {\n /**\n * Outside value braces.\n */\n Static,\n /**\n * Inside value braces; currently parsing the name of the value. e.g. `{{ [name] | number(style: currency, currency: USD) }}`\n */\n ValueName,\n /**\n * Inside value braces; currently parsing the name of a format function. e.g. `{{ name | [number](style: currency, currency: USD) }}`\n */\n FormatName,\n /**\n * Inside value braces; currently parsing the name of a format option. e.g. `{{ name | number([style]: currency, currency: USD) }}`\n */\n FormatOptionName,\n /**\n * Inside value braces; currently parsing the value of a format option. e.g. `{{ name | number(style: [currency], currency: USD ) }}`\n */\n FormatOptionValue,\n /**\n * Inside value braces; just reached the closing bracket of a format option. e.g. `{{ name | number(style: [currency], currency: USD) [] }}`\n */\n FormatOptionEnd,\n }\n\n const parsed: StringTemplate = {\n segments: [],\n };\n\n let buffer = \"\";\n let i = 0;\n let loc: Loc = Loc.Static;\n let segment!: VariableSegment;\n let format!: VariableSegment[\"formats\"][0];\n\n let formatOptionName!: string;\n\n const startSegment = () => {\n segment = {\n type: SegmentType.Variable,\n name: \"\",\n formats: [],\n };\n };\n\n const startFormat = () => {\n format = {\n name: \"\",\n options: {},\n };\n };\n\n while (i < template.length) {\n // Skip spaces (unless we're in static)\n if (loc !== Loc.Static && template[i] === \" \") {\n i++;\n continue;\n }\n\n switch (loc) {\n case Loc.Static:\n if (template[i] === \"{\" && template[i + 1] === \"{\") {\n loc = Loc.ValueName;\n i += 2;\n // close static segment\n if (buffer.length > 0) {\n parsed.segments.push({ type: SegmentType.Static, text: buffer });\n buffer = \"\";\n }\n startSegment();\n } else {\n buffer += template[i];\n i++;\n }\n break;\n case Loc.ValueName:\n if (template[i] === \"|\") {\n loc = Loc.FormatName;\n i += 1;\n // add name to value segment\n segment.name = buffer;\n buffer = \"\";\n startFormat();\n } else if (template[i] === \"}\" && template[i + 1] === \"}\") {\n loc = Loc.Static;\n i += 2;\n // close value segment\n segment.name = buffer;\n buffer = \"\";\n parsed.segments.push(segment);\n } else {\n buffer += template[i];\n i++;\n }\n break;\n case Loc.FormatName:\n if (template[i] === \"(\") {\n loc = Loc.FormatOptionName;\n i += 1;\n // add name to format object\n format.name = buffer;\n buffer = \"\";\n } else if (template[i] === \"}\" && template[i + 1] === \"}\") {\n loc = Loc.Static;\n i += 2;\n // close format and value segment\n segment.formats.push(format);\n parsed.segments.push(segment);\n } else {\n buffer += template[i];\n i++;\n }\n break;\n case Loc.FormatOptionName:\n if (template[i] === \")\") {\n // TODO: error - no value provided for option\n } else if (template[i] === \":\") {\n loc = Loc.FormatOptionValue;\n i += 1;\n // add name to format option object\n formatOptionName = buffer;\n buffer = \"\";\n } else if (template[i] === \"}\" && template[i + 1] === \"}\") {\n // TODO: error - format options parenthesis not closed\n } else {\n buffer += template[i];\n i++;\n }\n break;\n case Loc.FormatOptionValue:\n if (template[i] === \")\") {\n loc = Loc.FormatOptionEnd;\n i += 1;\n // add value to format option object\n // add format option to format object; we're done with this format\n format.options[formatOptionName] = buffer;\n buffer = \"\";\n segment.formats.push(format);\n } else if (template[i] === \",\") {\n loc = Loc.FormatOptionName;\n i += 1;\n // add value to format option object\n // add format option to format object; we're adding another option\n format.options[formatOptionName] = buffer;\n buffer = \"\";\n } else if (template[i] === \"}\" && template[i + 1] === \"}\") {\n // TODO: error - format options parenthesis not closed\n } else {\n buffer += template[i];\n i++;\n }\n break;\n case Loc.FormatOptionEnd:\n if (template[i] === \"|\") {\n loc = Loc.FormatName;\n i += 1;\n startFormat();\n } else if (template[i] === \"}\" && template[i + 1] === \"}\") {\n loc = Loc.Static;\n i += 2;\n // add value segment\n parsed.segments.push(segment);\n } else {\n // TODO: error - no other valid characters\n }\n break;\n }\n }\n\n if (loc === Loc.Static && buffer.length > 0) {\n parsed.segments.push({ type: SegmentType.Static, text: buffer });\n }\n\n return parsed;\n }\n}\n\n/**\n * Dolla's I(nternationalizatio)n module. Manages language translations and locale-based formatting.\n */\nclass I18n {\n #logger: Logger;\n #translations = new Map<string, Translation>();\n #cache: [key: string, values: Record<string, any> | undefined, output: string][] = [];\n #formats = new Map<string, Formatter>();\n\n #initialLocale = \"auto\";\n\n #locale = writable<string>(\"en\");\n\n readonly $locale = memo(this.#locale);\n\n constructor() {\n this.#logger = createLogger(\"dolla.i18n\");\n\n this.addFormat(\"number\", (_, value, options) => {\n return this.#formatNumber(Number(value), options);\n });\n this.addFormat(\"datetime\", (_, value, options) => {\n return this.#formatDateTime(value as any, options);\n });\n this.addFormat(\"list\", (_, value, options) => {\n return this.#formatList(value as any, options);\n });\n }\n\n get locales() {\n return [...this.#translations.keys()];\n }\n\n async setup(options: I18nSetupOptions) {\n // Convert languages into Language instances.\n options.translations.forEach((entry) => {\n this.#translations.set(entry.locale, new Translation(entry));\n });\n\n // Check that initialLanguage is actually registered.\n if (options.locale && options.locale !== \"auto\") {\n const isRegistered = options.translations.some((entry) => entry.locale === options.locale);\n if (!isRegistered) {\n throw new Error(`Initial locale '${options.locale}' is not registered in the locales array.`);\n }\n this.#initialLocale = options.locale;\n }\n\n this.#logger.info(\n `${this.#translations.size} language${this.#translations.size === 1 ? \"\" : \"s\"} supported: '${[...this.#translations.keys()].join(\"', '\")}'`,\n );\n\n if (this.#translations.size > 0) {\n await this.setLocale(this.#initialLocale);\n }\n }\n\n async setLocale(name: string) {\n let realName!: string;\n\n if (name === \"auto\") {\n let names = [];\n\n if (typeof navigator !== \"undefined\") {\n const nav = navigator as any;\n\n if (nav.languages?.length > 0) {\n names.push(...nav.languages);\n } else if (nav.language) {\n names.push(nav.language);\n } else if (nav.browserLanguage) {\n names.push(nav.browserLanguage);\n } else if (nav.userLanguage) {\n names.push(nav.userLanguage);\n }\n }\n\n for (const name of names) {\n if (this.#translations.has(name)) {\n // Found a matching language.\n realName = name;\n }\n }\n } else {\n // Tag is the actual tag to set.\n if (this.#translations.has(name)) {\n realName = name;\n }\n }\n\n if (realName == null) {\n const firstLanguage = this.#translations.keys().next().value;\n if (firstLanguage) {\n realName = firstLanguage;\n }\n }\n\n if (!realName || !this.#translations.has(realName)) {\n throw new Error(`Locale '${name}' has no translation.`);\n }\n\n const translation = this.#translations.get(realName)!;\n\n try {\n await translation.load();\n\n this.#cache = [];\n this.#locale.set(realName);\n\n this.#logger.info(\"set language to \" + realName);\n } catch (error) {\n if (error instanceof Error) {\n this.#logger.crash(error);\n }\n }\n }\n\n /**\n * Returns a State containing the value at `key`.\n\n * @param selector - Key to the translated value.\n * @param options - A map of `{{placeholder}}` names and the values to replace them with.\n *\n * @example\n * const $value = t(\"your.key.here\", { count: 5 });\n */\n t(selector: string, options?: TOptions): Signal<string> {\n if (this === undefined) {\n throw new Error(\n `The 't' function cannot be destructured. If you need a standalone version you can import it like so: 'import { t } from \"@manyducks.co/dolla\"'`,\n );\n }\n\n return memo(() => {\n const values: Record<string, any> = {};\n\n // Track all option values.\n for (const key in options) {\n values[key] = get(options[key]);\n }\n\n return this.#getValue(this.#locale(), selector, values);\n });\n }\n\n #getValue(locale: string, selector: string, options: Record<string, any>): string {\n const cached = this.#getCached(selector, options);\n if (cached) return cached;\n\n const translation = this.#translations.get(locale)!;\n\n // Handle count (pluralization) and context. Keys become \"key_context_pluralization\".\n\n if (options.context != null) {\n selector += \"_\" + options.context;\n }\n if (options.count != null) {\n if (options.ordinal) {\n // Try to match the exact number key if there is one (e.g. \"myExampleKey_ordinal_(=2)\" when count is 2).\n const exact = `${selector}_ordinal_(=${options.count})`;\n if (translation.hasTemplate(exact)) {\n selector = exact;\n } else {\n selector += \"_ordinal_\" + new Intl.PluralRules(locale, { type: \"ordinal\" }).select(options.count);\n }\n } else {\n // Try to match the exact number key if there is one (e.g. \"myExampleKey_(=2)\" when count is 2).\n const exact = `${selector}_(=${options.count})`;\n if (translation.hasTemplate(exact)) {\n selector = exact;\n } else {\n selector += \"_\" + new Intl.PluralRules(locale).select(options.count);\n }\n }\n }\n\n const template = translation.getTemplate(selector);\n let output = \"\";\n\n for (const segment of template.segments) {\n if (segment.type === SegmentType.Static) {\n output += segment.text;\n } else if (segment.type === SegmentType.Variable) {\n let value = resolve(options, segment.name);\n\n const formats = options.formatOverrides?.[segment.name] ?? [...segment.formats];\n\n if (segment.name === \"count\" && formats.length === 0) {\n formats.push({ name: \"number\", options: {} });\n }\n\n for (const format of formats) {\n const fn = this.#formats.get(format.name);\n if (fn == null) {\n const error = new Error(\n `Failed to load format '${format.name}' when processing '${selector}', template: ${template}`,\n );\n this.#logger.crash(error);\n throw error;\n }\n value = fn(locale, value, format.options);\n }\n\n output += value;\n }\n }\n\n return output;\n }\n\n /**\n * Add a custom format callback.\n *\n * @example\n * Dolla.i18n.addFormat(\"uppercase\", (locale, value, options) => {\n * return value.toUpperCase();\n * });\n *\n * {\n * \"greeting\": \"Hello, {{name|uppercase}}!\"\n * }\n *\n * t(\"greeting\", {name: \"world\"}); // State<\"Hello, WORLD!\">\n */\n addFormat(name: string, callback: (locale: string, value: unknown, options: Record<string, any>) => string) {\n this.#formats.set(name, callback);\n }\n\n /**\n * Creates an `Intl.Collator` configured for the current locale.\n * NOTE: The locale is tracked if called within a signal tracking context.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator/Collator#options\n */\n collator(options?: Intl.CollatorOptions) {\n return new Intl.Collator(this.#locale(), options);\n }\n\n /**\n * Formats a number for the current locale. Uses `Intl.NumberFormat` under the hood.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options\n */\n number(count: MaybeSignal<number | bigint>, options?: Intl.NumberFormatOptions): Signal<string> {\n return memo(() => this.#formatNumber(get(count), options));\n }\n\n #formatNumber(count: number | bigint, options?: Intl.NumberFormatOptions): string {\n // NOTE: Locale is tracked if called within a tracking context.\n return new Intl.NumberFormat(this.#locale(), options).format(count);\n }\n\n /**\n * Formats a date for the current locale. Uses `Intl.DateTimeFormat` under the hood.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#options\n *\n * @example\n * const date = new Date();\n * const $formatted = Dolla.i18n.dateTime(date, { dateFormat: \"short\" });\n */\n dateTime(\n date?: MaybeSignal<string | number | Date | undefined>,\n options?: Intl.DateTimeFormatOptions,\n ): Signal<string> {\n return memo(() => this.#formatDateTime(get(date), options));\n }\n\n #formatDateTime(date?: string | number | Date, options?: Intl.DateTimeFormatOptions): string {\n // NOTE: Locale is tracked if called within a tracking context.\n return new Intl.DateTimeFormat(this.#locale(), options).format(isString(date) ? new Date(date) : date);\n }\n\n /**\n * Formats a list for the current locale. Uses `Intl.ListFormat` under the hood.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#options\n *\n * @example\n * const list = new Date();\n * const $formatted = Dolla.i18n.list(list, { });\n */\n list(list: MaybeSignal<Iterable<string>>, options?: Intl.ListFormatOptions): Signal<string> {\n return memo(() => this.#formatList(get(list), options));\n }\n\n #formatList(list: Iterable<string>, options?: Intl.ListFormatOptions): string {\n // NOTE: Locale is tracked if called within a tracking context.\n return new Intl.ListFormat(this.#locale(), options).format(list);\n }\n\n // relativeTime(date?: MaybeSignal<string | number | Date | undefined>): Signal<string> {}\n\n #getCached(key: string, values?: Record<string, any>): string | undefined {\n for (const entry of this.#cache) {\n if (entry[0] === key && deepEqual(entry[1], values)) {\n return entry[2];\n }\n }\n }\n}\n\nfunction resolve(object: any, key: string) {\n const parsed = String(key)\n .split(/[\\.\\[\\]]/)\n .filter((part) => part.trim() !== \"\");\n let value = object;\n\n while (parsed.length > 0) {\n const part = parsed.shift()!;\n\n if (value != null) {\n value = value[part];\n } else {\n value = undefined;\n }\n }\n\n return value;\n}\n\nexport const i18n = new I18n();\nexport const t = i18n.t.bind(i18n);\n"],"names":["Translation","config","__privateAdd","_Translation_instances","__publicField","_isLoaded","_templates","strings","__privateGet","isObject","isFunction","isString","res","body","entries","__privateMethod","compile_fn","entry","selector","path","key","typeOf","parseTemplate_fn","template","Loc","Loc2","parsed","buffer","i","loc","segment","format","formatOptionName","startSegment","startFormat","I18n","_I18n_instances","_logger","_translations","_cache","_formats","_initialLocale","_locale","writable","memo","__privateSet","createLogger","_","value","options","formatNumber_fn","formatDateTime_fn","formatList_fn","name","realName","names","nav","_a","firstLanguage","translation","error","values","get","getValue_fn","callback","count","date","list","locale","cached","getCached_fn","exact","output","resolve","formats","fn","deepEqual","object","part","i18n","t"],"mappings":"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"}
|