Skip to content

feat(react): add context derivation#1173

Merged
ErnestM1234 merged 12 commits intomainfrom
e/react/derive-context
Apr 7, 2026
Merged

feat(react): add context derivation#1173
ErnestM1234 merged 12 commits intomainfrom
e/react/derive-context

Conversation

@ErnestM1234
Copy link
Copy Markdown
Contributor

@ErnestM1234 ErnestM1234 commented Apr 6, 2026

add the ability to derive context

Greptile Summary

This PR adds context derivation support across the React/Next.js CLI extractor, the SWC Rust compiler plugin, and the Python extractor. When a translation call uses derive() in its $context attribute (e.g. <T context={derive(getFormality())}>…</T> or t("Hello", { $context: derive(getFormality()) })), the toolchain now statically resolves all possible context variants and emits one translation entry per variant, sharing a staticId to group them together.

Confidence Score: 5/5

Safe to merge; all remaining findings are P2 style/defensive improvements that do not affect the happy path.

The feature works correctly for the normal case. Both P2 findings are edge-case defensive improvements (stale metadata key and empty-array guard) that would only manifest in unusual error conditions or with dollar-prefixed $context syntax. No P0/P1 logic errors were found.

parseTProps.ts (stale $context key) and handleLiteralTranslationCall.ts / derivation/index.ts (empty contextVariants truthy check)

Important Files Changed

Filename Overview
packages/cli/src/react/jsx/utils/jsxParsing/parseTProps.ts Detects derive() in JSX context prop and stores as _contextDeriveExpr; else-branch also sets metadata[attrName]=code, leaving a stale $context key in metadata when derivation succeeds
packages/cli/src/react/jsx/utils/stringParsing/processTranslationCall/handleLiteralTranslationCall.ts Adds contextVariants cross-product for string literals; truthy-check on empty array could silently swallow entries without error
packages/cli/src/react/jsx/utils/stringParsing/processTranslationCall/index.ts Correctly resolves contextDeriveExpr → contextVariants before routing; cleans up the temporary AST expression field before structuredClone
packages/cli/src/react/jsx/utils/stringParsing/derivation/index.ts Cross-product of content strings × context variants; same empty-array truthy-check concern when contextVariants is []
packages/cli/src/react/jsx/utils/stringParsing/derivation/containsDeriveCall.ts Added ConditionalExpression arm so ternaries containing derive() in context are correctly detected as derive expressions
packages/next/swc-plugin/src/visitor/expr_utils.rs Added Cond arm to contains_derive_call and has_derive_context flag to emit empty hash when $context contains derive()
packages/next/swc-plugin/src/ast/traversal.rs Uses jsx_attr_contains_derive_call to produce empty hash when JSX context attribute contains derive(), matching TS compiler behavior
packages/python-extractor/src/extractCalls.ts Adds extractDeriveContext to parse _context=derive() kwargs and emit cross-product entries with shared staticId on both simple and hasStaticHelpers paths
packages/compiler/src/processing/collection/processCallExpression.ts Sets hash to empty string when hasDeriveContext is true on JSX component and translation function paths, delegating hash resolution to the CLI
packages/cli/src/react/jsx/utils/jsxParsing/parseJsx.ts Resolves _contextDeriveExpr to contextVariants and generates cross-product JSX updates; correctly deletes _contextDeriveExpr before structuredClone to prevent AST serialization errors

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Source: context={derive(fn())} or $context=derive(fn())] --> B{CLI/Babel parse}
    B --> C[containsDeriveCall detects derive]
    C --> D[Store _contextDeriveExpr on metadata]
    D --> E[handleDerivation resolves fn return variants]
    E --> F{Resolved?}
    F -- Yes: variants=[formal,casual] --> G[contextVariants array]
    F -- No --> H[Push error, contextVariants=undefined]
    G --> I{Content type?}
    I -- JSX Tree --> J[parseJsx: emit N updates, one per context variant]
    I -- String Literal --> K[handleLiteralTranslationCall: emit N updates]
    I -- Derive content --> L[deriveExpression: cross-product content×context]
    J --> M[Each update: source + context + shared staticId]
    K --> M
    L --> M
    M --> N[Compiler: hash='' when hasDeriveContext, CLI resolves real hashes]
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: packages/cli/src/react/jsx/utils/jsxParsing/parseTProps.ts
Line: 93-97

Comment:
**Stale `$context` key persists in metadata after derivation**

When `attrName` is `'$context'` (the dollar-sign sugar form) and the expression contains `derive()`, both `metadata._contextDeriveExpr = expr` and `metadata['$context'] = code` are set. `parseJsx.ts` overrides `metadata.context` with the resolved value, but `metadata['$context']` (with the dollar prefix) is never cleaned up and ends up in every emitted update payload. If the translation API treats `$context` as an alias for `context`, it would see the raw code string instead of the resolved context.

