ai-localize-cli 2.0.1 → 2.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/CHANGELOG.md +43 -0
- package/dist/cli.js +12 -2
- package/package.json +10 -10
- package/src/commands/extract.ts +48 -28
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,48 @@
|
|
|
1
1
|
# ai-localize-cli
|
|
2
2
|
|
|
3
|
+
## 2.0.3
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- **`keyStyle` config option** — `extract` and `full-migrate` commands now respect `keyStyle: "screaming_snake"` in `ai-localize.config.json`; all scanned hardcoded strings are extracted with UPPER_SNAKE_CASE keys matching the text value (e.g. `"Save Changes"` -> key `SAVE_CHANGES`, value `"Save Changes"`) instead of the default hierarchical path-based key style
|
|
8
|
+
- **`staticKeys` config option** — `extract` and `full-migrate` commands now inject `staticKeys` entries from config into every generated locale file regardless of scanning results; useful for enum labels, status codes, and other constant strings not present as literals in source files
|
|
9
|
+
|
|
10
|
+
### Patch Changes
|
|
11
|
+
|
|
12
|
+
- Updated dependencies
|
|
13
|
+
- ai-localize-scanner@2.0.3
|
|
14
|
+
- ai-localize-config@2.0.3
|
|
15
|
+
- ai-localize-shared@2.0.3
|
|
16
|
+
- ai-localize-aws-cloudfront@2.0.3
|
|
17
|
+
- ai-localize-codemods@2.0.3
|
|
18
|
+
- ai-localize-framework-detectors@2.0.3
|
|
19
|
+
- ai-localize-locale-engine@2.0.3
|
|
20
|
+
- ai-localize-reporting@2.0.3
|
|
21
|
+
- ai-localize-validators@2.0.3
|
|
22
|
+
|
|
23
|
+
## 2.0.2
|
|
24
|
+
|
|
25
|
+
### Minor Changes
|
|
26
|
+
|
|
27
|
+
- **Flat locale layout in `extract` and `full-migrate` commands** — `--locale-structure flat` flag (or `localeStructure: "flat"` in config) now writes one `<lang>.json` per language with all namespace keys merged
|
|
28
|
+
- **Rich CLI report output** — `report` command now renders a structured terminal dashboard with coverage bars, top-file charts, missing-translation rankings, AST-context distribution, AI Insights, and actionable recommended next steps
|
|
29
|
+
- **HTML analytics dashboard** — `report --format html` now generates a fully self-contained interactive dashboard (light/dark theme, sortable tables, SVG donut chart, CSV/JSON export, print/PDF)
|
|
30
|
+
|
|
31
|
+
### Patch Changes
|
|
32
|
+
|
|
33
|
+
- **Bug fix — locale key prefix** — resolved an issue where locale keys included ancestor path segments when `sourceRoot` was an absolute path
|
|
34
|
+
- **Bug fix — codemods config wired through** — `codemods` block in `ai-localize.config.json` is now applied by all codemod commands instead of being silently ignored
|
|
35
|
+
- Updated dependencies
|
|
36
|
+
- ai-localize-scanner@2.0.2
|
|
37
|
+
- ai-localize-config@2.0.2
|
|
38
|
+
- ai-localize-shared@2.0.2
|
|
39
|
+
- ai-localize-aws-cloudfront@2.0.2
|
|
40
|
+
- ai-localize-codemods@2.0.2
|
|
41
|
+
- ai-localize-framework-detectors@2.0.2
|
|
42
|
+
- ai-localize-locale-engine@2.0.2
|
|
43
|
+
- ai-localize-reporting@2.0.2
|
|
44
|
+
- ai-localize-validators@2.0.2
|
|
45
|
+
|
|
3
46
|
## 2.0.1
|
|
4
47
|
|
|
5
48
|
### Patch Changes
|
package/dist/cli.js
CHANGED
|
@@ -167,6 +167,13 @@ function extractCommand() {
|
|
|
167
167
|
spinner.succeed("Configuration loaded");
|
|
168
168
|
const structure = config.localeStructure ?? "nested";
|
|
169
169
|
logger.info("Locale structure: " + import_chalk4.default.cyan(structure));
|
|
170
|
+
const staticKeys = config.staticKeys ?? {};
|
|
171
|
+
const staticKeyCount = Object.keys(staticKeys).length;
|
|
172
|
+
if (staticKeyCount > 0) {
|
|
173
|
+
logger.info(
|
|
174
|
+
"Static keys: " + import_chalk4.default.cyan(String(staticKeyCount)) + " (" + Object.keys(staticKeys).join(", ") + ")"
|
|
175
|
+
);
|
|
176
|
+
}
|
|
170
177
|
const ss = createSpinner("Scanning for hardcoded text...").start();
|
|
171
178
|
const scanner = new import_ai_localize_scanner2.ProjectScanner(config);
|
|
172
179
|
const scanResult = await scanner.scan();
|
|
@@ -176,11 +183,14 @@ function extractCommand() {
|
|
|
176
183
|
const extractor = new import_ai_localize_locale_engine.LocaleExtractor({
|
|
177
184
|
defaultLanguage: config.defaultLanguage,
|
|
178
185
|
targetLanguages: config.targetLanguages,
|
|
179
|
-
namespaceSplitting: structure === "nested"
|
|
186
|
+
namespaceSplitting: structure === "nested",
|
|
180
187
|
// flat mode does not need namespace splitting
|
|
188
|
+
staticKeys
|
|
181
189
|
});
|
|
182
190
|
const { localeFiles, keyCount, namespaces } = extractor.extract(uniqueTexts);
|
|
183
|
-
logger.info(
|
|
191
|
+
logger.info(
|
|
192
|
+
"Keys generated: " + import_chalk4.default.green(String(keyCount)) + (staticKeyCount > 0 ? import_chalk4.default.dim(" (+ " + staticKeyCount + " static)") : "")
|
|
193
|
+
);
|
|
184
194
|
if (structure === "nested") {
|
|
185
195
|
logger.info("Namespaces: " + import_chalk4.default.cyan(namespaces.join(", ")));
|
|
186
196
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-localize-cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "CLI for ai-localize-core: scan, extract, validate, migrate CDN",
|
|
5
5
|
"bin": {
|
|
6
6
|
"ai-localize": "./dist/cli.js"
|
|
@@ -11,15 +11,15 @@
|
|
|
11
11
|
"chalk": "^5.3.0",
|
|
12
12
|
"ora": "^8.0.1",
|
|
13
13
|
"inquirer": "^9.2.12",
|
|
14
|
-
"ai-localize-
|
|
15
|
-
"ai-localize-
|
|
16
|
-
"ai-localize-config": "2.0.
|
|
17
|
-
"ai-localize-scanner": "2.0.
|
|
18
|
-
"ai-localize-
|
|
19
|
-
"ai-localize-
|
|
20
|
-
"ai-localize-
|
|
21
|
-
"ai-localize-
|
|
22
|
-
"ai-localize-
|
|
14
|
+
"ai-localize-framework-detectors": "2.0.3",
|
|
15
|
+
"ai-localize-shared": "2.0.3",
|
|
16
|
+
"ai-localize-config": "2.0.3",
|
|
17
|
+
"ai-localize-scanner": "2.0.3",
|
|
18
|
+
"ai-localize-aws-cloudfront": "2.0.3",
|
|
19
|
+
"ai-localize-validators": "2.0.3",
|
|
20
|
+
"ai-localize-locale-engine": "2.0.3",
|
|
21
|
+
"ai-localize-reporting": "2.0.3",
|
|
22
|
+
"ai-localize-codemods": "2.0.3"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/inquirer": "^9.0.7",
|
package/src/commands/extract.ts
CHANGED
|
@@ -17,56 +17,76 @@ export function extractCommand(): Command {
|
|
|
17
17
|
logger.header('ai-localize extract');
|
|
18
18
|
const cwd = opts.cwd as string;
|
|
19
19
|
const spinner = createSpinner('Loading configuration...').start();
|
|
20
|
-
|
|
20
|
+
try {
|
|
21
21
|
const { config } = await loadConfig(cwd);
|
|
22
22
|
spinner.succeed('Configuration loaded');
|
|
23
23
|
|
|
24
24
|
// Log locale structure in use
|
|
25
|
-
|
|
25
|
+
const structure = config.localeStructure ?? 'nested';
|
|
26
26
|
logger.info('Locale structure: ' + chalk.cyan(structure));
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
const
|
|
28
|
+
// Log static keys if configured
|
|
29
|
+
const staticKeys = config.staticKeys ?? {};
|
|
30
|
+
const staticKeyCount = Object.keys(staticKeys).length;
|
|
31
|
+
if (staticKeyCount > 0) {
|
|
32
|
+
logger.info(
|
|
33
|
+
'Static keys: ' +
|
|
34
|
+
chalk.cyan(String(staticKeyCount)) +
|
|
35
|
+
' (' +
|
|
36
|
+
Object.keys(staticKeys).join(', ') +
|
|
37
|
+
')'
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const ss = createSpinner('Scanning for hardcoded text...').start();
|
|
42
|
+
const scanner = new ProjectScanner(config);
|
|
30
43
|
const scanResult = await scanner.scan();
|
|
31
|
-
|
|
44
|
+
ss.succeed('Found ' + chalk.cyan(String(scanResult.detectedTexts.length)) + ' texts in ' + scanResult.scannedFiles + ' files');
|
|
32
45
|
|
|
33
|
-
|
|
34
|
-
|
|
46
|
+
const uniqueTexts = deduplicateTexts(scanResult.detectedTexts);
|
|
47
|
+
logger.info('Unique texts: ' + chalk.cyan(String(uniqueTexts.length)));
|
|
35
48
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
const extractor = new LocaleExtractor({
|
|
50
|
+
defaultLanguage: config.defaultLanguage,
|
|
51
|
+
targetLanguages: config.targetLanguages,
|
|
52
|
+
namespaceSplitting: structure === 'nested', // flat mode does not need namespace splitting
|
|
53
|
+
staticKeys,
|
|
54
|
+
});
|
|
41
55
|
const { localeFiles, keyCount, namespaces } = extractor.extract(uniqueTexts);
|
|
42
|
-
logger.info(
|
|
43
|
-
|
|
44
|
-
|
|
56
|
+
logger.info(
|
|
57
|
+
'Keys generated: ' +
|
|
58
|
+
chalk.green(String(keyCount)) +
|
|
59
|
+
(staticKeyCount > 0
|
|
60
|
+
? chalk.dim(' (+ ' + staticKeyCount + ' static)')
|
|
61
|
+
: '')
|
|
62
|
+
);
|
|
63
|
+
if (structure === 'nested') {
|
|
64
|
+
logger.info('Namespaces: ' + chalk.cyan(namespaces.join(', ')));
|
|
45
65
|
}
|
|
46
66
|
|
|
47
|
-
|
|
67
|
+
if (!opts.dryRun) {
|
|
48
68
|
const localesDir = path.resolve(cwd, config.localesDir);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
69
|
+
const writer = new LocaleWriter({
|
|
70
|
+
localesDir,
|
|
71
|
+
merge: opts.merge !== false,
|
|
72
|
+
localeStructure: structure,
|
|
53
73
|
});
|
|
54
|
-
|
|
74
|
+
const { written, created, merged } = writer.write(localeFiles);
|
|
55
75
|
logger.success(
|
|
56
|
-
|
|
57
|
-
|
|
76
|
+
'Wrote ' + written.length + ' locale files (' + created.length + ' new, ' + merged.length + ' merged)'
|
|
77
|
+
);
|
|
58
78
|
written.forEach((f) => logger.info(' ' + chalk.gray(f)));
|
|
59
79
|
} else {
|
|
60
80
|
logger.info('Dry run — no files written');
|
|
61
81
|
localeFiles.forEach((lf) => {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
82
|
+
const label = structure === 'flat'
|
|
83
|
+
? `${lf.language}.json`
|
|
84
|
+
: `${lf.language}/${lf.namespace}.json`;
|
|
85
|
+
logger.info(' ' + chalk.gray(label) + ' — ' + Object.keys(lf.entries).length + ' keys');
|
|
66
86
|
});
|
|
67
87
|
}
|
|
68
88
|
} catch (err) {
|
|
69
|
-
|
|
89
|
+
spinner.fail('Extraction failed');
|
|
70
90
|
logger.error(String(err));
|
|
71
91
|
process.exit(1);
|
|
72
92
|
}
|