gtx-cli 2.6.17 → 2.6.19
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 +18 -0
- package/dist/cli/base.d.ts +2 -0
- package/dist/cli/base.js +76 -14
- package/dist/cli/flags.d.ts +12 -1
- package/dist/cli/flags.js +24 -5
- package/dist/cli/inline.d.ts +17 -0
- package/dist/cli/inline.js +133 -0
- package/dist/cli/next.d.ts +2 -3
- package/dist/cli/next.js +2 -11
- package/dist/cli/node.d.ts +10 -0
- package/dist/cli/node.js +9 -0
- package/dist/cli/react.d.ts +4 -11
- package/dist/cli/react.js +7 -121
- package/dist/formats/files/collectFiles.js +4 -3
- package/dist/fs/determineFramework.js +11 -4
- package/dist/generated/version.d.ts +1 -1
- package/dist/generated/version.js +1 -1
- package/dist/index.js +8 -2
- package/dist/next/parse/wrapContent.d.ts +2 -1
- package/dist/next/parse/wrapContent.js +8 -7
- package/dist/react/jsx/utils/constants.d.ts +1 -5
- package/dist/react/jsx/utils/constants.js +2 -43
- package/dist/react/jsx/utils/getPathsAndAliases.d.ts +1 -1
- package/dist/react/jsx/utils/getPathsAndAliases.js +3 -4
- package/dist/react/jsx/utils/jsxParsing/parseJsx.d.ts +1 -1
- package/dist/react/jsx/utils/jsxParsing/parseTProps.js +2 -1
- package/dist/react/jsx/utils/mapAttributeName.d.ts +6 -0
- package/dist/react/jsx/utils/mapAttributeName.js +14 -0
- package/dist/react/jsx/utils/parseAst.d.ts +1 -1
- package/dist/react/jsx/utils/parseString.js +2 -1
- package/dist/react/jsx/utils/parseStringFunction.js +3 -2
- package/dist/react/parse/createInlineUpdates.d.ts +1 -1
- package/dist/react/parse/createInlineUpdates.js +23 -20
- package/dist/react/parse/wrapContent.d.ts +2 -1
- package/dist/react/parse/wrapContent.js +6 -6
- package/dist/setup/agentInstructions.d.ts +24 -0
- package/dist/setup/agentInstructions.js +138 -0
- package/dist/setup/frameworkUtils.js +4 -1
- package/dist/setup/instructions/base.md +29 -0
- package/dist/setup/instructions/gt-next.md +107 -0
- package/dist/setup/instructions/gt-react.md +98 -0
- package/dist/setup/wizard.js +10 -9
- package/dist/translation/parse.d.ts +2 -1
- package/dist/translation/stage.d.ts +2 -1
- package/dist/translation/stage.js +1 -1
- package/dist/translation/validate.d.ts +4 -3
- package/dist/types/index.d.ts +3 -2
- package/dist/types/libraries.d.ts +31 -0
- package/dist/types/libraries.js +72 -0
- package/package.json +3 -3
|
@@ -2,6 +2,7 @@ import chalk from 'chalk';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import fs from 'node:fs';
|
|
4
4
|
import { logger } from '../console/logger.js';
|
|
5
|
+
import { Libraries } from '../types/libraries.js';
|
|
5
6
|
export function determineLibrary() {
|
|
6
7
|
let library = 'base';
|
|
7
8
|
const additionalModules = [];
|
|
@@ -21,11 +22,17 @@ export function determineLibrary() {
|
|
|
21
22
|
...packageJson.devDependencies,
|
|
22
23
|
};
|
|
23
24
|
// Check for gt-next or gt-react in dependencies
|
|
24
|
-
if (dependencies[
|
|
25
|
-
library =
|
|
25
|
+
if (dependencies[Libraries.GT_NEXT]) {
|
|
26
|
+
library = Libraries.GT_NEXT;
|
|
26
27
|
}
|
|
27
|
-
else if (dependencies[
|
|
28
|
-
library =
|
|
28
|
+
else if (dependencies[Libraries.GT_REACT]) {
|
|
29
|
+
library = Libraries.GT_REACT;
|
|
30
|
+
}
|
|
31
|
+
else if (dependencies[Libraries.GT_REACT_NATIVE]) {
|
|
32
|
+
library = Libraries.GT_REACT_NATIVE;
|
|
33
|
+
}
|
|
34
|
+
else if (dependencies[Libraries.GT_NODE]) {
|
|
35
|
+
library = Libraries.GT_NODE;
|
|
29
36
|
}
|
|
30
37
|
else if (dependencies['next-intl']) {
|
|
31
38
|
library = 'next-intl';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PACKAGE_VERSION = "2.6.
|
|
1
|
+
export declare const PACKAGE_VERSION = "2.6.19";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// This file is auto-generated. Do not edit manually.
|
|
2
|
-
export const PACKAGE_VERSION = '2.6.
|
|
2
|
+
export const PACKAGE_VERSION = '2.6.19';
|
package/dist/index.js
CHANGED
|
@@ -2,16 +2,22 @@ import { BaseCLI } from './cli/base.js';
|
|
|
2
2
|
import { NextCLI } from './cli/next.js';
|
|
3
3
|
import { ReactCLI } from './cli/react.js';
|
|
4
4
|
import { determineLibrary } from './fs/determineFramework.js';
|
|
5
|
+
import { NodeCLI } from './cli/node.js';
|
|
6
|
+
import { Libraries } from './types/libraries.js';
|
|
5
7
|
export function main(program) {
|
|
6
8
|
program.name('gtx-cli');
|
|
7
9
|
const { library, additionalModules } = determineLibrary();
|
|
8
10
|
let cli;
|
|
9
|
-
if (library ===
|
|
11
|
+
if (library === Libraries.GT_NEXT) {
|
|
10
12
|
cli = new NextCLI(program, library, additionalModules);
|
|
11
13
|
}
|
|
12
|
-
else if (library ===
|
|
14
|
+
else if (library === Libraries.GT_REACT ||
|
|
15
|
+
library === Libraries.GT_REACT_NATIVE) {
|
|
13
16
|
cli = new ReactCLI(program, library, additionalModules);
|
|
14
17
|
}
|
|
18
|
+
else if (library === Libraries.GT_NODE) {
|
|
19
|
+
cli = new NodeCLI(program, library, additionalModules);
|
|
20
|
+
}
|
|
15
21
|
else {
|
|
16
22
|
cli = new BaseCLI(program, library, additionalModules);
|
|
17
23
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { WrapOptions } from '../../types/index.js';
|
|
2
|
+
import { Libraries } from '../../types/libraries.js';
|
|
2
3
|
/**
|
|
3
4
|
* Wraps all JSX elements in the src directory with a <T> tag, with unique ids.
|
|
4
5
|
* - Ignores pure strings
|
|
@@ -6,6 +7,6 @@ import { WrapOptions } from '../../types/index.js';
|
|
|
6
7
|
* @param options - The options object
|
|
7
8
|
* @returns An object containing the updates and errors
|
|
8
9
|
*/
|
|
9
|
-
export declare function wrapContentNext(options: WrapOptions, pkg:
|
|
10
|
+
export declare function wrapContentNext(options: WrapOptions, pkg: typeof Libraries.GT_NEXT, errors: string[], warnings: string[]): Promise<{
|
|
10
11
|
filesUpdated: string[];
|
|
11
12
|
}>;
|
|
@@ -13,13 +13,14 @@ import { isHtmlElement, isBodyElement, hasGTProviderChild, addDynamicLangAttribu
|
|
|
13
13
|
import { generateImportMap, createImports, } from '../../react/jsx/utils/parseAst.js';
|
|
14
14
|
import { matchFiles } from '../../fs/matchFiles.js';
|
|
15
15
|
import { DEFAULT_SRC_PATTERNS } from '../../config/generateSettings.js';
|
|
16
|
+
import { Libraries } from '../../types/libraries.js';
|
|
16
17
|
const IMPORT_MAP = {
|
|
17
|
-
T: { name: 'T', source:
|
|
18
|
-
Var: { name: 'Var', source:
|
|
19
|
-
GTT: { name: 'T', source:
|
|
20
|
-
GTVar: { name: 'Var', source:
|
|
21
|
-
GTProvider: { name: 'GTProvider', source:
|
|
22
|
-
getLocale: { name: 'getLocale', source: '
|
|
18
|
+
T: { name: 'T', source: Libraries.GT_NEXT },
|
|
19
|
+
Var: { name: 'Var', source: Libraries.GT_NEXT },
|
|
20
|
+
GTT: { name: 'T', source: Libraries.GT_NEXT },
|
|
21
|
+
GTVar: { name: 'Var', source: Libraries.GT_NEXT },
|
|
22
|
+
GTProvider: { name: 'GTProvider', source: Libraries.GT_NEXT },
|
|
23
|
+
getLocale: { name: 'getLocale', source: Libraries.GT_NEXT + '/server' },
|
|
23
24
|
};
|
|
24
25
|
/**
|
|
25
26
|
* Wraps all JSX elements in the src directory with a <T> tag, with unique ids.
|
|
@@ -58,7 +59,7 @@ export async function wrapContentNext(options, pkg, errors, warnings) {
|
|
|
58
59
|
let globalId = 0;
|
|
59
60
|
traverse(ast, {
|
|
60
61
|
JSXElement(path) {
|
|
61
|
-
if (pkg ===
|
|
62
|
+
if (pkg === Libraries.GT_NEXT &&
|
|
62
63
|
options.addGTProvider &&
|
|
63
64
|
isHtmlElement(path.node.openingElement)) {
|
|
64
65
|
// Find the body element recursively in the HTML tree
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare const DECLARE_VAR_FUNCTION = "declareVar";
|
|
2
2
|
export declare const DECLARE_STATIC_FUNCTION = "declareStatic";
|
|
3
|
-
export declare const
|
|
3
|
+
export declare const MSG_REGISTRATION_FUNCTION = "msg";
|
|
4
4
|
export declare const INLINE_TRANSLATION_HOOK = "useGT";
|
|
5
5
|
export declare const INLINE_TRANSLATION_HOOK_ASYNC = "getGT";
|
|
6
6
|
export declare const INLINE_MESSAGE_HOOK = "useMessages";
|
|
@@ -11,7 +11,3 @@ export declare const GT_TRANSLATION_FUNCS: string[];
|
|
|
11
11
|
export declare const VARIABLE_COMPONENTS: string[];
|
|
12
12
|
export declare const GT_ATTRIBUTES_WITH_SUGAR: readonly ["$id", "$context", "$maxChars"];
|
|
13
13
|
export declare const GT_ATTRIBUTES: readonly ["id", "context", "maxChars", "$id", "$context", "$maxChars"];
|
|
14
|
-
export declare function mapAttributeName(attrName: string): string;
|
|
15
|
-
export declare const GT_LIBRARIES: readonly ["gt-react", "gt-next", "gt-react-native", "gt-i18n", "@generaltranslation/react-core"];
|
|
16
|
-
export type GTLibrary = (typeof GT_LIBRARIES)[number];
|
|
17
|
-
export declare const GT_LIBRARIES_UPSTREAM: Record<GTLibrary, GTLibrary[]>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export const DECLARE_VAR_FUNCTION = 'declareVar';
|
|
2
2
|
export const DECLARE_STATIC_FUNCTION = 'declareStatic';
|
|
3
|
-
export const
|
|
3
|
+
export const MSG_REGISTRATION_FUNCTION = 'msg';
|
|
4
4
|
export const INLINE_TRANSLATION_HOOK = 'useGT';
|
|
5
5
|
export const INLINE_TRANSLATION_HOOK_ASYNC = 'getGT';
|
|
6
6
|
export const INLINE_MESSAGE_HOOK = 'useMessages';
|
|
@@ -13,7 +13,7 @@ export const GT_TRANSLATION_FUNCS = [
|
|
|
13
13
|
INLINE_TRANSLATION_HOOK_ASYNC,
|
|
14
14
|
INLINE_MESSAGE_HOOK,
|
|
15
15
|
INLINE_MESSAGE_HOOK_ASYNC,
|
|
16
|
-
|
|
16
|
+
MSG_REGISTRATION_FUNCTION,
|
|
17
17
|
DECLARE_VAR_FUNCTION,
|
|
18
18
|
DECLARE_STATIC_FUNCTION,
|
|
19
19
|
TRANSLATION_COMPONENT,
|
|
@@ -44,44 +44,3 @@ export const GT_ATTRIBUTES = [
|
|
|
44
44
|
'maxChars',
|
|
45
45
|
...GT_ATTRIBUTES_WITH_SUGAR,
|
|
46
46
|
];
|
|
47
|
-
export function mapAttributeName(attrName) {
|
|
48
|
-
if (attrName === '$id')
|
|
49
|
-
return 'id';
|
|
50
|
-
if (attrName === '$context')
|
|
51
|
-
return 'context';
|
|
52
|
-
if (attrName === '$maxChars')
|
|
53
|
-
return 'maxChars';
|
|
54
|
-
return attrName;
|
|
55
|
-
}
|
|
56
|
-
export const GT_LIBRARIES = [
|
|
57
|
-
'gt-react',
|
|
58
|
-
'gt-next',
|
|
59
|
-
'gt-react-native',
|
|
60
|
-
'gt-i18n',
|
|
61
|
-
'@generaltranslation/react-core',
|
|
62
|
-
];
|
|
63
|
-
export const GT_LIBRARIES_UPSTREAM = {
|
|
64
|
-
'gt-next': [
|
|
65
|
-
'gt-i18n',
|
|
66
|
-
'@generaltranslation/react-core',
|
|
67
|
-
'gt-react',
|
|
68
|
-
'gt-next',
|
|
69
|
-
],
|
|
70
|
-
'gt-react': [
|
|
71
|
-
'gt-i18n',
|
|
72
|
-
'@generaltranslation/react-core',
|
|
73
|
-
'gt-react',
|
|
74
|
-
'gt-react-native', // allow for cross-library compatibility (gt-react/gt-react-native only)
|
|
75
|
-
],
|
|
76
|
-
'gt-react-native': [
|
|
77
|
-
'gt-i18n',
|
|
78
|
-
'@generaltranslation/react-core',
|
|
79
|
-
'gt-react-native',
|
|
80
|
-
'gt-react', // allow for cross-library compatibility (gt-react/gt-react-native only)
|
|
81
|
-
],
|
|
82
|
-
'@generaltranslation/react-core': [
|
|
83
|
-
'gt-i18n',
|
|
84
|
-
'@generaltranslation/react-core',
|
|
85
|
-
],
|
|
86
|
-
'gt-i18n': ['gt-i18n'],
|
|
87
|
-
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NodePath } from '@babel/traverse';
|
|
2
|
-
import { GTLibrary } from '
|
|
2
|
+
import { GTLibrary } from '../../../types/libraries.js';
|
|
3
3
|
/**
|
|
4
4
|
* Constructs tracking for gt related variables of interest
|
|
5
5
|
* inlineTranslationPaths: these are string-related translation functions
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import traverseModule from '@babel/traverse';
|
|
2
|
-
import { GT_TRANSLATION_FUNCS, INLINE_TRANSLATION_HOOK, INLINE_TRANSLATION_HOOK_ASYNC, INLINE_MESSAGE_HOOK, INLINE_MESSAGE_HOOK_ASYNC,
|
|
2
|
+
import { GT_TRANSLATION_FUNCS, INLINE_TRANSLATION_HOOK, INLINE_TRANSLATION_HOOK_ASYNC, INLINE_MESSAGE_HOOK, INLINE_MESSAGE_HOOK_ASYNC, MSG_REGISTRATION_FUNCTION, TRANSLATION_COMPONENT, } from '../../jsx/utils/constants.js';
|
|
3
3
|
import { extractImportName } from './parseAst.js';
|
|
4
4
|
// Handle CommonJS/ESM interop
|
|
5
5
|
const traverse = traverseModule.default || traverseModule;
|
|
@@ -23,7 +23,7 @@ export function getPathsAndAliases(ast, pkgs) {
|
|
|
23
23
|
name.original === INLINE_TRANSLATION_HOOK_ASYNC ||
|
|
24
24
|
name.original === INLINE_MESSAGE_HOOK ||
|
|
25
25
|
name.original === INLINE_MESSAGE_HOOK_ASYNC ||
|
|
26
|
-
name.original ===
|
|
26
|
+
name.original === MSG_REGISTRATION_FUNCTION) {
|
|
27
27
|
inlineTranslationPaths.push({
|
|
28
28
|
localName: name.local,
|
|
29
29
|
path,
|
|
@@ -60,8 +60,7 @@ export function getPathsAndAliases(ast, pkgs) {
|
|
|
60
60
|
if (name.original === INLINE_TRANSLATION_HOOK ||
|
|
61
61
|
name.original === INLINE_TRANSLATION_HOOK_ASYNC ||
|
|
62
62
|
name.original === INLINE_MESSAGE_HOOK ||
|
|
63
|
-
name.original === INLINE_MESSAGE_HOOK_ASYNC
|
|
64
|
-
name.original === MSG_TRANSLATION_FUNCTION) {
|
|
63
|
+
name.original === INLINE_MESSAGE_HOOK_ASYNC) {
|
|
65
64
|
inlineTranslationPaths.push({
|
|
66
65
|
localName: name.local,
|
|
67
66
|
path: parentPath,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Updates } from '../../../../types/index.js';
|
|
2
2
|
import { ParsingConfigOptions } from '../../../../types/parsing.js';
|
|
3
3
|
import traverseModule from '@babel/traverse';
|
|
4
|
-
import { GTLibrary } from '
|
|
4
|
+
import { GTLibrary } from '../../../../types/libraries.js';
|
|
5
5
|
/**
|
|
6
6
|
* Immutable configuration options for parsing.
|
|
7
7
|
*/
|
|
@@ -2,7 +2,8 @@ import * as t from '@babel/types';
|
|
|
2
2
|
import generateModule from '@babel/generator';
|
|
3
3
|
// Handle CommonJS/ESM interop
|
|
4
4
|
const generate = generateModule.default || generateModule;
|
|
5
|
-
import { GT_ATTRIBUTES
|
|
5
|
+
import { GT_ATTRIBUTES } from '../constants.js';
|
|
6
|
+
import { mapAttributeName } from '../mapAttributeName.js';
|
|
6
7
|
import { isStaticExpression } from '../../evaluateJsx.js';
|
|
7
8
|
import { warnInvalidMaxCharsSync, warnVariablePropSync, } from '../../../../console/index.js';
|
|
8
9
|
import { isNumberLiteral } from '../isNumberLiteral.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map the attribute name to the corresponding attribute name in the metadata
|
|
3
|
+
* @param attrName - The attribute name to map
|
|
4
|
+
* @returns The mapped attribute name
|
|
5
|
+
*/
|
|
6
|
+
export function mapAttributeName(attrName) {
|
|
7
|
+
if (attrName === '$id')
|
|
8
|
+
return 'id';
|
|
9
|
+
if (attrName === '$context')
|
|
10
|
+
return 'context';
|
|
11
|
+
if (attrName === '$maxChars')
|
|
12
|
+
return 'maxChars';
|
|
13
|
+
return attrName;
|
|
14
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as t from '@babel/types';
|
|
2
2
|
import { ParseResult } from '@babel/parser';
|
|
3
3
|
import { ImportDeclaration, VariableDeclaration } from '@babel/types';
|
|
4
|
-
import { GTLibrary } from '
|
|
4
|
+
import { GTLibrary } from '../../../types/libraries.js';
|
|
5
5
|
export declare function determineModuleType(ast: ParseResult<t.File>): boolean;
|
|
6
6
|
export type ImportItem = string | {
|
|
7
7
|
local: string;
|
|
@@ -5,7 +5,8 @@ import { parse } from '@babel/parser';
|
|
|
5
5
|
import fs from 'node:fs';
|
|
6
6
|
import { warnDeclareStaticNoResultsSync, warnFunctionNotFoundSync, warnInvalidDeclareVarNameSync, } from '../../../console/index.js';
|
|
7
7
|
import traverseModule from '@babel/traverse';
|
|
8
|
-
import { DECLARE_VAR_FUNCTION
|
|
8
|
+
import { DECLARE_VAR_FUNCTION } from '../../jsx/utils/constants.js';
|
|
9
|
+
import { GT_LIBRARIES } from '../../../types/libraries.js';
|
|
9
10
|
import { declareVar } from 'generaltranslation/internal';
|
|
10
11
|
import { isStaticExpression } from '../evaluateJsx.js';
|
|
11
12
|
import generateModule from '@babel/generator';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as t from '@babel/types';
|
|
2
2
|
import { isStaticExpression, isValidIcu } from '../evaluateJsx.js';
|
|
3
|
-
import { GT_ATTRIBUTES_WITH_SUGAR,
|
|
3
|
+
import { GT_ATTRIBUTES_WITH_SUGAR, MSG_REGISTRATION_FUNCTION, INLINE_TRANSLATION_HOOK, INLINE_TRANSLATION_HOOK_ASYNC, INLINE_MESSAGE_HOOK, INLINE_MESSAGE_HOOK_ASYNC, } from './constants.js';
|
|
4
|
+
import { mapAttributeName } from './mapAttributeName.js';
|
|
4
5
|
import { warnNonStaticExpressionSync, warnNonStringSync, warnTemplateLiteralSync, warnAsyncUseGT, warnSyncGetGT, warnInvalidIcuSync, warnInvalidMaxCharsSync, } from '../../../console/index.js';
|
|
5
6
|
import generateModule from '@babel/generator';
|
|
6
7
|
import traverseModule from '@babel/traverse';
|
|
@@ -432,7 +433,7 @@ export function parseStrings(importName, originalName, path, config, output) {
|
|
|
432
433
|
const referencePaths = path.scope.bindings[importName]?.referencePaths || [];
|
|
433
434
|
for (const refPath of referencePaths) {
|
|
434
435
|
// Handle msg() calls directly without variable assignment
|
|
435
|
-
if (originalName ===
|
|
436
|
+
if (originalName === MSG_REGISTRATION_FUNCTION) {
|
|
436
437
|
const msgConfig = {
|
|
437
438
|
parsingOptions: config.parsingOptions,
|
|
438
439
|
file: config.file,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Updates } from '../../types/index.js';
|
|
2
2
|
import type { ParsingConfigOptions } from '../../types/parsing.js';
|
|
3
|
-
import { GTLibrary } from '
|
|
3
|
+
import { GTLibrary } from '../../types/libraries.js';
|
|
4
4
|
export declare function createInlineUpdates(pkg: GTLibrary, validate: boolean, filePatterns: string[] | undefined, parsingOptions: ParsingConfigOptions): Promise<{
|
|
5
5
|
updates: Updates;
|
|
6
6
|
errors: string[];
|
|
@@ -7,7 +7,7 @@ import { logger } from '../../console/logger.js';
|
|
|
7
7
|
import { matchFiles } from '../../fs/matchFiles.js';
|
|
8
8
|
import { DEFAULT_SRC_PATTERNS } from '../../config/generateSettings.js';
|
|
9
9
|
import { getPathsAndAliases } from '../jsx/utils/getPathsAndAliases.js';
|
|
10
|
-
import { GT_LIBRARIES_UPSTREAM } from '
|
|
10
|
+
import { GT_LIBRARIES_UPSTREAM, REACT_LIBRARIES, } from '../../types/libraries.js';
|
|
11
11
|
export async function createInlineUpdates(pkg, validate, filePatterns, parsingOptions) {
|
|
12
12
|
const updates = [];
|
|
13
13
|
const errors = [];
|
|
@@ -41,24 +41,26 @@ export async function createInlineUpdates(pkg, validate, filePatterns, parsingOp
|
|
|
41
41
|
}, { updates, errors, warnings });
|
|
42
42
|
}
|
|
43
43
|
// Parse <T> components
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
44
|
+
if (REACT_LIBRARIES.includes(pkg)) {
|
|
45
|
+
for (const { localName, path } of translationComponentPaths) {
|
|
46
|
+
parseTranslationComponent({
|
|
47
|
+
originalName: localName,
|
|
48
|
+
localName,
|
|
49
|
+
path,
|
|
50
|
+
updates,
|
|
51
|
+
config: {
|
|
52
|
+
importAliases,
|
|
53
|
+
parsingOptions,
|
|
54
|
+
pkgs,
|
|
55
|
+
file,
|
|
56
|
+
},
|
|
57
|
+
output: {
|
|
58
|
+
errors,
|
|
59
|
+
warnings,
|
|
60
|
+
unwrappedExpressions: [],
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
}
|
|
62
64
|
}
|
|
63
65
|
}
|
|
64
66
|
// Post processing steps:
|
|
@@ -69,7 +71,8 @@ export async function createInlineUpdates(pkg, validate, filePatterns, parsingOp
|
|
|
69
71
|
}
|
|
70
72
|
/**
|
|
71
73
|
* Given a package name, return the upstream packages that it depends on
|
|
72
|
-
* @param pkg
|
|
74
|
+
* @param pkg - The package name
|
|
75
|
+
* @returns The upstream packages that the package depends on
|
|
73
76
|
*/
|
|
74
77
|
function getUpstreamPackages(pkg) {
|
|
75
78
|
return GT_LIBRARIES_UPSTREAM[pkg];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SupportedFrameworks, WrapOptions } from '../../types/index.js';
|
|
2
|
+
import { Libraries } from '../../types/libraries.js';
|
|
2
3
|
/**
|
|
3
4
|
* Wraps all JSX elements in the src directory with a <T> tag, with unique ids.
|
|
4
5
|
* - Ignores pure strings
|
|
@@ -6,6 +7,6 @@ import { SupportedFrameworks, WrapOptions } from '../../types/index.js';
|
|
|
6
7
|
* @param options - The options object
|
|
7
8
|
* @returns An object containing the updates and errors
|
|
8
9
|
*/
|
|
9
|
-
export declare function wrapContentReact(options: WrapOptions, pkg:
|
|
10
|
+
export declare function wrapContentReact(options: WrapOptions, pkg: typeof Libraries.GT_REACT, framework: SupportedFrameworks, errors: string[], warnings: string[]): Promise<{
|
|
10
11
|
filesUpdated: string[];
|
|
11
12
|
}>;
|
|
@@ -13,13 +13,13 @@ import { getRelativePath } from '../../fs/findFilepath.js';
|
|
|
13
13
|
import { generateImportMap, createImports, } from '../jsx/utils/parseAst.js';
|
|
14
14
|
import { DEFAULT_SRC_PATTERNS } from '../../config/generateSettings.js';
|
|
15
15
|
import { matchFiles } from '../../fs/matchFiles.js';
|
|
16
|
+
import { Libraries } from '../../types/libraries.js';
|
|
16
17
|
const IMPORT_MAP = {
|
|
17
|
-
T: { name: 'T', source:
|
|
18
|
-
Var: { name: 'Var', source:
|
|
19
|
-
GTT: { name: 'T', source:
|
|
20
|
-
GTVar: { name: 'Var', source:
|
|
21
|
-
GTProvider: { name: 'GTProvider', source:
|
|
22
|
-
// getLocale: { name: 'getLocale', source: 'gt-react/server' },
|
|
18
|
+
T: { name: 'T', source: Libraries.GT_REACT },
|
|
19
|
+
Var: { name: 'Var', source: Libraries.GT_REACT },
|
|
20
|
+
GTT: { name: 'T', source: Libraries.GT_REACT },
|
|
21
|
+
GTVar: { name: 'Var', source: Libraries.GT_REACT },
|
|
22
|
+
GTProvider: { name: 'GTProvider', source: Libraries.GT_REACT },
|
|
23
23
|
};
|
|
24
24
|
/**
|
|
25
25
|
* Wraps all JSX elements in the src directory with a <T> tag, with unique ids.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { SupportedLibraries } from '../types/index.js';
|
|
2
|
+
export declare const CURSOR_GT_RULES_FILE = ".cursor/rules/gt-i18n.mdc";
|
|
3
|
+
/**
|
|
4
|
+
* Detect existing AI agent instruction files in the project.
|
|
5
|
+
*/
|
|
6
|
+
export declare function findAgentFiles(): string[];
|
|
7
|
+
/**
|
|
8
|
+
* Find agent files that already contain GT instructions.
|
|
9
|
+
*/
|
|
10
|
+
export declare function findAgentFilesWithInstructions(): string[];
|
|
11
|
+
/**
|
|
12
|
+
* Check if the .cursor/rules/ directory exists (for offering to create gt-i18n.mdc).
|
|
13
|
+
*/
|
|
14
|
+
export declare function hasCursorRulesDir(): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Generate GT agent instructions content based on the detected library.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getAgentInstructions(library: SupportedLibraries): string;
|
|
19
|
+
/**
|
|
20
|
+
* Append or replace GT instructions in an agent file.
|
|
21
|
+
* Skips writing if the file already contains identical instructions.
|
|
22
|
+
* For .cursor/rules/gt.md, writes the file fresh (dedicated GT rules file).
|
|
23
|
+
*/
|
|
24
|
+
export declare function appendAgentInstructions(filePath: string, instructions: string): boolean;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { getCLIVersion, getPackageVersion } from '../utils/packageJson.js';
|
|
5
|
+
import { Libraries } from '../types/libraries.js';
|
|
6
|
+
const INSTRUCTIONS_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), 'instructions');
|
|
7
|
+
const AGENT_FILE_PATHS = [
|
|
8
|
+
'CLAUDE.md',
|
|
9
|
+
'AGENTS.md',
|
|
10
|
+
'GPT.md',
|
|
11
|
+
'CHATGPT.md',
|
|
12
|
+
'.cursorrules',
|
|
13
|
+
];
|
|
14
|
+
const CURSOR_RULES_DIR = '.cursor/rules';
|
|
15
|
+
export const CURSOR_GT_RULES_FILE = '.cursor/rules/gt-i18n.mdc';
|
|
16
|
+
const GT_SECTION_START = '<!-- GT I18N RULES START -->';
|
|
17
|
+
const GT_SECTION_END = '<!-- GT I18N RULES END -->';
|
|
18
|
+
function getLibraryVersion(library) {
|
|
19
|
+
const packageJsonPath = path.resolve(process.cwd(), 'package.json');
|
|
20
|
+
if (!fs.existsSync(packageJsonPath))
|
|
21
|
+
return undefined;
|
|
22
|
+
try {
|
|
23
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
24
|
+
return getPackageVersion(library, packageJson);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Detect existing AI agent instruction files in the project.
|
|
32
|
+
*/
|
|
33
|
+
export function findAgentFiles() {
|
|
34
|
+
const cwd = process.cwd();
|
|
35
|
+
const found = [];
|
|
36
|
+
for (const filePath of [...AGENT_FILE_PATHS, CURSOR_GT_RULES_FILE]) {
|
|
37
|
+
const fullPath = path.resolve(cwd, filePath);
|
|
38
|
+
if (fs.existsSync(fullPath)) {
|
|
39
|
+
found.push(filePath);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return found;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Find agent files that already contain GT instructions.
|
|
46
|
+
*/
|
|
47
|
+
export function findAgentFilesWithInstructions() {
|
|
48
|
+
const cwd = process.cwd();
|
|
49
|
+
const found = [];
|
|
50
|
+
for (const filePath of [...AGENT_FILE_PATHS, CURSOR_GT_RULES_FILE]) {
|
|
51
|
+
const fullPath = path.resolve(cwd, filePath);
|
|
52
|
+
if (fs.existsSync(fullPath)) {
|
|
53
|
+
const content = fs.readFileSync(fullPath, 'utf8');
|
|
54
|
+
if (content.includes(GT_SECTION_START)) {
|
|
55
|
+
found.push(filePath);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return found;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Check if the .cursor/rules/ directory exists (for offering to create gt-i18n.mdc).
|
|
63
|
+
*/
|
|
64
|
+
export function hasCursorRulesDir() {
|
|
65
|
+
const cursorRulesDir = path.resolve(process.cwd(), CURSOR_RULES_DIR);
|
|
66
|
+
return (fs.existsSync(cursorRulesDir) && fs.statSync(cursorRulesDir).isDirectory());
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Generate GT agent instructions content based on the detected library.
|
|
70
|
+
*/
|
|
71
|
+
export function getAgentInstructions(library) {
|
|
72
|
+
const libraryVersion = getLibraryVersion(library);
|
|
73
|
+
const versionLine = libraryVersion
|
|
74
|
+
? `- **${library}**: ${libraryVersion}\n- **gtx-cli**: v${getCLIVersion()}`
|
|
75
|
+
: `- **gtx-cli**: v${getCLIVersion()}`;
|
|
76
|
+
const base = fs.readFileSync(path.join(INSTRUCTIONS_DIR, 'base.md'), 'utf8');
|
|
77
|
+
let body = '';
|
|
78
|
+
const libToFile = {
|
|
79
|
+
[Libraries.GT_NEXT]: 'gt-next.md',
|
|
80
|
+
[Libraries.GT_REACT]: 'gt-react.md',
|
|
81
|
+
// TODO: add gt-react-native.md
|
|
82
|
+
[Libraries.GT_REACT_NATIVE]: 'gt-react.md',
|
|
83
|
+
};
|
|
84
|
+
const instructionFile = libToFile[library];
|
|
85
|
+
if (instructionFile) {
|
|
86
|
+
body += '\n\n'; // add two newlines between the base and the specific instructions
|
|
87
|
+
body += fs.readFileSync(path.join(INSTRUCTIONS_DIR, instructionFile), 'utf8');
|
|
88
|
+
}
|
|
89
|
+
return `${GT_SECTION_START}
|
|
90
|
+
|
|
91
|
+
${versionLine}
|
|
92
|
+
|
|
93
|
+
${base}${body}
|
|
94
|
+
${GT_SECTION_END}`;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Append or replace GT instructions in an agent file.
|
|
98
|
+
* Skips writing if the file already contains identical instructions.
|
|
99
|
+
* For .cursor/rules/gt.md, writes the file fresh (dedicated GT rules file).
|
|
100
|
+
*/
|
|
101
|
+
export function appendAgentInstructions(filePath, instructions) {
|
|
102
|
+
const fullPath = path.resolve(process.cwd(), filePath);
|
|
103
|
+
// For .cursor/rules/gt.md, write as a standalone file with frontmatter
|
|
104
|
+
if (filePath === CURSOR_GT_RULES_FILE) {
|
|
105
|
+
const cursorContent = `---\ndescription: GT internationalization instructions\nalwaysApply: true\n---\n${instructions}\n`;
|
|
106
|
+
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
|
|
107
|
+
if (fs.existsSync(fullPath)) {
|
|
108
|
+
const existing = fs.readFileSync(fullPath, 'utf8');
|
|
109
|
+
if (existing === cursorContent)
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
fs.writeFileSync(fullPath, cursorContent, 'utf8');
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
// For other files, read existing content and append/replace
|
|
116
|
+
let content = '';
|
|
117
|
+
if (fs.existsSync(fullPath)) {
|
|
118
|
+
content = fs.readFileSync(fullPath, 'utf8');
|
|
119
|
+
}
|
|
120
|
+
// Already has identical instructions — skip
|
|
121
|
+
if (content.includes(instructions))
|
|
122
|
+
return false;
|
|
123
|
+
const startIdx = content.indexOf(GT_SECTION_START);
|
|
124
|
+
const endIdx = startIdx !== -1 ? content.indexOf(GT_SECTION_END, startIdx) : -1;
|
|
125
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
126
|
+
// Replace existing section
|
|
127
|
+
const before = content.substring(0, startIdx);
|
|
128
|
+
const after = content.substring(endIdx + GT_SECTION_END.length);
|
|
129
|
+
content = before + instructions + after;
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
// Append to end
|
|
133
|
+
const separator = content.length > 0 && !content.endsWith('\n') ? '\n' : '';
|
|
134
|
+
content = content + separator + '\n' + instructions + '\n';
|
|
135
|
+
}
|
|
136
|
+
fs.writeFileSync(fullPath, content, 'utf8');
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Libraries } from '../types/libraries.js';
|
|
1
2
|
export function getFrameworkDisplayName(frameworkObject) {
|
|
2
3
|
if (frameworkObject.name === 'mintlify') {
|
|
3
4
|
return 'Mintlify';
|
|
@@ -23,5 +24,7 @@ export function getFrameworkDisplayName(frameworkObject) {
|
|
|
23
24
|
return 'another framework';
|
|
24
25
|
}
|
|
25
26
|
export function getReactFrameworkLibrary(frameworkObject) {
|
|
26
|
-
return frameworkObject.name === 'next-app'
|
|
27
|
+
return frameworkObject.name === 'next-app'
|
|
28
|
+
? Libraries.GT_NEXT
|
|
29
|
+
: Libraries.GT_REACT;
|
|
27
30
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# General Translation (GT) Internationalization Rules
|
|
2
|
+
|
|
3
|
+
This project is using [General Translation](https://generaltranslation.com/docs/overview.md) for internationalization (i18n) and translations. General Translation is a developer-first localization stack, built for the world's best engineering teams to ship apps in every language with ease.
|
|
4
|
+
|
|
5
|
+
## Configuration
|
|
6
|
+
|
|
7
|
+
The General Translation configuration file is called `gt.config.json`. It is usually located in the root or src directory of a project.
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"defaultLocale": "en",
|
|
12
|
+
"locales": ["es", "fr", "de"],
|
|
13
|
+
"files": {
|
|
14
|
+
"json": {
|
|
15
|
+
"include": ["./**/[locale]/*.json"]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The API reference for the config file can be found at <https://generaltranslation.com/docs/cli/reference/config.md>.
|
|
22
|
+
|
|
23
|
+
## Translation
|
|
24
|
+
|
|
25
|
+
Run `npx gtx-cli translate` to create translation files for your project. You must have an API key to do this.
|
|
26
|
+
|
|
27
|
+
## Documentation
|
|
28
|
+
|
|
29
|
+
<https://generaltranslation.com/llms.txt>
|