gtx-cli 2.0.5 → 2.0.6-alpha.6

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 (40) hide show
  1. package/dist/api/checkFileTranslations.d.ts +6 -0
  2. package/dist/api/checkFileTranslations.js +49 -58
  3. package/dist/api/downloadFile.d.ts +8 -1
  4. package/dist/api/downloadFile.js +20 -28
  5. package/dist/api/downloadFileBatch.d.ts +9 -9
  6. package/dist/api/downloadFileBatch.js +45 -52
  7. package/dist/api/fetchTranslations.d.ts +2 -5
  8. package/dist/api/fetchTranslations.js +7 -19
  9. package/dist/api/sendFiles.d.ts +16 -19
  10. package/dist/api/sendFiles.js +9 -31
  11. package/dist/api/sendUpdates.d.ts +6 -6
  12. package/dist/api/sendUpdates.js +10 -33
  13. package/dist/api/waitForUpdates.d.ts +1 -3
  14. package/dist/api/waitForUpdates.js +39 -45
  15. package/dist/cli/base.d.ts +3 -0
  16. package/dist/cli/base.js +13 -0
  17. package/dist/cli/react.js +13 -11
  18. package/dist/config/generateSettings.js +8 -0
  19. package/dist/config/utils.d.ts +1 -1
  20. package/dist/config/utils.js +1 -1
  21. package/dist/formats/files/translate.js +2 -2
  22. package/dist/formats/gt/save.d.ts +1 -1
  23. package/dist/react/jsx/utils/parseJsx.d.ts +2 -2
  24. package/dist/react/jsx/utils/parseJsx.js +13 -10
  25. package/dist/react/parse/createInlineUpdates.d.ts +1 -0
  26. package/dist/react/parse/createInlineUpdates.js +3 -2
  27. package/dist/translation/parse.d.ts +1 -0
  28. package/dist/translation/parse.js +4 -2
  29. package/dist/translation/stage.js +12 -1
  30. package/dist/translation/translate.js +2 -2
  31. package/dist/translation/validate.js +9 -2
  32. package/dist/types/data.d.ts +1 -2
  33. package/dist/types/index.d.ts +3 -13
  34. package/dist/utils/flattenJsonFiles.d.ts +1 -1
  35. package/dist/utils/gt.d.ts +2 -0
  36. package/dist/utils/gt.js +2 -0
  37. package/dist/utils/localizeStaticUrls.d.ts +1 -1
  38. package/package.json +6 -6
  39. package/dist/types/api.d.ts +0 -6
  40. package/dist/types/api.js +0 -1
@@ -1,67 +1,61 @@
1
1
  import chalk from 'chalk';
2
2
  import { createOraSpinner, logErrorAndExit, } from '../console/logging.js';
3
3
  import { getLocaleProperties } from 'generaltranslation';
4
- import { getAuthHeaders } from '../utils/headers.js';
4
+ import { gt } from '../utils/gt.js';
5
5
  /**
6
6
  * Waits for translations to be deployed to the General Translation API
7
- * @param apiKey - The API key for the General Translation API
8
- * @param baseUrl - The base URL for the General Translation API
9
7
  * @param versionId - The version ID of the project
10
8
  * @param locales - The locales to wait for
11
9
  * @param startTime - The start time of the wait
12
10
  * @param timeoutDuration - The timeout duration for the wait
13
11
  * @returns True if all translations are deployed, false otherwise
14
12
  */
