gt 2.14.7 → 2.14.8

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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # gtx-cli
2
2
 
3
+ ## 2.14.8
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1187](https://github.com/generaltranslation/gt/pull/1187) [`9281fe5`](https://github.com/generaltranslation/gt/commit/9281fe5d9c2f3e35b67ccedb9c444aebbb6a8bd1) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - fix(cli): extend autoderive gt msg
8
+
9
+ - [#1185](https://github.com/generaltranslation/gt/pull/1185) [`121be24`](https://github.com/generaltranslation/gt/commit/121be24def7f9dc464b8589bf0be14d04ac3e6e1) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - fix: exploration of properties for Branch and Plural during multiplication step
10
+
11
+ - [#1186](https://github.com/generaltranslation/gt/pull/1186) [`7a3c7de`](https://github.com/generaltranslation/gt/commit/7a3c7de8e5d5103bd9fec893a677a13068f822e6) Thanks [@moss-bryophyta](https://github.com/moss-bryophyta)! - Warn when Mintlify docs.json contains unsupported $ref fields
12
+
3
13
  ## 2.14.7
4
14
 
5
15
  ## 2.14.6
@@ -53,6 +53,6 @@ export declare class BaseCLI {
53
53
  protected setupInitCommand(): void;
54
54
  protected setupConfigureCommand(): void;
55
55
  protected handleUploadCommand(settings: Settings & UploadOptions): Promise<void>;
56
- protected handleInitCommand(ranReactSetup: boolean, useDefaults?: boolean): Promise<void>;
56
+ protected handleInitCommand(ranReactSetup: boolean, useDefaults?: boolean, isVite?: boolean): Promise<void>;
57
57
  protected handleLoginCommand(options: LoginOptions): Promise<void>;
58
58
  }
package/dist/cli/base.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { DEFAULT_TRANSLATIONS_DIR, DEFAULT_VITE_TRANSLATIONS_DIR, } from '../utils/constants.js';
1
2
  import { createOrUpdateConfig } from '../fs/config/setupConfig.js';
2
3
  import findFilepath from '../fs/findFilepath.js';
3
4
  import { displayHeader, promptText, logErrorAndExit, promptConfirm, promptMultiSelect, promptSelect, } from '../console/logging.js';
@@ -271,9 +272,12 @@ export class BaseCLI {
271
272
  ? getReactFrameworkLibrary(framework)
272
273
  : null;
273
274
  // Build defaults description based on detected framework
275
+ const defaultTranslationsDir = framework.name === 'vite'
276
+ ? DEFAULT_VITE_TRANSLATIONS_DIR
277
+ : DEFAULT_TRANSLATIONS_DIR;
274
278
  const defaultsDescription = framework.type === 'react'
275
- ? `${library} & GTProvider, ${frameworkDisplayName}, Files saved locally in ./public/_gt`
276
- : 'Files saved locally in ./public/_gt';
279
+ ? `${library} & GTProvider, ${frameworkDisplayName}, Files saved locally in ${defaultTranslationsDir}`
280
+ : `Files saved locally in ${defaultTranslationsDir}`;
277
281
  // Ask if user wants to use defaults
278
282
  const useDefaults = await promptConfirm({
279
283
  message: `Would you like to use the recommended General Translation defaults? ${chalk.dim(`(${defaultsDescription})`)}`,
@@ -300,7 +304,7 @@ export class BaseCLI {
300
304
  logger.startCommand('Setting up project config...');
301
305
  }
302
306
  // Configure gt.config.json
303
- await this.handleInitCommand(ranReactSetup, useDefaults);
307
+ await this.handleInitCommand(ranReactSetup, useDefaults, framework.name === 'vite');
304
308
  logger.endCommand('Done! Check out our docs for more information on how to use General Translation: https://generaltranslation.com/docs');
305
309
  }
306
310
  });
@@ -313,7 +317,8 @@ export class BaseCLI {
313
317
  displayHeader('Configuring project...');
314
318
  logger.info('Welcome! This tool will help you configure your gt.config.json file. See the docs: https://generaltranslation.com/docs/cli/reference/config for more information.');
315
319
  // Configure gt.config.json
316
- await this.handleInitCommand(false);
320
+ const framework = await detectFramework();
321
+ await this.handleInitCommand(false, false, framework.name === 'vite');
317
322
  logger.endCommand('Done! Make sure you have an API key and project ID to use General Translation. Get them on the dashboard: https://generaltranslation.com/dashboard');
318
323
  });
319
324
  }
@@ -342,7 +347,7 @@ export class BaseCLI {
342
347
  await upload(sourceFiles, placeholderPaths, transformPaths, dataFormat, settings);
343
348
  }
344
349
  // Wizard for configuring gt.config.json
345
- async handleInitCommand(ranReactSetup, useDefaults = false) {
350
+ async handleInitCommand(ranReactSetup, useDefaults = false, isVite = false) {
346
351
  const { defaultLocale, locales } = await getDesiredLocales(); // Locales should still be asked for even if using defaults
347
352
  const packageJson = await searchForPackageJson();
348
353
  // Ask if using another i18n library
@@ -365,17 +370,20 @@ export class BaseCLI {
365
370
  });
366
371
  return selectedValue === 'cdn';
367
372
  })();
