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 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.12";
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.12';
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.12",
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.8"
113
+ "generaltranslation": "8.1.9"
114
114
  },
115
115
  "devDependencies": {
116
116
  "@babel/types": "^7.28.4",