gt 2.10.6 → 2.10.7

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,11 @@
1
1
  # gtx-cli
2
2
 
3
+ ## 2.10.7
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1118](https://github.com/generaltranslation/gt/pull/1118) [`de6a2d1`](https://github.com/generaltranslation/gt/commit/de6a2d1caa150383c70844b3ee6b9b2e66f77769) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - feat: add t macro
8
+
3
9
  ## 2.10.6
4
10
 
5
11
  ### Patch Changes
@@ -1 +1 @@
1
- export declare const PACKAGE_VERSION = "2.10.6";
1
+ export declare const PACKAGE_VERSION = "2.10.7";
@@ -1,2 +1,2 @@
1
1
  // This file is auto-generated. Do not edit manually.
2
- export const PACKAGE_VERSION = '2.10.6';
2
+ export const PACKAGE_VERSION = '2.10.7';
@@ -6,6 +6,7 @@ export declare const DECLARE_STATIC_FUNCTION = "declareStatic";
6
6
  export declare const DERIVE_FUNCTION = "derive";
7
7
  export declare const MSG_REGISTRATION_FUNCTION = "msg";
8
8
  export declare const T_REGISTRATION_FUNCTION = "t";
9
+ export declare const T_GLOBAL_REGISTRATION_FUNCTION = "t";
9
10
  export declare const INLINE_TRANSLATION_HOOK = "useGT";
10
11
  export declare const INLINE_TRANSLATION_HOOK_ASYNC = "getGT";
11
12
  export declare const INLINE_MESSAGE_HOOK = "useMessages";
@@ -23,3 +24,4 @@ export declare const VARIABLE_COMPONENTS: string[];
23
24
  export declare const GT_ATTRIBUTES_WITH_SUGAR: readonly ["$id", "$context", "$maxChars"];
24
25
  export declare const GT_ATTRIBUTES: readonly ["id", "context", "maxChars", "$id", "$context", "$maxChars"];
25
26
  export declare const DATA_ATTR_PREFIX: "data-";
27
+ export declare const T_GLOBAL_REGISTRATION_FUNCTION_MARKER = "_gt_internal_t_global_registration_marker";
@@ -6,6 +6,7 @@ export const DECLARE_STATIC_FUNCTION = 'declareStatic';
6
6
  export const DERIVE_FUNCTION = 'derive';
7
7
  export const MSG_REGISTRATION_FUNCTION = 'msg';
8
8
  export const T_REGISTRATION_FUNCTION = 't';
9
+ export const T_GLOBAL_REGISTRATION_FUNCTION = 't';
9
10
  export const INLINE_TRANSLATION_HOOK = 'useGT';
10
11
  export const INLINE_TRANSLATION_HOOK_ASYNC = 'getGT';
11
12
  export const INLINE_MESSAGE_HOOK = 'useMessages';
@@ -65,3 +66,5 @@ export const GT_ATTRIBUTES = [
65
66
  ];
66
67
  // Data attribute prefix injected by build tools
67
68
  export const DATA_ATTR_PREFIX = 'data-';
69
+ // demarcation for global t macro
70
+ export const T_GLOBAL_REGISTRATION_FUNCTION_MARKER = '_gt_internal_t_global_registration_marker';
@@ -1,6 +1,7 @@
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_REGISTRATION_FUNCTION, T_REGISTRATION_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, T_REGISTRATION_FUNCTION, TRANSLATION_COMPONENT, T_GLOBAL_REGISTRATION_FUNCTION, T_GLOBAL_REGISTRATION_FUNCTION_MARKER, } from '../../jsx/utils/constants.js';
3
3
  import { extractImportName } from './parseAst.js';
4
+ import * as t from '@babel/types';
4
5
  // Handle CommonJS/ESM interop
5
6
  const traverse = traverseModule.default || traverseModule;