373
+ const defaultTranslationsDir = isVite
374
+ ? DEFAULT_VITE_TRANSLATIONS_DIR
375
+ : DEFAULT_TRANSLATIONS_DIR;
368
376
  // Ask where the translations are stored
369
377
  const translationsDir = isUsingGT && !usingCDN
370
378
  ? useDefaults
371
- ? './public/_gt'
379
+ ? defaultTranslationsDir
372
380
  : await promptText({
373
381
  message: 'What is the path to the directory where you would like to store your translation files?',
374
- defaultValue: './public/_gt',
382
+ defaultValue: defaultTranslationsDir,
375
383
  })
376
384
  : null;
377
385
  // Determine final translations directory with fallback
378
- const finalTranslationsDir = translationsDir?.trim() || './public/_gt';
386
+ const finalTranslationsDir = translationsDir?.trim() || defaultTranslationsDir;
379
387
  if (isUsingGT && !usingCDN) {
380
388
  // Create loadTranslations.js file for local translations
381
389
  await createLoadTranslationsFile(process.cwd(), finalTranslationsDir, locales);
@@ -2,11 +2,12 @@ import { noSupportedFormatError, noDefaultLocaleError, } from '../../console/ind
2
2
  import { exitSync, logErrorAndExit } from '../../console/logging.js';
3
3
  import { logger } from '../../console/logger.js';
4
4
  import { getRelative, readFile } from '../../fs/findFilepath.js';
5
+ import path from 'node:path';
5
6
  import { SUPPORTED_FILE_EXTENSIONS } from '../../formats/files/supportedFiles.js';
6
7
  import sanitizeFileContent from '../../utils/sanitizeFileContent.js';
7
8
  import { parseJson } from '../../formats/json/parseJson.js';
8
9
  import { extractJson } from '../../formats/json/extractJson.js';
9
- import { validateJsonSchema } from '../../formats/json/utils.js';
10
+ import { validateJsonSchema, detectMintlifyUnsupportedFields, } from '../../formats/json/utils.js';
10
11
  import { runUploadFilesWorkflow } from '../../workflows/upload.js';
11
12
  import { existsSync, readFileSync } from 'node:fs';
12
13
  import { createFileMapping } from '../../formats/files/fileMapping.js';
@@ -37,6 +38,16 @@ export async function upload(filePaths, placeholderPaths, transformPaths, dataFo
37
38
  }
38
39
  const jsonFiles = filePaths.json.map((filePath) => {
39
40
  const content = readFile(filePath);
41
+ // Detect unsupported fields in Mintlify docs.json
42
+ if (settings.framework === 'mintlify' &&
43
+ path.basename(filePath) === 'docs.json') {
44
+ try {
45
+ detectMintlifyUnsupportedFields(JSON.parse(content), filePath);
46
+ }
47
+ catch {
48
+ // JSON parse errors are handled below by parseJson
49
+ }
50
+ }
40
51
  const parsedJson = parseJson(content, filePath, additionalOptions, settings.defaultLocale);
41
52
  const relativePath = getRelative(filePath);
42
53
  const jsonSchema = validateJsonSchema(additionalOptions, filePath);
@@ -3,6 +3,8 @@ import { recordWarning } from '../../state/translateWarnings.js';
3
3
  import { getRelative, readFile } from '../../fs/findFilepath.js';
4
4
  import { SUPPORTED_FILE_EXTENSIONS } from './supportedFiles.js';
5
5
  import { parseJson } from '../json/parseJson.js';
6
+ import { detectMintlifyUnsupportedFields } from '../json/utils.js';
7
+ import path from 'node:path';
6
8
  import parseYaml from '../yaml/parseYaml.js';
7
9
  import { validateYamlSchema } from '../yaml/utils.js';
8
10
  import { flattenJson } from '../json/flattenJson.js';
@@ -73,6 +75,16 @@ export async function aggregateFiles(settings) {
73
75
  return null;
74
76
  }
75
77
  }
78
+ // Detect unsupported fields in Mintlify docs.json
79
+ if (settings.framework === 'mintlify' &&
80
+ path.basename(filePath) === 'docs.json') {
81
+ try {
82
+ detectMintlifyUnsupportedFields(JSON.parse(content), filePath);
83
+ }
84
+ catch {
85
+ // JSON parse errors are handled below by parseJson
86
+ }
87
+ }
76
88
  const parsedJson = parseJson(content, filePath, settings.options || {}, settings.defaultLocale);
77
89
  // Detect companion metadata file
78
90
  let keyedMetadata;
@@ -52,3 +52,8 @@ export declare function generateSourceObjectPointers(jsonSchema: {
52
52
  * @returns exitSync(1) if the json schema is invalid
53
53
  */
54
54
  export declare function validateJsonSchema(options: AdditionalOptions, filePath: string): JsonSchema | null;
55
+ /**
56
+ * Detect unsupported fields (e.g. $ref) in Mintlify docs.json files.
57
+ * Logs a warning listing the fields found.
58
+ */
59
+ export declare function detectMintlifyUnsupportedFields(json: any, filePath: string): void;
@@ -3,6 +3,7 @@ import { exitSync } from '../../console/logging.js';
3
3
  import { logger } from '../../console/logger.js';
4
4
  import { JSONPath } from 'jsonpath-plus';
5
5
  import { flattenJson } from './flattenJson.js';
6
+ import chalk from 'chalk';
6
7
  import path from 'node:path';
7
8
  import micromatch from 'micromatch';
8
9
  const { isMatch } = micromatch;
@@ -160,3 +161,46 @@ export function validateJsonSchema(options, filePath) {
160
161
  }
161
162
  return jsonSchema;
162
163
  }
164
+ const UNSUPPORTED_MINTLIFY_FIELDS = ['$ref'];
165
+ /**
166
+ * Recursively traverse a JSON value and collect all objects whose key
167
+ * matches one of the unsupported field names.
168
+ */
169
+ function findMintlifyUnsupportedFields(value, fieldNames, pointer = '') {
170
+ if (value === null || typeof value !== 'object')
171
+ return [];
172
+ if (Array.isArray(value)) {
173
+ const results = [];
174
+ for (let i = 0; i < value.length; i++) {
175
+ results.push(...findMintlifyUnsupportedFields(value[i], fieldNames, `${pointer}/${i}`));
176
+ }
177
+ return results;
178
+ }
179
+ // Check if this object contains an unsupported field
180
+ for (const field of fieldNames) {
181
+ if (typeof value[field] === 'string') {
182
+ return [{ pointer, field, fieldValue: value[field] }];
183
+ }
184
+ }
185
+ // Recurse into child properties
186
+ const results = [];
187
+ for (const key of Object.keys(value)) {
188
+ results.push(...findMintlifyUnsupportedFields(value[key], fieldNames, `${pointer}/${key}`));
189
+ }
190
+ return results;
191
+ }
192
+ /**
193
+ * Detect unsupported fields (e.g. $ref) in Mintlify docs.json files.
194
+ * Logs a warning listing the fields found.
195
+ */
196
+ export function detectMintlifyUnsupportedFields(json, filePath) {
197
+ const unsupported = findMintlifyUnsupportedFields(json, UNSUPPORTED_MINTLIFY_FIELDS);
198
+ if (unsupported.length > 0) {
199
+ const fileName = path.basename(filePath);
200
+ const lines = unsupported
201
+ .map((u) => chalk.yellow('• ') +
202
+ chalk.white(`${u.pointer.replace(/\//g, '.').replace(/^\./, '')}.${u.field}`))
203
+ .join('\n');
204
+ logger.warn(chalk.yellow(`Mintlify config splitting is not yet supported. The following \`$ref\` fields were detected in \`${fileName}\` and will not be resolved:\n`) + lines);
205
+ }
206
+ }
@@ -2,7 +2,8 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { logger } from '../console/logger.js';
4
4
  import chalk from 'chalk';
5
- export async function createLoadTranslationsFile(appDirectory, translationsDir = './public/_gt', locales) {
5
+ import { DEFAULT_TRANSLATIONS_DIR } from '../utils/constants.js';
6
+ export async function createLoadTranslationsFile(appDirectory, translationsDir = DEFAULT_TRANSLATIONS_DIR, locales) {
6
7
  const usingSrcDirectory = fs.existsSync(path.join(appDirectory, 'src'));
7
8
  // Calculate the relative path from the loadTranslations.js location to the translations directory
8
9
  const loadTranslationsDir = usingSrcDirectory
@@ -1 +1 @@
1
- export declare const PACKAGE_VERSION = "2.14.7";
1
+ export declare const PACKAGE_VERSION = "2.14.8";
@@ -1,2 +1,2 @@
1
1
  // This file is auto-generated. Do not edit manually.
2
- export const PACKAGE_VERSION = '2.14.7';
2
+ export const PACKAGE_VERSION = '2.14.8';
@@ -1,4 +1,6 @@
1
1
  import { isWhitespaceMultiplicationNode, isWhitespaceJsxTree, } from '../types.js';
2
+ import { isAcceptedPluralForm } from 'generaltranslation/internal';
3
+ import { PLURAL_COMPONENT, BRANCH_COMPONENT, BRANCH_CONTROL_PROPS, } from '../../constants.js';
2
4
  /**
3
5
  * Finds the immediate multiplication node from the given root (eg no nested multiplication nodes)
4
6
  * TODO: I am sure there is some optimization to be done here
@@ -28,12 +30,34 @@ export function findMultiplicationNode(root) {
28
30
  return { parent, key, node: curr };
29
31
  }
30
32
  else if (isWhitespaceJsxTree(curr)) {
31
- if (curr.props?.children) {
32
- return handleChildren(curr.props.children, curr.props, 'children');
33
- }
34
- else {
33
+ if (!curr.props)
35
34
  return undefined;
35
+ // Check children first
36
+ if (curr.props.children) {
37
+ const result = handleChildren(curr.props.children, curr.props, 'children');
38
+ if (result)
39
+ return result;
36
40
  }
41
+ // For Plural/Branch, also search translatable content props
42
+ // Mirrors the prop filtering in handleChildrenWhitespace.ts and autoInsertion.ts
43
+ const elementIsPlural = curr.type === PLURAL_COMPONENT;
44
+ const elementIsBranch = curr.type === BRANCH_COMPONENT;
45
+ if (elementIsPlural || elementIsBranch) {
46
+ for (const [propKey, propValue] of Object.entries(curr.props)) {
47
+ if (propKey === 'children')
48
+ continue;
49
+ if (elementIsPlural && !isAcceptedPluralForm(propKey))
50
+ continue;
51
+ if (elementIsBranch && BRANCH_CONTROL_PROPS.has(propKey))
52
+ continue;
53
+ if (propValue && typeof propValue === 'object') {
54
+ const result = handleChildren(propValue, curr.props, propKey);
55
+ if (result)
56
+ return result;
57
+ }
58
+ }
59
+ }
60
+ return undefined;
37
61
  }
38
62
  else {
39
63
  return undefined;
@@ -1,5 +1,5 @@
1
1
  import * as t from '@babel/types';
2
- import { INLINE_TRANSLATION_HOOK, INLINE_TRANSLATION_HOOK_ASYNC, INLINE_MESSAGE_HOOK, INLINE_MESSAGE_HOOK_ASYNC, STRING_REGISTRATION_FUNCS, T_GLOBAL_REGISTRATION_FUNCTION_MARKER, T_REGISTRATION_FUNCTION, } from './constants.js';
2
+ import { INLINE_TRANSLATION_HOOK, INLINE_TRANSLATION_HOOK_ASYNC, INLINE_MESSAGE_HOOK, INLINE_MESSAGE_HOOK_ASYNC, STRING_REGISTRATION_FUNCS, T_GLOBAL_REGISTRATION_FUNCTION_MARKER, } from './constants.js';
3
3
  import { warnAsyncUseGT, warnSyncGetGT } from '../../../console/index.js';
4
4
  import traverseModule from '@babel/traverse';
5
5
  // Handle CommonJS/ESM interop
@@ -323,7 +323,7 @@ export function parseStrings(importName, originalName, path, config, output) {
323
323
  if (refPath.parent.type === 'CallExpression' &&
324
324
  refPath.parent.callee === refPath.node) {
325
325
  /**
326
- * SPECIAL CASE: Auto-derive t() function
326
+ * CASE: Auto-derive t() and msg() function
327
327
  * The t() function, will treat variable content as if it was marked for derivation
328
328
  * without explicit calls to derive().
329
329
  *
@@ -336,17 +336,12 @@ export function parseStrings(importName, originalName, path, config, output) {
336
336
  * );
337
337
  * // "Hello, John! My name is {interpolatedValue}"
338
338
  */
339
- if (originalName === T_REGISTRATION_FUNCTION) {
340
- processTranslationCall(refPath, config.autoDeriveMethod === 'AUTO'
341
- ? {
342
- ...stringRegistrationConfig,
343
- autoDeriveMethod: 'ENABLED',
344
- }
345
- : stringRegistrationConfig, output);
346
- }
347
- else {
348
- processTranslationCall(refPath, stringRegistrationConfig, output);
349
- }
339
+ processTranslationCall(refPath, config.autoDeriveMethod === 'AUTO'
340
+ ? {
341
+ ...stringRegistrationConfig,
342
+ autoDeriveMethod: 'ENABLED',
343
+ }
344
+ : stringRegistrationConfig, output);
350
345
  }
351
346
  else if (!stringRegistrationConfig.ignoreTaggedTemplates &&
352
347
  refPath.parent.type === 'TaggedTemplateExpression' &&
@@ -392,7 +387,9 @@ export function parseStrings(importName, originalName, path, config, output) {
392
387
  ignoreGlobalTaggedTemplates: false,
393
388
  // User configurable, otherwise default to DISABLED
394
389
  autoDeriveMethod: config.autoDeriveMethod === 'AUTO'
395
- ? 'DISABLED'
390
+ ? isInlineGT
391
+ ? 'ENABLED'
392
+ : 'DISABLED'
396
393
  : config.autoDeriveMethod,
397
394
  };
398
395
  const effectiveParent = parentPath?.node.type === 'AwaitExpression'
@@ -5,3 +5,5 @@ export declare const TEMPLATE_FILE_ID: string;
5
5
  export declare const DEFAULT_GIT_REMOTE_NAME = "origin";
6
6
  export declare const DEFAULT_TIMEOUT_SECONDS = 900;
7
7
  export declare const SURROUNDING_LINE_COUNT = 5;
8
+ export declare const DEFAULT_TRANSLATIONS_DIR = "./public/_gt";
9
+ export declare const DEFAULT_VITE_TRANSLATIONS_DIR = "./src/_gt";
@@ -7,3 +7,6 @@ export const DEFAULT_GIT_REMOTE_NAME = 'origin';
7
7
  export const DEFAULT_TIMEOUT_SECONDS = 900;
8
8
  // Number of source code lines to capture above and below a translation site
9
9
  export const SURROUNDING_LINE_COUNT = 5;
10
+ // Default translations directory paths
11
+ export const DEFAULT_TRANSLATIONS_DIR = './public/_gt';
12
+ export const DEFAULT_VITE_TRANSLATIONS_DIR = './src/_gt';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gt",
3
- "version": "2.14.7",
3
+ "version": "2.14.8",
4
4
  "main": "dist/index.js",
5
5
  "bin": "dist/main.js",
6
6
  "files": [