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
@@ -20,4 +20,7 @@ export declare function checkFileTranslations(data: {
20
20
  versionId: string;
21
21
  fileName: string;
22
22
  };
23
- }, locales: string[], timeoutDuration: number, resolveOutputPath: (sourcePath: string, locale: string) => string | null, options: Settings): Promise<boolean>;
23
+ }, locales: string[], timeoutDuration: number, resolveOutputPath: (sourcePath: string, locale: string) => string, downloadStatus: {
24
+ downloaded: Set<string>;
25
+ failed: Set<string>;
26
+ }, options: Settings): Promise<boolean>;
@@ -1,9 +1,9 @@
1
1
  import chalk from 'chalk';
2
2
  import { createOraSpinner, logError } from '../console/logging.js';
3
3
  import { getLocaleProperties } from 'generaltranslation';
4
+ import { downloadFile } from './downloadFile.js';
4
5
  import { downloadFileBatch } from './downloadFileBatch.js';
5
6
  import { gt } from '../utils/gt.js';
6
- import { TEMPLATE_FILE_NAME } from '../cli/commands/stage.js';
7
7
  /**
8
8
  * Checks the status of translations for a given version ID
9
9
  * @param apiKey - The API key for the General Translation API
@@ -14,18 +14,13 @@ import { TEMPLATE_FILE_NAME } from '../cli/commands/stage.js';
14
14
  * @param timeoutDuration - The timeout duration for the wait in seconds
15
15
  * @returns True if all translations are deployed, false otherwise
16
16
  */
