gtx-cli 2.1.5-alpha.3 → 2.1.5-alpha.5
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/dist/api/checkFileTranslations.d.ts +4 -1
- package/dist/api/checkFileTranslations.js +35 -32
- package/dist/api/downloadFile.d.ts +9 -0
- package/dist/api/downloadFile.js +74 -0
- package/dist/api/downloadFileBatch.d.ts +0 -1
- package/dist/api/fetchTranslations.d.ts +7 -0
- package/dist/api/fetchTranslations.js +18 -0
- package/dist/api/sendFiles.d.ts +13 -2
- package/dist/api/sendFiles.js +8 -15
- package/dist/api/sendUpdates.d.ts +19 -0
- package/dist/api/sendUpdates.js +48 -0
- package/dist/api/waitForUpdates.d.ts +9 -0
- package/dist/api/waitForUpdates.js +89 -0
- package/dist/cli/base.d.ts +17 -5
- package/dist/cli/base.js +75 -48
- package/dist/cli/next.js +1 -0
- package/dist/cli/react.d.ts +5 -2
- package/dist/cli/react.js +153 -13
- package/dist/config/generateSettings.js +6 -11
- package/dist/console/index.d.ts +0 -1
- package/dist/console/index.js +0 -1
- package/dist/console/logging.d.ts +0 -1
- package/dist/console/logging.js +0 -3
- package/dist/formats/files/fileMapping.d.ts +1 -2
- package/dist/formats/files/fileMapping.js +0 -6
- package/dist/formats/files/translate.d.ts +13 -4
- package/dist/formats/files/translate.js +142 -30
- package/dist/formats/files/upload.js +75 -1
- package/dist/formats/gt/save.d.ts +2 -1
- package/dist/formats/gt/save.js +5 -2
- package/dist/fs/config/setupConfig.d.ts +0 -1
- package/dist/fs/config/setupConfig.js +0 -1
- package/dist/fs/config/updateConfig.d.ts +2 -1
- package/dist/fs/config/updateConfig.js +1 -1
- package/dist/fs/copyFile.d.ts +2 -1
- package/dist/translation/parse.d.ts +2 -2
- package/dist/translation/parse.js +6 -4
- package/dist/translation/stage.d.ts +5 -2
- package/dist/translation/stage.js +55 -13
- package/dist/translation/translate.d.ts +2 -0
- package/dist/translation/translate.js +18 -0
- package/dist/types/index.d.ts +4 -27
- package/dist/utils/flattenJsonFiles.d.ts +2 -2
- package/dist/utils/localizeStaticImports.d.ts +2 -2
- package/dist/utils/localizeStaticUrls.d.ts +6 -2
- package/dist/utils/localizeStaticUrls.js +119 -96
- package/package.json +2 -2
- package/dist/cli/commands/stage.d.ts +0 -5
- package/dist/cli/commands/stage.js +0 -100
- package/dist/cli/commands/translate.d.ts +0 -6
- package/dist/cli/commands/translate.js +0 -54
- package/dist/cli/flags.d.ts +0 -3
- package/dist/cli/flags.js +0 -37
- package/dist/fs/config/updateVersions.d.ts +0 -10
- package/dist/fs/config/updateVersions.js +0 -30
- package/dist/types/files.d.ts +0 -1
- package/dist/types/files.js +0 -1
- package/dist/utils/hash.d.ts +0 -6
- package/dist/utils/hash.js +0 -11
package/dist/cli/base.js
CHANGED
|
@@ -5,6 +5,7 @@ import path from 'node:path';
|
|
|
5
5
|
import fs from 'node:fs';
|
|
6
6
|
import { generateSettings } from '../config/generateSettings.js';
|
|
7
7
|
import chalk from 'chalk';
|
|
8
|
+
import { translateFiles } from '../formats/files/translate.js';
|
|
8
9
|
import { FILE_EXT_TO_EXT_LABEL } from '../formats/files/supportedFiles.js';
|
|
9
10
|
import { handleSetupReactCommand } from '../setup/wizard.js';
|
|
10
11
|
import { isPackageInstalled, searchForPackageJson, } from '../utils/packageJson.js';
|
|
@@ -13,11 +14,11 @@ import { installPackage } from '../utils/installPackage.js';
|
|
|
13
14
|
import { getPackageManager } from '../utils/packageManager.js';
|
|
14
15
|
import { retrieveCredentials, setCredentials } from '../utils/credentials.js';
|
|
15
16
|
import { areCredentialsSet } from '../utils/credentials.js';
|
|
17
|
+
import localizeStaticUrls from '../utils/localizeStaticUrls.js';
|
|
18
|
+
import flattenJsonFiles from '../utils/flattenJsonFiles.js';
|
|
19
|
+
import localizeStaticImports from '../utils/localizeStaticImports.js';
|
|
20
|
+
import copyFile from '../fs/copyFile.js';
|
|
16
21
|
import { upload } from '../formats/files/upload.js';
|
|
17
|
-
import { attachTranslateFlags } from './flags.js';
|
|
18
|
-
import { handleStage } from './commands/stage.js';
|
|
19
|
-
import { handleDownload, handleTranslate, postProcessTranslations, } from './commands/translate.js';
|
|
20
|
-
import updateConfig from '../fs/config/updateConfig.js';
|
|
21
22
|
export class BaseCLI {
|
|
22
23
|
library;
|
|
23
24
|
additionalModules;
|
|
@@ -35,7 +36,7 @@ export class BaseCLI {
|
|
|
35
36
|
}
|
|
36
37
|
// Init is never called in a child class
|
|
37
38
|
init() {
|
|
38
|
-
this.
|
|
39
|
+
this.setupGTCommand();
|
|
39
40
|
}
|
|
40
41
|
// Execute is called by the main program
|
|
41
42
|
execute() {
|
|
@@ -44,49 +45,28 @@ export class BaseCLI {
|
|
|
44
45
|
process.argv.push('init');
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
.command('stage')
|
|
50
|
-
.description('Submits the project to the General Translation API for translation. Translations created using this command will require human approval.')).action(async (initOptions) => {
|
|
51
|
-
displayHeader('Staging project for translation with approval required...');
|
|
52
|
-
await this.handleStage(initOptions);
|
|
53
|
-
endCommand('Done!');
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
setupTranslateCommand() {
|
|
57
|
-
attachTranslateFlags(this.program
|
|
48
|
+
setupGTCommand() {
|
|
49
|
+
this.program
|
|
58
50
|
.command('translate')
|
|
59
|
-
.description('Translate your project using General Translation')
|
|
51
|
+
.description('Translate your project using General Translation')
|
|
52
|
+
.option('-c, --config <path>', 'Filepath to config file, by default gt.config.json', findFilepath(['gt.config.json']))
|
|
53
|
+
.option('--api-key <key>', 'API key for General Translation cloud service')
|
|
54
|
+
.option('--project-id <id>', 'Project ID for the translation service')
|
|
55
|
+
.option('--default-language, --default-locale <locale>', 'Default locale (e.g., en)')
|
|
56
|
+
.option('--new, --locales <locales...>', 'Space-separated list of locales (e.g., en fr es)')
|
|
57
|
+
.option('--dry-run', 'Dry run, does not send updates to General Translation API', false)
|
|
58
|
+
.option('--experimental-localize-static-urls', 'Triggering this will run a script after the cli tool that localizes all urls in content files. Currently only supported for md and mdx files.', false)
|
|
59
|
+
.option('--experimental-hide-default-locale', 'When localizing static locales, hide the default locale from the path', false)
|
|
60
|
+
.option('--experimental-flatten-json-files', 'Triggering this will flatten the json files into a single file. This is useful for projects that have a lot of json files.', false)
|
|
61
|
+
.option('--experimental-localize-static-imports', 'Triggering this will run a script after the cli tool that localizes all static imports in content files. Currently only supported for md and mdx files.', false)
|
|
62
|
+
.action(async (initOptions) => {
|
|
60
63
|
displayHeader('Starting translation...');
|
|
61
|
-
await
|
|
64
|
+
const settings = await generateSettings(initOptions);
|
|
65
|
+
const options = { ...initOptions, ...settings };
|
|
66
|
+
await this.handleGenericTranslate(options);
|
|
62
67
|
endCommand('Done!');
|
|
63
68
|
});
|
|
64
69
|
}
|
|
65
|
-
async handleStage(initOptions) {
|
|
66
|
-
const settings = await generateSettings(initOptions);
|
|
67
|
-
if (!settings.stageTranslations) {
|
|
68
|
-
// Update settings.stageTranslations to true
|
|
69
|
-
settings.stageTranslations = true;
|
|
70
|
-
await updateConfig({
|
|
71
|
-
configFilepath: settings.config,
|
|
72
|
-
stageTranslations: true,
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
await handleStage(initOptions, settings, this.library, true);
|
|
76
|
-
}
|
|
77
|
-
async handleTranslate(initOptions) {
|
|
78
|
-
const settings = await generateSettings(initOptions);
|
|
79
|
-
if (!settings.stageTranslations) {
|
|
80
|
-
const results = await handleStage(initOptions, settings, this.library, false);
|
|
81
|
-
if (results) {
|
|
82
|
-
await handleTranslate(initOptions, settings, results);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
await handleDownload(initOptions, settings);
|
|
87
|
-
}
|
|
88
|
-
await postProcessTranslations(settings);
|
|
89
|
-
}
|
|
90
70
|
setupUploadCommand() {
|
|
91
71
|
this.program
|
|
92
72
|
.command('upload')
|
|
@@ -217,6 +197,55 @@ See the docs for more information: https://generaltranslation.com/docs/react/tut
|
|
|
217
197
|
// Process all file types at once with a single call
|
|
218
198
|
await upload(sourceFiles, placeholderPaths, transformPaths, dataFormat, settings);
|
|
219
199
|
}
|
|
200
|
+
async handleGenericTranslate(settings) {
|
|
201
|
+
// dataFormat for JSONs
|
|
202
|
+
let dataFormat;
|
|
203
|
+
if (this.library === 'next-intl') {
|
|
204
|
+
dataFormat = 'ICU';
|
|
205
|
+
}
|
|
206
|
+
else if (this.library === 'i18next') {
|
|
207
|
+
if (this.additionalModules.includes('i18next-icu')) {
|
|
208
|
+
dataFormat = 'ICU';
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
dataFormat = 'I18NEXT';
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
dataFormat = 'JSX';
|
|
216
|
+
}
|
|
217
|
+
if (!settings.files ||
|
|
218
|
+
(Object.keys(settings.files.placeholderPaths).length === 1 &&
|
|
219
|
+
settings.files.placeholderPaths.gt)) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const { resolvedPaths: sourceFiles, placeholderPaths, transformPaths, } = settings.files;
|
|
223
|
+
// Localize static urls in default locale BEFORE translation
|
|
224
|
+
if (settings.experimentalLocalizeStaticUrls) {
|
|
225
|
+
await localizeStaticUrls(settings, [settings.defaultLocale]);
|
|
226
|
+
}
|
|
227
|
+
// Process all file types at once with a single call
|
|
228
|
+
await translateFiles(sourceFiles, placeholderPaths, transformPaths, dataFormat, settings);
|
|
229
|
+
// Localize static urls in other locales AFTER translation
|
|
230
|
+
if (settings.experimentalLocalizeStaticUrls) {
|
|
231
|
+
const otherLocales = settings.locales.filter((locale) => locale !== settings.defaultLocale);
|
|
232
|
+
if (otherLocales.length > 0) {
|
|
233
|
+
await localizeStaticUrls(settings, otherLocales);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
// Localize static imports (/docs -> /[locale]/docs)
|
|
237
|
+
if (settings.experimentalLocalizeStaticImports) {
|
|
238
|
+
await localizeStaticImports(settings);
|
|
239
|
+
}
|
|
240
|
+
// Flatten json files into a single file
|
|
241
|
+
if (settings.experimentalFlattenJsonFiles) {
|
|
242
|
+
await flattenJsonFiles(settings);
|
|
243
|
+
}
|
|
244
|
+
// Copy files to the target locale
|
|
245
|
+
if (settings.options?.copyFiles) {
|
|
246
|
+
await copyFile(settings);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
220
249
|
async handleSetupReactCommand(options) {
|
|
221
250
|
await handleSetupReactCommand(options);
|
|
222
251
|
}
|
|
@@ -236,14 +265,13 @@ See the docs for more information: https://generaltranslation.com/docs/react/tut
|
|
|
236
265
|
const usingCDN = isUsingGT
|
|
237
266
|
? await promptConfirm({
|
|
238
267
|
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
|
|
239
|
-
? 'https://generaltranslation.com/
|
|
240
|
-
: 'https://generaltranslation.com/
|
|
268
|
+
? 'https://generaltranslation.com/docs/next/reference/local-tx'
|
|
269
|
+
: 'https://generaltranslation.com/docs/react/reference/local-tx'} for more information.\nIf you answer no, we'll configure the CLI tool to download completed translations.`,
|
|
241
270
|
defaultValue: true,
|
|
242
271
|
})
|
|
243
272
|
: false;
|
|
244
273
|
if (isUsingGT && !usingCDN) {
|
|
245
|
-
logMessage(`
|
|
246
|
-
See https://generaltranslation.com/en/docs/next/guides/local-tx`);
|
|
274
|
+
logMessage(`To prevent translations from being published, please disable the project setting on the dashboard: ${chalk.cyan('https://dash.generaltranslation.com/settings/project')}`);
|
|
247
275
|
}
|
|
248
276
|
// Ask where the translations are stored
|
|
249
277
|
const translationsDir = isUsingGT && !usingCDN
|
|
@@ -292,7 +320,6 @@ See https://generaltranslation.com/en/docs/next/guides/local-tx`);
|
|
|
292
320
|
defaultLocale,
|
|
293
321
|
locales,
|
|
294
322
|
files: Object.keys(files).length > 0 ? files : undefined,
|
|
295
|
-
publish: isUsingGT && usingCDN,
|
|
296
323
|
});
|
|
297
324
|
logSuccess(`Feel free to edit ${chalk.cyan(configFilepath)} to customize your translation setup. Docs: https://generaltranslation.com/docs/cli/reference/config`);
|
|
298
325
|
// Install gtx-cli if not installed
|
package/dist/cli/next.js
CHANGED
package/dist/cli/react.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import { Options, SupportedFrameworks, WrapOptions,
|
|
2
|
+
import { Options, SupportedFrameworks, WrapOptions, GenerateSourceOptions, SupportedLibraries } from '../types/index.js';
|
|
3
3
|
import { BaseCLI } from './base.js';
|
|
4
4
|
export declare class ReactCLI extends BaseCLI {
|
|
5
5
|
constructor(command: Command, library: 'gt-react' | 'gt-next', additionalModules?: SupportedLibraries[]);
|
|
@@ -12,7 +12,10 @@ export declare class ReactCLI extends BaseCLI {
|
|
|
12
12
|
protected setupTranslateCommand(): void;
|
|
13
13
|
protected setupValidateCommand(): void;
|
|
14
14
|
protected setupGenerateSourceCommand(): void;
|
|
15
|
-
protected
|
|
15
|
+
protected setupScanCommand(): void;
|
|
16
|
+
protected handleGenerateSourceCommand(initOptions: GenerateSourceOptions): Promise<void>;
|
|
16
17
|
protected handleScanCommand(options: WrapOptions): Promise<void>;
|
|
18
|
+
protected handleStage(initOptions: Options): Promise<void>;
|
|
19
|
+
protected handleTranslate(initOptions: Options): Promise<void>;
|
|
17
20
|
protected handleValidate(initOptions: Options, files?: string[]): Promise<void>;
|
|
18
21
|
}
|
package/dist/cli/react.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { displayHeader, endCommand, logError, logStep, logSuccess, logWarning, promptConfirm, } from '../console/logging.js';
|
|
1
|
+
import { displayHeader, endCommand, logError, logErrorAndExit, logStep, logSuccess, logWarning, promptConfirm, } from '../console/logging.js';
|
|
2
2
|
import loadJSON from '../fs/loadJSON.js';
|
|
3
3
|
import findFilepath from '../fs/findFilepath.js';
|
|
4
4
|
import chalk from 'chalk';
|
|
@@ -8,12 +8,15 @@ import { wrapContentReact } from '../react/parse/wrapContent.js';
|
|
|
8
8
|
import { generateSettings } from '../config/generateSettings.js';
|
|
9
9
|
import { saveJSON } from '../fs/saveJSON.js';
|
|
10
10
|
import { resolveLocaleFiles } from '../fs/config/parseFilesConfig.js';
|
|
11
|
-
import { noFilesError } from '../console/index.js';
|
|
12
|
-
import {
|
|
11
|
+
import { noFilesError, noVersionIdError } from '../console/index.js';
|
|
12
|
+
import { stageProject } from '../translation/stage.js';
|
|
13
|
+
import { createUpdates } from '../translation/parse.js';
|
|
14
|
+
import { translate } from '../translation/translate.js';
|
|
15
|
+
import updateConfig from '../fs/config/updateConfig.js';
|
|
13
16
|
import { validateConfigExists } from '../config/validateSettings.js';
|
|
14
17
|
import { validateProject } from '../translation/validate.js';
|
|
15
18
|
import { intro } from '@clack/prompts';
|
|
16
|
-
|
|
19
|
+
const DEFAULT_TIMEOUT = 600;
|
|
17
20
|
const pkg = 'gt-react';
|
|
18
21
|
export class ReactCLI extends BaseCLI {
|
|
19
22
|
constructor(command, library, additionalModules) {
|
|
@@ -22,6 +25,7 @@ export class ReactCLI extends BaseCLI {
|
|
|
22
25
|
init() {
|
|
23
26
|
this.setupStageCommand();
|
|
24
27
|
this.setupTranslateCommand();
|
|
28
|
+
this.setupScanCommand();
|
|
25
29
|
this.setupGenerateSourceCommand();
|
|
26
30
|
this.setupValidateCommand();
|
|
27
31
|
}
|
|
@@ -32,18 +36,50 @@ export class ReactCLI extends BaseCLI {
|
|
|
32
36
|
return wrapContentReact(options, pkg, framework, errors, warnings);
|
|
33
37
|
}
|
|
34
38
|
setupStageCommand() {
|
|
35
|
-
|
|
39
|
+
this.program
|
|
36
40
|
.command('stage')
|
|
37
|
-
.description('Submits the project to the General Translation API for translation. Translations created using this command will require human approval.')
|
|
38
|
-
|
|
41
|
+
.description('Submits the project to the General Translation API for translation. Translations created using this command will require human approval.')
|
|
42
|
+
.option('-c, --config <path>', 'Filepath to config file, by default gt.config.json', findFilepath(['gt.config.json']))
|
|
43
|
+
.option('--api-key <key>', 'API key for General Translation cloud service')
|
|
44
|
+
.option('--project-id <id>', 'Project ID for the translation service')
|
|
45
|
+
.option('--version-id <id>', 'Version ID for the translation service')
|
|
46
|
+
.option('--tsconfig, --jsconfig <path>', 'Path to jsconfig or tsconfig file', findFilepath(['./tsconfig.json', './jsconfig.json']))
|
|
47
|
+
.option('--dictionary <path>', 'Path to dictionary file')
|
|
48
|
+
.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}'")
|
|
49
|
+
.option('--default-language, --default-locale <locale>', 'Default locale (e.g., en)')
|
|
50
|
+
.option('--new, --locales <locales...>', 'Space-separated list of locales (e.g., en fr es)')
|
|
51
|
+
.option('--inline', 'Include inline <T> tags in addition to dictionary file', true)
|
|
52
|
+
.option('--ignore-errors', 'Ignore errors encountered while scanning for <T> tags', false)
|
|
53
|
+
.option('--dry-run', 'Dry run, does not send updates to General Translation API', false)
|
|
54
|
+
.option('--timeout <seconds>', 'Timeout in seconds for waiting for updates to be deployed to the CDN', DEFAULT_TIMEOUT.toString())
|
|
55
|
+
.action(async (options) => {
|
|
56
|
+
displayHeader('Staging project for translation with approval...');
|
|
39
57
|
await this.handleStage(options);
|
|
40
58
|
endCommand('Done!');
|
|
41
59
|
});
|
|
42
60
|
}
|
|
43
61
|
setupTranslateCommand() {
|
|
44
|
-
|
|
62
|
+
this.program
|
|
45
63
|
.command('translate')
|
|
46
|
-
.description('Scans the project for a dictionary and/or <T> tags, and sends the updates to the General Translation API for translation.')
|
|
64
|
+
.description('Scans the project for a dictionary and/or <T> tags, and sends the updates to the General Translation API for translation.')
|
|
65
|
+
.option('-c, --config <path>', 'Filepath to config file, by default gt.config.json', findFilepath(['gt.config.json']))
|
|
66
|
+
.option('--api-key <key>', 'API key for General Translation cloud service')
|
|
67
|
+
.option('--project-id <id>', 'Project ID for the translation service')
|
|
68
|
+
.option('--version-id <id>', 'Version ID for the translation service')
|
|
69
|
+
.option('--tsconfig, --jsconfig <path>', 'Path to jsconfig or tsconfig file', findFilepath(['./tsconfig.json', './jsconfig.json']))
|
|
70
|
+
.option('--dictionary <path>', 'Path to dictionary file')
|
|
71
|
+
.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}'")
|
|
72
|
+
.option('--default-language, --default-locale <locale>', 'Default locale (e.g., en)')
|
|
73
|
+
.option('--new, --locales <locales...>', 'Space-separated list of locales (e.g., en fr es)')
|
|
74
|
+
.option('--inline', 'Include inline <T> tags in addition to dictionary file', true)
|
|
75
|
+
.option('--ignore-errors', 'Ignore errors encountered while scanning for <T> tags', false)
|
|
76
|
+
.option('--dry-run', 'Dry run, does not send updates to General Translation API', false)
|
|
77
|
+
.option('--timeout <seconds>', 'Timeout in seconds for waiting for updates to be deployed to the CDN', DEFAULT_TIMEOUT.toString())
|
|
78
|
+
.option('--experimental-localize-static-urls', 'Triggering this will run a script after the cli tool that localizes all urls in content files. Currently only supported for md and mdx files.', false)
|
|
79
|
+
.option('--experimental-hide-default-locale', 'When localizing static locales, hide the default locale from the path', false)
|
|
80
|
+
.option('--experimental-flatten-json-files', 'Triggering this will flatten the json files into a single file. This is useful for projects that have a lot of json files.', false)
|
|
81
|
+
.option('--experimental-localize-static-imports', 'Triggering this will run a script after the cli tool that localizes all static imports in content files. Currently only supported for md and mdx files.', false)
|
|
82
|
+
.action(async (options) => {
|
|
47
83
|
displayHeader('Translating project...');
|
|
48
84
|
await this.handleTranslate(options);
|
|
49
85
|
endCommand('Done!');
|
|
@@ -66,17 +102,79 @@ export class ReactCLI extends BaseCLI {
|
|
|
66
102
|
});
|
|
67
103
|
}
|
|
68
104
|
setupGenerateSourceCommand() {
|
|
69
|
-
|
|
105
|
+
this.program
|
|
70
106
|
.command('generate')
|
|
71
|
-
.description('Generate a translation file for the source locale. This command should be used if you are handling your own translations.')
|
|
107
|
+
.description('Generate a translation file for the source locale. The -t flag must be provided. This command should be used if you are handling your own translations.')
|
|
108
|
+
.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}'")
|
|
109
|
+
.option('--tsconfig, --jsconfig <path>', 'Path to jsconfig or tsconfig file', findFilepath(['./tsconfig.json', './jsconfig.json']))
|
|
110
|
+
.option('--dictionary <path>', 'Path to dictionary file')
|
|
111
|
+
.option('--default-language, --default-locale <locale>', 'Source locale (e.g., en)')
|
|
112
|
+
.option('--inline', 'Include inline <T> tags in addition to dictionary file', true)
|
|
113
|
+
.option('--ignore-errors', 'Ignore errors encountered while scanning for <T> tags', false)
|
|
114
|
+
.option('--suppress-warnings', 'Suppress warnings encountered while scanning for <T> tags', false)
|
|
115
|
+
.option('-t, --translations-dir, --translation-dir <path>', 'Path to directory where translations will be saved. If this flag is not provided, translations will not be saved locally.')
|
|
116
|
+
.action(async (options) => {
|
|
72
117
|
displayHeader('Generating source templates...');
|
|
73
|
-
await this.handleGenerateSourceCommand(
|
|
118
|
+
await this.handleGenerateSourceCommand(options);
|
|
119
|
+
endCommand('Done!');
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
setupScanCommand() {
|
|
123
|
+
this.program
|
|
124
|
+
.command('scan')
|
|
125
|
+
.description('Scans the project and wraps all JSX elements in the src directory with a <T> tag, with unique ids')
|
|
126
|
+
.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}'")
|
|
127
|
+
.option('-c, --config <path>', 'Filepath to config file, by default gt.config.json', findFilepath(['gt.config.json']))
|
|
128
|
+
.option('--disable-ids', 'Disable id generation for the <T> tags', false)
|
|
129
|
+
.option('--disable-formatting', 'Disable formatting of edited files', false)
|
|
130
|
+
.option('--skip-ts', 'Skip wrapping <T> tags in TypeScript files', false)
|
|
131
|
+
.action(async (options) => {
|
|
132
|
+
displayHeader('Scanning project...');
|
|
133
|
+
await this.handleScanCommand(options);
|
|
74
134
|
endCommand('Done!');
|
|
75
135
|
});
|
|
76
136
|
}
|
|
77
137
|
async handleGenerateSourceCommand(initOptions) {
|
|
78
138
|
const settings = await generateSettings(initOptions);
|
|
79
|
-
const
|
|
139
|
+
const options = { ...initOptions, ...settings };
|
|
140
|
+
if (!options.dictionary) {
|
|
141
|
+
options.dictionary = findFilepath([
|
|
142
|
+
'./dictionary.js',
|
|
143
|
+
'./src/dictionary.js',
|
|
144
|
+
'./dictionary.json',
|
|
145
|
+
'./src/dictionary.json',
|
|
146
|
+
'./dictionary.ts',
|
|
147
|
+
'./src/dictionary.ts',
|
|
148
|
+
]);
|
|
149
|
+
}
|
|
150
|
+
// User has to provide a dictionary file
|
|
151
|
+
// will not read from settings.files.resolvedPaths.json
|
|
152
|
+
const { updates, errors, warnings } = await createUpdates(options, options.dictionary, this.library === 'gt-next' ? 'gt-next' : 'gt-react', false);
|
|
153
|
+
if (warnings.length > 0) {
|
|
154
|
+
if (options.suppressWarnings) {
|
|
155
|
+
logWarning(chalk.yellow(`CLI tool encountered ${warnings.length} warnings while scanning for translatable content. ${chalk.gray('To view these warnings, re-run without the --suppress-warnings flag')}`));
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
logWarning(chalk.yellow(`CLI tool encountered ${warnings.length} warnings while scanning for translatable content. ${chalk.gray('To suppress these warnings, re-run with --suppress-warnings')}\n` +
|
|
159
|
+
warnings
|
|
160
|
+
.map((warning) => chalk.yellow('• Warning: ') + chalk.white(warning))
|
|
161
|
+
.join('\n')));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (errors.length > 0) {
|
|
165
|
+
if (options.ignoreErrors) {
|
|
166
|
+
logWarning(chalk.yellow(`CLI tool encountered errors while scanning for translatable content. These components will not be translated.\n` +
|
|
167
|
+
errors
|
|
168
|
+
.map((error) => chalk.yellow('• Warning: ') + chalk.white(error))
|
|
169
|
+
.join('\n')));
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
logErrorAndExit(chalk.red(`CLI tool encountered errors while scanning for translatable content. ${chalk.gray('To ignore these errors, re-run with --ignore-errors')}\n` +
|
|
173
|
+
errors
|
|
174
|
+
.map((error) => chalk.red('• Error: ') + chalk.white(error))
|
|
175
|
+
.join('\n')));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
80
178
|
// Convert updates to the proper data format
|
|
81
179
|
const newData = {};
|
|
82
180
|
for (const update of updates) {
|
|
@@ -157,6 +255,48 @@ export class ReactCLI extends BaseCLI {
|
|
|
157
255
|
.join('\n'));
|
|
158
256
|
}
|
|
159
257
|
}
|
|
258
|
+
async handleStage(initOptions) {
|
|
259
|
+
const settings = await generateSettings(initOptions);
|
|
260
|
+
// First run the base class's handleTranslate method
|
|
261
|
+
const options = { ...initOptions, ...settings };
|
|
262
|
+
if (!settings.stageTranslations) {
|
|
263
|
+
// Update settings.stageTranslations to true
|
|
264
|
+
settings.stageTranslations = true;
|
|
265
|
+
await updateConfig({
|
|
266
|
+
configFilepath: options.config,
|
|
267
|
+
stageTranslations: true,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
const pkg = this.library === 'gt-next' ? 'gt-next' : 'gt-react';
|
|
271
|
+
await stageProject(options, pkg);
|
|
272
|
+
}
|
|
273
|
+
async handleTranslate(initOptions) {
|
|
274
|
+
const settings = await generateSettings(initOptions);
|
|
275
|
+
// First run the base class's handleTranslate method
|
|
276
|
+
const options = { ...initOptions, ...settings };
|
|
277
|
+
try {
|
|
278
|
+
await super.handleGenericTranslate(options);
|
|
279
|
+
// If the base class's handleTranslate completes successfully, continue with ReactCLI-specific code
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
// Continue with ReactCLI-specific code even if base handleTranslate failed
|
|
283
|
+
}
|
|
284
|
+
if (!settings.stageTranslations) {
|
|
285
|
+
// If stageTranslations is false, stage the project
|
|
286
|
+
const pkg = this.library === 'gt-next' ? 'gt-next' : 'gt-react';
|
|
287
|
+
const results = await stageProject(options, pkg);
|
|
288
|
+
if (results) {
|
|
289
|
+
await translate(options, results.versionId);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
if (!settings._versionId) {
|
|
294
|
+
logError(noVersionIdError);
|
|
295
|
+
process.exit(1);
|
|
296
|
+
}
|
|
297
|
+
await translate(options, settings._versionId);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
160
300
|
async handleValidate(initOptions, files) {
|
|
161
301
|
validateConfigExists();
|
|
162
302
|
const settings = await generateSettings(initOptions);
|
|
@@ -76,14 +76,9 @@ export async function generateSettings(options, cwd = process.cwd()) {
|
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
// merge options
|
|
79
|
-
|
|
80
|
-
// Add defaultLocale if not provided
|
|
81
|
-
mergedOptions.defaultLocale =
|
|
82
|
-
mergedOptions.defaultLocale || libraryDefaultLocale;
|
|
79
|
+
let mergedOptions = { ...gtConfig, ...options };
|
|
83
80
|
// merge locales
|
|
84
81
|
mergedOptions.locales = Array.from(new Set([...(gtConfig.locales || []), ...(options.locales || [])]));
|
|
85
|
-
// Separate defaultLocale from locales
|
|
86
|
-
mergedOptions.locales = mergedOptions.locales.filter((locale) => locale !== mergedOptions.defaultLocale);
|
|
87
82
|
// Add apiKey if not provided
|
|
88
83
|
mergedOptions.apiKey = mergedOptions.apiKey || process.env.GT_API_KEY;
|
|
89
84
|
// Add projectId if not provided
|
|
@@ -92,6 +87,9 @@ export async function generateSettings(options, cwd = process.cwd()) {
|
|
|
92
87
|
mergedOptions.baseUrl = mergedOptions.baseUrl || defaultBaseUrl;
|
|
93
88
|
// Add dashboardUrl if not provided
|
|
94
89
|
mergedOptions.dashboardUrl = mergedOptions.dashboardUrl || GT_DASHBOARD_URL;
|
|
90
|
+
// Add defaultLocale if not provided
|
|
91
|
+
mergedOptions.defaultLocale =
|
|
92
|
+
mergedOptions.defaultLocale || libraryDefaultLocale;
|
|
95
93
|
// Add locales if not provided
|
|
96
94
|
mergedOptions.locales = mergedOptions.locales || [];
|
|
97
95
|
// Add default config file name if not provided
|
|
@@ -103,16 +101,14 @@ export async function generateSettings(options, cwd = process.cwd()) {
|
|
|
103
101
|
// Add stageTranslations if not provided
|
|
104
102
|
// For human review, always stage the project
|
|
105
103
|
mergedOptions.stageTranslations = mergedOptions.stageTranslations ?? false;
|
|
106
|
-
// Add publish if not provided
|
|
107
|
-
mergedOptions.publish = mergedOptions.publish ?? false;
|
|
108
104
|
// Populate src if not provided
|
|
109
105
|
mergedOptions.src = mergedOptions.src || DEFAULT_SRC_PATTERNS;
|
|
110
106
|
// Resolve all glob patterns in the files object
|
|
111
107
|
mergedOptions.files = mergedOptions.files
|
|
112
108
|
? resolveFiles(mergedOptions.files, mergedOptions.defaultLocale, mergedOptions.locales, cwd)
|
|
113
109
|
: undefined;
|
|
114
|
-
mergedOptions
|
|
115
|
-
...
|
|
110
|
+
mergedOptions = {
|
|
111
|
+
...mergedOptions,
|
|
116
112
|
experimentalLocalizeStaticImports: gtConfig.options?.experimentalLocalizeStaticImports ||
|
|
117
113
|
options.experimentalLocalizeStaticImports,
|
|
118
114
|
experimentalLocalizeStaticUrls: gtConfig.options?.experimentalLocalizeStaticUrls ||
|
|
@@ -157,7 +153,6 @@ export async function generateSettings(options, cwd = process.cwd()) {
|
|
|
157
153
|
framework: mergedOptions.framework,
|
|
158
154
|
});
|
|
159
155
|
}
|
|
160
|
-
mergedOptions.configDirectory = path.join(cwd, '.gt');
|
|
161
156
|
validateSettings(mergedOptions);
|
|
162
157
|
// Set up GT instance
|
|
163
158
|
gt.setConfig({
|
package/dist/console/index.d.ts
CHANGED
|
@@ -18,4 +18,3 @@ export declare const noApiKeyError = "No API key found! Please provide an API ke
|
|
|
18
18
|
export declare const devApiKeyError = "You are using a development API key. Please use a production API key to use the General Translation API.\nYou can generate a production API key with the command: npx gtx-cli auth -t production";
|
|
19
19
|
export declare const noProjectIdError = "No project ID found! Please provide a project ID using the --project-id flag, specify it in your gt.config.json file, or set the GT_PROJECT_ID environment variable.";
|
|
20
20
|
export declare const noVersionIdError = "No version ID found! Please provide a version ID using the --version-id flag or specify it in your gt.config.json file as the _versionId property.";
|
|
21
|
-
export declare const invalidConfigurationError = "Invalid files configuration! Please either provide a valid configuration to download local translations or set the --publish flag to true to upload translations to the CDN.";
|
package/dist/console/index.js
CHANGED
|
@@ -21,4 +21,3 @@ export const noApiKeyError = `No API key found! Please provide an API key using
|
|
|
21
21
|
export const devApiKeyError = `You are using a development API key. Please use a production API key to use the General Translation API.\nYou can generate a production API key with the command: npx gtx-cli auth -t production`;
|
|
22
22
|
export const noProjectIdError = `No project ID found! Please provide a project ID using the --project-id flag, specify it in your gt.config.json file, or set the GT_PROJECT_ID environment variable.`;
|
|
23
23
|
export const noVersionIdError = `No version ID found! Please provide a version ID using the --version-id flag or specify it in your gt.config.json file as the _versionId property.`;
|
|
24
|
-
export const invalidConfigurationError = `Invalid files configuration! Please either provide a valid configuration to download local translations or set the --publish flag to true to upload translations to the CDN.`;
|
|
@@ -13,7 +13,6 @@ export declare function displayProjectId(projectId: string): void;
|
|
|
13
13
|
export declare function displayResolvedPaths(resolvedPaths: [string, string][]): void;
|
|
14
14
|
export declare function displayCreatedConfigFile(configFilepath: string): void;
|
|
15
15
|
export declare function displayUpdatedConfigFile(configFilepath: string): void;
|
|
16
|
-
export declare function displayUpdatedVersionsFile(versionFilepath: string): void;
|
|
17
16
|
export declare function createSpinner(indicator?: 'dots' | 'timer'): import("@clack/prompts").SpinnerResult;
|
|
18
17
|
export declare function createOraSpinner(indicator?: 'dots' | 'circleHalves'): Promise<import("ora").Ora>;
|
|
19
18
|
export declare function promptText({ message, defaultValue, validate, }: {
|
package/dist/console/logging.js
CHANGED
|
@@ -73,9 +73,6 @@ export function displayCreatedConfigFile(configFilepath) {
|
|
|
73
73
|
export function displayUpdatedConfigFile(configFilepath) {
|
|
74
74
|
log.success(`Updated config file ${chalk.cyan(configFilepath)}`);
|
|
75
75
|
}
|
|
76
|
-
export function displayUpdatedVersionsFile(versionFilepath) {
|
|
77
|
-
log.success(`Updated versions file ${chalk.cyan(versionFilepath)}`);
|
|
78
|
-
}
|
|
79
76
|
// Spinner functionality
|
|
80
77
|
export function createSpinner(indicator = 'timer') {
|
|
81
78
|
return spinner({ indicator });
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { ResolvedFiles, TransformFiles } from '../../types/index.js';
|
|
2
|
-
import { FileMapping } from '../../types/files.js';
|
|
3
2
|
/**
|
|
4
3
|
* Creates a mapping between source files and their translated counterparts for each locale
|
|
5
4
|
* @param filePaths - Resolved file paths for different file types
|
|
@@ -8,4 +7,4 @@ import { FileMapping } from '../../types/files.js';
|
|
|
8
7
|
* @param locales - List of locales to create a mapping for
|
|
9
8
|
* @returns A mapping between source files and their translated counterparts for each locale, in the form of relative paths
|
|
10
9
|
*/
|
|
11
|
-
export declare function createFileMapping(filePaths: ResolvedFiles, placeholderPaths: ResolvedFiles, transformPaths: TransformFiles, targetLocales: string[], defaultLocale: string):
|
|
10
|
+
export declare function createFileMapping(filePaths: ResolvedFiles, placeholderPaths: ResolvedFiles, transformPaths: TransformFiles, targetLocales: string[], defaultLocale: string): Record<string, Record<string, string>>;
|
|
@@ -4,7 +4,6 @@ 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 '../../cli/commands/stage.js';
|
|
8
7
|
/**
|
|
9
8
|
* Creates a mapping between source files and their translated counterparts for each locale
|
|
10
9
|
* @param filePaths - Resolved file paths for different file types
|
|
@@ -19,11 +18,6 @@ export function createFileMapping(filePaths, placeholderPaths, transformPaths, t
|
|
|
19
18
|
const translatedPaths = resolveLocaleFiles(placeholderPaths, locale);
|
|
20
19
|
const localeMapping = {};
|
|
21
20
|
// Process each file type
|
|
22
|
-
// Start with GTJSON Template files
|
|
23
|
-
if (translatedPaths.gt) {
|
|
24
|
-
const filepath = translatedPaths.gt;
|
|
25
|
-
localeMapping[TEMPLATE_FILE_NAME] = filepath;
|
|
26
|
-
}
|
|
27
21
|
for (const typeIndex of SUPPORTED_FILE_EXTENSIONS) {
|
|
28
22
|
if (!filePaths[typeIndex] || !translatedPaths[typeIndex])
|
|
29
23
|
continue;
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import { Settings } from '../../types/index.js';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { ResolvedFiles, Settings, TransformFiles } from '../../types/index.js';
|
|
2
|
+
import { DataFormat } from '../../types/data.js';
|
|
3
|
+
import { TranslateOptions } from '../../cli/base.js';
|
|
4
|
+
/**
|
|
5
|
+
* Sends multiple files to the API for translation
|
|
6
|
+
* @param filePaths - Resolved file paths for different file types
|
|
7
|
+
* @param placeholderPaths - Placeholder paths for translated files
|
|
8
|
+
* @param transformPaths - Transform paths for file naming
|
|
9
|
+
* @param dataFormat - Format of the data within the files
|
|
10
|
+
* @param options - Translation options including API settings
|
|
11
|
+
* @returns Promise that resolves when translation is complete
|
|
12
|
+
*/
|
|
13
|
+
export declare function translateFiles(filePaths: ResolvedFiles, placeholderPaths: ResolvedFiles, transformPaths: TransformFiles, dataFormat: DataFormat | undefined, options: Settings & TranslateOptions): Promise<void>;
|