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.
Files changed (59) hide show
  1. package/dist/api/checkFileTranslations.d.ts +4 -1
  2. package/dist/api/checkFileTranslations.js +35 -32
  3. package/dist/api/downloadFile.d.ts +9 -0
  4. package/dist/api/downloadFile.js +74 -0
  5. package/dist/api/downloadFileBatch.d.ts +0 -1
  6. package/dist/api/fetchTranslations.d.ts +7 -0
  7. package/dist/api/fetchTranslations.js +18 -0
  8. package/dist/api/sendFiles.d.ts +13 -2
  9. package/dist/api/sendFiles.js +8 -15
  10. package/dist/api/sendUpdates.d.ts +19 -0
  11. package/dist/api/sendUpdates.js +48 -0
  12. package/dist/api/waitForUpdates.d.ts +9 -0
  13. package/dist/api/waitForUpdates.js +89 -0
  14. package/dist/cli/base.d.ts +17 -5
  15. package/dist/cli/base.js +75 -48
  16. package/dist/cli/next.js +1 -0
  17. package/dist/cli/react.d.ts +5 -2
  18. package/dist/cli/react.js +153 -13
  19. package/dist/config/generateSettings.js +6 -11
  20. package/dist/console/index.d.ts +0 -1
  21. package/dist/console/index.js +0 -1
  22. package/dist/console/logging.d.ts +0 -1
  23. package/dist/console/logging.js +0 -3
  24. package/dist/formats/files/fileMapping.d.ts +1 -2
  25. package/dist/formats/files/fileMapping.js +0 -6
  26. package/dist/formats/files/translate.d.ts +13 -4
  27. package/dist/formats/files/translate.js +142 -30
  28. package/dist/formats/files/upload.js +75 -1
  29. package/dist/formats/gt/save.d.ts +2 -1
  30. package/dist/formats/gt/save.js +5 -2
  31. package/dist/fs/config/setupConfig.d.ts +0 -1
  32. package/dist/fs/config/setupConfig.js +0 -1
  33. package/dist/fs/config/updateConfig.d.ts +2 -1
  34. package/dist/fs/config/updateConfig.js +1 -1
  35. package/dist/fs/copyFile.d.ts +2 -1
  36. package/dist/translation/parse.d.ts +2 -2
  37. package/dist/translation/parse.js +6 -4
  38. package/dist/translation/stage.d.ts +5 -2
  39. package/dist/translation/stage.js +55 -13
  40. package/dist/translation/translate.d.ts +2 -0
  41. package/dist/translation/translate.js +18 -0
  42. package/dist/types/index.d.ts +4 -27
  43. package/dist/utils/flattenJsonFiles.d.ts +2 -2
  44. package/dist/utils/localizeStaticImports.d.ts +2 -2
  45. package/dist/utils/localizeStaticUrls.d.ts +6 -2
  46. package/dist/utils/localizeStaticUrls.js +119 -96
  47. package/package.json +2 -2
  48. package/dist/cli/commands/stage.d.ts +0 -5
  49. package/dist/cli/commands/stage.js +0 -100
  50. package/dist/cli/commands/translate.d.ts +0 -6
  51. package/dist/cli/commands/translate.js +0 -54
  52. package/dist/cli/flags.d.ts +0 -3
  53. package/dist/cli/flags.js +0 -37
  54. package/dist/fs/config/updateVersions.d.ts +0 -10
  55. package/dist/fs/config/updateVersions.js +0 -30
  56. package/dist/types/files.d.ts +0 -1
  57. package/dist/types/files.js +0 -1
  58. package/dist/utils/hash.d.ts +0 -6
  59. 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.setupTranslateCommand();
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
- setupStageCommand() {
48
- attachTranslateFlags(this.program
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')).action(async (initOptions) => {
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 this.handleTranslate(initOptions);
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/en/docs/next/guides/local-tx'
240
- : '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
+ ? '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(`Make sure to add a loadTranslations function to your app configuration to correctly use local translations.
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
@@ -8,6 +8,7 @@ export class NextCLI extends ReactCLI {
8
8
  init() {
9
9
  this.setupStageCommand();
10
10
  this.setupTranslateCommand();
11
+ this.setupScanCommand();
11
12
  this.setupGenerateSourceCommand();
12
13
  this.setupValidateCommand();
13
14
  }
@@ -1,5 +1,5 @@
1
1
  import { Command } from 'commander';
2
- import { Options, SupportedFrameworks, WrapOptions, SupportedLibraries, TranslateFlags } from '../types/index.js';
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 handleGenerateSourceCommand(initOptions: TranslateFlags): Promise<void>;
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 { aggregateReactTranslations } from '../translation/stage.js';
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
- import { attachAdditionalReactTranslateFlags, attachTranslateFlags, } from './flags.js';
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
- attachAdditionalReactTranslateFlags(attachTranslateFlags(this.program
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.'))).action(async (options) => {
38
- displayHeader('Staging project for translation with approval required...');
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
- attachAdditionalReactTranslateFlags(attachTranslateFlags(this.program
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.'))).action(async (options) => {
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
- attachAdditionalReactTranslateFlags(attachTranslateFlags(this.program
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.'))).action(async (initOptions) => {
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(initOptions);
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 updates = await aggregateReactTranslations(initOptions, settings, this.library === 'gt-next' ? 'gt-next' : 'gt-react');
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
- const mergedOptions = { ...gtConfig, ...options };
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.options = {
115
- ...(mergedOptions.options || {}),
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({
@@ -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.";
@@ -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, }: {
@@ -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): FileMapping;
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 { FileToTranslate } from '../../types/data.js';
3
- export declare const SUPPORTED_DATA_FORMATS: string[];
4
- export declare function aggregateFiles(settings: Settings): Promise<FileToTranslate[]>;
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>;