17
- export async function checkFileTranslations(data, locales, timeoutDuration, resolveOutputPath, options) {
17
+ export async function checkFileTranslations(data, locales, timeoutDuration, resolveOutputPath, downloadStatus, options) {
18
18
  const startTime = Date.now();
19
19
  console.log();
20
20
  const spinner = await createOraSpinner();
21
21
  spinner.start('Waiting for translation...');
22
22
  // Initialize the query data
23
23
  const fileQueryData = prepareFileQueryData(data, locales);
24
- const downloadStatus = {
25
- downloaded: new Set(),
26
- failed: new Set(),
27
- skipped: new Set(),
28
- };
29
24
  // Do first check immediately
30
25
  const initialCheck = await checkTranslationDeployment(fileQueryData, downloadStatus, spinner, resolveOutputPath, options);
31
26
  if (initialCheck) {
@@ -151,8 +146,7 @@ function generateStatusSuffixText(downloadStatus, fileQueryData) {
151
146
  localeStatuses.push(chalk.yellow(`${pendingCodes}`));
152
147
  }
153
148
  // Format the line
154
- const prettyFileName = fileName === TEMPLATE_FILE_NAME ? '<React Elements>' : fileName;
155
- newSuffixText.push(`${chalk.bold(prettyFileName)} [${localeStatuses.join(', ')}]`);
149
+ newSuffixText.push(`${chalk.bold(fileName)} [${localeStatuses.join(', ')}]`);
156
150
  }
157
151
  // If we couldn't show all files, add an indicator
158
152
  if (filesArray.length > maxFilesToShow) {
@@ -167,8 +161,7 @@ async function checkTranslationDeployment(fileQueryData, downloadStatus, spinner
167
161
  try {
168
162
  // Only query for files that haven't been downloaded yet
169
163
  const currentQueryData = fileQueryData.filter((item) => !downloadStatus.downloaded.has(`${item.fileName}:${item.locale}`) &&
170
- !downloadStatus.failed.has(`${item.fileName}:${item.locale}`) &&
171
- !downloadStatus.skipped.has(`${item.fileName}:${item.locale}`));
164
+ !downloadStatus.failed.has(`${item.fileName}:${item.locale}`));
172
165
  // If all files have been downloaded, we're done
173
166
  if (currentQueryData.length === 0) {
174
167
  return true;
@@ -180,17 +173,11 @@ async function checkTranslationDeployment(fileQueryData, downloadStatus, spinner
180
173
  const readyTranslations = translations.filter((translation) => translation.isReady && translation.fileName);
181
174
  if (readyTranslations.length > 0) {
182
175
  // Prepare batch download data
183
- const batchFiles = readyTranslations
184
- .map((translation) => {
176
+ const batchFiles = readyTranslations.map((translation) => {
185
177
  const locale = translation.locale;
186
178
  const fileName = translation.fileName;
187
179
  const translationId = translation.id;
188
180
  const outputPath = resolveOutputPath(fileName, locale);
189
- // Skip downloading GTJSON files that are not in the files configuration
190
- if (outputPath === null) {
191
- downloadStatus.skipped.add(`${fileName}:${locale}`);
192
- return null;
193
- }
194
181
  return {
195
182
  translationId,
196
183
  inputPath: fileName,
@@ -198,28 +185,44 @@ async function checkTranslationDeployment(fileQueryData, downloadStatus, spinner
198
185
  locale,
199
186
  fileLocale: `${fileName}:${locale}`,
200
187
  };
201
- })
202
- .filter((file) => file !== null);
203
- const batchResult = await downloadFileBatch(batchFiles, options);
204
- // Process results
205
- batchFiles.forEach((file) => {
206
- const { translationId, fileLocale } = file;
207
- if (batchResult.successful.includes(translationId)) {
208
- downloadStatus.downloaded.add(fileLocale);
188
+ });
189
+ // Use batch download if there are multiple files
190
+ if (batchFiles.length > 1) {
191
+ const batchResult = await downloadFileBatch(batchFiles.map(({ translationId, outputPath, inputPath, locale }) => ({
192
+ translationId,
193
+ outputPath,
194
+ inputPath,
195
+ locale,
196
+ })), options);
197
+ // Process results
198
+ batchFiles.forEach((file) => {
199
+ const { translationId, fileLocale } = file;
200
+ if (batchResult.successful.includes(translationId)) {
201
+ downloadStatus.downloaded.add(fileLocale);
202
+ }
203
+ else if (batchResult.failed.includes(translationId)) {
204
+ downloadStatus.failed.add(fileLocale);
205
+ }
206
+ });
207
+ }
208
+ else if (batchFiles.length === 1) {
209
+ // For a single file, use the original downloadFile method
210
+ const file = batchFiles[0];
211
+ const result = await downloadFile(file.translationId, file.outputPath, file.inputPath, file.locale, options);
212
+ if (result) {
213
+ downloadStatus.downloaded.add(file.fileLocale);
209
214
  }
210
- else if (batchResult.failed.includes(translationId)) {
211
- downloadStatus.failed.add(fileLocale);
215
+ else {
216
+ downloadStatus.failed.add(file.fileLocale);
212
217
  }
213
- });
218
+ }
214
219
  }
215
220
  // Force a refresh of the spinner display
216
221
  const statusText = generateStatusSuffixText(downloadStatus, fileQueryData);
217
222
  // Clear and reapply the suffix to force a refresh
218
223
  spinner.text = statusText;
219
224
  // If all files have been downloaded, we're done
220
- if (downloadStatus.downloaded.size +
221
- downloadStatus.failed.size +
222
- downloadStatus.skipped.size ===
225
+ if (downloadStatus.downloaded.size + downloadStatus.failed.size ===
223
226
  fileQueryData.length) {
224
227
  return true;
225
228
  }
@@ -0,0 +1,9 @@
1
+ import { Settings } from '../types/index.js';
2
+ /**
3
+ * Downloads a file from the API and saves it to a local directory
4
+ * @param translationId - The ID of the translation to download
5
+ * @param outputPath - The path to save the file to
6
+ * @param maxRetries - The maximum number of retries to attempt
7
+ * @param retryDelay - The delay between retries in milliseconds
8
+ */
9
+ export declare function downloadFile(translationId: string, outputPath: string, inputPath: string, locale: string, options: Settings, maxRetries?: number, retryDelay?: number): Promise<boolean>;
@@ -0,0 +1,74 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { logError } from '../console/logging.js';
4
+ import { gt } from '../utils/gt.js';
5
+ import { validateJsonSchema } from '../formats/json/utils.js';
6
+ import { mergeJson } from '../formats/json/mergeJson.js';
7
+ import { TextDecoder } from 'node:util';
8
+ import mergeYaml from '../formats/yaml/mergeYaml.js';
9
+ import { validateYamlSchema } from '../formats/yaml/utils.js';
10
+ /**
11
+ * Downloads a file from the API and saves it to a local directory
12
+ * @param translationId - The ID of the translation to download
13
+ * @param outputPath - The path to save the file to
14
+ * @param maxRetries - The maximum number of retries to attempt
15
+ * @param retryDelay - The delay between retries in milliseconds
16
+ */
17
+ export async function downloadFile(translationId, outputPath, inputPath, locale, options, maxRetries = 3, retryDelay = 1000) {
18
+ let retries = 0;
19
+ while (retries <= maxRetries) {
20
+ try {
21
+ // Get the file data as an ArrayBuffer
22
+ const fileData = await gt.downloadFile(translationId);
23
+ // Ensure the directory exists
24
+ const dir = path.dirname(outputPath);
25
+ if (!fs.existsSync(dir)) {
26
+ fs.mkdirSync(dir, { recursive: true });
27
+ }
28
+ let data = new TextDecoder().decode(fileData);
29
+ if (options.options?.jsonSchema && locale) {
30
+ const jsonSchema = validateJsonSchema(options.options, inputPath);
31
+ if (jsonSchema) {
32
+ const originalContent = fs.readFileSync(inputPath, 'utf8');
33
+ if (originalContent) {
34
+ data = mergeJson(originalContent, inputPath, options.options, [
35
+ {
36
+ translatedContent: data,
37
+ targetLocale: locale,
38
+ },
39
+ ], options.defaultLocale)[0];
40
+ }
41
+ }
42
+ }
43
+ if (options.options?.yamlSchema && locale) {
44
+ const yamlSchema = validateYamlSchema(options.options, inputPath);
45
+ if (yamlSchema) {
46
+ const originalContent = fs.readFileSync(inputPath, 'utf8');
47
+ if (originalContent) {
48
+ data = mergeYaml(originalContent, inputPath, options.options, [
49
+ {
50
+ translatedContent: data,
51
+ targetLocale: locale,
52
+ },
53
+ ])[0];
54
+ }
55
+ }
56
+ }
57
+ // Write the file to disk
58
+ await fs.promises.writeFile(outputPath, data);
59
+ return true;
60
+ }
61
+ catch (error) {
62
+ // If we've retried too many times, log an error and return false
63
+ if (retries >= maxRetries) {
64
+ logError(`Error downloading file ${outputPath} after ${maxRetries + 1} attempts: ` +
65
+ error);
66
+ return false;
67
+ }
68
+ // Increment retry counter and wait before next attempt
69
+ retries++;
70
+ await new Promise((resolve) => setTimeout(resolve, retryDelay));
71
+ }
72
+ }
73
+ return false;
74
+ }
@@ -4,7 +4,6 @@ export type BatchedFiles = Array<{
4
4
  outputPath: string;
5
5
  inputPath: string;
6
6
  locale: string;
7
- fileLocale: string;
8
7
  }>;
9
8
  export type DownloadFileBatchResult = {
10
9
  successful: string[];
@@ -0,0 +1,7 @@
1
+ import { RetrievedTranslations } from 'generaltranslation/types';
2
+ /**
3
+ * Fetches translations from the API and saves them to a local directory
4
+ * @param translationsDir - The directory to save the translations to
5
+ * @param fileType - The file type to save the translations as (file extension)
6
+ */
7
+ export declare function fetchTranslations(versionId: string): Promise<RetrievedTranslations>;
@@ -0,0 +1,18 @@
1
+ import chalk from 'chalk';
2
+ import { logError } from '../console/logging.js';
3
+ import { gt } from '../utils/gt.js';
4
+ /**
5
+ * Fetches translations from the API and saves them to a local directory
6
+ * @param translationsDir - The directory to save the translations to
7
+ * @param fileType - The file type to save the translations as (file extension)
8
+ */
9
+ export async function fetchTranslations(versionId) {
10
+ try {
11
+ const result = await gt.fetchTranslations(versionId);
12
+ return result.translations;
13
+ }
14
+ catch {
15
+ logError(chalk.red('Failed to fetch translations'));
16
+ return [];
17
+ }
18
+ }
@@ -1,5 +1,9 @@
1
- import { Settings, TranslateFlags } from '../types/index.js';
1
+ import { Settings } from '../types/index.js';
2
2
  import { CompletedFileTranslationData, FileToTranslate } from 'generaltranslation/types';
3
+ export type ApiOptions = Settings & {
4
+ publish: boolean;
5
+ wait: boolean;
6
+ };
3
7
  export type SendFilesResult = {
4
8
  data: Record<string, {
5
9
  fileName: string;
@@ -14,4 +18,11 @@ export type SendFilesResult = {
14
18
  * @param options - The options for the API call
15
19
  * @returns The translated content or version ID
16
20
  */
17
- export declare function sendFiles(files: FileToTranslate[], options: TranslateFlags, settings: Settings): Promise<SendFilesResult>;
21
+ export declare function sendFiles(files: FileToTranslate[], options: ApiOptions): Promise<{
22
+ data: Record<string, {
23
+ fileName: string;
24
+ versionId: string;
25
+ }>;
26
+ locales: string[];
27
+ translations: CompletedFileTranslationData[];
28
+ }>;
@@ -1,34 +1,27 @@
1
1
  import chalk from 'chalk';
2
2
  import { createSpinner, logMessage, logSuccess } from '../console/logging.js';
3
3
  import { gt } from '../utils/gt.js';
4
- import { TEMPLATE_FILE_NAME } from '../cli/commands/stage.js';
5
4
  /**
6
5
  * Sends multiple files for translation to the API
7
6
  * @param files - Array of file objects to translate
8
7
  * @param options - The options for the API call
9
8
  * @returns The translated content or version ID
10
9
  */
11
- export async function sendFiles(files, options, settings) {
10
+ export async function sendFiles(files, options) {
12
11
  logMessage(chalk.cyan('Files to translate:') +
13
12
  '\n' +
14
- files
15
- .map((file) => {
16
- if (file.fileName === TEMPLATE_FILE_NAME) {
17
- return `- <React Elements>`;
18
- }
19
- return `- ${file.fileName}`;
20
- })
21
- .join('\n'));
13
+ files.map((file) => ` - ${chalk.bold(file.fileName)}`).join('\n'));
22
14
  const spinner = createSpinner('dots');
23
15
  spinner.start(`Sending ${files.length} file${files.length !== 1 ? 's' : ''} to General Translation API...`);
24
16
  try {
25
17
  // Send the files to the API
26
18
  const responseData = await gt.enqueueFiles(files, {
27
- publish: settings.publish,
28
- sourceLocale: settings.defaultLocale,
29
- targetLocales: settings.locales,
30
- version: settings.version, // not set ATM
31
- modelProvider: settings.modelProvider,
19
+ publish: options.publish,
20
+ description: options.description,
21
+ sourceLocale: options.defaultLocale,
22
+ targetLocales: options.locales,
23
+ _versionId: options._versionId,
24
+ modelProvider: options.modelProvider,
32
25
  });
33
26
  // Handle version ID response (for async processing)
34
27
  const { data, message, locales, translations } = responseData;
@@ -0,0 +1,19 @@
1
+ import { Settings, SupportedLibraries, Updates } from '../types/index.js';
2
+ import { DataFormat } from '../types/data.js';
3
+ export type ApiOptions = Settings & {
4
+ timeout: string;
5
+ dataFormat: DataFormat;
6
+ description?: string;
7
+ requireApproval?: boolean;
8
+ };
9
+ export type SendUpdatesResult = {
10
+ versionId: string;
11
+ locales: string[];
12
+ };
13
+ /**
14
+ * Sends updates to the API
15
+ * @param updates - The updates to send
16
+ * @param options - The options for the API call
17
+ * @returns The versionId of the updated project
18
+ */
19
+ export declare function sendUpdates(updates: Updates, options: ApiOptions, library: SupportedLibraries): Promise<SendUpdatesResult>;
@@ -0,0 +1,48 @@
1
+ import chalk from 'chalk';
2
+ import { createSpinner, logSuccess, logWarning, } from '../console/logging.js';
3
+ import updateConfig from '../fs/config/updateConfig.js';
4
+ import { isUsingLocalTranslations } from '../config/utils.js';
5
+ import { gt } from '../utils/gt.js';
6
+ /**
7
+ * Sends updates to the API
8
+ * @param updates - The updates to send
9
+ * @param options - The options for the API call
10
+ * @returns The versionId of the updated project
11
+ */
12
+ export async function sendUpdates(updates, options, library) {
13
+ const spinner = createSpinner('dots');
14
+ spinner.start(`Sending ${library} updates to General Translation API...`);
15
+ try {
16
+ const responseData = await gt.enqueueEntries(updates, {
17
+ sourceLocale: options.defaultLocale,
18
+ targetLocales: options.locales,
19
+ dataFormat: options.dataFormat,
20
+ version: options.version,
21
+ description: options.description,
22
+ requireApproval: options.requireApproval,
23
+ modelProvider: options.modelProvider,
24
+ });
25
+ const { versionId, message, locales, projectSettings } = responseData;
26
+ spinner.stop(chalk.green('Sent updates'));
27
+ logSuccess(message);
28
+ if (isUsingLocalTranslations(options) && projectSettings.cdnEnabled) {
29
+ logWarning(chalk.yellow('Your project is configured to use the CDN, but you are also using local translations. Please disable one or the other.'));
30
+ }
31
+ else if (!isUsingLocalTranslations(options) &&
32
+ !projectSettings.cdnEnabled) {
33
+ logWarning(chalk.yellow('Your project is not using the CDN, nor are you using local translations. Please enable one or the other.'));
34
+ }
35
+ if (options.config) {
36
+ await updateConfig({
37
+ configFilepath: options.config,
38
+ _versionId: versionId,
39
+ locales,
40
+ });
41
+ }
42
+ return { versionId, locales };
43
+ }
44
+ catch (error) {
45
+ spinner.stop(chalk.red('Failed to send updates'));
46
+ throw error;
47
+ }
48
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Waits for translations to be deployed to the General Translation API
3
+ * @param versionId - The version ID of the project
4
+ * @param locales - The locales to wait for
5
+ * @param startTime - The start time of the wait
6
+ * @param timeoutDuration - The timeout duration for the wait
7
+ * @returns True if all translations are deployed, false otherwise
8
+ */
9
+ export declare const waitForUpdates: (versionId: string, startTime: number, timeoutDuration: number) => Promise<boolean>;
@@ -0,0 +1,89 @@
1
+ import chalk from 'chalk';
2
+ import { createOraSpinner, logErrorAndExit, } from '../console/logging.js';
3
+ import { getLocaleProperties } from 'generaltranslation';
4
+ import { gt } from '../utils/gt.js';
5
+ /**
6
+ * Waits for translations to be deployed to the General Translation API
7
+ * @param versionId - The version ID of the project
8
+ * @param locales - The locales to wait for
9
+ * @param startTime - The start time of the wait
10
+ * @param timeoutDuration - The timeout duration for the wait
11
+ * @returns True if all translations are deployed, false otherwise
12
+ */
13
+ export const waitForUpdates = async (versionId, startTime, timeoutDuration) => {
14
+ console.log();
15
+ const spinner = await createOraSpinner();
16
+ spinner.start('Waiting for translation...');
17
+ const checkDeployment = async () => {
18
+ let data;
19
+ try {
20
+ // get translation status
21
+ data = await gt.checkTranslationStatus(versionId);
22
+ }
23
+ catch {
24
+ return false;
25
+ }
26
+ // check if any locales are waiting for approval
27
+ const { availableLocales, locales, localesWaitingForApproval } = data;
28
+ if (localesWaitingForApproval.length > 0) {
29
+ spinner.stop();
30
+ logErrorAndExit(`Error! ${localesWaitingForApproval.length} translations are waiting for approval:\n${localesWaitingForApproval
31
+ .map((locale) => {
32
+ const localeProperties = getLocaleProperties(locale);
33
+ return `${localeProperties.name} (${localeProperties.code})`;
34
+ })
35
+ .join('\n')}\nPlease approve these locales in the General Translation dashboard, then re-run the command.`);
36
+ }
37
+ // check if all locales are available
38
+ if (availableLocales) {
39
+ availableLocales.forEach((locale) => {
40
+ if (!availableLocales.includes(locale)) {
41
+ availableLocales.push(locale);
42
+ }
43
+ });
44
+ const newSuffixText = [
45
+ chalk.green(`[${availableLocales.length}/${locales.length}]`) +
46
+ ` translations completed`,
47
+ ...availableLocales.map((locale) => {
48
+ const localeProperties = getLocaleProperties(locale);
49
+ return `Translation completed for ${chalk.green(localeProperties.name)} (${chalk.green(localeProperties.code)})`;
50
+ }),
51
+ ];
52
+ spinner.text = newSuffixText.join('\n');
53
+ }
54
+ // check if all locales are available
55
+ if (locales.every((locale) => availableLocales.includes(locale))) {
56
+ return true;
57
+ }
58
+ return false;
59
+ };
60
+ // Calculate time until next 5-second interval since startTime
61
+ const msUntilNextInterval = Math.max(0, 5000 - ((Date.now() - startTime) % 5000));
62
+ // Do first check immediately
63
+ const initialCheck = await checkDeployment();
64
+ if (initialCheck) {
65
+ spinner.succeed(chalk.green('All translations are live!'));
66
+ return true;
67
+ }
68
+ return new Promise((resolve) => {
69
+ let intervalCheck;
70
+ // Start the interval aligned with the original request time
71
+ setTimeout(() => {
72
+ intervalCheck = setInterval(async () => {
73
+ const isDeployed = await checkDeployment();
74
+ const elapsed = Date.now() - startTime;
75
+ if (isDeployed || elapsed >= timeoutDuration) {
76
+ clearInterval(intervalCheck);
77
+ if (isDeployed) {
78
+ spinner.succeed(chalk.green('All translations are live!'));
79
+ resolve(true);
80
+ }
81
+ else {
82
+ spinner.fail(chalk.red('Timed out waiting for translations'));
83
+ resolve(false);
84
+ }
85
+ }
86
+ }, 5000);
87
+ }, msUntilNextInterval);
88
+ });
89
+ };
@@ -1,11 +1,25 @@
1
1
  import { Command } from 'commander';
2
- import { Settings, SupportedLibraries, SetupOptions, TranslateFlags } from '../types/index.js';
2
+ import { Settings, SupportedLibraries, SetupOptions } from '../types/index.js';
3
3
  export type UploadOptions = {
4
4
  config?: string;
5
5
  apiKey?: string;
6
6
  projectId?: string;
7
7
  defaultLocale?: string;
8
8
  };
9
+ export type TranslateOptions = {
10
+ config?: string;
11
+ defaultLocale?: string;
12
+ locales?: string[];
13
+ apiKey?: string;
14
+ projectId?: string;
15
+ dryRun: boolean;
16
+ experimentalLocalizeStaticUrls?: boolean;
17
+ experimentalHideDefaultLocale?: boolean;
18
+ experimentalFlattenJsonFiles?: boolean;
19
+ experimentalLocalizeStaticImports?: boolean;
20
+ excludeStaticUrls?: string[];
21
+ excludeStaticImports?: string[];
22
+ };
9
23
  export type LoginOptions = {
10
24
  keyType?: 'development' | 'production';
11
25
  };
@@ -16,16 +30,14 @@ export declare class BaseCLI {
16
30
  constructor(program: Command, library: SupportedLibraries, additionalModules?: SupportedLibraries[]);
17
31
  init(): void;
18
32
  execute(): void;
19
- protected setupStageCommand(): void;
20
- protected setupTranslateCommand(): void;
21
- protected handleStage(initOptions: TranslateFlags): Promise<void>;
22
- protected handleTranslate(initOptions: TranslateFlags): Promise<void>;
33
+ protected setupGTCommand(): void;
23
34
  protected setupUploadCommand(): void;
24
35
  protected setupLoginCommand(): void;
25
36
  protected setupInitCommand(): void;
26
37
  protected setupConfigureCommand(): void;
27
38
  protected setupSetupCommand(): void;
28
39
  protected handleUploadCommand(settings: Settings & UploadOptions): Promise<void>;
40
+ protected handleGenericTranslate(settings: Settings & TranslateOptions): Promise<void>;
29
41
  protected handleSetupReactCommand(options: SetupOptions): Promise<void>;
30
42
  protected handleInitCommand(ranReactSetup: boolean): Promise<void>;
31
43
  protected handleLoginCommand(options: LoginOptions): Promise<void>;