The `else` branch should be skipped when the derive expression was already captured:
```suggestion
        } else if (!(mapAttributeName(attrName) === 'context' && t.isExpression(expr) && containsDeriveCall(expr))) {
          // Only store the code if we couldn't extract a derivable value
          metadata[attrName] = code;
        }
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: packages/cli/src/react/jsx/utils/stringParsing/processTranslationCall/handleLiteralTranslationCall.ts
Line: 57

Comment:
**Empty `contextVariants` array silently drops the translation entry**

`if (contextVariants)` is truthy for `[]`. If `nodeToStrings` ever returns an empty array (e.g. a `derive()` call that resolves to zero variants), the `for` loop runs zero times and nothing is pushed to `output.updates` — the string silently disappears with no error. A length guard is safer:
```suggestion
  if (contextVariants && contextVariants.length > 0) {
```
The same pattern applies in `derivation/index.ts` where `contexts = contextVariants ?? [metadata.context]` — an empty `contextVariants` causes the entire outer content loop to produce no updates.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (5): Last reviewed commit: "fix greptile feedback" | Re-trigger Greptile

@ErnestM1234 ErnestM1234 requested a review from a team as a code owner April 6, 2026 23:50
@ErnestM1234
Copy link
Copy Markdown
Contributor Author

@greptileai plz re-review

@ErnestM1234
Copy link
Copy Markdown
Contributor Author

@greptileai plz review

@ErnestM1234
Copy link
Copy Markdown
Contributor Author

@greptileai plz review

@ErnestM1234
Copy link
Copy Markdown
Contributor Author

@greptileai plz-review

@ErnestM1234
Copy link
Copy Markdown
Contributor Author

@greptileai plz-review

@archie-mckenzie
Copy link
Copy Markdown
Contributor

@greptile-ai please re-review

@ErnestM1234 ErnestM1234 merged commit 6b0b56b into main Apr 7, 2026
28 checks passed
@ErnestM1234 ErnestM1234 deleted the e/react/derive-context branch April 7, 2026 02:23
@github-actions github-actions bot mentioned this pull request Apr 7, 2026
ErnestM1234 pushed a commit that referenced this pull request Apr 7, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## gt-i18n@0.8.0

### Minor Changes

- [#1173](#1173)
[`6b0b56b`](6b0b56b)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - add context
derivation

## gt-next@6.16.0

### Minor Changes

- [#1173](#1173)
[`6b0b56b`](6b0b56b)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - add context
derivation

### Patch Changes

- Updated dependencies
\[[`6b0b56b`](6b0b56b)]:
    -   gt-i18n@0.8.0
    -   gt-react@10.18.0
    -   @generaltranslation/compiler@1.3.1

## gt-node@0.5.0

### Minor Changes

- [#1173](#1173)
[`6b0b56b`](6b0b56b)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - add context
derivation

### Patch Changes

- Updated dependencies
\[[`6b0b56b`](6b0b56b)]:
    -   gt-i18n@0.8.0

## gt-react@10.18.0

### Minor Changes

- [#1173](#1173)
[`6b0b56b`](6b0b56b)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - add context
derivation

### Patch Changes

- Updated dependencies
\[[`6b0b56b`](6b0b56b)]:
    -   gt-i18n@0.8.0
    -   @generaltranslation/react-core@1.8.0

## @generaltranslation/react-core@1.8.0

### Minor Changes

- [#1173](#1173)
[`6b0b56b`](6b0b56b)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - add context
derivation

### Patch Changes

- Updated dependencies
\[[`6b0b56b`](6b0b56b)]:
    -   gt-i18n@0.8.0

## gt-tanstack-start@0.4.0

### Minor Changes

- [#1173](#1173)
[`6b0b56b`](6b0b56b)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - add context
derivation

### Patch Changes

- Updated dependencies
\[[`6b0b56b`](6b0b56b)]:
    -   gt-i18n@0.8.0
    -   gt-react@10.18.0
    -   @generaltranslation/react-core@1.8.0

## gt@2.14.6

### Patch Changes

- [#1173](#1173)
[`6b0b56b`](6b0b56b)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - add context
derivation

- Updated dependencies
\[[`6b0b56b`](6b0b56b)]:
    -   @generaltranslation/python-extractor@0.2.7

## @generaltranslation/compiler@1.3.1

### Patch Changes

- [#1173](#1173)
[`6b0b56b`](6b0b56b)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - add context
derivation

## gtx-cli@2.14.6

### Patch Changes

- Updated dependencies
\[[`6b0b56b`](6b0b56b)]:
    -   gt@2.14.6

## locadex@1.0.141

### Patch Changes

- Updated dependencies
\[[`6b0b56b`](6b0b56b)]:
    -   gt@2.14.6

## @generaltranslation/gt-next-lint@14.0.0

### Patch Changes

- Updated dependencies
\[[`6b0b56b`](6b0b56b)]:
    -   gt-next@6.16.0

## @generaltranslation/python-extractor@0.2.7

### Patch Changes

- [#1173](#1173)
[`6b0b56b`](6b0b56b)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - add context
derivation

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
moss-bryophyta added a commit to generaltranslation/content that referenced this pull request Apr 7, 2026
…ons + devlog

- Add context derivation section to derive string and component templates
- Update T context prop description to mention derive()
- Update InlineTranslationOptions $context to mention derive()
- Add devlog for gt-next@6.16.0 covering context derivation feature

Ref: generaltranslation/gt#1173
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants