gtx-cli 2.5.44 → 2.5.45
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/CHANGELOG.md +8 -0
- package/dist/cli/base.d.ts +2 -2
- package/dist/cli/base.js +46 -29
- package/dist/formats/files/translate.js +23 -16
- package/dist/generated/version.d.ts +1 -1
- package/dist/generated/version.js +1 -1
- package/dist/setup/detectFramework.d.ts +31 -0
- package/dist/setup/detectFramework.js +106 -0
- package/dist/setup/frameworkUtils.d.ts +3 -0
- package/dist/setup/frameworkUtils.js +27 -0
- package/dist/setup/userInput.js +4 -4
- package/dist/setup/wizard.d.ts +2 -1
- package/dist/setup/wizard.js +8 -7
- package/dist/types/index.d.ts +20 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# gtx-cli
|
|
2
2
|
|
|
3
|
+
## 2.5.45
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#944](https://github.com/generaltranslation/gt/pull/944) [`0a58f13`](https://github.com/generaltranslation/gt/commit/0a58f13c9d25938a5e12644349248ce18aebb796) Thanks [@fernando-aviles](https://github.com/fernando-aviles)! - Add option to skip file validation when passing for translation
|
|
8
|
+
|
|
9
|
+
- [#942](https://github.com/generaltranslation/gt/pull/942) [`0cb890b`](https://github.com/generaltranslation/gt/commit/0cb890b84d775b360de0d8f6ed2b1ec8aeaa0af2) Thanks [@archie-mckenzie](https://github.com/archie-mckenzie)! - Refreshed CLI setup wizard flow
|
|
10
|
+
|
|
3
11
|
## 2.5.44
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
package/dist/cli/base.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import { Settings, SupportedLibraries, SetupOptions, TranslateFlags } from '../types/index.js';
|
|
2
|
+
import { Settings, ReactFrameworkObject, SupportedLibraries, SetupOptions, TranslateFlags } from '../types/index.js';
|
|
3
3
|
export type UploadOptions = {
|
|
4
4
|
config?: string;
|
|
5
5
|
apiKey?: string;
|
|
@@ -28,7 +28,7 @@ export declare class BaseCLI {
|
|
|
28
28
|
protected setupInitCommand(): void;
|
|
29
29
|
protected setupConfigureCommand(): void;
|
|
30
30
|
protected handleUploadCommand(settings: Settings & UploadOptions): Promise<void>;
|
|
31
|
-
protected handleSetupReactCommand(options: SetupOptions): Promise<void>;
|
|
31
|
+
protected handleSetupReactCommand(options: SetupOptions, frameworkObject: ReactFrameworkObject): Promise<void>;
|
|
32
32
|
protected handleInitCommand(ranReactSetup: boolean): Promise<void>;
|
|
33
33
|
protected handleLoginCommand(options: LoginOptions): Promise<void>;
|
|
34
34
|
}
|
package/dist/cli/base.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createOrUpdateConfig } from '../fs/config/setupConfig.js';
|
|
2
2
|
import findFilepath from '../fs/findFilepath.js';
|
|
3
|
-
import { displayHeader, promptText, logErrorAndExit, promptConfirm, promptMultiSelect, } from '../console/logging.js';
|
|
3
|
+
import { displayHeader, promptText, logErrorAndExit, promptConfirm, promptMultiSelect, promptSelect, } from '../console/logging.js';
|
|
4
4
|
import { logger } from '../console/logger.js';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import fs from 'node:fs';
|
|
@@ -25,6 +25,8 @@ import { createLoadTranslationsFile } from '../fs/createLoadTranslationsFile.js'
|
|
|
25
25
|
import { saveLocalEdits } from '../api/saveLocalEdits.js';
|
|
26
26
|
import processSharedStaticAssets from '../utils/sharedStaticAssets.js';
|
|
27
27
|
import { setupLocadex } from '../locadex/setupFlow.js';
|
|
28
|
+
import { detectFramework } from '../setup/detectFramework.js';
|
|
29
|
+
import { getFrameworkDisplayName, getReactFrameworkLibrary, } from '../setup/frameworkUtils.js';
|
|
28
30
|
export class BaseCLI {
|
|
29
31
|
library;
|
|
30
32
|
additionalModules;
|
|
@@ -183,32 +185,42 @@ export class BaseCLI {
|
|
|
183
185
|
.action(async (options) => {
|
|
184
186
|
const settings = await generateSettings(options);
|
|
185
187
|
displayHeader('Running setup wizard...');
|
|
186
|
-
const
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
188
|
+
const framework = await detectFramework();
|
|
189
|
+
const useAgent = await (async () => {
|
|
190
|
+
let useAgentMessage;
|
|
191
|
+
if (framework.name === 'mintlify') {
|
|
192
|
+
useAgentMessage = `Mintlify project detected. Would you like to connect to GitHub so that the Locadex AI Agent can translate your project automatically?`;
|
|
193
|
+
}
|
|
194
|
+
if (framework.name === 'next-app') {
|
|
195
|
+
useAgentMessage = `Next.js App Router detected. Would you like to connect to GitHub so that the Locadex AI Agent can set up your project automatically?`;
|
|
196
|
+
}
|
|
197
|
+
if (useAgentMessage) {
|
|
198
|
+
return await promptConfirm({
|
|
199
|
+
message: useAgentMessage,
|
|
200
|
+
defaultValue: false,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
return false;
|
|
204
|
+
})();
|
|
194
205
|
if (useAgent) {
|
|
195
206
|
await setupLocadex(settings);
|
|
196
|
-
logger.endCommand('
|
|
207
|
+
logger.endCommand('Once installed, Locadex will open a PR to your repository. See the docs for more information: https://generaltranslation.com/docs/locadex');
|
|
197
208
|
}
|
|
198
209
|
else {
|
|
199
210
|
let ranReactSetup = false;
|
|
200
211
|
// so that people can run init in non-js projects
|
|
201
|
-
if (
|
|
212
|
+
if (framework.type === 'react') {
|
|
213
|
+
const frameworkDisplayName = getFrameworkDisplayName(framework);
|
|
214
|
+
const library = getReactFrameworkLibrary(framework);
|
|
202
215
|
const wrap = await promptConfirm({
|
|
203
|
-
message:
|
|
216
|
+
message: `${frameworkDisplayName} detected. Would you like to install ${library} and add the GTProvider? See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`,
|
|
204
217
|
defaultValue: true,
|
|
205
218
|
});
|
|
206
219
|
if (wrap) {
|
|
207
|
-
logger.info(`${chalk.yellow('[EXPERIMENTAL]')}
|
|
208
|
-
await this.handleSetupReactCommand(options);
|
|
220
|
+
logger.info(`${chalk.yellow('[EXPERIMENTAL]')} Configuring project...`);
|
|
221
|
+
await this.handleSetupReactCommand(options, framework);
|
|
209
222
|
logger.endCommand(`Done! Since this wizard is experimental, please review the changes and make modifications as needed.
|
|
210
|
-
|
|
211
|
-
See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`);
|
|
223
|
+
\nNext step: start internationalizing! See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`);
|
|
212
224
|
ranReactSetup = true;
|
|
213
225
|
}
|
|
214
226
|
}
|
|
@@ -257,8 +269,8 @@ See the docs for more information: https://generaltranslation.com/docs/react/tut
|
|
|
257
269
|
// Process all file types at once with a single call
|
|
258
270
|
await upload(sourceFiles, placeholderPaths, transformPaths, dataFormat, settings);
|
|
259
271
|
}
|
|
260
|
-
async handleSetupReactCommand(options) {
|
|
261
|
-
await handleSetupReactCommand(options);
|
|
272
|
+
async handleSetupReactCommand(options, frameworkObject) {
|
|
273
|
+
await handleSetupReactCommand(options, frameworkObject);
|
|
262
274
|
}
|
|
263
275
|
// Wizard for configuring gt.config.json
|
|
264
276
|
async handleInitCommand(ranReactSetup) {
|
|
@@ -273,18 +285,23 @@ See the docs for more information: https://generaltranslation.com/docs/react/tut
|
|
|
273
285
|
// Ask if using another i18n library
|
|
274
286
|
const isUsingGT = isUsingGTNext || isUsingGTReact || ranReactSetup;
|
|
275
287
|
// Ask where the translations are stored
|
|
276
|
-
const usingCDN =
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
288
|
+
const usingCDN = await (async () => {
|
|
289
|
+
if (!isUsingGT)
|
|
290
|
+
return false;
|
|
291
|
+
const selectedValue = await promptSelect({
|
|
292
|
+
message: `Would you like to save translation files locally or use the General Translation CDN to store them?`,
|
|
293
|
+
options: [
|
|
294
|
+
{ value: 'local', label: 'Save locally' },
|
|
295
|
+
{ value: 'cdn', label: 'Use CDN' },
|
|
296
|
+
],
|
|
297
|
+
defaultValue: 'local',
|
|
298
|
+
});
|
|
299
|
+
return selectedValue === 'cdn';
|
|
300
|
+
})();
|
|
284
301
|
// Ask where the translations are stored
|
|
285
302
|
const translationsDir = isUsingGT && !usingCDN
|
|
286
303
|
? await promptText({
|
|
287
|
-
message: 'What is the path to the directory where you would like to
|
|
304
|
+
message: 'What is the path to the directory where you would like to store your translation files?',
|
|
288
305
|
defaultValue: './public/_gt',
|
|
289
306
|
})
|
|
290
307
|
: null;
|
|
@@ -299,7 +316,7 @@ See https://generaltranslation.com/en/docs/next/guides/local-tx`);
|
|
|
299
316
|
}
|
|
300
317
|
const message = !isUsingGT
|
|
301
318
|
? 'What is the format of your language resource files? Select as many as applicable.\nAdditionally, you can translate any other files you have in your project.'
|
|
302
|
-
:
|
|
319
|
+
: `Do you have any additional files in this project to translate? For example, Markdown files for docs. ${chalk.dim('(To continue without selecting press Enter)')}`;
|
|
303
320
|
const fileExtensions = await promptMultiSelect({
|
|
304
321
|
message,
|
|
305
322
|
options: [
|
|
@@ -339,7 +356,7 @@ See https://generaltranslation.com/en/docs/next/guides/local-tx`);
|
|
|
339
356
|
files: Object.keys(files).length > 0 ? files : undefined,
|
|
340
357
|
publish: isUsingGT && usingCDN,
|
|
341
358
|
});
|
|
342
|
-
logger.success(`
|
|
359
|
+
logger.success(`Edit ${chalk.cyan(configFilepath)} to customize your translation setup. Docs: https://generaltranslation.com/docs/cli/reference/config`);
|
|
343
360
|
// Install gtx-cli if not installed
|
|
344
361
|
const isCLIInstalled = packageJson
|
|
345
362
|
? isPackageInstalled('gtx-cli', packageJson, true, true)
|
|
@@ -18,6 +18,7 @@ export async function aggregateFiles(settings) {
|
|
|
18
18
|
return allFiles;
|
|
19
19
|
}
|
|
20
20
|
const { resolvedPaths: filePaths } = settings.files;
|
|
21
|
+
const skipValidation = settings.options?.skipFileValidation;
|
|
21
22
|
// Process JSON files
|
|
22
23
|
if (filePaths.json) {
|
|
23
24
|
const { library, additionalModules } = determineLibrary();
|
|
@@ -42,12 +43,14 @@ export async function aggregateFiles(settings) {
|
|
|
42
43
|
const content = readFile(filePath);
|
|
43
44
|
const relativePath = getRelative(filePath);
|
|
44
45
|
// Pre-validate JSON parseability
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
if (!skipValidation?.json) {
|
|
47
|
+
try {
|
|
48
|
+
JSON.parse(content);
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
logger.warn(`Skipping ${relativePath}: JSON file is not parsable`);
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
51
54
|
}
|
|
52
55
|
const parsedJson = parseJson(content, filePath, settings.options || {}, settings.defaultLocale);
|
|
53
56
|
return {
|
|
@@ -78,12 +81,14 @@ export async function aggregateFiles(settings) {
|
|
|
78
81
|
const content = readFile(filePath);
|
|
79
82
|
const relativePath = getRelative(filePath);
|
|
80
83
|
// Pre-validate YAML parseability
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
if (!skipValidation?.yaml) {
|
|
85
|
+
try {
|
|
86
|
+
YAML.parse(content);
|
|
87
|
+
}
|
|
88
|
+
catch (e) {
|
|
89
|
+
logger.warn(`Skipping ${relativePath}: YAML file is not parsable`);
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
87
92
|
}
|
|
88
93
|
const { content: parsedYaml, fileFormat } = parseYaml(content, filePath, settings.options || {});
|
|
89
94
|
return {
|
|
@@ -113,10 +118,12 @@ export async function aggregateFiles(settings) {
|
|
|
113
118
|
const content = readFile(filePath);
|
|
114
119
|
const relativePath = getRelative(filePath);
|
|
115
120
|
if (fileType === 'mdx') {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
121
|
+
if (!skipValidation?.mdx) {
|
|
122
|
+
const validation = isValidMdx(content, filePath);
|
|
123
|
+
if (!validation.isValid) {
|
|
124
|
+
logger.warn(`Skipping ${relativePath}: MDX file is not AST parsable${validation.error ? `: ${validation.error}` : ''}`);
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
120
127
|
}
|
|
121
128
|
}
|
|
122
129
|
const sanitizedContent = sanitizeFileContent(content);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PACKAGE_VERSION = "2.5.
|
|
1
|
+
export declare const PACKAGE_VERSION = "2.5.45";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// This file is auto-generated. Do not edit manually.
|
|
2
|
-
export const PACKAGE_VERSION = '2.5.
|
|
2
|
+
export const PACKAGE_VERSION = '2.5.45';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { FrameworkObject } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Detects the frontend framework used in the current project.
|
|
4
|
+
*
|
|
5
|
+
* Analyzes the project structure and dependencies to identify the framework.
|
|
6
|
+
* Detection order: Mintlify → Next.js (App/Pages Router) → Gatsby → RedwoodJS → Vite → React.
|
|
7
|
+
*
|
|
8
|
+
* For Next.js projects, further determines whether it uses App Router or Pages Router
|
|
9
|
+
* by checking for the presence of `app/` or `pages/` directories.
|
|
10
|
+
*
|
|
11
|
+
* @returns A promise resolving to a FrameworkObject containing:
|
|
12
|
+
* - `name`: The detected framework identifier (e.g., 'next-app', 'gatsby', 'react')
|
|
13
|
+
* or undefined if no framework is detected
|
|
14
|
+
* - `type`: The framework category (currently only 'react' for React-based frameworks)
|
|
15
|
+
*/
|
|
16
|
+
export declare function detectFramework(): Promise<FrameworkObject | {
|
|
17
|
+
name: undefined;
|
|
18
|
+
type?: undefined;
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
21
|
+
* Detects if the current project is a Mintlify documentation project.
|
|
22
|
+
*
|
|
23
|
+
* Checks for the presence of docs.json (preferred) or mint.json (legacy) files.
|
|
24
|
+
* For docs.json, validates that the $schema field contains "mintlify.com/docs.json".
|
|
25
|
+
* Rejects projects with Next.js config files to avoid misclassification.
|
|
26
|
+
*
|
|
27
|
+
* @param _packageJson - The parsed package.json object (not used for Mintlify detection,
|
|
28
|
+
* but kept for API consistency with other detection functions)
|
|
29
|
+
* @returns True if the project is identified as a Mintlify project, false otherwise
|
|
30
|
+
*/
|
|
31
|
+
export declare function isMintlifyProject(_packageJson: Record<string, any> | null): boolean;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { isPackageInstalled } from '../utils/packageJson.js';
|
|
2
|
+
import { searchForPackageJson } from '../utils/packageJson.js';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
/* ----- MAIN ----- */
|
|
6
|
+
/**
|
|
7
|
+
* Detects the frontend framework used in the current project.
|
|
8
|
+
*
|
|
9
|
+
* Analyzes the project structure and dependencies to identify the framework.
|
|
10
|
+
* Detection order: Mintlify → Next.js (App/Pages Router) → Gatsby → RedwoodJS → Vite → React.
|
|
11
|
+
*
|
|
12
|
+
* For Next.js projects, further determines whether it uses App Router or Pages Router
|
|
13
|
+
* by checking for the presence of `app/` or `pages/` directories.
|
|
14
|
+
*
|
|
15
|
+
* @returns A promise resolving to a FrameworkObject containing:
|
|
16
|
+
* - `name`: The detected framework identifier (e.g., 'next-app', 'gatsby', 'react')
|
|
17
|
+
* or undefined if no framework is detected
|
|
18
|
+
* - `type`: The framework category (currently only 'react' for React-based frameworks)
|
|
19
|
+
*/
|
|
20
|
+
export async function detectFramework() {
|
|
21
|
+
const packageJson = await searchForPackageJson();
|
|
22
|
+
if (isMintlifyProject(packageJson)) {
|
|
23
|
+
return { name: 'mintlify' };
|
|
24
|
+
}
|
|
25
|
+
if (!packageJson) {
|
|
26
|
+
return { name: undefined };
|
|
27
|
+
}
|
|
28
|
+
// Check for Next.js first
|
|
29
|
+
if (isPackageInstalled('next', packageJson, false, true)) {
|
|
30
|
+
// Determine if it's App Router or Pages Router
|
|
31
|
+
const cwd = process.cwd();
|
|
32
|
+
const hasAppDir = fs.existsSync(path.join(cwd, 'app')) ||
|
|
33
|
+
fs.existsSync(path.join(cwd, 'src', 'app'));
|
|
34
|
+
const hasPagesDir = fs.existsSync(path.join(cwd, 'pages')) ||
|
|
35
|
+
fs.existsSync(path.join(cwd, 'src', 'pages'));
|
|
36
|
+
// App Router takes precedence if both exist
|
|
37
|
+
if (hasAppDir) {
|
|
38
|
+
return { name: 'next-app', type: 'react' };
|
|
39
|
+
}
|
|
40
|
+
if (hasPagesDir) {
|
|
41
|
+
return { name: 'next-pages', type: 'react' };
|
|
42
|
+
}
|
|
43
|
+
// Default to app router for new Next.js projects
|
|
44
|
+
return { name: 'next-app', type: 'react' };
|
|
45
|
+
}
|
|
46
|
+
// Check for Gatsby
|
|
47
|
+
if (isPackageInstalled('gatsby', packageJson, false, true)) {
|
|
48
|
+
return { name: 'gatsby', type: 'react' };
|
|
49
|
+
}
|
|
50
|
+
// Check for RedwoodJS
|
|
51
|
+
if (isPackageInstalled('@redwoodjs/core', packageJson, false, true)) {
|
|
52
|
+
return { name: 'redwood', type: 'react' };
|
|
53
|
+
}
|
|
54
|
+
// Check for Vite
|
|
55
|
+
if (isPackageInstalled('vite', packageJson, false, true)) {
|
|
56
|
+
return { name: 'vite', type: 'react' };
|
|
57
|
+
}
|
|
58
|
+
// Check for React (generic)
|
|
59
|
+
if (isPackageInstalled('react', packageJson, false, true)) {
|
|
60
|
+
return { name: 'react', type: 'react' };
|
|
61
|
+
}
|
|
62
|
+
return { name: undefined };
|
|
63
|
+
}
|
|
64
|
+
// ----- HELPER FUNCTIONS ----- //
|
|
65
|
+
/**
|
|
66
|
+
* Detects if the current project is a Mintlify documentation project.
|
|
67
|
+
*
|
|
68
|
+
* Checks for the presence of docs.json (preferred) or mint.json (legacy) files.
|
|
69
|
+
* For docs.json, validates that the $schema field contains "mintlify.com/docs.json".
|
|
70
|
+
* Rejects projects with Next.js config files to avoid misclassification.
|
|
71
|
+
*
|
|
72
|
+
* @param _packageJson - The parsed package.json object (not used for Mintlify detection,
|
|
73
|
+
* but kept for API consistency with other detection functions)
|
|
74
|
+
* @returns True if the project is identified as a Mintlify project, false otherwise
|
|
75
|
+
*/
|
|
76
|
+
export function isMintlifyProject(_packageJson) {
|
|
77
|
+
const cwd = process.cwd();
|
|
78
|
+
// Check for Next.js config files - if present, this is not a Mintlify project
|
|
79
|
+
const nextConfigFiles = [
|
|
80
|
+
'next.config.js',
|
|
81
|
+
'next.config.ts',
|
|
82
|
+
'next.config.mjs',
|
|
83
|
+
'next.config.cjs',
|
|
84
|
+
];
|
|
85
|
+
for (const configFile of nextConfigFiles) {
|
|
86
|
+
if (fs.existsSync(path.join(cwd, configFile))) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Check for docs.json (preferred format)
|
|
91
|
+
const docsJsonPath = path.join(cwd, 'docs.json');
|
|
92
|
+
if (fs.existsSync(docsJsonPath)) {
|
|
93
|
+
try {
|
|
94
|
+
const docsJson = JSON.parse(fs.readFileSync(docsJsonPath, 'utf-8'));
|
|
95
|
+
// Validate the $schema field contains mintlify.com/docs.json
|
|
96
|
+
if (docsJson.$schema &&
|
|
97
|
+
docsJson.$schema.includes('mintlify.com/docs.json')) {
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export function getFrameworkDisplayName(frameworkObject) {
|
|
2
|
+
if (frameworkObject.name === 'mintlify') {
|
|
3
|
+
return 'Mintlify';
|
|
4
|
+
}
|
|
5
|
+
if (frameworkObject.name === 'next-app') {
|
|
6
|
+
return 'Next.js App Router';
|
|
7
|
+
}
|
|
8
|
+
if (frameworkObject.name === 'next-pages') {
|
|
9
|
+
return 'Next.js Pages Router';
|
|
10
|
+
}
|
|
11
|
+
if (frameworkObject.name === 'vite') {
|
|
12
|
+
return 'Vite + React';
|
|
13
|
+
}
|
|
14
|
+
if (frameworkObject.name === 'gatsby') {
|
|
15
|
+
return 'Gatsby';
|
|
16
|
+
}
|
|
17
|
+
if (frameworkObject.name === 'redwood') {
|
|
18
|
+
return 'RedwoodJS';
|
|
19
|
+
}
|
|
20
|
+
if (frameworkObject.type === 'react') {
|
|
21
|
+
return 'React';
|
|
22
|
+
}
|
|
23
|
+
return 'another framework';
|
|
24
|
+
}
|
|
25
|
+
export function getReactFrameworkLibrary(frameworkObject) {
|
|
26
|
+
return frameworkObject.name === 'next-app' ? 'gt-next' : 'gt-react';
|
|
27
|
+
}
|
package/dist/setup/userInput.js
CHANGED
|
@@ -10,19 +10,19 @@ export async function getDesiredLocales() {
|
|
|
10
10
|
});
|
|
11
11
|
// Ask for the locales
|
|
12
12
|
const locales = await promptText({
|
|
13
|
-
message: `
|
|
14
|
-
defaultValue: 'es
|
|
13
|
+
message: `Which languages would you like to translate your project into? Enter your response as a list of BCP-47 locale tags. ${chalk.dim('(space-separated list)')}`,
|
|
14
|
+
defaultValue: 'es fr de ja zh',
|
|
15
15
|
validate: (input) => {
|
|
16
16
|
const localeList = input.split(' ');
|
|
17
17
|
if (localeList.length === 0) {
|
|
18
18
|
return 'Please enter at least one locale';
|
|
19
19
|
}
|
|
20
20
|
if (localeList.some((locale) => !locale.trim())) {
|
|
21
|
-
return 'Please enter a valid locale (e.g.,
|
|
21
|
+
return 'Please enter a valid locale (e.g., es fr de)';
|
|
22
22
|
}
|
|
23
23
|
for (const locale of localeList) {
|
|
24
24
|
if (!gt.isValidLocale(locale)) {
|
|
25
|
-
return 'Please enter a valid locale (e.g.,
|
|
25
|
+
return 'Please enter a valid locale (e.g., es fr de)';
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
return true;
|
package/dist/setup/wizard.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import { SetupOptions } from '../types/index.js';
|
|
2
|
-
|
|
2
|
+
import { ReactFrameworkObject } from '../types/index.js';
|
|
3
|
+
export declare function handleSetupReactCommand(options: SetupOptions, frameworkObject: ReactFrameworkObject): Promise<void>;
|
package/dist/setup/wizard.js
CHANGED
|
@@ -14,11 +14,12 @@ import { createOrUpdateConfig } from '../fs/config/setupConfig.js';
|
|
|
14
14
|
import { loadConfig } from '../fs/config/loadConfig.js';
|
|
15
15
|
import { addVitePlugin } from '../react/parse/addVitePlugin/index.js';
|
|
16
16
|
import { exitSync } from '../console/logging.js';
|
|
17
|
-
|
|
17
|
+
import { getFrameworkDisplayName } from './frameworkUtils.js';
|
|
18
|
+
export async function handleSetupReactCommand(options, frameworkObject) {
|
|
19
|
+
const frameworkDisplayName = getFrameworkDisplayName(frameworkObject);
|
|
18
20
|
// Ask user for confirmation using inquirer
|
|
19
21
|
const answer = await promptConfirm({
|
|
20
|
-
message: chalk.yellow(`This wizard will configure your
|
|
21
|
-
If your project is already using a different i18n library, this wizard may cause issues.
|
|
22
|
+
message: chalk.yellow(`This wizard will configure your ${frameworkDisplayName} project for internationalization with GT. If your project is already using a different i18n library, this wizard may cause issues.
|
|
22
23
|
|
|
23
24
|
Make sure you have committed or stashed any changes. Do you want to continue?`),
|
|
24
25
|
defaultValue: true,
|
|
@@ -29,7 +30,7 @@ Make sure you have committed or stashed any changes. Do you want to continue?`),
|
|
|
29
30
|
exitSync(0);
|
|
30
31
|
}
|
|
31
32
|
const frameworkType = await promptSelect({
|
|
32
|
-
message: '
|
|
33
|
+
message: 'Which framework are you using?',
|
|
33
34
|
options: [
|
|
34
35
|
{ value: 'next-app', label: chalk.blue('Next.js App Router') },
|
|
35
36
|
{ value: 'next-pages', label: chalk.green('Next.js Pages Router') },
|
|
@@ -39,11 +40,11 @@ Make sure you have committed or stashed any changes. Do you want to continue?`),
|
|
|
39
40
|
{ value: 'redwood', label: chalk.red('RedwoodJS') },
|
|
40
41
|
{ value: 'other', label: chalk.dim('Other') },
|
|
41
42
|
],
|
|
42
|
-
defaultValue: '
|
|
43
|
+
defaultValue: frameworkObject?.name || 'other',
|
|
43
44
|
});
|
|
44
45
|
if (frameworkType === 'other') {
|
|
45
|
-
logger.error(`Sorry,
|
|
46
|
-
Please let us know what you would like to see
|
|
46
|
+
logger.error(`Sorry, the wizard doesn't currently support other React frameworks.
|
|
47
|
+
Please let us know what you would like to see added at https://github.com/generaltranslation/gt/issues`);
|
|
47
48
|
exitSync(0);
|
|
48
49
|
}
|
|
49
50
|
// ----- Create a starter gt.config.json file -----
|
package/dist/types/index.d.ts
CHANGED
|
@@ -93,7 +93,21 @@ export type GenerateSourceOptions = {
|
|
|
93
93
|
suppressWarnings: boolean;
|
|
94
94
|
};
|
|
95
95
|
export type Framework = 'gt-next' | 'gt-react';
|
|
96
|
-
export type
|
|
96
|
+
export type FrameworkObject = {
|
|
97
|
+
name: 'mintlify';
|
|
98
|
+
type?: undefined;
|
|
99
|
+
} | {
|
|
100
|
+
name: 'next-app' | 'next-pages' | 'vite' | 'gatsby' | 'redwood' | 'react';
|
|
101
|
+
type: 'react';
|
|
102
|
+
};
|
|
103
|
+
export type ReactFrameworkObject = Extract<FrameworkObject, {
|
|
104
|
+
type: 'react';
|
|
105
|
+
}>;
|
|
106
|
+
export type FrameworkType = FrameworkObject['type'];
|
|
107
|
+
export type SupportedFrameworks = FrameworkObject['name'];
|
|
108
|
+
export type SupportedReactFrameworks = Extract<FrameworkObject, {
|
|
109
|
+
type: 'react';
|
|
110
|
+
}>['name'];
|
|
97
111
|
export type SupportedLibraries = 'gt-next' | 'gt-react' | 'next-intl' | 'react-i18next' | 'next-i18next' | 'i18next' | 'i18next-icu' | 'base';
|
|
98
112
|
export interface ContentScanner {
|
|
99
113
|
scanForContent(options: WrapOptions, framework: Framework): Promise<{
|
|
@@ -167,6 +181,11 @@ export type AdditionalOptions = {
|
|
|
167
181
|
yamlSchema?: {
|
|
168
182
|
[fileGlob: string]: YamlSchema;
|
|
169
183
|
};
|
|
184
|
+
skipFileValidation?: {
|
|
185
|
+
json?: boolean;
|
|
186
|
+
yaml?: boolean;
|
|
187
|
+
mdx?: boolean;
|
|
188
|
+
};
|
|
170
189
|
mintlify?: MintlifyOptions;
|
|
171
190
|
docsUrlPattern?: string;
|
|
172
191
|
docsImportPattern?: string;
|