@vmz/vmz 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -2
- package/bin/vmz.js +4 -0
- package/dist/application-cmd.d.ts +21 -0
- package/dist/application-cmd.js +347 -0
- package/dist/bundler-adapter.d.ts +63 -0
- package/dist/bundler-adapter.js +110 -0
- package/dist/cli.d.ts +23 -0
- package/dist/cli.js +474 -0
- package/dist/dev-session.d.ts +35 -0
- package/dist/dev-session.js +290 -0
- package/dist/document-build.d.ts +99 -0
- package/dist/document-build.js +273 -0
- package/dist/document-check.d.ts +44 -0
- package/dist/document-check.js +246 -0
- package/dist/document-cmd.d.ts +8 -0
- package/dist/document-cmd.js +146 -0
- package/dist/document-designs.d.ts +9 -0
- package/dist/document-designs.js +126 -0
- package/dist/document-enrich.d.ts +23 -0
- package/dist/document-enrich.js +233 -0
- package/dist/document-evidence.d.ts +49 -0
- package/dist/document-evidence.js +509 -0
- package/dist/document-integrate.d.ts +34 -0
- package/dist/document-integrate.js +88 -0
- package/dist/document-interactive.d.ts +69 -0
- package/dist/document-interactive.js +254 -0
- package/dist/document-locale.d.ts +31 -0
- package/dist/document-locale.js +59 -0
- package/dist/document-markdown.d.ts +12 -0
- package/dist/document-markdown.js +45 -0
- package/dist/document-scan.d.ts +21 -0
- package/dist/document-scan.js +151 -0
- package/dist/document-schema.d.ts +86 -0
- package/dist/document-schema.js +87 -0
- package/dist/explain-cmd.d.ts +5 -0
- package/dist/explain-cmd.js +123 -0
- package/dist/index.d.ts +359 -0
- package/dist/index.js +580 -0
- package/dist/invocation.d.ts +91 -0
- package/dist/invocation.js +190 -0
- package/dist/locale-check.d.ts +106 -0
- package/dist/locale-check.js +736 -0
- package/dist/locale-cmd.d.ts +5 -0
- package/dist/locale-cmd.js +442 -0
- package/dist/locale-delivery.d.ts +298 -0
- package/dist/locale-delivery.js +443 -0
- package/dist/locale-router.d.ts +206 -0
- package/dist/locale-router.js +507 -0
- package/dist/locale-runtime.d.ts +406 -0
- package/dist/locale-runtime.js +541 -0
- package/dist/locale-schema.d.ts +8 -0
- package/dist/locale-schema.js +9 -0
- package/dist/locale-tooling.d.ts +118 -0
- package/dist/locale-tooling.js +357 -0
- package/dist/log.d.ts +19 -0
- package/dist/log.js +42 -0
- package/dist/packages.d.ts +26 -0
- package/dist/packages.js +146 -0
- package/dist/plugin-host.d.ts +29 -0
- package/dist/plugin-host.js +369 -0
- package/dist/refactor-cmd.d.ts +8 -0
- package/dist/refactor-cmd.js +156 -0
- package/dist/resolve-native-cli.d.ts +14 -0
- package/dist/resolve-native-cli.js +84 -0
- package/dist/resolve.d.ts +24 -0
- package/dist/resolve.js +55 -0
- package/dist/test-cmd.d.ts +9 -0
- package/dist/test-cmd.js +363 -0
- package/dist/test-compile.d.ts +2 -0
- package/dist/test-compile.js +3 -0
- package/dist/test-discover.d.ts +2 -0
- package/dist/test-discover.js +3 -0
- package/dist/test-logic.d.ts +2 -0
- package/dist/test-logic.js +3 -0
- package/dist/test-protocol.d.ts +2 -0
- package/dist/test-protocol.js +3 -0
- package/dist/watch-diff.d.ts +17 -0
- package/dist/watch-diff.js +56 -0
- package/package.json +96 -3
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* `vmz locale` CLI (–).
|
|
4
|
+
*/
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import JSON5 from 'json5';
|
|
8
|
+
import { parseArgs } from './cli.js';
|
|
9
|
+
import { checkLocales, emitLocaleTypedModules, localeHasErrors, planLocaleRename } from './locale-check.js';
|
|
10
|
+
import { checkLocaleDelivery } from './locale-delivery.js';
|
|
11
|
+
import { checkLocaleRouter } from './locale-router.js';
|
|
12
|
+
import { checkLocaleRuntime } from './locale-runtime.js';
|
|
13
|
+
import { checkLocaleConformance, diffLocaleCatalogs, explainLocaleMessage, extractHardcodedText, pseudoLocalizeCatalog, } from './locale-tooling.js';
|
|
14
|
+
import { log } from './log.js';
|
|
15
|
+
function printLocaleHelp() {
|
|
16
|
+
console.log(`vmz locale — /locales application i18n (–)
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
vmz locale check [project] Check locales.json5 + catalogs + param contracts
|
|
20
|
+
vmz locale list [project] List LocaleIds (manifest order)
|
|
21
|
+
vmz locale emit-types [project] Emit #locales/* .d.ts stubs (I1)
|
|
22
|
+
vmz locale rename <from> <to> MessageId rename plan (I1)
|
|
23
|
+
vmz locale runtime-check [project] LocaleContext / FormatterContext / SSR parity (I2)
|
|
24
|
+
vmz locale router-check [project] Route realization / canonical / hreflang / PageMeta (I3)
|
|
25
|
+
vmz locale delivery-check [project] Multi-host LocaleDeliveryResolution (I4)
|
|
26
|
+
vmz locale explain <message-id> [project] Explain MessageId (I5)
|
|
27
|
+
vmz locale diff <base> <target> [project] Diff two locales (I5)
|
|
28
|
+
vmz locale extract [project] Hardcoded text sink check (I5)
|
|
29
|
+
vmz locale pseudo <source> [project] Pseudo-localize catalog (I5, dev/test)
|
|
30
|
+
vmz locale conformance [project] Cross-host MessageId/hash conformance (I5)
|
|
31
|
+
|
|
32
|
+
Options:
|
|
33
|
+
--root <dir> Project root (default: . or positional)
|
|
34
|
+
--out <dir> emit-types / pseudo output
|
|
35
|
+
--locale <id> explain requested locale
|
|
36
|
+
--delivery <id> explain delivery id
|
|
37
|
+
--strict Require variants or explicit fallback for every MessageId
|
|
38
|
+
--check extract: treat CJK hardcoded as errors
|
|
39
|
+
--production pseudo: fail (pseudo must not ship)
|
|
40
|
+
--json [file] Emit check report JSON
|
|
41
|
+
`);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* @param {string[]} argv
|
|
45
|
+
* @returns {Promise<number>}
|
|
46
|
+
*/
|
|
47
|
+
export async function cmdLocale(argv) {
|
|
48
|
+
const [sub, ...rest] = argv;
|
|
49
|
+
if (!sub || sub === 'help' || sub === '-h' || sub === '--help') {
|
|
50
|
+
printLocaleHelp();
|
|
51
|
+
return 0;
|
|
52
|
+
}
|
|
53
|
+
const args = parseArgs(rest);
|
|
54
|
+
switch (sub) {
|
|
55
|
+
case 'check':
|
|
56
|
+
return cmdLocaleCheck(args);
|
|
57
|
+
case 'list':
|
|
58
|
+
return cmdLocaleList(args);
|
|
59
|
+
case 'emit-types':
|
|
60
|
+
return cmdLocaleEmitTypes(args);
|
|
61
|
+
case 'rename':
|
|
62
|
+
return cmdLocaleRename(args);
|
|
63
|
+
case 'runtime-check':
|
|
64
|
+
return cmdLocaleRuntimeCheck(args);
|
|
65
|
+
case 'router-check':
|
|
66
|
+
return cmdLocaleRouterCheck(args);
|
|
67
|
+
case 'delivery-check':
|
|
68
|
+
return cmdLocaleDeliveryCheck(args);
|
|
69
|
+
case 'explain':
|
|
70
|
+
return cmdLocaleExplain(args);
|
|
71
|
+
case 'diff':
|
|
72
|
+
return cmdLocaleDiff(args);
|
|
73
|
+
case 'extract':
|
|
74
|
+
return cmdLocaleExtract(args);
|
|
75
|
+
case 'pseudo':
|
|
76
|
+
return cmdLocalePseudo(args);
|
|
77
|
+
case 'conformance':
|
|
78
|
+
return cmdLocaleConformance(args);
|
|
79
|
+
default:
|
|
80
|
+
log.error(`unknown locale subcommand \`${sub}\``);
|
|
81
|
+
printLocaleHelp();
|
|
82
|
+
return 1;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function resolveProject(args) {
|
|
86
|
+
const project = (typeof args.root === 'string' && args.root) || (typeof args._[0] === 'string' && args._[0]) || '.';
|
|
87
|
+
return path.resolve(project);
|
|
88
|
+
}
|
|
89
|
+
function cmdLocaleCheck(args) {
|
|
90
|
+
const projectRoot = resolveProject(args);
|
|
91
|
+
const report = checkLocales({ projectRoot, strict: Boolean(args.strict) });
|
|
92
|
+
const jsonOut = args.json;
|
|
93
|
+
if (jsonOut) {
|
|
94
|
+
const text = JSON.stringify(report, null, 2);
|
|
95
|
+
if (typeof jsonOut === 'string') {
|
|
96
|
+
fs.writeFileSync(jsonOut, `${text}\n`, 'utf8');
|
|
97
|
+
log.info(`wrote ${jsonOut}`);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
console.log(text);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
for (const d of report.diagnostics) {
|
|
105
|
+
const loc = d.path ? ` (${d.path})` : '';
|
|
106
|
+
if (d.severity === 'error')
|
|
107
|
+
log.error(`${d.code}: ${d.message}${loc}`);
|
|
108
|
+
else
|
|
109
|
+
console.warn(`vmz warn ${d.code}: ${d.message}${loc}`);
|
|
110
|
+
}
|
|
111
|
+
const n = report.messageCatalog?.messages?.length || 0;
|
|
112
|
+
log.info(`locale check: locales=${(report.manifest?.locales || []).map((l) => l.id).join(',') || '(none)'} messages=${n} status=${report.status}`);
|
|
113
|
+
}
|
|
114
|
+
return localeHasErrors(report) ? 1 : 0;
|
|
115
|
+
}
|
|
116
|
+
function cmdLocaleList(args) {
|
|
117
|
+
const projectRoot = resolveProject(args);
|
|
118
|
+
const report = checkLocales({ projectRoot, checkUnused: false });
|
|
119
|
+
if (!report.manifest) {
|
|
120
|
+
log.error('locales.json5 missing');
|
|
121
|
+
return 1;
|
|
122
|
+
}
|
|
123
|
+
for (const loc of report.manifest.locales) {
|
|
124
|
+
const mark = loc.id === report.manifest.defaultLocale ? ' (default)' : '';
|
|
125
|
+
console.log(`${loc.id}\t${loc.label || ''}${mark}`);
|
|
126
|
+
}
|
|
127
|
+
return localeHasErrors(report) ? 1 : 0;
|
|
128
|
+
}
|
|
129
|
+
function cmdLocaleEmitTypes(args) {
|
|
130
|
+
const projectRoot = resolveProject(args);
|
|
131
|
+
const outDir = (typeof args.out === 'string' && args.out) || path.join(projectRoot, 'dist', 'locales-types');
|
|
132
|
+
const report = checkLocales({ projectRoot, strict: Boolean(args.strict) });
|
|
133
|
+
if (localeHasErrors(report)) {
|
|
134
|
+
for (const d of report.diagnostics.filter((x) => x.severity === 'error')) {
|
|
135
|
+
log.error(`${d.code}: ${d.message}`);
|
|
136
|
+
}
|
|
137
|
+
return 1;
|
|
138
|
+
}
|
|
139
|
+
const written = emitLocaleTypedModules(report, outDir);
|
|
140
|
+
log.info(`locale emit-types: modules=${written.length} out=${path.relative(process.cwd(), outDir) || '.'}`);
|
|
141
|
+
return 0;
|
|
142
|
+
}
|
|
143
|
+
function cmdLocaleRename(args) {
|
|
144
|
+
const fromId = typeof args._[0] === 'string' ? args._[0] : '';
|
|
145
|
+
const toId = typeof args._[1] === 'string' ? args._[1] : '';
|
|
146
|
+
if (!fromId || !toId) {
|
|
147
|
+
log.error('usage: vmz locale rename <from-message-id> <to-message-id>');
|
|
148
|
+
return 1;
|
|
149
|
+
}
|
|
150
|
+
const projectRoot = resolveProject({ ...args, _: args._.slice(2) });
|
|
151
|
+
const report = checkLocales({ projectRoot, checkUnused: false });
|
|
152
|
+
const plan = planLocaleRename(report, fromId, toId);
|
|
153
|
+
if (args.json) {
|
|
154
|
+
console.log(JSON.stringify(plan, null, 2));
|
|
155
|
+
}
|
|
156
|
+
else if (plan.status !== 'ready') {
|
|
157
|
+
log.error(plan.error || 'rename failed');
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
log.info(`rename plan ${fromId} → ${toId} edits=${plan.edits.length}`);
|
|
161
|
+
for (const e of plan.edits)
|
|
162
|
+
console.log(` ${e.path}`);
|
|
163
|
+
}
|
|
164
|
+
return plan.status === 'ready' ? 0 : 1;
|
|
165
|
+
}
|
|
166
|
+
function cmdLocaleRuntimeCheck(args) {
|
|
167
|
+
const projectRoot = resolveProject(args);
|
|
168
|
+
const base = checkLocales({ projectRoot, checkUnused: false });
|
|
169
|
+
if (localeHasErrors(base) || !base.manifest) {
|
|
170
|
+
for (const d of (base.diagnostics || []).filter((x) => x.severity === 'error')) {
|
|
171
|
+
log.error(`${d.code}: ${d.message}`);
|
|
172
|
+
}
|
|
173
|
+
return 1;
|
|
174
|
+
}
|
|
175
|
+
const report = checkLocaleRuntime({
|
|
176
|
+
manifest: base.manifest,
|
|
177
|
+
messages: base.messageCatalog?.messages || [],
|
|
178
|
+
applicationId: 'app.locales-fixture',
|
|
179
|
+
deliveryId: 'delivery.web',
|
|
180
|
+
timeZone: typeof args.timezone === 'string' ? args.timezone : 'Asia/Shanghai',
|
|
181
|
+
});
|
|
182
|
+
const { session: _session, ...jsonReport } = report;
|
|
183
|
+
if (args.json) {
|
|
184
|
+
const text = JSON.stringify(jsonReport, null, 2);
|
|
185
|
+
if (typeof args.json === 'string') {
|
|
186
|
+
fs.writeFileSync(args.json, `${text}\n`, 'utf8');
|
|
187
|
+
log.info(`wrote ${args.json}`);
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
console.log(text);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
for (const d of report.diagnostics) {
|
|
195
|
+
if (d.severity === 'error')
|
|
196
|
+
log.error(`${d.code}: ${d.message}`);
|
|
197
|
+
else
|
|
198
|
+
console.warn(`vmz warn ${d.code}: ${d.message}`);
|
|
199
|
+
}
|
|
200
|
+
log.info(`locale runtime-check: locale=${report.applicationContext?.localeId} digest=${report.formatterDigest} status=${report.status}`);
|
|
201
|
+
}
|
|
202
|
+
return report.status === 'ready' ? 0 : 1;
|
|
203
|
+
}
|
|
204
|
+
function loadRoutesFixture(projectRoot) {
|
|
205
|
+
const candidates = [path.join(projectRoot, 'locale-routes.json5'), path.join(projectRoot, 'locale-routes.json')];
|
|
206
|
+
for (const p of candidates) {
|
|
207
|
+
if (fs.existsSync(p)) {
|
|
208
|
+
return JSON5.parse(fs.readFileSync(p, 'utf8'));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
routes: [{ routeId: 'index', path: '/' }],
|
|
213
|
+
origin: 'https://example.test',
|
|
214
|
+
titles: {},
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function cmdLocaleRouterCheck(args) {
|
|
218
|
+
const projectRoot = resolveProject(args);
|
|
219
|
+
const base = checkLocales({ projectRoot, checkUnused: false });
|
|
220
|
+
if (localeHasErrors(base) || !base.manifest) {
|
|
221
|
+
for (const d of (base.diagnostics || []).filter((x) => x.severity === 'error')) {
|
|
222
|
+
log.error(`${d.code}: ${d.message}`);
|
|
223
|
+
}
|
|
224
|
+
return 1;
|
|
225
|
+
}
|
|
226
|
+
const routesFile = loadRoutesFixture(projectRoot);
|
|
227
|
+
const report = checkLocaleRouter({
|
|
228
|
+
manifest: base.manifest,
|
|
229
|
+
routes: routesFile.routes || [],
|
|
230
|
+
titles: routesFile.titles || {},
|
|
231
|
+
origin: routesFile.origin || 'https://example.test',
|
|
232
|
+
});
|
|
233
|
+
if (args.json) {
|
|
234
|
+
const text = JSON.stringify(report, null, 2);
|
|
235
|
+
if (typeof args.json === 'string') {
|
|
236
|
+
fs.writeFileSync(args.json, `${text}\n`, 'utf8');
|
|
237
|
+
log.info(`wrote ${args.json}`);
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
console.log(text);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
for (const d of report.diagnostics) {
|
|
245
|
+
if (d.severity === 'error')
|
|
246
|
+
log.error(`${d.code}: ${d.message}`);
|
|
247
|
+
else
|
|
248
|
+
console.warn(`vmz warn ${d.code}: ${d.message}`);
|
|
249
|
+
}
|
|
250
|
+
const n = report.realizationTable?.realizations?.length || 0;
|
|
251
|
+
log.info(`locale router-check: realizations=${n} pageMetas=${report.pageMetas?.length || 0} status=${report.status}`);
|
|
252
|
+
}
|
|
253
|
+
return report.status === 'ready' ? 0 : 1;
|
|
254
|
+
}
|
|
255
|
+
function cmdLocaleDeliveryCheck(args) {
|
|
256
|
+
const projectRoot = resolveProject(args);
|
|
257
|
+
const base = checkLocales({ projectRoot, checkUnused: false });
|
|
258
|
+
if (localeHasErrors(base) || !base.manifest) {
|
|
259
|
+
for (const d of (base.diagnostics || []).filter((x) => x.severity === 'error')) {
|
|
260
|
+
log.error(`${d.code}: ${d.message}`);
|
|
261
|
+
}
|
|
262
|
+
return 1;
|
|
263
|
+
}
|
|
264
|
+
const report = checkLocaleDelivery({
|
|
265
|
+
manifest: base.manifest,
|
|
266
|
+
messages: base.messageCatalog?.messages || [],
|
|
267
|
+
applicationId: 'app.locales-fixture',
|
|
268
|
+
planVersion: 'plan.v0',
|
|
269
|
+
});
|
|
270
|
+
if (args.json) {
|
|
271
|
+
const text = JSON.stringify(report, null, 2);
|
|
272
|
+
if (typeof args.json === 'string') {
|
|
273
|
+
fs.writeFileSync(args.json, `${text}\n`, 'utf8');
|
|
274
|
+
log.info(`wrote ${args.json}`);
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
console.log(text);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
for (const d of report.diagnostics) {
|
|
282
|
+
if (d.severity === 'error')
|
|
283
|
+
log.error(`${d.code}: ${d.message}`);
|
|
284
|
+
else
|
|
285
|
+
console.warn(`vmz warn ${d.code}: ${d.message}`);
|
|
286
|
+
}
|
|
287
|
+
const hosts = Object.keys(report.resolutions || {}).join(',');
|
|
288
|
+
log.info(`locale delivery-check: hosts=${hosts} status=${report.status}`);
|
|
289
|
+
}
|
|
290
|
+
return report.status === 'ready' ? 0 : 1;
|
|
291
|
+
}
|
|
292
|
+
function emitJson(args, report) {
|
|
293
|
+
const text = JSON.stringify(report, null, 2);
|
|
294
|
+
if (typeof args.json === 'string') {
|
|
295
|
+
fs.writeFileSync(args.json, `${text}\n`, 'utf8');
|
|
296
|
+
log.info(`wrote ${args.json}`);
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
console.log(text);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
function cmdLocaleExplain(args) {
|
|
303
|
+
const messageId = typeof args._[0] === 'string' ? args._[0] : '';
|
|
304
|
+
if (!messageId) {
|
|
305
|
+
log.error('usage: vmz locale explain <message-id> [project]');
|
|
306
|
+
return 1;
|
|
307
|
+
}
|
|
308
|
+
const projectRoot = resolveProject({ ...args, _: args._.slice(1) });
|
|
309
|
+
const base = checkLocales({ projectRoot, checkUnused: false });
|
|
310
|
+
if (localeHasErrors(base) || !base.manifest) {
|
|
311
|
+
for (const d of (base.diagnostics || []).filter((x) => x.severity === 'error')) {
|
|
312
|
+
log.error(`${d.code}: ${d.message}`);
|
|
313
|
+
}
|
|
314
|
+
return 1;
|
|
315
|
+
}
|
|
316
|
+
const report = explainLocaleMessage({
|
|
317
|
+
messageId,
|
|
318
|
+
locale: typeof args.locale === 'string' ? args.locale : null,
|
|
319
|
+
deliveryId: typeof args.delivery === 'string' ? args.delivery : null,
|
|
320
|
+
checkReport: base,
|
|
321
|
+
});
|
|
322
|
+
if (args.json)
|
|
323
|
+
emitJson(args, report);
|
|
324
|
+
else if (report.status !== 'ready') {
|
|
325
|
+
for (const d of report.diagnostics)
|
|
326
|
+
log.error(`${d.code}: ${d.message}`);
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
log.info(`explain ${report.messageId}: resolved=${report.resolvedLocale} params=${(report.params || []).map((p) => p.name).join(',') || '(none)'}`);
|
|
330
|
+
for (const [loc, v] of Object.entries(report.variants || {})) {
|
|
331
|
+
console.log(` ${loc}\t${v.template}`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return report.status === 'ready' ? 0 : 1;
|
|
335
|
+
}
|
|
336
|
+
function cmdLocaleDiff(args) {
|
|
337
|
+
const baseLocale = typeof args._[0] === 'string' ? args._[0] : '';
|
|
338
|
+
const targetLocale = typeof args._[1] === 'string' ? args._[1] : '';
|
|
339
|
+
if (!baseLocale || !targetLocale) {
|
|
340
|
+
log.error('usage: vmz locale diff <base-locale> <target-locale> [project]');
|
|
341
|
+
return 1;
|
|
342
|
+
}
|
|
343
|
+
const projectRoot = resolveProject({ ...args, _: args._.slice(2) });
|
|
344
|
+
const base = checkLocales({ projectRoot, checkUnused: false });
|
|
345
|
+
if (localeHasErrors(base) || !base.manifest)
|
|
346
|
+
return 1;
|
|
347
|
+
const report = diffLocaleCatalogs({
|
|
348
|
+
baseLocale,
|
|
349
|
+
targetLocale,
|
|
350
|
+
messages: base.messageCatalog?.messages || [],
|
|
351
|
+
});
|
|
352
|
+
if (args.json)
|
|
353
|
+
emitJson(args, report);
|
|
354
|
+
else {
|
|
355
|
+
log.info(`diff ${baseLocale} → ${targetLocale}: missing=${report.summary.missingInTarget} changed=${report.summary.changed} params=${report.summary.paramMismatches}`);
|
|
356
|
+
for (const id of report.missingInTarget || [])
|
|
357
|
+
console.log(` - missing ${id}`);
|
|
358
|
+
for (const c of report.changed || [])
|
|
359
|
+
console.log(` ~ ${c.messageId}`);
|
|
360
|
+
}
|
|
361
|
+
return 0;
|
|
362
|
+
}
|
|
363
|
+
function cmdLocaleExtract(args) {
|
|
364
|
+
const projectRoot = resolveProject(args);
|
|
365
|
+
const report = extractHardcodedText(projectRoot, { check: Boolean(args.check) });
|
|
366
|
+
if (args.json)
|
|
367
|
+
emitJson(args, report);
|
|
368
|
+
else {
|
|
369
|
+
for (const d of report.diagnostics) {
|
|
370
|
+
if (d.severity === 'error')
|
|
371
|
+
log.error(`${d.code}: ${d.message}`);
|
|
372
|
+
else
|
|
373
|
+
console.warn(`vmz warn ${d.code}: ${d.message}`);
|
|
374
|
+
}
|
|
375
|
+
log.info(`locale extract: findings=${report.findings?.length || 0} status=${report.status}`);
|
|
376
|
+
}
|
|
377
|
+
return report.status === 'ready' ? 0 : 1;
|
|
378
|
+
}
|
|
379
|
+
function cmdLocalePseudo(args) {
|
|
380
|
+
const sourceLocale = typeof args._[0] === 'string' ? args._[0] : '';
|
|
381
|
+
if (!sourceLocale) {
|
|
382
|
+
log.error('usage: vmz locale pseudo <source-locale> [project]');
|
|
383
|
+
return 1;
|
|
384
|
+
}
|
|
385
|
+
const projectRoot = resolveProject({ ...args, _: args._.slice(1) });
|
|
386
|
+
const base = checkLocales({ projectRoot, checkUnused: false });
|
|
387
|
+
if (localeHasErrors(base) || !base.manifest)
|
|
388
|
+
return 1;
|
|
389
|
+
const report = pseudoLocalizeCatalog({
|
|
390
|
+
sourceLocale,
|
|
391
|
+
messages: base.messageCatalog?.messages || [],
|
|
392
|
+
production: Boolean(args.production),
|
|
393
|
+
});
|
|
394
|
+
if (args.json)
|
|
395
|
+
emitJson(args, report);
|
|
396
|
+
else if (report.status !== 'ready') {
|
|
397
|
+
for (const d of report.diagnostics)
|
|
398
|
+
log.error(`${d.code}: ${d.message}`);
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
const outDir = (typeof args.out === 'string' && args.out) || path.join(projectRoot, 'dist', 'locales-pseudo');
|
|
402
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
403
|
+
const outFile = path.join(outDir, `${report.pseudoLocale}.json`);
|
|
404
|
+
fs.writeFileSync(outFile, `${JSON.stringify(report.catalog, null, 2)}\n`, 'utf8');
|
|
405
|
+
log.info(`locale pseudo: source=${sourceLocale} keys=${Object.keys(report.catalog).length} out=${outFile}`);
|
|
406
|
+
}
|
|
407
|
+
return report.status === 'ready' ? 0 : 1;
|
|
408
|
+
}
|
|
409
|
+
function cmdLocaleConformance(args) {
|
|
410
|
+
const projectRoot = resolveProject(args);
|
|
411
|
+
const base = checkLocales({ projectRoot, checkUnused: false });
|
|
412
|
+
if (localeHasErrors(base) || !base.manifest)
|
|
413
|
+
return 1;
|
|
414
|
+
let routeIds = [];
|
|
415
|
+
const routesPath = path.join(projectRoot, 'locale-routes.json5');
|
|
416
|
+
if (fs.existsSync(routesPath)) {
|
|
417
|
+
try {
|
|
418
|
+
const routesFile = JSON5.parse(fs.readFileSync(routesPath, 'utf8'));
|
|
419
|
+
routeIds = (routesFile.routes || []).map((r) => r.routeId);
|
|
420
|
+
}
|
|
421
|
+
catch {
|
|
422
|
+
/* ignore */
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
const report = checkLocaleConformance({
|
|
426
|
+
manifest: base.manifest,
|
|
427
|
+
messages: base.messageCatalog?.messages || [],
|
|
428
|
+
routeIds,
|
|
429
|
+
});
|
|
430
|
+
if (args.json)
|
|
431
|
+
emitJson(args, report);
|
|
432
|
+
else {
|
|
433
|
+
for (const d of report.diagnostics) {
|
|
434
|
+
if (d.severity === 'error')
|
|
435
|
+
log.error(`${d.code}: ${d.message}`);
|
|
436
|
+
else
|
|
437
|
+
console.warn(`vmz warn ${d.code}: ${d.message}`);
|
|
438
|
+
}
|
|
439
|
+
log.info(`locale conformance: hosts=${(report.hosts || []).join(',')} messages=${report.messageIds?.length || 0} status=${report.status}`);
|
|
440
|
+
}
|
|
441
|
+
return report.status === 'ready' ? 0 : 1;
|
|
442
|
+
}
|