6
7
  /**
@@ -15,6 +16,19 @@ export function getPathsAndAliases(ast, pkgs) {
15
16
  const inlineTranslationPaths = [];
16
17
  const translationComponentPaths = [];
17
18
  traverse(ast, {
19
+ // extract global t tagged template
20
+ TaggedTemplateExpression(path) {
21
+ if (t.isIdentifier(path.node.tag, {
22
+ name: T_GLOBAL_REGISTRATION_FUNCTION,
23
+ }) &&
24
+ !path.scope.hasBinding(T_GLOBAL_REGISTRATION_FUNCTION)) {
25
+ inlineTranslationPaths.push({
26
+ localName: T_GLOBAL_REGISTRATION_FUNCTION,
27
+ path: path.get('tag'),
28
+ originalName: T_GLOBAL_REGISTRATION_FUNCTION_MARKER,
29
+ });
30
+ }
31
+ },
18
32
  ImportDeclaration(path) {
19
33
  if (pkgs.some((pkg) => path.node.source.value.startsWith(pkg))) {
20
34
  const importName = extractImportName(path.node, pkgs, GT_TRANSLATION_FUNCS);
@@ -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, } 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
@@ -9,6 +9,7 @@ import { parse } from '@babel/parser';
9
9
  import { resolveImportPath } from './resolveImportPath.js';
10
10
  import { buildImportMap } from './buildImportMap.js';
11
11
  import { processTranslationCall } from './stringParsing/processTranslationCall/index.js';
12
+ import { processTaggedTemplateCall } from './stringParsing/processTaggedTemplateCall/index.js';
12
13
  /**
13
14
  * Cache for resolved import paths to avoid redundant I/O operations.
14
15
  * Key: `${currentFile}::${importPath}`
@@ -88,6 +89,12 @@ function handleFunctionCall(tPath, config, state, output) {
88
89
  // Direct translation call: t('hello')
89
90
  processTranslationCall(tPath, config, output);
90
91
  }
92
+ else if (!config.ignoreTaggedTemplates &&
93
+ tPath.parent.type === 'TaggedTemplateExpression' &&
94
+ tPath.parent.tag === tPath.node) {
95
+ // Tagged template: t`hello ${name}`
96
+ processTaggedTemplateCall(tPath, config, output);
97
+ }
91
98
  else if (tPath.parent.type === 'CallExpression' &&
92
99
  t.isExpression(tPath.node) &&
93
100
  tPath.parent.arguments.includes(tPath.node)) {
@@ -270,6 +277,13 @@ function processFunctionInFile(filePath, functionName, argIndex, config, state,
270
277
  * - This will parse constants.ts to find translation calls within getInfo function
271
278
  */
272
279
  export function parseStrings(importName, originalName, path, config, output) {
280
+ // Handle global t macro directly — path is already the tag identifier
281
+ if (originalName === T_GLOBAL_REGISTRATION_FUNCTION_MARKER) {
282
+ if (!config.ignoreGlobalTaggedTemplates) {
283
+ processTaggedTemplateCall(path, config, output);
284
+ }
285
+ return;
286
+ }
273
287
  // First, collect all imports in this file to track cross-file function calls
274
288
  const importMap = buildImportMap(path.scope.getProgramParent().path);
275
289
  const referencePaths = path.scope.bindings[importName]?.referencePaths || [];
@@ -284,12 +298,20 @@ export function parseStrings(importName, originalName, path, config, output) {
284
298
  ignoreInvalidIcu: false,
285
299
  ignoreInlineListContent: false,
286
300
  includeSourceCodeContext: config.includeSourceCodeContext,
301
+ ignoreTaggedTemplates: false,
302
+ ignoreGlobalTaggedTemplates: false,
287
303
  };
288
- // Check if this is a direct call to msg('string')
304
+ // Check if this is a direct call to msg('string') or t('string')
289
305
  if (refPath.parent.type === 'CallExpression' &&
290
306
  refPath.parent.callee === refPath.node) {
291
307
  processTranslationCall(refPath, stringRegistrationConfig, output);
292
308
  }
309
+ else if (!stringRegistrationConfig.ignoreTaggedTemplates &&
310
+ refPath.parent.type === 'TaggedTemplateExpression' &&
311
+ refPath.parent.tag === refPath.node) {
312
+ // Tagged template: t`hello ${name}`
313
+ processTaggedTemplateCall(refPath, stringRegistrationConfig, output);
314
+ }
293
315
  continue;
294
316
  }
295
317
  // Handle useGT(), getGT(), useMessages(), and getMessages() calls that need variable assignment
@@ -324,6 +346,8 @@ export function parseStrings(importName, originalName, path, config, output) {
324
346
  // TODO: when we add support for array content in gt function, this should just always be false
325
347
  ignoreInlineListContent: isInlineGT,
326
348
  includeSourceCodeContext: config.includeSourceCodeContext,
349
+ ignoreTaggedTemplates: false,
350
+ ignoreGlobalTaggedTemplates: false,
327
351
  };
328
352
  const effectiveParent = parentPath?.node.type === 'AwaitExpression'
329
353
  ? parentPath.parentPath
