gtx-cli 2.6.12 → 2.6.13
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 +9 -0
- package/dist/api/downloadFileBatch.js +3 -0
- package/dist/cli/base.js +4 -0
- package/dist/console/displayTranslateSummary.d.ts +1 -0
- package/dist/console/displayTranslateSummary.js +42 -0
- package/dist/formats/files/translate.js +7 -0
- package/dist/generated/version.d.ts +1 -1
- package/dist/generated/version.js +1 -1
- package/dist/state/translateWarnings.d.ts +10 -0
- package/dist/state/translateWarnings.js +13 -0
- package/dist/workflow/DownloadStep.js +4 -0
- package/dist/workflow/UploadSourcesStep.js +7 -0
- package/dist/workflow/download.js +4 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# gtx-cli
|
|
2
2
|
|
|
3
|
+
## 2.6.13
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#995](https://github.com/generaltranslation/gt/pull/995) [`b33e1fd`](https://github.com/generaltranslation/gt/commit/b33e1fd3073b23c2cc5db900619fb4c8d4a64c1f) Thanks [@fernando-aviles](https://github.com/fernando-aviles)! - Improve warning display for CLI
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`4a66903`](https://github.com/generaltranslation/gt/commit/4a669031f74a0b20783709752ab7fc0ab40869df)]:
|
|
10
|
+
- generaltranslation@8.1.9
|
|
11
|
+
|
|
3
12
|
## 2.6.12
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
|
@@ -8,6 +8,7 @@ import { mergeJson } from '../formats/json/mergeJson.js';
|
|
|
8
8
|
import mergeYaml from '../formats/yaml/mergeYaml.js';
|
|
9
9
|
import { getDownloadedVersions, saveDownloadedVersions, ensureNestedObject, } from '../fs/config/downloadedVersions.js';
|
|
10
10
|
import { recordDownloaded } from '../state/recentDownloads.js';
|
|
11
|
+
import { recordWarning } from '../state/translateWarnings.js';
|
|
11
12
|
import stringify from 'fast-json-stable-stringify';
|
|
12
13
|
/**
|
|
13
14
|
* Downloads multiple translation files in a single batch request
|
|
@@ -56,6 +57,7 @@ export async function downloadFileBatch(fileTracker, files, options, forceDownlo
|
|
|
56
57
|
const fileProperties = fileTracker.completed.get(fileKey);
|
|
57
58
|
if (!outputPath || !fileProperties) {
|
|
58
59
|
logger.warn(`No input/output path found for file: ${fileKey}`);
|
|
60
|
+
recordWarning('failed_download', fileKey, 'No input/output path found');
|
|
59
61
|
result.failed.push(requestedFile);
|
|
60
62
|
continue;
|
|
61
63
|
}
|
|
@@ -139,6 +141,7 @@ export async function downloadFileBatch(fileTracker, files, options, forceDownlo
|
|
|
139
141
|
}
|
|
140
142
|
catch (error) {
|
|
141
143
|
logger.error(`Error saving file ${fileKey}: ` + error);
|
|
144
|
+
recordWarning('failed_download', fileKey, `Error saving file: ${error}`);
|
|
142
145
|
result.failed.push(requestedFile);
|
|
143
146
|
}
|
|
144
147
|
}
|
package/dist/cli/base.js
CHANGED
|
@@ -20,6 +20,8 @@ import { handleStage } from './commands/stage.js';
|
|
|
20
20
|
import { handleSetupProject } from './commands/setupProject.js';
|
|
21
21
|
import { handleDownload, handleTranslate, postProcessTranslations, } from './commands/translate.js';
|
|
22
22
|
import { getDownloaded, clearDownloaded } from '../state/recentDownloads.js';
|
|
23
|
+
import { clearWarnings } from '../state/translateWarnings.js';
|
|
24
|
+
import { displayTranslateSummary } from '../console/displayTranslateSummary.js';
|
|
23
25
|
import updateConfig from '../fs/config/updateConfig.js';
|
|
24
26
|
import { createLoadTranslationsFile } from '../fs/createLoadTranslationsFile.js';
|
|
25
27
|
import { saveLocalEdits } from '../api/saveLocalEdits.js';
|
|
@@ -130,6 +132,8 @@ export class BaseCLI {
|
|
|
130
132
|
await postProcessTranslations(settings, include);
|
|
131
133
|
}
|
|
132
134
|
clearDownloaded();
|
|
135
|
+
displayTranslateSummary();
|
|
136
|
+
clearWarnings();
|
|
133
137
|
}
|
|
134
138
|
setupUploadCommand() {
|
|
135
139
|
attachTranslateFlags(this.program
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function displayTranslateSummary(): void;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { logger } from './logger.js';
|
|
3
|
+
import { getWarnings, hasWarnings, } from '../state/translateWarnings.js';
|
|
4
|
+
const CATEGORY_LABELS = {
|
|
5
|
+
skipped_file: 'Files skipped',
|
|
6
|
+
failed_move: 'File moves failed',
|
|
7
|
+
failed_translation: 'Translations failed',
|
|
8
|
+
failed_download: 'Downloads failed',
|
|
9
|
+
};
|
|
10
|
+
const CATEGORY_ORDER = [
|
|
11
|
+
'skipped_file',
|
|
12
|
+
'failed_move',
|
|
13
|
+
'failed_translation',
|
|
14
|
+
'failed_download',
|
|
15
|
+
];
|
|
16
|
+
export function displayTranslateSummary() {
|
|
17
|
+
if (!hasWarnings())
|
|
18
|
+
return;
|
|
19
|
+
const warnings = getWarnings();
|
|
20
|
+
// Group by category
|
|
21
|
+
const grouped = new Map();
|
|
22
|
+
for (const w of warnings) {
|
|
23
|
+
let list = grouped.get(w.category);
|
|
24
|
+
if (!list) {
|
|
25
|
+
list = [];
|
|
26
|
+
grouped.set(w.category, list);
|
|
27
|
+
}
|
|
28
|
+
list.push({ fileName: w.fileName, reason: w.reason });
|
|
29
|
+
}
|
|
30
|
+
const lines = [chalk.yellow('⚠ Warnings:'), ''];
|
|
31
|
+
for (const category of CATEGORY_ORDER) {
|
|
32
|
+
const items = grouped.get(category);
|
|
33
|
+
if (!items)
|
|
34
|
+
continue;
|
|
35
|
+
lines.push(` ${CATEGORY_LABELS[category]} (${items.length}):`);
|
|
36
|
+
for (const item of items) {
|
|
37
|
+
lines.push(` - ${item.fileName}: ${item.reason}`);
|
|
38
|
+
}
|
|
39
|
+
lines.push('');
|
|
40
|
+
}
|
|
41
|
+
logger.warn(lines.join('\n'));
|
|
42
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { logger } from '../../console/logger.js';
|
|
2
|
+
import { recordWarning } from '../../state/translateWarnings.js';
|
|
2
3
|
import { getRelative, readFile } from '../../fs/findFilepath.js';
|
|
3
4
|
import { SUPPORTED_FILE_EXTENSIONS } from './supportedFiles.js';
|
|
4
5
|
import sanitizeFileContent from '../../utils/sanitizeFileContent.js';
|
|
@@ -50,6 +51,7 @@ export async function aggregateFiles(settings) {
|
|
|
50
51
|
}
|
|
51
52
|
catch (e) {
|
|
52
53
|
logger.warn(`Skipping ${relativePath}: JSON file is not parsable`);
|
|
54
|
+
recordWarning('skipped_file', relativePath, 'JSON file is not parsable');
|
|
53
55
|
return null;
|
|
54
56
|
}
|
|
55
57
|
}
|
|
@@ -69,6 +71,7 @@ export async function aggregateFiles(settings) {
|
|
|
69
71
|
return false;
|
|
70
72
|
if (typeof file.content !== 'string' || !file.content.trim()) {
|
|
71
73
|
logger.warn(`Skipping ${file.fileName}: JSON file is empty`);
|
|
74
|
+
recordWarning('skipped_file', file.fileName, 'JSON file is empty');
|
|
72
75
|
return false;
|
|
73
76
|
}
|
|
74
77
|
return true;
|
|
@@ -88,6 +91,7 @@ export async function aggregateFiles(settings) {
|
|
|
88
91
|
}
|
|
89
92
|
catch (e) {
|
|
90
93
|
logger.warn(`Skipping ${relativePath}: YAML file is not parsable`);
|
|
94
|
+
recordWarning('skipped_file', relativePath, 'YAML file is not parsable');
|
|
91
95
|
return null;
|
|
92
96
|
}
|
|
93
97
|
}
|
|
@@ -104,6 +108,7 @@ export async function aggregateFiles(settings) {
|
|
|
104
108
|
.filter((file) => {
|
|
105
109
|
if (!file || typeof file.content !== 'string' || !file.content.trim()) {
|
|
106
110
|
logger.warn(`Skipping ${file?.fileName ?? 'unknown'}: YAML file is empty`);
|
|
111
|
+
recordWarning('skipped_file', file?.fileName ?? 'unknown', 'YAML file is empty');
|
|
107
112
|
return false;
|
|
108
113
|
}
|
|
109
114
|
return true;
|
|
@@ -123,6 +128,7 @@ export async function aggregateFiles(settings) {
|
|
|
123
128
|
const validation = isValidMdx(content, filePath);
|
|
124
129
|
if (!validation.isValid) {
|
|
125
130
|
logger.warn(`Skipping ${relativePath}: MDX file is not AST parsable${validation.error ? `: ${validation.error}` : ''}`);
|
|
131
|
+
recordWarning('skipped_file', relativePath, `MDX file is not AST parsable${validation.error ? `: ${validation.error}` : ''}`);
|
|
126
132
|
return null;
|
|
127
133
|
}
|
|
128
134
|
}
|
|
@@ -152,6 +158,7 @@ export async function aggregateFiles(settings) {
|
|
|
152
158
|
typeof file.content !== 'string' ||
|
|
153
159
|
!file.content.trim()) {
|
|
154
160
|
logger.warn(`Skipping ${file?.fileName ?? 'unknown'}: File is empty after sanitization`);
|
|
161
|
+
recordWarning('skipped_file', file?.fileName ?? 'unknown', 'File is empty after sanitization');
|
|
155
162
|
return false;
|
|
156
163
|
}
|
|
157
164
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PACKAGE_VERSION = "2.6.
|
|
1
|
+
export declare const PACKAGE_VERSION = "2.6.13";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// This file is auto-generated. Do not edit manually.
|
|
2
|
-
export const PACKAGE_VERSION = '2.6.
|
|
2
|
+
export const PACKAGE_VERSION = '2.6.13';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type WarningCategory = 'skipped_file' | 'failed_move' | 'failed_translation' | 'failed_download';
|
|
2
|
+
export type TranslateWarning = {
|
|
3
|
+
category: WarningCategory;
|
|
4
|
+
fileName: string;
|
|
5
|
+
reason: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function recordWarning(category: WarningCategory, fileName: string, reason: string): void;
|
|
8
|
+
export declare function getWarnings(): TranslateWarning[];
|
|
9
|
+
export declare function hasWarnings(): boolean;
|
|
10
|
+
export declare function clearWarnings(): void;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const warnings = [];
|
|
2
|
+
export function recordWarning(category, fileName, reason) {
|
|
3
|
+
warnings.push({ category, fileName, reason });
|
|
4
|
+
}
|
|
5
|
+
export function getWarnings() {
|
|
6
|
+
return warnings;
|
|
7
|
+
}
|
|
8
|
+
export function hasWarnings() {
|
|
9
|
+
return warnings.length > 0;
|
|
10
|
+
}
|
|
11
|
+
export function clearWarnings() {
|
|
12
|
+
warnings.length = 0;
|
|
13
|
+
}
|
|
@@ -2,6 +2,7 @@ import chalk from 'chalk';
|
|
|
2
2
|
import { WorkflowStep } from './Workflow.js';
|
|
3
3
|
import { logger } from '../console/logger.js';
|
|
4
4
|
import { downloadFileBatch, } from '../api/downloadFileBatch.js';
|
|
5
|
+
import { recordWarning } from '../state/translateWarnings.js';
|
|
5
6
|
export class DownloadTranslationsStep extends WorkflowStep {
|
|
6
7
|
gt;
|
|
7
8
|
settings;
|
|
@@ -74,6 +75,9 @@ export class DownloadTranslationsStep extends WorkflowStep {
|
|
|
74
75
|
this.spinner?.stop(chalk.green(`Downloaded ${batchResult.successful.length} files${batchResult.skipped.length > 0 ? `, skipped ${batchResult.skipped.length} files` : ''}`));
|
|
75
76
|
if (batchResult.failed.length > 0) {
|
|
76
77
|
logger.warn(`Failed to download ${batchResult.failed.length} files: ${batchResult.failed.map((f) => f.inputPath).join('\n')}`);
|
|
78
|
+
for (const f of batchResult.failed) {
|
|
79
|
+
recordWarning('failed_download', f.inputPath, `Failed to download for locale ${f.locale}`);
|
|
80
|
+
}
|
|
77
81
|
}
|
|
78
82
|
}
|
|
79
83
|
else {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { WorkflowStep } from './Workflow.js';
|
|
2
2
|
import { logger } from '../console/logger.js';
|
|
3
|
+
import { recordWarning } from '../state/translateWarnings.js';
|
|
3
4
|
import chalk from 'chalk';
|
|
4
5
|
export class UploadSourcesStep extends WorkflowStep {
|
|
5
6
|
gt;
|
|
@@ -72,6 +73,12 @@ export class UploadSourcesStep extends WorkflowStep {
|
|
|
72
73
|
const failed = moveResult.summary.failed;
|
|
73
74
|
if (failed > 0) {
|
|
74
75
|
logger.warn(`Failed to migrate ${failed} moved file${failed !== 1 ? 's' : ''}`);
|
|
76
|
+
for (const r of moveResult.results) {
|
|
77
|
+
if (!r.success) {
|
|
78
|
+
const move = moves.find((m) => m.newFileId === r.newFileId);
|
|
79
|
+
recordWarning('failed_move', move?.newFileName ?? r.newFileId, r.error ?? 'Unknown error');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
75
82
|
}
|
|
76
83
|
}
|
|
77
84
|
// Build a map of branch:fileId:versionId to fileData
|
|
@@ -5,6 +5,7 @@ import { PollTranslationJobsStep } from './PollJobsStep.js';
|
|
|
5
5
|
import { DownloadTranslationsStep } from './DownloadStep.js';
|
|
6
6
|
import { logErrorAndExit } from '../console/logging.js';
|
|
7
7
|
import { logger } from '../console/logger.js';
|
|
8
|
+
import { recordWarning } from '../state/translateWarnings.js';
|
|
8
9
|
import { BranchStep } from './BranchStep.js';
|
|
9
10
|
import chalk from 'chalk';
|
|
10
11
|
/**
|
|
@@ -70,6 +71,9 @@ export async function downloadTranslations(fileVersionData, jobData, branchData,
|
|
|
70
71
|
logger.error(`${chalk.red(`${pollResult.fileTracker.failed.size} file(s) failed to translate:`)}\n${Array.from(pollResult.fileTracker.failed.entries())
|
|
71
72
|
.map(([key, value]) => `- ${value.fileName}`)
|
|
72
73
|
.join('\n')}`);
|
|
74
|
+
for (const [, value] of pollResult.fileTracker.failed) {
|
|
75
|
+
recordWarning('failed_translation', value.fileName, `Failed to translate for locale ${value.locale}`);
|
|
76
|
+
}
|
|
73
77
|
}
|
|
74
78
|
if (!pollResult.success) {
|
|
75
79
|
return false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gtx-cli",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.13",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"bin": "dist/main.js",
|
|
6
6
|
"files": [
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
"unified": "^11.0.5",
|
|
111
111
|
"unist-util-visit": "^5.0.0",
|
|
112
112
|
"yaml": "^2.8.0",
|
|
113
|
-
"generaltranslation": "8.1.
|
|
113
|
+
"generaltranslation": "8.1.9"
|
|
114
114
|
},
|
|
115
115
|
"devDependencies": {
|
|
116
116
|
"@babel/types": "^7.28.4",
|