@fluenti/cli 0.1.3 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +9 -9
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +206 -209
- package/dist/cli.js.map +1 -1
- package/dist/compile-runner.d.ts +7 -0
- package/dist/compile-runner.d.ts.map +1 -0
- package/dist/compile.d.ts.map +1 -1
- package/dist/{compile-BJdEF9QX.js → config-loader-BgAoTfxH.js} +123 -93
- package/dist/config-loader-BgAoTfxH.js.map +1 -0
- package/dist/config-loader-D3RGkK_r.cjs +16 -0
- package/dist/config-loader-D3RGkK_r.cjs.map +1 -0
- package/dist/config-loader.d.ts +7 -0
- package/dist/config-loader.d.ts.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -6
- package/dist/index.js.map +1 -1
- package/dist/translate.d.ts +2 -1
- package/dist/translate.d.ts.map +1 -1
- package/dist/{tsx-extractor-DZrY1LMS.js → tsx-extractor-CcFjsYI-.js} +1 -1
- package/dist/{tsx-extractor-DZrY1LMS.js.map → tsx-extractor-CcFjsYI-.js.map} +1 -1
- package/dist/tsx-extractor-D__s_cP8.cjs +2 -0
- package/dist/{tsx-extractor-LEAVCuX9.cjs.map → tsx-extractor-D__s_cP8.cjs.map} +1 -1
- package/dist/vue-extractor.cjs +3 -0
- package/dist/vue-extractor.cjs.map +1 -0
- package/dist/{vue-extractor-iUl6SUkv.js → vue-extractor.js} +60 -67
- package/dist/vue-extractor.js.map +1 -0
- package/package.json +27 -2
- package/dist/compile-BJdEF9QX.js.map +0 -1
- package/dist/compile-d4Q8bND5.cjs +0 -16
- package/dist/compile-d4Q8bND5.cjs.map +0 -1
- package/dist/tsx-extractor-LEAVCuX9.cjs +0 -2
- package/dist/vue-extractor-BlHc3vzt.cjs +0 -3
- package/dist/vue-extractor-BlHc3vzt.cjs.map +0 -1
- package/dist/vue-extractor-iUl6SUkv.js.map +0 -1
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { hashMessage as e, parse as t } from "@fluenti/core";
|
|
2
2
|
import * as n from "gettext-parser";
|
|
3
|
+
import { existsSync as r } from "node:fs";
|
|
4
|
+
import { resolve as i } from "node:path";
|
|
3
5
|
//#region src/catalog.ts
|
|
4
|
-
function
|
|
5
|
-
let r = new Set(t.map((e) => e.id)),
|
|
6
|
+
function a(e, t, n) {
|
|
7
|
+
let r = new Set(t.map((e) => e.id)), i = /* @__PURE__ */ new Set(), a = {}, c = 0, l = 0, u = 0;
|
|
6
8
|
for (let r of t) {
|
|
7
|
-
let t = e[r.id], u = t ? void 0 :
|
|
8
|
-
if (u &&
|
|
9
|
+
let t = e[r.id], u = t ? void 0 : s(e, r, i), d = `${r.origin.file}:${r.origin.line}`, f = t ?? u?.entry;
|
|
10
|
+
if (u && i.add(u.id), f) a[r.id] = {
|
|
9
11
|
...f,
|
|
10
12
|
message: r.message ?? f.message,
|
|
11
13
|
context: r.context,
|
|
@@ -13,26 +15,26 @@ function r(e, t, n) {
|
|
|
13
15
|
origin: d,
|
|
14
16
|
obsolete: !1
|
|
15
17
|
}, l++;
|
|
16
|
-
else if (
|
|
17
|
-
let e =
|
|
18
|
-
|
|
18
|
+
else if (a[r.id]) {
|
|
19
|
+
let e = a[r.id];
|
|
20
|
+
a[r.id] = {
|
|
19
21
|
...e,
|
|
20
|
-
origin:
|
|
22
|
+
origin: o(e.origin, d)
|
|
21
23
|
};
|
|
22
|
-
} else
|
|
24
|
+
} else a[r.id] = {
|
|
23
25
|
message: r.message,
|
|
24
26
|
context: r.context,
|
|
25
27
|
comment: r.comment,
|
|
26
28
|
origin: d
|
|
27
29
|
}, c++;
|
|
28
30
|
if (n?.stripFuzzy) {
|
|
29
|
-
let { fuzzy: e, ...t } =
|
|
30
|
-
|
|
31
|
+
let { fuzzy: e, ...t } = a[r.id];
|
|
32
|
+
a[r.id] = t;
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
for (let [t, i] of Object.entries(e)) if (!r.has(t)) {
|
|
34
36
|
let { fuzzy: e, ...r } = i;
|
|
35
|
-
|
|
37
|
+
a[t] = n?.stripFuzzy ? {
|
|
36
38
|
...r,
|
|
37
39
|
obsolete: !0
|
|
38
40
|
} : {
|
|
@@ -41,7 +43,7 @@ function r(e, t, n) {
|
|
|
41
43
|
}, u++;
|
|
42
44
|
}
|
|
43
45
|
return {
|
|
44
|
-
catalog:
|
|
46
|
+
catalog: a,
|
|
45
47
|
result: {
|
|
46
48
|
added: c,
|
|
47
49
|
unchanged: l,
|
|
@@ -49,28 +51,28 @@ function r(e, t, n) {
|
|
|
49
51
|
}
|
|
50
52
|
};
|
|
51
53
|
}
|
|
52
|
-
function
|
|
54
|
+
function o(e, t) {
|
|
53
55
|
if (!e) return t;
|
|
54
56
|
let n = Array.isArray(e) ? e : [e], r = [...new Set([...n, t])];
|
|
55
57
|
return r.length === 1 ? r[0] : r;
|
|
56
58
|
}
|
|
57
|
-
function
|
|
59
|
+
function s(e, t, n) {
|
|
58
60
|
if (!t.context) return;
|
|
59
61
|
let r = `${t.origin.file}:${t.origin.line}`;
|
|
60
|
-
for (let [i, a] of Object.entries(e)) if (!n.has(i) && a.context === void 0 && a.message === t.message &&
|
|
62
|
+
for (let [i, a] of Object.entries(e)) if (!n.has(i) && a.context === void 0 && a.message === t.message && c(a.origin, r)) return {
|
|
61
63
|
id: i,
|
|
62
64
|
entry: a
|
|
63
65
|
};
|
|
64
66
|
}
|
|
65
|
-
function
|
|
66
|
-
return e ? (Array.isArray(e) ? e : [e]).some((e) => e === t ||
|
|
67
|
+
function c(e, t) {
|
|
68
|
+
return e ? (Array.isArray(e) ? e : [e]).some((e) => e === t || l(e) === l(t)) : !1;
|
|
67
69
|
}
|
|
68
|
-
function
|
|
70
|
+
function l(e) {
|
|
69
71
|
return e.match(/^(.*):\d+$/)?.[1] ?? e;
|
|
70
72
|
}
|
|
71
73
|
//#endregion
|
|
72
74
|
//#region src/json-format.ts
|
|
73
|
-
function
|
|
75
|
+
function u(e) {
|
|
74
76
|
let t = JSON.parse(e), n = {};
|
|
75
77
|
for (let [e, r] of Object.entries(t)) if (typeof r == "object" && r) {
|
|
76
78
|
let t = r;
|
|
@@ -86,7 +88,7 @@ function c(e) {
|
|
|
86
88
|
}
|
|
87
89
|
return n;
|
|
88
90
|
}
|
|
89
|
-
function
|
|
91
|
+
function d(e) {
|
|
90
92
|
let t = {};
|
|
91
93
|
for (let [n, r] of Object.entries(e)) {
|
|
92
94
|
let e = {};
|
|
@@ -96,14 +98,14 @@ function l(e) {
|
|
|
96
98
|
}
|
|
97
99
|
//#endregion
|
|
98
100
|
//#region src/po-format.ts
|
|
99
|
-
var
|
|
100
|
-
function
|
|
101
|
+
var f = "fluenti-id:";
|
|
102
|
+
function p(t) {
|
|
101
103
|
let r = n.po.parse(t), i = {}, a = r.translations ?? {};
|
|
102
104
|
for (let [t, n] of Object.entries(a)) for (let [r, a] of Object.entries(n)) {
|
|
103
105
|
if (!r) continue;
|
|
104
|
-
let n = t || a.msgctxt || void 0, o = a.msgstr?.[0] ?? void 0, s = a.comments?.reference ?? void 0, c = s?.includes("\n") ? s.split("\n").map((e) => e.trim()).filter(Boolean) : s?.includes(" ") ? s.split(/\s+/).filter(Boolean) : s, l = Array.isArray(c) && c.length === 1 ? c[0] : c, u = a.comments?.flag?.includes("fuzzy") ?? !1, { comment: d, customId: f, sourceMessage:
|
|
106
|
+
let n = t || a.msgctxt || void 0, o = a.msgstr?.[0] ?? void 0, s = a.comments?.reference ?? void 0, c = s?.includes("\n") ? s.split("\n").map((e) => e.trim()).filter(Boolean) : s?.includes(" ") ? s.split(/\s+/).filter(Boolean) : s, l = Array.isArray(c) && c.length === 1 ? c[0] : c, u = a.comments?.flag?.includes("fuzzy") ?? !1, { comment: d, customId: f, sourceMessage: p } = h(a.comments?.extracted), m = p && e(p, n) === r ? p : void 0, g = f ?? (m ? r : e(r, n));
|
|
105
107
|
i[g] = {
|
|
106
|
-
message:
|
|
108
|
+
message: m ?? r,
|
|
107
109
|
...n === void 0 ? {} : { context: n },
|
|
108
110
|
...d === void 0 ? {} : { comment: d },
|
|
109
111
|
...o ? { translation: o } : {},
|
|
@@ -113,7 +115,7 @@ function d(t) {
|
|
|
113
115
|
}
|
|
114
116
|
return i;
|
|
115
117
|
}
|
|
116
|
-
function
|
|
118
|
+
function m(e) {
|
|
117
119
|
let t = { "": { "": {
|
|
118
120
|
msgid: "",
|
|
119
121
|
msgstr: ["Content-Type: text/plain; charset=UTF-8\n"]
|
|
@@ -125,7 +127,7 @@ function f(e) {
|
|
|
125
127
|
msgstr: [r.translation ?? ""]
|
|
126
128
|
}, i = {};
|
|
127
129
|
r.origin && (i.reference = Array.isArray(r.origin) ? r.origin.join("\n") : r.origin);
|
|
128
|
-
let a =
|
|
130
|
+
let a = _(n, r.message ?? n, r.context, r.comment);
|
|
129
131
|
a && (i.extracted = a), r.fuzzy && (i.flag = "fuzzy"), (i.reference || i.extracted || i.flag) && (e.comments = i);
|
|
130
132
|
let o = r.context ?? "";
|
|
131
133
|
t[o] ??= {}, t[o][e.msgid] = e;
|
|
@@ -136,11 +138,11 @@ function f(e) {
|
|
|
136
138
|
};
|
|
137
139
|
return n.po.compile(r).toString();
|
|
138
140
|
}
|
|
139
|
-
function
|
|
141
|
+
function h(e) {
|
|
140
142
|
if (!e) return {};
|
|
141
143
|
let t = e.split("\n").map((e) => e.trim()).filter(Boolean), n, r, i = [];
|
|
142
144
|
for (let e of t) {
|
|
143
|
-
if (e.startsWith(
|
|
145
|
+
if (e.startsWith(f)) {
|
|
144
146
|
n = e.slice(11).trim() || void 0;
|
|
145
147
|
continue;
|
|
146
148
|
}
|
|
@@ -149,7 +151,7 @@ function p(e) {
|
|
|
149
151
|
continue;
|
|
150
152
|
}
|
|
151
153
|
if (e.startsWith("Trans: ")) {
|
|
152
|
-
r =
|
|
154
|
+
r = g(e.slice(7));
|
|
153
155
|
continue;
|
|
154
156
|
}
|
|
155
157
|
i.push(e);
|
|
@@ -160,7 +162,7 @@ function p(e) {
|
|
|
160
162
|
...r ? { sourceMessage: r } : {}
|
|
161
163
|
};
|
|
162
164
|
}
|
|
163
|
-
function
|
|
165
|
+
function g(e) {
|
|
164
166
|
let t = [], n = 0;
|
|
165
167
|
return e.replace(/<\/?([a-zA-Z][\w-]*)>/g, (e, r) => {
|
|
166
168
|
let i = r;
|
|
@@ -178,75 +180,78 @@ function m(e) {
|
|
|
178
180
|
}), `<${a}>`;
|
|
179
181
|
});
|
|
180
182
|
}
|
|
181
|
-
function
|
|
183
|
+
function _(t, n, r, i) {
|
|
182
184
|
let a = [];
|
|
183
|
-
return i && a.push(i), t !== e(n, r) && a.push(`${
|
|
185
|
+
return i && a.push(i), t !== e(n, r) && a.push(`${f} ${t}`), a.length > 0 ? a.join("\n") : void 0;
|
|
184
186
|
}
|
|
185
187
|
//#endregion
|
|
186
188
|
//#region src/compile.ts
|
|
187
|
-
var
|
|
188
|
-
function
|
|
189
|
-
return
|
|
189
|
+
var v = /\{(\w+)\}/g, y = /\{(\w+)\}/;
|
|
190
|
+
function b(e) {
|
|
191
|
+
return y.test(e);
|
|
190
192
|
}
|
|
191
|
-
function
|
|
193
|
+
function x(e) {
|
|
192
194
|
return e.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "\\r");
|
|
193
195
|
}
|
|
194
|
-
function
|
|
196
|
+
function S(e, t) {
|
|
197
|
+
return /^\d/.test(t) ? `${e}[${t}]` : `${e}.${t}`;
|
|
198
|
+
}
|
|
199
|
+
function C(e) {
|
|
195
200
|
return e.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${").replace(/\n/g, "\\n").replace(/\r/g, "\\r");
|
|
196
201
|
}
|
|
197
|
-
function
|
|
198
|
-
return e.replace(
|
|
202
|
+
function w(e) {
|
|
203
|
+
return e.replace(v, (e, t) => `\${${S("v", t)}}`);
|
|
199
204
|
}
|
|
200
|
-
var
|
|
201
|
-
function
|
|
202
|
-
return
|
|
205
|
+
var T = /\{(\w+),\s*(plural|select|selectordinal)\s*,/;
|
|
206
|
+
function E(e) {
|
|
207
|
+
return T.test(e);
|
|
203
208
|
}
|
|
204
|
-
function
|
|
209
|
+
function D(e, t) {
|
|
205
210
|
if (e.length === 0) return "''";
|
|
206
|
-
let n = e.map((e) =>
|
|
211
|
+
let n = e.map((e) => O(e, t));
|
|
207
212
|
return n.length === 1 ? n[0] : n.join(" + ");
|
|
208
213
|
}
|
|
209
|
-
function
|
|
214
|
+
function O(e, t) {
|
|
210
215
|
switch (e.type) {
|
|
211
|
-
case "text": return `'${
|
|
212
|
-
case "variable": return e.name === "#" ? "String(__c)" : `String(v
|
|
213
|
-
case "plural": return
|
|
214
|
-
case "select": return
|
|
215
|
-
case "function": return `String(v
|
|
216
|
+
case "text": return `'${x(e.value)}'`;
|
|
217
|
+
case "variable": return e.name === "#" ? "String(__c)" : `String(${S("v", e.name)} ?? '{${e.name}}')`;
|
|
218
|
+
case "plural": return k(e, t);
|
|
219
|
+
case "select": return A(e, t);
|
|
220
|
+
case "function": return `String(${S("v", e.variable)} ?? '')`;
|
|
216
221
|
}
|
|
217
222
|
}
|
|
218
|
-
function
|
|
219
|
-
let n = e.offset ?? 0, r = n ? `(
|
|
220
|
-
|
|
221
|
-
let
|
|
222
|
-
if (
|
|
223
|
-
let r = n.slice(1),
|
|
224
|
-
|
|
223
|
+
function k(e, t) {
|
|
224
|
+
let n = e.offset ?? 0, r = S("v", e.variable), i = n ? `(${r} - ${n})` : r, a = [];
|
|
225
|
+
a.push("((c) => { const __c = c; ");
|
|
226
|
+
let o = Object.keys(e.options).filter((e) => e.startsWith("="));
|
|
227
|
+
if (o.length > 0) for (let n of o) {
|
|
228
|
+
let r = n.slice(1), i = D(e.options[n], t);
|
|
229
|
+
a.push(`if (c === ${r}) return ${i}; `);
|
|
225
230
|
}
|
|
226
|
-
let
|
|
227
|
-
if (
|
|
228
|
-
|
|
229
|
-
for (let n of
|
|
231
|
+
let s = Object.keys(e.options).filter((e) => !e.startsWith("="));
|
|
232
|
+
if (s.length > 1 || s.length === 1 && s[0] !== "other") {
|
|
233
|
+
a.push(`const __cat = new Intl.PluralRules('${x(t)}').select(c); `);
|
|
234
|
+
for (let n of s) {
|
|
230
235
|
if (n === "other") continue;
|
|
231
|
-
let r =
|
|
232
|
-
|
|
236
|
+
let r = D(e.options[n], t);
|
|
237
|
+
a.push(`if (__cat === '${n}') return ${r}; `);
|
|
233
238
|
}
|
|
234
239
|
}
|
|
235
|
-
let
|
|
236
|
-
return
|
|
240
|
+
let c = e.options.other ? D(e.options.other, t) : "''";
|
|
241
|
+
return a.push(`return ${c}; `), a.push(`})(${i})`), a.join("");
|
|
237
242
|
}
|
|
238
|
-
function
|
|
243
|
+
function A(e, t) {
|
|
239
244
|
let n = [];
|
|
240
245
|
n.push("((s) => { ");
|
|
241
246
|
let r = Object.keys(e.options).filter((e) => e !== "other");
|
|
242
247
|
for (let i of r) {
|
|
243
|
-
let r =
|
|
244
|
-
n.push(`if (s === '${
|
|
248
|
+
let r = D(e.options[i], t);
|
|
249
|
+
n.push(`if (s === '${x(i)}') return ${r}; `);
|
|
245
250
|
}
|
|
246
|
-
let i = e.options.other ?
|
|
247
|
-
return n.push(`return ${i}; `), n.push(`})(String(v
|
|
251
|
+
let i = e.options.other ? D(e.options.other, t) : "''";
|
|
252
|
+
return n.push(`return ${i}; `), n.push(`})(String(${S("v", e.variable)} ?? ''))`), n.join("");
|
|
248
253
|
}
|
|
249
|
-
function
|
|
254
|
+
function j(n, r, i, a, o) {
|
|
250
255
|
let s = [];
|
|
251
256
|
s.push("// @fluenti/compiled v1");
|
|
252
257
|
let c = [], l = 0, u = [], d = /* @__PURE__ */ new Map();
|
|
@@ -254,15 +259,15 @@ function O(n, r, i, a, o) {
|
|
|
254
259
|
let i = e(f), p = d.get(i);
|
|
255
260
|
if (p !== void 0 && p !== f) throw Error(`Hash collision detected: messages "${p}" and "${f}" produce the same hash "${i}"`);
|
|
256
261
|
d.set(i, f);
|
|
257
|
-
let m = `_${i}`, h = n[f], g =
|
|
262
|
+
let m = `_${i}`, h = n[f], g = M(h, f, r, a, o?.skipFuzzy);
|
|
258
263
|
if (g === void 0) s.push(`export const ${m} = undefined`), u.push(f);
|
|
259
|
-
else if (
|
|
260
|
-
let e =
|
|
264
|
+
else if (E(g)) {
|
|
265
|
+
let e = D(t(g), r);
|
|
261
266
|
s.push(`export const ${m} = (v) => ${e}`), l++;
|
|
262
|
-
} else if (
|
|
263
|
-
let e =
|
|
267
|
+
} else if (b(g)) {
|
|
268
|
+
let e = w(C(g));
|
|
264
269
|
s.push(`export const ${m} = (v) => \`${e}\``), l++;
|
|
265
|
-
} else s.push(`export const ${m} = '${
|
|
270
|
+
} else s.push(`export const ${m} = '${x(g)}'`), l++;
|
|
266
271
|
c.push({
|
|
267
272
|
id: f,
|
|
268
273
|
exportName: m
|
|
@@ -276,7 +281,7 @@ function O(n, r, i, a, o) {
|
|
|
276
281
|
}
|
|
277
282
|
};
|
|
278
283
|
s.push(""), s.push("export default {");
|
|
279
|
-
for (let { id: e, exportName: t } of c) s.push(` '${
|
|
284
|
+
for (let { id: e, exportName: t } of c) s.push(` '${x(e)}': ${t},`);
|
|
280
285
|
return s.push("}"), s.push(""), {
|
|
281
286
|
code: s.join("\n"),
|
|
282
287
|
stats: {
|
|
@@ -285,32 +290,32 @@ function O(n, r, i, a, o) {
|
|
|
285
290
|
}
|
|
286
291
|
};
|
|
287
292
|
}
|
|
288
|
-
function
|
|
293
|
+
function M(e, t, n, r, i) {
|
|
289
294
|
let a = r ?? n;
|
|
290
295
|
if (e && !(i && e.fuzzy)) {
|
|
291
296
|
if (e.translation !== void 0 && e.translation.length > 0) return e.translation;
|
|
292
297
|
if (n === a) return e.message ?? t;
|
|
293
298
|
}
|
|
294
299
|
}
|
|
295
|
-
function
|
|
300
|
+
function N(e, t) {
|
|
296
301
|
let n = [];
|
|
297
302
|
n.push(`export const locales = ${JSON.stringify(e)}`), n.push(""), n.push("export const loaders = {");
|
|
298
|
-
for (let t of e) n.push(` '${
|
|
303
|
+
for (let t of e) n.push(` '${x(t)}': () => import('./${x(t)}.js'),`);
|
|
299
304
|
return n.push("}"), n.push(""), n.join("\n");
|
|
300
305
|
}
|
|
301
|
-
function
|
|
306
|
+
function P(e) {
|
|
302
307
|
let t = /* @__PURE__ */ new Set();
|
|
303
308
|
for (let n of Object.values(e)) for (let [e, r] of Object.entries(n)) r.obsolete || t.add(e);
|
|
304
309
|
return [...t].sort();
|
|
305
310
|
}
|
|
306
|
-
function
|
|
311
|
+
function F(e) {
|
|
307
312
|
let n = t(e), r = /* @__PURE__ */ new Map();
|
|
308
|
-
return
|
|
313
|
+
return I(n, r), [...r.entries()].sort(([e], [t]) => e.localeCompare(t)).map(([e, t]) => ({
|
|
309
314
|
name: e,
|
|
310
315
|
type: t
|
|
311
316
|
}));
|
|
312
317
|
}
|
|
313
|
-
function
|
|
318
|
+
function I(e, t) {
|
|
314
319
|
for (let n of e) switch (n.type) {
|
|
315
320
|
case "variable":
|
|
316
321
|
n.name !== "#" && !t.has(n.name) && t.set(n.name, "string | number");
|
|
@@ -318,13 +323,13 @@ function N(e, t) {
|
|
|
318
323
|
case "plural": {
|
|
319
324
|
let e = n;
|
|
320
325
|
t.set(e.variable, "number");
|
|
321
|
-
for (let n of Object.values(e.options))
|
|
326
|
+
for (let n of Object.values(e.options)) I(n, t);
|
|
322
327
|
break;
|
|
323
328
|
}
|
|
324
329
|
case "select": {
|
|
325
330
|
let e = n, r = Object.keys(e.options).filter((e) => e !== "other"), i = "other" in e.options, a = r.map((e) => `'${e}'`).join(" | "), o = i ? r.length > 0 ? `${a} | string` : "string" : r.length > 0 ? a : "string";
|
|
326
331
|
t.set(e.variable, o);
|
|
327
|
-
for (let n of Object.values(e.options))
|
|
332
|
+
for (let n of Object.values(e.options)) I(n, t);
|
|
328
333
|
break;
|
|
329
334
|
}
|
|
330
335
|
case "function":
|
|
@@ -333,16 +338,16 @@ function N(e, t) {
|
|
|
333
338
|
case "text": break;
|
|
334
339
|
}
|
|
335
340
|
}
|
|
336
|
-
function
|
|
341
|
+
function L(e, t, n) {
|
|
337
342
|
let r = [];
|
|
338
343
|
if (r.push("// Auto-generated by @fluenti/cli — do not edit"), r.push(""), e.length === 0) r.push("export type MessageId = never");
|
|
339
344
|
else {
|
|
340
345
|
r.push("export type MessageId =");
|
|
341
|
-
for (let t of e) r.push(` | '${
|
|
346
|
+
for (let t of e) r.push(` | '${x(t)}'`);
|
|
342
347
|
}
|
|
343
348
|
r.push(""), r.push("export interface MessageValues {");
|
|
344
349
|
for (let i of e) {
|
|
345
|
-
let e =
|
|
350
|
+
let e = F(t[n]?.[i]?.message ?? i), a = x(i);
|
|
346
351
|
if (e.length === 0) r.push(` '${a}': Record<string, never>`);
|
|
347
352
|
else {
|
|
348
353
|
let t = e.map((e) => `${e.name}: ${e.type}`).join("; ");
|
|
@@ -352,6 +357,31 @@ function P(e, t, n) {
|
|
|
352
357
|
return r.push("}"), r.push(""), r.join("\n");
|
|
353
358
|
}
|
|
354
359
|
//#endregion
|
|
355
|
-
|
|
360
|
+
//#region src/config-loader.ts
|
|
361
|
+
var R = {
|
|
362
|
+
sourceLocale: "en",
|
|
363
|
+
locales: ["en"],
|
|
364
|
+
catalogDir: "./locales",
|
|
365
|
+
format: "po",
|
|
366
|
+
include: ["./src/**/*.{vue,tsx,jsx,ts,js}"],
|
|
367
|
+
compileOutDir: "./src/locales/compiled"
|
|
368
|
+
};
|
|
369
|
+
async function z(e, t) {
|
|
370
|
+
let n = t ?? process.cwd(), a = e ? [i(n, e)] : [
|
|
371
|
+
i(n, "fluenti.config.ts"),
|
|
372
|
+
i(n, "fluenti.config.js"),
|
|
373
|
+
i(n, "fluenti.config.mjs")
|
|
374
|
+
];
|
|
375
|
+
for (let e of a) if (r(e)) {
|
|
376
|
+
let { createJiti: t } = await import("jiti"), n = await t(import.meta.url).import(e), r = n.default ?? n;
|
|
377
|
+
return {
|
|
378
|
+
...R,
|
|
379
|
+
...r
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
return R;
|
|
383
|
+
}
|
|
384
|
+
//#endregion
|
|
385
|
+
export { L as a, u as c, N as i, d as l, P as n, p as o, j as r, m as s, z as t, a as u };
|
|
356
386
|
|
|
357
|
-
//# sourceMappingURL=
|
|
387
|
+
//# sourceMappingURL=config-loader-BgAoTfxH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-loader-BgAoTfxH.js","names":[],"sources":["../src/catalog.ts","../src/json-format.ts","../src/po-format.ts","../src/compile.ts","../src/config-loader.ts"],"sourcesContent":["import type { ExtractedMessage } from '@fluenti/core'\n\nexport interface CatalogEntry {\n message?: string | undefined\n context?: string | undefined\n comment?: string | undefined\n translation?: string | undefined\n origin?: string | string[] | undefined\n obsolete?: boolean | undefined\n fuzzy?: boolean | undefined\n}\n\nexport type CatalogData = Record<string, CatalogEntry>\n\nexport interface UpdateResult {\n added: number\n unchanged: number\n obsolete: number\n}\n\nexport interface UpdateCatalogOptions {\n stripFuzzy?: boolean\n}\n\n/** Update catalog with newly extracted messages */\nexport function updateCatalog(\n existing: CatalogData,\n extracted: ExtractedMessage[],\n options?: UpdateCatalogOptions,\n): { catalog: CatalogData; result: UpdateResult } {\n const extractedIds = new Set(extracted.map((m) => m.id))\n const consumedCarryForwardIds = new Set<string>()\n const catalog: CatalogData = {}\n let added = 0\n let unchanged = 0\n let obsolete = 0\n\n for (const msg of extracted) {\n const existingEntry = existing[msg.id]\n const carried = existingEntry\n ? undefined\n : findCarryForwardEntry(existing, msg, consumedCarryForwardIds)\n const origin = `${msg.origin.file}:${msg.origin.line}`\n const baseEntry = existingEntry ?? carried?.entry\n\n if (carried) {\n consumedCarryForwardIds.add(carried.id)\n }\n\n if (baseEntry) {\n catalog[msg.id] = {\n ...baseEntry,\n message: msg.message ?? baseEntry.message,\n context: msg.context,\n comment: msg.comment,\n origin,\n obsolete: false,\n }\n unchanged++\n } else if (catalog[msg.id]) {\n // Same ID already seen in this extraction batch — merge origin\n const existing = catalog[msg.id]!\n catalog[msg.id] = {\n ...existing,\n origin: mergeOrigins(existing.origin, origin),\n }\n } else {\n catalog[msg.id] = {\n message: msg.message,\n context: msg.context,\n comment: msg.comment,\n origin,\n }\n added++\n }\n\n if (options?.stripFuzzy) {\n const { fuzzy: _fuzzy, ...rest } = catalog[msg.id]!\n catalog[msg.id] = rest\n }\n }\n\n for (const [id, entry] of Object.entries(existing)) {\n if (!extractedIds.has(id)) {\n const { fuzzy: _fuzzy, ...rest } = entry\n const obsoleteEntry = options?.stripFuzzy\n ? { ...rest, obsolete: true }\n : { ...entry, obsolete: true }\n catalog[id] = obsoleteEntry\n obsolete++\n }\n }\n\n return { catalog, result: { added, unchanged, obsolete } }\n}\n\nfunction mergeOrigins(\n existing: string | string[] | undefined,\n newOrigin: string,\n): string | string[] {\n if (!existing) return newOrigin\n const existingArray = Array.isArray(existing) ? existing : [existing]\n const merged = [...new Set([...existingArray, newOrigin])]\n return merged.length === 1 ? merged[0]! : merged\n}\n\nfunction findCarryForwardEntry(\n existing: CatalogData,\n extracted: ExtractedMessage,\n consumedCarryForwardIds: Set<string>,\n): { id: string; entry: CatalogEntry } | undefined {\n if (!extracted.context) {\n return undefined\n }\n\n const extractedOrigin = `${extracted.origin.file}:${extracted.origin.line}`\n for (const [id, entry] of Object.entries(existing)) {\n if (consumedCarryForwardIds.has(id)) continue\n if (entry.context !== undefined) continue\n if (entry.message !== extracted.message) continue\n if (!sameOrigin(entry.origin, extractedOrigin)) continue\n return { id, entry }\n }\n\n return undefined\n}\n\nfunction sameOrigin(previous: string | string[] | undefined, next: string): boolean {\n if (!previous) return false\n const origins = Array.isArray(previous) ? previous : [previous]\n return origins.some((o) => o === next || originFile(o) === originFile(next))\n}\n\nfunction originFile(origin: string): string {\n const match = origin.match(/^(.*):\\d+$/)\n return match?.[1] ?? origin\n}\n","import type { CatalogData } from './catalog'\n\n/** Read a JSON catalog file */\nexport function readJsonCatalog(content: string): CatalogData {\n const raw = JSON.parse(content) as Record<string, unknown>\n const catalog: CatalogData = {}\n\n for (const [id, entry] of Object.entries(raw)) {\n if (typeof entry === 'object' && entry !== null) {\n const e = entry as Record<string, unknown>\n catalog[id] = {\n message: typeof e['message'] === 'string' ? e['message'] : undefined,\n context: typeof e['context'] === 'string' ? e['context'] : undefined,\n comment: typeof e['comment'] === 'string' ? e['comment'] : undefined,\n translation: typeof e['translation'] === 'string' ? e['translation'] : undefined,\n origin: typeof e['origin'] === 'string'\n ? e['origin']\n : Array.isArray(e['origin']) && (e['origin'] as unknown[]).every((v) => typeof v === 'string')\n ? (e['origin'] as string[])\n : undefined,\n obsolete: typeof e['obsolete'] === 'boolean' ? e['obsolete'] : undefined,\n fuzzy: typeof e['fuzzy'] === 'boolean' ? e['fuzzy'] : undefined,\n }\n }\n }\n\n return catalog\n}\n\n/** Write a catalog to JSON format */\nexport function writeJsonCatalog(catalog: CatalogData): string {\n const output: Record<string, Record<string, unknown>> = {}\n\n for (const [id, entry] of Object.entries(catalog)) {\n const obj: Record<string, unknown> = {}\n if (entry.message !== undefined) obj['message'] = entry.message\n if (entry.context !== undefined) obj['context'] = entry.context\n if (entry.comment !== undefined) obj['comment'] = entry.comment\n if (entry.translation !== undefined) obj['translation'] = entry.translation\n if (entry.origin !== undefined) obj['origin'] = entry.origin\n if (entry.obsolete) obj['obsolete'] = true\n if (entry.fuzzy) obj['fuzzy'] = true\n output[id] = obj\n }\n\n return JSON.stringify(output, null, 2) + '\\n'\n}\n","import type { CatalogData } from './catalog'\nimport { hashMessage } from '@fluenti/core'\nimport * as gettextParser from 'gettext-parser'\n\nconst CUSTOM_ID_MARKER = 'fluenti-id:'\n\ninterface POTranslation {\n msgid: string\n msgctxt?: string\n msgstr: string[]\n comments?: {\n reference?: string\n extracted?: string\n flag?: string\n translator?: string\n previous?: string\n }\n}\n\ninterface POData {\n headers?: Record<string, string>\n translations: Record<string, Record<string, POTranslation>>\n}\n\ninterface ParsedExtractedComment {\n comment?: string\n customId?: string\n sourceMessage?: string\n}\n\n/** Read a PO catalog file */\nexport function readPoCatalog(content: string): CatalogData {\n const po = gettextParser.po.parse(content) as POData\n const catalog: CatalogData = {}\n const translations = po.translations ?? {}\n\n for (const [contextKey, entries] of Object.entries(translations)) {\n for (const [msgid, entry] of Object.entries(entries)) {\n if (!msgid) continue\n\n const context = contextKey || entry.msgctxt || undefined\n const translation = entry.msgstr?.[0] ?? undefined\n const rawReference = entry.comments?.reference ?? undefined\n const origin = rawReference?.includes('\\n')\n ? rawReference.split('\\n').map((r: string) => r.trim()).filter(Boolean)\n : rawReference?.includes(' ')\n ? rawReference.split(/\\s+/).filter(Boolean)\n : rawReference\n const normalizedOrigin = Array.isArray(origin) && origin.length === 1 ? origin[0] : origin\n const isFuzzy = entry.comments?.flag?.includes('fuzzy') ?? false\n const { comment, customId, sourceMessage } = parseExtractedComment(entry.comments?.extracted)\n const resolvedSourceMessage = sourceMessage\n && hashMessage(sourceMessage, context) === msgid\n ? sourceMessage\n : undefined\n const id = customId\n ?? (resolvedSourceMessage ? msgid : hashMessage(msgid, context))\n\n catalog[id] = {\n message: resolvedSourceMessage ?? msgid,\n ...(context !== undefined ? { context } : {}),\n ...(comment !== undefined ? { comment } : {}),\n ...(translation ? { translation } : {}),\n ...(normalizedOrigin !== undefined ? { origin: normalizedOrigin } : {}),\n ...(isFuzzy ? { fuzzy: true } : {}),\n }\n }\n }\n\n return catalog\n}\n\n/** Write a catalog to PO format */\nexport function writePoCatalog(catalog: CatalogData): string {\n const translations: POData['translations'] = {\n '': {\n '': {\n msgid: '',\n msgstr: ['Content-Type: text/plain; charset=UTF-8\\n'],\n },\n },\n }\n\n for (const [id, entry] of Object.entries(catalog)) {\n const poEntry: POTranslation = {\n msgid: entry.message ?? id,\n ...(entry.context !== undefined ? { msgctxt: entry.context } : {}),\n msgstr: [entry.translation ?? ''],\n }\n\n const comments: POTranslation['comments'] = {}\n if (entry.origin) {\n comments.reference = Array.isArray(entry.origin)\n ? entry.origin.join('\\n')\n : entry.origin\n }\n const extractedComment = buildExtractedComment(id, entry.message ?? id, entry.context, entry.comment)\n if (extractedComment) {\n comments.extracted = extractedComment\n }\n if (entry.fuzzy) {\n comments.flag = 'fuzzy'\n }\n if (comments.reference || comments.extracted || comments.flag) {\n poEntry.comments = comments\n }\n\n const contextKey = entry.context ?? ''\n translations[contextKey] ??= {}\n translations[contextKey][poEntry.msgid] = poEntry\n }\n\n const poData: POData = {\n headers: {\n 'Content-Type': 'text/plain; charset=UTF-8',\n },\n translations,\n }\n\n const buffer = gettextParser.po.compile(poData as Parameters<typeof gettextParser.po.compile>[0])\n return buffer.toString()\n}\n\nfunction parseExtractedComment(\n extracted: string | undefined,\n): ParsedExtractedComment {\n if (!extracted) {\n return {}\n }\n\n const lines = extracted.split('\\n').map((line) => line.trim()).filter(Boolean)\n let customId: string | undefined\n let sourceMessage: string | undefined\n const commentLines: string[] = []\n\n for (const line of lines) {\n if (line.startsWith(CUSTOM_ID_MARKER)) {\n customId = line.slice(CUSTOM_ID_MARKER.length).trim() || undefined\n continue\n }\n if (line.startsWith('msg`') && line.endsWith('`')) {\n sourceMessage = line.slice(4, -1)\n continue\n }\n if (line.startsWith('Trans: ')) {\n sourceMessage = normalizeRichTextComment(line.slice('Trans: '.length))\n continue\n }\n commentLines.push(line)\n }\n\n return {\n ...(commentLines.length > 0 ? { comment: commentLines.join('\\n') } : {}),\n ...(customId ? { customId } : {}),\n ...(sourceMessage ? { sourceMessage } : {}),\n }\n}\n\nfunction normalizeRichTextComment(comment: string): string {\n let stack: Array<{ tag: string; index: number }> = []\n let nextIndex = 0\n\n return comment.replace(/<\\/?([a-zA-Z][\\w-]*)>/g, (match, rawTag: string) => {\n const tag = rawTag\n if (match.startsWith('</')) {\n for (let index = stack.length - 1; index >= 0; index--) {\n const entry = stack[index]\n if (entry?.tag !== tag) continue\n stack = stack.filter((_, i) => i !== index)\n return `</${entry.index}>`\n }\n return match\n }\n\n const index = nextIndex++\n stack.push({ tag, index })\n return `<${index}>`\n })\n}\n\nfunction buildExtractedComment(\n id: string,\n message: string,\n context: string | undefined,\n comment: string | undefined,\n): string | undefined {\n const lines: string[] = []\n\n if (comment) {\n lines.push(comment)\n }\n\n if (id !== hashMessage(message, context)) {\n lines.push(`${CUSTOM_ID_MARKER} ${id}`)\n }\n\n return lines.length > 0 ? lines.join('\\n') : undefined\n}\n","import type { CatalogData } from './catalog'\nimport { hashMessage } from '@fluenti/core'\nimport { parse } from '@fluenti/core'\nimport type { ASTNode, PluralNode, SelectNode, VariableNode, FunctionNode } from '@fluenti/core'\n\nconst ICU_VAR_REGEX = /\\{(\\w+)\\}/g\nconst ICU_VAR_TEST = /\\{(\\w+)\\}/\n\nfunction hasVariables(message: string): boolean {\n return ICU_VAR_TEST.test(message)\n}\n\n\nfunction escapeStringLiteral(str: string): string {\n return str\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/'/g, \"\\\\'\")\n .replace(/\\n/g, '\\\\n')\n .replace(/\\r/g, '\\\\r')\n}\n\n/** Generate safe JS property access: `v.name` for identifiers, `v[0]` for numeric names */\nfunction propAccess(obj: string, name: string): string {\n return /^\\d/.test(name) ? `${obj}[${name}]` : `${obj}.${name}`\n}\n\nfunction escapeTemplateLiteral(str: string): string {\n return str\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/`/g, '\\\\`')\n .replace(/\\$\\{/g, '\\\\${')\n .replace(/\\n/g, '\\\\n')\n .replace(/\\r/g, '\\\\r')\n}\n\nfunction messageToTemplateString(message: string): string {\n return message.replace(ICU_VAR_REGEX, (_match, name: string) => `\\${${propAccess('v', name)}}`)\n}\n\n\n// ─── ICU → JS code generation for split mode ───────────────────────────────\n\nconst ICU_PLURAL_SELECT_REGEX = /\\{(\\w+),\\s*(plural|select|selectordinal)\\s*,/\n\n/** Check if message contains ICU plural/select syntax */\nfunction hasIcuPluralOrSelect(message: string): boolean {\n return ICU_PLURAL_SELECT_REGEX.test(message)\n}\n\n/**\n * Compile an ICU AST node array into a JS expression string.\n * Used for generating static code (not runtime evaluation).\n */\nfunction astToJsExpression(nodes: ASTNode[], locale: string): string {\n if (nodes.length === 0) return \"''\"\n\n const parts = nodes.map((node) => astNodeToJs(node, locale))\n\n if (parts.length === 1) return parts[0]!\n return parts.join(' + ')\n}\n\nfunction astNodeToJs(node: ASTNode, locale: string): string {\n switch (node.type) {\n case 'text':\n return `'${escapeStringLiteral(node.value)}'`\n\n case 'variable':\n if (node.name === '#') return 'String(__c)'\n return `String(${propAccess('v', node.name)} ?? '{${node.name}}')`\n\n case 'plural':\n return pluralToJs(node as PluralNode, locale)\n\n case 'select':\n return selectToJs(node as SelectNode, locale)\n\n case 'function':\n return `String(${propAccess('v', node.variable)} ?? '')`\n }\n}\n\nfunction pluralToJs(node: PluralNode, locale: string): string {\n const offset = node.offset ?? 0\n const access = propAccess('v', node.variable)\n const countExpr = offset ? `(${access} - ${offset})` : access\n\n const lines: string[] = []\n lines.push(`((c) => { const __c = c; `)\n\n // Exact matches first\n const exactKeys = Object.keys(node.options).filter((k) => k.startsWith('='))\n if (exactKeys.length > 0) {\n for (const key of exactKeys) {\n const num = key.slice(1)\n const body = astToJsExpression(node.options[key]!, locale)\n lines.push(`if (c === ${num}) return ${body}; `)\n }\n }\n\n // CLDR categories via Intl.PluralRules\n const cldrKeys = Object.keys(node.options).filter((k) => !k.startsWith('='))\n if (cldrKeys.length > 1 || (cldrKeys.length === 1 && cldrKeys[0] !== 'other')) {\n lines.push(`const __cat = new Intl.PluralRules('${escapeStringLiteral(locale)}').select(c); `)\n for (const key of cldrKeys) {\n if (key === 'other') continue\n const body = astToJsExpression(node.options[key]!, locale)\n lines.push(`if (__cat === '${key}') return ${body}; `)\n }\n }\n\n // Fallback to 'other'\n const otherBody = node.options['other']\n ? astToJsExpression(node.options['other'], locale)\n : \"''\"\n lines.push(`return ${otherBody}; `)\n lines.push(`})(${countExpr})`)\n\n return lines.join('')\n}\n\nfunction selectToJs(node: SelectNode, locale: string): string {\n const lines: string[] = []\n lines.push(`((s) => { `)\n\n const keys = Object.keys(node.options).filter((k) => k !== 'other')\n for (const key of keys) {\n const body = astToJsExpression(node.options[key]!, locale)\n lines.push(`if (s === '${escapeStringLiteral(key)}') return ${body}; `)\n }\n\n const otherBody = node.options['other']\n ? astToJsExpression(node.options['other'], locale)\n : \"''\"\n lines.push(`return ${otherBody}; `)\n lines.push(`})(String(${propAccess('v', node.variable)} ?? ''))`)\n\n return lines.join('')\n}\n\n/**\n * Compile a catalog to ES module with tree-shakeable named exports.\n * Each message becomes a `/* @__PURE__ */` annotated named export.\n * A default export maps message IDs to their compiled values for runtime lookup.\n */\n/** Catalog format version. Bump when the compiled output format changes. */\nexport const CATALOG_VERSION = 1\n\nexport interface CompileStats {\n compiled: number\n missing: string[]\n}\n\nexport interface CompileOptions {\n skipFuzzy?: boolean\n}\n\nexport function compileCatalog(\n catalog: CatalogData,\n locale: string,\n allIds: string[],\n sourceLocale?: string,\n options?: CompileOptions,\n): { code: string; stats: CompileStats } {\n const lines: string[] = []\n lines.push(`// @fluenti/compiled v${CATALOG_VERSION}`)\n const exportNames: Array<{ id: string; exportName: string }> = []\n let compiled = 0\n const missing: string[] = []\n\n const hashToId = new Map<string, string>()\n\n for (const id of allIds) {\n const hash = hashMessage(id)\n\n const existingId = hashToId.get(hash)\n if (existingId !== undefined && existingId !== id) {\n throw new Error(\n `Hash collision detected: messages \"${existingId}\" and \"${id}\" produce the same hash \"${hash}\"`,\n )\n }\n hashToId.set(hash, id)\n\n const exportName = `_${hash}`\n const entry = catalog[id]\n const translated = resolveCompiledMessage(entry, id, locale, sourceLocale, options?.skipFuzzy)\n\n if (translated === undefined) {\n lines.push(`export const ${exportName} = undefined`)\n missing.push(id)\n } else if (hasIcuPluralOrSelect(translated)) {\n // Parse ICU and compile to JS\n const ast = parse(translated)\n const jsExpr = astToJsExpression(ast, locale)\n lines.push(`export const ${exportName} = (v) => ${jsExpr}`)\n compiled++\n } else if (hasVariables(translated)) {\n const templateStr = messageToTemplateString(escapeTemplateLiteral(translated))\n lines.push(`export const ${exportName} = (v) => \\`${templateStr}\\``)\n compiled++\n } else {\n lines.push(`export const ${exportName} = '${escapeStringLiteral(translated)}'`)\n compiled++\n }\n\n exportNames.push({ id, exportName })\n }\n\n if (exportNames.length === 0) {\n return {\n code: `// @fluenti/compiled v${CATALOG_VERSION}\\n// empty catalog\\nexport default {}\\n`,\n stats: { compiled: 0, missing: [] },\n }\n }\n\n // Default export maps message IDs → compiled values for runtime lookup\n lines.push('')\n lines.push('export default {')\n for (const { id, exportName } of exportNames) {\n lines.push(` '${escapeStringLiteral(id)}': ${exportName},`)\n }\n lines.push('}')\n lines.push('')\n\n return { code: lines.join('\\n'), stats: { compiled, missing } }\n}\n\nfunction resolveCompiledMessage(\n entry: CatalogData[string] | undefined,\n id: string,\n locale: string,\n sourceLocale: string | undefined,\n skipFuzzy?: boolean,\n): string | undefined {\n const effectiveSourceLocale = sourceLocale ?? locale\n\n if (!entry) {\n return undefined\n }\n\n if (skipFuzzy && entry.fuzzy) {\n return undefined\n }\n\n if (entry.translation !== undefined && entry.translation.length > 0) {\n return entry.translation\n }\n\n if (locale === effectiveSourceLocale) {\n return entry.message ?? id\n }\n\n return undefined\n}\n\n/**\n * Generate the index module that exports locale list and lazy loaders.\n */\nexport function compileIndex(locales: string[], _catalogDir: string): string {\n const lines: string[] = []\n lines.push(`export const locales = ${JSON.stringify(locales)}`)\n lines.push('')\n lines.push('export const loaders = {')\n for (const locale of locales) {\n lines.push(` '${escapeStringLiteral(locale)}': () => import('./${escapeStringLiteral(locale)}.js'),`)\n }\n lines.push('}')\n lines.push('')\n return lines.join('\\n')\n}\n\n/**\n * Collect the union of all message IDs across all locale catalogs.\n * Ensures every locale file exports the same names.\n */\nexport function collectAllIds(catalogs: Record<string, CatalogData>): string[] {\n const idSet = new Set<string>()\n for (const catalog of Object.values(catalogs)) {\n for (const [id, entry] of Object.entries(catalog)) {\n if (!entry.obsolete) {\n idSet.add(id)\n }\n }\n }\n return [...idSet].sort()\n}\n\n// ─── Type-safe message ID generation ─────────────────────────────────────────\n\nexport interface MessageVariable {\n name: string\n type: string\n}\n\n/**\n * Extract variable names and their TypeScript types from an ICU message string.\n */\nexport function extractMessageVariables(message: string): MessageVariable[] {\n const ast = parse(message)\n const vars = new Map<string, string>()\n collectVariablesFromNodes(ast, vars)\n return [...vars.entries()]\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([name, type]) => ({ name, type }))\n}\n\nfunction collectVariablesFromNodes(nodes: ASTNode[], vars: Map<string, string>): void {\n for (const node of nodes) {\n switch (node.type) {\n case 'variable':\n if (node.name !== '#' && !vars.has(node.name)) {\n vars.set((node as VariableNode).name, 'string | number')\n }\n break\n case 'plural': {\n const pn = node as PluralNode\n // Plural variable is always a number\n vars.set(pn.variable, 'number')\n // Recurse into plural option bodies\n for (const optionNodes of Object.values(pn.options)) {\n collectVariablesFromNodes(optionNodes, vars)\n }\n break\n }\n case 'select': {\n const sn = node as SelectNode\n const keys = Object.keys(sn.options).filter((k) => k !== 'other')\n const hasOther = 'other' in sn.options\n const literalTypes = keys.map((k) => `'${k}'`).join(' | ')\n const selectType = hasOther\n ? (keys.length > 0 ? `${literalTypes} | string` : 'string')\n : (keys.length > 0 ? literalTypes : 'string')\n vars.set(sn.variable, selectType)\n // Recurse into select option bodies\n for (const optionNodes of Object.values(sn.options)) {\n collectVariablesFromNodes(optionNodes, vars)\n }\n break\n }\n case 'function':\n if (!vars.has((node as FunctionNode).variable)) {\n vars.set((node as FunctionNode).variable, 'string | number')\n }\n break\n case 'text':\n break\n }\n }\n}\n\n/**\n * Generate a TypeScript declaration file with MessageId union and MessageValues interface.\n */\nexport function compileTypeDeclaration(\n allIds: string[],\n catalogs: Record<string, CatalogData>,\n sourceLocale: string,\n): string {\n const lines: string[] = []\n lines.push('// Auto-generated by @fluenti/cli — do not edit')\n lines.push('')\n\n // MessageId union\n if (allIds.length === 0) {\n lines.push('export type MessageId = never')\n } else {\n lines.push('export type MessageId =')\n for (const id of allIds) {\n lines.push(` | '${escapeStringLiteral(id)}'`)\n }\n }\n\n lines.push('')\n\n // MessageValues interface\n lines.push('export interface MessageValues {')\n for (const id of allIds) {\n // Use source locale catalog to get the message for variable extraction\n const sourceCatalog = catalogs[sourceLocale]\n const entry = sourceCatalog?.[id]\n const message = entry?.message ?? id\n const vars = extractMessageVariables(message)\n\n const escapedId = escapeStringLiteral(id)\n if (vars.length === 0) {\n lines.push(` '${escapedId}': Record<string, never>`)\n } else {\n const fields = vars.map((v) => `${v.name}: ${v.type}`).join('; ')\n lines.push(` '${escapedId}': { ${fields} }`)\n }\n }\n lines.push('}')\n lines.push('')\n\n return lines.join('\\n')\n}\n","import { existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport type { FluentiConfig } from '@fluenti/core'\n\nconst defaultConfig: FluentiConfig = {\n sourceLocale: 'en',\n locales: ['en'],\n catalogDir: './locales',\n format: 'po',\n include: ['./src/**/*.{vue,tsx,jsx,ts,js}'],\n compileOutDir: './src/locales/compiled',\n}\n\n/**\n * Load Fluenti config from the given path or auto-discover it.\n * When `cwd` is provided, config paths are resolved relative to it.\n */\nexport async function loadConfig(configPath?: string, cwd?: string): Promise<FluentiConfig> {\n const base = cwd ?? process.cwd()\n const paths = configPath\n ? [resolve(base, configPath)]\n : [\n resolve(base, 'fluenti.config.ts'),\n resolve(base, 'fluenti.config.js'),\n resolve(base, 'fluenti.config.mjs'),\n ]\n\n for (const p of paths) {\n if (existsSync(p)) {\n const { createJiti } = await import('jiti')\n const jiti = createJiti(import.meta.url)\n const mod = await jiti.import(p) as { default?: Partial<FluentiConfig> }\n const userConfig = mod.default ?? mod as unknown as Partial<FluentiConfig>\n return { ...defaultConfig, ...userConfig }\n }\n }\n\n return defaultConfig\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`@fluenti/core`),l=require(`gettext-parser`);l=s(l);let u=require(`node:fs`),d=require(`node:path`);function f(e,t,n){let r=new Set(t.map(e=>e.id)),i=new Set,a={},o=0,s=0,c=0;for(let r of t){let t=e[r.id],c=t?void 0:m(e,r,i),l=`${r.origin.file}:${r.origin.line}`,u=t??c?.entry;if(c&&i.add(c.id),u)a[r.id]={...u,message:r.message??u.message,context:r.context,comment:r.comment,origin:l,obsolete:!1},s++;else if(a[r.id]){let e=a[r.id];a[r.id]={...e,origin:p(e.origin,l)}}else a[r.id]={message:r.message,context:r.context,comment:r.comment,origin:l},o++;if(n?.stripFuzzy){let{fuzzy:e,...t}=a[r.id];a[r.id]=t}}for(let[t,i]of Object.entries(e))if(!r.has(t)){let{fuzzy:e,...r}=i;a[t]=n?.stripFuzzy?{...r,obsolete:!0}:{...i,obsolete:!0},c++}return{catalog:a,result:{added:o,unchanged:s,obsolete:c}}}function p(e,t){if(!e)return t;let n=Array.isArray(e)?e:[e],r=[...new Set([...n,t])];return r.length===1?r[0]:r}function m(e,t,n){if(!t.context)return;let r=`${t.origin.file}:${t.origin.line}`;for(let[i,a]of Object.entries(e))if(!n.has(i)&&a.context===void 0&&a.message===t.message&&h(a.origin,r))return{id:i,entry:a}}function h(e,t){return e?(Array.isArray(e)?e:[e]).some(e=>e===t||g(e)===g(t)):!1}function g(e){return e.match(/^(.*):\d+$/)?.[1]??e}function _(e){let t=JSON.parse(e),n={};for(let[e,r]of Object.entries(t))if(typeof r==`object`&&r){let t=r;n[e]={message:typeof t.message==`string`?t.message:void 0,context:typeof t.context==`string`?t.context:void 0,comment:typeof t.comment==`string`?t.comment:void 0,translation:typeof t.translation==`string`?t.translation:void 0,origin:typeof t.origin==`string`||Array.isArray(t.origin)&&t.origin.every(e=>typeof e==`string`)?t.origin:void 0,obsolete:typeof t.obsolete==`boolean`?t.obsolete:void 0,fuzzy:typeof t.fuzzy==`boolean`?t.fuzzy:void 0}}return n}function v(e){let t={};for(let[n,r]of Object.entries(e)){let e={};r.message!==void 0&&(e.message=r.message),r.context!==void 0&&(e.context=r.context),r.comment!==void 0&&(e.comment=r.comment),r.translation!==void 0&&(e.translation=r.translation),r.origin!==void 0&&(e.origin=r.origin),r.obsolete&&(e.obsolete=!0),r.fuzzy&&(e.fuzzy=!0),t[n]=e}return JSON.stringify(t,null,2)+`
|
|
2
|
+
`}var y=`fluenti-id:`;function b(e){let t=l.po.parse(e),n={},r=t.translations??{};for(let[e,t]of Object.entries(r))for(let[r,i]of Object.entries(t)){if(!r)continue;let t=e||i.msgctxt||void 0,a=i.msgstr?.[0]??void 0,o=i.comments?.reference??void 0,s=o?.includes(`
|
|
3
|
+
`)?o.split(`
|
|
4
|
+
`).map(e=>e.trim()).filter(Boolean):o?.includes(` `)?o.split(/\s+/).filter(Boolean):o,l=Array.isArray(s)&&s.length===1?s[0]:s,u=i.comments?.flag?.includes(`fuzzy`)??!1,{comment:d,customId:f,sourceMessage:p}=S(i.comments?.extracted),m=p&&(0,c.hashMessage)(p,t)===r?p:void 0,h=f??(m?r:(0,c.hashMessage)(r,t));n[h]={message:m??r,...t===void 0?{}:{context:t},...d===void 0?{}:{comment:d},...a?{translation:a}:{},...l===void 0?{}:{origin:l},...u?{fuzzy:!0}:{}}}return n}function x(e){let t={"":{"":{msgid:``,msgstr:[`Content-Type: text/plain; charset=UTF-8
|
|
5
|
+
`]}}};for(let[n,r]of Object.entries(e)){let e={msgid:r.message??n,...r.context===void 0?{}:{msgctxt:r.context},msgstr:[r.translation??``]},i={};r.origin&&(i.reference=Array.isArray(r.origin)?r.origin.join(`
|
|
6
|
+
`):r.origin);let a=w(n,r.message??n,r.context,r.comment);a&&(i.extracted=a),r.fuzzy&&(i.flag=`fuzzy`),(i.reference||i.extracted||i.flag)&&(e.comments=i);let o=r.context??``;t[o]??={},t[o][e.msgid]=e}let n={headers:{"Content-Type":`text/plain; charset=UTF-8`},translations:t};return l.po.compile(n).toString()}function S(e){if(!e)return{};let t=e.split(`
|
|
7
|
+
`).map(e=>e.trim()).filter(Boolean),n,r,i=[];for(let e of t){if(e.startsWith(y)){n=e.slice(11).trim()||void 0;continue}if(e.startsWith("msg`")&&e.endsWith("`")){r=e.slice(4,-1);continue}if(e.startsWith(`Trans: `)){r=C(e.slice(7));continue}i.push(e)}return{...i.length>0?{comment:i.join(`
|
|
8
|
+
`)}:{},...n?{customId:n}:{},...r?{sourceMessage:r}:{}}}function C(e){let t=[],n=0;return e.replace(/<\/?([a-zA-Z][\w-]*)>/g,(e,r)=>{let i=r;if(e.startsWith(`</`)){for(let e=t.length-1;e>=0;e--){let n=t[e];if(n?.tag===i)return t=t.filter((t,n)=>n!==e),`</${n.index}>`}return e}let a=n++;return t.push({tag:i,index:a}),`<${a}>`})}function w(e,t,n,r){let i=[];return r&&i.push(r),e!==(0,c.hashMessage)(t,n)&&i.push(`${y} ${e}`),i.length>0?i.join(`
|
|
9
|
+
`):void 0}var T=/\{(\w+)\}/g,E=/\{(\w+)\}/;function D(e){return E.test(e)}function O(e){return e.replace(/\\/g,`\\\\`).replace(/'/g,`\\'`).replace(/\n/g,`\\n`).replace(/\r/g,`\\r`)}function k(e,t){return/^\d/.test(t)?`${e}[${t}]`:`${e}.${t}`}function A(e){return e.replace(/\\/g,`\\\\`).replace(/`/g,"\\`").replace(/\$\{/g,"\\${").replace(/\n/g,`\\n`).replace(/\r/g,`\\r`)}function j(e){return e.replace(T,(e,t)=>`\${${k(`v`,t)}}`)}var M=/\{(\w+),\s*(plural|select|selectordinal)\s*,/;function N(e){return M.test(e)}function P(e,t){if(e.length===0)return`''`;let n=e.map(e=>F(e,t));return n.length===1?n[0]:n.join(` + `)}function F(e,t){switch(e.type){case`text`:return`'${O(e.value)}'`;case`variable`:return e.name===`#`?`String(__c)`:`String(${k(`v`,e.name)} ?? '{${e.name}}')`;case`plural`:return I(e,t);case`select`:return L(e,t);case`function`:return`String(${k(`v`,e.variable)} ?? '')`}}function I(e,t){let n=e.offset??0,r=k(`v`,e.variable),i=n?`(${r} - ${n})`:r,a=[];a.push(`((c) => { const __c = c; `);let o=Object.keys(e.options).filter(e=>e.startsWith(`=`));if(o.length>0)for(let n of o){let r=n.slice(1),i=P(e.options[n],t);a.push(`if (c === ${r}) return ${i}; `)}let s=Object.keys(e.options).filter(e=>!e.startsWith(`=`));if(s.length>1||s.length===1&&s[0]!==`other`){a.push(`const __cat = new Intl.PluralRules('${O(t)}').select(c); `);for(let n of s){if(n===`other`)continue;let r=P(e.options[n],t);a.push(`if (__cat === '${n}') return ${r}; `)}}let c=e.options.other?P(e.options.other,t):`''`;return a.push(`return ${c}; `),a.push(`})(${i})`),a.join(``)}function L(e,t){let n=[];n.push(`((s) => { `);let r=Object.keys(e.options).filter(e=>e!==`other`);for(let i of r){let r=P(e.options[i],t);n.push(`if (s === '${O(i)}') return ${r}; `)}let i=e.options.other?P(e.options.other,t):`''`;return n.push(`return ${i}; `),n.push(`})(String(${k(`v`,e.variable)} ?? ''))`),n.join(``)}function R(e,t,n,r,i){let a=[];a.push(`// @fluenti/compiled v1`);let o=[],s=0,l=[],u=new Map;for(let d of n){let n=(0,c.hashMessage)(d),f=u.get(n);if(f!==void 0&&f!==d)throw Error(`Hash collision detected: messages "${f}" and "${d}" produce the same hash "${n}"`);u.set(n,d);let p=`_${n}`,m=e[d],h=z(m,d,t,r,i?.skipFuzzy);if(h===void 0)a.push(`export const ${p} = undefined`),l.push(d);else if(N(h)){let e=P((0,c.parse)(h),t);a.push(`export const ${p} = (v) => ${e}`),s++}else if(D(h)){let e=j(A(h));a.push(`export const ${p} = (v) => \`${e}\``),s++}else a.push(`export const ${p} = '${O(h)}'`),s++;o.push({id:d,exportName:p})}if(o.length===0)return{code:`// @fluenti/compiled v1
|
|
10
|
+
// empty catalog
|
|
11
|
+
export default {}
|
|
12
|
+
`,stats:{compiled:0,missing:[]}};a.push(``),a.push(`export default {`);for(let{id:e,exportName:t}of o)a.push(` '${O(e)}': ${t},`);return a.push(`}`),a.push(``),{code:a.join(`
|
|
13
|
+
`),stats:{compiled:s,missing:l}}}function z(e,t,n,r,i){let a=r??n;if(e&&!(i&&e.fuzzy)){if(e.translation!==void 0&&e.translation.length>0)return e.translation;if(n===a)return e.message??t}}function B(e,t){let n=[];n.push(`export const locales = ${JSON.stringify(e)}`),n.push(``),n.push(`export const loaders = {`);for(let t of e)n.push(` '${O(t)}': () => import('./${O(t)}.js'),`);return n.push(`}`),n.push(``),n.join(`
|
|
14
|
+
`)}function V(e){let t=new Set;for(let n of Object.values(e))for(let[e,r]of Object.entries(n))r.obsolete||t.add(e);return[...t].sort()}function H(e){let t=(0,c.parse)(e),n=new Map;return U(t,n),[...n.entries()].sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>({name:e,type:t}))}function U(e,t){for(let n of e)switch(n.type){case`variable`:n.name!==`#`&&!t.has(n.name)&&t.set(n.name,`string | number`);break;case`plural`:{let e=n;t.set(e.variable,`number`);for(let n of Object.values(e.options))U(n,t);break}case`select`:{let e=n,r=Object.keys(e.options).filter(e=>e!==`other`),i=`other`in e.options,a=r.map(e=>`'${e}'`).join(` | `),o=i?r.length>0?`${a} | string`:`string`:r.length>0?a:`string`;t.set(e.variable,o);for(let n of Object.values(e.options))U(n,t);break}case`function`:t.has(n.variable)||t.set(n.variable,`string | number`);break;case`text`:break}}function W(e,t,n){let r=[];if(r.push(`// Auto-generated by @fluenti/cli — do not edit`),r.push(``),e.length===0)r.push(`export type MessageId = never`);else{r.push(`export type MessageId =`);for(let t of e)r.push(` | '${O(t)}'`)}r.push(``),r.push(`export interface MessageValues {`);for(let i of e){let e=H(t[n]?.[i]?.message??i),a=O(i);if(e.length===0)r.push(` '${a}': Record<string, never>`);else{let t=e.map(e=>`${e.name}: ${e.type}`).join(`; `);r.push(` '${a}': { ${t} }`)}}return r.push(`}`),r.push(``),r.join(`
|
|
15
|
+
`)}var G={sourceLocale:`en`,locales:[`en`],catalogDir:`./locales`,format:`po`,include:[`./src/**/*.{vue,tsx,jsx,ts,js}`],compileOutDir:`./src/locales/compiled`};async function K(e,t){let n=t??process.cwd(),r=e?[(0,d.resolve)(n,e)]:[(0,d.resolve)(n,`fluenti.config.ts`),(0,d.resolve)(n,`fluenti.config.js`),(0,d.resolve)(n,`fluenti.config.mjs`)];for(let e of r)if((0,u.existsSync)(e)){let{createJiti:t}=await import(`jiti`),n=await t({}.url).import(e),r=n.default??n;return{...G,...r}}return G}Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return W}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return B}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return V}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return R}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return K}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return f}});
|
|
16
|
+
//# sourceMappingURL=config-loader-D3RGkK_r.cjs.map
|