@@ -0,0 +1,23 @@
1
+ import * as t from '@babel/types';
2
+ import { ParsingConfig, ParsingOutput } from '../types.js';
3
+ import { InlineMetadata } from '../processTranslationCall/extractStringEntryMetadata.js';
4
+ /**
5
+ * Extracts a translatable message from a TaggedTemplateExpression.
6
+ *
7
+ * Follows the same extraction pattern as `extractInterpolatableValues` in
8
+ * `packages/react/src/i18n-context/functions/translation/t.ts`:
9
+ * - Iterates through quasis and expressions interleaved
10
+ * - Creates numeric placeholders ({0}, {1}, etc.) for each expression
11
+ * - Joins all parts into the final source string
12
+ *
13
+ * @param quasi - The TemplateLiteral from the TaggedTemplateExpression
14
+ * @param metadata - Extracted metadata (empty for tagged templates)
15
+ * @param config - Parsing configuration
16
+ * @param output - Parsing output collectors
17
+ */
18
+ export declare function handleTaggedTemplateTranslationCall({ quasi, metadata, config, output, }: {
19
+ quasi: t.TemplateLiteral;
20
+ metadata: InlineMetadata;
21
+ config: ParsingConfig;
22
+ output: ParsingOutput;
23
+ }): void;
@@ -0,0 +1,42 @@
1
+ import { isValidIcu } from '../../../evaluateJsx.js';
2
+ import { warnInvalidIcuSync } from '../../../../../console/index.js';
3
+ /**
4
+ * Extracts a translatable message from a TaggedTemplateExpression.
5
+ *
6
+ * Follows the same extraction pattern as `extractInterpolatableValues` in
7
+ * `packages/react/src/i18n-context/functions/translation/t.ts`:
8
+ * - Iterates through quasis and expressions interleaved
9
+ * - Creates numeric placeholders ({0}, {1}, etc.) for each expression
10
+ * - Joins all parts into the final source string
11
+ *
12
+ * @param quasi - The TemplateLiteral from the TaggedTemplateExpression
13
+ * @param metadata - Extracted metadata (empty for tagged templates)
14
+ * @param config - Parsing configuration
15
+ * @param output - Parsing output collectors
16
+ */
17
+ export function handleTaggedTemplateTranslationCall({ quasi, metadata, config, output, }) {
18
+ const parts = [];
19
+ let varIndex = 0;
20
+ for (let i = 0; i < quasi.quasis.length; i++) {
21
+ parts.push(quasi.quasis[i].value.cooked ?? quasi.quasis[i].value.raw);
22
+ if (i < quasi.expressions.length) {
23
+ const key = varIndex.toString();
24
+ parts.push(`{${key}}`);
25
+ varIndex++;
26
+ }
27
+ }
28
+ const source = parts.join('');
29
+ // Validate ICU format
30
+ if (!config.ignoreInvalidIcu) {
31
+ const { isValid, error } = isValidIcu(source);
32
+ if (!isValid) {
33
+ output.warnings.add(warnInvalidIcuSync(config.file, source, error ?? 'Unknown error', `${quasi.loc?.start?.line}:${quasi.loc?.start?.column}`));
34
+ return;
35
+ }
36
+ }
37
+ output.updates.push({
38
+ dataFormat: 'ICU',
39
+ source,
40
+ metadata,
41
+ });
42
+ }
@@ -0,0 +1,13 @@
1
+ import { NodePath } from '@babel/traverse';
2
+ import { ParsingConfig, ParsingOutput } from '../types.js';
3
+ /**
4
+ * Processes a tagged template expression (e.g., t`hello ${name}`).
5
+ * Extracts the translatable string with numeric placeholders for expressions.
6
+ *
7
+ * Tagged templates don't support an options argument, so metadata is empty.
8
+ *
9
+ * @param tPath - The path to the tag identifier
10
+ * @param config - Parsing configuration
11
+ * @param output - Parsing output collectors
12
+ */
13
+ export declare function processTaggedTemplateCall(tPath: NodePath, config: ParsingConfig, output: ParsingOutput): void;
@@ -0,0 +1,24 @@
1
+ import * as t from '@babel/types';
2
+ import { handleTaggedTemplateTranslationCall } from './handleTaggedTemplateTranslationCall.js';
3
+ /**
4
+ * Processes a tagged template expression (e.g., t`hello ${name}`).
5
+ * Extracts the translatable string with numeric placeholders for expressions.
6
+ *
7
+ * Tagged templates don't support an options argument, so metadata is empty.
8
+ *
9
+ * @param tPath - The path to the tag identifier
10
+ * @param config - Parsing configuration
11
+ * @param output - Parsing output collectors
12
+ */
13
+ export function processTaggedTemplateCall(tPath, config, output) {
14
+ if (!t.isTaggedTemplateExpression(tPath.parent) ||
15
+ tPath.parent.tag !== tPath.node) {
16
+ return;
17
+ }
18
+ handleTaggedTemplateTranslationCall({
19
+ quasi: tPath.parent.quasi,
20
+ metadata: {},
21
+ config,
22
+ output,
23
+ });
24
+ }
@@ -27,6 +27,14 @@ export type ParsingConfig = {
27
27
  * If true, include surrounding source code lines as context for translations
28
28
  */
29
29
  includeSourceCodeContext?: boolean;
30
+ /**
31
+ * If true, ignore tagged template expressions (e.g., t`hello ${name}`)
32
+ */
33
+ ignoreTaggedTemplates: boolean;
34
+ /**
35
+ * If true, ignore global tagged template expressions (t`hello` without import)
36
+ */
37
+ ignoreGlobalTaggedTemplates: boolean;
30
38
  };
31
39
  /**
32
40
  * Mutable state for tracking parsing progress.
@@ -40,6 +40,8 @@ export async function createInlineUpdates(pkg, validate, filePatterns, parsingOp
40
40
  ignoreInvalidIcu: false,
41
41
  ignoreInlineListContent: false,
42
42
  includeSourceCodeContext,
43
+ ignoreTaggedTemplates: false,
44
+ ignoreGlobalTaggedTemplates: false,
43
45
  }, { updates, errors, warnings });
44
46
  }
45
47
  // Parse <T> components
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gt",
3
- "version": "2.10.6",
3
+ "version": "2.10.7",
4
4
  "main": "dist/index.js",
5
5
  "bin": "dist/main.js",
6
6
  "files": [