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.
Files changed (50) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/cli/base.d.ts +2 -0
  3. package/dist/cli/base.js +76 -14
  4. package/dist/cli/flags.d.ts +12 -1
  5. package/dist/cli/flags.js +24 -5
  6. package/dist/cli/inline.d.ts +17 -0
  7. package/dist/cli/inline.js +133 -0
  8. package/dist/cli/next.d.ts +2 -3
  9. package/dist/cli/next.js +2 -11
  10. package/dist/cli/node.d.ts +10 -0
  11. package/dist/cli/node.js +9 -0
  12. package/dist/cli/react.d.ts +4 -11
  13. package/dist/cli/react.js +7 -121
  14. package/dist/formats/files/collectFiles.js +4 -3
  15. package/dist/fs/determineFramework.js +11 -4
  16. package/dist/generated/version.d.ts +1 -1
  17. package/dist/generated/version.js +1 -1
  18. package/dist/index.js +8 -2
  19. package/dist/next/parse/wrapContent.d.ts +2 -1
  20. package/dist/next/parse/wrapContent.js +8 -7
  21. package/dist/react/jsx/utils/constants.d.ts +1 -5
  22. package/dist/react/jsx/utils/constants.js +2 -43
  23. package/dist/react/jsx/utils/getPathsAndAliases.d.ts +1 -1
  24. package/dist/react/jsx/utils/getPathsAndAliases.js +3 -4
  25. package/dist/react/jsx/utils/jsxParsing/parseJsx.d.ts +1 -1
  26. package/dist/react/jsx/utils/jsxParsing/parseTProps.js +2 -1
  27. package/dist/react/jsx/utils/mapAttributeName.d.ts +6 -0
  28. package/dist/react/jsx/utils/mapAttributeName.js +14 -0
  29. package/dist/react/jsx/utils/parseAst.d.ts +1 -1
  30. package/dist/react/jsx/utils/parseString.js +2 -1
  31. package/dist/react/jsx/utils/parseStringFunction.js +3 -2
  32. package/dist/react/parse/createInlineUpdates.d.ts +1 -1
  33. package/dist/react/parse/createInlineUpdates.js +23 -20
  34. package/dist/react/parse/wrapContent.d.ts +2 -1
  35. package/dist/react/parse/wrapContent.js +6 -6
  36. package/dist/setup/agentInstructions.d.ts +24 -0
  37. package/dist/setup/agentInstructions.js +138 -0
  38. package/dist/setup/frameworkUtils.js +4 -1
  39. package/dist/setup/instructions/base.md +29 -0
  40. package/dist/setup/instructions/gt-next.md +107 -0
  41. package/dist/setup/instructions/gt-react.md +98 -0
  42. package/dist/setup/wizard.js +10 -9
  43. package/dist/translation/parse.d.ts +2 -1
  44. package/dist/translation/stage.d.ts +2 -1
  45. package/dist/translation/stage.js +1 -1
  46. package/dist/translation/validate.d.ts +4 -3
  47. package/dist/types/index.d.ts +3 -2
  48. package/dist/types/libraries.d.ts +31 -0
  49. package/dist/types/libraries.js +72 -0
  50. 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['gt-next']) {
25
- library = 'gt-next';
25
+ if (dependencies[Libraries.GT_NEXT]) {
26
+ library = Libraries.GT_NEXT;
26
27
  }
27
- else if (dependencies['gt-react']) {
28
- library = 'gt-react';
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.17";
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.17';
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 === 'gt-next') {
11
+ if (library === Libraries.GT_NEXT) {
10
12
  cli = new NextCLI(program, library, additionalModules);
11
13
  }
12
- else if (library === 'gt-react') {
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: 'gt-next', errors: string[], warnings: string[]): Promise<{
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: 'gt-next' },
18
- Var: { name: 'Var', source: 'gt-next' },
19
- GTT: { name: 'T', source: 'gt-next' },
20
- GTVar: { name: 'Var', source: 'gt-next' },
21
- GTProvider: { name: 'GTProvider', source: 'gt-next' },
22
- getLocale: { name: 'getLocale', source: 'gt-next/server' },
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 === 'gt-next' &&
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 MSG_TRANSLATION_FUNCTION = "msg";
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 MSG_TRANSLATION_FUNCTION = 'msg';
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
- MSG_TRANSLATION_FUNCTION,
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 '../../jsx/utils/constants.js';
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, MSG_TRANSLATION_FUNCTION, TRANSLATION_COMPONENT, } from '../../jsx/utils/constants.js';
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 === MSG_TRANSLATION_FUNCTION) {
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 '../constants.js';
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, mapAttributeName } from '../constants.js';
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,6 @@
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 declare function mapAttributeName(attrName: string): string;
@@ -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 './constants.js';
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, GT_LIBRARIES } from './constants.js';
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, MSG_TRANSLATION_FUNCTION, INLINE_TRANSLATION_HOOK, INLINE_TRANSLATION_HOOK_ASYNC, mapAttributeName, INLINE_MESSAGE_HOOK, INLINE_MESSAGE_HOOK_ASYNC, } from './constants.js';
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 === MSG_TRANSLATION_FUNCTION) {
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 '../jsx/utils/constants.js';
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 '../jsx/utils/constants.js';
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
- for (const { localName, path } of translationComponentPaths) {
45
- parseTranslationComponent({
46
- originalName: localName,
47
- localName,
48
- path,
49
- updates,
50
- config: {
51
- importAliases,
52
- parsingOptions,
53
- pkgs,
54
- file,
55
- },
56
- output: {
57
- errors,
58
- warnings,
59
- unwrappedExpressions: [],
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: 'gt-react', framework: SupportedFrameworks, errors: string[], warnings: string[]): Promise<{
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: 'gt-react' },
18
- Var: { name: 'Var', source: 'gt-react' },
19
- GTT: { name: 'T', source: 'gt-react' },
20
- GTVar: { name: 'Var', source: 'gt-react' },
21
- GTProvider: { name: 'GTProvider', source: 'gt-react' },
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' ? 'gt-next' : 'gt-react';
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>