gtx-cli 2.5.8 → 2.5.9
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/cli/base.d.ts +2 -1
- package/dist/cli/base.js +20 -15
- package/dist/cli/commands/setupProject.d.ts +7 -0
- package/dist/cli/commands/setupProject.js +50 -0
- package/dist/cli/commands/stage.d.ts +0 -2
- package/dist/cli/commands/stage.js +7 -56
- package/dist/cli/next.js +1 -0
- package/dist/cli/react.d.ts +1 -0
- package/dist/cli/react.js +10 -0
- package/dist/console/logger.d.ts +8 -0
- package/dist/console/logger.js +17 -2
- package/dist/console/logging.d.ts +5 -0
- package/dist/console/logging.js +16 -0
- package/dist/formats/files/collectFiles.d.ts +6 -0
- package/dist/formats/files/collectFiles.js +49 -0
- package/dist/formats/files/fileMapping.js +1 -1
- package/dist/fs/createLoadTranslationsFile.d.ts +1 -1
- package/dist/fs/createLoadTranslationsFile.js +8 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/utils/constants.d.ts +2 -0
- package/dist/utils/constants.js +3 -0
- package/dist/workflow/PollJobsStep.js +1 -1
- package/dist/workflow/SetupStep.d.ts +1 -1
- package/dist/workflow/SetupStep.js +2 -1
- package/dist/workflow/setupProject.d.ts +13 -0
- package/dist/workflow/setupProject.js +48 -0
- package/dist/workflow/stage.js +2 -20
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# gtx-cli
|
|
2
2
|
|
|
3
|
+
## 2.5.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#823](https://github.com/generaltranslation/gt/pull/823) [`afbd29a`](https://github.com/generaltranslation/gt/commit/afbd29a34b051c76fce387269c4eb4a2e00a5831) Thanks [@brian-lou](https://github.com/brian-lou)! - Deprecate old 'setup' command -> Use 'init' instead. New 'setup' command runs project setup
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`afbd29a`](https://github.com/generaltranslation/gt/commit/afbd29a34b051c76fce387269c4eb4a2e00a5831)]:
|
|
10
|
+
- generaltranslation@8.0.3
|
|
11
|
+
|
|
3
12
|
## 2.5.8
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
package/dist/cli/base.d.ts
CHANGED
|
@@ -16,16 +16,17 @@ export declare class BaseCLI {
|
|
|
16
16
|
constructor(program: Command, library: SupportedLibraries, additionalModules?: SupportedLibraries[]);
|
|
17
17
|
init(): void;
|
|
18
18
|
execute(): void;
|
|
19
|
+
protected setupSetupProjectCommand(): void;
|
|
19
20
|
protected setupStageCommand(): void;
|
|
20
21
|
protected setupTranslateCommand(): void;
|
|
21
22
|
protected setupSendDiffsCommand(): void;
|
|
23
|
+
protected handleSetupProject(initOptions: TranslateFlags): Promise<void>;
|
|
22
24
|
protected handleStage(initOptions: TranslateFlags): Promise<void>;
|
|
23
25
|
protected handleTranslate(initOptions: TranslateFlags): Promise<void>;
|
|
24
26
|
protected setupUploadCommand(): void;
|
|
25
27
|
protected setupLoginCommand(): void;
|
|
26
28
|
protected setupInitCommand(): void;
|
|
27
29
|
protected setupConfigureCommand(): void;
|
|
28
|
-
protected setupSetupCommand(): void;
|
|
29
30
|
protected handleUploadCommand(settings: Settings & UploadOptions): Promise<void>;
|
|
30
31
|
protected handleSetupReactCommand(options: SetupOptions): Promise<void>;
|
|
31
32
|
protected handleInitCommand(ranReactSetup: boolean): Promise<void>;
|
package/dist/cli/base.js
CHANGED
|
@@ -17,6 +17,7 @@ import { areCredentialsSet } from '../utils/credentials.js';
|
|
|
17
17
|
import { upload } from '../formats/files/upload.js';
|
|
18
18
|
import { attachTranslateFlags } from './flags.js';
|
|
19
19
|
import { handleStage } from './commands/stage.js';
|
|
20
|
+
import { handleSetupProject } from './commands/setupProject.js';
|
|
20
21
|
import { handleDownload, handleTranslate, postProcessTranslations, } from './commands/translate.js';
|
|
21
22
|
import { getDownloaded, clearDownloaded } from '../state/recentDownloads.js';
|
|
22
23
|
import updateConfig from '../fs/config/updateConfig.js';
|
|
@@ -34,13 +35,14 @@ export class BaseCLI {
|
|
|
34
35
|
this.additionalModules = additionalModules || [];
|
|
35
36
|
this.setupInitCommand();
|
|
36
37
|
this.setupConfigureCommand();
|
|
37
|
-
this.setupSetupCommand();
|
|
38
38
|
this.setupUploadCommand();
|
|
39
39
|
this.setupLoginCommand();
|
|
40
40
|
this.setupSendDiffsCommand();
|
|
41
41
|
}
|
|
42
42
|
// Init is never called in a child class
|
|
43
43
|
init() {
|
|
44
|
+
this.setupSetupProjectCommand();
|
|
45
|
+
this.setupStageCommand();
|
|
44
46
|
this.setupTranslateCommand();
|
|
45
47
|
}
|
|
46
48
|
// Execute is called by the main program
|
|
@@ -50,6 +52,15 @@ export class BaseCLI {
|
|
|
50
52
|
process.argv.push('init');
|
|
51
53
|
}
|
|
52
54
|
}
|
|
55
|
+
setupSetupProjectCommand() {
|
|
56
|
+
attachTranslateFlags(this.program
|
|
57
|
+
.command('setup')
|
|
58
|
+
.description('Upload source files and setup the project for translation')).action(async (initOptions) => {
|
|
59
|
+
displayHeader('Uploading source files and setting up project...');
|
|
60
|
+
await this.handleSetupProject(initOptions);
|
|
61
|
+
logger.endCommand('Done!');
|
|
62
|
+
});
|
|
63
|
+
}
|
|
53
64
|
setupStageCommand() {
|
|
54
65
|
attachTranslateFlags(this.program
|
|
55
66
|
.command('stage')
|
|
@@ -80,6 +91,12 @@ export class BaseCLI {
|
|
|
80
91
|
logger.endCommand('Saved local edits');
|
|
81
92
|
});
|
|
82
93
|
}
|
|
94
|
+
async handleSetupProject(initOptions) {
|
|
95
|
+
const settings = await generateSettings(initOptions);
|
|
96
|
+
// Preprocess shared static assets if configured (move + rewrite sources)
|
|
97
|
+
await processSharedStaticAssets(settings);
|
|
98
|
+
await handleSetupProject(initOptions, settings, this.library);
|
|
99
|
+
}
|
|
83
100
|
async handleStage(initOptions) {
|
|
84
101
|
const settings = await generateSettings(initOptions);
|
|
85
102
|
// Preprocess shared static assets if configured (move + rewrite sources)
|
|
@@ -208,18 +225,6 @@ See the docs for more information: https://generaltranslation.com/docs/react/tut
|
|
|
208
225
|
logger.endCommand('Done! Make sure you have an API key and project ID to use General Translation. Get them on the dashboard: https://generaltranslation.com/dashboard');
|
|
209
226
|
});
|
|
210
227
|
}
|
|
211
|
-
setupSetupCommand() {
|
|
212
|
-
this.program
|
|
213
|
-
.command('setup')
|
|
214
|
-
.description('Run the setup to configure your Next.js or React project for General Translation')
|
|
215
|
-
.option('--src <paths...>', "Space-separated list of glob patterns containing the app's source code, by default 'src/**/*.{js,jsx,ts,tsx}' 'app/**/*.{js,jsx,ts,tsx}' 'pages/**/*.{js,jsx,ts,tsx}' 'components/**/*.{js,jsx,ts,tsx}'")
|
|
216
|
-
.option('-c, --config <path>', 'Filepath to config file, by default gt.config.json', findFilepath(['gt.config.json']))
|
|
217
|
-
.action(async (options) => {
|
|
218
|
-
displayHeader('Running React setup wizard...');
|
|
219
|
-
await this.handleSetupReactCommand(options);
|
|
220
|
-
logger.endCommand("Done! Take advantage of all of General Translation's features by signing up for a free account! https://generaltranslation.com/signup");
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
228
|
async handleUploadCommand(settings) {
|
|
224
229
|
// dataFormat for JSONs
|
|
225
230
|
let dataFormat;
|
|
@@ -265,7 +270,7 @@ See the docs for more information: https://generaltranslation.com/docs/react/tut
|
|
|
265
270
|
message: `Auto-detected that you're using gt-next or gt-react. Would you like to use the General Translation CDN to store your translations?\nSee ${isUsingGTNext
|
|
266
271
|
? 'https://generaltranslation.com/en/docs/next/guides/local-tx'
|
|
267
272
|
: 'https://generaltranslation.com/en/docs/react/guides/local-tx'} for more information.\nIf you answer no, we'll configure the CLI tool to download completed translations.`,
|
|
268
|
-
defaultValue:
|
|
273
|
+
defaultValue: false,
|
|
269
274
|
})
|
|
270
275
|
: false;
|
|
271
276
|
// Ask where the translations are stored
|
|
@@ -279,7 +284,7 @@ See the docs for more information: https://generaltranslation.com/docs/react/tut
|
|
|
279
284
|
const finalTranslationsDir = translationsDir?.trim() || './public/_gt';
|
|
280
285
|
if (isUsingGT && !usingCDN) {
|
|
281
286
|
// Create loadTranslations.js file for local translations
|
|
282
|
-
await createLoadTranslationsFile(process.cwd(), finalTranslationsDir);
|
|
287
|
+
await createLoadTranslationsFile(process.cwd(), finalTranslationsDir, locales);
|
|
283
288
|
logger.message(`Created ${chalk.cyan('loadTranslations.js')} file for local translations.
|
|
284
289
|
Make sure to add this function to your app configuration.
|
|
285
290
|
See https://generaltranslation.com/en/docs/next/guides/local-tx`);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Settings, SupportedLibraries, TranslateFlags } from '../../types/index.js';
|
|
2
|
+
import { FileTranslationData } from '../../workflow/download.js';
|
|
3
|
+
import { BranchData } from '../../types/branch.js';
|
|
4
|
+
export declare function handleSetupProject(options: TranslateFlags, settings: Settings, library: SupportedLibraries): Promise<{
|
|
5
|
+
fileVersionData: FileTranslationData | undefined;
|
|
6
|
+
branchData: BranchData | undefined;
|
|
7
|
+
} | null>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { logger } from '../../console/logger.js';
|
|
2
|
+
import { logCollectedFiles, logErrorAndExit } from '../../console/logging.js';
|
|
3
|
+
import { noLocalesError, noDefaultLocaleError, noApiKeyError, noProjectIdError, devApiKeyError, } from '../../console/index.js';
|
|
4
|
+
import { collectFiles } from '../../formats/files/collectFiles.js';
|
|
5
|
+
import { setupProject } from '../../workflow/setupProject.js';
|
|
6
|
+
export async function handleSetupProject(options, settings, library) {
|
|
7
|
+
// Validate required settings are present if not in dry run
|
|
8
|
+
if (!options.dryRun) {
|
|
9
|
+
if (!settings.locales) {
|
|
10
|
+
return logErrorAndExit(noLocalesError);
|
|
11
|
+
}
|
|
12
|
+
if (!settings.defaultLocale) {
|
|
13
|
+
return logErrorAndExit(noDefaultLocaleError);
|
|
14
|
+
}
|
|
15
|
+
if (!settings.apiKey) {
|
|
16
|
+
return logErrorAndExit(noApiKeyError);
|
|
17
|
+
}
|
|
18
|
+
if (settings.apiKey.startsWith('gtx-dev-')) {
|
|
19
|
+
return logErrorAndExit(devApiKeyError);
|
|
20
|
+
}
|
|
21
|
+
if (!settings.projectId) {
|
|
22
|
+
return logErrorAndExit(noProjectIdError);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const { files: allFiles, reactComponents } = await collectFiles(options, settings, library);
|
|
26
|
+
// Dry run
|
|
27
|
+
if (options.dryRun) {
|
|
28
|
+
logger.success(`Dry run: No files were uploaded to General Translation.`);
|
|
29
|
+
logCollectedFiles(allFiles, reactComponents);
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
// Upload files and run setup step
|
|
33
|
+
let fileVersionData;
|
|
34
|
+
let branchData;
|
|
35
|
+
if (allFiles.length > 0) {
|
|
36
|
+
const { branchData: branchDataResult } = await setupProject(allFiles, options, settings);
|
|
37
|
+
branchData = branchDataResult;
|
|
38
|
+
fileVersionData = Object.fromEntries(allFiles.map((file) => [
|
|
39
|
+
file.fileId,
|
|
40
|
+
{
|
|
41
|
+
fileName: file.fileName,
|
|
42
|
+
versionId: file.versionId,
|
|
43
|
+
},
|
|
44
|
+
]));
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
fileVersionData,
|
|
48
|
+
branchData,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -2,8 +2,6 @@ import { Settings, SupportedLibraries, TranslateFlags } from '../../types/index.
|
|
|
2
2
|
import type { EnqueueFilesResult } from 'generaltranslation/types';
|
|
3
3
|
import { FileTranslationData } from '../../workflow/download.js';
|
|
4
4
|
import { BranchData } from '../../types/branch.js';
|
|
5
|
-
export declare const TEMPLATE_FILE_NAME = "__INTERNAL_GT_TEMPLATE_NAME__";
|
|
6
|
-
export declare const TEMPLATE_FILE_ID: string;
|
|
7
5
|
export declare function handleStage(options: TranslateFlags, settings: Settings, library: SupportedLibraries, stage: boolean): Promise<{
|
|
8
6
|
fileVersionData: FileTranslationData | undefined;
|
|
9
7
|
jobData: EnqueueFilesResult | undefined;
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { logger } from '../../console/logger.js';
|
|
2
|
-
import { logErrorAndExit } from '../../console/logging.js';
|
|
3
|
-
import { noLocalesError, noDefaultLocaleError, noApiKeyError, noProjectIdError, devApiKeyError,
|
|
4
|
-
import { aggregateFiles } from '../../formats/files/translate.js';
|
|
5
|
-
import { aggregateReactTranslations } from '../../translation/stage.js';
|
|
2
|
+
import { logCollectedFiles, logErrorAndExit } from '../../console/logging.js';
|
|
3
|
+
import { noLocalesError, noDefaultLocaleError, noApiKeyError, noProjectIdError, devApiKeyError, } from '../../console/index.js';
|
|
6
4
|
import { stageFiles } from '../../workflow/stage.js';
|
|
7
5
|
import { updateVersions } from '../../fs/config/updateVersions.js';
|
|
8
6
|
import updateConfig from '../../fs/config/updateConfig.js';
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
export const TEMPLATE_FILE_ID = hashStringSync(TEMPLATE_FILE_NAME);
|
|
7
|
+
import { TEMPLATE_FILE_ID } from '../../utils/constants.js';
|
|
8
|
+
import { collectFiles } from '../../formats/files/collectFiles.js';
|
|
12
9
|
export async function handleStage(options, settings, library, stage) {
|
|
13
10
|
// Validate required settings are present if not in dry run
|
|
14
11
|
if (!options.dryRun) {
|
|
@@ -28,57 +25,11 @@ export async function handleStage(options, settings, library, stage) {
|
|
|
28
25
|
return logErrorAndExit(noProjectIdError);
|
|
29
26
|
}
|
|
30
27
|
}
|
|
31
|
-
|
|
32
|
-
const allFiles = await aggregateFiles(settings);
|
|
33
|
-
// Parse for React components
|
|
34
|
-
let reactComponents = 0;
|
|
35
|
-
if (library === 'gt-react' || library === 'gt-next') {
|
|
36
|
-
const updates = await aggregateReactTranslations(options, settings, library);
|
|
37
|
-
if (updates.length > 0) {
|
|
38
|
-
if (!options.dryRun &&
|
|
39
|
-
!settings.publish &&
|
|
40
|
-
!settings.files?.placeholderPaths.gt) {
|
|
41
|
-
logErrorAndExit(invalidConfigurationError);
|
|
42
|
-
}
|
|
43
|
-
reactComponents = updates.length;
|
|
44
|
-
// Convert updates to a file object
|
|
45
|
-
const fileData = {};
|
|
46
|
-
const fileMetadata = {};
|
|
47
|
-
// Convert updates to the proper data format
|
|
48
|
-
for (const update of updates) {
|
|
49
|
-
const { source, metadata, dataFormat } = update;
|
|
50
|
-
metadata.dataFormat = dataFormat; // add the data format to the metadata
|
|
51
|
-
const { hash, id } = metadata;
|
|
52
|
-
if (id) {
|
|
53
|
-
fileData[id] = source;
|
|
54
|
-
fileMetadata[id] = metadata;
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
fileData[hash] = source;
|
|
58
|
-
fileMetadata[hash] = metadata;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
allFiles.push({
|
|
62
|
-
fileName: TEMPLATE_FILE_NAME,
|
|
63
|
-
content: JSON.stringify(fileData),
|
|
64
|
-
fileFormat: 'GTJSON',
|
|
65
|
-
formatMetadata: fileMetadata,
|
|
66
|
-
fileId: TEMPLATE_FILE_ID,
|
|
67
|
-
versionId: hashStringSync(JSON.stringify(fileData)),
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
}
|
|
28
|
+
const { files: allFiles, reactComponents } = await collectFiles(options, settings, library);
|
|
71
29
|
// Dry run
|
|
72
30
|
if (options.dryRun) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (file.fileName === TEMPLATE_FILE_NAME) {
|
|
76
|
-
return `- <React Elements> (${reactComponents})`;
|
|
77
|
-
}
|
|
78
|
-
return `- ${file.fileName}`;
|
|
79
|
-
})
|
|
80
|
-
.join('\n');
|
|
81
|
-
logger.success(`Dry run: No files were sent to General Translation. Found files:\n${fileNames}`);
|
|
31
|
+
logger.success(`Dry run: No files were sent to General Translation.`);
|
|
32
|
+
logCollectedFiles(allFiles, reactComponents);
|
|
82
33
|
return null;
|
|
83
34
|
}
|
|
84
35
|
// Send translations to General Translation
|
package/dist/cli/next.js
CHANGED
package/dist/cli/react.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare class ReactCLI extends BaseCLI {
|
|
|
8
8
|
protected wrapContent(options: WrapOptions, framework: SupportedFrameworks, errors: string[], warnings: string[]): Promise<{
|
|
9
9
|
filesUpdated: string[];
|
|
10
10
|
}>;
|
|
11
|
+
protected setupSetupProjectCommand(): void;
|
|
11
12
|
protected setupStageCommand(): void;
|
|
12
13
|
protected setupTranslateCommand(): void;
|
|
13
14
|
protected setupValidateCommand(): void;
|
package/dist/cli/react.js
CHANGED
|
@@ -21,6 +21,7 @@ export class ReactCLI extends BaseCLI {
|
|
|
21
21
|
super(command, library, additionalModules);
|
|
22
22
|
}
|
|
23
23
|
init() {
|
|
24
|
+
this.setupSetupProjectCommand();
|
|
24
25
|
this.setupStageCommand();
|
|
25
26
|
this.setupTranslateCommand();
|
|
26
27
|
this.setupGenerateSourceCommand();
|
|
@@ -32,6 +33,15 @@ export class ReactCLI extends BaseCLI {
|
|
|
32
33
|
wrapContent(options, framework, errors, warnings) {
|
|
33
34
|
return wrapContentReact(options, pkg, framework, errors, warnings);
|
|
34
35
|
}
|
|
36
|
+
setupSetupProjectCommand() {
|
|
37
|
+
attachAdditionalReactTranslateFlags(attachTranslateFlags(this.program
|
|
38
|
+
.command('setup')
|
|
39
|
+
.description('Upload source files and setup the project for translation'))).action(async (options) => {
|
|
40
|
+
displayHeader('Uploading source files and setting up project...');
|
|
41
|
+
await this.handleSetupProject(options);
|
|
42
|
+
logger.endCommand('Done!');
|
|
43
|
+
});
|
|
44
|
+
}
|
|
35
45
|
setupStageCommand() {
|
|
36
46
|
attachAdditionalReactTranslateFlags(attachTranslateFlags(this.program
|
|
37
47
|
.command('stage')
|
package/dist/console/logger.d.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import type { SpinnerResult, ProgressResult } from '@clack/prompts';
|
|
2
2
|
export type LogFormat = 'default' | 'json';
|
|
3
|
+
/**
|
|
4
|
+
* GT_LOG_FORMAT: default | json.
|
|
5
|
+
* - If default, logs will be pretty-printed using @clack/prompts.
|
|
6
|
+
* - If json, logs will be written in JSON format to the console.
|
|
7
|
+
* GT_LOG_FILE: If specified, logs will be written to the file.
|
|
8
|
+
* GT_LOG_LEVEL: The level of logs to write. If not specified, defaults to 'info'.
|
|
9
|
+
* - Valid levels: debug, info, warn, error.
|
|
10
|
+
*/
|
|
3
11
|
declare class Logger {
|
|
4
12
|
private static instance;
|
|
5
13
|
private pinoLogger;
|
package/dist/console/logger.js
CHANGED
|
@@ -59,6 +59,14 @@ class MockProgress {
|
|
|
59
59
|
this.logger.info(`[Progress] ${msg} (${this.current}/${this.max})`);
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* GT_LOG_FORMAT: default | json.
|
|
64
|
+
* - If default, logs will be pretty-printed using @clack/prompts.
|
|
65
|
+
* - If json, logs will be written in JSON format to the console.
|
|
66
|
+
* GT_LOG_FILE: If specified, logs will be written to the file.
|
|
67
|
+
* GT_LOG_LEVEL: The level of logs to write. If not specified, defaults to 'info'.
|
|
68
|
+
* - Valid levels: debug, info, warn, error.
|
|
69
|
+
*/
|
|
62
70
|
class Logger {
|
|
63
71
|
static instance;
|
|
64
72
|
pinoLogger = null;
|
|
@@ -67,12 +75,19 @@ class Logger {
|
|
|
67
75
|
constructor() {
|
|
68
76
|
// Read configuration from environment variables
|
|
69
77
|
const format = (process.env.GT_LOG_FORMAT || 'default').toLowerCase();
|
|
78
|
+
const logFile = process.env.GT_LOG_FILE;
|
|
79
|
+
const logLevel = process.env.GT_LOG_LEVEL || 'info';
|
|
70
80
|
if (format !== 'default' && format !== 'json') {
|
|
71
81
|
console.error('Invalid log format');
|
|
72
82
|
process.exit(1);
|
|
73
83
|
}
|
|
74
|
-
|
|
75
|
-
|
|
84
|
+
if (logLevel !== 'debug' &&
|
|
85
|
+
logLevel !== 'info' &&
|
|
86
|
+
logLevel !== 'warn' &&
|
|
87
|
+
logLevel !== 'error') {
|
|
88
|
+
console.error('Invalid log level');
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
76
91
|
this.logFormat = format;
|
|
77
92
|
const transports = [];
|
|
78
93
|
// Console output (stdout)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { FileToUpload } from 'generaltranslation/types';
|
|
1
2
|
export declare function logErrorAndExit(message: string): never;
|
|
2
3
|
export declare function exitSync(code: number): never;
|
|
3
4
|
export declare function displayHeader(introString?: string): void;
|
|
@@ -41,3 +42,7 @@ export declare function warnHasUnwrappedExpression(file: string, id: string, unw
|
|
|
41
42
|
export declare function warnNonStaticExpression(file: string, attrName: string, value: string): void;
|
|
42
43
|
export declare function warnTemplateLiteral(file: string, value: string): void;
|
|
43
44
|
export declare function warnTernary(file: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* Helper: Log all collected files
|
|
47
|
+
*/
|
|
48
|
+
export declare function logCollectedFiles(files: FileToUpload[], reactComponents?: number): void;
|
package/dist/console/logging.js
CHANGED
|
@@ -2,6 +2,7 @@ import { text, select, confirm, isCancel, cancel, multiselect, } from '@clack/pr
|
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { getCLIVersion } from '../utils/packageJson.js';
|
|
4
4
|
import { logger } from './logger.js';
|
|
5
|
+
import { TEMPLATE_FILE_NAME } from '../utils/constants.js';
|
|
5
6
|
export function logErrorAndExit(message) {
|
|
6
7
|
logger.error(message);
|
|
7
8
|
return exitSync(1);
|
|
@@ -151,3 +152,18 @@ export function warnTernary(file) {
|
|
|
151
152
|
logger.warn(`Found ternary expression in ${chalk.cyan(file)}. ` +
|
|
152
153
|
chalk.white('A Branch component may be more appropriate here.'));
|
|
153
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* Helper: Log all collected files
|
|
157
|
+
*/
|
|
158
|
+
export function logCollectedFiles(files, reactComponents) {
|
|
159
|
+
logger.message(chalk.cyan('Files found in project:') +
|
|
160
|
+
'\n' +
|
|
161
|
+
files
|
|
162
|
+
.map((file) => {
|
|
163
|
+
if (file.fileName === TEMPLATE_FILE_NAME) {
|
|
164
|
+
return `- <React Elements>${reactComponents ? ` (${reactComponents})` : ''}`;
|
|
165
|
+
}
|
|
166
|
+
return `- ${file.fileName}`;
|
|
167
|
+
})
|
|
168
|
+
.join('\n'));
|
|
169
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Settings, SupportedLibraries, TranslateFlags } from '../../types/index.js';
|
|
2
|
+
import type { FileToUpload } from 'generaltranslation/types';
|
|
3
|
+
export declare function collectFiles(options: TranslateFlags, settings: Settings, library: SupportedLibraries): Promise<{
|
|
4
|
+
files: FileToUpload[];
|
|
5
|
+
reactComponents: number;
|
|
6
|
+
}>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { logErrorAndExit } from '../../console/logging.js';
|
|
2
|
+
import { invalidConfigurationError } from '../../console/index.js';
|
|
3
|
+
import { aggregateFiles } from '../../formats/files/translate.js';
|
|
4
|
+
import { aggregateReactTranslations } from '../../translation/stage.js';
|
|
5
|
+
import { hashStringSync } from '../../utils/hash.js';
|
|
6
|
+
import { TEMPLATE_FILE_NAME, TEMPLATE_FILE_ID } from '../../utils/constants.js';
|
|
7
|
+
export async function collectFiles(options, settings, library) {
|
|
8
|
+
// Aggregate files
|
|
9
|
+
const allFiles = await aggregateFiles(settings);
|
|
10
|
+
// Parse for React components
|
|
11
|
+
let reactComponents = 0;
|
|
12
|
+
if (library === 'gt-react' || library === 'gt-next') {
|
|
13
|
+
const updates = await aggregateReactTranslations(options, settings, library);
|
|
14
|
+
if (updates.length > 0) {
|
|
15
|
+
if (!options.dryRun &&
|
|
16
|
+
!settings.publish &&
|
|
17
|
+
!settings.files?.placeholderPaths.gt) {
|
|
18
|
+
logErrorAndExit(invalidConfigurationError);
|
|
19
|
+
}
|
|
20
|
+
// Convert updates to a file object
|
|
21
|
+
const fileData = {};
|
|
22
|
+
const fileMetadata = {};
|
|
23
|
+
// Convert updates to the proper data format
|
|
24
|
+
for (const update of updates) {
|
|
25
|
+
const { source, metadata, dataFormat } = update;
|
|
26
|
+
metadata.dataFormat = dataFormat; // add the data format to the metadata
|
|
27
|
+
const { hash, id } = metadata;
|
|
28
|
+
if (id) {
|
|
29
|
+
fileData[id] = source;
|
|
30
|
+
fileMetadata[id] = metadata;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
fileData[hash] = source;
|
|
34
|
+
fileMetadata[hash] = metadata;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
reactComponents = updates.length;
|
|
38
|
+
allFiles.push({
|
|
39
|
+
fileName: TEMPLATE_FILE_NAME,
|
|
40
|
+
content: JSON.stringify(fileData),
|
|
41
|
+
fileFormat: 'GTJSON',
|
|
42
|
+
formatMetadata: fileMetadata,
|
|
43
|
+
fileId: TEMPLATE_FILE_ID,
|
|
44
|
+
versionId: hashStringSync(JSON.stringify(fileData)),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return { files: allFiles, reactComponents };
|
|
49
|
+
}
|
|
@@ -4,7 +4,7 @@ import path from 'node:path';
|
|
|
4
4
|
import { getRelative } from '../../fs/findFilepath.js';
|
|
5
5
|
import { getLocaleProperties } from 'generaltranslation';
|
|
6
6
|
import { replaceLocalePlaceholders } from '../utils.js';
|
|
7
|
-
import { TEMPLATE_FILE_NAME } from '../../
|
|
7
|
+
import { TEMPLATE_FILE_NAME } from '../../utils/constants.js';
|
|
8
8
|
/**
|
|
9
9
|
* Creates a mapping between source files and their translated counterparts for each locale
|
|
10
10
|
* @param filePaths - Resolved file paths for different file types
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function createLoadTranslationsFile(appDirectory: string, translationsDir
|
|
1
|
+
export declare function createLoadTranslationsFile(appDirectory: string, translationsDir: string | undefined, locales: string[]): Promise<void>;
|
|
@@ -2,7 +2,7 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { logger } from '../console/logger.js';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
|
-
export async function createLoadTranslationsFile(appDirectory, translationsDir = './public/_gt') {
|
|
5
|
+
export async function createLoadTranslationsFile(appDirectory, translationsDir = './public/_gt', locales) {
|
|
6
6
|
const usingSrcDirectory = fs.existsSync(path.join(appDirectory, 'src'));
|
|
7
7
|
// Calculate the relative path from the loadTranslations.js location to the translations directory
|
|
8
8
|
const loadTranslationsDir = usingSrcDirectory
|
|
@@ -29,6 +29,13 @@ export default async function loadTranslations(locale) {
|
|
|
29
29
|
`;
|
|
30
30
|
await fs.promises.writeFile(filePath, loadTranslationsContent);
|
|
31
31
|
logger.info(`Created ${chalk.cyan('loadTranslations.js')} file at ${chalk.cyan(filePath)}.`);
|
|
32
|
+
// Create empty JSON files
|
|
33
|
+
for (const locale of locales) {
|
|
34
|
+
if (fs.existsSync(path.join(translationsDir, `${locale}.json`))) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
await fs.promises.writeFile(path.join(translationsDir, `${locale}.json`), '{}');
|
|
38
|
+
}
|
|
32
39
|
}
|
|
33
40
|
else {
|
|
34
41
|
logger.info(`Found ${chalk.cyan('loadTranslations.js')} file at ${chalk.cyan(filePath)}. Skipping creation...`);
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
export declare const GT_DASHBOARD_URL = "https://dash.generaltranslation.com";
|
|
2
2
|
export declare const GT_CONFIG_SCHEMA_URL = "https://assets.gtx.dev/config-schema.json";
|
|
3
|
+
export declare const TEMPLATE_FILE_NAME = "__INTERNAL_GT_TEMPLATE_NAME__";
|
|
4
|
+
export declare const TEMPLATE_FILE_ID: string;
|
package/dist/utils/constants.js
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
|
+
import { hashStringSync } from './hash.js';
|
|
1
2
|
export const GT_DASHBOARD_URL = 'https://dash.generaltranslation.com';
|
|
2
3
|
export const GT_CONFIG_SCHEMA_URL = 'https://assets.gtx.dev/config-schema.json';
|
|
4
|
+
export const TEMPLATE_FILE_NAME = '__INTERNAL_GT_TEMPLATE_NAME__';
|
|
5
|
+
export const TEMPLATE_FILE_ID = hashStringSync(TEMPLATE_FILE_NAME);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { WorkflowStep } from './Workflow.js';
|
|
3
3
|
import { logger } from '../console/logger.js';
|
|
4
|
-
import { TEMPLATE_FILE_NAME } from '../
|
|
4
|
+
import { TEMPLATE_FILE_NAME } from '../utils/constants.js';
|
|
5
5
|
export class PollTranslationJobsStep extends WorkflowStep {
|
|
6
6
|
gt;
|
|
7
7
|
spinner = null;
|
|
@@ -11,6 +11,6 @@ export declare class SetupStep extends WorkflowStep<FileReference[], FileReferen
|
|
|
11
11
|
private files;
|
|
12
12
|
private completed;
|
|
13
13
|
constructor(gt: GT, settings: Settings, timeoutMs: number);
|
|
14
|
-
run(files: FileReference[]): Promise<FileReference[]>;
|
|
14
|
+
run(files: FileReference[], force?: boolean): Promise<FileReference[]>;
|
|
15
15
|
wait(): Promise<void>;
|
|
16
16
|
}
|
|
@@ -15,7 +15,7 @@ export class SetupStep extends WorkflowStep {
|
|
|
15
15
|
this.settings = settings;
|
|
16
16
|
this.timeoutMs = timeoutMs;
|
|
17
17
|
}
|
|
18
|
-
async run(files) {
|
|
18
|
+
async run(files, force = false) {
|
|
19
19
|
this.files = files;
|
|
20
20
|
this.spinner.start('Setting up project...');
|
|
21
21
|
if (files.length === 0) {
|
|
@@ -24,6 +24,7 @@ export class SetupStep extends WorkflowStep {
|
|
|
24
24
|
}
|
|
25
25
|
const result = await this.gt.setupProject(files, {
|
|
26
26
|
locales: this.settings.locales,
|
|
27
|
+
force,
|
|
27
28
|
});
|
|
28
29
|
if (result.status === 'completed') {
|
|
29
30
|
this.completed = true;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Settings, TranslateFlags } from '../types/index.js';
|
|
2
|
+
import { FileToUpload } from 'generaltranslation/types';
|
|
3
|
+
import { BranchData } from '../types/branch.js';
|
|
4
|
+
/**
|
|
5
|
+
* Sets up a project by uploading files running the setup step
|
|
6
|
+
* @param files - Array of file objects to upload
|
|
7
|
+
* @param options - The options for the API call
|
|
8
|
+
* @param settings - Settings configuration
|
|
9
|
+
* @returns The branch data
|
|
10
|
+
*/
|
|
11
|
+
export declare function setupProject(files: FileToUpload[], options: TranslateFlags, settings: Settings): Promise<{
|
|
12
|
+
branchData: BranchData;
|
|
13
|
+
}>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { logErrorAndExit } from '../console/logging.js';
|
|
2
|
+
import { gt } from '../utils/gt.js';
|
|
3
|
+
import { UploadStep } from './UploadStep.js';
|
|
4
|
+
import { SetupStep } from './SetupStep.js';
|
|
5
|
+
import { BranchStep } from './BranchStep.js';
|
|
6
|
+
import { logCollectedFiles } from '../console/logging.js';
|
|
7
|
+
/**
|
|
8
|
+
* Helper: Calculate timeout with validation
|
|
9
|
+
*/
|
|
10
|
+
function calculateTimeout(timeout) {
|
|
11
|
+
const value = timeout !== undefined ? Number(timeout) : 600;
|
|
12
|
+
return (Number.isFinite(value) ? value : 600) * 1000;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Sets up a project by uploading files running the setup step
|
|
16
|
+
* @param files - Array of file objects to upload
|
|
17
|
+
* @param options - The options for the API call
|
|
18
|
+
* @param settings - Settings configuration
|
|
19
|
+
* @returns The branch data
|
|
20
|
+
*/
|
|
21
|
+
export async function setupProject(files, options, settings) {
|
|
22
|
+
try {
|
|
23
|
+
// Log files to be translated
|
|
24
|
+
logCollectedFiles(files);
|
|
25
|
+
// Calculate timeout for setup step
|
|
26
|
+
const timeoutMs = calculateTimeout(options.timeout);
|
|
27
|
+
// Create workflow with steps
|
|
28
|
+
const branchStep = new BranchStep(gt, settings);
|
|
29
|
+
const uploadStep = new UploadStep(gt, settings);
|
|
30
|
+
const setupStep = new SetupStep(gt, settings, timeoutMs);
|
|
31
|
+
// first run the branch step
|
|
32
|
+
const branchData = await branchStep.run();
|
|
33
|
+
await branchStep.wait();
|
|
34
|
+
if (!branchData) {
|
|
35
|
+
return logErrorAndExit('Failed to resolve git branch information.');
|
|
36
|
+
}
|
|
37
|
+
// then run the upload step
|
|
38
|
+
const uploadedFiles = await uploadStep.run({ files, branchData });
|
|
39
|
+
await uploadStep.wait();
|
|
40
|
+
// then run the setup step
|
|
41
|
+
await setupStep.run(uploadedFiles, options.force ?? false);
|
|
42
|
+
await setupStep.wait();
|
|
43
|
+
return { branchData };
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
return logErrorAndExit('Failed to run project setup. ' + error);
|
|
47
|
+
}
|
|
48
|
+
}
|
package/dist/workflow/stage.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { logErrorAndExit } from '../console/logging.js';
|
|
3
|
-
import { logger } from '../console/logger.js';
|
|
1
|
+
import { logCollectedFiles, logErrorAndExit } from '../console/logging.js';
|
|
4
2
|
import { gt } from '../utils/gt.js';
|
|
5
|
-
import { TEMPLATE_FILE_NAME } from '../cli/commands/stage.js';
|
|
6
3
|
import { UploadStep } from './UploadStep.js';
|
|
7
4
|
import { SetupStep } from './SetupStep.js';
|
|
8
5
|
import { EnqueueStep } from './EnqueueStep.js';
|
|
@@ -15,21 +12,6 @@ function calculateTimeout(timeout) {
|
|
|
15
12
|
const value = timeout !== undefined ? Number(timeout) : 600;
|
|
16
13
|
return (Number.isFinite(value) ? value : 600) * 1000;
|
|
17
14
|
}
|
|
18
|
-
/**
|
|
19
|
-
* Helper: Log files to be translated
|
|
20
|
-
*/
|
|
21
|
-
function logFilesToTranslate(files) {
|
|
22
|
-
logger.message(chalk.cyan('Files found in project:') +
|
|
23
|
-
'\n' +
|
|
24
|
-
files
|
|
25
|
-
.map((file) => {
|
|
26
|
-
if (file.fileName === TEMPLATE_FILE_NAME) {
|
|
27
|
-
return `- <React Elements>`;
|
|
28
|
-
}
|
|
29
|
-
return `- ${file.fileName}`;
|
|
30
|
-
})
|
|
31
|
-
.join('\n'));
|
|
32
|
-
}
|
|
33
15
|
/**
|
|
34
16
|
* Sends multiple files for translation to the API using a workflow pattern
|
|
35
17
|
* @param files - Array of file objects to translate
|
|
@@ -40,7 +22,7 @@ function logFilesToTranslate(files) {
|
|
|
40
22
|
export async function stageFiles(files, options, settings) {
|
|
41
23
|
try {
|
|
42
24
|
// Log files to be translated
|
|
43
|
-
|
|
25
|
+
logCollectedFiles(files);
|
|
44
26
|
// Calculate timeout for setup step
|
|
45
27
|
const timeoutMs = calculateTimeout(options.timeout);
|
|
46
28
|
// Create workflow with steps
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gtx-cli",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.9",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"bin": "dist/main.js",
|
|
6
6
|
"files": [
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
"unified": "^11.0.5",
|
|
94
94
|
"unist-util-visit": "^5.0.0",
|
|
95
95
|
"yaml": "^2.8.0",
|
|
96
|
-
"generaltranslation": "8.0.
|
|
96
|
+
"generaltranslation": "8.0.3"
|
|
97
97
|
},
|
|
98
98
|
"devDependencies": {
|
|
99
99
|
"@babel/types": "^7.28.4",
|