gtx-cli 2.5.36 → 2.5.37
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 +11 -0
- package/dist/cli/base.js +2 -7
- package/dist/formats/files/collectFiles.js +1 -0
- package/dist/formats/files/translate.js +3 -0
- package/dist/formats/files/upload.js +13 -2
- package/dist/formats/json/mergeJson.js +26 -7
- package/dist/generated/version.d.ts +1 -1
- package/dist/generated/version.js +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/workflow/{UploadStep.d.ts → UploadSourcesStep.d.ts} +1 -1
- package/dist/workflow/{UploadStep.js → UploadSourcesStep.js} +2 -1
- package/dist/workflow/UploadTranslationsStep.d.ts +22 -0
- package/dist/workflow/UploadTranslationsStep.js +71 -0
- package/dist/workflow/setupProject.js +2 -2
- package/dist/workflow/stage.js +2 -2
- package/dist/workflow/upload.d.ts +12 -0
- package/dist/workflow/upload.js +47 -0
- package/package.json +2 -2
- package/dist/api/uploadFiles.d.ts +0 -27
- package/dist/api/uploadFiles.js +0 -41
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# gtx-cli
|
|
2
2
|
|
|
3
|
+
## 2.5.37
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#911](https://github.com/generaltranslation/gt/pull/911) [`6af64c0`](https://github.com/generaltranslation/gt/commit/6af64c04fa6e3d6332a206d9b68fa1a46de1c002) Thanks [@fernando-aviles](https://github.com/fernando-aviles)! - Adding `experimentalCanonicalLocaleKeys` option to `gt.config.json`. It overrides alias configurations when setting keys in a JSON schema
|
|
8
|
+
|
|
9
|
+
- [#908](https://github.com/generaltranslation/gt/pull/908) [`1e7e52f`](https://github.com/generaltranslation/gt/commit/1e7e52f3a77835887ff187ffeb99d6e3dc2a9e6c) Thanks [@brian-lou](https://github.com/brian-lou)! - Fix timeout logic; Refactor upload command
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [[`1e7e52f`](https://github.com/generaltranslation/gt/commit/1e7e52f3a77835887ff187ffeb99d6e3dc2a9e6c)]:
|
|
12
|
+
- generaltranslation@8.1.5
|
|
13
|
+
|
|
3
14
|
## 2.5.36
|
|
4
15
|
|
|
5
16
|
### Patch Changes
|
package/dist/cli/base.js
CHANGED
|
@@ -130,14 +130,9 @@ export class BaseCLI {
|
|
|
130
130
|
clearDownloaded();
|
|
131
131
|
}
|
|
132
132
|
setupUploadCommand() {
|
|
133
|
-
this.program
|
|
133
|
+
attachTranslateFlags(this.program
|
|
134
134
|
.command('upload')
|
|
135
|
-
.description('Upload source files and translations to the General Translation platform')
|
|
136
|
-
.option('-c, --config <path>', 'Filepath to config file, by default gt.config.json', findFilepath(['gt.config.json']))
|
|
137
|
-
.option('--api-key <key>', 'API key for General Translation cloud service')
|
|
138
|
-
.option('--project-id <id>', 'Project ID for the translation service')
|
|
139
|
-
.option('--default-language, --default-locale <locale>', 'Default locale (e.g., en)')
|
|
140
|
-
.action(async (initOptions) => {
|
|
135
|
+
.description('Upload source files and translations to the General Translation platform')).action(async (initOptions) => {
|
|
141
136
|
displayHeader('Starting upload...');
|
|
142
137
|
const settings = await generateSettings(initOptions);
|
|
143
138
|
const options = { ...initOptions, ...settings };
|
|
@@ -40,6 +40,7 @@ export async function collectFiles(options, settings, library) {
|
|
|
40
40
|
formatMetadata: fileMetadata,
|
|
41
41
|
fileId: TEMPLATE_FILE_ID,
|
|
42
42
|
versionId: hashStringSync(JSON.stringify({ data: fileData, metadata: fileMetadata })),
|
|
43
|
+
locale: settings.defaultLocale,
|
|
43
44
|
});
|
|
44
45
|
}
|
|
45
46
|
}
|
|
@@ -57,6 +57,7 @@ export async function aggregateFiles(settings) {
|
|
|
57
57
|
fileName: relativePath,
|
|
58
58
|
fileFormat: 'JSON',
|
|
59
59
|
dataFormat,
|
|
60
|
+
locale: settings.defaultLocale,
|
|
60
61
|
};
|
|
61
62
|
})
|
|
62
63
|
.filter((file) => {
|
|
@@ -91,6 +92,7 @@ export async function aggregateFiles(settings) {
|
|
|
91
92
|
fileFormat,
|
|
92
93
|
fileId: hashStringSync(relativePath),
|
|
93
94
|
versionId: hashStringSync(parsedYaml),
|
|
95
|
+
locale: settings.defaultLocale,
|
|
94
96
|
};
|
|
95
97
|
})
|
|
96
98
|
.filter((file) => {
|
|
@@ -124,6 +126,7 @@ export async function aggregateFiles(settings) {
|
|
|
124
126
|
fileFormat: fileType.toUpperCase(),
|
|
125
127
|
fileId: hashStringSync(relativePath),
|
|
126
128
|
versionId: hashStringSync(content),
|
|
129
|
+
locale: settings.defaultLocale,
|
|
127
130
|
};
|
|
128
131
|
})
|
|
129
132
|
.filter((file) => {
|
|
@@ -5,10 +5,11 @@ import { getRelative, readFile } from '../../fs/findFilepath.js';
|
|
|
5
5
|
import { SUPPORTED_FILE_EXTENSIONS } from './supportedFiles.js';
|
|
6
6
|
import sanitizeFileContent from '../../utils/sanitizeFileContent.js';
|
|
7
7
|
import { parseJson } from '../json/parseJson.js';
|
|
8
|
-
import { uploadFiles } from '../../
|
|
8
|
+
import { uploadFiles } from '../../workflow/upload.js';
|
|
9
9
|
import { existsSync, readFileSync } from 'node:fs';
|
|
10
10
|
import { createFileMapping } from './fileMapping.js';
|
|
11
11
|
import parseYaml from '../yaml/parseYaml.js';
|
|
12
|
+
import { hashStringSync } from '../../utils/hash.js';
|
|
12
13
|
const SUPPORTED_DATA_FORMATS = ['JSX', 'ICU', 'I18NEXT'];
|
|
13
14
|
/**
|
|
14
15
|
* Sends multiple files to the API for translation
|
|
@@ -38,6 +39,8 @@ export async function upload(filePaths, placeholderPaths, transformPaths, dataFo
|
|
|
38
39
|
fileFormat: 'JSON',
|
|
39
40
|
dataFormat,
|
|
40
41
|
locale: options.defaultLocale,
|
|
42
|
+
fileId: hashStringSync(relativePath),
|
|
43
|
+
versionId: hashStringSync(parsedJson),
|
|
41
44
|
};
|
|
42
45
|
});
|
|
43
46
|
allFiles.push(...jsonFiles);
|
|
@@ -57,6 +60,8 @@ export async function upload(filePaths, placeholderPaths, transformPaths, dataFo
|
|
|
57
60
|
fileFormat,
|
|
58
61
|
dataFormat,
|
|
59
62
|
locale: options.defaultLocale,
|
|
63
|
+
fileId: hashStringSync(relativePath),
|
|
64
|
+
versionId: hashStringSync(parsedYaml),
|
|
60
65
|
};
|
|
61
66
|
});
|
|
62
67
|
allFiles.push(...yamlFiles);
|
|
@@ -75,6 +80,8 @@ export async function upload(filePaths, placeholderPaths, transformPaths, dataFo
|
|
|
75
80
|
fileFormat: fileType.toUpperCase(),
|
|
76
81
|
dataFormat,
|
|
77
82
|
locale: options.defaultLocale,
|
|
83
|
+
fileId: hashStringSync(relativePath),
|
|
84
|
+
versionId: hashStringSync(sanitizedContent),
|
|
78
85
|
};
|
|
79
86
|
});
|
|
80
87
|
allFiles.push(...files);
|
|
@@ -107,6 +114,8 @@ export async function upload(filePaths, placeholderPaths, transformPaths, dataFo
|
|
|
107
114
|
fileFormat: file.fileFormat,
|
|
108
115
|
dataFormat: file.dataFormat,
|
|
109
116
|
locale: file.locale,
|
|
117
|
+
fileId: file.fileId,
|
|
118
|
+
versionId: file.versionId,
|
|
110
119
|
};
|
|
111
120
|
const translations = [];
|
|
112
121
|
for (const locale of locales) {
|
|
@@ -115,10 +124,12 @@ export async function upload(filePaths, placeholderPaths, transformPaths, dataFo
|
|
|
115
124
|
const translatedContent = readFileSync(translatedFileName, 'utf8');
|
|
116
125
|
translations.push({
|
|
117
126
|
content: translatedContent,
|
|
118
|
-
fileName:
|
|
127
|
+
fileName: file.fileName,
|
|
119
128
|
fileFormat: file.fileFormat,
|
|
120
129
|
dataFormat: file.dataFormat,
|
|
121
130
|
locale,
|
|
131
|
+
fileId: file.fileId,
|
|
132
|
+
versionId: file.versionId,
|
|
122
133
|
});
|
|
123
134
|
}
|
|
124
135
|
}
|
|
@@ -5,6 +5,7 @@ import { findMatchingItemArray, findMatchingItemObject, generateSourceObjectPoin
|
|
|
5
5
|
import { JSONPath } from 'jsonpath-plus';
|
|
6
6
|
import { getLocaleProperties } from 'generaltranslation';
|
|
7
7
|
import { replaceLocalePlaceholders } from '../utils.js';
|
|
8
|
+
import { gt } from '../../utils/gt.js';
|
|
8
9
|
export function mergeJson(originalContent, inputPath, options, targets, defaultLocale, localeOrder = []) {
|
|
9
10
|
const jsonSchema = validateJsonSchema(options, inputPath);
|
|
10
11
|
if (!jsonSchema) {
|
|
@@ -18,6 +19,13 @@ export function mergeJson(originalContent, inputPath, options, targets, defaultL
|
|
|
18
19
|
logger.error(`Invalid JSON file: ${inputPath}`);
|
|
19
20
|
return exitSync(1);
|
|
20
21
|
}
|
|
22
|
+
const useCanonicalLocaleKeys = options?.experimentalCanonicalLocaleKeys ?? false;
|
|
23
|
+
const canonicalDefaultLocale = useCanonicalLocaleKeys
|
|
24
|
+
? gt.resolveCanonicalLocale(defaultLocale)
|
|
25
|
+
: defaultLocale;
|
|
26
|
+
const canonicalLocaleOrder = useCanonicalLocaleKeys
|
|
27
|
+
? localeOrder.map((locale) => gt.resolveCanonicalLocale(locale))
|
|
28
|
+
: localeOrder;
|
|
21
29
|
// Handle include
|
|
22
30
|
if (jsonSchema.include) {
|
|
23
31
|
const output = [];
|
|
@@ -59,7 +67,7 @@ export function mergeJson(originalContent, inputPath, options, targets, defaultL
|
|
|
59
67
|
return exitSync(1);
|
|
60
68
|
}
|
|
61
69
|
// Get source item for default locale
|
|
62
|
-
const matchingDefaultLocaleItems = findMatchingItemArray(
|
|
70
|
+
const matchingDefaultLocaleItems = findMatchingItemArray(canonicalDefaultLocale, sourceObjectOptions, sourceObjectPointer, sourceObjectValue);
|
|
63
71
|
if (!Object.keys(matchingDefaultLocaleItems).length) {
|
|
64
72
|
logger.warn(`Matching sourceItems not found at path: ${sourceObjectPointer}. Please check your JSON file includes the key field. Skipping this target`);
|
|
65
73
|
continue;
|
|
@@ -88,7 +96,9 @@ export function mergeJson(originalContent, inputPath, options, targets, defaultL
|
|
|
88
96
|
targetItems = {};
|
|
89
97
|
}
|
|
90
98
|
// 2. Track all array indecies to remove (will be overwritten)
|
|
91
|
-
const targetItemsToRemove = findMatchingItemArray(
|
|
99
|
+
const targetItemsToRemove = findMatchingItemArray(useCanonicalLocaleKeys
|
|
100
|
+
? gt.resolveCanonicalLocale(target.targetLocale)
|
|
101
|
+
: target.targetLocale, sourceObjectOptions, sourceObjectPointer, sourceObjectValue);
|
|
92
102
|
Object.values(targetItemsToRemove).forEach(({ index }) => indiciesToRemove.add(index));
|
|
93
103
|
// 3. Merge matchingDefaultLocaleItems and targetItems
|
|
94
104
|
const mergedItems = {
|
|
@@ -110,14 +120,21 @@ export function mergeJson(originalContent, inputPath, options, targets, defaultL
|
|
|
110
120
|
const defaultLocaleSourceItem = matchingDefaultLocaleItems[sourceItemPointer].sourceItem;
|
|
111
121
|
const defaultLocaleKeyPointer = matchingDefaultLocaleItems[sourceItemPointer].keyPointer;
|
|
112
122
|
const mutatedSourceItem = structuredClone(defaultLocaleSourceItem);
|
|
113
|
-
const { identifyingLocaleProperty: targetLocaleKeyProperty } = getSourceObjectOptionsArray(
|
|
123
|
+
const { identifyingLocaleProperty: targetLocaleKeyProperty } = getSourceObjectOptionsArray(useCanonicalLocaleKeys
|
|
124
|
+
? gt.resolveCanonicalLocale(target.targetLocale)
|
|
125
|
+
: target.targetLocale, sourceObjectPointer, sourceObjectOptions);
|
|
114
126
|
JSONPointer.set(mutatedSourceItem, defaultLocaleKeyPointer, targetLocaleKeyProperty);
|
|
115
127
|
for (const [translatedKeyJsonPointer, translatedValue,] of Object.entries(targetItem || {})) {
|
|
128
|
+
const valueToSet = useCanonicalLocaleKeys &&
|
|
129
|
+
defaultLocaleKeyPointer &&
|
|
130
|
+
translatedKeyJsonPointer === defaultLocaleKeyPointer
|
|
131
|
+
? targetLocaleKeyProperty
|
|
132
|
+
: translatedValue;
|
|
116
133
|
try {
|
|
117
134
|
const value = JSONPointer.get(mutatedSourceItem, translatedKeyJsonPointer);
|
|
118
135
|
if (!value)
|
|
119
136
|
continue;
|
|
120
|
-
JSONPointer.set(mutatedSourceItem, translatedKeyJsonPointer,
|
|
137
|
+
JSONPointer.set(mutatedSourceItem, translatedKeyJsonPointer, valueToSet);
|
|
121
138
|
}
|
|
122
139
|
catch {
|
|
123
140
|
/* empty */
|
|
@@ -137,7 +154,7 @@ export function mergeJson(originalContent, inputPath, options, targets, defaultL
|
|
|
137
154
|
const filteredSourceObjectValue = sourceObjectValue.filter((_, index) => !indiciesToRemove.has(index));
|
|
138
155
|
// 10. Add all items to the original JSON
|
|
139
156
|
filteredSourceObjectValue.push(...itemsToAdd);
|
|
140
|
-
JSONPointer.set(mergedJson, sourceObjectPointer, sortByLocaleOrder(filteredSourceObjectValue, sourceObjectOptions,
|
|
157
|
+
JSONPointer.set(mergedJson, sourceObjectPointer, sortByLocaleOrder(filteredSourceObjectValue, sourceObjectOptions, canonicalLocaleOrder, sourceObjectPointer, canonicalDefaultLocale));
|
|
141
158
|
}
|
|
142
159
|
else {
|
|
143
160
|
// Validate type
|
|
@@ -146,7 +163,7 @@ export function mergeJson(originalContent, inputPath, options, targets, defaultL
|
|
|
146
163
|
return exitSync(1);
|
|
147
164
|
}
|
|
148
165
|
// Validate localeProperty
|
|
149
|
-
const matchingDefaultLocaleItem = findMatchingItemObject(
|
|
166
|
+
const matchingDefaultLocaleItem = findMatchingItemObject(canonicalDefaultLocale, sourceObjectPointer, sourceObjectOptions, sourceObjectValue);
|
|
150
167
|
// Validate source item exists
|
|
151
168
|
if (!matchingDefaultLocaleItem.sourceItem) {
|
|
152
169
|
logger.error(`Source item not found at path: ${sourceObjectPointer}. You must specify a source item where its key matches the default locale`);
|
|
@@ -169,7 +186,9 @@ export function mergeJson(originalContent, inputPath, options, targets, defaultL
|
|
|
169
186
|
targetItems = {};
|
|
170
187
|
}
|
|
171
188
|
// 2. Find the source item for the target locale
|
|
172
|
-
const matchingTargetItem = findMatchingItemObject(
|
|
189
|
+
const matchingTargetItem = findMatchingItemObject(useCanonicalLocaleKeys
|
|
190
|
+
? gt.resolveCanonicalLocale(target.targetLocale)
|
|
191
|
+
: target.targetLocale, sourceObjectPointer, sourceObjectOptions, sourceObjectValue);
|
|
173
192
|
// If the target locale has a matching source item, use it to mutate the source item
|
|
174
193
|
// Otherwise, fallback to the default locale source item
|
|
175
194
|
const mutateSourceItem = structuredClone(defaultLocaleSourceItem);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PACKAGE_VERSION = "2.5.
|
|
1
|
+
export declare const PACKAGE_VERSION = "2.5.37";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// This file is auto-generated. Do not edit manually.
|
|
2
|
-
export const PACKAGE_VERSION = '2.5.
|
|
2
|
+
export const PACKAGE_VERSION = '2.5.37';
|
package/dist/types/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { GT } from 'generaltranslation';
|
|
|
4
4
|
import { Settings } from '../types/index.js';
|
|
5
5
|
import { BranchData } from '../types/branch.js';
|
|
6
6
|
import type { FileReference } from 'generaltranslation/types';
|
|
7
|
-
export declare class
|
|
7
|
+
export declare class UploadSourcesStep extends WorkflowStep<{
|
|
8
8
|
files: FileToUpload[];
|
|
9
9
|
branchData: BranchData;
|
|
10
10
|
}, FileReference[]> {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { WorkflowStep } from './Workflow.js';
|
|
2
2
|
import { logger } from '../console/logger.js';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
|
-
export class
|
|
4
|
+
export class UploadSourcesStep extends WorkflowStep {
|
|
5
5
|
gt;
|
|
6
6
|
settings;
|
|
7
7
|
spinner = logger.createSpinner('dots');
|
|
@@ -62,6 +62,7 @@ export class UploadStep extends WorkflowStep {
|
|
|
62
62
|
fileName: f.fileName,
|
|
63
63
|
fileFormat: f.fileFormat,
|
|
64
64
|
dataFormat: f.dataFormat,
|
|
65
|
+
locale: f.locale,
|
|
65
66
|
})));
|
|
66
67
|
this.spinner.stop(chalk.green('Files uploaded successfully'));
|
|
67
68
|
return this.result;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { WorkflowStep } from './Workflow.js';
|
|
2
|
+
import { GT } from 'generaltranslation';
|
|
3
|
+
import { Settings } from '../types/index.js';
|
|
4
|
+
import { BranchData } from '../types/branch.js';
|
|
5
|
+
import type { FileReference, FileToUpload } from 'generaltranslation/types';
|
|
6
|
+
type UploadTranslationsInput = {
|
|
7
|
+
files: {
|
|
8
|
+
source: FileToUpload;
|
|
9
|
+
translations: FileToUpload[];
|
|
10
|
+
}[];
|
|
11
|
+
branchData: BranchData;
|
|
12
|
+
};
|
|
13
|
+
export declare class UploadTranslationsStep extends WorkflowStep<UploadTranslationsInput, FileReference[]> {
|
|
14
|
+
private gt;
|
|
15
|
+
private settings;
|
|
16
|
+
private spinner;
|
|
17
|
+
private result;
|
|
18
|
+
constructor(gt: GT, settings: Settings);
|
|
19
|
+
run({ files, branchData, }: UploadTranslationsInput): Promise<FileReference[]>;
|
|
20
|
+
wait(): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { WorkflowStep } from './Workflow.js';
|
|
2
|
+
import { logger } from '../console/logger.js';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
export class UploadTranslationsStep extends WorkflowStep {
|
|
5
|
+
gt;
|
|
6
|
+
settings;
|
|
7
|
+
spinner = logger.createSpinner('dots');
|
|
8
|
+
result = [];
|
|
9
|
+
constructor(gt, settings) {
|
|
10
|
+
super();
|
|
11
|
+
this.gt = gt;
|
|
12
|
+
this.settings = settings;
|
|
13
|
+
}
|
|
14
|
+
async run({ files, branchData, }) {
|
|
15
|
+
// Filter to only files that have translations
|
|
16
|
+
const filesWithTranslations = files.filter((f) => f.translations.length > 0);
|
|
17
|
+
if (filesWithTranslations.length === 0) {
|
|
18
|
+
logger.info('No translation files to upload... skipping upload translations step');
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
const totalTranslations = filesWithTranslations.reduce((acc, f) => acc + f.translations.length, 0);
|
|
22
|
+
this.spinner.start(`Syncing ${totalTranslations} translation file${totalTranslations !== 1 ? 's' : ''} with General Translation API...`);
|
|
23
|
+
// Build the query for existing translation files
|
|
24
|
+
const translatedFilesQuery = filesWithTranslations.flatMap((f) => f.translations.map((t) => ({
|
|
25
|
+
fileId: t.fileId,
|
|
26
|
+
versionId: t.versionId,
|
|
27
|
+
branchId: t.branchId ?? branchData.currentBranch.id,
|
|
28
|
+
locale: t.locale,
|
|
29
|
+
})));
|
|
30
|
+
// Query for existing translation files
|
|
31
|
+
const fileData = await this.gt.queryFileData({
|
|
32
|
+
translatedFiles: translatedFilesQuery,
|
|
33
|
+
});
|
|
34
|
+
// Build a map of existing translations: branchId:fileId:versionId:locale
|
|
35
|
+
const existingTranslationsMap = new Set();
|
|
36
|
+
fileData.translatedFiles?.forEach((f) => {
|
|
37
|
+
existingTranslationsMap.add(`${f.branchId}:${f.fileId}:${f.versionId}:${f.locale}`);
|
|
38
|
+
});
|
|
39
|
+
// Filter out translations that already exist
|
|
40
|
+
const filesToUpload = filesWithTranslations
|
|
41
|
+
.map((f) => {
|
|
42
|
+
const newTranslations = f.translations.filter((t) => {
|
|
43
|
+
const branchId = t.branchId ?? branchData.currentBranch.id;
|
|
44
|
+
const key = `${branchId}:${t.fileId}:${t.versionId}:${t.locale}`;
|
|
45
|
+
return !existingTranslationsMap.has(key);
|
|
46
|
+
});
|
|
47
|
+
return {
|
|
48
|
+
source: f.source,
|
|
49
|
+
translations: newTranslations,
|
|
50
|
+
};
|
|
51
|
+
})
|
|
52
|
+
.filter((f) => f.translations.length > 0);
|
|
53
|
+
const skippedCount = totalTranslations -
|
|
54
|
+
filesToUpload.reduce((acc, f) => acc + f.translations.length, 0);
|
|
55
|
+
if (filesToUpload.length === 0) {
|
|
56
|
+
this.spinner.stop(chalk.green(`All ${totalTranslations} translation files already uploaded`));
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
const uploadCount = filesToUpload.reduce((acc, f) => acc + f.translations.length, 0);
|
|
60
|
+
const response = await this.gt.uploadTranslations(filesToUpload, {
|
|
61
|
+
sourceLocale: this.settings.defaultLocale,
|
|
62
|
+
modelProvider: this.settings.modelProvider,
|
|
63
|
+
});
|
|
64
|
+
this.result = response.uploadedFiles;
|
|
65
|
+
this.spinner.stop(chalk.green(`Translation files synced successfully! Uploaded: (${uploadCount}), Skipped: (${skippedCount})`));
|
|
66
|
+
return this.result;
|
|
67
|
+
}
|
|
68
|
+
async wait() {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { logErrorAndExit } from '../console/logging.js';
|
|
2
2
|
import { gt } from '../utils/gt.js';
|
|
3
|
-
import {
|
|
3
|
+
import { UploadSourcesStep } from './UploadSourcesStep.js';
|
|
4
4
|
import { SetupStep } from './SetupStep.js';
|
|
5
5
|
import { BranchStep } from './BranchStep.js';
|
|
6
6
|
import { logCollectedFiles } from '../console/logging.js';
|
|
@@ -26,7 +26,7 @@ export async function setupProject(files, options, settings) {
|
|
|
26
26
|
const timeoutMs = calculateTimeout(options.timeout);
|
|
27
27
|
// Create workflow with steps
|
|
28
28
|
const branchStep = new BranchStep(gt, settings);
|
|
29
|
-
const uploadStep = new
|
|
29
|
+
const uploadStep = new UploadSourcesStep(gt, settings);
|
|
30
30
|
const setupStep = new SetupStep(gt, settings, timeoutMs);
|
|
31
31
|
// first run the branch step
|
|
32
32
|
const branchData = await branchStep.run();
|
package/dist/workflow/stage.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { logCollectedFiles, logErrorAndExit } from '../console/logging.js';
|
|
2
2
|
import { gt } from '../utils/gt.js';
|
|
3
|
-
import {
|
|
3
|
+
import { UploadSourcesStep } from './UploadSourcesStep.js';
|
|
4
4
|
import { SetupStep } from './SetupStep.js';
|
|
5
5
|
import { EnqueueStep } from './EnqueueStep.js';
|
|
6
6
|
import { BranchStep } from './BranchStep.js';
|
|
@@ -27,7 +27,7 @@ export async function stageFiles(files, options, settings) {
|
|
|
27
27
|
const timeoutMs = calculateTimeout(options.timeout);
|
|
28
28
|
// Create workflow with steps
|
|
29
29
|
const branchStep = new BranchStep(gt, settings);
|
|
30
|
-
const uploadStep = new
|
|
30
|
+
const uploadStep = new UploadSourcesStep(gt, settings);
|
|
31
31
|
const userEditDiffsStep = new UserEditDiffsStep(settings);
|
|
32
32
|
const setupStep = new SetupStep(gt, settings, timeoutMs);
|
|
33
33
|
const enqueueStep = new EnqueueStep(gt, settings, options.force);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Settings } from '../types/index.js';
|
|
2
|
+
import type { FileToUpload } from 'generaltranslation/types';
|
|
3
|
+
/**
|
|
4
|
+
* Uploads multiple files to the API using a workflow pattern
|
|
5
|
+
* @param files - Array of file objects to upload
|
|
6
|
+
* @param options - The options for the API call
|
|
7
|
+
* @returns The uploaded content or version ID
|
|
8
|
+
*/
|
|
9
|
+
export declare function uploadFiles(files: {
|
|
10
|
+
source: FileToUpload;
|
|
11
|
+
translations: FileToUpload[];
|
|
12
|
+
}[], options: Settings): Promise<undefined>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { logger } from '../console/logger.js';
|
|
3
|
+
import { logErrorAndExit } from '../console/logging.js';
|
|
4
|
+
import { gt } from '../utils/gt.js';
|
|
5
|
+
import { BranchStep } from './BranchStep.js';
|
|
6
|
+
import { UploadSourcesStep } from './UploadSourcesStep.js';
|
|
7
|
+
import { UploadTranslationsStep } from './UploadTranslationsStep.js';
|
|
8
|
+
/**
|
|
9
|
+
* Uploads multiple files to the API using a workflow pattern
|
|
10
|
+
* @param files - Array of file objects to upload
|
|
11
|
+
* @param options - The options for the API call
|
|
12
|
+
* @returns The uploaded content or version ID
|
|
13
|
+
*/
|
|
14
|
+
export async function uploadFiles(files, options) {
|
|
15
|
+
try {
|
|
16
|
+
logger.message(chalk.cyan('Files to upload:') +
|
|
17
|
+
'\n' +
|
|
18
|
+
files
|
|
19
|
+
.map((file) => ` - ${chalk.bold(file.source.fileName)}${file.translations.length > 0 ? ` -> ${file.translations.map((t) => t.locale).join(', ')}` : ''}`)
|
|
20
|
+
.join('\n'));
|
|
21
|
+
// Create workflow steps
|
|
22
|
+
const branchStep = new BranchStep(gt, options);
|
|
23
|
+
const uploadStep = new UploadSourcesStep(gt, options);
|
|
24
|
+
const uploadTranslationsStep = new UploadTranslationsStep(gt, options);
|
|
25
|
+
// Step 1: Resolve branch information
|
|
26
|
+
const branchData = await branchStep.run();
|
|
27
|
+
await branchStep.wait();
|
|
28
|
+
if (!branchData) {
|
|
29
|
+
return logErrorAndExit('Failed to resolve git branch information.');
|
|
30
|
+
}
|
|
31
|
+
await uploadStep.run({ files: files.map((f) => f.source), branchData });
|
|
32
|
+
await uploadStep.wait();
|
|
33
|
+
// Step 3: Upload translations (if any exist)
|
|
34
|
+
const filesWithTranslations = files.filter((f) => f.translations.length > 0);
|
|
35
|
+
if (filesWithTranslations.length > 0) {
|
|
36
|
+
await uploadTranslationsStep.run({
|
|
37
|
+
files: filesWithTranslations,
|
|
38
|
+
branchData,
|
|
39
|
+
});
|
|
40
|
+
await uploadTranslationsStep.wait();
|
|
41
|
+
}
|
|
42
|
+
logger.success('All files uploaded successfully');
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
return logErrorAndExit('Failed to upload files. ' + error);
|
|
46
|
+
}
|
|
47
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gtx-cli",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.37",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"bin": "dist/main.js",
|
|
6
6
|
"files": [
|
|
@@ -106,7 +106,7 @@
|
|
|
106
106
|
"unified": "^11.0.5",
|
|
107
107
|
"unist-util-visit": "^5.0.0",
|
|
108
108
|
"yaml": "^2.8.0",
|
|
109
|
-
"generaltranslation": "8.1.
|
|
109
|
+
"generaltranslation": "8.1.5"
|
|
110
110
|
},
|
|
111
111
|
"devDependencies": {
|
|
112
112
|
"@babel/types": "^7.28.4",
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { Settings } from '../types/index.js';
|
|
2
|
-
import { DataFormat, FileFormat } from '../types/data.js';
|
|
3
|
-
export type FileUpload = {
|
|
4
|
-
content: string;
|
|
5
|
-
fileName: string;
|
|
6
|
-
fileFormat: FileFormat;
|
|
7
|
-
dataFormat?: DataFormat;
|
|
8
|
-
locale: string;
|
|
9
|
-
};
|
|
10
|
-
export type UploadData = {
|
|
11
|
-
data: {
|
|
12
|
-
source: FileUpload;
|
|
13
|
-
translations: FileUpload[];
|
|
14
|
-
}[];
|
|
15
|
-
sourceLocale: string;
|
|
16
|
-
modelProvider?: string;
|
|
17
|
-
};
|
|
18
|
-
/**
|
|
19
|
-
* Uploads multiple files to the API
|
|
20
|
-
* @param files - Array of file objects to upload
|
|
21
|
-
* @param options - The options for the API call
|
|
22
|
-
* @returns The uploaded content or version ID
|
|
23
|
-
*/
|
|
24
|
-
export declare function uploadFiles(files: {
|
|
25
|
-
source: FileUpload;
|
|
26
|
-
translations: FileUpload[];
|
|
27
|
-
}[], options: Settings): Promise<undefined>;
|
package/dist/api/uploadFiles.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { logger } from '../console/logger.js';
|
|
3
|
-
import { exitSync } from '../console/logging.js';
|
|
4
|
-
import { gt } from '../utils/gt.js';
|
|
5
|
-
/**
|
|
6
|
-
* Uploads multiple files to the API
|
|
7
|
-
* @param files - Array of file objects to upload
|
|
8
|
-
* @param options - The options for the API call
|
|
9
|
-
* @returns The uploaded content or version ID
|
|
10
|
-
*/
|
|
11
|
-
export async function uploadFiles(files, options) {
|
|
12
|
-
logger.message(chalk.cyan('Files to upload:') +
|
|
13
|
-
'\n' +
|
|
14
|
-
files
|
|
15
|
-
.map((file) => ` - ${chalk.bold(file.source.fileName)} -> ${file.translations
|
|
16
|
-
.map((t) => t.locale)
|
|
17
|
-
.join(', ')}`)
|
|
18
|
-
.join('\n'));
|
|
19
|
-
const spinner = logger.createSpinner('dots');
|
|
20
|
-
spinner.start(`Uploading ${files.length} file${files.length !== 1 ? 's' : ''} to General Translation...`);
|
|
21
|
-
try {
|
|
22
|
-
// Upload sources
|
|
23
|
-
await gt.uploadSourceFiles(files, {
|
|
24
|
-
...options,
|
|
25
|
-
sourceLocale: options.defaultLocale,
|
|
26
|
-
});
|
|
27
|
-
// Upload translations (if any exist)
|
|
28
|
-
const withTranslations = files.filter((f) => f.translations.length > 0);
|
|
29
|
-
if (withTranslations.length > 0) {
|
|
30
|
-
await gt.uploadTranslations(withTranslations, {
|
|
31
|
-
...options,
|
|
32
|
-
sourceLocale: options.defaultLocale, // optional, safe to include
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
spinner.stop(chalk.green('Files uploaded successfully'));
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
38
|
-
spinner.stop(chalk.red('An unexpected error occurred while uploading files'));
|
|
39
|
-
return exitSync(1);
|
|
40
|
-
}
|
|
41
|
-
}
|