@fluenti/cli 0.3.3 → 0.4.0-rc.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/dist/ai-provider.d.ts +4 -3
- package/dist/ai-provider.d.ts.map +1 -1
- package/dist/cli.cjs +13 -12
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +486 -289
- package/dist/cli.js.map +1 -1
- package/dist/{compile-B4y2UPsX.js → compile-CdA4EZ-p.js} +36 -33
- package/dist/compile-CdA4EZ-p.js.map +1 -0
- package/dist/compile-cache.d.ts.map +1 -1
- package/dist/compile-kXClO6q4.cjs +8 -0
- package/dist/compile-kXClO6q4.cjs.map +1 -0
- package/dist/compile-worker.cjs +1 -1
- package/dist/compile-worker.cjs.map +1 -1
- package/dist/compile-worker.d.ts +1 -0
- package/dist/compile-worker.d.ts.map +1 -1
- package/dist/compile-worker.js +19 -7
- package/dist/compile-worker.js.map +1 -1
- package/dist/compile.d.ts.map +1 -1
- package/dist/{extract-cache-idNfsd7n.cjs → extract-cache-BioSaoFo.cjs} +5 -5
- package/dist/extract-cache-BioSaoFo.cjs.map +1 -0
- package/dist/{extract-cache-DYoHe5P-.js → extract-cache-C-MI1_ll.js} +57 -44
- package/dist/extract-cache-C-MI1_ll.js.map +1 -0
- package/dist/extract-cache.d.ts.map +1 -1
- package/dist/extract-runner.d.ts.map +1 -1
- package/dist/glossary.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/dist/lint.d.ts.map +1 -1
- package/dist/migrate.d.ts.map +1 -1
- package/dist/parallel-compile.d.ts.map +1 -1
- package/dist/po-format.d.ts.map +1 -1
- package/dist/translate-parse.d.ts +10 -0
- package/dist/translate-parse.d.ts.map +1 -0
- package/dist/translate-prompt.d.ts +9 -0
- package/dist/translate-prompt.d.ts.map +1 -0
- package/dist/translate.d.ts +11 -9
- package/dist/translate.d.ts.map +1 -1
- package/dist/{tsx-extractor-C-9_TnCW.cjs → tsx-extractor-B0vFXziu.cjs} +2 -2
- package/dist/tsx-extractor-B0vFXziu.cjs.map +1 -0
- package/dist/{tsx-extractor-CjQIMvKo.js → tsx-extractor-C-HZNobu.js} +2 -2
- package/dist/tsx-extractor-C-HZNobu.js.map +1 -0
- package/dist/tsx-extractor.d.ts.map +1 -1
- package/dist/validation.d.ts +4 -1
- package/dist/validation.d.ts.map +1 -1
- package/dist/vue-extractor.cjs +2 -2
- package/dist/vue-extractor.cjs.map +1 -1
- package/dist/vue-extractor.d.ts.map +1 -1
- package/dist/vue-extractor.js +3 -3
- package/dist/vue-extractor.js.map +1 -1
- package/package.json +2 -2
- package/dist/compile-B4y2UPsX.js.map +0 -1
- package/dist/compile-Brygn0bn.cjs +0 -8
- package/dist/compile-Brygn0bn.cjs.map +0 -1
- package/dist/extract-cache-DYoHe5P-.js.map +0 -1
- package/dist/extract-cache-idNfsd7n.cjs.map +0 -1
- package/dist/tsx-extractor-C-9_TnCW.cjs.map +0 -1
- package/dist/tsx-extractor-CjQIMvKo.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { i as e, n as t, r as n, t as r } from "./compile-
|
|
3
|
-
import { t as i } from "./tsx-extractor-
|
|
4
|
-
import { a, c as o, i as s, n as c, o as l, r as u, s as d, t as f } from "./extract-cache-
|
|
5
|
-
import {
|
|
6
|
-
import { appendFileSync as
|
|
7
|
-
import { dirname as
|
|
8
|
-
import { fileURLToPath as
|
|
9
|
-
import
|
|
10
|
-
import { createHash as
|
|
11
|
-
import { defineCommand as
|
|
12
|
-
import
|
|
13
|
-
import { execFile as
|
|
14
|
-
import { promisify as
|
|
2
|
+
import { i as e, n as t, r as n, t as r } from "./compile-CdA4EZ-p.js";
|
|
3
|
+
import { t as i } from "./tsx-extractor-C-HZNobu.js";
|
|
4
|
+
import { a, c as o, i as s, n as c, o as l, r as u, s as d, t as f } from "./extract-cache-C-MI1_ll.js";
|
|
5
|
+
import { parse as p, resolveLocaleCodes as m } from "@fluenti/core/internal";
|
|
6
|
+
import { appendFileSync as h, existsSync as g, mkdirSync as _, readFileSync as v, statSync as y, writeFileSync as b } from "node:fs";
|
|
7
|
+
import { dirname as x, extname as S, join as C, resolve as w } from "node:path";
|
|
8
|
+
import { fileURLToPath as T } from "node:url";
|
|
9
|
+
import E from "fast-glob";
|
|
10
|
+
import { createHash as D } from "node:crypto";
|
|
11
|
+
import { defineCommand as O, runMain as k } from "citty";
|
|
12
|
+
import A from "consola";
|
|
13
|
+
import { execFile as j } from "node:child_process";
|
|
14
|
+
import { promisify as M } from "node:util";
|
|
15
|
+
import { setTimeout as N } from "node:timers/promises";
|
|
15
16
|
//#region src/stats-format.ts
|
|
16
17
|
var ee = "█", te = "░";
|
|
17
18
|
function ne(e, t = 20) {
|
|
@@ -27,8 +28,60 @@ function ie(e, t, n) {
|
|
|
27
28
|
return ` ${e.padEnd(8)}│ ${String(t).padStart(5)} │ ${String(n).padStart(10)} │ ${a} ${i}`;
|
|
28
29
|
}
|
|
29
30
|
//#endregion
|
|
31
|
+
//#region src/validation.ts
|
|
32
|
+
var P = /\{(\w+),\s*(plural|select|selectordinal)\s*,/;
|
|
33
|
+
function F(e) {
|
|
34
|
+
try {
|
|
35
|
+
let t = p(e), n = /* @__PURE__ */ new Set();
|
|
36
|
+
return I(t, n), [...n].sort();
|
|
37
|
+
} catch {
|
|
38
|
+
let t = /* @__PURE__ */ new Set(), n = 0, r = 0;
|
|
39
|
+
for (; r < e.length;) {
|
|
40
|
+
if (e[r] === "{") {
|
|
41
|
+
if (n++, n === 1) {
|
|
42
|
+
let n = e.indexOf("}", r + 1);
|
|
43
|
+
if (n !== -1) {
|
|
44
|
+
let i = e.slice(r + 1, n).trim(), a = /^(\w+)/.exec(i);
|
|
45
|
+
a && t.add(a[1]);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
} else e[r] === "}" && n--;
|
|
49
|
+
r++;
|
|
50
|
+
}
|
|
51
|
+
return [...t].sort();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function I(e, t) {
|
|
55
|
+
for (let n of e) if (n.type === "variable" && n.name !== "#") t.add(n.name);
|
|
56
|
+
else if (n.type === "plural" || n.type === "select") {
|
|
57
|
+
t.add(n.variable);
|
|
58
|
+
for (let e of Object.values(n.options)) I(e, t);
|
|
59
|
+
} else n.type === "function" && t.add(n.variable);
|
|
60
|
+
}
|
|
61
|
+
function L(e) {
|
|
62
|
+
let t = /* @__PURE__ */ new Set(), n = /<\/?([a-zA-Z][\w-]*)[^>]*>/g, r;
|
|
63
|
+
for (; (r = n.exec(e)) !== null;) t.add(r[1].toLowerCase());
|
|
64
|
+
return [...t].sort();
|
|
65
|
+
}
|
|
66
|
+
function ae(e, t) {
|
|
67
|
+
let n = F(e), r = F(t), i = L(e), a = L(t), o = n.filter((e) => !r.includes(e)), s = r.filter((e) => !n.includes(e)), c = i.filter((e) => !a.includes(e)), l = a.filter((e) => !i.includes(e)), u = [];
|
|
68
|
+
if (P.test(t)) try {
|
|
69
|
+
p(t);
|
|
70
|
+
} catch (e) {
|
|
71
|
+
u.push(e.message);
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
valid: o.length === 0 && s.length === 0 && c.length === 0 && l.length === 0 && u.length === 0,
|
|
75
|
+
missingPlaceholders: o,
|
|
76
|
+
extraPlaceholders: s,
|
|
77
|
+
missingHtmlTags: c,
|
|
78
|
+
extraHtmlTags: l,
|
|
79
|
+
syntaxErrors: u
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
//#endregion
|
|
30
83
|
//#region src/lint.ts
|
|
31
|
-
function
|
|
84
|
+
function R(e, t) {
|
|
32
85
|
let n = [], { sourceLocale: r } = t, i = t.locales ?? Object.keys(e), a = e[r];
|
|
33
86
|
if (!a) return n.push({
|
|
34
87
|
rule: "missing-source",
|
|
@@ -60,7 +113,7 @@ function j(e, t) {
|
|
|
60
113
|
});
|
|
61
114
|
continue;
|
|
62
115
|
}
|
|
63
|
-
let s =
|
|
116
|
+
let s = F(r.message ?? e), c = F(o.translation), l = s.filter((e) => !c.includes(e)), u = c.filter((e) => !s.includes(e));
|
|
64
117
|
l.length > 0 && n.push({
|
|
65
118
|
rule: "inconsistent-placeholders",
|
|
66
119
|
severity: "error",
|
|
@@ -103,17 +156,9 @@ function j(e, t) {
|
|
|
103
156
|
});
|
|
104
157
|
return n;
|
|
105
158
|
}
|
|
106
|
-
function
|
|
107
|
-
let t = [], n = /\{(\w+)(?:\s*,\s*(?:plural|select|selectordinal|number|date|time))?/g, r;
|
|
108
|
-
for (; (r = n.exec(e)) !== null;) {
|
|
109
|
-
let e = r[1];
|
|
110
|
-
t.includes(e) || t.push(e);
|
|
111
|
-
}
|
|
112
|
-
return t.sort();
|
|
113
|
-
}
|
|
114
|
-
function ae(e) {
|
|
159
|
+
function oe(e) {
|
|
115
160
|
if (e.length === 0) return " ✓ All checks passed";
|
|
116
|
-
let t = [], n =
|
|
161
|
+
let t = [], n = se(e, (e) => e.rule);
|
|
117
162
|
for (let [e, r] of Object.entries(n)) {
|
|
118
163
|
t.push(` ${e} (${r.length}):`);
|
|
119
164
|
for (let e of r) {
|
|
@@ -124,7 +169,7 @@ function ae(e) {
|
|
|
124
169
|
let r = e.filter((e) => e.severity === "error").length, i = e.filter((e) => e.severity === "warning").length, a = e.filter((e) => e.severity === "info").length;
|
|
125
170
|
return t.push(""), t.push(` Summary: ${r} errors, ${i} warnings, ${a} info`), t.join("\n");
|
|
126
171
|
}
|
|
127
|
-
function
|
|
172
|
+
function se(e, t) {
|
|
128
173
|
let n = {};
|
|
129
174
|
for (let r of e) {
|
|
130
175
|
let e = t(r);
|
|
@@ -134,7 +179,7 @@ function N(e, t) {
|
|
|
134
179
|
}
|
|
135
180
|
//#endregion
|
|
136
181
|
//#region src/check.ts
|
|
137
|
-
function
|
|
182
|
+
function ce(e, t) {
|
|
138
183
|
let { sourceLocale: n, minCoverage: r, locale: i } = t, a = e[n];
|
|
139
184
|
if (!a) return {
|
|
140
185
|
results: [],
|
|
@@ -182,10 +227,10 @@ function P(e, t) {
|
|
|
182
227
|
passed: p,
|
|
183
228
|
minCoverage: r,
|
|
184
229
|
actualCoverage: f,
|
|
185
|
-
diagnostics:
|
|
230
|
+
diagnostics: R(e, m)
|
|
186
231
|
};
|
|
187
232
|
}
|
|
188
|
-
function
|
|
233
|
+
function le(e) {
|
|
189
234
|
let t = [];
|
|
190
235
|
for (let n of e.results) {
|
|
191
236
|
let r = n.coverage >= e.minCoverage ? "✓" : "✗", i = n.coverage.toFixed(1), a = n.missing > 0 ? ` — ${n.missing} missing` : "", o = n.fuzzy > 0 ? `, ${n.fuzzy} fuzzy` : "";
|
|
@@ -195,7 +240,7 @@ function oe(e) {
|
|
|
195
240
|
let n = e.actualCoverage.toFixed(1), r = e.passed ? "PASSED" : "FAILED";
|
|
196
241
|
return t.push(`Coverage: ${n}% (min: ${e.minCoverage}%) — ${r}`), t.join("\n");
|
|
197
242
|
}
|
|
198
|
-
function
|
|
243
|
+
function ue(e, t, n) {
|
|
199
244
|
let r = [], i = n === "json" ? ".json" : ".po";
|
|
200
245
|
for (let n of e.results) if (n.coverage < e.minCoverage) {
|
|
201
246
|
let a = `${t}/${n.locale}${i}`;
|
|
@@ -208,7 +253,7 @@ function se(e, t, n) {
|
|
|
208
253
|
}
|
|
209
254
|
return r.join("\n");
|
|
210
255
|
}
|
|
211
|
-
function
|
|
256
|
+
function de(e) {
|
|
212
257
|
return JSON.stringify({
|
|
213
258
|
results: e.results,
|
|
214
259
|
passed: e.passed,
|
|
@@ -218,96 +263,196 @@ function ce(e) {
|
|
|
218
263
|
}
|
|
219
264
|
//#endregion
|
|
220
265
|
//#region src/compile-cache.ts
|
|
221
|
-
var
|
|
266
|
+
var z = "1", fe = class {
|
|
222
267
|
data;
|
|
223
268
|
cachePath;
|
|
224
269
|
dirty = !1;
|
|
225
270
|
constructor(e, t) {
|
|
226
|
-
this.cachePath =
|
|
271
|
+
this.cachePath = w(t ? w(e, ".cache", t) : w(e, ".cache"), "compile-cache.json"), this.data = this.load();
|
|
227
272
|
}
|
|
228
273
|
isUpToDate(e, t) {
|
|
229
274
|
let n = this.data.entries[e];
|
|
230
275
|
if (!n) return !1;
|
|
231
|
-
let r =
|
|
276
|
+
let r = B(t);
|
|
232
277
|
return n.inputHash === r;
|
|
233
278
|
}
|
|
234
279
|
set(e, t) {
|
|
235
|
-
this.data.entries[e] = { inputHash:
|
|
280
|
+
this.data.entries[e] = { inputHash: B(t) }, this.dirty = !0;
|
|
236
281
|
}
|
|
237
282
|
save() {
|
|
238
|
-
|
|
283
|
+
if (this.dirty) try {
|
|
284
|
+
_(x(this.cachePath), { recursive: !0 }), b(this.cachePath, JSON.stringify(this.data), "utf-8"), this.dirty = !1;
|
|
285
|
+
} catch {}
|
|
239
286
|
}
|
|
240
287
|
load() {
|
|
241
288
|
try {
|
|
242
|
-
if (
|
|
243
|
-
let e =
|
|
244
|
-
if (t.version ===
|
|
289
|
+
if (g(this.cachePath)) {
|
|
290
|
+
let e = v(this.cachePath, "utf-8"), t = JSON.parse(e);
|
|
291
|
+
if (t.version === z) return t;
|
|
245
292
|
}
|
|
246
293
|
} catch {}
|
|
247
294
|
return {
|
|
248
|
-
version:
|
|
295
|
+
version: z,
|
|
249
296
|
entries: {}
|
|
250
297
|
};
|
|
251
298
|
}
|
|
252
299
|
};
|
|
253
|
-
function
|
|
254
|
-
return
|
|
300
|
+
function B(e) {
|
|
301
|
+
return D("md5").update(e).digest("hex");
|
|
255
302
|
}
|
|
256
303
|
//#endregion
|
|
257
|
-
//#region src/
|
|
258
|
-
var
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
304
|
+
//#region src/ai-provider.ts
|
|
305
|
+
var V = M(j), pe = {
|
|
306
|
+
claude: "npm install -g @anthropic-ai/claude-code",
|
|
307
|
+
codex: "npm install -g @openai/codex"
|
|
308
|
+
};
|
|
309
|
+
function me(e, t) {
|
|
310
|
+
return e === "claude" ? ["-p", t] : [
|
|
311
|
+
"-p",
|
|
312
|
+
t,
|
|
313
|
+
"--full-auto"
|
|
314
|
+
];
|
|
315
|
+
}
|
|
316
|
+
function he(e) {
|
|
317
|
+
return e.code === "ENOENT";
|
|
318
|
+
}
|
|
319
|
+
async function ge(e) {
|
|
320
|
+
let { provider: t, prompt: n, maxRetries: r = 3, initialDelayMs: i = 1e3, maxBuffer: a = 10 * 1024 * 1024, timeoutMs: o = 12e4 } = e, s = me(t, n), c = t === "claude" ? "claude" : "codex", l;
|
|
321
|
+
for (let e = 0; e <= r; e++) try {
|
|
322
|
+
let t = V(c, [...s], { maxBuffer: a }), { stdout: n } = await Promise.race([t, N(o).then(() => {
|
|
323
|
+
throw Error(`AI provider timed out after ${o}ms`);
|
|
324
|
+
})]);
|
|
325
|
+
return {
|
|
326
|
+
stdout: n,
|
|
327
|
+
attempts: e + 1
|
|
328
|
+
};
|
|
329
|
+
} catch (n) {
|
|
330
|
+
if (he(n)) throw Error(`"${t}" CLI not found. Please install it first:\n ${pe[t]}`);
|
|
331
|
+
if (n instanceof Error && n.message.includes("timed out")) throw n;
|
|
332
|
+
l = n, e < r && await N(i * 2 ** e);
|
|
333
|
+
}
|
|
334
|
+
throw l;
|
|
335
|
+
}
|
|
336
|
+
//#endregion
|
|
337
|
+
//#region src/glossary.ts
|
|
338
|
+
var H = 1048576;
|
|
339
|
+
function _e(e) {
|
|
340
|
+
if (!g(e)) return {};
|
|
341
|
+
let t = y(e).size;
|
|
342
|
+
if (t > H) throw Error(`Glossary file exceeds maximum size of ${H} bytes (got ${t} bytes)`);
|
|
343
|
+
let n;
|
|
344
|
+
try {
|
|
345
|
+
let t = v(e, "utf-8");
|
|
346
|
+
n = JSON.parse(t);
|
|
347
|
+
} catch (e) {
|
|
348
|
+
let t = e instanceof Error ? e.message : String(e);
|
|
349
|
+
throw Error(`Invalid glossary format: failed to parse JSON — ${t}`);
|
|
350
|
+
}
|
|
351
|
+
if (typeof n != "object" || !n || Array.isArray(n)) throw Error("Invalid glossary format: root must be a plain object");
|
|
352
|
+
for (let [e, t] of Object.entries(n)) {
|
|
353
|
+
if (typeof t != "object" || !t || Array.isArray(t)) throw Error(`Invalid glossary format: value for "${e}" must be a plain object`);
|
|
354
|
+
for (let [n, r] of Object.entries(t)) if (typeof r != "string") throw Error(`Invalid glossary format: "${e}.${n}" must be a string, got ${typeof r}`);
|
|
355
|
+
}
|
|
356
|
+
return n;
|
|
357
|
+
}
|
|
358
|
+
function ve(e, t) {
|
|
359
|
+
let n = {};
|
|
360
|
+
for (let [r, i] of Object.entries(e)) t in i && (n[r] = i[t]);
|
|
361
|
+
return n;
|
|
362
|
+
}
|
|
363
|
+
function U(e) {
|
|
364
|
+
return e.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/[\n\r]/g, " ").replace(/\t/g, " ");
|
|
365
|
+
}
|
|
366
|
+
function ye(e) {
|
|
367
|
+
let t = Object.entries(e);
|
|
368
|
+
return t.length === 0 ? "" : `=== GLOSSARY (use these exact translations) ===\n${[...t].sort(([e], [t]) => e.localeCompare(t)).map(([e, t]) => `"${U(e)}" → "${U(t)}"`).join("\n")}`;
|
|
369
|
+
}
|
|
370
|
+
//#endregion
|
|
371
|
+
//#region src/translate-prompt.ts
|
|
372
|
+
function be(e) {
|
|
373
|
+
let { sourceLocale: t, targetLocale: n, messages: r, glossary: i, context: a } = e, o = JSON.stringify(r, null, 2), s = [
|
|
374
|
+
`You are a professional translator. Translate the following messages from "${t}" to "${n}".`,
|
|
267
375
|
"",
|
|
268
376
|
"Rules:",
|
|
269
|
-
"
|
|
270
|
-
"
|
|
271
|
-
"
|
|
272
|
-
"
|
|
273
|
-
|
|
377
|
+
"1. Output ONLY a valid JSON object with the same keys and translated values.",
|
|
378
|
+
"2. Keep ICU MessageFormat placeholders unchanged: {name}, {count, plural, ...}, {val, number}, etc.",
|
|
379
|
+
"3. Keep HTML tags unchanged: <b>, <a href=\"...\">, </span>, <br/>, etc.",
|
|
380
|
+
"4. Keep numbered rich-text tags unchanged: <0>, </0>, <1/>, etc.",
|
|
381
|
+
"5. Do not add any explanation, markdown formatting, or code fences — output raw JSON only."
|
|
382
|
+
];
|
|
383
|
+
if (i && Object.keys(i).length > 0) {
|
|
384
|
+
let e = ye(i);
|
|
385
|
+
e && s.push("", e);
|
|
386
|
+
}
|
|
387
|
+
return a && s.push("", "=== PROJECT CONTEXT ===", a), s.push("", "Input (JSON):", o), s.join("\n");
|
|
274
388
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
], { maxBuffer: n });
|
|
287
|
-
return e;
|
|
389
|
+
//#endregion
|
|
390
|
+
//#region src/translate-parse.ts
|
|
391
|
+
function xe(e) {
|
|
392
|
+
let t = e.indexOf("{");
|
|
393
|
+
if (t === -1) throw Error("No JSON object found in AI response");
|
|
394
|
+
let n = 0, r = !1, i = !1;
|
|
395
|
+
for (let a = t; a < e.length; a++) {
|
|
396
|
+
let o = e[a];
|
|
397
|
+
if (i) {
|
|
398
|
+
i = !1;
|
|
399
|
+
continue;
|
|
288
400
|
}
|
|
289
|
-
|
|
290
|
-
|
|
401
|
+
if (o === "\\" && r) {
|
|
402
|
+
i = !0;
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
if (o === "\"" && !i) {
|
|
406
|
+
r = !r;
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
if (!r && (o === "{" && n++, o === "}" && (n--, n === 0))) return e.slice(t, a + 1);
|
|
291
410
|
}
|
|
411
|
+
throw Error("Unterminated JSON object in AI response");
|
|
292
412
|
}
|
|
293
|
-
function
|
|
294
|
-
let t = e.match(
|
|
295
|
-
|
|
296
|
-
|
|
413
|
+
function Se(e) {
|
|
414
|
+
let t = e.match(/```(?:json)?\s*\n?([\s\S]*?)```/);
|
|
415
|
+
return t ? t[1] : e;
|
|
416
|
+
}
|
|
417
|
+
function Ce(e, t) {
|
|
418
|
+
let n = [], r = xe(Se(e)), i;
|
|
297
419
|
try {
|
|
298
|
-
|
|
420
|
+
i = JSON.parse(r);
|
|
299
421
|
} catch {
|
|
300
|
-
throw Error(`Failed to parse JSON from AI response: ${
|
|
422
|
+
throw Error(`Failed to parse JSON from AI response: ${r.slice(0, 200)}`);
|
|
301
423
|
}
|
|
302
|
-
if (typeof
|
|
303
|
-
|
|
424
|
+
if (typeof i != "object" || !i || Array.isArray(i)) throw Error("AI response is not a valid JSON object");
|
|
425
|
+
let a = i, o = {}, s = new Set(Object.keys(t));
|
|
426
|
+
for (let [e, r] of Object.entries(a)) {
|
|
427
|
+
if (!s.has(e)) {
|
|
428
|
+
n.push(`Extra key in AI response (ignored): "${e}"`);
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
if (typeof r != "string") {
|
|
432
|
+
n.push(`Non-string value for key "${e}" (ignored)`);
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
o[e] = r;
|
|
436
|
+
let i = t[e], a = ae(i, r);
|
|
437
|
+
if (!a.valid) {
|
|
438
|
+
let t = [];
|
|
439
|
+
a.missingPlaceholders.length > 0 && t.push(`missing placeholders: ${a.missingPlaceholders.join(", ")}`), a.extraPlaceholders.length > 0 && t.push(`extra placeholders: ${a.extraPlaceholders.join(", ")}`), a.missingHtmlTags.length > 0 && t.push(`missing HTML tags: ${a.missingHtmlTags.join(", ")}`), a.extraHtmlTags.length > 0 && t.push(`extra HTML tags: ${a.extraHtmlTags.join(", ")}`), a.syntaxErrors.length > 0 && t.push(`ICU syntax errors: ${a.syntaxErrors.join("; ")}`), n.push(`QA issue for "${e}": ${t.join("; ")}`);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
for (let e of s) e in o || n.push(`Missing translation for key: "${e}"`);
|
|
443
|
+
return {
|
|
444
|
+
translations: o,
|
|
445
|
+
warnings: n
|
|
446
|
+
};
|
|
304
447
|
}
|
|
305
|
-
|
|
448
|
+
//#endregion
|
|
449
|
+
//#region src/translate.ts
|
|
450
|
+
function we(e) {
|
|
306
451
|
let t = {};
|
|
307
452
|
for (let [n, r] of Object.entries(e)) r.obsolete || (!r.translation || r.translation.length === 0) && (t[n] = r.message ?? n);
|
|
308
453
|
return t;
|
|
309
454
|
}
|
|
310
|
-
function
|
|
455
|
+
function Te(e, t) {
|
|
311
456
|
let n = Object.keys(e), r = [];
|
|
312
457
|
for (let i = 0; i < n.length; i += t) {
|
|
313
458
|
let a = {};
|
|
@@ -316,31 +461,49 @@ function H(e, t) {
|
|
|
316
461
|
}
|
|
317
462
|
return r;
|
|
318
463
|
}
|
|
319
|
-
async function
|
|
320
|
-
let { provider: t, sourceLocale: n, targetLocale: r, catalog: i, batchSize: a, context: o } = e,
|
|
321
|
-
if (
|
|
464
|
+
async function Ee(e) {
|
|
465
|
+
let { provider: t, sourceLocale: n, targetLocale: r, catalog: i, batchSize: a, context: o, glossary: s, timeoutMs: c } = e, l = we(i), u = Object.keys(l).length;
|
|
466
|
+
if (u === 0) return {
|
|
322
467
|
catalog: { ...i },
|
|
323
|
-
translated: 0
|
|
468
|
+
translated: 0,
|
|
469
|
+
warnings: []
|
|
324
470
|
};
|
|
325
|
-
|
|
326
|
-
let
|
|
327
|
-
for (let e = 0; e <
|
|
328
|
-
let i =
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
471
|
+
A.info(` ${u} untranslated messages, translating with ${t}...`);
|
|
472
|
+
let d = { ...i }, f = Te(l, a), p = 0, m = [];
|
|
473
|
+
for (let e = 0; e < f.length; e++) {
|
|
474
|
+
let i = f[e], a = Object.keys(i);
|
|
475
|
+
f.length > 1 && A.info(` Batch ${e + 1}/${f.length} (${a.length} messages)`);
|
|
476
|
+
try {
|
|
477
|
+
let { stdout: e } = await ge({
|
|
478
|
+
provider: t,
|
|
479
|
+
prompt: be({
|
|
480
|
+
sourceLocale: n,
|
|
481
|
+
targetLocale: r,
|
|
482
|
+
messages: i,
|
|
483
|
+
glossary: s,
|
|
484
|
+
context: o
|
|
485
|
+
}),
|
|
486
|
+
timeoutMs: c
|
|
487
|
+
}), { translations: l, warnings: u } = Ce(e, i);
|
|
488
|
+
for (let e of u) m.push(`[${r}] ${e}`), A.warn(` ${e}`);
|
|
489
|
+
for (let e of a) e in l && (d[e] = {
|
|
490
|
+
...d[e],
|
|
491
|
+
translation: l[e]
|
|
492
|
+
}, p++);
|
|
493
|
+
} catch (t) {
|
|
494
|
+
let n = t instanceof Error ? t.message : String(t);
|
|
495
|
+
m.push(`[${r}] Batch ${e + 1} failed: ${n}`), A.error(` Batch ${e + 1} failed: ${n}`);
|
|
496
|
+
}
|
|
335
497
|
}
|
|
336
498
|
return {
|
|
337
|
-
catalog:
|
|
338
|
-
translated:
|
|
499
|
+
catalog: d,
|
|
500
|
+
translated: p,
|
|
501
|
+
warnings: m
|
|
339
502
|
};
|
|
340
503
|
}
|
|
341
504
|
//#endregion
|
|
342
505
|
//#region src/migrate.ts
|
|
343
|
-
var W =
|
|
506
|
+
var W = M(j), G = {
|
|
344
507
|
"vue-i18n": {
|
|
345
508
|
name: "vue-i18n",
|
|
346
509
|
framework: "Vue",
|
|
@@ -481,36 +644,36 @@ var W = A(k), G = {
|
|
|
481
644
|
migrationGuide: "react/llms-migration.txt"
|
|
482
645
|
}
|
|
483
646
|
}, K = Object.keys(G);
|
|
484
|
-
function
|
|
647
|
+
function De(e) {
|
|
485
648
|
let t = e.toLowerCase().replace(/^@nuxtjs\//, "nuxt-").replace(/^@/, "");
|
|
486
649
|
return K.find((e) => e === t);
|
|
487
650
|
}
|
|
488
|
-
async function
|
|
651
|
+
async function Oe(e) {
|
|
489
652
|
let t = {
|
|
490
653
|
configFiles: [],
|
|
491
654
|
localeFiles: [],
|
|
492
655
|
sampleSources: [],
|
|
493
656
|
packageJson: void 0
|
|
494
|
-
}, n =
|
|
495
|
-
|
|
657
|
+
}, n = w("package.json");
|
|
658
|
+
g(n) && (t.packageJson = v(n, "utf-8"));
|
|
496
659
|
for (let n of e.configPatterns) {
|
|
497
|
-
let e =
|
|
498
|
-
|
|
660
|
+
let e = w(n);
|
|
661
|
+
g(e) && t.configFiles.push({
|
|
499
662
|
path: n,
|
|
500
|
-
content:
|
|
663
|
+
content: v(e, "utf-8")
|
|
501
664
|
});
|
|
502
665
|
}
|
|
503
|
-
let r = await
|
|
666
|
+
let r = await E(e.localePatterns, { absolute: !1 });
|
|
504
667
|
for (let e of r.slice(0, 10)) {
|
|
505
|
-
let n =
|
|
668
|
+
let n = v(w(e), "utf-8");
|
|
506
669
|
t.localeFiles.push({
|
|
507
670
|
path: e,
|
|
508
671
|
content: n.length > 5e3 ? n.slice(0, 5e3) + "\n... (truncated)" : n
|
|
509
672
|
});
|
|
510
673
|
}
|
|
511
|
-
let i = await
|
|
674
|
+
let i = await E(e.sourcePatterns, { absolute: !1 });
|
|
512
675
|
for (let e of i.slice(0, 5)) {
|
|
513
|
-
let n =
|
|
676
|
+
let n = v(w(e), "utf-8");
|
|
514
677
|
t.sampleSources.push({
|
|
515
678
|
path: e,
|
|
516
679
|
content: n.length > 3e3 ? n.slice(0, 3e3) + "\n... (truncated)" : n
|
|
@@ -518,16 +681,16 @@ async function ue(e) {
|
|
|
518
681
|
}
|
|
519
682
|
return t;
|
|
520
683
|
}
|
|
521
|
-
function
|
|
522
|
-
let t = typeof __dirname < "u" ? __dirname :
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
684
|
+
function ke(e) {
|
|
685
|
+
let t = typeof __dirname < "u" ? __dirname : x(T(import.meta.url)), n = [
|
|
686
|
+
w("node_modules", "@fluenti", "cli", "..", "..", e),
|
|
687
|
+
C(t, "..", "..", "..", e),
|
|
688
|
+
C(t, "..", "..", e)
|
|
526
689
|
];
|
|
527
|
-
for (let e of n) if (
|
|
690
|
+
for (let e of n) if (g(e)) return v(e, "utf-8");
|
|
528
691
|
return "";
|
|
529
692
|
}
|
|
530
|
-
function
|
|
693
|
+
function Ae(e, t, n) {
|
|
531
694
|
let r = [];
|
|
532
695
|
if (r.push(`You are a migration assistant helping convert a ${e.framework} project from "${e.name}" to Fluenti (@fluenti).`, "", "Your task:", "1. Generate a `fluenti.config.ts` file based on the existing i18n configuration", "2. Convert each locale/translation file to Fluenti PO format", "3. List the code changes needed (file by file) to migrate source code from the old API to Fluenti API", ""), n && r.push("=== MIGRATION GUIDE ===", n, ""), t.packageJson && r.push("=== package.json ===", t.packageJson, ""), t.configFiles.length > 0) {
|
|
533
696
|
r.push("=== EXISTING CONFIG FILES ===");
|
|
@@ -543,7 +706,7 @@ function fe(e, t, n) {
|
|
|
543
706
|
}
|
|
544
707
|
return r.push("", "=== OUTPUT FORMAT ===", "Respond with the following sections, each starting with the exact header shown:", "", "### FLUENTI_CONFIG", "```ts", "// The fluenti.config.ts content", "```", "", "### LOCALE_FILES", "For each locale file, output:", "#### LOCALE: {locale_code}", "```po", "// The PO file content", "```", "", "### MIGRATION_STEPS", "A numbered checklist of specific code changes needed, with before/after examples.", "", "### INSTALL_COMMANDS", "```bash", "// The install and uninstall commands", "```"), r.join("\n");
|
|
545
708
|
}
|
|
546
|
-
async function
|
|
709
|
+
async function je(e, t) {
|
|
547
710
|
let n = 10 * 1024 * 1024;
|
|
548
711
|
try {
|
|
549
712
|
if (e === "claude") {
|
|
@@ -562,79 +725,79 @@ async function pe(e, t) {
|
|
|
562
725
|
throw n.code === "ENOENT" || n.code === "EPERM" || n.code === "EACCES" ? Error(`"${e}" CLI not found or not executable. Please install it first:\n` + (e === "claude" ? " npm install -g @anthropic-ai/claude-code" : " npm install -g @openai/codex")) : t;
|
|
563
726
|
}
|
|
564
727
|
}
|
|
565
|
-
function
|
|
566
|
-
let t = {
|
|
728
|
+
function Me(e) {
|
|
729
|
+
let t = 5e5, n = e.length > t ? e.slice(0, t) : e, r = {
|
|
567
730
|
config: void 0,
|
|
568
731
|
localeFiles: [],
|
|
569
732
|
steps: void 0,
|
|
570
733
|
installCommands: void 0
|
|
571
|
-
},
|
|
572
|
-
|
|
573
|
-
let
|
|
574
|
-
if (
|
|
575
|
-
let e = /#### LOCALE:\s*(\S+)\s*\n```(?:po)?\n([\s\S]*?)```/g,
|
|
576
|
-
for (; (
|
|
577
|
-
locale:
|
|
578
|
-
content:
|
|
734
|
+
}, i = n.match(/### FLUENTI_CONFIG[\s\S]*?```(?:ts|typescript)?\n([\s\S]*?)```/);
|
|
735
|
+
i && (r.config = i[1].trim());
|
|
736
|
+
let a = n.match(/### LOCALE_FILES([\s\S]*?)(?=### MIGRATION_STEPS|### INSTALL_COMMANDS|$)/);
|
|
737
|
+
if (a) {
|
|
738
|
+
let e = /#### LOCALE:\s*(\S+)\s*\n```(?:po)?\n([\s\S]*?)```/g, t;
|
|
739
|
+
for (; (t = e.exec(a[1])) !== null;) r.localeFiles.push({
|
|
740
|
+
locale: t[1],
|
|
741
|
+
content: t[2].trim()
|
|
579
742
|
});
|
|
580
743
|
}
|
|
581
|
-
let
|
|
582
|
-
|
|
583
|
-
let
|
|
584
|
-
return
|
|
744
|
+
let o = n.match(/### MIGRATION_STEPS\s*\n([\s\S]*?)(?=### INSTALL_COMMANDS|$)/);
|
|
745
|
+
o && (r.steps = o[1].trim());
|
|
746
|
+
let s = n.match(/### INSTALL_COMMANDS[\s\S]*?```(?:bash|sh)?\n([\s\S]*?)```/);
|
|
747
|
+
return s && (r.installCommands = s[1].trim()), r;
|
|
585
748
|
}
|
|
586
|
-
async function
|
|
587
|
-
let { from: t, provider: n, write: r } = e, i =
|
|
749
|
+
async function Ne(e) {
|
|
750
|
+
let { from: t, provider: n, write: r } = e, i = De(t);
|
|
588
751
|
if (!i) {
|
|
589
|
-
|
|
590
|
-
for (let e of K)
|
|
752
|
+
A.error(`Unsupported library "${t}". Supported libraries:`);
|
|
753
|
+
for (let e of K) A.log(` - ${e}`);
|
|
591
754
|
return;
|
|
592
755
|
}
|
|
593
756
|
let a = G[i];
|
|
594
|
-
|
|
595
|
-
let o = await
|
|
757
|
+
A.info(`Migrating from ${a.name} (${a.framework}) to Fluenti`), A.info("Scanning project for existing i18n files...");
|
|
758
|
+
let o = await Oe(a);
|
|
596
759
|
if (o.configFiles.length === 0 && o.localeFiles.length === 0) {
|
|
597
|
-
|
|
760
|
+
A.warn(`No ${a.name} configuration or locale files found.`), A.info("Make sure you are running this command from the project root directory.");
|
|
598
761
|
return;
|
|
599
762
|
}
|
|
600
|
-
|
|
601
|
-
let s =
|
|
602
|
-
|
|
603
|
-
let c =
|
|
604
|
-
if (c.installCommands && (
|
|
763
|
+
A.info(`Found: ${o.configFiles.length} config file(s), ${o.localeFiles.length} locale file(s), ${o.sampleSources.length} source file(s)`);
|
|
764
|
+
let s = ke(a.migrationGuide);
|
|
765
|
+
A.info(`Generating migration plan with ${n}...`);
|
|
766
|
+
let c = Me(await je(n, Ae(a, o, s)));
|
|
767
|
+
if (c.installCommands && (A.log(""), A.box({
|
|
605
768
|
title: "Install Commands",
|
|
606
769
|
message: c.installCommands
|
|
607
770
|
})), c.config) if (r) {
|
|
608
|
-
let { writeFileSync: e } = await import("node:fs"), t =
|
|
609
|
-
e(t, c.config, "utf-8"),
|
|
610
|
-
} else
|
|
771
|
+
let { writeFileSync: e } = await import("node:fs"), t = w("fluenti.config.ts");
|
|
772
|
+
e(t, c.config, "utf-8"), A.success(`Written: ${t}`);
|
|
773
|
+
} else A.log(""), A.box({
|
|
611
774
|
title: "fluenti.config.ts",
|
|
612
775
|
message: c.config
|
|
613
776
|
});
|
|
614
777
|
if (c.localeFiles.length > 0) if (r) {
|
|
615
778
|
let { writeFileSync: e, mkdirSync: t } = await import("node:fs"), n = "./locales";
|
|
616
|
-
t(
|
|
779
|
+
t(w(n), { recursive: !0 });
|
|
617
780
|
for (let t of c.localeFiles) {
|
|
618
|
-
let r =
|
|
619
|
-
e(r, t.content, "utf-8"),
|
|
781
|
+
let r = w(n, `${t.locale}.po`);
|
|
782
|
+
e(r, t.content, "utf-8"), A.success(`Written: ${r}`);
|
|
620
783
|
}
|
|
621
|
-
} else for (let e of c.localeFiles)
|
|
784
|
+
} else for (let e of c.localeFiles) A.log(""), A.box({
|
|
622
785
|
title: `locales/${e.locale}.po`,
|
|
623
786
|
message: e.content.length > 500 ? e.content.slice(0, 500) + "\n... (use --write to save full file)" : e.content
|
|
624
787
|
});
|
|
625
|
-
c.steps && (
|
|
788
|
+
c.steps && (A.log(""), A.box({
|
|
626
789
|
title: "Migration Steps",
|
|
627
790
|
message: c.steps
|
|
628
|
-
})), !r && (c.config || c.localeFiles.length > 0) && (
|
|
791
|
+
})), !r && (c.config || c.localeFiles.length > 0) && (A.log(""), A.info("Run with --write to save generated files to disk:"), A.log(` fluenti migrate --from ${t} --write`));
|
|
629
792
|
}
|
|
630
793
|
//#endregion
|
|
631
794
|
//#region src/init.ts
|
|
632
|
-
var
|
|
633
|
-
function
|
|
634
|
-
if (!
|
|
795
|
+
var Pe = /^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{1,8})*$/;
|
|
796
|
+
function q(e) {
|
|
797
|
+
if (!Pe.test(e)) throw Error(`Invalid locale format: "${e}"`);
|
|
635
798
|
return e;
|
|
636
799
|
}
|
|
637
|
-
var
|
|
800
|
+
var Fe = [
|
|
638
801
|
{
|
|
639
802
|
dep: "next",
|
|
640
803
|
name: "nextjs",
|
|
@@ -666,8 +829,8 @@ var _e = [
|
|
|
666
829
|
pluginPackage: "@fluenti/react"
|
|
667
830
|
}
|
|
668
831
|
];
|
|
669
|
-
function
|
|
670
|
-
for (let t of
|
|
832
|
+
function Ie(e) {
|
|
833
|
+
for (let t of Fe) if (t.dep in e) return {
|
|
671
834
|
name: t.name,
|
|
672
835
|
pluginPackage: t.pluginPackage
|
|
673
836
|
};
|
|
@@ -676,64 +839,64 @@ function ve(e) {
|
|
|
676
839
|
pluginPackage: null
|
|
677
840
|
};
|
|
678
841
|
}
|
|
679
|
-
function
|
|
680
|
-
let t = e.locales.map((e) =>
|
|
842
|
+
function Le(e) {
|
|
843
|
+
let t = e.locales.map((e) => JSON.stringify(e)).join(", ");
|
|
681
844
|
return `import { defineConfig } from '@fluenti/cli'
|
|
682
845
|
|
|
683
846
|
export default defineConfig({
|
|
684
|
-
sourceLocale:
|
|
847
|
+
sourceLocale: ${JSON.stringify(e.sourceLocale)},
|
|
685
848
|
locales: [${t}],
|
|
686
849
|
catalogDir: './locales',
|
|
687
|
-
format:
|
|
850
|
+
format: ${JSON.stringify(e.format)},
|
|
688
851
|
include: ['./src/**/*.{vue,tsx,jsx,ts,js}'],
|
|
689
852
|
compileOutDir: './src/locales/compiled',
|
|
690
853
|
})
|
|
691
854
|
`;
|
|
692
855
|
}
|
|
693
|
-
async function
|
|
694
|
-
let t =
|
|
695
|
-
if (!
|
|
696
|
-
|
|
856
|
+
async function Re(e) {
|
|
857
|
+
let t = w(e.cwd, "package.json");
|
|
858
|
+
if (!g(t)) {
|
|
859
|
+
A.error("No package.json found in current directory.");
|
|
697
860
|
return;
|
|
698
861
|
}
|
|
699
|
-
let n = JSON.parse(
|
|
862
|
+
let n = JSON.parse(v(t, "utf-8")), r = Ie({
|
|
700
863
|
...n.dependencies,
|
|
701
864
|
...n.devDependencies
|
|
702
865
|
});
|
|
703
|
-
|
|
704
|
-
let i =
|
|
705
|
-
if (
|
|
706
|
-
|
|
866
|
+
A.info(`Detected framework: ${r.name}`), r.pluginPackage && A.info(`Recommended plugin: ${r.pluginPackage}`);
|
|
867
|
+
let i = w(e.cwd, "fluenti.config.ts");
|
|
868
|
+
if (g(i)) {
|
|
869
|
+
A.warn("fluenti.config.ts already exists. Skipping config generation.");
|
|
707
870
|
return;
|
|
708
871
|
}
|
|
709
|
-
let a = await
|
|
872
|
+
let a = await A.prompt("Source locale?", {
|
|
710
873
|
type: "text",
|
|
711
874
|
default: "en",
|
|
712
875
|
placeholder: "en"
|
|
713
876
|
});
|
|
714
877
|
if (typeof a == "symbol") return;
|
|
715
|
-
let o = await
|
|
878
|
+
let o = await A.prompt("Target locales (comma-separated)?", {
|
|
716
879
|
type: "text",
|
|
717
880
|
default: "ja,zh-CN",
|
|
718
881
|
placeholder: "ja,zh-CN"
|
|
719
882
|
});
|
|
720
883
|
if (typeof o == "symbol") return;
|
|
721
|
-
let s = await
|
|
884
|
+
let s = await A.prompt("Catalog format?", {
|
|
722
885
|
type: "select",
|
|
723
886
|
options: ["po", "json"],
|
|
724
887
|
initial: "po"
|
|
725
888
|
});
|
|
726
889
|
if (typeof s == "symbol") return;
|
|
727
890
|
let c = o.split(",").map((e) => e.trim()).filter(Boolean);
|
|
728
|
-
|
|
729
|
-
for (let e of c)
|
|
730
|
-
|
|
891
|
+
q(a);
|
|
892
|
+
for (let e of c) q(e);
|
|
893
|
+
b(i, Le({
|
|
731
894
|
sourceLocale: a,
|
|
732
895
|
locales: [a, ...c.filter((e) => e !== a)],
|
|
733
896
|
format: s
|
|
734
|
-
}), "utf-8"),
|
|
735
|
-
let l =
|
|
736
|
-
|
|
897
|
+
}), "utf-8"), A.success("Created fluenti.config.ts");
|
|
898
|
+
let l = w(e.cwd, ".gitignore"), u = "src/locales/compiled/";
|
|
899
|
+
g(l) ? v(l, "utf-8").includes(u) || (h(l, `\n# Fluenti compiled catalogs\n${u}\n`), A.success("Updated .gitignore")) : (b(l, `# Fluenti compiled catalogs\n${u}\n`), A.success("Created .gitignore"));
|
|
737
900
|
let d = n.scripts ?? {}, f = {}, p = !1;
|
|
738
901
|
if (d["i18n:extract"] || (f["i18n:extract"] = "fluenti extract", p = !0), d["i18n:compile"] || (f["i18n:compile"] = "fluenti compile", p = !0), p) {
|
|
739
902
|
let e = {
|
|
@@ -743,9 +906,9 @@ async function be(e) {
|
|
|
743
906
|
...f
|
|
744
907
|
}
|
|
745
908
|
};
|
|
746
|
-
|
|
909
|
+
b(t, JSON.stringify(e, null, 2) + "\n", "utf-8"), A.success("Added i18n:extract and i18n:compile scripts to package.json");
|
|
747
910
|
}
|
|
748
|
-
|
|
911
|
+
A.log(""), A.box({
|
|
749
912
|
title: "Next steps",
|
|
750
913
|
message: [
|
|
751
914
|
r.pluginPackage ? `1. Install: pnpm add -D ${r.pluginPackage} @fluenti/cli` : "1. Install: pnpm add -D @fluenti/cli",
|
|
@@ -758,27 +921,27 @@ async function be(e) {
|
|
|
758
921
|
}
|
|
759
922
|
//#endregion
|
|
760
923
|
//#region src/cli.ts
|
|
761
|
-
function
|
|
762
|
-
return
|
|
924
|
+
function J(e) {
|
|
925
|
+
return D("md5").update(e).digest("hex").slice(0, 8);
|
|
763
926
|
}
|
|
764
|
-
function
|
|
765
|
-
if (!
|
|
766
|
-
let n =
|
|
927
|
+
function Y(e, t) {
|
|
928
|
+
if (!g(e)) return {};
|
|
929
|
+
let n = v(e, "utf-8");
|
|
767
930
|
return t === "json" ? l(n) : s(n);
|
|
768
931
|
}
|
|
769
|
-
function
|
|
770
|
-
|
|
932
|
+
function X(e, t, n) {
|
|
933
|
+
_(x(e), { recursive: !0 }), b(e, n === "json" ? d(t) : a(t), "utf-8");
|
|
771
934
|
}
|
|
772
|
-
async function
|
|
773
|
-
if (
|
|
935
|
+
async function ze(e, t, n) {
|
|
936
|
+
if (S(e) === ".vue") try {
|
|
774
937
|
let { extractFromVue: r } = await import("./vue-extractor.js");
|
|
775
938
|
return r(t, e, n);
|
|
776
939
|
} catch {
|
|
777
|
-
return
|
|
940
|
+
return A.warn(`Skipping ${e}: install @vue/compiler-sfc to extract from .vue files`), [];
|
|
778
941
|
}
|
|
779
942
|
return i(t, e, n);
|
|
780
943
|
}
|
|
781
|
-
var
|
|
944
|
+
var Z = O({
|
|
782
945
|
meta: {
|
|
783
946
|
name: "extract",
|
|
784
947
|
description: "Extract messages from source files"
|
|
@@ -805,9 +968,9 @@ var Se = E({
|
|
|
805
968
|
}
|
|
806
969
|
},
|
|
807
970
|
async run({ args: e }) {
|
|
808
|
-
let t = await u(e.config), n =
|
|
809
|
-
|
|
810
|
-
let r = await
|
|
971
|
+
let t = await u(e.config), n = m(t.locales);
|
|
972
|
+
A.info(`Extracting messages from ${t.include.join(", ")}`);
|
|
973
|
+
let r = await E(t.include, { ignore: t.exclude ?? [] }), i = [], a = e["no-cache"] ?? !1 ? null : new f(t.catalogDir, J(process.cwd())), s = 0;
|
|
811
974
|
for (let e of r) {
|
|
812
975
|
if (a) {
|
|
813
976
|
let t = a.get(e);
|
|
@@ -816,16 +979,16 @@ var Se = E({
|
|
|
816
979
|
continue;
|
|
817
980
|
}
|
|
818
981
|
}
|
|
819
|
-
let n = await
|
|
982
|
+
let n = await ze(e, v(e, "utf-8"), t.idGenerator);
|
|
820
983
|
i.push(...n), a && a.set(e, n);
|
|
821
984
|
}
|
|
822
|
-
a && (a.prune(new Set(r)), a.save()), s > 0 ?
|
|
985
|
+
a && (a.prune(new Set(r)), a.save()), s > 0 ? A.info(`Found ${i.length} messages in ${r.length} files (${s} cached)`) : A.info(`Found ${i.length} messages in ${r.length} files`);
|
|
823
986
|
let c = t.format === "json" ? ".json" : ".po", l = e.clean ?? !1, d = e["no-fuzzy"] ?? !1;
|
|
824
987
|
for (let e of n) {
|
|
825
|
-
let n =
|
|
826
|
-
|
|
988
|
+
let n = w(t.catalogDir, `${e}${c}`), { catalog: r, result: a } = o(Y(n, t.format), i, { stripFuzzy: d });
|
|
989
|
+
X(n, l ? Object.fromEntries(Object.entries(r).filter(([, e]) => !e.obsolete)) : r, t.format);
|
|
827
990
|
let s = l ? `${a.obsolete} removed` : `${a.obsolete} obsolete`;
|
|
828
|
-
|
|
991
|
+
A.success(`${e}: ${a.added} added, ${a.unchanged} unchanged, ${s}`);
|
|
829
992
|
}
|
|
830
993
|
for (let e of t.plugins ?? []) await e.onAfterExtract?.({
|
|
831
994
|
messages: new Map(i.map((e) => [e.id, e])),
|
|
@@ -835,13 +998,13 @@ var Se = E({
|
|
|
835
998
|
});
|
|
836
999
|
}
|
|
837
1000
|
});
|
|
838
|
-
function
|
|
1001
|
+
function Be(e) {
|
|
839
1002
|
let t = {};
|
|
840
1003
|
for (let [n, r] of Object.entries(e)) r.translation && r.translation.length > 0 ? t[n] = r.translation : r.message && (t[n] = r.message);
|
|
841
1004
|
return t;
|
|
842
1005
|
}
|
|
843
1006
|
async function Q(e, t, n) {
|
|
844
|
-
let r =
|
|
1007
|
+
let r = Be(e);
|
|
845
1008
|
for (let e of n) e.transformMessages && (r = await e.transformMessages(r, t));
|
|
846
1009
|
let i = {};
|
|
847
1010
|
for (let [t, n] of Object.entries(e)) {
|
|
@@ -863,7 +1026,7 @@ function $(e, t, n, r) {
|
|
|
863
1026
|
config: r
|
|
864
1027
|
};
|
|
865
1028
|
}
|
|
866
|
-
var
|
|
1029
|
+
var Ve = O({
|
|
867
1030
|
meta: {
|
|
868
1031
|
name: "compile",
|
|
869
1032
|
description: "Compile message catalogs to JS modules"
|
|
@@ -894,32 +1057,32 @@ var we = E({
|
|
|
894
1057
|
}
|
|
895
1058
|
},
|
|
896
1059
|
async run({ args: i }) {
|
|
897
|
-
let a = await u(i.config), o =
|
|
898
|
-
|
|
899
|
-
let f = {},
|
|
1060
|
+
let a = await u(i.config), o = m(a.locales), d = a.format === "json" ? ".json" : ".po";
|
|
1061
|
+
_(a.compileOutDir, { recursive: !0 });
|
|
1062
|
+
let f = {}, p = {};
|
|
900
1063
|
for (let e of o) {
|
|
901
|
-
let t =
|
|
902
|
-
if (
|
|
903
|
-
let n =
|
|
904
|
-
|
|
905
|
-
} else
|
|
1064
|
+
let t = w(a.catalogDir, `${e}${d}`);
|
|
1065
|
+
if (g(t)) {
|
|
1066
|
+
let n = v(t, "utf-8");
|
|
1067
|
+
p[e] = n, f[e] = a.format === "json" ? l(n) : s(n);
|
|
1068
|
+
} else p[e] = "", f[e] = {};
|
|
906
1069
|
}
|
|
907
|
-
let
|
|
908
|
-
|
|
909
|
-
let
|
|
910
|
-
if (
|
|
911
|
-
|
|
1070
|
+
let h = r(f);
|
|
1071
|
+
A.info(`Compiling ${h.length} messages across ${o.length} locales`);
|
|
1072
|
+
let y = i["skip-fuzzy"] ?? !1, x = i["no-cache"] ?? !1 ? null : new fe(a.catalogDir, J(process.cwd())), S = i.parallel ?? !1, C = i.concurrency ? parseInt(i.concurrency, 10) : void 0;
|
|
1073
|
+
if (C !== void 0 && (isNaN(C) || C < 1)) {
|
|
1074
|
+
A.error("Invalid --concurrency. Must be a positive integer."), process.exitCode = 1;
|
|
912
1075
|
return;
|
|
913
1076
|
}
|
|
914
1077
|
let T = 0, E = !1, D = [];
|
|
915
1078
|
for (let e of o) {
|
|
916
|
-
if (x && x.isUpToDate(e,
|
|
1079
|
+
if (x && x.isUpToDate(e, p[e]) && g(w(a.compileOutDir, `${e}.js`))) {
|
|
917
1080
|
T++;
|
|
918
1081
|
continue;
|
|
919
1082
|
}
|
|
920
1083
|
D.push(e);
|
|
921
1084
|
}
|
|
922
|
-
if (D.length > 0 && (E = !0),
|
|
1085
|
+
if (D.length > 0 && (E = !0), S && D.length > 1) {
|
|
923
1086
|
let e = a.plugins ?? [], t = {};
|
|
924
1087
|
for (let n of D) {
|
|
925
1088
|
for (let t of e) await t.onBeforeCompile?.($(n, f[n], a.compileOutDir, a));
|
|
@@ -928,36 +1091,36 @@ var we = E({
|
|
|
928
1091
|
let n = await c(D.map((e) => ({
|
|
929
1092
|
locale: e,
|
|
930
1093
|
catalog: t[e],
|
|
931
|
-
allIds:
|
|
1094
|
+
allIds: h,
|
|
932
1095
|
sourceLocale: a.sourceLocale,
|
|
933
|
-
options: { skipFuzzy:
|
|
934
|
-
})),
|
|
1096
|
+
options: { skipFuzzy: y }
|
|
1097
|
+
})), C);
|
|
935
1098
|
for (let e of n) {
|
|
936
|
-
let t =
|
|
937
|
-
if (
|
|
938
|
-
|
|
939
|
-
for (let t of e.stats.missing)
|
|
940
|
-
} else
|
|
1099
|
+
let t = w(a.compileOutDir, `${e.locale}.js`);
|
|
1100
|
+
if (b(t, e.code, "utf-8"), x && x.set(e.locale, p[e.locale]), e.stats.missing.length > 0) {
|
|
1101
|
+
A.warn(`${e.locale}: ${e.stats.compiled} compiled, ${e.stats.missing.length} missing translations`);
|
|
1102
|
+
for (let t of e.stats.missing) A.warn(` ⤷ ${t}`);
|
|
1103
|
+
} else A.success(`Compiled ${e.locale}: ${e.stats.compiled} messages → ${t}`);
|
|
941
1104
|
}
|
|
942
1105
|
for (let n of D) for (let r of e) await r.onAfterCompile?.($(n, t[n], a.compileOutDir, a));
|
|
943
1106
|
} else {
|
|
944
1107
|
let e = a.plugins ?? [];
|
|
945
1108
|
for (let n of D) {
|
|
946
|
-
let r =
|
|
1109
|
+
let r = w(a.compileOutDir, `${n}.js`);
|
|
947
1110
|
for (let t of e) await t.onBeforeCompile?.($(n, f[n], a.compileOutDir, a));
|
|
948
|
-
let i = e.length > 0 ? await Q(f[n], n, e) : f[n], { code: o, stats: s } = t(i, n,
|
|
949
|
-
if (
|
|
950
|
-
|
|
951
|
-
for (let e of s.missing)
|
|
952
|
-
} else
|
|
1111
|
+
let i = e.length > 0 ? await Q(f[n], n, e) : f[n], { code: o, stats: s } = t(i, n, h, a.sourceLocale, { skipFuzzy: y });
|
|
1112
|
+
if (b(r, o, "utf-8"), x && x.set(n, p[n]), s.missing.length > 0) {
|
|
1113
|
+
A.warn(`${n}: ${s.compiled} compiled, ${s.missing.length} missing translations`);
|
|
1114
|
+
for (let e of s.missing) A.warn(` ⤷ ${e}`);
|
|
1115
|
+
} else A.success(`Compiled ${n}: ${s.compiled} messages → ${r}`);
|
|
953
1116
|
for (let t of e) await t.onAfterCompile?.($(n, i, a.compileOutDir, a));
|
|
954
1117
|
}
|
|
955
1118
|
}
|
|
956
|
-
T > 0 &&
|
|
957
|
-
let
|
|
958
|
-
(E || !
|
|
1119
|
+
T > 0 && A.info(`${T} locale(s) unchanged — skipped`), x && x.save();
|
|
1120
|
+
let O = w(a.compileOutDir, "index.js"), k = w(a.compileOutDir, "messages.d.ts");
|
|
1121
|
+
(E || !g(O)) && (b(O, n(o, a.compileOutDir), "utf-8"), A.success(`Generated index → ${O}`)), (E || !g(k)) && (b(k, e(h, f, a.sourceLocale), "utf-8"), A.success(`Generated types → ${k}`));
|
|
959
1122
|
}
|
|
960
|
-
}),
|
|
1123
|
+
}), He = O({
|
|
961
1124
|
meta: {
|
|
962
1125
|
name: "stats",
|
|
963
1126
|
description: "Show translation progress"
|
|
@@ -967,9 +1130,9 @@ var we = E({
|
|
|
967
1130
|
description: "Path to config file"
|
|
968
1131
|
} },
|
|
969
1132
|
async run({ args: e }) {
|
|
970
|
-
let t = await u(e.config), n =
|
|
1133
|
+
let t = await u(e.config), n = m(t.locales), r = t.format === "json" ? ".json" : ".po", i = [];
|
|
971
1134
|
for (let e of n) {
|
|
972
|
-
let n =
|
|
1135
|
+
let n = Y(w(t.catalogDir, `${e}${r}`), t.format), a = Object.values(n).filter((e) => !e.obsolete), o = a.length, s = a.filter((e) => e.translation && e.translation.length > 0).length, c = o > 0 ? (s / o * 100).toFixed(1) + "%" : "—";
|
|
973
1136
|
i.push({
|
|
974
1137
|
locale: e,
|
|
975
1138
|
total: o,
|
|
@@ -977,11 +1140,11 @@ var we = E({
|
|
|
977
1140
|
pct: c
|
|
978
1141
|
});
|
|
979
1142
|
}
|
|
980
|
-
|
|
981
|
-
for (let e of i)
|
|
982
|
-
|
|
1143
|
+
A.log(""), A.log(" Locale │ Total │ Translated │ Progress"), A.log(" ────────┼───────┼────────────┼─────────────────────────────");
|
|
1144
|
+
for (let e of i) A.log(ie(e.locale, e.total, e.translated));
|
|
1145
|
+
A.log("");
|
|
983
1146
|
}
|
|
984
|
-
}),
|
|
1147
|
+
}), Ue = O({
|
|
985
1148
|
meta: {
|
|
986
1149
|
name: "lint",
|
|
987
1150
|
description: "Check translation quality (missing, inconsistent placeholders, fuzzy)"
|
|
@@ -1002,21 +1165,21 @@ var we = E({
|
|
|
1002
1165
|
}
|
|
1003
1166
|
},
|
|
1004
1167
|
async run({ args: e }) {
|
|
1005
|
-
let t = await u(e.config), n =
|
|
1006
|
-
for (let e of n) i[e] =
|
|
1168
|
+
let t = await u(e.config), n = m(t.locales), r = t.format === "json" ? ".json" : ".po", i = {};
|
|
1169
|
+
for (let e of n) i[e] = Y(w(t.catalogDir, `${e}${r}`), t.format);
|
|
1007
1170
|
let a = e.locale ? [e.locale] : void 0;
|
|
1008
|
-
|
|
1171
|
+
A.info(`Linting ${a ? a.join(", ") : "all locales"} (source: ${t.sourceLocale})`);
|
|
1009
1172
|
let o = {
|
|
1010
1173
|
sourceLocale: t.sourceLocale,
|
|
1011
1174
|
strict: e.strict ?? !1
|
|
1012
1175
|
};
|
|
1013
1176
|
a && (o.locales = a);
|
|
1014
|
-
let s =
|
|
1015
|
-
|
|
1177
|
+
let s = R(i, o);
|
|
1178
|
+
A.log(""), A.log(oe(s)), A.log("");
|
|
1016
1179
|
let c = s.filter((e) => e.severity === "error"), l = s.filter((e) => e.severity === "warning");
|
|
1017
1180
|
(c.length > 0 || e.strict && l.length > 0) && (process.exitCode = 1);
|
|
1018
1181
|
}
|
|
1019
|
-
}),
|
|
1182
|
+
}), We = O({
|
|
1020
1183
|
meta: {
|
|
1021
1184
|
name: "check",
|
|
1022
1185
|
description: "Check translation coverage for CI"
|
|
@@ -1046,11 +1209,11 @@ var we = E({
|
|
|
1046
1209
|
}
|
|
1047
1210
|
},
|
|
1048
1211
|
async run({ args: e }) {
|
|
1049
|
-
let t = await u(e.config), n =
|
|
1050
|
-
for (let e of n) i[e] =
|
|
1212
|
+
let t = await u(e.config), n = m(t.locales), r = t.format === "json" ? ".json" : ".po", i = {};
|
|
1213
|
+
for (let e of n) i[e] = Y(w(t.catalogDir, `${e}${r}`), t.format);
|
|
1051
1214
|
let a = parseFloat(e["min-coverage"] ?? "100");
|
|
1052
1215
|
if (isNaN(a) || a < 0 || a > 100) {
|
|
1053
|
-
|
|
1216
|
+
A.error("Invalid --min-coverage. Must be a number between 0 and 100."), process.exitCode = 1;
|
|
1054
1217
|
return;
|
|
1055
1218
|
}
|
|
1056
1219
|
let o = e.format ?? (e.ci ? "github" : "text"), s = {
|
|
@@ -1059,21 +1222,31 @@ var we = E({
|
|
|
1059
1222
|
format: o
|
|
1060
1223
|
};
|
|
1061
1224
|
e.locale && (s.locale = e.locale);
|
|
1062
|
-
let c =
|
|
1225
|
+
let c = ce(i, s);
|
|
1063
1226
|
switch (o) {
|
|
1064
1227
|
case "json":
|
|
1065
|
-
|
|
1228
|
+
A.log(de(c));
|
|
1066
1229
|
break;
|
|
1067
1230
|
case "github":
|
|
1068
|
-
|
|
1231
|
+
A.log(ue(c, t.catalogDir, t.format));
|
|
1069
1232
|
break;
|
|
1070
1233
|
default:
|
|
1071
|
-
|
|
1234
|
+
A.log(""), A.log(le(c)), A.log("");
|
|
1072
1235
|
break;
|
|
1073
1236
|
}
|
|
1074
1237
|
c.passed || (process.exitCode = 1);
|
|
1075
1238
|
}
|
|
1076
|
-
})
|
|
1239
|
+
});
|
|
1240
|
+
async function Ge(e, t, n) {
|
|
1241
|
+
let r = Array(e.length), i = 0, a = Array.from({ length: Math.min(n, e.length) }, async () => {
|
|
1242
|
+
for (; i < e.length;) {
|
|
1243
|
+
let n = i++;
|
|
1244
|
+
r[n] = await t(e[n]);
|
|
1245
|
+
}
|
|
1246
|
+
});
|
|
1247
|
+
return await Promise.all(a), r;
|
|
1248
|
+
}
|
|
1249
|
+
var Ke = O({
|
|
1077
1250
|
meta: {
|
|
1078
1251
|
name: "translate",
|
|
1079
1252
|
description: "Translate messages using AI (Claude Code or Codex CLI)"
|
|
@@ -1105,49 +1278,73 @@ var we = E({
|
|
|
1105
1278
|
context: {
|
|
1106
1279
|
type: "string",
|
|
1107
1280
|
description: "Project context description to improve translation quality"
|
|
1281
|
+
},
|
|
1282
|
+
glossary: {
|
|
1283
|
+
type: "string",
|
|
1284
|
+
description: "Path to glossary JSON file"
|
|
1285
|
+
},
|
|
1286
|
+
concurrency: {
|
|
1287
|
+
type: "string",
|
|
1288
|
+
description: "Max parallel locale translations (default: 3)"
|
|
1289
|
+
},
|
|
1290
|
+
timeout: {
|
|
1291
|
+
type: "string",
|
|
1292
|
+
description: "AI call timeout in seconds (default: 120)"
|
|
1108
1293
|
}
|
|
1109
1294
|
},
|
|
1110
1295
|
async run({ args: e }) {
|
|
1111
|
-
let t = await u(e.config), n =
|
|
1296
|
+
let t = await u(e.config), n = m(t.locales), r = e.provider;
|
|
1112
1297
|
if (r !== "claude" && r !== "codex") {
|
|
1113
|
-
|
|
1298
|
+
A.error(`Invalid provider "${r}". Use "claude" or "codex".`);
|
|
1114
1299
|
return;
|
|
1115
1300
|
}
|
|
1116
1301
|
let i = parseInt(e["batch-size"] ?? "50", 10);
|
|
1117
1302
|
if (isNaN(i) || i < 1) {
|
|
1118
|
-
|
|
1303
|
+
A.error("Invalid batch-size. Must be a positive integer.");
|
|
1119
1304
|
return;
|
|
1120
1305
|
}
|
|
1121
|
-
let a = e.
|
|
1122
|
-
if (
|
|
1123
|
-
|
|
1306
|
+
let a = e.glossary ? _e(w(e.glossary)) : void 0, o = e.concurrency ? parseInt(e.concurrency, 10) : 3;
|
|
1307
|
+
if (isNaN(o) || o < 1) {
|
|
1308
|
+
A.error("Invalid concurrency. Must be a positive integer.");
|
|
1124
1309
|
return;
|
|
1125
1310
|
}
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1311
|
+
let s = e.timeout ? parseInt(e.timeout, 10) : 120;
|
|
1312
|
+
if (isNaN(s) || s < 1) {
|
|
1313
|
+
A.error("Invalid timeout. Must be a positive integer (seconds).");
|
|
1314
|
+
return;
|
|
1315
|
+
}
|
|
1316
|
+
let c = s * 1e3, l = e.locale ? [e.locale] : n.filter((e) => e !== t.sourceLocale);
|
|
1317
|
+
if (l.length === 0) {
|
|
1318
|
+
A.warn("No target locales to translate.");
|
|
1319
|
+
return;
|
|
1320
|
+
}
|
|
1321
|
+
A.info(`Translating with ${r} (batch size: ${i})`);
|
|
1322
|
+
let d = t.format === "json" ? ".json" : ".po";
|
|
1323
|
+
await Ge(l, async (n) => {
|
|
1324
|
+
A.info(`\n[${n}]`);
|
|
1325
|
+
let o = w(t.catalogDir, `${n}${d}`), s = Y(o, t.format);
|
|
1131
1326
|
if (e["dry-run"]) {
|
|
1132
1327
|
let e = Object.entries(s).filter(([, e]) => !e.obsolete && (!e.translation || e.translation.length === 0));
|
|
1133
1328
|
if (e.length > 0) {
|
|
1134
|
-
for (let [t, n] of e)
|
|
1135
|
-
|
|
1136
|
-
} else
|
|
1137
|
-
|
|
1329
|
+
for (let [t, n] of e) A.log(` ${t}: ${n.message ?? t}`);
|
|
1330
|
+
A.success(` ${n}: ${e.length} messages would be translated (dry-run)`);
|
|
1331
|
+
} else A.success(` ${n}: already fully translated`);
|
|
1332
|
+
return;
|
|
1138
1333
|
}
|
|
1139
|
-
let { catalog:
|
|
1334
|
+
let l = a ? ve(a, n) : void 0, { catalog: u, translated: f, warnings: p } = await Ee({
|
|
1140
1335
|
provider: r,
|
|
1141
1336
|
sourceLocale: t.sourceLocale,
|
|
1142
1337
|
targetLocale: n,
|
|
1143
1338
|
catalog: s,
|
|
1144
1339
|
batchSize: i,
|
|
1340
|
+
glossary: l,
|
|
1341
|
+
timeoutMs: c,
|
|
1145
1342
|
...e.context ? { context: e.context } : {}
|
|
1146
1343
|
});
|
|
1147
|
-
|
|
1148
|
-
}
|
|
1344
|
+
f > 0 ? (X(o, u, t.format), A.success(` ${n}: ${f} messages translated`)) : A.success(` ${n}: already fully translated`), p.length > 0 && A.warn(` ${n}: ${p.length} QA warnings`);
|
|
1345
|
+
}, o);
|
|
1149
1346
|
}
|
|
1150
|
-
}),
|
|
1347
|
+
}), qe = O({
|
|
1151
1348
|
meta: {
|
|
1152
1349
|
name: "migrate",
|
|
1153
1350
|
description: "Migrate from another i18n library using AI"
|
|
@@ -1172,40 +1369,40 @@ var we = E({
|
|
|
1172
1369
|
async run({ args: e }) {
|
|
1173
1370
|
let t = e.provider;
|
|
1174
1371
|
if (t !== "claude" && t !== "codex") {
|
|
1175
|
-
|
|
1372
|
+
A.error(`Invalid provider "${t}". Use "claude" or "codex".`);
|
|
1176
1373
|
return;
|
|
1177
1374
|
}
|
|
1178
|
-
await
|
|
1375
|
+
await Ne({
|
|
1179
1376
|
from: e.from,
|
|
1180
1377
|
provider: t,
|
|
1181
1378
|
write: e.write ?? !1
|
|
1182
1379
|
});
|
|
1183
1380
|
}
|
|
1184
1381
|
});
|
|
1185
|
-
|
|
1382
|
+
k(O({
|
|
1186
1383
|
meta: {
|
|
1187
1384
|
name: "fluenti",
|
|
1188
1385
|
version: "0.0.1",
|
|
1189
1386
|
description: "Compile-time i18n for modern frameworks"
|
|
1190
1387
|
},
|
|
1191
1388
|
subCommands: {
|
|
1192
|
-
init:
|
|
1389
|
+
init: O({
|
|
1193
1390
|
meta: {
|
|
1194
1391
|
name: "init",
|
|
1195
1392
|
description: "Initialize Fluenti in your project"
|
|
1196
1393
|
},
|
|
1197
1394
|
args: {},
|
|
1198
1395
|
async run() {
|
|
1199
|
-
await
|
|
1396
|
+
await Re({ cwd: process.cwd() });
|
|
1200
1397
|
}
|
|
1201
1398
|
}),
|
|
1202
|
-
extract:
|
|
1203
|
-
compile:
|
|
1204
|
-
stats:
|
|
1205
|
-
lint:
|
|
1206
|
-
check:
|
|
1207
|
-
translate:
|
|
1208
|
-
migrate:
|
|
1399
|
+
extract: Z,
|
|
1400
|
+
compile: Ve,
|
|
1401
|
+
stats: He,
|
|
1402
|
+
lint: Ue,
|
|
1403
|
+
check: We,
|
|
1404
|
+
translate: Ke,
|
|
1405
|
+
migrate: qe
|
|
1209
1406
|
}
|
|
1210
1407
|
}));
|
|
1211
1408
|
//#endregion
|