langsys-js-typescript 0.6.4 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +110 -0
- package/README.md +469 -29
- package/dist/index.d.mts +1641 -372
- package/dist/index.d.ts +1641 -372
- package/dist/index.js +5400 -1240
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5349 -1241
- package/dist/index.mjs.map +1 -1
- package/dist/langsys.browser.global.js +3 -0
- package/dist/langsys.browser.mjs +3 -0
- package/dist/pure-DkFXdgVa.d.mts +933 -0
- package/dist/pure-DkFXdgVa.d.ts +933 -0
- package/dist/pure.d.mts +1 -0
- package/dist/pure.d.ts +1 -0
- package/dist/pure.js +1196 -0
- package/dist/pure.js.map +1 -0
- package/dist/pure.mjs +1145 -0
- package/dist/pure.mjs.map +1 -0
- package/package.json +18 -4
package/dist/pure.js
ADDED
|
@@ -0,0 +1,1196 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var intlMessageformat = require('intl-messageformat');
|
|
4
|
+
|
|
5
|
+
// src/utils.ts
|
|
6
|
+
var isEmpty = (data) => {
|
|
7
|
+
if (typeof data === "number" || typeof data === "boolean") return false;
|
|
8
|
+
if (typeof data === "undefined" || data === null) return true;
|
|
9
|
+
if (typeof data.length !== "undefined") {
|
|
10
|
+
return data.length === 0;
|
|
11
|
+
}
|
|
12
|
+
if (typeof data === "object") return Object.keys(data).length === 0;
|
|
13
|
+
return false;
|
|
14
|
+
};
|
|
15
|
+
function toUtf8ByteString(input) {
|
|
16
|
+
const bytes = new TextEncoder().encode(input);
|
|
17
|
+
let out = "";
|
|
18
|
+
for (let i = 0; i < bytes.length; i += 8192) {
|
|
19
|
+
out += String.fromCharCode(...bytes.subarray(i, i + 8192));
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
function md5(inputString) {
|
|
24
|
+
if (typeof inputString !== "string") inputString = JSON.stringify(inputString);
|
|
25
|
+
return md5Core(toUtf8ByteString(inputString));
|
|
26
|
+
}
|
|
27
|
+
function md5Legacy(inputString) {
|
|
28
|
+
if (typeof inputString !== "string") inputString = JSON.stringify(inputString);
|
|
29
|
+
return md5Core(inputString);
|
|
30
|
+
}
|
|
31
|
+
function md5Core(inputString) {
|
|
32
|
+
const hc = "0123456789abcdef";
|
|
33
|
+
function rh(n) {
|
|
34
|
+
let j, s = "";
|
|
35
|
+
for (j = 0; j <= 3; j++) s += hc.charAt(n >> j * 8 + 4 & 15) + hc.charAt(n >> j * 8 & 15);
|
|
36
|
+
return s;
|
|
37
|
+
}
|
|
38
|
+
function ad(x2, y) {
|
|
39
|
+
const l = (x2 & 65535) + (y & 65535);
|
|
40
|
+
const m = (x2 >> 16) + (y >> 16) + (l >> 16);
|
|
41
|
+
return m << 16 | l & 65535;
|
|
42
|
+
}
|
|
43
|
+
function rl(n, c2) {
|
|
44
|
+
return n << c2 | n >>> 32 - c2;
|
|
45
|
+
}
|
|
46
|
+
function cm(q, a2, b2, x2, s, t) {
|
|
47
|
+
return ad(rl(ad(ad(a2, q), ad(x2, t)), s), b2);
|
|
48
|
+
}
|
|
49
|
+
function ff(a2, b2, c2, d2, x2, s, t) {
|
|
50
|
+
return cm(b2 & c2 | ~b2 & d2, a2, b2, x2, s, t);
|
|
51
|
+
}
|
|
52
|
+
function gg(a2, b2, c2, d2, x2, s, t) {
|
|
53
|
+
return cm(b2 & d2 | c2 & ~d2, a2, b2, x2, s, t);
|
|
54
|
+
}
|
|
55
|
+
function hh(a2, b2, c2, d2, x2, s, t) {
|
|
56
|
+
return cm(b2 ^ c2 ^ d2, a2, b2, x2, s, t);
|
|
57
|
+
}
|
|
58
|
+
function ii(a2, b2, c2, d2, x2, s, t) {
|
|
59
|
+
return cm(c2 ^ (b2 | ~d2), a2, b2, x2, s, t);
|
|
60
|
+
}
|
|
61
|
+
function sb(x2) {
|
|
62
|
+
let i2;
|
|
63
|
+
const nblk = (x2.length + 8 >> 6) + 1;
|
|
64
|
+
const blks = new Array(nblk * 16);
|
|
65
|
+
for (i2 = 0; i2 < nblk * 16; i2++) blks[i2] = 0;
|
|
66
|
+
for (i2 = 0; i2 < x2.length; i2++) blks[i2 >> 2] |= x2.charCodeAt(i2) << i2 % 4 * 8;
|
|
67
|
+
blks[i2 >> 2] |= 128 << i2 % 4 * 8;
|
|
68
|
+
blks[nblk * 16 - 2] = x2.length * 8;
|
|
69
|
+
return blks;
|
|
70
|
+
}
|
|
71
|
+
let i, x = sb("" + inputString), a = 1732584193, b = -271733879, c = -1732584194, d = 271733878, olda, oldb, oldc, oldd;
|
|
72
|
+
for (i = 0; i < x.length; i += 16) {
|
|
73
|
+
olda = a;
|
|
74
|
+
oldb = b;
|
|
75
|
+
oldc = c;
|
|
76
|
+
oldd = d;
|
|
77
|
+
a = ff(a, b, c, d, x[i + 0], 7, -680876936);
|
|
78
|
+
d = ff(d, a, b, c, x[i + 1], 12, -389564586);
|
|
79
|
+
c = ff(c, d, a, b, x[i + 2], 17, 606105819);
|
|
80
|
+
b = ff(b, c, d, a, x[i + 3], 22, -1044525330);
|
|
81
|
+
a = ff(a, b, c, d, x[i + 4], 7, -176418897);
|
|
82
|
+
d = ff(d, a, b, c, x[i + 5], 12, 1200080426);
|
|
83
|
+
c = ff(c, d, a, b, x[i + 6], 17, -1473231341);
|
|
84
|
+
b = ff(b, c, d, a, x[i + 7], 22, -45705983);
|
|
85
|
+
a = ff(a, b, c, d, x[i + 8], 7, 1770035416);
|
|
86
|
+
d = ff(d, a, b, c, x[i + 9], 12, -1958414417);
|
|
87
|
+
c = ff(c, d, a, b, x[i + 10], 17, -42063);
|
|
88
|
+
b = ff(b, c, d, a, x[i + 11], 22, -1990404162);
|
|
89
|
+
a = ff(a, b, c, d, x[i + 12], 7, 1804603682);
|
|
90
|
+
d = ff(d, a, b, c, x[i + 13], 12, -40341101);
|
|
91
|
+
c = ff(c, d, a, b, x[i + 14], 17, -1502002290);
|
|
92
|
+
b = ff(b, c, d, a, x[i + 15], 22, 1236535329);
|
|
93
|
+
a = gg(a, b, c, d, x[i + 1], 5, -165796510);
|
|
94
|
+
d = gg(d, a, b, c, x[i + 6], 9, -1069501632);
|
|
95
|
+
c = gg(c, d, a, b, x[i + 11], 14, 643717713);
|
|
96
|
+
b = gg(b, c, d, a, x[i + 0], 20, -373897302);
|
|
97
|
+
a = gg(a, b, c, d, x[i + 5], 5, -701558691);
|
|
98
|
+
d = gg(d, a, b, c, x[i + 10], 9, 38016083);
|
|
99
|
+
c = gg(c, d, a, b, x[i + 15], 14, -660478335);
|
|
100
|
+
b = gg(b, c, d, a, x[i + 4], 20, -405537848);
|
|
101
|
+
a = gg(a, b, c, d, x[i + 9], 5, 568446438);
|
|
102
|
+
d = gg(d, a, b, c, x[i + 14], 9, -1019803690);
|
|
103
|
+
c = gg(c, d, a, b, x[i + 3], 14, -187363961);
|
|
104
|
+
b = gg(b, c, d, a, x[i + 8], 20, 1163531501);
|
|
105
|
+
a = gg(a, b, c, d, x[i + 13], 5, -1444681467);
|
|
106
|
+
d = gg(d, a, b, c, x[i + 2], 9, -51403784);
|
|
107
|
+
c = gg(c, d, a, b, x[i + 7], 14, 1735328473);
|
|
108
|
+
b = gg(b, c, d, a, x[i + 12], 20, -1926607734);
|
|
109
|
+
a = hh(a, b, c, d, x[i + 5], 4, -378558);
|
|
110
|
+
d = hh(d, a, b, c, x[i + 8], 11, -2022574463);
|
|
111
|
+
c = hh(c, d, a, b, x[i + 11], 16, 1839030562);
|
|
112
|
+
b = hh(b, c, d, a, x[i + 14], 23, -35309556);
|
|
113
|
+
a = hh(a, b, c, d, x[i + 1], 4, -1530992060);
|
|
114
|
+
d = hh(d, a, b, c, x[i + 4], 11, 1272893353);
|
|
115
|
+
c = hh(c, d, a, b, x[i + 7], 16, -155497632);
|
|
116
|
+
b = hh(b, c, d, a, x[i + 10], 23, -1094730640);
|
|
117
|
+
a = hh(a, b, c, d, x[i + 13], 4, 681279174);
|
|
118
|
+
d = hh(d, a, b, c, x[i + 0], 11, -358537222);
|
|
119
|
+
c = hh(c, d, a, b, x[i + 3], 16, -722521979);
|
|
120
|
+
b = hh(b, c, d, a, x[i + 6], 23, 76029189);
|
|
121
|
+
a = hh(a, b, c, d, x[i + 9], 4, -640364487);
|
|
122
|
+
d = hh(d, a, b, c, x[i + 12], 11, -421815835);
|
|
123
|
+
c = hh(c, d, a, b, x[i + 15], 16, 530742520);
|
|
124
|
+
b = hh(b, c, d, a, x[i + 2], 23, -995338651);
|
|
125
|
+
a = ii(a, b, c, d, x[i + 0], 6, -198630844);
|
|
126
|
+
d = ii(d, a, b, c, x[i + 7], 10, 1126891415);
|
|
127
|
+
c = ii(c, d, a, b, x[i + 14], 15, -1416354905);
|
|
128
|
+
b = ii(b, c, d, a, x[i + 5], 21, -57434055);
|
|
129
|
+
a = ii(a, b, c, d, x[i + 12], 6, 1700485571);
|
|
130
|
+
d = ii(d, a, b, c, x[i + 3], 10, -1894986606);
|
|
131
|
+
c = ii(c, d, a, b, x[i + 10], 15, -1051523);
|
|
132
|
+
b = ii(b, c, d, a, x[i + 1], 21, -2054922799);
|
|
133
|
+
a = ii(a, b, c, d, x[i + 8], 6, 1873313359);
|
|
134
|
+
d = ii(d, a, b, c, x[i + 15], 10, -30611744);
|
|
135
|
+
c = ii(c, d, a, b, x[i + 6], 15, -1560198380);
|
|
136
|
+
b = ii(b, c, d, a, x[i + 13], 21, 1309151649);
|
|
137
|
+
a = ii(a, b, c, d, x[i + 4], 6, -145523070);
|
|
138
|
+
d = ii(d, a, b, c, x[i + 11], 10, -1120210379);
|
|
139
|
+
c = ii(c, d, a, b, x[i + 2], 15, 718787259);
|
|
140
|
+
b = ii(b, c, d, a, x[i + 9], 21, -343485551);
|
|
141
|
+
a = ad(a, olda);
|
|
142
|
+
b = ad(b, oldb);
|
|
143
|
+
c = ad(c, oldc);
|
|
144
|
+
d = ad(d, oldd);
|
|
145
|
+
}
|
|
146
|
+
return rh(a) + rh(b) + rh(c) + rh(d);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// src/identity.ts
|
|
150
|
+
var TRANSLATABLE_ATTRIBUTES = [
|
|
151
|
+
"placeholder",
|
|
152
|
+
"alt",
|
|
153
|
+
"title",
|
|
154
|
+
"label",
|
|
155
|
+
// <option>, <optgroup>, <track> — the text a user reads in the picker
|
|
156
|
+
"aria-label",
|
|
157
|
+
"aria-placeholder",
|
|
158
|
+
"aria-description",
|
|
159
|
+
"aria-valuetext",
|
|
160
|
+
// the spoken value of a slider/meter
|
|
161
|
+
"aria-roledescription",
|
|
162
|
+
"data-error",
|
|
163
|
+
"data-error-message",
|
|
164
|
+
"data-validation-message",
|
|
165
|
+
"data-invalid-message",
|
|
166
|
+
"data-required-message",
|
|
167
|
+
"data-pattern-message",
|
|
168
|
+
// The 12 below converge on langsys-php's list, verified against
|
|
169
|
+
// `src/Html/HtmlParser.php` rather than taken on report. ORDER IS IDENTITY:
|
|
170
|
+
// `custom_id` hashes the token array, so these must stay appended in PHP's
|
|
171
|
+
// order — reordering them silently re-keys every block using one.
|
|
172
|
+
"data-confirm",
|
|
173
|
+
// Rails-style confirmation dialogs
|
|
174
|
+
"data-tooltip",
|
|
175
|
+
"data-title",
|
|
176
|
+
"data-content",
|
|
177
|
+
"data-original-title",
|
|
178
|
+
// Bootstrap 4 tooltip/popover
|
|
179
|
+
"data-bs-title",
|
|
180
|
+
// Bootstrap 5
|
|
181
|
+
"data-bs-content",
|
|
182
|
+
"data-loading-text",
|
|
183
|
+
"data-success-message",
|
|
184
|
+
"data-warning-message",
|
|
185
|
+
"data-empty-message",
|
|
186
|
+
"data-placeholder"
|
|
187
|
+
// editors that shadow the native attribute
|
|
188
|
+
];
|
|
189
|
+
var NON_TRANSLATABLE_ELEMENTS = ["script", "style", "template", "noscript", "math"];
|
|
190
|
+
function isTranslationExcluded(element) {
|
|
191
|
+
if ((element.getAttribute("translate") ?? "").toLowerCase() === "no") return true;
|
|
192
|
+
if (!element.hasAttribute("data-notrans")) return false;
|
|
193
|
+
const value = (element.getAttribute("data-notrans") ?? "").trim().toLowerCase();
|
|
194
|
+
return value !== "false" && value !== "0";
|
|
195
|
+
}
|
|
196
|
+
var PHRASE_MARKER_ATTR = "data-ls-phrase";
|
|
197
|
+
var PHRASE_MARKER_ATTR_LEGACY = "data-langsys-phrase";
|
|
198
|
+
var PHRASE_MARKER_ATTRS = [PHRASE_MARKER_ATTR, PHRASE_MARKER_ATTR_LEGACY];
|
|
199
|
+
var CONTENT_BLOCK_MARKER_ATTR = "data-ls-contentblock";
|
|
200
|
+
var CONTENT_BLOCK_MARKER_ATTR_LEGACY = "data-langsys-contentblock";
|
|
201
|
+
var CONTENT_BLOCK_MARKER_ATTRS = [
|
|
202
|
+
CONTENT_BLOCK_MARKER_ATTR,
|
|
203
|
+
CONTENT_BLOCK_MARKER_ATTR_LEGACY
|
|
204
|
+
];
|
|
205
|
+
var RESOLVED_MARKER_ATTR = "data-ls-resolved";
|
|
206
|
+
var RESOLVED_MARKER_ATTR_LEGACY = "data-langsys-resolved";
|
|
207
|
+
var RESOLVED_MARKER_ATTRS = [RESOLVED_MARKER_ATTR, RESOLVED_MARKER_ATTR_LEGACY];
|
|
208
|
+
function normalizeTokenText(value) {
|
|
209
|
+
return stripC0Controls(value).replace(/\s+/g, " ").trim();
|
|
210
|
+
}
|
|
211
|
+
function stripC0Controls(value) {
|
|
212
|
+
return value.replace(/[\u0001-\u0008\u000B\u000C\u000E-\u001F]/g, "");
|
|
213
|
+
}
|
|
214
|
+
function normalizeMarkupPlaceholders(text) {
|
|
215
|
+
return text.replace(/%([A-Za-z_][A-Za-z0-9_]*)%/g, "{$1}");
|
|
216
|
+
}
|
|
217
|
+
function generateCustomId(category, tokens) {
|
|
218
|
+
return md5(canonicalContentBlockJson(category, tokens));
|
|
219
|
+
}
|
|
220
|
+
function hashableCategory(category) {
|
|
221
|
+
return !category || category === "__uncategorized__" ? "" : category;
|
|
222
|
+
}
|
|
223
|
+
function canonicalContentBlockJson(category, tokens) {
|
|
224
|
+
return JSON.stringify([hashableCategory(category), tokens]);
|
|
225
|
+
}
|
|
226
|
+
function generateLegacyCustomId(category, tokens) {
|
|
227
|
+
return md5Legacy(JSON.stringify([category, tokens]));
|
|
228
|
+
}
|
|
229
|
+
function encodeRichPhrase(nodes) {
|
|
230
|
+
const slots = [];
|
|
231
|
+
const assembled = _encodeRichNodes(nodes, slots);
|
|
232
|
+
return { phrase: normalizeMarkupPlaceholders(normalizeTokenText(assembled)), slots };
|
|
233
|
+
}
|
|
234
|
+
function _encodeRichNodes(nodes, slots) {
|
|
235
|
+
let out = "";
|
|
236
|
+
for (const node of nodes) {
|
|
237
|
+
if ("text" in node) {
|
|
238
|
+
out += node.text;
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
if ("param" in node) {
|
|
242
|
+
out += `{${node.param}}`;
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
const index = slots.length;
|
|
246
|
+
slots.push(node.payload);
|
|
247
|
+
out += `{m${index}o}` + _encodeRichNodes(node.children, slots) + `{m${index}c}`;
|
|
248
|
+
}
|
|
249
|
+
return out;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// src/logger.ts
|
|
253
|
+
var STYLES = {
|
|
254
|
+
log: "display:inline-block;background:rgb(239,239,244);color:black;font-weight:bold;padding:3px 7px;border-radius:3px",
|
|
255
|
+
warn: "display:inline-block;background:gold;color:black;font-weight:bold;padding:3px 7px;border-radius:3px",
|
|
256
|
+
error: "display:inline-block;background:#e0005a;color:#fff;font-weight:bold;padding:3px 7px;border-radius:3px"
|
|
257
|
+
};
|
|
258
|
+
function supportsStyle() {
|
|
259
|
+
try {
|
|
260
|
+
if (typeof window === "undefined") return false;
|
|
261
|
+
return !(typeof navigator !== "undefined" && navigator.product === "ReactNative");
|
|
262
|
+
} catch {
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
function emit(level, label, args) {
|
|
267
|
+
if (supportsStyle()) {
|
|
268
|
+
console[level](`%c${label}`, STYLES[level], ...args);
|
|
269
|
+
} else {
|
|
270
|
+
console[level](`[${label}]`, ...args);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
var Logger = class {
|
|
274
|
+
constructor(debugEnabled = false) {
|
|
275
|
+
this.debugEnabled = debugEnabled;
|
|
276
|
+
}
|
|
277
|
+
log(...args) {
|
|
278
|
+
if (!this.debugEnabled) return;
|
|
279
|
+
emit("log", "Langsys Debug", args);
|
|
280
|
+
}
|
|
281
|
+
warn(...args) {
|
|
282
|
+
emit("warn", "Langsys Warning", args);
|
|
283
|
+
}
|
|
284
|
+
error(...args) {
|
|
285
|
+
emit("error", "Langsys Error", args);
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
var logger = new Logger(false);
|
|
289
|
+
|
|
290
|
+
// src/locale.ts
|
|
291
|
+
var LANGUAGE_SCRIPT_REGION = /^(?:[a-z]{2,3}|[a-z]{5,8})(?:-[a-z]{4})?(?:-(?:[a-z]{2}|\d{3}))?(?=-|$)/i;
|
|
292
|
+
function canonicalizeLocale(locale) {
|
|
293
|
+
if (!locale || typeof locale !== "string") return locale;
|
|
294
|
+
const cleaned = locale.trim().replace(/_/g, "-");
|
|
295
|
+
try {
|
|
296
|
+
Intl.getCanonicalLocales(cleaned);
|
|
297
|
+
const [head] = LANGUAGE_SCRIPT_REGION.exec(cleaned);
|
|
298
|
+
return (Intl.getCanonicalLocales(head)[0] + cleaned.slice(head.length)).toLowerCase();
|
|
299
|
+
} catch {
|
|
300
|
+
if (logger.debugEnabled) logger.warn(
|
|
301
|
+
`"${locale}" is not a valid BCP 47 locale tag. Falling back to lowercasing it as-is, which will very likely miss the catalog and render base language with no other symptom.`
|
|
302
|
+
);
|
|
303
|
+
return cleaned.toLowerCase();
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
function maximizedLangScript(locale) {
|
|
307
|
+
try {
|
|
308
|
+
const max = new Intl.Locale(canonicalizeLocale(locale)).maximize();
|
|
309
|
+
return `${max.language}-${max.script ?? ""}`.toLowerCase();
|
|
310
|
+
} catch {
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
function isICU(template) {
|
|
315
|
+
return ICU_PATTERN.test(template);
|
|
316
|
+
}
|
|
317
|
+
var ICU_PATTERN = /\{[^{}]+,\s*(plural|select|selectordinal|number|date|time)\s*[,}]/;
|
|
318
|
+
function adoptPercentPlaceholders(template, params) {
|
|
319
|
+
if (!template.includes("%") || !params) return template;
|
|
320
|
+
return template.replace(
|
|
321
|
+
/%([A-Za-z_][A-Za-z0-9_]*)%/g,
|
|
322
|
+
(whole, name) => Object.prototype.hasOwnProperty.call(params, name) ? `{${name}}` : whole
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
var IDENTIFIER_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
326
|
+
var GENDER_COMPANION = /^(.+)_gender$/;
|
|
327
|
+
function escapeForRegExp(key2) {
|
|
328
|
+
return key2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
329
|
+
}
|
|
330
|
+
function findUnusedParamKeys(texts, params) {
|
|
331
|
+
if (!params) return [];
|
|
332
|
+
const keys = Object.keys(params);
|
|
333
|
+
if (!keys.length || !texts.length) return keys;
|
|
334
|
+
const haystack = texts.join("\0");
|
|
335
|
+
const isPlaceholder = (key2) => {
|
|
336
|
+
const escaped = escapeForRegExp(key2);
|
|
337
|
+
const percent = IDENTIFIER_KEY.test(key2) ? `|%${escaped}%` : "";
|
|
338
|
+
return new RegExp(`\\{\\s*${escaped}\\s*[,}]${percent}`).test(haystack);
|
|
339
|
+
};
|
|
340
|
+
return keys.filter((key2) => {
|
|
341
|
+
if (isPlaceholder(key2)) return false;
|
|
342
|
+
const genderOf = GENDER_COMPANION.exec(key2)?.[1];
|
|
343
|
+
return !(genderOf && isPlaceholder(genderOf));
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
function interpolate(template, params = {}, locale, options = {}) {
|
|
347
|
+
template = adoptPercentPlaceholders(template, params);
|
|
348
|
+
if (isICU(template)) {
|
|
349
|
+
const resolved = locale || "en";
|
|
350
|
+
const hasNullParam = !!params && Object.values(params).some((value) => value === null);
|
|
351
|
+
let formatterError;
|
|
352
|
+
if (!hasNullParam) {
|
|
353
|
+
try {
|
|
354
|
+
return formatIcu(new intlMessageformat.IntlMessageFormat(template, resolved), params, resolved);
|
|
355
|
+
} catch (error) {
|
|
356
|
+
formatterError = error;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
let ast;
|
|
360
|
+
try {
|
|
361
|
+
ast = new intlMessageformat.IntlMessageFormat(template, resolved).ast;
|
|
362
|
+
} catch {
|
|
363
|
+
return simpleInterpolate(template, params, locale);
|
|
364
|
+
}
|
|
365
|
+
if (!Array.isArray(ast)) return simpleInterpolate(template, params, locale);
|
|
366
|
+
const defaulted = [];
|
|
367
|
+
const recovered = _recoverMissingArgs(JSON.parse(JSON.stringify(ast)), params, defaulted);
|
|
368
|
+
if (defaulted.length) {
|
|
369
|
+
if (options.onDefaulted) options.onDefaulted([...new Set(defaulted)], template, resolved);
|
|
370
|
+
else noteDefaultedArgs(template, resolved, defaulted);
|
|
371
|
+
}
|
|
372
|
+
if (defaulted.length || formatterError === void 0) {
|
|
373
|
+
try {
|
|
374
|
+
return formatIcu(new intlMessageformat.IntlMessageFormat(recovered, resolved), params, resolved);
|
|
375
|
+
} catch (error) {
|
|
376
|
+
formatterError = error;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
if (options.onFormatterFailure) options.onFormatterFailure(formatterError, template, resolved);
|
|
380
|
+
else noteFormatterFailure(template, resolved, formatterError);
|
|
381
|
+
return renderWithoutFormatter(ast, params, resolved);
|
|
382
|
+
}
|
|
383
|
+
return simpleInterpolate(template, params, locale);
|
|
384
|
+
}
|
|
385
|
+
function defaultedArguments(template, params = {}, locale = "en") {
|
|
386
|
+
template = adoptPercentPlaceholders(template, params);
|
|
387
|
+
if (!isICU(template)) return [];
|
|
388
|
+
let ast;
|
|
389
|
+
try {
|
|
390
|
+
ast = new intlMessageformat.IntlMessageFormat(template, locale).ast;
|
|
391
|
+
} catch {
|
|
392
|
+
return [];
|
|
393
|
+
}
|
|
394
|
+
if (!Array.isArray(ast)) return [];
|
|
395
|
+
const defaulted = [];
|
|
396
|
+
_recoverMissingArgs(JSON.parse(JSON.stringify(ast)), params, defaulted);
|
|
397
|
+
return [...new Set(defaulted)];
|
|
398
|
+
}
|
|
399
|
+
var ICU_LITERAL = 0;
|
|
400
|
+
var ICU_ARGUMENT = 1;
|
|
401
|
+
var ICU_NUMBER = 2;
|
|
402
|
+
var ICU_DATE = 3;
|
|
403
|
+
var ICU_TIME = 4;
|
|
404
|
+
var ICU_SELECT = 5;
|
|
405
|
+
var ICU_PLURAL = 6;
|
|
406
|
+
var ICU_POUND = 7;
|
|
407
|
+
var ICU_TAG = 8;
|
|
408
|
+
var notifiedDefaults = /* @__PURE__ */ new Set();
|
|
409
|
+
function noteDefaultedArgs(template, locale, names) {
|
|
410
|
+
if (!logger.debugEnabled) return;
|
|
411
|
+
const key2 = `${locale}\0${template}`;
|
|
412
|
+
if (notifiedDefaults.has(key2)) return;
|
|
413
|
+
notifiedDefaults.add(key2);
|
|
414
|
+
const unique = [...new Set(names)];
|
|
415
|
+
logger.warn(
|
|
416
|
+
`Interpolation defaulted ${unique.length === 1 ? "argument" : "arguments"} ${unique.map((n) => `"${n}"`).join(", ")} while rendering a '${locale}' string. The translated phrase asks for ${unique.length === 1 ? "it" : "them"} but the source phrase does not, which is normal \u2014 a gendered target locale can introduce an argument the source never had. The neutral branch was used. Pass ${unique.length === 1 ? "the value" : "the values"} in \`params\` if your app knows ${unique.length === 1 ? "it" : "them"}.`
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
function _recoverMissingArgs(nodes, params, defaulted) {
|
|
420
|
+
const out = [];
|
|
421
|
+
for (const node of nodes) {
|
|
422
|
+
const name = node.value;
|
|
423
|
+
const value = name !== void 0 && name in params ? params[name] : void 0;
|
|
424
|
+
const supplied = value !== void 0 && value !== null;
|
|
425
|
+
if (node.type === ICU_TAG) {
|
|
426
|
+
out.push({ ...node, children: _recoverMissingArgs(node.children ?? [], params, defaulted) });
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
if (node.type === ICU_SELECT || node.type === ICU_PLURAL) {
|
|
430
|
+
if (supplied) {
|
|
431
|
+
const options = {};
|
|
432
|
+
for (const [key2, branch2] of Object.entries(node.options ?? {})) {
|
|
433
|
+
options[key2] = { value: _recoverMissingArgs(branch2.value, params, defaulted) };
|
|
434
|
+
}
|
|
435
|
+
out.push({ ...node, options });
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
const other = node.options?.other;
|
|
439
|
+
if (!other) {
|
|
440
|
+
out.push(node);
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
if (name) defaulted.push(name);
|
|
444
|
+
const branch = _recoverMissingArgs(other.value, params, defaulted);
|
|
445
|
+
out.push(
|
|
446
|
+
...branch.map(
|
|
447
|
+
(child) => child.type === ICU_POUND ? { type: ICU_LITERAL, value: `{${name}}` } : child
|
|
448
|
+
)
|
|
449
|
+
);
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
if (!supplied && (node.type === ICU_ARGUMENT || node.type === ICU_NUMBER || node.type === ICU_DATE || node.type === ICU_TIME)) {
|
|
453
|
+
if (name) defaulted.push(name);
|
|
454
|
+
out.push({ type: ICU_LITERAL, value: `{${name}}` });
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
out.push(node);
|
|
458
|
+
}
|
|
459
|
+
return out;
|
|
460
|
+
}
|
|
461
|
+
var notifiedFailures = /* @__PURE__ */ new Set();
|
|
462
|
+
function noteFormatterFailure(template, locale, error) {
|
|
463
|
+
const key2 = `${locale}\0${template}`;
|
|
464
|
+
if (notifiedFailures.has(key2)) return;
|
|
465
|
+
notifiedFailures.add(key2);
|
|
466
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
467
|
+
logger.warn(
|
|
468
|
+
`The message formatter failed on a '${locale}' phrase, so it was rendered by the SDK's own branch selection. Fix the phrase: ${JSON.stringify(template)}. Formatter error: ${reason}`
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
function renderWithoutFormatter(nodes, params, locale, pound) {
|
|
472
|
+
let out = "";
|
|
473
|
+
for (const node of nodes) {
|
|
474
|
+
const name = node.value;
|
|
475
|
+
const value = name !== void 0 && params && name in params ? params[name] : void 0;
|
|
476
|
+
const supplied = value !== void 0 && value !== null;
|
|
477
|
+
switch (node.type) {
|
|
478
|
+
case ICU_LITERAL:
|
|
479
|
+
out += node.value ?? "";
|
|
480
|
+
break;
|
|
481
|
+
case ICU_POUND:
|
|
482
|
+
out += pound === void 0 ? "#" : typeof pound === "string" ? pound : formatScalar(pound, locale);
|
|
483
|
+
break;
|
|
484
|
+
case ICU_TAG:
|
|
485
|
+
out += `<${name}>${renderWithoutFormatter(node.children ?? [], params, locale, pound)}</${name}>`;
|
|
486
|
+
break;
|
|
487
|
+
case ICU_SELECT: {
|
|
488
|
+
const options = node.options ?? {};
|
|
489
|
+
const branch = (supplied ? options[String(value)] : void 0) ?? options.other;
|
|
490
|
+
out += branch ? renderWithoutFormatter(branch.value, params, locale, pound) : `{${name}}`;
|
|
491
|
+
break;
|
|
492
|
+
}
|
|
493
|
+
case ICU_PLURAL: {
|
|
494
|
+
const options = node.options ?? {};
|
|
495
|
+
const count = supplied ? Number(value) : NaN;
|
|
496
|
+
if (Number.isNaN(count)) {
|
|
497
|
+
const other = options.other;
|
|
498
|
+
out += other ? renderWithoutFormatter(other.value, params, locale, `{${name}}`) : `{${name}}`;
|
|
499
|
+
break;
|
|
500
|
+
}
|
|
501
|
+
const adjusted = count - (node.offset ?? 0);
|
|
502
|
+
let branch = options[`=${count}`];
|
|
503
|
+
if (!branch) {
|
|
504
|
+
try {
|
|
505
|
+
branch = options[new Intl.PluralRules(locale, { type: node.pluralType ?? "cardinal" }).select(adjusted)];
|
|
506
|
+
} catch {
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
branch = branch ?? options.other;
|
|
510
|
+
out += branch ? renderWithoutFormatter(branch.value, params, locale, adjusted) : `{${name}}`;
|
|
511
|
+
break;
|
|
512
|
+
}
|
|
513
|
+
default:
|
|
514
|
+
out += supplied ? formatScalar(value, locale) : `{${name}}`;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
return out;
|
|
518
|
+
}
|
|
519
|
+
function formatIcu(message, params, locale) {
|
|
520
|
+
const scalars = Object.fromEntries(Object.entries(params ?? {}).map(([name, value]) => [name, typeof value === "boolean" ? String(value) : value]));
|
|
521
|
+
const out = message.format(scalars);
|
|
522
|
+
if (typeof out === "string") return out;
|
|
523
|
+
return Array.isArray(out) ? out.map((part) => typeof part === "string" ? part : formatScalar(part, locale)).join("") : formatScalar(out, locale);
|
|
524
|
+
}
|
|
525
|
+
function formatScalar(value, locale) {
|
|
526
|
+
try {
|
|
527
|
+
if (value instanceof Date) return new Intl.DateTimeFormat(locale, { dateStyle: "medium" }).format(value);
|
|
528
|
+
if (typeof value === "number" || typeof value === "bigint") return new Intl.NumberFormat(locale).format(value);
|
|
529
|
+
} catch {
|
|
530
|
+
}
|
|
531
|
+
return value instanceof Date ? value.toISOString() : String(value);
|
|
532
|
+
}
|
|
533
|
+
function simpleInterpolate(template, params, locale) {
|
|
534
|
+
return template.replace(/\{([^{},]+)\}/g, (match, rawKey) => {
|
|
535
|
+
const key2 = rawKey.trim();
|
|
536
|
+
if (!(key2 in params)) return match;
|
|
537
|
+
const value = params[key2];
|
|
538
|
+
if (value === void 0 || value === null) return match;
|
|
539
|
+
if (value instanceof Date) {
|
|
540
|
+
try {
|
|
541
|
+
return new Intl.DateTimeFormat(locale || "en", { dateStyle: "medium" }).format(value);
|
|
542
|
+
} catch {
|
|
543
|
+
return value.toISOString();
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
if (typeof value === "number" || typeof value === "bigint") {
|
|
547
|
+
try {
|
|
548
|
+
return new Intl.NumberFormat(locale || "en").format(value);
|
|
549
|
+
} catch {
|
|
550
|
+
return String(value);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return String(value);
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// src/legacy-value.ts
|
|
558
|
+
var LEGACY_FORMATS = ["laravel", "vue-i18n", "i18next", "gettext", "rails-i18n", "plain"];
|
|
559
|
+
var SUPPORTED_LEGACY_FORMATS = ["i18next", "vue-i18n", "plain"];
|
|
560
|
+
var PLURAL_CATEGORIES = ["zero", "one", "two", "few", "many", "other"];
|
|
561
|
+
var PLACEHOLDER = /%%|%\{([A-Za-z_][A-Za-z0-9_]*)\}|%\(([A-Za-z_][A-Za-z0-9_]*)\)[sd]|%\([A-Za-z_][A-Za-z0-9_]*\)[-+ #0-9.]*[a-zA-Z]|%<[A-Za-z_][A-Za-z0-9_]*>[-+ #0-9.]*[a-zA-Z]|%(?:\.\d+)?[sdif](?![A-Za-z])|\{\{\s*([A-Za-z_][A-Za-z0-9_]*)\s*\}\}|(?<![\w:]):([a-z][a-z0-9_]*)/g;
|
|
562
|
+
var CASE_TRANSFORM = /(?<![\w:]):[A-Z][A-Za-z0-9_]*/;
|
|
563
|
+
var Unconvertible = class extends Error {
|
|
564
|
+
};
|
|
565
|
+
function convertLegacyValue(value, format = "plain") {
|
|
566
|
+
value = String(value);
|
|
567
|
+
if (CASE_TRANSFORM.test(value)) {
|
|
568
|
+
return unrecognised(value, "uses a case-transforming placeholder (:Name or :NAME), which ICU cannot express");
|
|
569
|
+
}
|
|
570
|
+
if (!value.includes("|")) return convertPlaceholders(value);
|
|
571
|
+
if (format === "vue-i18n") return convertVuePipes(value);
|
|
572
|
+
return unrecognised(
|
|
573
|
+
value,
|
|
574
|
+
format === "i18next" ? 'holds a "|", which i18next does not read as a plural' : `holds a "|" in a file with no plural format declared; declare the file's format to convert it`
|
|
575
|
+
);
|
|
576
|
+
}
|
|
577
|
+
function convertLegacyPluralForms(forms) {
|
|
578
|
+
const raw = PLURAL_CATEGORIES.filter((c) => forms[c] !== void 0).map((c) => forms[c]).join(" | ");
|
|
579
|
+
if (forms.other === void 0) return unrecognised(raw, 'is a plural with no "other" form');
|
|
580
|
+
const branches = [];
|
|
581
|
+
for (const category of PLURAL_CATEGORIES) {
|
|
582
|
+
const text = forms[category];
|
|
583
|
+
if (text === void 0) continue;
|
|
584
|
+
if (CASE_TRANSFORM.test(text)) {
|
|
585
|
+
return unrecognised(raw, "uses a case-transforming placeholder (:Name or :NAME), which ICU cannot express");
|
|
586
|
+
}
|
|
587
|
+
branches.push([category, text]);
|
|
588
|
+
}
|
|
589
|
+
return plural(branches, raw);
|
|
590
|
+
}
|
|
591
|
+
function convertLegacyCall(text, entryPoint) {
|
|
592
|
+
if (entryPoint === "t") return { text: String(text), recognised: true, issue: null };
|
|
593
|
+
if (entryPoint === "vue-i18n" || entryPoint === "i18next") return convertLegacyValue(text, entryPoint);
|
|
594
|
+
throw new Error(`Unknown entry point "${String(entryPoint)}"; expected t, vue-i18n or i18next`);
|
|
595
|
+
}
|
|
596
|
+
function convertVuePipes(value) {
|
|
597
|
+
const segments = value.split("|").map((s) => s.trim());
|
|
598
|
+
if (segments.length === 2) return plural([["=1", segments[0]], ["other", segments[1]]], value);
|
|
599
|
+
if (segments.length === 3) return plural([["=0", segments[0]], ["=1", segments[1]], ["other", segments[2]]], value);
|
|
600
|
+
return unrecognised(value, `is a vue-i18n plural with ${segments.length} forms; only 2 or 3 map to ICU`);
|
|
601
|
+
}
|
|
602
|
+
function plural(branches, raw) {
|
|
603
|
+
const parts = [];
|
|
604
|
+
for (const [selector, text] of branches) {
|
|
605
|
+
const converted = convertPlaceholders(text);
|
|
606
|
+
if (!converted.recognised) return unrecognised(raw, converted.issue);
|
|
607
|
+
parts.push(`${selector} {${converted.text.replace(/\{(?:count|n)\}/g, "#")}}`);
|
|
608
|
+
}
|
|
609
|
+
return { text: `{count, plural, ${parts.join(" ")}}`, recognised: true, issue: null };
|
|
610
|
+
}
|
|
611
|
+
function convertPlaceholders(value) {
|
|
612
|
+
try {
|
|
613
|
+
const text = value.replace(PLACEHOLDER, (match, rails, python, braces, laravel) => {
|
|
614
|
+
if (match === "%%") return "%";
|
|
615
|
+
const name = rails ?? python ?? braces ?? laravel;
|
|
616
|
+
if (name !== void 0) return `{${name}}`;
|
|
617
|
+
throw new Unconvertible(
|
|
618
|
+
match.startsWith("%(") || match.startsWith("%<") ? `uses a formatted placeholder (${match}), which {name} cannot express` : `uses a positional placeholder (${match}), which names no argument`
|
|
619
|
+
);
|
|
620
|
+
});
|
|
621
|
+
return { text, recognised: true, issue: null };
|
|
622
|
+
} catch (error) {
|
|
623
|
+
if (error instanceof Unconvertible) return unrecognised(value, error.message);
|
|
624
|
+
throw error;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
function unrecognised(value, issue) {
|
|
628
|
+
return { text: value, recognised: false, issue };
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// src/legacy-keys.ts
|
|
632
|
+
var LegacyFormatError = class extends Error {
|
|
633
|
+
constructor(message, file, format) {
|
|
634
|
+
super(message);
|
|
635
|
+
this.file = file;
|
|
636
|
+
this.format = format;
|
|
637
|
+
this.name = "LegacyFormatError";
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
var FOREIGN_EXTENSIONS = {
|
|
641
|
+
php: "laravel",
|
|
642
|
+
yml: "rails-i18n",
|
|
643
|
+
yaml: "rails-i18n",
|
|
644
|
+
po: "gettext",
|
|
645
|
+
mo: "gettext"
|
|
646
|
+
};
|
|
647
|
+
function createLegacyKeys(files) {
|
|
648
|
+
const normalized = files.map(normalize);
|
|
649
|
+
return {
|
|
650
|
+
resolve(key2) {
|
|
651
|
+
if (typeof key2 !== "string" || key2 === "") return null;
|
|
652
|
+
for (const file of normalized) {
|
|
653
|
+
const found = lookup(file, key2);
|
|
654
|
+
if (!found) continue;
|
|
655
|
+
const converted = convert(found.value, file.format);
|
|
656
|
+
return { ...converted, phrase: converted.text, category: found.category, key: key2, file: file.name };
|
|
657
|
+
}
|
|
658
|
+
return null;
|
|
659
|
+
},
|
|
660
|
+
duplicates() {
|
|
661
|
+
const seen = {};
|
|
662
|
+
for (const file of normalized) {
|
|
663
|
+
for (const key2 of Object.keys(leaves(file))) (seen[key2] ??= []).push(file.name);
|
|
664
|
+
}
|
|
665
|
+
return Object.fromEntries(Object.entries(seen).filter(([, names]) => names.length > 1));
|
|
666
|
+
},
|
|
667
|
+
problems() {
|
|
668
|
+
const problems = [];
|
|
669
|
+
for (const file of normalized) {
|
|
670
|
+
if (file.data === null) {
|
|
671
|
+
problems.push({ file: file.name, key: null, issue: "is not a JSON object", fix: "pass the parsed contents of the file" });
|
|
672
|
+
continue;
|
|
673
|
+
}
|
|
674
|
+
for (const [key2, value] of Object.entries(leaves(file))) {
|
|
675
|
+
const converted = convert(value, file.format);
|
|
676
|
+
if (!converted.recognised) {
|
|
677
|
+
problems.push({
|
|
678
|
+
file: file.name,
|
|
679
|
+
key: key2,
|
|
680
|
+
issue: converted.issue,
|
|
681
|
+
fix: "rewrite the value as Langsys source text, or declare the file's format"
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
return problems;
|
|
687
|
+
}
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
function normalize(file) {
|
|
691
|
+
const name = String(file?.name ?? "");
|
|
692
|
+
const extension = name.includes(".") ? name.slice(name.lastIndexOf(".") + 1).toLowerCase() : "";
|
|
693
|
+
if (extension === "mo") {
|
|
694
|
+
const po = name.slice(0, -3) + ".po";
|
|
695
|
+
throw new LegacyFormatError(
|
|
696
|
+
`The legacy file ${name} is a compiled gettext catalog. gettext reads .po only (${po}), and gettext is not a format this core reads; it reads ${SUPPORTED_LEGACY_FORMATS.join(", ")}.`,
|
|
697
|
+
name,
|
|
698
|
+
"gettext"
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
const declared = file?.format;
|
|
702
|
+
const format = declared ?? FOREIGN_EXTENSIONS[extension] ?? "plain";
|
|
703
|
+
if (!SUPPORTED_LEGACY_FORMATS.includes(format)) {
|
|
704
|
+
const known = LEGACY_FORMATS.includes(format);
|
|
705
|
+
throw new LegacyFormatError(
|
|
706
|
+
`The legacy file ${name} is in the ${known ? "" : "unknown "}format "${format}", which this core does not read. It reads ${SUPPORTED_LEGACY_FORMATS.join(", ")}.`,
|
|
707
|
+
name,
|
|
708
|
+
format
|
|
709
|
+
);
|
|
710
|
+
}
|
|
711
|
+
const data = isRecord(file?.data) ? file.data : null;
|
|
712
|
+
return { name, format, namespace: file?.namespace ? String(file.namespace) : null, data };
|
|
713
|
+
}
|
|
714
|
+
function lookup(file, key2) {
|
|
715
|
+
if (!file.data) return null;
|
|
716
|
+
const pairs = file.format === "i18next";
|
|
717
|
+
if (file.namespace !== null) {
|
|
718
|
+
if (!key2.startsWith(file.namespace + ".")) return null;
|
|
719
|
+
const value2 = valueAt(file.data, key2.slice(file.namespace.length + 1).split("."), pairs);
|
|
720
|
+
return value2 === null ? null : { value: value2, category: file.namespace };
|
|
721
|
+
}
|
|
722
|
+
if (!key2.includes(".")) {
|
|
723
|
+
const value2 = valueAt(file.data, [key2], pairs);
|
|
724
|
+
return value2 === null ? null : { value: value2, category: null };
|
|
725
|
+
}
|
|
726
|
+
const flat = file.data[key2];
|
|
727
|
+
if (typeof flat === "string") return { value: flat, category: looksLikeAPath(key2) ? key2.slice(0, key2.indexOf(".")) : null };
|
|
728
|
+
const value = valueAt(file.data, key2.split("."), pairs);
|
|
729
|
+
return value === null ? null : { value, category: key2.slice(0, key2.indexOf(".")) };
|
|
730
|
+
}
|
|
731
|
+
function valueAt(data, segments, pairs) {
|
|
732
|
+
const last = segments.pop();
|
|
733
|
+
let container = data;
|
|
734
|
+
for (const segment of segments) {
|
|
735
|
+
if (!isRecord(container) || !(segment in container)) return null;
|
|
736
|
+
container = container[segment];
|
|
737
|
+
}
|
|
738
|
+
if (!isRecord(container)) return null;
|
|
739
|
+
if (pairs) {
|
|
740
|
+
const forms = {};
|
|
741
|
+
for (const category of PLURAL_CATEGORIES) {
|
|
742
|
+
const value2 = container[`${last}_${category}`];
|
|
743
|
+
if (typeof value2 === "string") forms[category] = value2;
|
|
744
|
+
}
|
|
745
|
+
if (Object.keys(forms).length > 0) return forms;
|
|
746
|
+
const singular = container[last];
|
|
747
|
+
const pluralForm = container[`${last}_plural`];
|
|
748
|
+
if (typeof singular === "string" && typeof pluralForm === "string") return { one: singular, other: pluralForm };
|
|
749
|
+
}
|
|
750
|
+
const value = container[last];
|
|
751
|
+
return typeof value === "string" ? value : null;
|
|
752
|
+
}
|
|
753
|
+
function leaves(file) {
|
|
754
|
+
const out = {};
|
|
755
|
+
if (!file.data) return out;
|
|
756
|
+
const prefix = file.namespace !== null ? file.namespace + "." : "";
|
|
757
|
+
collect(file.data, prefix, out, file.format === "i18next");
|
|
758
|
+
return out;
|
|
759
|
+
}
|
|
760
|
+
var SUFFIXES = [...PLURAL_CATEGORIES.map((c) => `_${c}`), "_plural"];
|
|
761
|
+
function collect(node, prefix, out, pairs) {
|
|
762
|
+
for (const [key2, value] of Object.entries(node)) {
|
|
763
|
+
if (isRecord(value)) {
|
|
764
|
+
collect(value, `${prefix}${key2}.`, out, pairs);
|
|
765
|
+
continue;
|
|
766
|
+
}
|
|
767
|
+
if (typeof value !== "string") continue;
|
|
768
|
+
if (pairs) {
|
|
769
|
+
const suffix = SUFFIXES.find((s) => key2.endsWith(s) && key2.length > s.length);
|
|
770
|
+
if (suffix) {
|
|
771
|
+
const base = key2.slice(0, -suffix.length);
|
|
772
|
+
const forms = valueAt(node, [base], true);
|
|
773
|
+
if (forms !== null && typeof forms !== "string") {
|
|
774
|
+
out[prefix + base] = forms;
|
|
775
|
+
continue;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
if (!(prefix + key2 in out)) out[prefix + key2] = value;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
function convert(value, format) {
|
|
783
|
+
return typeof value === "string" ? convertLegacyValue(value, format) : convertLegacyPluralForms(value);
|
|
784
|
+
}
|
|
785
|
+
function looksLikeAPath(key2) {
|
|
786
|
+
return /^[A-Za-z0-9_-]+(\.[A-Za-z0-9_-]+)+$/.test(key2);
|
|
787
|
+
}
|
|
788
|
+
function isRecord(value) {
|
|
789
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
// src/snapshot.ts
|
|
793
|
+
var SNAPSHOT_FORMAT = "langsys-catalog-snapshot";
|
|
794
|
+
var SNAPSHOT_VERSION = 1;
|
|
795
|
+
var SnapshotError = class extends Error {
|
|
796
|
+
constructor(message, reason) {
|
|
797
|
+
super(message);
|
|
798
|
+
this.reason = reason;
|
|
799
|
+
this.name = "SnapshotError";
|
|
800
|
+
}
|
|
801
|
+
};
|
|
802
|
+
var PAYLOAD_MEMBERS = ["project_id", "generated_at", "base_locale", "locales", "categories", "catalog"];
|
|
803
|
+
function canonicalSnapshotJson(value) {
|
|
804
|
+
if (value === null) return "null";
|
|
805
|
+
if (typeof value === "string") return JSON.stringify(value);
|
|
806
|
+
if (typeof value === "number" || typeof value === "boolean") return JSON.stringify(value);
|
|
807
|
+
if (Array.isArray(value)) return `[${value.map(canonicalSnapshotJson).join(",")}]`;
|
|
808
|
+
if (typeof value === "object") {
|
|
809
|
+
const record = value;
|
|
810
|
+
const keys = Object.keys(record).filter((key2) => record[key2] !== void 0).sort(compareCodePoints);
|
|
811
|
+
return `{${keys.map((key2) => `${JSON.stringify(key2)}:${canonicalSnapshotJson(record[key2])}`).join(",")}}`;
|
|
812
|
+
}
|
|
813
|
+
throw new TypeError(`A snapshot cannot hold a ${typeof value}.`);
|
|
814
|
+
}
|
|
815
|
+
function snapshotChecksum(payload) {
|
|
816
|
+
const hashed = {};
|
|
817
|
+
for (const member of PAYLOAD_MEMBERS) hashed[member] = payload[member];
|
|
818
|
+
return "sha256:" + sha256Hex(canonicalSnapshotJson(hashed));
|
|
819
|
+
}
|
|
820
|
+
function buildSnapshot(options) {
|
|
821
|
+
const categories = [...new Set(options.categories.map(String))].sort(compareCodePoints);
|
|
822
|
+
const catalog = {};
|
|
823
|
+
for (const [locale, categoriesForLocale] of Object.entries(options.catalogs)) {
|
|
824
|
+
const kept = {};
|
|
825
|
+
for (const category of categories) {
|
|
826
|
+
if (Object.prototype.hasOwnProperty.call(categoriesForLocale, category)) kept[category] = categoriesForLocale[category];
|
|
827
|
+
}
|
|
828
|
+
catalog[locale.toLowerCase()] = kept;
|
|
829
|
+
}
|
|
830
|
+
const payload = {
|
|
831
|
+
project_id: String(options.projectId),
|
|
832
|
+
generated_at: (options.generatedAt ?? /* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z"),
|
|
833
|
+
base_locale: options.baseLocale.toLowerCase(),
|
|
834
|
+
locales: Object.keys(catalog).sort(compareCodePoints),
|
|
835
|
+
categories,
|
|
836
|
+
catalog
|
|
837
|
+
};
|
|
838
|
+
return { format: SNAPSHOT_FORMAT, version: SNAPSHOT_VERSION, ...payload, checksum: snapshotChecksum(payload) };
|
|
839
|
+
}
|
|
840
|
+
function parseSnapshot(input) {
|
|
841
|
+
let document = input;
|
|
842
|
+
if (typeof input === "string") {
|
|
843
|
+
try {
|
|
844
|
+
document = JSON.parse(input);
|
|
845
|
+
} catch {
|
|
846
|
+
throw new SnapshotError("This is not a Langsys catalog snapshot: it is not JSON.", "not-json");
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
if (typeof document !== "object" || document === null || Array.isArray(document)) {
|
|
850
|
+
throw new SnapshotError("This is not a Langsys catalog snapshot: it is not a JSON object.", "not-json");
|
|
851
|
+
}
|
|
852
|
+
const doc = document;
|
|
853
|
+
if (doc.format !== SNAPSHOT_FORMAT) {
|
|
854
|
+
throw new SnapshotError(`This is not a Langsys catalog snapshot: its format is ${JSON.stringify(doc.format)}, not "${SNAPSHOT_FORMAT}".`, "format");
|
|
855
|
+
}
|
|
856
|
+
if (doc.version !== SNAPSHOT_VERSION) {
|
|
857
|
+
throw new SnapshotError(`This snapshot is version ${JSON.stringify(doc.version)}; this SDK reads version ${SNAPSHOT_VERSION}. Export it again.`, "version");
|
|
858
|
+
}
|
|
859
|
+
for (const member of [...PAYLOAD_MEMBERS, "checksum"]) {
|
|
860
|
+
if (!Object.prototype.hasOwnProperty.call(doc, member)) {
|
|
861
|
+
throw new SnapshotError(`This snapshot has no "${member}". Export it again.`, "missing-member");
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
if (doc.checksum !== snapshotChecksum(doc)) {
|
|
865
|
+
throw new SnapshotError(
|
|
866
|
+
"This snapshot was changed after it was exported: its checksum does not match. A snapshot is a cache and is never edited; export it again.",
|
|
867
|
+
"checksum"
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
return doc;
|
|
871
|
+
}
|
|
872
|
+
function compareCodePoints(a, b) {
|
|
873
|
+
const ia = a[Symbol.iterator]();
|
|
874
|
+
const ib = b[Symbol.iterator]();
|
|
875
|
+
for (; ; ) {
|
|
876
|
+
const ca = ia.next();
|
|
877
|
+
const cb = ib.next();
|
|
878
|
+
if (ca.done || cb.done) return ca.done && cb.done ? 0 : ca.done ? -1 : 1;
|
|
879
|
+
const diff = ca.value.codePointAt(0) - cb.value.codePointAt(0);
|
|
880
|
+
if (diff !== 0) return diff;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
function sha256Hex(text) {
|
|
884
|
+
const bytes = new TextEncoder().encode(text);
|
|
885
|
+
const length = bytes.length;
|
|
886
|
+
const blocks = Math.ceil((length + 9) / 64);
|
|
887
|
+
const words = new Uint32Array(blocks * 16);
|
|
888
|
+
for (let i = 0; i < length; i++) words[i >> 2] |= bytes[i] << 24 - i % 4 * 8;
|
|
889
|
+
words[length >> 2] |= 128 << 24 - length % 4 * 8;
|
|
890
|
+
words[words.length - 2] = Math.floor(length * 8 / 4294967296);
|
|
891
|
+
words[words.length - 1] = length * 8 >>> 0;
|
|
892
|
+
const h = new Uint32Array([1779033703, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635, 1541459225]);
|
|
893
|
+
const w = new Uint32Array(64);
|
|
894
|
+
for (let block = 0; block < words.length; block += 16) {
|
|
895
|
+
for (let t = 0; t < 16; t++) w[t] = words[block + t];
|
|
896
|
+
for (let t = 16; t < 64; t++) {
|
|
897
|
+
const s0 = rotr(w[t - 15], 7) ^ rotr(w[t - 15], 18) ^ w[t - 15] >>> 3;
|
|
898
|
+
const s1 = rotr(w[t - 2], 17) ^ rotr(w[t - 2], 19) ^ w[t - 2] >>> 10;
|
|
899
|
+
w[t] = w[t - 16] + s0 + w[t - 7] + s1 >>> 0;
|
|
900
|
+
}
|
|
901
|
+
let [a, b, c, d, e, f, g, hh] = [h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7]];
|
|
902
|
+
for (let t = 0; t < 64; t++) {
|
|
903
|
+
const t1 = hh + (rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)) + (e & f ^ ~e & g) + K[t] + w[t] >>> 0;
|
|
904
|
+
const t2 = (rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)) + (a & b ^ a & c ^ b & c) >>> 0;
|
|
905
|
+
hh = g;
|
|
906
|
+
g = f;
|
|
907
|
+
f = e;
|
|
908
|
+
e = d + t1 >>> 0;
|
|
909
|
+
d = c;
|
|
910
|
+
c = b;
|
|
911
|
+
b = a;
|
|
912
|
+
a = t1 + t2 >>> 0;
|
|
913
|
+
}
|
|
914
|
+
h[0] = h[0] + a >>> 0;
|
|
915
|
+
h[1] = h[1] + b >>> 0;
|
|
916
|
+
h[2] = h[2] + c >>> 0;
|
|
917
|
+
h[3] = h[3] + d >>> 0;
|
|
918
|
+
h[4] = h[4] + e >>> 0;
|
|
919
|
+
h[5] = h[5] + f >>> 0;
|
|
920
|
+
h[6] = h[6] + g >>> 0;
|
|
921
|
+
h[7] = h[7] + hh >>> 0;
|
|
922
|
+
}
|
|
923
|
+
return Array.from(h, (word) => word.toString(16).padStart(8, "0")).join("");
|
|
924
|
+
}
|
|
925
|
+
function rotr(value, bits) {
|
|
926
|
+
return value >>> bits | value << 32 - bits;
|
|
927
|
+
}
|
|
928
|
+
var K = new Uint32Array([
|
|
929
|
+
1116352408,
|
|
930
|
+
1899447441,
|
|
931
|
+
3049323471,
|
|
932
|
+
3921009573,
|
|
933
|
+
961987163,
|
|
934
|
+
1508970993,
|
|
935
|
+
2453635748,
|
|
936
|
+
2870763221,
|
|
937
|
+
3624381080,
|
|
938
|
+
310598401,
|
|
939
|
+
607225278,
|
|
940
|
+
1426881987,
|
|
941
|
+
1925078388,
|
|
942
|
+
2162078206,
|
|
943
|
+
2614888103,
|
|
944
|
+
3248222580,
|
|
945
|
+
3835390401,
|
|
946
|
+
4022224774,
|
|
947
|
+
264347078,
|
|
948
|
+
604807628,
|
|
949
|
+
770255983,
|
|
950
|
+
1249150122,
|
|
951
|
+
1555081692,
|
|
952
|
+
1996064986,
|
|
953
|
+
2554220882,
|
|
954
|
+
2821834349,
|
|
955
|
+
2952996808,
|
|
956
|
+
3210313671,
|
|
957
|
+
3336571891,
|
|
958
|
+
3584528711,
|
|
959
|
+
113926993,
|
|
960
|
+
338241895,
|
|
961
|
+
666307205,
|
|
962
|
+
773529912,
|
|
963
|
+
1294757372,
|
|
964
|
+
1396182291,
|
|
965
|
+
1695183700,
|
|
966
|
+
1986661051,
|
|
967
|
+
2177026350,
|
|
968
|
+
2456956037,
|
|
969
|
+
2730485921,
|
|
970
|
+
2820302411,
|
|
971
|
+
3259730800,
|
|
972
|
+
3345764771,
|
|
973
|
+
3516065817,
|
|
974
|
+
3600352804,
|
|
975
|
+
4094571909,
|
|
976
|
+
275423344,
|
|
977
|
+
430227734,
|
|
978
|
+
506948616,
|
|
979
|
+
659060556,
|
|
980
|
+
883997877,
|
|
981
|
+
958139571,
|
|
982
|
+
1322822218,
|
|
983
|
+
1537002063,
|
|
984
|
+
1747873779,
|
|
985
|
+
1955562222,
|
|
986
|
+
2024104815,
|
|
987
|
+
2227730452,
|
|
988
|
+
2361852424,
|
|
989
|
+
2428436474,
|
|
990
|
+
2756734187,
|
|
991
|
+
3204031479,
|
|
992
|
+
3329325298
|
|
993
|
+
]);
|
|
994
|
+
|
|
995
|
+
// src/server-messages.ts
|
|
996
|
+
var DEFAULT_SERVER_MESSAGE_CATEGORY = "Errors";
|
|
997
|
+
var MARKER = /\{([a-z][a-z0-9_]*)\}/g;
|
|
998
|
+
function templateMarkers(template) {
|
|
999
|
+
if (typeof template !== "string" || template === "") return [];
|
|
1000
|
+
const names = [];
|
|
1001
|
+
for (const match of template.matchAll(MARKER)) {
|
|
1002
|
+
if (!names.includes(match[1])) names.push(match[1]);
|
|
1003
|
+
}
|
|
1004
|
+
return names;
|
|
1005
|
+
}
|
|
1006
|
+
function fillTemplate(template, params = {}) {
|
|
1007
|
+
return String(template).replace(MARKER, (marker, name) => {
|
|
1008
|
+
if (!Object.prototype.hasOwnProperty.call(params, name)) return marker;
|
|
1009
|
+
const value = params[name];
|
|
1010
|
+
if (value === void 0 || typeof value === "object" || typeof value === "function") return marker;
|
|
1011
|
+
return String(value);
|
|
1012
|
+
});
|
|
1013
|
+
}
|
|
1014
|
+
function toServerMessage(value, pieces = {}) {
|
|
1015
|
+
if (!isRecord2(value)) return null;
|
|
1016
|
+
const read = (piece) => value[pieces[piece] ?? piece];
|
|
1017
|
+
const template = read("template");
|
|
1018
|
+
const message = read("message");
|
|
1019
|
+
const params = read("params");
|
|
1020
|
+
const field = read("field");
|
|
1021
|
+
const code = read("code");
|
|
1022
|
+
const hasTemplate = typeof template === "string";
|
|
1023
|
+
const hasMessage = typeof message === "string";
|
|
1024
|
+
if (!hasTemplate && !hasMessage) return null;
|
|
1025
|
+
return {
|
|
1026
|
+
...hasTemplate ? { template } : {},
|
|
1027
|
+
...isRecord2(params) ? { params } : {},
|
|
1028
|
+
...hasMessage ? { message } : {},
|
|
1029
|
+
...field !== void 0 && field !== null && field !== "" ? { field } : {},
|
|
1030
|
+
...code !== void 0 && code !== null ? { code } : {}
|
|
1031
|
+
};
|
|
1032
|
+
}
|
|
1033
|
+
function resolveServerMessages(body, options) {
|
|
1034
|
+
const { key: key2, resolver, pieces } = options ?? {};
|
|
1035
|
+
if (typeof resolver !== "function" && (typeof key2 !== "string" || key2 === "")) {
|
|
1036
|
+
throw new TypeError(
|
|
1037
|
+
'resolveServerMessages needs to know where the entries sit: pass { key } with the path your server attaches them under (Laravel: "langsys_errors"), or { resolver }.'
|
|
1038
|
+
);
|
|
1039
|
+
}
|
|
1040
|
+
if (typeof body === "string") {
|
|
1041
|
+
try {
|
|
1042
|
+
body = JSON.parse(body);
|
|
1043
|
+
} catch {
|
|
1044
|
+
return [];
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
const found = typeof resolver === "function" ? resolver(body) : dig(body, key2);
|
|
1048
|
+
return toItems(found).map((item) => toServerMessage(item, pieces)).filter((entry) => entry !== null);
|
|
1049
|
+
}
|
|
1050
|
+
function toItems(found) {
|
|
1051
|
+
if (Array.isArray(found)) return found;
|
|
1052
|
+
if (!isRecord2(found)) return [];
|
|
1053
|
+
const values = Object.values(found);
|
|
1054
|
+
return values.every((value) => Array.isArray(value)) && values.length > 0 ? values.flat() : [found];
|
|
1055
|
+
}
|
|
1056
|
+
function dig(body, path) {
|
|
1057
|
+
let node = body;
|
|
1058
|
+
for (const segment of path.split(".")) {
|
|
1059
|
+
if (typeof node !== "object" || node === null || !Object.prototype.hasOwnProperty.call(node, segment)) {
|
|
1060
|
+
return void 0;
|
|
1061
|
+
}
|
|
1062
|
+
node = node[segment];
|
|
1063
|
+
}
|
|
1064
|
+
return node;
|
|
1065
|
+
}
|
|
1066
|
+
function isRecord2(value) {
|
|
1067
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
// src/var-names.ts
|
|
1071
|
+
var GRAMMAR = /^[a-z][a-z0-9_]*$/;
|
|
1072
|
+
var RESERVED = /^m\d+[oc]$/;
|
|
1073
|
+
var COUNT = /* @__PURE__ */ new Set(["length", "size", "count"]);
|
|
1074
|
+
var VALUE = /* @__PURE__ */ new Set(["value", "current"]);
|
|
1075
|
+
function snakeCase(segment) {
|
|
1076
|
+
const snake = segment.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").toLowerCase().replace(/[^a-z0-9_]+/g, "_").replace(/_+/g, "_").replace(/^[^a-z]+/, "").replace(/_+$/, "");
|
|
1077
|
+
return snake && GRAMMAR.test(snake) ? snake : null;
|
|
1078
|
+
}
|
|
1079
|
+
function derive(shape) {
|
|
1080
|
+
if ("identifier" in shape) {
|
|
1081
|
+
const name = snakeCase(shape.identifier);
|
|
1082
|
+
return name ? { name, prev: null } : null;
|
|
1083
|
+
}
|
|
1084
|
+
if ("member" in shape) {
|
|
1085
|
+
const segments = shape.member;
|
|
1086
|
+
if (segments.length === 0) return null;
|
|
1087
|
+
const last = segments[segments.length - 1];
|
|
1088
|
+
if (segments.length >= 2 && (COUNT.has(last) || VALUE.has(last))) {
|
|
1089
|
+
const base = snakeCase(segments[segments.length - 2]);
|
|
1090
|
+
if (!base) return null;
|
|
1091
|
+
const prev = segments.length >= 3 ? snakeCase(segments[segments.length - 3]) : null;
|
|
1092
|
+
return { name: COUNT.has(last) ? `${base}_count` : base, prev };
|
|
1093
|
+
}
|
|
1094
|
+
const name = snakeCase(last);
|
|
1095
|
+
if (!name) return null;
|
|
1096
|
+
return { name, prev: segments.length >= 2 ? snakeCase(segments[segments.length - 2]) : null };
|
|
1097
|
+
}
|
|
1098
|
+
if ("call" in shape) {
|
|
1099
|
+
return shape.call.args.length === 1 ? derive(shape.call.args[0]) : null;
|
|
1100
|
+
}
|
|
1101
|
+
return null;
|
|
1102
|
+
}
|
|
1103
|
+
var key = (shape) => JSON.stringify(shape);
|
|
1104
|
+
function identifies(shape) {
|
|
1105
|
+
if ("call" in shape) return shape.call.callee !== "" && shape.call.args.every(identifies);
|
|
1106
|
+
return !("other" in shape);
|
|
1107
|
+
}
|
|
1108
|
+
function derivePlaceholderNames(expressions) {
|
|
1109
|
+
const names = expressions.map((e) => e.explicit ? snakeCase(e.explicit) ?? e.explicit : null);
|
|
1110
|
+
const taken = new Set(names.filter((n) => n !== null));
|
|
1111
|
+
const derived = expressions.map((e, i) => names[i] === null ? derive(e.shape) : null);
|
|
1112
|
+
const firstOf = /* @__PURE__ */ new Map();
|
|
1113
|
+
const sameAs = expressions.map((e, i) => {
|
|
1114
|
+
if (names[i] !== null || !identifies(e.shape)) return i;
|
|
1115
|
+
const k = key(e.shape);
|
|
1116
|
+
if (!firstOf.has(k)) firstOf.set(k, i);
|
|
1117
|
+
return firstOf.get(k);
|
|
1118
|
+
});
|
|
1119
|
+
const wanted = /* @__PURE__ */ new Map();
|
|
1120
|
+
derived.forEach((d, i) => {
|
|
1121
|
+
if (d && sameAs[i] === i) wanted.set(d.name, [...wanted.get(d.name) ?? [], i]);
|
|
1122
|
+
});
|
|
1123
|
+
const claim = (name) => {
|
|
1124
|
+
let candidate = name;
|
|
1125
|
+
for (let n = 2; taken.has(candidate) || RESERVED.test(candidate); n++) candidate = `${name}_${n}`;
|
|
1126
|
+
taken.add(candidate);
|
|
1127
|
+
return candidate;
|
|
1128
|
+
};
|
|
1129
|
+
for (let i = 0; i < expressions.length; i++) {
|
|
1130
|
+
if (names[i] !== null || sameAs[i] !== i) continue;
|
|
1131
|
+
const d = derived[i];
|
|
1132
|
+
if (!d) continue;
|
|
1133
|
+
const collides = (wanted.get(d.name)?.length ?? 0) > 1 || taken.has(d.name) || RESERVED.test(d.name);
|
|
1134
|
+
names[i] = claim(collides && d.prev ? `${d.prev}_${d.name}` : d.name);
|
|
1135
|
+
}
|
|
1136
|
+
for (let i = 0; i < expressions.length; i++) {
|
|
1137
|
+
if (names[i] === null && sameAs[i] === i) names[i] = claim("value");
|
|
1138
|
+
}
|
|
1139
|
+
return expressions.map((_, i) => names[sameAs[i]]);
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
// src/var-markers.ts
|
|
1143
|
+
var VAR_PARAM_ATTR = "data-ls-param";
|
|
1144
|
+
|
|
1145
|
+
exports.CONTENT_BLOCK_MARKER_ATTR = CONTENT_BLOCK_MARKER_ATTR;
|
|
1146
|
+
exports.CONTENT_BLOCK_MARKER_ATTRS = CONTENT_BLOCK_MARKER_ATTRS;
|
|
1147
|
+
exports.CONTENT_BLOCK_MARKER_ATTR_LEGACY = CONTENT_BLOCK_MARKER_ATTR_LEGACY;
|
|
1148
|
+
exports.DEFAULT_SERVER_MESSAGE_CATEGORY = DEFAULT_SERVER_MESSAGE_CATEGORY;
|
|
1149
|
+
exports.LEGACY_FORMATS = LEGACY_FORMATS;
|
|
1150
|
+
exports.LegacyFormatError = LegacyFormatError;
|
|
1151
|
+
exports.NON_TRANSLATABLE_ELEMENTS = NON_TRANSLATABLE_ELEMENTS;
|
|
1152
|
+
exports.PHRASE_MARKER_ATTR = PHRASE_MARKER_ATTR;
|
|
1153
|
+
exports.PHRASE_MARKER_ATTRS = PHRASE_MARKER_ATTRS;
|
|
1154
|
+
exports.PHRASE_MARKER_ATTR_LEGACY = PHRASE_MARKER_ATTR_LEGACY;
|
|
1155
|
+
exports.RESOLVED_MARKER_ATTR = RESOLVED_MARKER_ATTR;
|
|
1156
|
+
exports.RESOLVED_MARKER_ATTRS = RESOLVED_MARKER_ATTRS;
|
|
1157
|
+
exports.RESOLVED_MARKER_ATTR_LEGACY = RESOLVED_MARKER_ATTR_LEGACY;
|
|
1158
|
+
exports.SNAPSHOT_FORMAT = SNAPSHOT_FORMAT;
|
|
1159
|
+
exports.SNAPSHOT_VERSION = SNAPSHOT_VERSION;
|
|
1160
|
+
exports.SUPPORTED_LEGACY_FORMATS = SUPPORTED_LEGACY_FORMATS;
|
|
1161
|
+
exports.SnapshotError = SnapshotError;
|
|
1162
|
+
exports.TRANSLATABLE_ATTRIBUTES = TRANSLATABLE_ATTRIBUTES;
|
|
1163
|
+
exports.VAR_PARAM_ATTR = VAR_PARAM_ATTR;
|
|
1164
|
+
exports.buildSnapshot = buildSnapshot;
|
|
1165
|
+
exports.canonicalContentBlockJson = canonicalContentBlockJson;
|
|
1166
|
+
exports.canonicalSnapshotJson = canonicalSnapshotJson;
|
|
1167
|
+
exports.canonicalizeLocale = canonicalizeLocale;
|
|
1168
|
+
exports.convertLegacyCall = convertLegacyCall;
|
|
1169
|
+
exports.convertLegacyPluralForms = convertLegacyPluralForms;
|
|
1170
|
+
exports.convertLegacyValue = convertLegacyValue;
|
|
1171
|
+
exports.createLegacyKeys = createLegacyKeys;
|
|
1172
|
+
exports.defaultedArguments = defaultedArguments;
|
|
1173
|
+
exports.derivePlaceholderNames = derivePlaceholderNames;
|
|
1174
|
+
exports.encodeRichPhrase = encodeRichPhrase;
|
|
1175
|
+
exports.fillTemplate = fillTemplate;
|
|
1176
|
+
exports.findUnusedParamKeys = findUnusedParamKeys;
|
|
1177
|
+
exports.generateCustomId = generateCustomId;
|
|
1178
|
+
exports.generateLegacyCustomId = generateLegacyCustomId;
|
|
1179
|
+
exports.interpolate = interpolate;
|
|
1180
|
+
exports.isEmpty = isEmpty;
|
|
1181
|
+
exports.isICU = isICU;
|
|
1182
|
+
exports.isTranslationExcluded = isTranslationExcluded;
|
|
1183
|
+
exports.maximizedLangScript = maximizedLangScript;
|
|
1184
|
+
exports.md5 = md5;
|
|
1185
|
+
exports.md5Legacy = md5Legacy;
|
|
1186
|
+
exports.normalizeMarkupPlaceholders = normalizeMarkupPlaceholders;
|
|
1187
|
+
exports.normalizeTokenText = normalizeTokenText;
|
|
1188
|
+
exports.parseSnapshot = parseSnapshot;
|
|
1189
|
+
exports.resolveServerMessages = resolveServerMessages;
|
|
1190
|
+
exports.snakeCase = snakeCase;
|
|
1191
|
+
exports.snapshotChecksum = snapshotChecksum;
|
|
1192
|
+
exports.stripC0Controls = stripC0Controls;
|
|
1193
|
+
exports.templateMarkers = templateMarkers;
|
|
1194
|
+
exports.toServerMessage = toServerMessage;
|
|
1195
|
+
//# sourceMappingURL=pure.js.map
|
|
1196
|
+
//# sourceMappingURL=pure.js.map
|