15
- export const waitForUpdates = async (projectId, apiKey, baseUrl, versionId, startTime, timeoutDuration) => {
13
+ export const waitForUpdates = async (versionId, startTime, timeoutDuration) => {
16
14
  console.log();
17
15
  const spinner = await createOraSpinner();
18
16
  spinner.start('Waiting for translation...');
19
17
  const checkDeployment = async () => {
18
+ let data;
20
19
  try {
21
- const response = await fetch(`${baseUrl}/v1/project/translations/status/${encodeURIComponent(versionId)}`, {
22
- method: 'GET',
23
- headers: {
24
- 'Content-Type': 'application/json',
25
- ...getAuthHeaders(projectId, apiKey),
26
- },
27
- });
28
- if (response.ok) {
29
- const data = await response.json();
30
- const { availableLocales, locales, localesWaitingForApproval } = data;
31
- if (localesWaitingForApproval.length > 0) {
32
- spinner.stop();
33
- logErrorAndExit(`Error! ${localesWaitingForApproval.length} translations are waiting for approval:\n${localesWaitingForApproval
34
- .map((locale) => {
35
- const localeProperties = getLocaleProperties(locale);
36
- return `${localeProperties.name} (${localeProperties.code})`;
37
- })
38
- .join('\n')}\nPlease approve these locales in the General Translation dashboard, then re-run the command.`);
39
- }
40
- if (availableLocales) {
41
- availableLocales.forEach((locale) => {
42
- if (!availableLocales.includes(locale)) {
43
- availableLocales.push(locale);
44
- }
45
- });
46
- const newSuffixText = [
47
- chalk.green(`[${availableLocales.length}/${locales.length}]`) +
48
- ` translations completed`,
49
- ...availableLocales.map((locale) => {
50
- const localeProperties = getLocaleProperties(locale);
51
- return `Translation completed for ${chalk.green(localeProperties.name)} (${chalk.green(localeProperties.code)})`;
52
- }),
53
- ];
54
- spinner.text = newSuffixText.join('\n');
55
- }
56
- if (locales.every((locale) => availableLocales.includes(locale))) {
57
- return true;
58
- }
59
- }
60
- return false;
20
+ // get translation status
21
+ data = await gt.checkTranslationStatus(versionId);
61
22
  }
62
- catch (error) {
23
+ catch {
63
24
  return false;
64
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;
65
59
  };
66
60
  // Calculate time until next 5-second interval since startTime
67
61
  const msUntilNextInterval = Math.max(0, 5000 - ((Date.now() - startTime) % 5000));
@@ -7,6 +7,9 @@ export type TranslateOptions = {
7
7
  apiKey?: string;
8
8
  projectId?: string;
9
9
  dryRun: boolean;
10
+ experimentalLocalizeStaticUrls?: boolean;
11
+ experimentalHideDefaultLocale?: boolean;
12
+ experimentalFlattenJsonFiles?: boolean;
10
13
  };
11
14
  export type LoginOptions = {
12
15
  keyType?: 'development' | 'production';
package/dist/cli/base.js CHANGED
@@ -14,6 +14,8 @@ import { installPackage } from '../utils/installPackage.js';
14
14
  import { getPackageManager } from '../utils/packageManager.js';
15
15
  import { retrieveCredentials, setCredentials } from '../utils/credentials.js';
16
16
  import { areCredentialsSet } from '../utils/credentials.js';
17
+ import localizeStaticUrls from '../utils/localizeStaticUrls.js';
18
+ import flattenJsonFiles from '../utils/flattenJsonFiles.js';
17
19
  export class BaseCLI {
18
20
  library;
19
21
  additionalModules;
@@ -49,6 +51,9 @@ export class BaseCLI {
49
51
  .option('--default-language, --default-locale <locale>', 'Default locale (e.g., en)')
50
52
  .option('--new, --locales <locales...>', 'Space-separated list of locales (e.g., en fr es)')
51
53
  .option('--dry-run', 'Dry run, does not send updates to General Translation API', false)
54
+ .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)
55
+ .option('--experimental-hide-default-locale', 'When localizing static locales, hide the default locale from the path', false)
56
+ .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)
52
57
  .action(async (initOptions) => {
53
58
  displayHeader('Starting translation...');
54
59
  const settings = await generateSettings(initOptions);
@@ -172,6 +177,14 @@ See the docs for more information: https://generaltranslation.com/docs/react/tut
172
177
  const { resolvedPaths: sourceFiles, placeholderPaths, transformPaths, } = settings.files;
173
178
  // Process all file types at once with a single call
174
179
  await translateFiles(sourceFiles, placeholderPaths, transformPaths, dataFormat, settings);
180
+ // Localize static urls (/docs -> /[locale]/docs)
181
+ if (settings.experimentalLocalizeStaticUrls) {
182
+ await localizeStaticUrls(settings);
183
+ }
184
+ // Flatten json files into a single file
185
+ if (settings.experimentalFlattenJsonFiles) {
186
+ await flattenJsonFiles(settings);
187
+ }
175
188
  }
176
189
  async handleSetupReactCommand(options) {
177
190
  await handleSetupReactCommand(options);
package/dist/cli/react.js CHANGED
@@ -16,8 +16,6 @@ import updateConfig from '../fs/config/updateConfig.js';
16
16
  import { validateConfigExists } from '../config/validateSettings.js';
17
17
  import { validateProject } from '../translation/validate.js';
18
18
  import { intro } from '@clack/prompts';
19
- import localizeStaticUrls from '../utils/localizeStaticUrls.js';
20
- import flattenJsonFiles from '../utils/flattenJsonFiles.js';
21
19
  const DEFAULT_TIMEOUT = 600;
22
20
  const pkg = 'gt-react';
23
21
  export class ReactCLI extends BaseCLI {
@@ -112,6 +110,7 @@ export class ReactCLI extends BaseCLI {
112
110
  .option('--default-language, --default-locale <locale>', 'Source locale (e.g., en)')
113
111
  .option('--inline', 'Include inline <T> tags in addition to dictionary file', true)
114
112
  .option('--ignore-errors', 'Ignore errors encountered while scanning for <T> tags', false)
113
+ .option('--suppress-warnings', 'Suppress warnings encountered while scanning for <T> tags', false)
115
114
  .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
115
  .action(async (options) => {
117
116
  displayHeader('Generating source templates...');
@@ -149,7 +148,18 @@ export class ReactCLI extends BaseCLI {
149
148
  }
150
149
  // User has to provide a dictionary file
151
150
  // will not read from settings.files.resolvedPaths.json
152
- const { updates, errors } = await createUpdates(options, options.dictionary, this.library === 'gt-next' ? 'gt-next' : 'gt-react', false);
151
+ const { updates, errors, warnings } = await createUpdates(options, options.dictionary, this.library === 'gt-next' ? 'gt-next' : 'gt-react', false);
152
+ if (warnings.length > 0) {
153
+ if (options.suppressWarnings) {
154
+ 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')}`));
155
+ }
156
+ else {
157
+ 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` +
158
+ warnings
159
+ .map((warning) => chalk.yellow('• Warning: ') + chalk.white(warning))
160
+ .join('\n')));
161
+ }
162
+ }
153
163
  if (errors.length > 0) {
154
164
  if (options.ignoreErrors) {
155
165
  logWarning(chalk.yellow(`CLI tool encountered errors while scanning for translatable content. These components will not be translated.\n` +
@@ -285,14 +295,6 @@ export class ReactCLI extends BaseCLI {
285
295
  }
286
296
  await translate(options, settings._versionId);
287
297
  }
288
- // Localize static urls (/docs -> /[locale]/docs)
289
- if (options.experimentalLocalizeStaticUrls) {
290
- await localizeStaticUrls(options);
291
- }
292
- // Flatten json files into a single file
293
- if (options.experimentalFlattenJsonFiles) {
294
- await flattenJsonFiles(options);
295
- }
296
298
  }
297
299
  async handleValidate(initOptions, files) {
298
300
  validateConfigExists();
@@ -10,6 +10,7 @@ import { resolveProjectId } from '../fs/utils.js';
10
10
  import path from 'node:path';
11
11
  import chalk from 'chalk';
12
12
  import { resolveConfig } from './resolveConfig.js';
13
+ import { gt } from '../utils/gt.js';
13
14
  export const DEFAULT_SRC_PATTERNS = [
14
15
  'src/**/*.{js,jsx,ts,tsx}',
15
16
  'app/**/*.{js,jsx,ts,tsx}',
@@ -101,5 +102,12 @@ export async function generateSettings(options, cwd = process.cwd()) {
101
102
  });
102
103
  }
103
104
  validateSettings(mergedOptions);
105
+ // Set up GT instance
106
+ gt.setConfig({
107
+ projectId: mergedOptions.projectId,
108
+ apiKey: mergedOptions.apiKey,
109
+ baseUrl: mergedOptions.baseUrl,
110
+ sourceLocale: mergedOptions.defaultLocale,
111
+ });
104
112
  return mergedOptions;
105
113
  }
@@ -1,2 +1,2 @@
1
1
  import { Settings } from '../types/index.js';
2
- export declare function isUsingLocalTranslations(settings: Settings): string | undefined;
2
+ export declare function isUsingLocalTranslations(settings: Settings): boolean;
@@ -1,4 +1,4 @@
1
1
  // returns true if the project is configured to use local translations
2
2
  export function isUsingLocalTranslations(settings) {
3
- return settings.files && settings.files.placeholderPaths.gt;
3
+ return !!(settings.files && settings.files.placeholderPaths.gt);
4
4
  }
@@ -182,7 +182,7 @@ async function processInitialTranslations(translations = [], fileMapping, option
182
182
  }
183
183
  // Use batch download if there are multiple files
184
184
  if (batchFiles.length > 1) {
185
- const batchResult = await downloadFileBatch(options.baseUrl, options.projectId, options.apiKey, batchFiles.map(({ translationId, outputPath }) => ({
185
+ const batchResult = await downloadFileBatch(batchFiles.map(({ translationId, outputPath }) => ({
186
186
  translationId,
187
187
  outputPath,
188
188
  })));
@@ -200,7 +200,7 @@ async function processInitialTranslations(translations = [], fileMapping, option
200
200
  else if (batchFiles.length === 1) {
201
201
  // For a single file, use the original downloadFile method
202
202
  const file = batchFiles[0];
203
- const result = await downloadFile(options.baseUrl, options.projectId, options.apiKey, file.translationId, file.outputPath);
203
+ const result = await downloadFile(file.translationId, file.outputPath);
204
204
  if (result) {
205
205
  downloadStatus.downloaded.add(file.fileLocale);
206
206
  }
@@ -1,4 +1,4 @@
1
- import { RetrievedTranslations } from '../../types/api.js';
1
+ import { RetrievedTranslations } from 'generaltranslation/types';
2
2
  import { ResolvedFiles } from '../../types/index.js';
3
3
  import { DataFormat } from '../../types/data.js';
4
4
  /**
@@ -10,7 +10,7 @@ import * as t from '@babel/types';
10
10
  * @param insideT - Whether the current node is inside a <T> component
11
11
  * @returns The built JSX tree
12
12
  */
13
- export declare function buildJSXTree(importAliases: Record<string, string>, node: any, unwrappedExpressions: string[], updates: Updates, errors: string[], file: string, insideT: boolean): {
13
+ export declare function buildJSXTree(importAliases: Record<string, string>, node: any, unwrappedExpressions: string[], updates: Updates, errors: string[], warnings: Set<string>, file: string, insideT: boolean): {
14
14
  expression?: boolean;
15
15
  result?: string;
16
16
  type?: string;
@@ -18,4 +18,4 @@ export declare function buildJSXTree(importAliases: Record<string, string>, node
18
18
  children?: any;
19
19
  };
20
20
  } | string | null;
21
- export declare function parseJSXElement(importAliases: Record<string, string>, node: t.JSXElement, updates: Updates, errors: string[], file: string): void;
21
+ export declare function parseJSXElement(importAliases: Record<string, string>, node: t.JSXElement, updates: Updates, errors: string[], warnings: Set<string>, file: string): void;
@@ -18,7 +18,7 @@ import { GT_ATTRIBUTES, mapAttributeName, VARIABLE_COMPONENTS, } from './constan
18
18
  * @param insideT - Whether the current node is inside a <T> component
19
19
  * @returns The built JSX tree
20
20
  */
21
- export function buildJSXTree(importAliases, node, unwrappedExpressions, updates, errors, file, insideT) {
21
+ export function buildJSXTree(importAliases, node, unwrappedExpressions, updates, errors, warnings, file, insideT) {
22
22
  if (t.isJSXExpressionContainer(node)) {
23
23
  // Skip JSX comments
24
24
  if (t.isJSXEmptyExpression(node.expression)) {
@@ -60,9 +60,8 @@ export function buildJSXTree(importAliases, node, unwrappedExpressions, updates,
60
60
  // Convert from alias to original name
61
61
  const componentType = importAliases[typeName ?? ''];
62
62
  if (componentType === 'T' && insideT) {
63
- // Add error: No nested <T> components are allowed
64
- errors.push(warnNestedTComponent(file, `${element.loc?.start?.line}:${element.loc?.start?.column}`));
65
- return null;
63
+ // Add warning: Nested <T> components are allowed, but they are advised against
64
+ warnings.add(warnNestedTComponent(file, `${element.loc?.start?.line}:${element.loc?.start?.column}`));
66
65
  }
67
66
  // If this JSXElement is one of the recognized variable components,
68
67
  const elementIsVariable = VARIABLE_COMPONENTS.includes(componentType);
@@ -86,14 +85,14 @@ export function buildJSXTree(importAliases, node, unwrappedExpressions, updates,
86
85
  unwrappedExpressions.push(generate(attr.value).code);
87
86
  }
88
87
  }
89
- attrValue = buildJSXTree(importAliases, attr.value.expression, unwrappedExpressions, updates, errors, file, true);
88
+ attrValue = buildJSXTree(importAliases, attr.value.expression, unwrappedExpressions, updates, errors, warnings, file, true);
90
89
  }
91
90
  }
92
91
  props[attrName] = attrValue;
93
92
  }
94
93
  });
95
94
  if (elementIsVariable) {
96
- parseJSXElement(importAliases, element, updates, errors, file);
95
+ parseJSXElement(importAliases, element, updates, errors, warnings, file);
97
96
  return {
98
97
  // if componentType is undefined, use typeName
99
98
  // Basically, if componentType is not a GT component, use typeName such as <div>
@@ -102,7 +101,7 @@ export function buildJSXTree(importAliases, node, unwrappedExpressions, updates,
102
101
  };
103
102
  }
104
103
  const children = element.children
105
- .map((child) => buildJSXTree(importAliases, child, unwrappedExpressions, updates, errors, file, true))
104
+ .map((child) => buildJSXTree(importAliases, child, unwrappedExpressions, updates, errors, warnings, file, true))
106
105
  .filter((child) => child !== null && child !== '');
107
106
  if (children.length === 1) {
108
107
  props.children = children[0];
@@ -120,7 +119,7 @@ export function buildJSXTree(importAliases, node, unwrappedExpressions, updates,
120
119
  // If it's a JSX fragment
121
120
  else if (t.isJSXFragment(node)) {
122
121
  const children = node.children
123
- .map((child) => buildJSXTree(importAliases, child, unwrappedExpressions, updates, errors, file, true))
122
+ .map((child) => buildJSXTree(importAliases, child, unwrappedExpressions, updates, errors, warnings, file, true))
124
123
  .filter((child) => child !== null && child !== '');
125
124
  const props = {};
126
125
  if (children.length === 1) {
@@ -153,7 +152,7 @@ export function buildJSXTree(importAliases, node, unwrappedExpressions, updates,
153
152
  }
154
153
  // end buildJSXTree
155
154
  // Parses a JSX element and adds it to the updates array
156
- export function parseJSXElement(importAliases, node, updates, errors, file) {
155
+ export function parseJSXElement(importAliases, node, updates, errors, warnings, file) {
157
156
  const openingElement = node.openingElement;
158
157
  const name = openingElement.name;
159
158
  // Only proceed if it's <T> ...
@@ -161,6 +160,7 @@ export function parseJSXElement(importAliases, node, updates, errors, file) {
161
160
  return;
162
161
  }
163
162
  const componentErrors = [];
163
+ const componentWarnings = new Set();
164
164
  const metadata = {};
165
165
  // We'll track this flag to know if any unwrapped {variable} is found in children
166
166
  const unwrappedExpressions = [];
@@ -203,7 +203,7 @@ export function parseJSXElement(importAliases, node, updates, errors, file) {
203
203
  }
204
204
  });
205
205
  // Build the JSX tree for this component
206
- const treeResult = buildJSXTree(importAliases, node, unwrappedExpressions, updates, componentErrors, file, false);
206
+ const treeResult = buildJSXTree(importAliases, node, unwrappedExpressions, updates, componentErrors, componentWarnings, file, false);
207
207
  let jsxTree = undefined;
208
208
  if (treeResult && typeof treeResult === 'object') {
209
209
  jsxTree = treeResult.props?.children;
@@ -211,6 +211,9 @@ export function parseJSXElement(importAliases, node, updates, errors, file) {
211
211
  else {
212
212
  jsxTree = treeResult;
213
213
  }
214
+ if (componentWarnings.size > 0) {
215
+ componentWarnings.forEach((warning) => warnings.add(warning));
216
+ }
214
217
  if (componentErrors.length > 0) {
215
218
  errors.push(...componentErrors);
216
219
  return;
@@ -2,4 +2,5 @@ import { Updates } from '../../types/index.js';
2
2
  export declare function createInlineUpdates(pkg: 'gt-react' | 'gt-next', validate: boolean, filePatterns: string[] | undefined): Promise<{
3
3
  updates: Updates;
4
4
  errors: string[];
5
+ warnings: string[];
5
6
  }>;
@@ -14,6 +14,7 @@ import { DEFAULT_SRC_PATTERNS } from '../../config/generateSettings.js';
14
14
  export async function createInlineUpdates(pkg, validate, filePatterns) {
15
15
  const updates = [];
16
16
  const errors = [];
17
+ const warnings = new Set();
17
18
  // Use the provided app directory or default to the current directory
18
19
  const files = matchFiles(process.cwd(), filePatterns || DEFAULT_SRC_PATTERNS);
19
20
  for (const file of files) {
@@ -87,7 +88,7 @@ export async function createInlineUpdates(pkg, validate, filePatterns) {
87
88
  // Parse <T> components
88
89
  traverse(ast, {
89
90
  JSXElement(path) {
90
- parseJSXElement(importAliases, path.node, updates, errors, file);
91
+ parseJSXElement(importAliases, path.node, updates, errors, warnings, file);
91
92
  },
92
93
  });
93
94
  // Extra validation (for Locadex)
@@ -109,5 +110,5 @@ export async function createInlineUpdates(pkg, validate, filePatterns) {
109
110
  });
110
111
  update.metadata.hash = hash;
111
112
  }));
112
- return { updates, errors };
113
+ return { updates, errors, warnings: [...warnings] };
113
114
  }
@@ -11,4 +11,5 @@ import { Options, GenerateSourceOptions, Updates } from '../types/index.js';
11
11
  export declare function createUpdates(options: Options | GenerateSourceOptions, sourceDictionary: string | undefined, pkg: 'gt-react' | 'gt-next', validate: boolean): Promise<{
12
12
  updates: Updates;
13
13
  errors: string[];
14
+ warnings: string[];
14
15
  }>;
@@ -17,6 +17,7 @@ import chalk from 'chalk';
17
17
  export async function createUpdates(options, sourceDictionary, pkg, validate) {
18
18
  let updates = [];
19
19
  let errors = [];
20
+ let warnings = [];
20
21
  // Parse dictionary with esbuildConfig
21
22
  if (sourceDictionary &&
22
23
  fs.existsSync(sourceDictionary) &&
@@ -48,8 +49,9 @@ export async function createUpdates(options, sourceDictionary, pkg, validate) {
48
49
  }
49
50
  // Scan through project for <T> tags
50
51
  if (options.inline) {
51
- const { updates: newUpdates, errors: newErrors } = await createInlineUpdates(pkg, validate, options.src);
52
+ const { updates: newUpdates, errors: newErrors, warnings: newWarnings, } = await createInlineUpdates(pkg, validate, options.src);
52
53
  errors = [...errors, ...newErrors];
54
+ warnings = [...warnings, ...newWarnings];
53
55
  updates = [...updates, ...newUpdates];
54
56
  }
55
57
  // Metadata addition and validation
@@ -72,5 +74,5 @@ export async function createUpdates(options, sourceDictionary, pkg, validate) {
72
74
  });
73
75
  // Filter out updates with duplicate IDs
74
76
  updates = updates.filter((update) => !duplicateIds.has(update.metadata.id));
75
- return { updates, errors };
77
+ return { updates, errors, warnings };
76
78
  }
@@ -26,7 +26,18 @@ export async function stageProject(settings, pkg) {
26
26
  }
27
27
  settings.timeout = timeout.toString();
28
28
  // ---- CREATING UPDATES ---- //
29
- const { updates, errors } = await createUpdates(settings, settings.dictionary, pkg, false);
29
+ const { updates, errors, warnings } = await createUpdates(settings, settings.dictionary, pkg, false);
30
+ if (warnings.length > 0) {
31
+ if (settings.suppressWarnings) {
32
+ 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')}`));
33
+ }
34
+ else {
35
+ 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` +
36
+ warnings
37
+ .map((warning) => chalk.yellow('• Warning: ') + chalk.white(warning))
38
+ .join('\n')));
39
+ }
40
+ }
30
41
  if (errors.length > 0) {
31
42
  if (settings.ignoreErrors) {
32
43
  logWarning(chalk.yellow(`Warning: CLI tool encountered ${errors.length} syntax errors while scanning for translatable content. These components will not be translated.\n` +
@@ -6,11 +6,11 @@ export async function translate(settings, versionId) {
6
6
  // timeout was validated earlier
7
7
  const startTime = Date.now();
8
8
  const timeout = parseInt(settings.timeout) * 1000;
9
- const result = await waitForUpdates(settings.projectId, settings.apiKey, settings.baseUrl, versionId, startTime, timeout);
9
+ const result = await waitForUpdates(versionId, startTime, timeout);
10
10
  if (!result) {
11
11
  process.exit(1);
12
12
  }
13
- const translations = await fetchTranslations(settings.baseUrl, settings.projectId, settings.apiKey, versionId);
13
+ const translations = await fetchTranslations(versionId);
14
14
  // Save translations to local directory if files.gt.output is provided
15
15
  if (settings.files && isUsingLocalTranslations(settings)) {
16
16
  await saveTranslations(translations, settings.files.placeholderPaths, 'JSX');
@@ -1,4 +1,4 @@
1
- import { logErrorAndExit } from '../console/logging.js';
1
+ import { logErrorAndExit, logWarning } from '../console/logging.js';
2
2
  import chalk from 'chalk';
3
3
  import findFilepath from '../fs/findFilepath.js';
4
4
  import { logError, logSuccess } from '../console/logging.js';
@@ -27,7 +27,14 @@ export async function validateProject(settings, pkg, files) {
27
27
  './src/dictionary.ts',
28
28
  ]);
29
29
  }
30
- const { updates, errors } = await createUpdates(settings, settings.dictionary, pkg, true);
30
+ const { updates, errors, warnings } = await createUpdates(settings, settings.dictionary, pkg, true);
31
+ if (warnings.length > 0) {
32
+ logWarning(chalk.yellow(`CLI tool encountered ${warnings.length} warnings while scanning for translatable content.`) +
33
+ '\n' +
34
+ warnings
35
+ .map((warning) => chalk.yellow('• ') + chalk.white(warning))
36
+ .join('\n'));
37
+ }
31
38
  if (errors.length > 0) {
32
39
  logErrorAndExit(chalk.red(`Error: CLI tool encountered ${errors.length} syntax errors while scanning for translatable content.\n` +
33
40
  errors
@@ -17,8 +17,7 @@ export type JSONDictionary = {
17
17
  export type FlattenedJSONDictionary = {
18
18
  [key: string]: string;
19
19
  };
20
- export type DataFormat = 'JSX' | 'ICU' | 'I18NEXT';
21
- export type FileFormat = 'JSON' | 'YAML' | 'MDX' | 'MD' | 'TS' | 'JS';
20
+ export type { FileFormat, DataFormat } from 'generaltranslation/types';
22
21
  export type JsxChildren = string | string[] | any;
23
22
  export type Translations = {
24
23
  [key: string]: JsxChildren;
@@ -1,17 +1,5 @@
1
- import { JsxChildren } from 'generaltranslation/internal';
2
1
  import { SUPPORTED_FILE_EXTENSIONS } from '../formats/files/supportedFiles.js';
3
- export type Updates = ({
4
- metadata: Record<string, any>;
5
- } & ({
6
- dataFormat: 'JSX';
7
- source: JsxChildren;
8
- } | {
9
- dataFormat: 'ICU';
10
- source: string;
11
- } | {
12
- dataFormat: 'I18NEXT';
13
- source: string;
14
- }))[];
2
+ export type { Updates } from 'generaltranslation/types';
15
3
  export type Options = {
16
4
  config: string;
17
5
  apiKey?: string;
@@ -25,6 +13,7 @@ export type Options = {
25
13
  baseUrl: string;
26
14
  inline?: boolean;
27
15
  ignoreErrors: boolean;
16
+ suppressWarnings: boolean;
28
17
  dryRun: boolean;
29
18
  timeout: string;
30
19
  stageTranslations?: boolean;
@@ -52,6 +41,7 @@ export type GenerateSourceOptions = {
52
41
  jsconfig?: string;
53
42
  inline?: boolean;
54
43
  ignoreErrors: boolean;
44
+ suppressWarnings: boolean;
55
45
  };
56
46
  export type Framework = 'gt-next' | 'gt-react';
57
47
  export type SupportedFrameworks = 'next-app' | 'next-pages' | 'vite' | 'gatsby' | 'react' | 'redwood';
@@ -1,2 +1,2 @@
1
1
  import { Settings, Options } from '../types/index.js';
2
- export default function flattenJsonFiles(settings: Settings & Options): Promise<void>;
2
+ export default function flattenJsonFiles(settings: Omit<Settings & Options, 'ignoreErrors' | 'suppressWarnings' | 'timeout'>): Promise<void>;
@@ -0,0 +1,2 @@
1
+ import { GT } from 'generaltranslation';
2
+ export declare const gt: GT;
@@ -0,0 +1,2 @@
1
+ import { GT } from 'generaltranslation';
2
+ export const gt = new GT();
@@ -12,4 +12,4 @@ import { Options, Settings } from '../types/index.js';
12
12
  * - Support more file types
13
13
  * - Support more complex paths
14
14
  */
15
- export default function localizeStaticUrls(settings: Settings & Options): Promise<void>;
15
+ export default function localizeStaticUrls(settings: Omit<Settings & Options, 'ignoreErrors' | 'suppressWarnings' | 'timeout'>): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gtx-cli",
3
- "version": "2.0.5",
3
+ "version": "2.0.6-alpha.6",
4
4
  "main": "dist/index.js",
5
5
  "bin": "dist/main.js",
6
6
  "files": [
@@ -12,10 +12,10 @@
12
12
  "build": "tsc",
13
13
  "build:clean": "rm -rf dist; npm run build",
14
14
  "build:release": "npm run build:clean",
15
- "lint": "eslint \"src/**/*.{js,ts}\" \"__tests__/**/*.{js,ts}\"",
16
- "lint:fix": "eslint \"src/**/*.{js,ts}\" \"__tests__/**/*.{js,ts}\" --fix",
17
- "test": "vitest run",
18
- "test:watch": "vitest",
15
+ "lint": "eslint \"src/**/*.{js,ts}\" \"./**/__tests__/**/*.{js,ts}\"",
16
+ "lint:fix": "eslint \"src/**/*.{js,ts}\" \"./**/__tests__/**/*.{js,ts}\" --fix",
17
+ "test": "vitest run --config=./vitest.config.ts",
18
+ "test:watch": "vitest --config=./vitest.config.ts",
19
19
  "release": "npm run build:clean && npm publish",
20
20
  "release:alpha": "npm run build:clean && npm publish --tag alpha",
21
21
  "release:beta": "npm run build:clean && npm publish --tag beta",
@@ -87,7 +87,7 @@
87
87
  "esbuild": "^0.25.4",
88
88
  "fast-glob": "^3.3.3",
89
89
  "form-data": "^4.0.2",
90
- "generaltranslation": "^7.0.1",
90
+ "generaltranslation": "^7.1.0-alpha.6",
91
91
  "open": "^10.1.1",
92
92
  "ora": "^8.2.0",
93
93
  "resolve": "^1.22.10",
@@ -1,6 +0,0 @@
1
- export type RetrievedTranslation = {
2
- locale: string;
3
- translation: any;
4
- metadata: any;
5
- };
6
- export type RetrievedTranslations = RetrievedTranslation[];
package/dist/types/api.js DELETED
@@ -1 +0,0 @@
1
- export {};