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.
- package/dist/api/checkFileTranslations.d.ts +6 -0
- package/dist/api/checkFileTranslations.js +49 -58
- package/dist/api/downloadFile.d.ts +8 -1
- package/dist/api/downloadFile.js +20 -28
- package/dist/api/downloadFileBatch.d.ts +9 -9
- package/dist/api/downloadFileBatch.js +45 -52
- package/dist/api/fetchTranslations.d.ts +2 -5
- package/dist/api/fetchTranslations.js +7 -19
- package/dist/api/sendFiles.d.ts +16 -19
- package/dist/api/sendFiles.js +9 -31
- package/dist/api/sendUpdates.d.ts +6 -6
- package/dist/api/sendUpdates.js +10 -33
- package/dist/api/waitForUpdates.d.ts +1 -3
- package/dist/api/waitForUpdates.js +39 -45
- package/dist/cli/base.d.ts +3 -0
- package/dist/cli/base.js +13 -0
- package/dist/cli/react.js +13 -11
- package/dist/config/generateSettings.js +8 -0
- package/dist/config/utils.d.ts +1 -1
- package/dist/config/utils.js +1 -1
- package/dist/formats/files/translate.js +2 -2
- package/dist/formats/gt/save.d.ts +1 -1
- package/dist/react/jsx/utils/parseJsx.d.ts +2 -2
- package/dist/react/jsx/utils/parseJsx.js +13 -10
- package/dist/react/parse/createInlineUpdates.d.ts +1 -0
- package/dist/react/parse/createInlineUpdates.js +3 -2
- package/dist/translation/parse.d.ts +1 -0
- package/dist/translation/parse.js +4 -2
- package/dist/translation/stage.js +12 -1
- package/dist/translation/translate.js +2 -2
- package/dist/translation/validate.js +9 -2
- package/dist/types/data.d.ts +1 -2
- package/dist/types/index.d.ts +3 -13
- package/dist/utils/flattenJsonFiles.d.ts +1 -1
- package/dist/utils/gt.d.ts +2 -0
- package/dist/utils/gt.js +2 -0
- package/dist/utils/localizeStaticUrls.d.ts +1 -1
- package/package.json +6 -6
- package/dist/types/api.d.ts +0 -6
- 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 {
|
|
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 (
|
|
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
|
-
|
|
22
|
-
|
|
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
|
|
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));
|
package/dist/cli/base.d.ts
CHANGED
|
@@ -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
|
}
|
package/dist/config/utils.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { Settings } from '../types/index.js';
|
|
2
|
-
export declare function isUsingLocalTranslations(settings: Settings):
|
|
2
|
+
export declare function isUsingLocalTranslations(settings: Settings): boolean;
|
package/dist/config/utils.js
CHANGED
|
@@ -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(
|
|
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(
|
|
203
|
+
const result = await downloadFile(file.translationId, file.outputPath);
|
|
204
204
|
if (result) {
|
|
205
205
|
downloadStatus.downloaded.add(file.fileLocale);
|
|
206
206
|
}
|
|
@@ -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
|
|
64
|
-
|
|
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;
|
|
@@ -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(
|
|
9
|
+
const result = await waitForUpdates(versionId, startTime, timeout);
|
|
10
10
|
if (!result) {
|
|
11
11
|
process.exit(1);
|
|
12
12
|
}
|
|
13
|
-
const translations = await fetchTranslations(
|
|
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
|
package/dist/types/data.d.ts
CHANGED
|
@@ -17,8 +17,7 @@ export type JSONDictionary = {
|
|
|
17
17
|
export type FlattenedJSONDictionary = {
|
|
18
18
|
[key: string]: string;
|
|
19
19
|
};
|
|
20
|
-
export type
|
|
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;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -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>;
|
package/dist/utils/gt.js
ADDED
|
@@ -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.
|
|
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.
|
|
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",
|
package/dist/types/api.d.ts
DELETED
package/dist/types/api.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|