@fluenti/cli 0.3.0 → 0.3.2
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 +12 -12
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +145 -143
- package/dist/cli.js.map +1 -1
- package/dist/{compile-DoeVtT7S.cjs → compile-CBSy1rNl.cjs} +2 -2
- package/dist/compile-CBSy1rNl.cjs.map +1 -0
- package/dist/{compile-BZGNcCK1.js → compile-jumIhf8m.js} +2 -2
- package/dist/compile-jumIhf8m.js.map +1 -0
- package/dist/compile-worker.cjs +1 -1
- package/dist/compile-worker.js +1 -1
- package/dist/compile.d.ts.map +1 -1
- package/dist/{extract-cache-1XVokN31.js → extract-cache-CmnwPMdA.js} +3 -3
- package/dist/{extract-cache-1XVokN31.js.map → extract-cache-CmnwPMdA.js.map} +1 -1
- package/dist/{extract-cache-BVyzqc__.cjs → extract-cache-IDp-S-ux.cjs} +2 -2
- package/dist/{extract-cache-BVyzqc__.cjs.map → extract-cache-IDp-S-ux.cjs.map} +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +2 -2
- package/dist/migrate.d.ts.map +1 -1
- package/dist/{tsx-extractor-Bi9AXMhH.cjs → tsx-extractor-j_z4fneM.cjs} +2 -2
- package/dist/{tsx-extractor-Bi9AXMhH.cjs.map → tsx-extractor-j_z4fneM.cjs.map} +1 -1
- package/dist/vue-extractor.cjs +1 -1
- package/package.json +2 -2
- package/dist/compile-BZGNcCK1.js.map +0 -1
- package/dist/compile-DoeVtT7S.cjs.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,33 +1,34 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { i as e, n as t, r as n, t as r } from "./compile-
|
|
2
|
+
import { i as e, n as t, r as n, t as r } from "./compile-jumIhf8m.js";
|
|
3
3
|
import { t as i } from "./tsx-extractor-B9fnGNTG.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-
|
|
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-CmnwPMdA.js";
|
|
5
5
|
import { resolveLocaleCodes as p } from "@fluenti/core/internal";
|
|
6
6
|
import { appendFileSync as m, existsSync as h, mkdirSync as g, readFileSync as _, writeFileSync as v } from "node:fs";
|
|
7
7
|
import { dirname as y, extname as b, join as x, resolve as S } from "node:path";
|
|
8
|
-
import C from "
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
11
|
-
import D from "
|
|
12
|
-
import
|
|
13
|
-
import {
|
|
8
|
+
import { fileURLToPath as C } from "node:url";
|
|
9
|
+
import w from "fast-glob";
|
|
10
|
+
import { createHash as T } from "node:crypto";
|
|
11
|
+
import { defineCommand as E, runMain as D } from "citty";
|
|
12
|
+
import O from "consola";
|
|
13
|
+
import { execFile as k } from "node:child_process";
|
|
14
|
+
import { promisify as A } from "node:util";
|
|
14
15
|
//#region src/stats-format.ts
|
|
15
|
-
var
|
|
16
|
-
function
|
|
16
|
+
var ee = "█", te = "░";
|
|
17
|
+
function ne(e, t = 20) {
|
|
17
18
|
let n = Math.max(0, Math.min(100, e)), r = Math.round(n / 100 * t);
|
|
18
|
-
return
|
|
19
|
+
return ee.repeat(r) + te.repeat(t - r);
|
|
19
20
|
}
|
|
20
|
-
function
|
|
21
|
+
function re(e) {
|
|
21
22
|
let t = e.toFixed(1) + "%";
|
|
22
23
|
return e >= 90 ? `\x1b[32m${t}\x1b[0m` : e >= 70 ? `\x1b[33m${t}\x1b[0m` : `\x1b[31m${t}\x1b[0m`;
|
|
23
24
|
}
|
|
24
|
-
function
|
|
25
|
-
let r = t > 0 ? n / t * 100 : 0, i = t > 0 ?
|
|
25
|
+
function ie(e, t, n) {
|
|
26
|
+
let r = t > 0 ? n / t * 100 : 0, i = t > 0 ? re(r) : "—", a = t > 0 ? ne(r) : "";
|
|
26
27
|
return ` ${e.padEnd(8)}│ ${String(t).padStart(5)} │ ${String(n).padStart(10)} │ ${a} ${i}`;
|
|
27
28
|
}
|
|
28
29
|
//#endregion
|
|
29
30
|
//#region src/lint.ts
|
|
30
|
-
function
|
|
31
|
+
function j(e, t) {
|
|
31
32
|
let n = [], { sourceLocale: r } = t, i = t.locales ?? Object.keys(e), a = e[r];
|
|
32
33
|
if (!a) return n.push({
|
|
33
34
|
rule: "missing-source",
|
|
@@ -59,7 +60,7 @@ function M(e, t) {
|
|
|
59
60
|
});
|
|
60
61
|
continue;
|
|
61
62
|
}
|
|
62
|
-
let s =
|
|
63
|
+
let s = M(r.message ?? e), c = M(o.translation), l = s.filter((e) => !c.includes(e)), u = c.filter((e) => !s.includes(e));
|
|
63
64
|
l.length > 0 && n.push({
|
|
64
65
|
rule: "inconsistent-placeholders",
|
|
65
66
|
severity: "error",
|
|
@@ -102,7 +103,7 @@ function M(e, t) {
|
|
|
102
103
|
});
|
|
103
104
|
return n;
|
|
104
105
|
}
|
|
105
|
-
function
|
|
106
|
+
function M(e) {
|
|
106
107
|
let t = [], n = /\{(\w+)(?:\s*,\s*(?:plural|select|selectordinal|number|date|time))?/g, r;
|
|
107
108
|
for (; (r = n.exec(e)) !== null;) {
|
|
108
109
|
let e = r[1];
|
|
@@ -110,9 +111,9 @@ function N(e) {
|
|
|
110
111
|
}
|
|
111
112
|
return t.sort();
|
|
112
113
|
}
|
|
113
|
-
function
|
|
114
|
+
function ae(e) {
|
|
114
115
|
if (e.length === 0) return " ✓ All checks passed";
|
|
115
|
-
let t = [], n =
|
|
116
|
+
let t = [], n = N(e, (e) => e.rule);
|
|
116
117
|
for (let [e, r] of Object.entries(n)) {
|
|
117
118
|
t.push(` ${e} (${r.length}):`);
|
|
118
119
|
for (let e of r) {
|
|
@@ -123,7 +124,7 @@ function P(e) {
|
|
|
123
124
|
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;
|
|
124
125
|
return t.push(""), t.push(` Summary: ${r} errors, ${i} warnings, ${a} info`), t.join("\n");
|
|
125
126
|
}
|
|
126
|
-
function
|
|
127
|
+
function N(e, t) {
|
|
127
128
|
let n = {};
|
|
128
129
|
for (let r of e) {
|
|
129
130
|
let e = t(r);
|
|
@@ -133,7 +134,7 @@ function re(e, t) {
|
|
|
133
134
|
}
|
|
134
135
|
//#endregion
|
|
135
136
|
//#region src/check.ts
|
|
136
|
-
function
|
|
137
|
+
function P(e, t) {
|
|
137
138
|
let { sourceLocale: n, minCoverage: r, locale: i } = t, a = e[n];
|
|
138
139
|
if (!a) return {
|
|
139
140
|
results: [],
|
|
@@ -181,10 +182,10 @@ function ie(e, t) {
|
|
|
181
182
|
passed: p,
|
|
182
183
|
minCoverage: r,
|
|
183
184
|
actualCoverage: f,
|
|
184
|
-
diagnostics:
|
|
185
|
+
diagnostics: j(e, m)
|
|
185
186
|
};
|
|
186
187
|
}
|
|
187
|
-
function
|
|
188
|
+
function oe(e) {
|
|
188
189
|
let t = [];
|
|
189
190
|
for (let n of e.results) {
|
|
190
191
|
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` : "";
|
|
@@ -194,7 +195,7 @@ function ae(e) {
|
|
|
194
195
|
let n = e.actualCoverage.toFixed(1), r = e.passed ? "PASSED" : "FAILED";
|
|
195
196
|
return t.push(`Coverage: ${n}% (min: ${e.minCoverage}%) — ${r}`), t.join("\n");
|
|
196
197
|
}
|
|
197
|
-
function
|
|
198
|
+
function se(e, t, n) {
|
|
198
199
|
let r = [], i = n === "json" ? ".json" : ".po";
|
|
199
200
|
for (let n of e.results) if (n.coverage < e.minCoverage) {
|
|
200
201
|
let a = `${t}/${n.locale}${i}`;
|
|
@@ -207,7 +208,7 @@ function oe(e, t, n) {
|
|
|
207
208
|
}
|
|
208
209
|
return r.join("\n");
|
|
209
210
|
}
|
|
210
|
-
function
|
|
211
|
+
function ce(e) {
|
|
211
212
|
return JSON.stringify({
|
|
212
213
|
results: e.results,
|
|
213
214
|
passed: e.passed,
|
|
@@ -217,7 +218,7 @@ function se(e) {
|
|
|
217
218
|
}
|
|
218
219
|
//#endregion
|
|
219
220
|
//#region src/compile-cache.ts
|
|
220
|
-
var F = "1",
|
|
221
|
+
var F = "1", le = class {
|
|
221
222
|
data;
|
|
222
223
|
cachePath;
|
|
223
224
|
dirty = !1;
|
|
@@ -250,11 +251,11 @@ var F = "1", ce = class {
|
|
|
250
251
|
}
|
|
251
252
|
};
|
|
252
253
|
function I(e) {
|
|
253
|
-
return
|
|
254
|
+
return T("md5").update(e).digest("hex");
|
|
254
255
|
}
|
|
255
256
|
//#endregion
|
|
256
257
|
//#region src/translate.ts
|
|
257
|
-
var L = k
|
|
258
|
+
var L = A(k);
|
|
258
259
|
function R(e, t, n, r) {
|
|
259
260
|
let i = JSON.stringify(n, null, 2);
|
|
260
261
|
return [
|
|
@@ -321,16 +322,16 @@ async function U(e) {
|
|
|
321
322
|
catalog: { ...i },
|
|
322
323
|
translated: 0
|
|
323
324
|
};
|
|
324
|
-
|
|
325
|
+
O.info(` ${c} untranslated messages, translating with ${t}...`);
|
|
325
326
|
let l = { ...i }, u = H(s, a), d = 0;
|
|
326
327
|
for (let e = 0; e < u.length; e++) {
|
|
327
328
|
let i = u[e], a = Object.keys(i);
|
|
328
|
-
u.length > 1 &&
|
|
329
|
+
u.length > 1 && O.info(` Batch ${e + 1}/${u.length} (${a.length} messages)`);
|
|
329
330
|
let s = B(await z(t, R(n, r, i, o)));
|
|
330
331
|
for (let e of a) s[e] && typeof s[e] == "string" ? (l[e] = {
|
|
331
332
|
...l[e],
|
|
332
333
|
translation: s[e]
|
|
333
|
-
}, d++) :
|
|
334
|
+
}, d++) : O.warn(` Missing translation for key: ${e}`);
|
|
334
335
|
}
|
|
335
336
|
return {
|
|
336
337
|
catalog: l,
|
|
@@ -339,7 +340,7 @@ async function U(e) {
|
|
|
339
340
|
}
|
|
340
341
|
//#endregion
|
|
341
342
|
//#region src/migrate.ts
|
|
342
|
-
var W = k
|
|
343
|
+
var W = A(k), G = {
|
|
343
344
|
"vue-i18n": {
|
|
344
345
|
name: "vue-i18n",
|
|
345
346
|
framework: "Vue",
|
|
@@ -480,7 +481,7 @@ var W = k(O), G = {
|
|
|
480
481
|
migrationGuide: "react/llms-migration.txt"
|
|
481
482
|
}
|
|
482
483
|
}, K = Object.keys(G);
|
|
483
|
-
function
|
|
484
|
+
function q(e) {
|
|
484
485
|
let t = e.toLowerCase().replace(/^@nuxtjs\//, "nuxt-").replace(/^@/, "");
|
|
485
486
|
return K.find((e) => e === t);
|
|
486
487
|
}
|
|
@@ -499,7 +500,7 @@ async function ue(e) {
|
|
|
499
500
|
content: _(e, "utf-8")
|
|
500
501
|
});
|
|
501
502
|
}
|
|
502
|
-
let r = await
|
|
503
|
+
let r = await w(e.localePatterns, { absolute: !1 });
|
|
503
504
|
for (let e of r.slice(0, 10)) {
|
|
504
505
|
let n = _(S(e), "utf-8");
|
|
505
506
|
t.localeFiles.push({
|
|
@@ -507,7 +508,7 @@ async function ue(e) {
|
|
|
507
508
|
content: n.length > 5e3 ? n.slice(0, 5e3) + "\n... (truncated)" : n
|
|
508
509
|
});
|
|
509
510
|
}
|
|
510
|
-
let i = await
|
|
511
|
+
let i = await w(e.sourcePatterns, { absolute: !1 });
|
|
511
512
|
for (let e of i.slice(0, 5)) {
|
|
512
513
|
let n = _(S(e), "utf-8");
|
|
513
514
|
t.sampleSources.push({
|
|
@@ -518,12 +519,12 @@ async function ue(e) {
|
|
|
518
519
|
return t;
|
|
519
520
|
}
|
|
520
521
|
function de(e) {
|
|
521
|
-
let t = [
|
|
522
|
+
let t = typeof __dirname < "u" ? __dirname : y(C(import.meta.url)), n = [
|
|
522
523
|
S("node_modules", "@fluenti", "cli", "..", "..", e),
|
|
523
|
-
x(
|
|
524
|
-
x(
|
|
524
|
+
x(t, "..", "..", "..", e),
|
|
525
|
+
x(t, "..", "..", e)
|
|
525
526
|
];
|
|
526
|
-
for (let e of
|
|
527
|
+
for (let e of n) if (h(e)) return _(e, "utf-8");
|
|
527
528
|
return "";
|
|
528
529
|
}
|
|
529
530
|
function fe(e, t, n) {
|
|
@@ -557,7 +558,8 @@ async function pe(e, t) {
|
|
|
557
558
|
return e;
|
|
558
559
|
}
|
|
559
560
|
} catch (t) {
|
|
560
|
-
|
|
561
|
+
let n = t;
|
|
562
|
+
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;
|
|
561
563
|
}
|
|
562
564
|
}
|
|
563
565
|
function me(e) {
|
|
@@ -582,30 +584,30 @@ function me(e) {
|
|
|
582
584
|
return a && (t.installCommands = a[1].trim()), t;
|
|
583
585
|
}
|
|
584
586
|
async function he(e) {
|
|
585
|
-
let { from: t, provider: n, write: r } = e, i =
|
|
587
|
+
let { from: t, provider: n, write: r } = e, i = q(t);
|
|
586
588
|
if (!i) {
|
|
587
|
-
|
|
588
|
-
for (let e of K)
|
|
589
|
+
O.error(`Unsupported library "${t}". Supported libraries:`);
|
|
590
|
+
for (let e of K) O.log(` - ${e}`);
|
|
589
591
|
return;
|
|
590
592
|
}
|
|
591
593
|
let a = G[i];
|
|
592
|
-
|
|
594
|
+
O.info(`Migrating from ${a.name} (${a.framework}) to Fluenti`), O.info("Scanning project for existing i18n files...");
|
|
593
595
|
let o = await ue(a);
|
|
594
596
|
if (o.configFiles.length === 0 && o.localeFiles.length === 0) {
|
|
595
|
-
|
|
597
|
+
O.warn(`No ${a.name} configuration or locale files found.`), O.info("Make sure you are running this command from the project root directory.");
|
|
596
598
|
return;
|
|
597
599
|
}
|
|
598
|
-
|
|
600
|
+
O.info(`Found: ${o.configFiles.length} config file(s), ${o.localeFiles.length} locale file(s), ${o.sampleSources.length} source file(s)`);
|
|
599
601
|
let s = de(a.migrationGuide);
|
|
600
|
-
|
|
602
|
+
O.info(`Generating migration plan with ${n}...`);
|
|
601
603
|
let c = me(await pe(n, fe(a, o, s)));
|
|
602
|
-
if (c.installCommands && (
|
|
604
|
+
if (c.installCommands && (O.log(""), O.box({
|
|
603
605
|
title: "Install Commands",
|
|
604
606
|
message: c.installCommands
|
|
605
607
|
})), c.config) if (r) {
|
|
606
608
|
let { writeFileSync: e } = await import("node:fs"), t = S("fluenti.config.ts");
|
|
607
|
-
e(t, c.config, "utf-8"),
|
|
608
|
-
} else
|
|
609
|
+
e(t, c.config, "utf-8"), O.success(`Written: ${t}`);
|
|
610
|
+
} else O.log(""), O.box({
|
|
609
611
|
title: "fluenti.config.ts",
|
|
610
612
|
message: c.config
|
|
611
613
|
});
|
|
@@ -614,21 +616,21 @@ async function he(e) {
|
|
|
614
616
|
t(S(n), { recursive: !0 });
|
|
615
617
|
for (let t of c.localeFiles) {
|
|
616
618
|
let r = S(n, `${t.locale}.po`);
|
|
617
|
-
e(r, t.content, "utf-8"),
|
|
619
|
+
e(r, t.content, "utf-8"), O.success(`Written: ${r}`);
|
|
618
620
|
}
|
|
619
|
-
} else for (let e of c.localeFiles)
|
|
621
|
+
} else for (let e of c.localeFiles) O.log(""), O.box({
|
|
620
622
|
title: `locales/${e.locale}.po`,
|
|
621
623
|
message: e.content.length > 500 ? e.content.slice(0, 500) + "\n... (use --write to save full file)" : e.content
|
|
622
624
|
});
|
|
623
|
-
c.steps && (
|
|
625
|
+
c.steps && (O.log(""), O.box({
|
|
624
626
|
title: "Migration Steps",
|
|
625
627
|
message: c.steps
|
|
626
|
-
})), !r && (c.config || c.localeFiles.length > 0) && (
|
|
628
|
+
})), !r && (c.config || c.localeFiles.length > 0) && (O.log(""), O.info("Run with --write to save generated files to disk:"), O.log(` fluenti migrate --from ${t} --write`));
|
|
627
629
|
}
|
|
628
630
|
//#endregion
|
|
629
631
|
//#region src/init.ts
|
|
630
632
|
var ge = /^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{1,8})*$/;
|
|
631
|
-
function
|
|
633
|
+
function J(e) {
|
|
632
634
|
if (!ge.test(e)) throw Error(`Invalid locale format: "${e}"`);
|
|
633
635
|
return e;
|
|
634
636
|
}
|
|
@@ -691,47 +693,47 @@ export default defineConfig({
|
|
|
691
693
|
async function be(e) {
|
|
692
694
|
let t = S(e.cwd, "package.json");
|
|
693
695
|
if (!h(t)) {
|
|
694
|
-
|
|
696
|
+
O.error("No package.json found in current directory.");
|
|
695
697
|
return;
|
|
696
698
|
}
|
|
697
699
|
let n = JSON.parse(_(t, "utf-8")), r = ve({
|
|
698
700
|
...n.dependencies,
|
|
699
701
|
...n.devDependencies
|
|
700
702
|
});
|
|
701
|
-
|
|
703
|
+
O.info(`Detected framework: ${r.name}`), r.pluginPackage && O.info(`Recommended plugin: ${r.pluginPackage}`);
|
|
702
704
|
let i = S(e.cwd, "fluenti.config.ts");
|
|
703
705
|
if (h(i)) {
|
|
704
|
-
|
|
706
|
+
O.warn("fluenti.config.ts already exists. Skipping config generation.");
|
|
705
707
|
return;
|
|
706
708
|
}
|
|
707
|
-
let a = await
|
|
709
|
+
let a = await O.prompt("Source locale?", {
|
|
708
710
|
type: "text",
|
|
709
711
|
default: "en",
|
|
710
712
|
placeholder: "en"
|
|
711
713
|
});
|
|
712
714
|
if (typeof a == "symbol") return;
|
|
713
|
-
let o = await
|
|
715
|
+
let o = await O.prompt("Target locales (comma-separated)?", {
|
|
714
716
|
type: "text",
|
|
715
717
|
default: "ja,zh-CN",
|
|
716
718
|
placeholder: "ja,zh-CN"
|
|
717
719
|
});
|
|
718
720
|
if (typeof o == "symbol") return;
|
|
719
|
-
let s = await
|
|
721
|
+
let s = await O.prompt("Catalog format?", {
|
|
720
722
|
type: "select",
|
|
721
723
|
options: ["po", "json"],
|
|
722
724
|
initial: "po"
|
|
723
725
|
});
|
|
724
726
|
if (typeof s == "symbol") return;
|
|
725
727
|
let c = o.split(",").map((e) => e.trim()).filter(Boolean);
|
|
726
|
-
|
|
727
|
-
for (let e of c)
|
|
728
|
+
J(a);
|
|
729
|
+
for (let e of c) J(e);
|
|
728
730
|
v(i, ye({
|
|
729
731
|
sourceLocale: a,
|
|
730
732
|
locales: [a, ...c.filter((e) => e !== a)],
|
|
731
733
|
format: s
|
|
732
|
-
}), "utf-8"),
|
|
734
|
+
}), "utf-8"), O.success("Created fluenti.config.ts");
|
|
733
735
|
let l = S(e.cwd, ".gitignore"), u = "src/locales/compiled/";
|
|
734
|
-
h(l) ? _(l, "utf-8").includes(u) || (m(l, `\n# Fluenti compiled catalogs\n${u}\n`),
|
|
736
|
+
h(l) ? _(l, "utf-8").includes(u) || (m(l, `\n# Fluenti compiled catalogs\n${u}\n`), O.success("Updated .gitignore")) : (v(l, `# Fluenti compiled catalogs\n${u}\n`), O.success("Created .gitignore"));
|
|
735
737
|
let d = n.scripts ?? {}, f = {}, p = !1;
|
|
736
738
|
if (d["i18n:extract"] || (f["i18n:extract"] = "fluenti extract", p = !0), d["i18n:compile"] || (f["i18n:compile"] = "fluenti compile", p = !0), p) {
|
|
737
739
|
let e = {
|
|
@@ -741,9 +743,9 @@ async function be(e) {
|
|
|
741
743
|
...f
|
|
742
744
|
}
|
|
743
745
|
};
|
|
744
|
-
v(t, JSON.stringify(e, null, 2) + "\n", "utf-8"),
|
|
746
|
+
v(t, JSON.stringify(e, null, 2) + "\n", "utf-8"), O.success("Added i18n:extract and i18n:compile scripts to package.json");
|
|
745
747
|
}
|
|
746
|
-
|
|
748
|
+
O.log(""), O.box({
|
|
747
749
|
title: "Next steps",
|
|
748
750
|
message: [
|
|
749
751
|
r.pluginPackage ? `1. Install: pnpm add -D ${r.pluginPackage} @fluenti/cli` : "1. Install: pnpm add -D @fluenti/cli",
|
|
@@ -756,15 +758,15 @@ async function be(e) {
|
|
|
756
758
|
}
|
|
757
759
|
//#endregion
|
|
758
760
|
//#region src/cli.ts
|
|
759
|
-
function
|
|
760
|
-
return
|
|
761
|
+
function Y(e) {
|
|
762
|
+
return T("md5").update(e).digest("hex").slice(0, 8);
|
|
761
763
|
}
|
|
762
|
-
function
|
|
764
|
+
function X(e, t) {
|
|
763
765
|
if (!h(e)) return {};
|
|
764
766
|
let n = _(e, "utf-8");
|
|
765
767
|
return t === "json" ? l(n) : s(n);
|
|
766
768
|
}
|
|
767
|
-
function
|
|
769
|
+
function Z(e, t, n) {
|
|
768
770
|
g(y(e), { recursive: !0 }), v(e, n === "json" ? d(t) : a(t), "utf-8");
|
|
769
771
|
}
|
|
770
772
|
async function xe(e, t, n) {
|
|
@@ -772,11 +774,11 @@ async function xe(e, t, n) {
|
|
|
772
774
|
let { extractFromVue: r } = await import("./vue-extractor.js");
|
|
773
775
|
return r(t, e, n);
|
|
774
776
|
} catch {
|
|
775
|
-
return
|
|
777
|
+
return O.warn(`Skipping ${e}: install @vue/compiler-sfc to extract from .vue files`), [];
|
|
776
778
|
}
|
|
777
779
|
return i(t, e, n);
|
|
778
780
|
}
|
|
779
|
-
var Se =
|
|
781
|
+
var Se = E({
|
|
780
782
|
meta: {
|
|
781
783
|
name: "extract",
|
|
782
784
|
description: "Extract messages from source files"
|
|
@@ -804,8 +806,8 @@ var Se = T({
|
|
|
804
806
|
},
|
|
805
807
|
async run({ args: e }) {
|
|
806
808
|
let t = await u(e.config), n = p(t.locales);
|
|
807
|
-
|
|
808
|
-
let r = await
|
|
809
|
+
O.info(`Extracting messages from ${t.include.join(", ")}`);
|
|
810
|
+
let r = await w(t.include, { ignore: t.exclude ?? [] }), i = [], a = e["no-cache"] ?? !1 ? null : new f(t.catalogDir, Y(process.cwd())), s = 0;
|
|
809
811
|
for (let e of r) {
|
|
810
812
|
if (a) {
|
|
811
813
|
let t = a.get(e);
|
|
@@ -817,13 +819,13 @@ var Se = T({
|
|
|
817
819
|
let n = await xe(e, _(e, "utf-8"), t.idGenerator);
|
|
818
820
|
i.push(...n), a && a.set(e, n);
|
|
819
821
|
}
|
|
820
|
-
a && (a.prune(new Set(r)), a.save()), s > 0 ?
|
|
822
|
+
a && (a.prune(new Set(r)), a.save()), s > 0 ? O.info(`Found ${i.length} messages in ${r.length} files (${s} cached)`) : O.info(`Found ${i.length} messages in ${r.length} files`);
|
|
821
823
|
let c = t.format === "json" ? ".json" : ".po", l = e.clean ?? !1, d = e["no-fuzzy"] ?? !1;
|
|
822
824
|
for (let e of n) {
|
|
823
|
-
let n = S(t.catalogDir, `${e}${c}`), { catalog: r, result: a } = o(
|
|
824
|
-
|
|
825
|
+
let n = S(t.catalogDir, `${e}${c}`), { catalog: r, result: a } = o(X(n, t.format), i, { stripFuzzy: d });
|
|
826
|
+
Z(n, l ? Object.fromEntries(Object.entries(r).filter(([, e]) => !e.obsolete)) : r, t.format);
|
|
825
827
|
let s = l ? `${a.obsolete} removed` : `${a.obsolete} obsolete`;
|
|
826
|
-
|
|
828
|
+
O.success(`${e}: ${a.added} added, ${a.unchanged} unchanged, ${s}`);
|
|
827
829
|
}
|
|
828
830
|
for (let e of t.plugins ?? []) await e.onAfterExtract?.({
|
|
829
831
|
messages: new Map(i.map((e) => [e.id, e])),
|
|
@@ -838,7 +840,7 @@ function Ce(e) {
|
|
|
838
840
|
for (let [n, r] of Object.entries(e)) r.translation && r.translation.length > 0 ? t[n] = r.translation : r.message && (t[n] = r.message);
|
|
839
841
|
return t;
|
|
840
842
|
}
|
|
841
|
-
async function
|
|
843
|
+
async function Q(e, t, n) {
|
|
842
844
|
let r = Ce(e);
|
|
843
845
|
for (let e of n) e.transformMessages && (r = await e.transformMessages(r, t));
|
|
844
846
|
let i = {};
|
|
@@ -851,7 +853,7 @@ async function Z(e, t, n) {
|
|
|
851
853
|
}
|
|
852
854
|
return i;
|
|
853
855
|
}
|
|
854
|
-
function
|
|
856
|
+
function $(e, t, n, r) {
|
|
855
857
|
let i = {};
|
|
856
858
|
for (let [e, n] of Object.entries(t)) n.translation && n.translation.length > 0 ? i[e] = n.translation : n.message && (i[e] = n.message);
|
|
857
859
|
return {
|
|
@@ -861,7 +863,7 @@ function Q(e, t, n, r) {
|
|
|
861
863
|
config: r
|
|
862
864
|
};
|
|
863
865
|
}
|
|
864
|
-
var
|
|
866
|
+
var we = E({
|
|
865
867
|
meta: {
|
|
866
868
|
name: "compile",
|
|
867
869
|
description: "Compile message catalogs to JS modules"
|
|
@@ -903,27 +905,27 @@ var $ = T({
|
|
|
903
905
|
} else m[e] = "", f[e] = {};
|
|
904
906
|
}
|
|
905
907
|
let y = r(f);
|
|
906
|
-
|
|
907
|
-
let b = i["skip-fuzzy"] ?? !1, x = i["no-cache"] ?? !1 ? null : new
|
|
908
|
+
O.info(`Compiling ${y.length} messages across ${o.length} locales`);
|
|
909
|
+
let b = i["skip-fuzzy"] ?? !1, x = i["no-cache"] ?? !1 ? null : new le(a.catalogDir, Y(process.cwd())), C = i.parallel ?? !1, w = i.concurrency ? parseInt(i.concurrency, 10) : void 0;
|
|
908
910
|
if (w !== void 0 && (isNaN(w) || w < 1)) {
|
|
909
|
-
|
|
911
|
+
O.error("Invalid --concurrency. Must be a positive integer."), process.exitCode = 1;
|
|
910
912
|
return;
|
|
911
913
|
}
|
|
912
|
-
let T = 0, E = !1,
|
|
914
|
+
let T = 0, E = !1, D = [];
|
|
913
915
|
for (let e of o) {
|
|
914
916
|
if (x && x.isUpToDate(e, m[e]) && h(S(a.compileOutDir, `${e}.js`))) {
|
|
915
917
|
T++;
|
|
916
918
|
continue;
|
|
917
919
|
}
|
|
918
|
-
|
|
920
|
+
D.push(e);
|
|
919
921
|
}
|
|
920
|
-
if (
|
|
922
|
+
if (D.length > 0 && (E = !0), C && D.length > 1) {
|
|
921
923
|
let e = a.plugins ?? [], t = {};
|
|
922
|
-
for (let n of
|
|
923
|
-
for (let t of e) await t.onBeforeCompile?.(
|
|
924
|
-
t[n] = e.length > 0 ? await
|
|
924
|
+
for (let n of D) {
|
|
925
|
+
for (let t of e) await t.onBeforeCompile?.($(n, f[n], a.compileOutDir, a));
|
|
926
|
+
t[n] = e.length > 0 ? await Q(f[n], n, e) : f[n];
|
|
925
927
|
}
|
|
926
|
-
let n = await c(
|
|
928
|
+
let n = await c(D.map((e) => ({
|
|
927
929
|
locale: e,
|
|
928
930
|
catalog: t[e],
|
|
929
931
|
allIds: y,
|
|
@@ -933,29 +935,29 @@ var $ = T({
|
|
|
933
935
|
for (let e of n) {
|
|
934
936
|
let t = S(a.compileOutDir, `${e.locale}.js`);
|
|
935
937
|
if (v(t, e.code, "utf-8"), x && x.set(e.locale, m[e.locale]), e.stats.missing.length > 0) {
|
|
936
|
-
|
|
937
|
-
for (let t of e.stats.missing)
|
|
938
|
-
} else
|
|
938
|
+
O.warn(`${e.locale}: ${e.stats.compiled} compiled, ${e.stats.missing.length} missing translations`);
|
|
939
|
+
for (let t of e.stats.missing) O.warn(` ⤷ ${t}`);
|
|
940
|
+
} else O.success(`Compiled ${e.locale}: ${e.stats.compiled} messages → ${t}`);
|
|
939
941
|
}
|
|
940
|
-
for (let n of
|
|
942
|
+
for (let n of D) for (let r of e) await r.onAfterCompile?.($(n, t[n], a.compileOutDir, a));
|
|
941
943
|
} else {
|
|
942
944
|
let e = a.plugins ?? [];
|
|
943
|
-
for (let n of
|
|
945
|
+
for (let n of D) {
|
|
944
946
|
let r = S(a.compileOutDir, `${n}.js`);
|
|
945
|
-
for (let t of e) await t.onBeforeCompile?.(
|
|
946
|
-
let i = e.length > 0 ? await
|
|
947
|
+
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, y, a.sourceLocale, { skipFuzzy: b });
|
|
947
949
|
if (v(r, o, "utf-8"), x && x.set(n, m[n]), s.missing.length > 0) {
|
|
948
|
-
|
|
949
|
-
for (let e of s.missing)
|
|
950
|
-
} else
|
|
951
|
-
for (let t of e) await t.onAfterCompile?.(
|
|
950
|
+
O.warn(`${n}: ${s.compiled} compiled, ${s.missing.length} missing translations`);
|
|
951
|
+
for (let e of s.missing) O.warn(` ⤷ ${e}`);
|
|
952
|
+
} else O.success(`Compiled ${n}: ${s.compiled} messages → ${r}`);
|
|
953
|
+
for (let t of e) await t.onAfterCompile?.($(n, i, a.compileOutDir, a));
|
|
952
954
|
}
|
|
953
955
|
}
|
|
954
|
-
T > 0 &&
|
|
956
|
+
T > 0 && O.info(`${T} locale(s) unchanged — skipped`), x && x.save();
|
|
955
957
|
let k = S(a.compileOutDir, "index.js"), A = S(a.compileOutDir, "messages.d.ts");
|
|
956
|
-
(E || !h(k)) && (v(k, n(o, a.compileOutDir), "utf-8"),
|
|
958
|
+
(E || !h(k)) && (v(k, n(o, a.compileOutDir), "utf-8"), O.success(`Generated index → ${k}`)), (E || !h(A)) && (v(A, e(y, f, a.sourceLocale), "utf-8"), O.success(`Generated types → ${A}`));
|
|
957
959
|
}
|
|
958
|
-
}),
|
|
960
|
+
}), Te = E({
|
|
959
961
|
meta: {
|
|
960
962
|
name: "stats",
|
|
961
963
|
description: "Show translation progress"
|
|
@@ -967,7 +969,7 @@ var $ = T({
|
|
|
967
969
|
async run({ args: e }) {
|
|
968
970
|
let t = await u(e.config), n = p(t.locales), r = t.format === "json" ? ".json" : ".po", i = [];
|
|
969
971
|
for (let e of n) {
|
|
970
|
-
let n =
|
|
972
|
+
let n = X(S(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) + "%" : "—";
|
|
971
973
|
i.push({
|
|
972
974
|
locale: e,
|
|
973
975
|
total: o,
|
|
@@ -975,11 +977,11 @@ var $ = T({
|
|
|
975
977
|
pct: c
|
|
976
978
|
});
|
|
977
979
|
}
|
|
978
|
-
|
|
979
|
-
for (let e of i)
|
|
980
|
-
|
|
980
|
+
O.log(""), O.log(" Locale │ Total │ Translated │ Progress"), O.log(" ────────┼───────┼────────────┼─────────────────────────────");
|
|
981
|
+
for (let e of i) O.log(ie(e.locale, e.total, e.translated));
|
|
982
|
+
O.log("");
|
|
981
983
|
}
|
|
982
|
-
}),
|
|
984
|
+
}), Ee = E({
|
|
983
985
|
meta: {
|
|
984
986
|
name: "lint",
|
|
985
987
|
description: "Check translation quality (missing, inconsistent placeholders, fuzzy)"
|
|
@@ -1001,20 +1003,20 @@ var $ = T({
|
|
|
1001
1003
|
},
|
|
1002
1004
|
async run({ args: e }) {
|
|
1003
1005
|
let t = await u(e.config), n = p(t.locales), r = t.format === "json" ? ".json" : ".po", i = {};
|
|
1004
|
-
for (let e of n) i[e] =
|
|
1006
|
+
for (let e of n) i[e] = X(S(t.catalogDir, `${e}${r}`), t.format);
|
|
1005
1007
|
let a = e.locale ? [e.locale] : void 0;
|
|
1006
|
-
|
|
1008
|
+
O.info(`Linting ${a ? a.join(", ") : "all locales"} (source: ${t.sourceLocale})`);
|
|
1007
1009
|
let o = {
|
|
1008
1010
|
sourceLocale: t.sourceLocale,
|
|
1009
1011
|
strict: e.strict ?? !1
|
|
1010
1012
|
};
|
|
1011
1013
|
a && (o.locales = a);
|
|
1012
|
-
let s =
|
|
1013
|
-
|
|
1014
|
+
let s = j(i, o);
|
|
1015
|
+
O.log(""), O.log(ae(s)), O.log("");
|
|
1014
1016
|
let c = s.filter((e) => e.severity === "error"), l = s.filter((e) => e.severity === "warning");
|
|
1015
1017
|
(c.length > 0 || e.strict && l.length > 0) && (process.exitCode = 1);
|
|
1016
1018
|
}
|
|
1017
|
-
}),
|
|
1019
|
+
}), De = E({
|
|
1018
1020
|
meta: {
|
|
1019
1021
|
name: "check",
|
|
1020
1022
|
description: "Check translation coverage for CI"
|
|
@@ -1045,10 +1047,10 @@ var $ = T({
|
|
|
1045
1047
|
},
|
|
1046
1048
|
async run({ args: e }) {
|
|
1047
1049
|
let t = await u(e.config), n = p(t.locales), r = t.format === "json" ? ".json" : ".po", i = {};
|
|
1048
|
-
for (let e of n) i[e] =
|
|
1050
|
+
for (let e of n) i[e] = X(S(t.catalogDir, `${e}${r}`), t.format);
|
|
1049
1051
|
let a = parseFloat(e["min-coverage"] ?? "100");
|
|
1050
1052
|
if (isNaN(a) || a < 0 || a > 100) {
|
|
1051
|
-
|
|
1053
|
+
O.error("Invalid --min-coverage. Must be a number between 0 and 100."), process.exitCode = 1;
|
|
1052
1054
|
return;
|
|
1053
1055
|
}
|
|
1054
1056
|
let o = e.format ?? (e.ci ? "github" : "text"), s = {
|
|
@@ -1057,21 +1059,21 @@ var $ = T({
|
|
|
1057
1059
|
format: o
|
|
1058
1060
|
};
|
|
1059
1061
|
e.locale && (s.locale = e.locale);
|
|
1060
|
-
let c =
|
|
1062
|
+
let c = P(i, s);
|
|
1061
1063
|
switch (o) {
|
|
1062
1064
|
case "json":
|
|
1063
|
-
|
|
1065
|
+
O.log(ce(c));
|
|
1064
1066
|
break;
|
|
1065
1067
|
case "github":
|
|
1066
|
-
|
|
1068
|
+
O.log(se(c, t.catalogDir, t.format));
|
|
1067
1069
|
break;
|
|
1068
1070
|
default:
|
|
1069
|
-
|
|
1071
|
+
O.log(""), O.log(oe(c)), O.log("");
|
|
1070
1072
|
break;
|
|
1071
1073
|
}
|
|
1072
1074
|
c.passed || (process.exitCode = 1);
|
|
1073
1075
|
}
|
|
1074
|
-
}),
|
|
1076
|
+
}), Oe = E({
|
|
1075
1077
|
meta: {
|
|
1076
1078
|
name: "translate",
|
|
1077
1079
|
description: "Translate messages using AI (Claude Code or Codex CLI)"
|
|
@@ -1108,30 +1110,30 @@ var $ = T({
|
|
|
1108
1110
|
async run({ args: e }) {
|
|
1109
1111
|
let t = await u(e.config), n = p(t.locales), r = e.provider;
|
|
1110
1112
|
if (r !== "claude" && r !== "codex") {
|
|
1111
|
-
|
|
1113
|
+
O.error(`Invalid provider "${r}". Use "claude" or "codex".`);
|
|
1112
1114
|
return;
|
|
1113
1115
|
}
|
|
1114
1116
|
let i = parseInt(e["batch-size"] ?? "50", 10);
|
|
1115
1117
|
if (isNaN(i) || i < 1) {
|
|
1116
|
-
|
|
1118
|
+
O.error("Invalid batch-size. Must be a positive integer.");
|
|
1117
1119
|
return;
|
|
1118
1120
|
}
|
|
1119
1121
|
let a = e.locale ? [e.locale] : n.filter((e) => e !== t.sourceLocale);
|
|
1120
1122
|
if (a.length === 0) {
|
|
1121
|
-
|
|
1123
|
+
O.warn("No target locales to translate.");
|
|
1122
1124
|
return;
|
|
1123
1125
|
}
|
|
1124
|
-
|
|
1126
|
+
O.info(`Translating with ${r} (batch size: ${i})`);
|
|
1125
1127
|
let o = t.format === "json" ? ".json" : ".po";
|
|
1126
1128
|
for (let n of a) {
|
|
1127
|
-
|
|
1128
|
-
let a = S(t.catalogDir, `${n}${o}`), s =
|
|
1129
|
+
O.info(`\n[${n}]`);
|
|
1130
|
+
let a = S(t.catalogDir, `${n}${o}`), s = X(a, t.format);
|
|
1129
1131
|
if (e["dry-run"]) {
|
|
1130
1132
|
let e = Object.entries(s).filter(([, e]) => !e.obsolete && (!e.translation || e.translation.length === 0));
|
|
1131
1133
|
if (e.length > 0) {
|
|
1132
|
-
for (let [t, n] of e)
|
|
1133
|
-
|
|
1134
|
-
} else
|
|
1134
|
+
for (let [t, n] of e) O.log(` ${t}: ${n.message ?? t}`);
|
|
1135
|
+
O.success(` ${n}: ${e.length} messages would be translated (dry-run)`);
|
|
1136
|
+
} else O.success(` ${n}: already fully translated`);
|
|
1135
1137
|
continue;
|
|
1136
1138
|
}
|
|
1137
1139
|
let { catalog: c, translated: l } = await U({
|
|
@@ -1142,10 +1144,10 @@ var $ = T({
|
|
|
1142
1144
|
batchSize: i,
|
|
1143
1145
|
...e.context ? { context: e.context } : {}
|
|
1144
1146
|
});
|
|
1145
|
-
l > 0 ? (
|
|
1147
|
+
l > 0 ? (Z(a, c, t.format), O.success(` ${n}: ${l} messages translated`)) : O.success(` ${n}: already fully translated`);
|
|
1146
1148
|
}
|
|
1147
1149
|
}
|
|
1148
|
-
}),
|
|
1150
|
+
}), ke = E({
|
|
1149
1151
|
meta: {
|
|
1150
1152
|
name: "migrate",
|
|
1151
1153
|
description: "Migrate from another i18n library using AI"
|
|
@@ -1170,7 +1172,7 @@ var $ = T({
|
|
|
1170
1172
|
async run({ args: e }) {
|
|
1171
1173
|
let t = e.provider;
|
|
1172
1174
|
if (t !== "claude" && t !== "codex") {
|
|
1173
|
-
|
|
1175
|
+
O.error(`Invalid provider "${t}". Use "claude" or "codex".`);
|
|
1174
1176
|
return;
|
|
1175
1177
|
}
|
|
1176
1178
|
await he({
|
|
@@ -1180,14 +1182,14 @@ var $ = T({
|
|
|
1180
1182
|
});
|
|
1181
1183
|
}
|
|
1182
1184
|
});
|
|
1183
|
-
E(
|
|
1185
|
+
D(E({
|
|
1184
1186
|
meta: {
|
|
1185
1187
|
name: "fluenti",
|
|
1186
1188
|
version: "0.0.1",
|
|
1187
1189
|
description: "Compile-time i18n for modern frameworks"
|
|
1188
1190
|
},
|
|
1189
1191
|
subCommands: {
|
|
1190
|
-
init:
|
|
1192
|
+
init: E({
|
|
1191
1193
|
meta: {
|
|
1192
1194
|
name: "init",
|
|
1193
1195
|
description: "Initialize Fluenti in your project"
|
|
@@ -1198,12 +1200,12 @@ E(T({
|
|
|
1198
1200
|
}
|
|
1199
1201
|
}),
|
|
1200
1202
|
extract: Se,
|
|
1201
|
-
compile:
|
|
1202
|
-
stats:
|
|
1203
|
-
lint:
|
|
1204
|
-
check:
|
|
1205
|
-
translate:
|
|
1206
|
-
migrate:
|
|
1203
|
+
compile: we,
|
|
1204
|
+
stats: Te,
|
|
1205
|
+
lint: Ee,
|
|
1206
|
+
check: De,
|
|
1207
|
+
translate: Oe,
|
|
1208
|
+
migrate: ke
|
|
1207
1209
|
}
|
|
1208
1210
|
}));
|
|
1209
1211
|
//#endregion
|