Skip to content

Odysseus#1439

Merged
ErnestM1234 merged 263 commits into
mainfrom
odysseus
Jul 4, 2026
Merged

Odysseus#1439
ErnestM1234 merged 263 commits into
mainfrom
odysseus

Conversation

@ErnestM1234

@ErnestM1234 ErnestM1234 commented May 18, 2026

Copy link
Copy Markdown
Contributor

Project Odysseus

  • breaking library changes
  • large refactors
  • major speed improvements

View in Codesmith
Need help on this PR? Tag @codesmith with what you need.

  • Let Codesmith autofix CI failures and bot reviews

@github-actions

github-actions Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size
generaltranslation 21.99 KB (0%)
@generaltranslation/format 14.25 KB (0%)
gt-i18n 33.12 KB (+1.47% 🔺)
@generaltranslation/react-core 43.57 KB (+0.25% 🔺)
gt-react 45.92 KB (+0.09% 🔺)
gt-tanstack-start -16 B (-100.03% 🔽)
gt-next/client 48.32 KB (+0.08% 🔺)

moving towards deprecating our string translation hooks

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1452"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-light.svg"><img
alt="View in Codesmith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"></picture></a>
<sup>Need help on this PR? Tag <code>@codesmith</code> with what you
need.</sup>

- [ ] Let Codesmith autofix CI failures and bot reviews
<!-- /codesmith:footer -->

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR re-exports the `t()` translation function from the server and
client entry points of `gt-react` and `gt-tanstack-start`, marking a
step toward deprecating the string translation hooks. Internally, `t()`
is rewritten to use `i18nManager.lookupTranslation` and a new
`resolveStringContent` helper, `getRuntimeEnvironment` is extracted into
a shared utility module, and `getLocale`/`getShouldTranslate` are
extracted as non-hook singletons that back their hook counterparts.

- **`t()` rewrite**: replaces `resolveTranslationSyncWithFallback` with
a direct `i18nManager.lookupTranslation` path; adds `enforceSSRRules` to
throw in dev and warn in prod when called at module level in an SSR app.
- **Non-reactive singletons**: `useLocale()` and `useShouldTranslate()`
now delegate to `getLocale()`/`getShouldTranslate()` which read from the
condition store singleton instead of React context — intentional as the
team moves toward full-page reloads for locale changes.
- **Shared utility**: `getRuntimeEnvironment()` is extracted from
`I18nManager.ts` into `packages/i18n/src/utils/getRuntimeEnvironment.ts`
and re-exported via `gt-i18n/internal`.

<details open><summary><h3>Confidence Score: 4/5</h3></summary>

Safe to merge with awareness that module-level SSR calls in production
will emit a console.warn and then throw from the uninitialized condition
store — an acknowledged intentional breaking change per prior
discussion.

The functional changes are intentional and scoped: the new
resolveStringContent path, the SSR enforcement logic, and the
non-reactive singleton helpers all behave as the team designed them. The
only concern is the stale JSDoc that could mislead library consumers
about where t() is allowed. No unintended regressions were found in the
changed paths.

packages/react-core/src/functions/translation/t.ts — the JSDoc
description of valid environments should be updated to match the new
server exports.
</details>

<details><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| packages/react-core/src/functions/translation/t.ts | Core rewrite of
t(): replaces resolveTranslationSyncWithFallback with new
resolveStringContent backed by the i18nManager, adds enforceSSRRules for
module-level SSR detection, and exports resolveStringContent for reuse.
JSDoc still says "BROWSER ONLY" despite new server exports. |
| packages/react-core/src/hooks/context-hooks.ts | Extracts getLocale()
as a non-hook function reading directly from the condition store
singleton; useLocale() now delegates to it, losing React context
reactivity intentionally. |
| packages/react-core/src/hooks/utils.ts | Splits useShouldTranslate
into a hook wrapper and getShouldTranslate() reading from the condition
store singleton directly; useShouldTranslate becomes non-reactive as a
result. |
| packages/i18n/src/utils/getRuntimeEnvironment.ts | Extracted
getRuntimeEnvironment() into its own utility module so it can be shared
across packages; logic is unchanged from the removed inline version in
I18nManager.ts. |
| packages/react-core/src/condition-store/singleton-operations.ts |
Exports isWritableConditionStoreInitialized so enforceSSRRules in t.ts
can check initialization state before calling the store. |
| packages/react/src/context.server.ts | Re-exports t from react-core
context, making it available on the server entry point alongside the
existing exports. |
| packages/tanstack-start/src/index.server.ts | Re-exports t through the
tanstack-start server entry, mirroring the react package change. |

</details>

</details>

<details><summary><h3>Flowchart</h3></summary>

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["t(message | template)"] --> B["enforceSSRRules()"]
    B --> C{ssrEnabled AND moduleLevel?}
    C -- No --> D{typeof messageOrStrings}
    C -- "Yes + dev" --> E["throw Error"]
    C -- "Yes + prod" --> F["console.warn → continues"]
    F --> D
    D -- string --> G["getLocale()"]
    G --> H["getWritableConditionStore().getLocale()"]
    D -- TemplateStringsArray --> I["handleTaggedTemplateLiteralTranslation()"]
    I --> H
    H --> J["resolveStringContent()"]
    J --> K["getShouldTranslate()"]
    K --> L{shouldTranslate?}
    L -- No --> M["interpolateMessage (source only)"]
    L -- Yes --> N["i18nManager.lookupTranslation()"]
    N --> O["interpolateMessage (translated)"]
    M --> P["return string"]
    O --> P
```
</details>

<a
href="https://app.greptile.com/ide/claude-code?prompt=Fix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Apackages%2Freact-core%2Fsrc%2Ffunctions%2Ftranslation%2Ft.ts%3A17-29%0A**Stale%20%22BROWSER%20ONLY%22%20JSDoc**%0A%0AThe%20block%20comment%20still%20says%20%60This%20is%20a%20BROWSER%20ONLY%20function.%60%20and%20%60t%28%29%20is%20the%20only%20function%20exported%20from%20the%20'gt-react'%20entry%20point%60%2C%20but%20this%20PR%20adds%20%60t%60%20to%20%60context.server.ts%60%2C%20%60index.server.ts%60%2C%20and%20%60index.types.ts%60.%20A%20developer%20reading%20this%20JSDoc%20would%20incorrectly%20conclude%20it's%20unsafe%20to%20call%20from%20an%20SSR%20route%20handler%2C%20undermining%20the%20purpose%20of%20this%20PR.%0A%0A&repo=generaltranslation%2Fgt&pr=1452&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaudeDark.svg?v=3"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=3"><img
alt="Fix All in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=3"
height="20"></picture></a> <a
href="https://chatgpt.com/codex/deeplink?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22generaltranslation%2Fgt%22%20on%20the%20existing%20branch%20%22e%2Fodysseus%2Fremove-gtproviders%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22e%2Fodysseus%2Fremove-gtproviders%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Apackages%2Freact-core%2Fsrc%2Ffunctions%2Ftranslation%2Ft.ts%3A17-29%0A**Stale%20%22BROWSER%20ONLY%22%20JSDoc**%0A%0AThe%20block%20comment%20still%20says%20%60This%20is%20a%20BROWSER%20ONLY%20function.%60%20and%20%60t%28%29%20is%20the%20only%20function%20exported%20from%20the%20'gt-react'%20entry%20point%60%2C%20but%20this%20PR%20adds%20%60t%60%20to%20%60context.server.ts%60%2C%20%60index.server.ts%60%2C%20and%20%60index.types.ts%60.%20A%20developer%20reading%20this%20JSDoc%20would%20incorrectly%20conclude%20it's%20unsafe%20to%20call%20from%20an%20SSR%20route%20handler%2C%20undermining%20the%20purpose%20of%20this%20PR.%0A%0A"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=3"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=3"><img
alt="Fix All in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=3"
height="20"></picture></a>

<details><summary>Prompt To Fix All With AI</summary>

`````markdown
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
packages/react-core/src/functions/translation/t.ts:17-29
**Stale "BROWSER ONLY" JSDoc**

The block comment still says `This is a BROWSER ONLY function.` and `t() is the only function exported from the 'gt-react' entry point`, but this PR adds `t` to `context.server.ts`, `index.server.ts`, and `index.types.ts`. A developer reading this JSDoc would incorrectly conclude it's unsafe to call from an SSR route handler, undermining the purpose of this PR.

`````

</details>

<sub>Reviews (2): Last reviewed commit: ["greptile
issues"](f9da764)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=32742953)</sub>

<!-- /greptile_comment -->
## Summary
- Run `pnpm format:fix` on latest `origin/odysseus`

## Verification
- `pnpm format:fix`

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1454"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-light.svg"><img
alt="View in Codesmith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"></picture></a>
<sup>Need help on this PR? Tag <code>@codesmith</code> with what you
need.</sup>

- [ ] Let Codesmith autofix CI failures and bot reviews
<!-- /codesmith:footer -->

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR applies `pnpm format:fix` across 84 files on the `odysseus`
branch, standardizing quote style (double → single), removing trailing
commas in function parameter and argument lists, and condensing
single-element arrays to one-liners. No logic is changed.

- **Quote style normalization**: All import paths and string literals
are converted from double quotes to single quotes across the entire
monorepo.
- **Trailing comma removal**: Function signatures, call sites, and type
parameter lists have trailing commas removed to match the formatter's
configured style.
- **Leftover debug log**:
`packages/i18n/src/condition-store/WritableConditionStore.ts` contains a
`console.log` debug statement that was pre-existing and is now formatted
but not removed — it will fire on every locale update in production.

<details open><summary><h3>Confidence Score: 4/5</h3></summary>

Safe to merge with one pre-existing debug log that should be cleaned up
before reaching production.

All 84 files contain only cosmetic formatter output with zero logic
changes. The one concern is a console.log statement in
WritableConditionStore.ts that was already present but reformatted and
not removed — it will fire on every locale change in production
environments.

packages/i18n/src/condition-store/WritableConditionStore.ts — contains
an unconditional console.log debug statement on the hot setLocale path.
</details>

<details><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| packages/i18n/src/condition-store/WritableConditionStore.ts |
Formatting only, but carries a leftover console.log debug statement
inside setLocale that will pollute production logs. |
| packages/i18n/src/i18n-manager/I18nManager.ts | Formatting only —
double quotes to single quotes, trailing comma removal; no logic
changes. |
| packages/react-core/src/deprecated/errors-dir/createErrors.ts |
Formatting only; large file reformatted with single quotes and condensed
arrays. |
| packages/react-core/src/i18n-store/I18nStore.ts | Formatting only —
quote style and trailing comma changes with no logic modifications. |
| packages/react-core/src/utils/rendering/renderTranslatedChildren.tsx |
Formatting only — quote style and trailing comma changes. |
| .changeset/pre.json | Changeset array condensed to a single line; no
content changes. |

</details>

</details>

<details><summary><h3>Flowchart</h3></summary>

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[pnpm format:fix] --> B[Prettier reformats 84 files]
    B --> C[Double quotes to Single quotes]
    B --> D[Trailing commas removed]
    B --> E[Single-element arrays condensed]
    C & D & E --> F[Formatted output committed]
    F --> G{Any side effects?}
    G -->|Yes| H[console.log in WritableConditionStore.setLocale still present]
    G -->|No| I[All other files: purely cosmetic]
```
</details>

<a
href="https://app.greptile.com/ide/claude-code?prompt=Fix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Apackages%2Fi18n%2Fsrc%2Fcondition-store%2FWritableConditionStore.ts%3A15%0A**Debug%20%60console.log%60%20in%20production%20code**%0A%0A%60console.log%28'WritableConditionStore.setLocale'%2C%20locale%29%60%20is%20a%20debug%20statement%20left%20in%20the%20%60setLocale%60%20method%2C%20which%20is%20called%20on%20every%20locale%20update.%20This%20will%20spam%20the%20browser%2FNode%20console%20in%20production%20for%20every%20locale%20change.%0A%0A&repo=generaltranslation%2Fgt&pr=1454&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaudeDark.svg?v=3"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=3"><img
alt="Fix All in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=3"
height="20"></picture></a> <a
href="https://chatgpt.com/codex/deeplink?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22generaltranslation%2Fgt%22%20on%20the%20existing%20branch%20%22bg%2Fformat-fix-odysseus%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22bg%2Fformat-fix-odysseus%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Apackages%2Fi18n%2Fsrc%2Fcondition-store%2FWritableConditionStore.ts%3A15%0A**Debug%20%60console.log%60%20in%20production%20code**%0A%0A%60console.log%28'WritableConditionStore.setLocale'%2C%20locale%29%60%20is%20a%20debug%20statement%20left%20in%20the%20%60setLocale%60%20method%2C%20which%20is%20called%20on%20every%20locale%20update.%20This%20will%20spam%20the%20browser%2FNode%20console%20in%20production%20for%20every%20locale%20change.%0A%0A"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=3"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=3"><img
alt="Fix All in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=3"
height="20"></picture></a>

<details><summary>Prompt To Fix All With AI</summary>

`````markdown
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
packages/i18n/src/condition-store/WritableConditionStore.ts:15
**Debug `console.log` in production code**

`console.log('WritableConditionStore.setLocale', locale)` is a debug statement left in the `setLocale` method, which is called on every locale update. This will spam the browser/Node console in production for every locale change.

`````

</details>

<sub>Reviews (1): Last reviewed commit: ["style: run format
fix"](c878fb3)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=32855602)</sub>

> Greptile also left **1 inline comment** on this PR.

**Context used:**

- Rule used - Remove console.log statements and debug logging fr...
([source](https://app.greptile.com/review/custom-context?memory=ea076fa4-7856-4d31-9266-35f86e49f4b6))

**Learned From**

[generaltranslation/gt-cloud#1266](generaltranslation/gt-cloud#1266)

[generaltranslation/gt-cloud#1240](generaltranslation/gt-cloud#1240)

<!-- /greptile_comment -->

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'Middleware Benchmarks'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.50.

Benchmark suite Current: 97cd40a Previous: c8ed2e7 Ratio
gt-next > e2e > middleware: redirect-chain-fr-about > ttfb 38.59999999997672 ms 16.900000000023283 ms 2.28
gt-next > e2e > middleware: redirect-chain-fr-about > domContentLoaded 47.29999999998836 ms 26.79999999998836 ms 1.76

This comment was automatically generated by workflow using github-action-benchmark.

CC: @generaltranslation/core

fernando-aviles and others added 5 commits May 19, 2026 13:56
<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1455"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-light.svg"><img
alt="View in Codesmith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"></picture></a>
<sup>Need help on this PR? Tag <code>@codesmith</code> with what you
need.</sup>

- [ ] Let Codesmith autofix CI failures and bot reviews
<!-- /codesmith:footer -->

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR introduces two improvements to Mintlify CLI postprocessing: it
adds localization of the `directory` field inside `openapi` objects in
`docs.json`, and introduces a new `localizeMintlifyFrontmatterUrls`
utility that rewrites root-relative `url` fields in translated MDX/MD
frontmatter. These are bundled under a new `postprocessMintlify`
orchestration function that replaces the direct call to `processOpenApi`
from the translate command.

- **`localizeDocsJsonDirectory`** (`processOpenApi.ts`): a new helper
that prefixes the `directory` value with the target locale (e.g., `api`
→ `es/api`), skipping the default locale and handling idempotency when
the prefix already matches the locale.
- **`localizeMintlifyFrontmatterUrls`** (new utility): parses YAML
frontmatter in `.md`/`.mdx` files and rewrites the `url` field with a
locale prefix, preserving the existing newline convention; idempotency
is ensured by checking whether the first path segment already equals the
target locale.
- **`postprocessMintlify`** (new postprocess module): replaces the old
direct `processOpenApi` import in `translate.ts`, calling both the
OpenAPI and frontmatter URL processors in sequence, with an early-return
guard for non-Mintlify projects lacking explicit OpenAPI config.

<details open><summary><h3>Confidence Score: 4/5</h3></summary>

Safe to merge; the changes add well-tested functionality with no
regressions to the existing translate pipeline.

The `directory` localization logic and `localizeMintlifyFrontmatterUrls`
are both new code paths that haven't had production exposure.
Idempotency is verified in tests, but certain edge cases in
`normalizeMintlifyFrontmatterUrl` (empty path bodies yielding
trailing-slash results, locale-only path segments being silently
stripped) are not covered. The refactor from `processOpenApi` to
`postprocessMintlify` in `translate.ts` is straightforward and the test
mock was updated to match.

The two new utility files — `localizeMintlifyFrontmatterUrls.ts` and the
directory-rewriting additions in `processOpenApi.ts` — are the only
areas with non-trivial new logic worth a second look.
</details>

<details><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| packages/cli/src/utils/processOpenApi.ts | Adds
`localizeDocsJsonDirectory` to localize the `directory` field in
Mintlify docs.json openapi objects; idempotency is correctly handled and
the default-locale bypass is in place. |
| packages/cli/src/utils/localizeMintlifyFrontmatterUrls.ts | New
utility that rewrites the frontmatter `url` field in translated MDX/MD
files with a locale prefix; strips the leading slash from root-relative
URLs by design (tests confirm this). |
| packages/cli/src/formats/files/postprocess/mintlify.ts | New
orchestration wrapper; logic is clean and properly guards against
non-Mintlify projects. |
| packages/cli/src/cli/commands/translate.ts | Swaps `processOpenApi`
for `postprocessMintlify`; straightforward refactor with no behavioral
regression for the translate pipeline. |
| packages/cli/src/utils/__tests__/processOpenApi.test.ts | Test updated
to assert `directory` rewriting and verifies idempotency with a second
`processOpenApi` call. |
|
packages/cli/src/utils/__tests__/localizeMintlifyFrontmatterUrls.test.ts
| New tests cover locale prefixing, idempotency, and skipping of
external/fragment URLs. |
| packages/cli/src/formats/files/postprocess/__tests__/mintlify.test.ts
| New tests for `postprocessMintlify` correctly cover all three dispatch
paths (explicit OpenAPI config, Mintlify framework, non-Mintlify). |
| packages/cli/src/cli/commands/__tests__/translate.test.ts | Test mock
correctly updated from `processOpenApi` to `postprocessMintlify` to
match the new import in translate.ts. |

</details>

</details>

<details><summary><h3>Flowchart</h3></summary>

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[postProcessTranslations] --> B[postprocessMintlify]
    B --> C{framework === mintlify\nOR has mintlify.openapi config?}
    C -- No --> D[return early]
    C -- Yes --> E[processOpenApi]
    E --> F{openapiConfig.files\nexists?}
    F -- No --> G[return early]
    F -- Yes --> H[Rewrite MDX/MD frontmatter\nopenapi fields]
    H --> I[Rewrite docs.json\nopenapi.source]
    I --> J[Rewrite docs.json\nopenapi.directory\nnew in this PR]
    J --> K[Strip locale prefix\nfrom openapi pages]
    K --> L{framework === mintlify?}
    B --> L
    L -- No --> M[done]
    L -- Yes --> N[localizeMintlifyFrontmatterUrls]
    N --> O[For each locale file mapping]
    O --> P[Parse YAML frontmatter]
    P --> Q{url field\npresent?}
    Q -- No --> R[skip file]
    Q -- Yes --> S[normalizeMintlifyFrontmatterUrl\nprefix with locale]
    S --> T[Write updated file]
```
</details>

<sub>Reviews (1): Last reviewed commit: ["fix:
changeset"](a617c6d)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=32885465)</sub>

<!-- /greptile_comment -->
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@2.14.39

### Patch Changes

- [#1455](#1455)
[`cd8fa50`](cd8fa50)
Thanks [@fernando-aviles](https://github.com/fernando-aviles)! - Handle
Mintlify `docs.json` `directory` field

- [#1448](#1448)
[`f19bade`](f19bade)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Fix CLI binary
release builds by resolving Ink's devtools peer dependency and failing
binary build scripts on compile errors.

## gtx-cli@2.14.39

### Patch Changes

- [#1448](#1448)
[`f19bade`](f19bade)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Fix CLI binary
release builds by resolving Ink's devtools peer dependency and failing
binary build scripts on compile errors.

- Updated dependencies
\[[`cd8fa50`](cd8fa50),
[`f19bade`](f19bade)]:
    -   gt@2.14.39

## locadex@1.0.174

### Patch Changes

- Updated dependencies
\[[`cd8fa50`](cd8fa50),
[`f19bade`](f19bade)]:
    -   gt@2.14.39

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1456"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-light.svg"><img
alt="View in Codesmith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"></picture></a>
<sup>Need help on this PR? Tag <code>@codesmith</code> with what you
need.</sup>

- [ ] Let Codesmith autofix CI failures and bot reviews
<!-- /codesmith:footer -->
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@2.14.40

### Patch Changes

- [#1456](#1456)
[`8094012`](8094012)
Thanks [@fernando-aviles](https://github.com/fernando-aviles)! -
Handling slash in Mint `url` fields

## gtx-cli@2.14.40

### Patch Changes

- Updated dependencies
\[[`8094012`](8094012)]:
    -   gt@2.14.40

## locadex@1.0.175

### Patch Changes

- Updated dependencies
\[[`8094012`](8094012)]:
    -   gt@2.14.40

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1457"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-light.svg"><img
alt="View in Codesmith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"></picture></a>
<sup>Need help on this PR? Tag <code>@codesmith</code> with what you
need.</sup>

- [ ] Let Codesmith autofix CI failures and bot reviews
<!-- /codesmith:footer -->

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## Summary
- remove deprecated `autoDerive` compatibility from CLI, compiler, and
Next config parsing
- remove deprecated Next config aliases: `experimentalSwcPluginOptions`,
`disableSSGWarnings`, and static request path props
- remove deprecated warning scaffolding for static request config and
SSG warning suppression

## Tests
- `pnpm --filter @generaltranslation/compiler typecheck`
- `pnpm --filter @generaltranslation/compiler test`
- `pnpm --filter gt test -- --runInBand`
- `pnpm --filter gt-next test:js -- src/__tests__/config.test.ts`
- `pnpm --filter @generaltranslation/react-core build`
- `pnpm --filter gt-react build`
- `pnpm --filter gt-next typecheck`
- `git diff --check`

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1458"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-light.svg"><img
alt="View in Codesmith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"></picture></a>
<sup>Need help on this PR? Tag <code>@codesmith</code> with what you
need.</sup>

- [ ] Let Codesmith autofix CI failures and bot reviews
<!-- /codesmith:footer -->

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR removes all deprecated compatibility shims introduced when
renaming `autoDerive` → `autoderive`, `experimentalSwcPluginOptions` →
`experimentalCompilerOptions`, and static locale path props → dynamic
path props, as well as the `disableSSGWarnings` escape hatch. It is a
breaking-change cleanup across the CLI, compiler, and Next packages.

- **`autoDerive` aliases removed** from the compiler config type,
`initializeState`, and `parseFilesConfig` — any user still passing
`autoDerive` will have it silently ignored instead of being normalized.
- **Static request function path props** (`getStaticLocalePath`,
`getStaticRegionPath`, `getStaticDomainPath`) removed from
`withGTConfigProps` and `resolveRequestFunctionPaths`; static functions
now rely entirely on filesystem auto-discovery.
- **`disableSSGWarnings` fully dropped**: the env variable injection,
its type/default, and the conditional short-circuit in the two SSG
warning factories are all gone, so the SSG warnings now always fire.

<details open><summary><h3>Confidence Score: 5/5</h3></summary>

Safe to merge — this is a targeted cleanup of long-deprecated APIs with
no new logic introduced.

Every removed symbol had an explicit deprecation notice and a direct
replacement already in use. The resolveRequestFunctionPaths refactor
correctly splits regular and static function resolution into two clearly
intentional loops. The disableSSGWarnings env-var path is consistently
removed from both the injection site and all consuming call sites. Tests
were updated in lockstep.

No files require special attention; all changes are symmetric removals
of deprecated code paths.
</details>

<details><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| packages/next/src/config-dir/utils/resolveRequestFunctionPaths.ts |
Splits the combined loop into two — regular functions use config-key
lookup then filesystem fallback; static functions now only use
filesystem auto-discovery, correctly removing the deprecated path-prop
path. |
| packages/next/src/config.ts | Removes deprecated warning, env-var
injection for _GENERALTRANSLATION_DISABLE_SSG_WARNINGS,
experimentalSwcPluginOptions merge, and autoDerive fallback; moves
customMapping to ConfigFileShape (read from gt.config.json). |
| packages/next/src/errors/ssg.ts | Removes the
process.env._GENERALTRANSLATION_DISABLE_SSG_WARNINGS conditional
short-circuit; warning functions now always return diagnostic strings. |
| packages/next/src/config-dir/props/withGTConfigProps.ts | Removes
deprecated props (disableSSGWarnings, experimentalSwcPluginOptions,
customMapping, static path props) and the
DEPRECATED_REQUEST_FUNCTION_TO_CONFIG_KEY map. |
| packages/compiler/src/state/utils/initializeState.ts | Drops
autoDerive fallback in both config-file read and options read; also
cleans up the destructuring exclusion list. |

</details>

</details>

<sub>Reviews (1): Last reviewed commit: ["refactor: remove deprecated
config
alias..."](b9a8096)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=32906779)</sub>

<!-- /greptile_comment -->
ErnestM1234 and others added 2 commits May 19, 2026 16:57
## Summary

- Skip `condenseVars()` parsing/printing unless the ICU string contains
an indexed GT variable like `_gt_1`.
- Preserve source-locale `declareVar()` strings that use unindexed
`_gt_`, including escaped trailing apostrophes like `Haas''`.
- Expand `condenseVars` regression coverage for source strings, indexed
translation strings, nested ICU structures, and parser normalization
behavior.
- Add a patch changeset for `generaltranslation`.

## Why

Source strings use unindexed `_gt_` variables, while translated strings
use indexed `_gt_#` variables. Those forms are mutually exclusive in
real inputs: source-locale strings should only contain `_gt_`, and
translated strings should only contain `_gt_#`.

`condenseVars()` only needs to condense indexed translation variables,
but the old guard ran the ICU parse/`printAST()` round trip for source
strings too.

That round trip is not a no-op: it can normalize escaped apostrophes,
turning a valid source fragment like `Haas''` into `Haas'`. Skipping
source strings avoids breaking default-locale interpolation while
preserving the existing translation condensing behavior.

## Tests

- `pnpm --filter generaltranslation test --
src/derive/__tests__/condenseVars.test.ts`
- `pnpm --filter generaltranslation typecheck`

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1460"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-light.svg"><img
alt="View in Codesmith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"></picture></a>
<sup>Need help on this PR? Tag <code>@codesmith</code> with what you
need.</sup>

- [ ] Let Codesmith autofix CI failures and bot reviews
<!-- /codesmith:footer -->

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR fixes a bug where `condenseVars()` incorrectly ran an ICU
parse/`printAST()` round-trip on source-locale strings that use
unindexed `_gt_` variables, causing escaped apostrophes like `Haas''` to
be collapsed to `Haas'`. The guard is tightened from a plain
`includes('_gt_')` check to a regex test for `_gt_\d+` (indexed form
only), so unindexed source strings are returned as-is.

- **`condenseVars.ts`**: Replaces the `VAR_IDENTIFIER` substring check
with `CONTAINS_INDEXED_GT_REGEX` (`/_gt_\d+/`), ensuring only strings
with indexed translation variables (`_gt_1`, `_gt_2`, …) proceed through
the parse/`printAST` round-trip.
- **`condenseVars.test.ts`**: Full test suite rewrite with four describe
blocks — source string preservation (including escaped-apostrophe edge
cases), non-select indexed patterns, indexed translation condensing, and
deeply nested structures.
- **`.changeset/tough-ghosts-shop.md`**: Patch changeset entry
accurately describing the bug.

<details open><summary><h3>Confidence Score: 5/5</h3></summary>

Safe to merge — the change is a focused guard tightening with
comprehensive test coverage and no functional changes to the translation
condensing path.

The one-line logic change is correct: `_gt_\d+` (unanchored substring)
is the right predicate to detect indexed translation strings without
false-positives against unindexed source strings or `_gt_var_name`. The
downstream `isGTIndexedSelectElement` already uses the anchored
`^_gt_\d+$` regex, so any string that passes the new guard but carries a
non-select or non-exact identifier still goes through a benign
parse/printAST round-trip without condensing. The extensive new test
suite covers apostrophe preservation, nested structures, edge-case
identifiers, and parser-normalization behavior.

No files require special attention.
</details>

<details><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| packages/core/src/derive/condenseVars.ts | Guard changed from
`includes('_gt_')` to a regex test for `_gt_\d+`, preventing
source-locale strings from going through the lossy parse/printAST
round-trip. |
| packages/core/src/derive/__tests__/condenseVars.test.ts | Full test
rewrite with four focused describe blocks covering source strings
(including escaped-apostrophe preservation), non-GT indexed selects,
indexed translation variables, and deeply nested structures. |
| .changeset/tough-ghosts-shop.md | Patch changeset added for
`generaltranslation` package with an accurate description of the bug
fixed. |

</details>

</details>

<details><summary><h3>Flowchart</h3></summary>

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[condenseVars called with icuString] --> B{CONTAINS_INDEXED_GT_REGEX\nmatches _gt_\\d+ ?}
    B -- No --> C[Return icuString unchanged\ne.g. source strings with _gt_\napostrophes preserved]
    B -- Yes --> D[traverseIcu with\nisGTIndexedSelectElement predicate]
    D --> E{Node is TYPE.select\nwith ^_gt_\\d+$ value\nand valid other branch?}
    E -- No --> F[Leave node unchanged\ne.g. _gt_1 plural/number/argument]
    E -- Yes --> G[Convert to TYPE.argument\ndelete options]
    F --> H[printAST — serialize AST]
    G --> H
    H --> I[Return condensed ICU string]
```
</details>

<sub>Reviews (2): Last reviewed commit: ["test: format condense vars
tests"](da4174a)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=32914159)</sub>

<!-- /greptile_comment -->
## Summary
- Route public react-core components through their GtInternal
counterparts via JSX
- Standardize public wrapper return types as React.JSX.Element
- Extract shared prop types for the wrapper/internal pairs

## Verification
- pnpm --filter @generaltranslation/react-core build

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1449"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-light.svg"><img
alt="View in Codesmith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"></picture></a>
<sup>Need help on this PR? Tag <code>@codesmith</code> with what you
need.</sup>

- [ ] Let Codesmith autofix CI failures and bot reviews
<!-- /codesmith:footer -->

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR standardizes the public/internal component wrapper pattern
across `react-core` by inverting the caller relationship — the
`GtInternal*` variants now own the implementation logic, and the public
wrappers (`Branch`, `Plural`, `Currency`, etc.) delegate to them via JSX
rather than direct function calls. Shared prop types (`BranchProps`,
`PluralProps`, `CurrencyProps`, etc.) are extracted to eliminate
duplication between the wrapper and internal pairs.

- **Wrapper inversion**: In all eight files the public component now
renders `<GtInternal* {...props} />` via JSX, making the React component
lifecycle (hooks, reconciliation) work correctly in the internal
variants rather than bypassing it through direct function invocation.
- **Return type standardisation**: Public wrapper return types are
uniformly declared as `React.JSX.Element`; internal implementations
continue to return their natural types (`ReactNode`, `string | null`, or
generic `T`).
- **Shared prop types**: A single named type per component pair replaces
duplicated inline object types, reducing divergence risk if props need
to evolve.

<details open><summary><h3>Confidence Score: 5/5</h3></summary>

Safe to merge — this is a pure structural refactor with no changes to
business logic or rendering output.

All eight files follow a uniform mechanical transformation: extract a
shared props type, move the implementation body into the GtInternal*
function, and have the public wrapper render it via JSX. No conditional
logic, hook calls, or data paths were altered. The build passes, _gtt
markers are preserved, and the only observable API differences were
already surfaced in the previous review round.

No files require special attention — the changes are consistent and
mechanical across all eight components.
</details>

<details><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| packages/react-core/src/components/branches/Branch.tsx | Inverted
public/internal relationship — GtInternalBranch is now the
implementation, Branch wraps it via JSX; shared BranchProps type
extracted; _gtt markers unchanged. |
| packages/react-core/src/components/branches/Plural.tsx | Same
inversion as Branch — GtInternalPlural holds the hook call and logic,
Plural delegates via JSX; PluralProps shared; no behavioural change. |
| packages/react-core/src/components/derivation/Derive.tsx | Public
Derive<T> now returns React.JSX.Element instead of T; the generic return
type is effectively dropped on the public wrapper (noted in previous
review). |
| packages/react-core/src/components/variables/Currency.tsx | Public
Currency now returns React.JSX.Element instead of string | null;
CurrencyProps extracted and shared; no React import but uses
React.JSX.Element (relies on UMD global from @types/react). |
| packages/react-core/src/components/variables/RelativeTime.tsx | name
prop now included in shared RelativeTimeProps, expanding the public API
surface; public wrapper return type changed to React.JSX.Element. |
| packages/react-core/src/components/variables/Var.tsx | computeVar
helper preserved and still exported; GtInternalVar is now the sole
caller of computeVar; Var<T> wraps via JSX losing the generic return
type on the public API. |
| packages/react-core/src/components/variables/DateTime.tsx |
DateTimeProps extracted; public DateTime return type changed from string
| null to React.JSX.Element; straightforward refactor with no logic
changes. |
| packages/react-core/src/components/variables/Num.tsx | NumProps
extracted; public Num return type changed from string | null to
React.JSX.Element; straightforward refactor with no logic changes. |

</details>

</details>

<details><summary><h3>Flowchart</h3></summary>

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph Before
        B1["Branch (implementation)"] -->|"direct call: Branch(props)"| B2["GtInternalBranch (wrapper)"]
        C1["Currency (implementation)\nreturns string | null"] -->|"direct call"| C2["GtInternalCurrency (wrapper)\nreturns string | null"]
    end

    subgraph After
        A1["GtInternalBranch (implementation)\nreturns ReactNode"] -->|"rendered via JSX"| A2["Branch (public wrapper)\nreturns React.JSX.Element"]
        D1["GtInternalCurrency (implementation)\nreturns string | null"] -->|"rendered via JSX"| D2["Currency (public wrapper)\nreturns React.JSX.Element"]
    end

    style Before fill:#f9f0e8,stroke:#ccc
    style After fill:#e8f4f9,stroke:#ccc
```
</details>

<sub>Reviews (2): Last reviewed commit: ["refactor: standardize
react-core
compone..."](93836ad)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=32723020)</sub>

<!-- /greptile_comment -->
github-actions Bot and others added 3 commits May 19, 2026 17:06
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@2.14.41

### Patch Changes

- Updated dependencies
\[[`e041312`](e041312)]:
    -   generaltranslation@8.2.16
    -   @generaltranslation/python-extractor@0.2.22
    -   @generaltranslation/supported-locales@2.1.1

## @generaltranslation/compiler@1.3.24

### Patch Changes

- Updated dependencies
\[[`e041312`](e041312)]:
    -   generaltranslation@8.2.16

## generaltranslation@8.2.16

### Patch Changes

- [#1460](#1460)
[`e041312`](e041312)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - fix: escape
characters in declareVar() for source locale consumed by condenseVars()

## gtx-cli@2.14.41

### Patch Changes

-   Updated dependencies \[]:
    -   gt@2.14.41

## gt-i18n@0.9.5

### Patch Changes

- Updated dependencies
\[[`e041312`](e041312)]:
    -   generaltranslation@8.2.16
    -   @generaltranslation/supported-locales@2.1.1

## locadex@1.0.176

### Patch Changes

-   Updated dependencies \[]:
    -   gt@2.14.41

## gt-next@6.16.30

### Patch Changes

- Updated dependencies
\[[`e041312`](e041312)]:
    -   generaltranslation@8.2.16
    -   @generaltranslation/compiler@1.3.24
    -   gt-i18n@0.9.5
    -   gt-react@10.19.19
    -   @generaltranslation/supported-locales@2.1.1

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

### Patch Changes

-   Updated dependencies \[]:
    -   gt-next@6.16.30

## gt-node@0.7.5

### Patch Changes

- Updated dependencies
\[[`e041312`](e041312)]:
    -   generaltranslation@8.2.16
    -   gt-i18n@0.9.5

## @generaltranslation/python-extractor@0.2.22

### Patch Changes

- Updated dependencies
\[[`e041312`](e041312)]:
    -   generaltranslation@8.2.16

## gt-react@10.19.19

### Patch Changes

- Updated dependencies
\[[`e041312`](e041312)]:
    -   generaltranslation@8.2.16
    -   gt-i18n@0.9.5
    -   @generaltranslation/react-core@1.8.21
    -   @generaltranslation/supported-locales@2.1.1

## @generaltranslation/react-core@1.8.21

### Patch Changes

- Updated dependencies
\[[`e041312`](e041312)]:
    -   generaltranslation@8.2.16
    -   gt-i18n@0.9.5
    -   @generaltranslation/supported-locales@2.1.1

## gt-react-native@10.19.19

### Patch Changes

- Updated dependencies
\[[`e041312`](e041312)]:
    -   generaltranslation@8.2.16
    -   @generaltranslation/react-core@1.8.21
    -   @generaltranslation/supported-locales@2.1.1

## gt-sanity@2.0.18

### Patch Changes

- Updated dependencies
\[[`e041312`](e041312)]:
    -   generaltranslation@8.2.16

## @generaltranslation/supported-locales@2.1.1

### Patch Changes

- Updated dependencies
\[[`e041312`](e041312)]:
    -   generaltranslation@8.2.16

## gt-tanstack-start@0.4.23

### Patch Changes

- Updated dependencies
\[[`e041312`](e041312)]:
    -   generaltranslation@8.2.16
    -   gt-i18n@0.9.5
    -   gt-react@10.19.19
    -   @generaltranslation/react-core@1.8.21

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1461"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-light.svg"><img
alt="View in Codesmith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"></picture></a>
<sup>Need help on this PR? Tag <code>@codesmith</code> with what you
need.</sup>

- [ ] Let Codesmith autofix CI failures and bot reviews
<!-- /codesmith:footer -->

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## Summary
- use the Oxc VS Code extension as the workspace formatter instead of
Prettier
- run Oxc fix-all on save so editor saves match pnpm lint:fix
- recommend the Oxc VS Code extension for contributors

## Verification
-
PATH=/opt/homebrew/bin:/Users/ernestmccarter/.cargo/bin:/bin:/usr/bin:/usr/ucb:/usr/local/bin
/opt/homebrew/bin/pnpm lint:fix
-
PATH=/opt/homebrew/bin:/Users/ernestmccarter/.cargo/bin:/bin:/usr/bin:/usr/ucb:/usr/local/bin
/opt/homebrew/bin/pnpm lint

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1467"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img
alt="View with Codesmith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a>
<a
href="https://backend.blacksmith.sh/track/enable-autofix?expires=1782422181&installation_id=127936663&pr_number=1467&repository=generaltranslation%2Fgt&return_to=https%3A%2F%2Fgithub.com%2Fgeneraltranslation%2Fgt%2Fpull%2F1467&signature=c11b997ec17b504011762f55d8c0fdce136342d14106bdb4ac8a49d3b7951047"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img
alt="Autofix with Codesmith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a>
<sup>Need help on this PR? Tag <code>@codesmith</code> with what you
need. Autofix is disabled.</sup>

<!-- codesmith:autofix:disabled -->
<!-- /codesmith:footer -->
## Summary
- move translation and dictionary hydration into `InternalGTProvider`
- split provider setup around readonly/browser condition stores
- simplify `I18nStore` so locale state comes from condition-store
snapshots

## Testing
- Not run; local `node`/`pnpm` are not available on PATH in this shell

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1466"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img
alt="View with Codesmith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a>
<a
href="https://backend.blacksmith.sh/track/enable-autofix?expires=1782412350&installation_id=127936663&pr_number=1466&repository=generaltranslation%2Fgt&return_to=https%3A%2F%2Fgithub.com%2Fgeneraltranslation%2Fgt%2Fpull%2F1466&signature=67343ad5aa85873e283263ae9a8d6c869e9ea3768531ba89ebc018e92cb1edc7"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img
alt="Autofix with Codesmith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a>
<sup>Need help on this PR? Tag <code>@codesmith</code> with what you
need. Autofix is disabled.</sup>

<!-- codesmith:autofix:disabled -->
<!-- /codesmith:footer -->

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR refactors provider initialization by moving translation and
dictionary hydration into `InternalGTProvider`, splitting
condition-store setup between readonly and browser variants, and
stripping locale management out of `I18nStore` (removing `setLocale`,
`setEnableI18n`, and the loading-status machinery). The result is a
leaner `I18nStore` that reads locale exclusively from condition-store
snapshots, and clearer boundaries between the SSR and CSR provider
paths.

- `InternalGTProvider` now owns
`updateTranslations`/`updateDictionaries` (inside a `useMemo`),
`translations` is promoted to a required prop, and the
`GTContext`/`reloadLocale` mechanism is deleted.
- Condition-store singletons in `react-core` are unified under a
read-only interface; the `react` package keeps a separate
`BrowserConditionStore` singleton with new
`updateLocale`/`updateEnableI18n` \"soft-update\" methods and a
configurable `reload` callback.
- `useSetLocale`/`useSetEnableI18n` are moved from `react-core` to the
`react` package where the browser singleton lives; `react-core` now
exposes only read hooks (`useLocale`, `useEnableI18n`).

<details open><summary><h3>Confidence Score: 4/5</h3></summary>

The refactor is structurally sound but several side-effect-in-render
issues flagged in earlier review threads remain unaddressed; merging
as-is carries those known risks.

The new code introduces no fresh critical paths of its own. The
unresolved concerns from earlier threads — side effects executed
directly in the CSRGTProvider and InternalGTProvider render bodies, and
the getRenderStrategy() throw inside the fallback catch block — are
still present and could cause observable issues in React StrictMode or
when the condition store is uninitialized. The dead
subscribeToLocale/subscribeToEnableI18n methods are also latent traps
for future subscribers.

packages/react-core/src/context/InternalGTProvider.tsx and
packages/react/src/provider/CSRGTProvider.tsx for the unresolved
render-body side effects;
packages/react-core/src/condition-store/singleton-operations.ts for the
throwing catch block.
</details>

<details><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| packages/react-core/src/context/InternalGTProvider.tsx | Core provider
drastically simplified — GTContext removed, translations now hydrated
via useMemo, but multiple side-effects (I18nStore construction,
singleton mutations, and useMemo-driven i18nManager calls) run in the
component body; previously flagged in review threads. |
| packages/react/src/provider/CSRGTProvider.tsx | Simplified to delegate
to createOrUpdateBrowserConditionStore; cookie writes and
condition-store mutation still occur unconditionally in the render body
on every re-render (previously flagged). |
| packages/react/src/provider/SSRGTProvider.tsx | Condition store
creation guarded by initialization check; translation/dictionary
hydration delegated to InternalGTProvider. Locale in
ReadonlyConditionStore is only set on first initialization (existing
limitation). |
| packages/react-core/src/condition-store/singleton-operations.ts | New
fallback wrapper provides resilience in production but calls
getRenderStrategy() inside the catch block, which can itself throw when
renderStrategy is unset — defeating the graceful fallback path (flagged
in previous thread, deferred to separate PR). |
| packages/react/src/condition-store/BrowserConditionStore.ts | Clean
split between soft (updateLocale/updateEnableI18n — cookie only) and
hard (setLocale/setEnableI18n — cookie + reload) operations;
configurable reload callback is a good extension point. |
| packages/react-core/src/i18n-store/I18nStore.ts | Significant removal
of setLocale, setEnableI18n, and translation-status machinery;
constructor validation now uses getReadonlyConditionStoreWithFallback()
which always succeeds in production, making the guard ineffective
outside development. |

</details>

</details>

<details><summary><h3>Sequence Diagram</h3></summary>

```mermaid
sequenceDiagram
    participant App
    participant SSRGTProvider
    participant CSRGTProvider
    participant createOrUpdate as createOrUpdateBrowserConditionStore
    participant BrowserCS as BrowserConditionStore
    participant ReadonlyCS as ReadonlyConditionStore
    participant InternalGTProvider
    participant I18nManager

    Note over App,I18nManager: SSR Path
    App->>SSRGTProvider: render(locale, translations, ...)
    SSRGTProvider->>ReadonlyCS: "new ReadonlyConditionStore({locale,...}) [first init only]"
    SSRGTProvider->>InternalGTProvider: render(translations, dictionaries, ...)
    InternalGTProvider->>I18nManager: useMemo → updateTranslations(translations)
    InternalGTProvider->>I18nManager: useMemo → updateDictionaries(dictionaries)
    InternalGTProvider-->>App: children

    Note over App,I18nManager: CSR Path
    App->>CSRGTProvider: render(locale, translations, ...)
    CSRGTProvider->>createOrUpdate: createOrUpdateBrowserConditionStore(config)
    alt First render
        createOrUpdate->>BrowserCS: "new BrowserConditionStore({locale,...})"
        BrowserCS->>BrowserCS: setCookieValue(locale)
    else Subsequent renders
        createOrUpdate->>BrowserCS: updateLocale(locale) → setCookieValue
        createOrUpdate->>BrowserCS: updateEnableI18n(enableI18n) → setCookieValue
    end
    CSRGTProvider->>InternalGTProvider: render(translations, dictionaries, ...)
    InternalGTProvider->>I18nManager: useMemo → updateTranslations(translations)
    InternalGTProvider->>I18nManager: useMemo → updateDictionaries(dictionaries)
    InternalGTProvider-->>App: children

    Note over App,I18nManager: Locale Change (CSR)
    App->>BrowserCS: setLocale(newLocale)
    BrowserCS->>BrowserCS: updateLocale → setCookieValue
    BrowserCS->>BrowserCS: reload() → window.location.reload()
```
</details>

<a
href="https://app.greptile.com/ide/claude-code?prompt=Fix%20the%20following%202%20code%20review%20issues.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%202%0Apackages%2Freact-core%2Fsrc%2Fi18n-store%2FI18nStore.ts%3A83-89%0A**Dead%20subscription%20methods%20after%20%60setLocale%60%2F%60setEnableI18n%60%20removal**%0A%0A%60subscribeToLocale%60%20and%20%60subscribeToEnableI18n%60%20still%20exist%20and%20expose%20a%20public%20API%2C%20but%20%60localeListeners%60%20and%20%60enableI18nListeners%60%20are%20never%20notified%20anymore%20%E2%80%94%20both%20%60.forEach%28listener%20%3D%3E%20listener%28%29%29%60%20calls%20lived%20in%20the%20now-removed%20%60setLocale%60%20and%20%60setEnableI18n%60%20methods.%20Any%20future%20caller%20using%20%60useSyncExternalStore%28store.subscribeToLocale%2C%20store.getLocaleSnapshot%29%60%20would%20subscribe%20successfully%20but%20never%20receive%20a%20notification%2C%20silently%20displaying%20a%20stale%20locale%20forever.%20These%20two%20methods%20and%20their%20backing%20listener%20sets%20should%20be%20removed%20or%20clearly%20marked%20as%20internal-only%20no-ops%20to%20avoid%20misleading%20future%20consumers.%0A%0A%23%23%23%20Issue%202%20of%202%0Apackages%2Freact-core%2Fsrc%2Fi18n-store%2FI18nStore.ts%3A58-65%0A**Constructor's%20condition-store%20guard%20is%20now%20a%20no-op%20in%20production**%0A%0A%60getReadonlyConditionStoreWithFallback%28%29%60%20never%20throws%20in%20production%20%E2%80%94%20it%20catches%20the%20uninitialized%20error%2C%20logs%20it%2C%20and%20returns%20a%20default%20%60ReadonlyConditionStore%60.%20So%20in%20production%20the%20%60try%2Fcatch%60%20will%20not%20catch%20a%20missing%20condition%20store%2C%20the%20constructor%20succeeds%20silently%2C%20and%20all%20subsequent%20%60getLocaleSnapshot%28%29%60%20calls%20fall%20back%20to%20%60libraryDefaultLocale%60.%20The%20%60getReactI18nManager%28%29%60%20call%20still%20validates%20correctly%2C%20but%20the%20condition-store%20invariant%20is%20no%20longer%20enforced.%20Consider%20using%20the%20un-guarded%20singleton%20accessor%20here%20if%20a%20hard%20failure%20on%20misconfiguration%20is%20the%20intended%20behavior%2C%20or%20document%20that%20production%20silently%20degrades%20to%20the%20default%20locale.%0A%0A&repo=generaltranslation%2Fgt&pr=1466&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaudeDark.svg?v=3"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=3"><img
alt="Fix All in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=3"
height="20"></picture></a> <a
href="https://chatgpt.com/codex/deeplink?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22generaltranslation%2Fgt%22%20on%20the%20existing%20branch%20%22e%2Fodysseus%2Fabstract-initializers-from-providers%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22e%2Fodysseus%2Fabstract-initializers-from-providers%22.%0A%0AFix%20the%20following%202%20code%20review%20issues.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%202%0Apackages%2Freact-core%2Fsrc%2Fi18n-store%2FI18nStore.ts%3A83-89%0A**Dead%20subscription%20methods%20after%20%60setLocale%60%2F%60setEnableI18n%60%20removal**%0A%0A%60subscribeToLocale%60%20and%20%60subscribeToEnableI18n%60%20still%20exist%20and%20expose%20a%20public%20API%2C%20but%20%60localeListeners%60%20and%20%60enableI18nListeners%60%20are%20never%20notified%20anymore%20%E2%80%94%20both%20%60.forEach%28listener%20%3D%3E%20listener%28%29%29%60%20calls%20lived%20in%20the%20now-removed%20%60setLocale%60%20and%20%60setEnableI18n%60%20methods.%20Any%20future%20caller%20using%20%60useSyncExternalStore%28store.subscribeToLocale%2C%20store.getLocaleSnapshot%29%60%20would%20subscribe%20successfully%20but%20never%20receive%20a%20notification%2C%20silently%20displaying%20a%20stale%20locale%20forever.%20These%20two%20methods%20and%20their%20backing%20listener%20sets%20should%20be%20removed%20or%20clearly%20marked%20as%20internal-only%20no-ops%20to%20avoid%20misleading%20future%20consumers.%0A%0A%23%23%23%20Issue%202%20of%202%0Apackages%2Freact-core%2Fsrc%2Fi18n-store%2FI18nStore.ts%3A58-65%0A**Constructor's%20condition-store%20guard%20is%20now%20a%20no-op%20in%20production**%0A%0A%60getReadonlyConditionStoreWithFallback%28%29%60%20never%20throws%20in%20production%20%E2%80%94%20it%20catches%20the%20uninitialized%20error%2C%20logs%20it%2C%20and%20returns%20a%20default%20%60ReadonlyConditionStore%60.%20So%20in%20production%20the%20%60try%2Fcatch%60%20will%20not%20catch%20a%20missing%20condition%20store%2C%20the%20constructor%20succeeds%20silently%2C%20and%20all%20subsequent%20%60getLocaleSnapshot%28%29%60%20calls%20fall%20back%20to%20%60libraryDefaultLocale%60.%20The%20%60getReactI18nManager%28%29%60%20call%20still%20validates%20correctly%2C%20but%20the%20condition-store%20invariant%20is%20no%20longer%20enforced.%20Consider%20using%20the%20un-guarded%20singleton%20accessor%20here%20if%20a%20hard%20failure%20on%20misconfiguration%20is%20the%20intended%20behavior%2C%20or%20document%20that%20production%20silently%20degrades%20to%20the%20default%20locale.%0A%0A"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=3"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=3"><img
alt="Fix All in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=3"
height="20"></picture></a>

<details><summary>Prompt To Fix All With AI</summary>

`````markdown
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
packages/react-core/src/i18n-store/I18nStore.ts:83-89
**Dead subscription methods after `setLocale`/`setEnableI18n` removal**

`subscribeToLocale` and `subscribeToEnableI18n` still exist and expose a public API, but `localeListeners` and `enableI18nListeners` are never notified anymore — both `.forEach(listener => listener())` calls lived in the now-removed `setLocale` and `setEnableI18n` methods. Any future caller using `useSyncExternalStore(store.subscribeToLocale, store.getLocaleSnapshot)` would subscribe successfully but never receive a notification, silently displaying a stale locale forever. These two methods and their backing listener sets should be removed or clearly marked as internal-only no-ops to avoid misleading future consumers.

### Issue 2 of 2
packages/react-core/src/i18n-store/I18nStore.ts:58-65
**Constructor's condition-store guard is now a no-op in production**

`getReadonlyConditionStoreWithFallback()` never throws in production — it catches the uninitialized error, logs it, and returns a default `ReadonlyConditionStore`. So in production the `try/catch` will not catch a missing condition store, the constructor succeeds silently, and all subsequent `getLocaleSnapshot()` calls fall back to `libraryDefaultLocale`. The `getReactI18nManager()` call still validates correctly, but the condition-store invariant is no longer enforced. Consider using the un-guarded singleton accessor here if a hard failure on misconfiguration is the intended behavior, or document that production silently degrades to the default locale.

`````

</details>

<sub>Reviews (4): Last reviewed commit: ["small
greptile"](68f488a)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=33998551)</sub>

<!-- /greptile_comment -->
ErnestM1234 and others added 5 commits July 3, 2026 13:16
## Summary
- Normalize source fallback options for `useGT()` and standalone
`t("...", options)` so ICU placeholders interpolate when translation is
not required.
- Preserve tagged-template lookup behavior; the tagged form still uses
the existing string-format lookup path.
- Clarify `tx()` docs so ICU formatting is described as opt-in via
`$format: 'ICU'`.
- Add patch changeset entries for `@generaltranslation/react-core` and
`gt-next`.

## Testing
- `pnpm --filter @generaltranslation/react-core test`
- `pnpm --filter @generaltranslation/react-core typecheck`
- `pnpm format`
- `pnpm --filter @generaltranslation/react-core... build`
- Linked `gt-test-apps/base/next-app-router` to this worktree and
verified dev + production builds/browser locale switching for
`gt("hello, {name}", { name: "brian" })` in `en`, `fr`, and `zh`.
## Summary
- Import the runtime FormatJS `TYPE` enum from
`@formatjs/icu-messageformat-parser` instead of the `types.js` subpath.
- Keep FormatJS element shapes as type-only imports from `types.js`.

## Testing
- `pnpm --filter generaltranslation test`
- `pnpm exec turbo run build --filter=gt-tanstack-start... --ui stream`
- Linked `base/tanstack-start` from `gt-test-apps` to this GT worktree
with `pnpm gt:link tanstack-start
/Users/ernestmccarter/Documents/dev/gt-wt/e-odysseus-fix-tanstack-formatjs-type`
- `pnpm --dir base/tanstack-start build`
- Browser checked `http://localhost:5173/ssr` in dev: selected `fr`,
verified provider locale `fr`, French GT strings, and zero captured
browser runtime/log errors
- Browser checked `http://localhost:4173/ssr` in production preview:
selected `fr`, verified provider locale `fr`, French GT strings, and
zero captured browser runtime/log errors

No changeset added.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR fixes an incorrect import path for the FormatJS `TYPE` runtime
enum in two files. Previously, `TYPE` was imported from
`@formatjs/icu-messageformat-parser/types.js`, a type-declaration-only
subpath that carries no runtime value, causing bundler/runtime failures
(observed in TanStack Start builds).

- **`condenseVars.ts`**: `TYPE` moved to the main
`@formatjs/icu-messageformat-parser` entry; `ArgumentElement` stays as a
`type`-only import from `types.js`.
- **`traverseHelpers.ts`**: Same split — `TYPE` from the main entry,
`MessageFormatElement` as a `type`-only import from `types.js`.

<details open><summary><h3>Confidence Score: 5/5</h3></summary>

Safe to merge — the change is a targeted two-line import split that
directly fixes a bundler runtime failure with no logic changes.

Both files receive the identical, correct treatment: the runtime TYPE
enum moves to the main package entry where it has an actual value
export, while the TypeScript shape types stay as type-only imports from
the declaration subpath. The rest of the codebase (utils/types.ts) was
already using import type from types.js correctly and is untouched. No
logic, no tests, and no public API are affected.

No files require special attention.
</details>

<details><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| packages/core/src/derive/condenseVars.ts | TYPE import moved from
types.js subpath to main package entry; ArgumentElement kept as
type-only import. Change is correct. |
| packages/core/src/derive/utils/traverseHelpers.ts | TYPE import moved
from types.js subpath to main package entry; MessageFormatElement kept
as type-only import. Change is correct. |

</details>

<details><summary><h3>Flowchart</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["@formatjs/icu-messageformat-parser\n(main entry)"] -->|"import { TYPE }"| B["condenseVars.ts"]
    A -->|"import { TYPE }"| C["traverseHelpers.ts"]
    D["@formatjs/icu-messageformat-parser/types.js\n(type declarations only)"] -->|"import type { ArgumentElement }"| B
    D -->|"import type { MessageFormatElement }"| C
    D -->|"import type { PluralOrSelectOption, LiteralElement, SelectElement }"| E["utils/types.ts"]

    style A fill:#22c55e,color:#fff
    style D fill:#64748b,color:#fff
```

</a>
<a href="#gh-dark-mode-only">

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["@formatjs/icu-messageformat-parser\n(main entry)"] -->|"import { TYPE }"| B["condenseVars.ts"]
    A -->|"import { TYPE }"| C["traverseHelpers.ts"]
    D["@formatjs/icu-messageformat-parser/types.js\n(type declarations only)"] -->|"import type { ArgumentElement }"| B
    D -->|"import type { MessageFormatElement }"| C
    D -->|"import type { PluralOrSelectOption, LiteralElement, SelectElement }"| E["utils/types.ts"]

    style A fill:#22c55e,color:#fff
    style D fill:#64748b,color:#fff
```

</a>
</details>

<sub>Reviews (2): Last reviewed commit: ["fix: avoid formatjs type
subpath
runtime..."](59b2561)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40704066)</sub>

<!-- /greptile_comment -->
## Summary
- Rename the React Native `GTProvider` loading fallback prop from
`loadingFallback` to `fallback`.
- Add a patch changeset for `gt-react-native`.

## Testing
- `pnpm --filter gt-react-native... build`
- `pnpm --filter gt-react-native test`
- `pnpm --filter gt-react-native typecheck`
- `pnpm exec oxlint packages/react-native`
- `pnpm exec oxfmt --check
packages/react-native/src/provider/GTProvider.tsx
.changeset/react-native-fallback-option.md`

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR renames the `GTProvider` loading fallback prop in
`gt-react-native` from `loadingFallback` to `fallback`, and adds a patch
changeset. The prop was introduced only one commit prior on this
prerelease branch, so no stable-release consumers are affected.

- Renames `loadingFallback?: ReactNode` to `fallback?: ReactNode` in
`GTProviderProps`, updates destructuring in `LoadableGTProvider`, and
introduces `renderedFallback` as the resolved local variable to avoid
shadowing the new prop name inside the JSX tree.
- Adds a `.changeset/react-native-fallback-option.md` entry marking the
`gt-react-native` package for a patch release.

<details open><summary><h3>Confidence Score: 5/5</h3></summary>

Safe to merge — this is a clean, self-contained prop rename with no
remaining references to the old name anywhere in the package.

The rename is complete: the type definition, destructuring, and all JSX
usages are consistently updated. The `loadingFallback` name was
introduced only in the immediately preceding commit on this prerelease
branch, so no stable-release consumers are affected. A repo-wide grep
confirmed zero lingering references to the old prop name.

No files require special attention.
</details>

<details><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| packages/react-native/src/provider/GTProvider.tsx | Prop renamed from
`loadingFallback` to `fallback`; local variable renamed to
`renderedFallback` to prevent shadowing — logic is correct and all
references updated. |
| .changeset/react-native-fallback-option.md | Changeset entry marks
`gt-react-native` for a patch release; appropriate given the prop was
first introduced on this prerelease branch in the immediately preceding
commit. |

</details>

<details><summary><h3>Sequence Diagram</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User as App / User
    participant GTP as GTProvider
    participant LGTP as LoadableGTProvider
    participant Susp as React Suspense
    participant NGTP as NativeGTProvider
    participant LDGTP as LoadedGTProvider

    User->>GTP: "render GTProvider fallback={...}"
    GTP->>LGTP: forwards all props
    LGTP->>LGTP: "destructure { fallback, ...providerProps }"
    LGTP->>LGTP: "renderedFallback = fallback ?? DefaultLoadingFallback"
    LGTP->>Susp: "render Suspense fallback={NativeGTProvider > renderedFallback}"
    Susp-->>NGTP: (while loading) render NativeGTProvider w/ empty translations
    NGTP-->>User: shows renderedFallback inside GT context
    Susp->>LDGTP: (once loaded) render LoadedGTProvider
    LDGTP->>NGTP: render NativeGTProvider w/ real translations
    NGTP-->>User: shows app children with full i18n context
```

</a>
<a href="#gh-dark-mode-only">

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant User as App / User
    participant GTP as GTProvider
    participant LGTP as LoadableGTProvider
    participant Susp as React Suspense
    participant NGTP as NativeGTProvider
    participant LDGTP as LoadedGTProvider

    User->>GTP: "render GTProvider fallback={...}"
    GTP->>LGTP: forwards all props
    LGTP->>LGTP: "destructure { fallback, ...providerProps }"
    LGTP->>LGTP: "renderedFallback = fallback ?? DefaultLoadingFallback"
    LGTP->>Susp: "render Suspense fallback={NativeGTProvider > renderedFallback}"
    Susp-->>NGTP: (while loading) render NativeGTProvider w/ empty translations
    NGTP-->>User: shows renderedFallback inside GT context
    Susp->>LDGTP: (once loaded) render LoadedGTProvider
    LDGTP->>NGTP: render NativeGTProvider w/ real translations
    NGTP-->>User: shows app children with full i18n context
```

</a>
</details>

<sub>Reviews (2): Last reviewed commit: ["fix: rename react native
fallback
prop"](da56eda)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=41670715)</sub>

<!-- /greptile_comment -->
## What

Audit + cleanup of the not-initialized error policy for the shared
singletons (`I18nConfig`, `I18nCache`, `I18nStore`, `GTContext`,
condition stores).

### Policy (now uniform)

**Strict everywhere**: every singleton getter throws a descriptive
diagnostic on uninitialized access, in every environment. When
`I18nConfig` itself is uninitialized, its own error propagates as the
root cause — error paths no longer swallow it to build a different
(masking) diagnostic.

### Changes

1. **Removed `getReadonlyConditionStoreWithFallback`** (react-core). It
was the lone degrade-in-prod exception to the strict protocol, and its
protection was illusory: neighboring reads (e.g. the unguarded
`getI18nConfig()` in `getShouldTranslate`) threw regardless, so whether
it "saved" prod depended on which read executed first. Replaced with the
strict `getReadonlyConditionStore`, whose diagnostic now carries a real
fix (`initializeGT()` + `<GTProvider>`). If we ever want forgiving
behavior it should be a deliberate whole-read-path policy (existing
TODOs), not a one-off wrapper.

2. **Root-cause error propagation**: `useGTContext` and the I18nStore
error builder previously called `getI18nConfig()` while
deciding/building their errors, replacing the intended diagnostic with a
bare config error (or vice versa). They now read config directly and let
its error propagate when init never ran — that error carries the correct
fix.

3. **Descriptive, consistently formatted messages**: the condition-store
singletons threw bare internal class names (`'WritableConditionStore is
not initialized.'`, etc.). All now use `createDiagnosticMessage` with
per-package fixes — `initializeGT()`/`initializeGTSPA()` for
gt-i18n/gt-react/gt-node; gt-next's message reflects that init runs via
its entry-point imports and flags edge/serverless bundling as a likely
cause. gt-react's Readonly/Browser condition-store singletons are typed
views of the same global slot, so they intentionally share one message.

## Deployment / bundler risk notes (analysis, no code change needed yet)

- **Registry design is sound for duplication**: singletons live on
`globalThis.__generaltranslation`, so duplicated module instances
(Metro's non-deduped `node_modules`, dual CJS/ESM copies) still share
state. The residual hazard is **version skew**: two different gt-i18n
versions sharing a slot can produce method-missing `TypeError`s instead
of diagnostics. There's an existing TODO in `createGlobalSingleton` for
a version compatibility check — worth prioritizing.
- **gt-next side-effect init**: entry-point module-scope init is
protected by the `sideEffects` allow-list; Next.js respects it, and
gt-next is always consumed by a Next.js app, so this is fine. The new
gt-next message still names the failure mode for unusual setups.
- **Metro**: named subpath entry points require
`unstable_enablePackageExports`; require cycles can expose partial
exports. The globalThis registry limits the blast radius; the
descriptive errors are the backstop.
- **Per-request edge isolates** (Cloudflare/Vercel edge): `globalThis`
is per-isolate, so init must run in every bundle that reads a singleton,
not just the main server bundle. Under the strict policy these surface
as loud, descriptive errors.

## Testing

- `turbo run build test lint` for `gt-i18n`,
`@generaltranslation/react-core`, `gt-react`, `gt-next`, `gt-node`,
`gt-react-native`, `gt-tanstack-start` — all green.
- `pnpm format` clean.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
- Merge `main` (through #1797, commit `4601904`) into `odysseus` to
reconcile git histories.
- **No content changes**: PR #1798 already squash-merged all of main's
content through #1797, and main has not moved since. The merged tree is
byte-identical to the current `odysseus` tip (`git diff odysseus HEAD`
is empty), so this merge only records the ancestry, which eliminates the
recurring stale conflicts on future `main` → `odysseus` merges.
- Merged with the `ours` strategy after verifying there are zero
unabsorbed commits on `main`.

## Tests
- Tree is identical to the `odysseus` baseline, so build/test results
are unchanged by construction.

---------

Co-authored-by: Ben Gubler <me@bengubler.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: fernando-aviles <fernando@generaltranslation.com>
Co-authored-by: Brian Lou <69982825+brian-lou@users.noreply.github.com>
@greptile-apps

greptile-apps Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Too many files changed for review. (1053 files found, 200 file limit)

ErnestM1234 and others added 23 commits July 3, 2026 13:59
…n-history

chore: merge main into odysseus (history reconciliation)
## Summary
- Escape backslashes alongside slashes before compiling middleware
dynamic path regexes.
- Preserve existing regex metacharacter behavior outside dynamic path
segments.
- Replace the tsdown use-client detector regex with a small scanner for
leading whitespace/comments.

## Tests
- `pnpm exec oxfmt --check packages/next/src/middleware-dir/utils.ts
packages/next/src/middleware-dir/__tests__/utils.test.ts
tsdown.preset.mts .changeset/codeql-path-regex.md`
- `pnpm exec oxlint packages/next/src/middleware-dir/utils.ts
packages/next/src/middleware-dir/__tests__/utils.test.ts
tsdown.preset.mts`
- `pnpm --filter gt-next exec vitest run
src/middleware-dir/__tests__/utils.test.ts`
- `pnpm --filter gt-next test:js`

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR fixes two CodeQL regex warnings: it escapes regex metacharacters
in static path segments before constructing dynamic path regexes in
middleware path matching, and replaces the `use client` directive
detector regex in `tsdown.preset.mts` with a manual whitespace/comment
scanner using `startsWith`.

- **`packages/next/src/middleware-dir/utils.ts`**: Introduces
`escapeRegexLiteral` and `createPathRegex` so that literal characters
like `.`, `+`, and `\\` in static portions of path patterns are escaped
before regex construction, preventing untrusted path strings from
injecting regex syntax.
- **`tsdown.preset.mts`**: Replaces a potentially catastrophic
`[\\s\\S]*?` regex over entire file contents with an explicit
character-by-character scanner (`firstCodeIndex` + `isWhitespace`) that
locates the first non-comment token and then uses a plain `startsWith`
check.
- **`packages/next/src/middleware-dir/__tests__/utils.test.ts`**: Adds a
regression test for literal regex metacharacters in path patterns
(targeting `getSharedPath`).

<details open><summary><h3>Confidence Score: 5/5</h3></summary>

Safe to merge; the regex escaping logic is correct and the manual
comment-skipping scanner in tsdown replaces a problematic regex without
introducing new edge-case failures.

The split-escape-rejoin approach in `createPathRegex` is mechanically
sound — static segments are isolated, escaped, and reassembled with the
raw dynamic pattern — and the `firstCodeIndex` scanner correctly handles
all standard JS comment and whitespace forms. The only gap is a missing
test for `inDefaultLocalePaths` with metacharacter inputs, which is
addressed by the same underlying helper that is already tested via
`getSharedPath`.

A test for `inDefaultLocalePaths` with literal metacharacter path
patterns would be a worthwhile addition to
`packages/next/src/middleware-dir/__tests__/utils.test.ts`.
</details>

<details><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| packages/next/src/middleware-dir/utils.ts | Adds `escapeRegexLiteral`
and `createPathRegex` to safely build path-matching regexes; the
split-escape-rejoin logic is correct and applied consistently to both
`getSharedPath` and `inDefaultLocalePaths`. |
| packages/next/src/middleware-dir/__tests__/utils.test.ts | Adds a
regression test for metacharacter escaping in `getSharedPath`; the
parallel fix in `inDefaultLocalePaths` is not covered by a test. |
| tsdown.preset.mts | Replaces a ReDoS-prone multi-line regex with a
simple linear scanner; `firstCodeIndex` correctly handles line comments,
block comments, and all ASCII whitespace. |
| .changeset/codeql-path-regex.md | Changelog entry for the patch;
accurately describes the fix. |

</details>

<details><summary><h3>Flowchart</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["path pattern string"] --> B{includes DYNAMIC_PATH_SEGMENT_PATTERN?}
    B -- No --> C[Skip — use exact string match only]
    B -- Yes --> D["split on '/[^/]+' → static segments array"]
    D --> E["map: escapeRegexLiteral each static segment"]
    E --> F["join with '/[^/]+' → escaped pattern string"]
    F --> G["new RegExp('^' + escaped + '$')"]
    G --> H["regex.test(pathname)"]
    H -- match --> I[Return shared path / true]
    H -- no match --> J[Continue to next pattern]
```

</a>
<a href="#gh-dark-mode-only">

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["path pattern string"] --> B{includes DYNAMIC_PATH_SEGMENT_PATTERN?}
    B -- No --> C[Skip — use exact string match only]
    B -- Yes --> D["split on '/[^/]+' → static segments array"]
    D --> E["map: escapeRegexLiteral each static segment"]
    E --> F["join with '/[^/]+' → escaped pattern string"]
    F --> G["new RegExp('^' + escaped + '$')"]
    G --> H["regex.test(pathname)"]
    H -- match --> I[Return shared path / true]
    H -- no match --> J[Continue to next pattern]
```

</a>
</details>

<a
href="https://app.greptile.com/ide/claude-code?prompt=Fix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Apackages%2Fnext%2Fsrc%2Fmiddleware-dir%2F__tests__%2Futils.test.ts%3A385-396%0A**Missing%20test%20coverage%20for%20%60inDefaultLocalePaths%60**%0A%0AThe%20new%20test%20only%20exercises%20%60getSharedPath%60%2C%20but%20%60inDefaultLocalePaths%60%20received%20the%20same%20%60createPathRegex%60%20fix%20at%20line%20264%20of%20%60utils.ts%60.%20A%20path%20config%20entry%20like%20%60'%2Ffiles%2F%5C%5Cd%2B%2F%5B%5E%2F%5D%2B'%60%20in%20%60defaultLocalePaths%60%20would%20exercise%20the%20same%20code%20path%3B%20without%20a%20test%2C%20a%20future%20refactor%20of%20%60inDefaultLocalePaths%60%20could%20silently%20re-introduce%20the%20metacharacter%20injection%20without%20a%20red%20test.%0A%0A&repo=generaltranslation%2Fgt&pr=1807&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaudeDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=6"><img
alt="Fix All in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=6"></picture></a>
<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22generaltranslation%2Fgt%22%20on%20the%20existing%20branch%20%22e%2Fodysseus%2Fcodeql-escaping-regex%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22e%2Fodysseus%2Fcodeql-escaping-regex%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Apackages%2Fnext%2Fsrc%2Fmiddleware-dir%2F__tests__%2Futils.test.ts%3A385-396%0A**Missing%20test%20coverage%20for%20%60inDefaultLocalePaths%60**%0A%0AThe%20new%20test%20only%20exercises%20%60getSharedPath%60%2C%20but%20%60inDefaultLocalePaths%60%20received%20the%20same%20%60createPathRegex%60%20fix%20at%20line%20264%20of%20%60utils.ts%60.%20A%20path%20config%20entry%20like%20%60'%2Ffiles%2F%5C%5Cd%2B%2F%5B%5E%2F%5D%2B'%60%20in%20%60defaultLocalePaths%60%20would%20exercise%20the%20same%20code%20path%3B%20without%20a%20test%2C%20a%20future%20refactor%20of%20%60inDefaultLocalePaths%60%20could%20silently%20re-introduce%20the%20metacharacter%20injection%20without%20a%20red%20test.%0A%0A&repo=generaltranslation%2Fgt&pr=1807&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img
alt="Fix All in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a>

<details><summary>Prompt To Fix All With AI</summary>

`````markdown
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
packages/next/src/middleware-dir/__tests__/utils.test.ts:385-396
**Missing test coverage for `inDefaultLocalePaths`**

The new test only exercises `getSharedPath`, but `inDefaultLocalePaths` received the same `createPathRegex` fix at line 264 of `utils.ts`. A path config entry like `'/files/\\d+/[^/]+'` in `defaultLocalePaths` would exercise the same code path; without a test, a future refactor of `inDefaultLocalePaths` could silently re-introduce the metacharacter injection without a red test.

`````

</details>

<sub>Reviews (1): Last reviewed commit: ["fix: address codeql regex
warnings"](c25b772)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=41710502)</sub>

> Greptile also left **1 inline comment** on this PR.

<!-- /greptile_comment -->
## Summary
- Add a patch changeset for `generaltranslation` to trigger an odysseus
prerelease.

## Testing
- `pnpm install`
- `pnpm changeset status --since=origin/odysseus`
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 odysseus, this PR
will be updated.

⚠️⚠️⚠️⚠️⚠️⚠️

`odysseus` is currently in **pre mode** so this branch has prereleases
rather than normal releases. If you want to exit prereleases, run
`changeset pre exit` on `odysseus`.

⚠️⚠️⚠️⚠️⚠️⚠️

# Releases
## gt@2.14.51-odysseus.6

### Patch Changes

- Updated dependencies [72e9e16]
- Updated dependencies [5adeede]
- Updated dependencies [2e85ebd]
  - generaltranslation@9.0.0-odysseus.5
  - @generaltranslation/python-extractor@0.2.23-odysseus.5
  - @generaltranslation/supported-locales@2.1.2-odysseus.5
## @generaltranslation/compiler@1.3.25-odysseus.7

### Patch Changes

- Updated dependencies [72e9e16]
- Updated dependencies [5adeede]
- Updated dependencies [2e85ebd]
  - generaltranslation@9.0.0-odysseus.5
## generaltranslation@9.0.0-odysseus.5

### Patch Changes

- 72e9e16: Split the runtime surface of the GT class (locale management,
formatting, runtime translation) into a GTRuntime base class exported
from the new `generaltranslation/runtime` entry point. The SDK runtime
(gt-i18n's I18nConfig, gt-next middleware) now constructs GTRuntime, so
production browser bundles no longer ship the project/file management
API client (enqueueFiles, uploads, downloads, etc.). The GT class
extends GTRuntime and keeps its full API for the CLI and other tooling.
Also import getLocaleProperties from @generaltranslation/format directly
in react-core so client bundles don't reach the full core entry.
- 5adeede: Trigger an odysseus prerelease patch for generaltranslation.
- 2e85ebd: Import the FormatJS `TYPE` runtime enum from the parser
entrypoint so Vite dev does not request the CommonJS `types.js` subpath
as a browser ESM module.
## gtx-cli@2.14.51-odysseus.6

### Patch Changes

- gt@2.14.51-odysseus.6
## gt-i18n@1.0.0-odysseus.8

### Patch Changes

- 72e9e16: Split the runtime surface of the GT class (locale management,
formatting, runtime translation) into a GTRuntime base class exported
from the new `generaltranslation/runtime` entry point. The SDK runtime
(gt-i18n's I18nConfig, gt-next middleware) now constructs GTRuntime, so
production browser bundles no longer ship the project/file management
API client (enqueueFiles, uploads, downloads, etc.). The GT class
extends GTRuntime and keeps its full API for the CLI and other tooling.
Also import getLocaleProperties from @generaltranslation/format directly
in react-core so client bundles don't reach the full core entry.
- 42a440f: Gate duplicate singleton initialization warnings behind
`_GENERALTRANSLATION_LOG_LEVEL=DEBUG`.
- c5364f9: Slim the i18n cache event surface by replacing the generic
EventEmitter base class with a single cache-miss listener and removing
unused cache helper methods.
- 195f009: fix: make singleton not-initialized errors consistent and
descriptive, and stop error paths from masking the original failure when
I18nConfig is also uninitialized
- Updated dependencies [72e9e16]
- Updated dependencies [5adeede]
- Updated dependencies [2e85ebd]
  - generaltranslation@9.0.0-odysseus.5
  - @generaltranslation/supported-locales@2.1.2-odysseus.5
## locadex@1.0.186-odysseus.6

### Patch Changes

- gt@2.14.51-odysseus.6
## gt-next@11.0.0-odysseus.15

### Patch Changes

- 04f419d: Fix source interpolation for default-locale string helpers.
  Clarify that `tx()` does not apply ICU formatting by default.
- 98698de: Escape backslashes in middleware path regex input before
dynamic path matching.
- 72e9e16: Split the runtime surface of the GT class (locale management,
formatting, runtime translation) into a GTRuntime base class exported
from the new `generaltranslation/runtime` entry point. The SDK runtime
(gt-i18n's I18nConfig, gt-next middleware) now constructs GTRuntime, so
production browser bundles no longer ship the project/file management
API client (enqueueFiles, uploads, downloads, etc.). The GT class
extends GTRuntime and keeps its full API for the CLI and other tooling.
Also import getLocaleProperties from @generaltranslation/format directly
in react-core so client bundles don't reach the full core entry.
- 8d2e84e: Preserve enableI18n hydration state from server props and
request cookies.
- 195f009: fix: make singleton not-initialized errors consistent and
descriptive, and stop error paths from masking the original failure when
I18nConfig is also uninitialized
- Updated dependencies [04f419d]
- Updated dependencies [72e9e16]
- Updated dependencies [42a440f]
- Updated dependencies [8d2e84e]
- Updated dependencies [5adeede]
- Updated dependencies [c5364f9]
- Updated dependencies [2e85ebd]
- Updated dependencies [195f009]
  - @generaltranslation/react-core@11.0.0-odysseus.15
  - generaltranslation@9.0.0-odysseus.5
  - gt-i18n@1.0.0-odysseus.8
  - gt-react@11.0.0-odysseus.15
  - @generaltranslation/compiler@1.3.25-odysseus.7
  - @generaltranslation/supported-locales@2.1.2-odysseus.5
## @generaltranslation/gt-next-lint@15.0.0-odysseus.15

### Patch Changes

- Updated dependencies [04f419d]
- Updated dependencies [98698de]
- Updated dependencies [72e9e16]
- Updated dependencies [8d2e84e]
- Updated dependencies [195f009]
  - gt-next@11.0.0-odysseus.15
## gt-node@1.0.0-odysseus.8

### Patch Changes

- 195f009: fix: make singleton not-initialized errors consistent and
descriptive, and stop error paths from masking the original failure when
I18nConfig is also uninitialized
- Updated dependencies [72e9e16]
- Updated dependencies [42a440f]
- Updated dependencies [5adeede]
- Updated dependencies [c5364f9]
- Updated dependencies [2e85ebd]
- Updated dependencies [195f009]
  - generaltranslation@9.0.0-odysseus.5
  - gt-i18n@1.0.0-odysseus.8
## @generaltranslation/python-extractor@0.2.23-odysseus.5

### Patch Changes

- Updated dependencies [72e9e16]
- Updated dependencies [5adeede]
- Updated dependencies [2e85ebd]
  - generaltranslation@9.0.0-odysseus.5
## gt-react@11.0.0-odysseus.15

### Patch Changes

- 8d2e84e: Preserve enableI18n hydration state from server props and
request cookies.
- c5364f9: Slim the i18n cache event surface by replacing the generic
EventEmitter base class with a single cache-miss listener and removing
unused cache helper methods.
- 195f009: fix: make singleton not-initialized errors consistent and
descriptive, and stop error paths from masking the original failure when
I18nConfig is also uninitialized
- Updated dependencies [04f419d]
- Updated dependencies [72e9e16]
- Updated dependencies [42a440f]
- Updated dependencies [5adeede]
- Updated dependencies [c5364f9]
- Updated dependencies [2e85ebd]
- Updated dependencies [195f009]
  - @generaltranslation/react-core@11.0.0-odysseus.15
  - generaltranslation@9.0.0-odysseus.5
  - gt-i18n@1.0.0-odysseus.8
  - @generaltranslation/supported-locales@2.1.2-odysseus.5
## @generaltranslation/react-core@11.0.0-odysseus.15

### Patch Changes

- 04f419d: Fix source interpolation for default-locale string helpers.
  Clarify that `tx()` does not apply ICU formatting by default.
- 72e9e16: Split the runtime surface of the GT class (locale management,
formatting, runtime translation) into a GTRuntime base class exported
from the new `generaltranslation/runtime` entry point. The SDK runtime
(gt-i18n's I18nConfig, gt-next middleware) now constructs GTRuntime, so
production browser bundles no longer ship the project/file management
API client (enqueueFiles, uploads, downloads, etc.). The GT class
extends GTRuntime and keeps its full API for the CLI and other tooling.
Also import getLocaleProperties from @generaltranslation/format directly
in react-core so client bundles don't reach the full core entry.
- 195f009: fix: make singleton not-initialized errors consistent and
descriptive, and stop error paths from masking the original failure when
I18nConfig is also uninitialized
- Updated dependencies [72e9e16]
- Updated dependencies [42a440f]
- Updated dependencies [5adeede]
- Updated dependencies [c5364f9]
- Updated dependencies [2e85ebd]
- Updated dependencies [195f009]
  - generaltranslation@9.0.0-odysseus.5
  - gt-i18n@1.0.0-odysseus.8
  - @generaltranslation/supported-locales@2.1.2-odysseus.5
## gt-react-native@11.0.0-odysseus.15

### Patch Changes

- 57047ea: Rename the React Native `GTProvider` loading fallback prop to
`fallback`.
- Updated dependencies [04f419d]
- Updated dependencies [72e9e16]
- Updated dependencies [42a440f]
- Updated dependencies [5adeede]
- Updated dependencies [c5364f9]
- Updated dependencies [2e85ebd]
- Updated dependencies [195f009]
  - @generaltranslation/react-core@11.0.0-odysseus.15
  - generaltranslation@9.0.0-odysseus.5
  - gt-i18n@1.0.0-odysseus.8
  - @generaltranslation/supported-locales@2.1.2-odysseus.5
## gt-sanity@2.0.18-odysseus.7

### Patch Changes

- Updated dependencies [72e9e16]
- Updated dependencies [5adeede]
- Updated dependencies [2e85ebd]
  - generaltranslation@9.0.0-odysseus.5
## @generaltranslation/supported-locales@2.1.2-odysseus.5

### Patch Changes

- Updated dependencies [72e9e16]
- Updated dependencies [5adeede]
- Updated dependencies [2e85ebd]
  - generaltranslation@9.0.0-odysseus.5
## gt-tanstack-start@11.0.0-odysseus.15

### Patch Changes

- Updated dependencies [04f419d]
- Updated dependencies [72e9e16]
- Updated dependencies [42a440f]
- Updated dependencies [8d2e84e]
- Updated dependencies [5adeede]
- Updated dependencies [c5364f9]
- Updated dependencies [2e85ebd]
- Updated dependencies [195f009]
  - @generaltranslation/react-core@11.0.0-odysseus.15
  - generaltranslation@9.0.0-odysseus.5
  - gt-i18n@1.0.0-odysseus.8
  - gt-react@11.0.0-odysseus.15

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## TL;DR

Statically gates the dev hot-reload branch bodies behind
production-foldable `process.env.NODE_ENV !== 'production'` checks in
`@generaltranslation/react-core`.

This is a small production bundle win, not a full removal of all dev
hot-reload scaffolding. Shared hook/module structure can still remain
after this change; a deeper production-stub split is follow-up work.

## Code Changes

- Adds foldable production guards around tracked lookup hot-reload work
in React core.
- Keeps development behavior intact for missing-translation reporting
and dictionary update refreshes.
- Adds focused tests for the production no-op paths.

## Bundle Check

Measured against temp tarball installs in `~/code/bengubler.com`, using
Next's experimental analyzer and normal production builds.

Commands used:

```sh
pnpm install --force
pnpm --filter @generaltranslation/format --filter @generaltranslation/supported-locales --filter generaltranslation --filter gt-i18n --filter @generaltranslation/react-core build
pnpm --filter gt-react build
pnpm --filter gt-next build:no-swc-plugin
pnpm --filter @generaltranslation/react-core test
pnpm --filter gt-i18n test
pnpm --filter @generaltranslation/react-core typecheck
pnpm --filter gt-i18n typecheck
pnpm lint

# In temp copies of ~/code/bengubler.com with gt packages installed from local tarballs:
pnpm exec next experimental-analyze --output
NEXT_TELEMETRY_DISABLED=1 pnpm exec next build
```

Observed impact:

- Homepage client JS: -727 raw bytes / -340 analyzer-compressed bytes;
GT-attributed: -746 raw / -361 compressed.
- Emitted browser static JS: -731 raw bytes / -187 gzip bytes.
- Route analyzer aggregate across 23 route records: GT-attributed -26.0
KB raw / -11.6 KB compressed. This is route-attributed analyzer output,
not a single browser payload.

## Notes / Flags

This PR only makes the guarded branch bodies statically foldable. It
does not by itself eliminate every module or hook related to dev hot
reload from production bundles.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR statically gates all dev hot-reload code paths in
`@generaltranslation/react-core` and `gt-i18n` behind
`process.env.NODE_ENV !== 'production'`, allowing bundlers (webpack,
Rollup, esbuild) to dead-code-eliminate those branches in production
builds. The measured outcome is a ~730 raw-byte / ~190 gzip-byte
reduction in emitted browser JS.

- Eight `isDevHotReloadEnabled()` call sites across `getGT.ts`, `T.tsx`,
`T.rsc.tsx`, `external-store.ts`, the three tracked resolver hooks, and
`useDevHotReloadQueue` each gain a leading `process.env.NODE_ENV !==
'production' &&` guard, making the hot-reload branch bodies statically
foldable while leaving development behavior completely intact.
- Shared hook infrastructure (`useDevHotReloadQueue`,
`useSubscribeToTrackedLookups`, the `prev` ref in `T.tsx`) still runs
unconditionally in production because React hooks cannot be conditional;
the PR explicitly scopes further elimination to follow-up work.

<details open><summary><h3>Confidence Score: 4/5</h3></summary>

Safe to merge; the guard pattern is applied consistently across all
eight call sites and the production translation path is unaffected.

All changes are additive short-circuit guards that can only make
hot-reload work cheaper in production, not break it. Development mode
and the non-hot-reload production path are unchanged. The one gap is
that the PR description promises production no-op tests that do not
appear in the diff, so the DCE invariant is unverified by the test
suite.

`missing-translation.ts` — the `useDevHotReloadQueue` hook still runs
its full hook body in production; worth verifying with a test that
`isDevHotReloadEnabled()` is never reached there.
</details>


<details><summary><h3>Important Files Changed</h3></summary>




| Filename | Overview |
|----------|----------|
| packages/i18n/src/translation-functions/internal/getGT.ts | Adds
`process.env.NODE_ENV !== 'production' &&` before
`isDevHotReloadEnabled()`, preventing the dev preload/hot-reload path
and the `lookupTranslationWithFallback` fire-and-forget from running in
production. |
| packages/react-core/src/components/translation/T.rsc.tsx | Guards the
RSC hot-reload `lookupTranslationWithFallback` branch; production always
falls through to the standard `getLookupTranslation` path, which is
correct. |
| packages/react-core/src/components/translation/T.tsx | Adds the
NODE_ENV guard to the stale-translation early-return block; the `prev`
ref is still allocated and `prev.current = result` still runs
unconditionally in production, but those are acknowledged as follow-up
work. |
|
packages/react-core/src/hooks/external-store/useTrackedTranslationResolver.ts
| Guards added in both `useTrackedTranslationResolver` and the private
`usePreloadCompilerLookups`; `useSubscribeToTrackedLookups` still runs
unconditionally (acknowledged as follow-up), but the tracked key set
stays empty in production so subscriptions are effectively no-ops. |
| packages/react-core/src/hooks/utils/missing-translation.ts | The
`useDevHotReloadQueue` hook now short-circuits `isDevHotReloadEnabled()`
in production; the hook itself still runs (creates a Map, registers a
useEffect that early-returns) because hooks cannot be conditional — this
residual overhead is intentional follow-up scope. |

</details>


<details><summary><h3>Flowchart</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Translation lookup\n(useTranslate / useTracked*Resolver / getGT / RscT)"]
    A --> B{process.env.NODE_ENV\n!== 'production'?}
    B -- "false (PRODUCTION)\nbundler folds branch" --> C["Standard path:\ngetLookupTranslation / store snapshot"]
    B -- "true (DEV)" --> D{isDevHotReloadEnabled?}
    D -- "false" --> C
    D -- "true" --> E["Dev hot-reload path:\nlookupTranslationWithFallback /\ntrackedKeysRef tracking /\nonMissingTranslation enqueue"]
    E --> F["useDevHotReloadQueue useEffect\n(post-commit: i18nStore.translate)"]
    C --> G["Render result"]
    F --> G
```

</a>
<a href="#gh-dark-mode-only">

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["Translation lookup\n(useTranslate / useTracked*Resolver / getGT / RscT)"]
    A --> B{process.env.NODE_ENV\n!== 'production'?}
    B -- "false (PRODUCTION)\nbundler folds branch" --> C["Standard path:\ngetLookupTranslation / store snapshot"]
    B -- "true (DEV)" --> D{isDevHotReloadEnabled?}
    D -- "false" --> C
    D -- "true" --> E["Dev hot-reload path:\nlookupTranslationWithFallback /\ntrackedKeysRef tracking /\nonMissingTranslation enqueue"]
    E --> F["useDevHotReloadQueue useEffect\n(post-commit: i18nStore.translate)"]
    C --> G["Render result"]
    F --> G
```

</a>
</details>


<!-- greptile_failed_comments -->
<details open><summary><h3>Comments Outside Diff (1)</h3></summary>

1. `packages/react-core/src/hooks/utils/missing-translation.ts`, line
101-139
([link](https://github.com/generaltranslation/gt/blob/ecb085a6e975e71447ee6b769aceb730cce99243/packages/react-core/src/hooks/utils/missing-translation.ts#L101-L139))

<a href="#"><img alt="P2"
src="https://greptile-static-assets.s3.amazonaws.com/badges/p2.svg?v=9"
align="top"></a> **PR description claims tests were added — no test
files in the diff**

The description says "Adds focused tests for the production no-op
paths," but no test files appear in the changeset (9 files changed, all
source). The existing suites in `src/hooks/__tests__/utils.test.ts` and
`src/hooks/__tests__/useGT.test.ts` don't cover the
`process.env.NODE_ENV === 'production'` short-circuit. Without a test
asserting that `isDevHotReloadEnabled()` is never reached and the
`useEffect` body is skipped when `NODE_ENV` is `'production'`, a future
refactor could accidentally reintroduce the call and the DCE win would
silently regress.

   <details><summary>Prompt To Fix With AI</summary>

   `````markdown
   This is a comment left during a code review.
   Path: packages/react-core/src/hooks/utils/missing-translation.ts
   Line: 101-139

   Comment:
**PR description claims tests were added — no test files in the diff**

The description says "Adds focused tests for the production no-op
paths," but no test files appear in the changeset (9 files changed, all
source). The existing suites in `src/hooks/__tests__/utils.test.ts` and
`src/hooks/__tests__/useGT.test.ts` don't cover the
`process.env.NODE_ENV === 'production'` short-circuit. Without a test
asserting that `isDevHotReloadEnabled()` is never reached and the
`useEffect` body is skipped when `NODE_ENV` is `'production'`, a future
refactor could accidentally reintroduce the call and the DCE win would
silently regress.

   How can I resolve this? If you propose a fix, please make it concise.
   `````
   </details>

<a
href="https://app.greptile.com/ide/claude-code?prompt=This%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20packages%2Freact-core%2Fsrc%2Fhooks%2Futils%2Fmissing-translation.ts%0ALine%3A%20101-139%0A%0AComment%3A%0A**PR%20description%20claims%20tests%20were%20added%20%E2%80%94%20no%20test%20files%20in%20the%20diff**%0A%0AThe%20description%20says%20%22Adds%20focused%20tests%20for%20the%20production%20no-op%20paths%2C%22%20but%20no%20test%20files%20appear%20in%20the%20changeset%20%289%20files%20changed%2C%20all%20source%29.%20The%20existing%20suites%20in%20%60src%2Fhooks%2F__tests__%2Futils.test.ts%60%20and%20%60src%2Fhooks%2F__tests__%2FuseGT.test.ts%60%20don't%20cover%20the%20%60process.env.NODE_ENV%20%3D%3D%3D%20'production'%60%20short-circuit.%20Without%20a%20test%20asserting%20that%20%60isDevHotReloadEnabled%28%29%60%20is%20never%20reached%20and%20the%20%60useEffect%60%20body%20is%20skipped%20when%20%60NODE_ENV%60%20is%20%60'production'%60%2C%20a%20future%20refactor%20could%20accidentally%20reintroduce%20the%20call%20and%20the%20DCE%20win%20would%20silently%20regress.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=generaltranslation%2Fgt&pr=1811&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaudeDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=6"><img
alt="Fix in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=6"></picture></a>
<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22generaltranslation%2Fgt%22%20on%20the%20existing%20branch%20%22e%2Fodysseus%2Fdev-hot-reload-dce%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22e%2Fodysseus%2Fdev-hot-reload-dce%22.%0A%0AThis%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20packages%2Freact-core%2Fsrc%2Fhooks%2Futils%2Fmissing-translation.ts%0ALine%3A%20101-139%0A%0AComment%3A%0A**PR%20description%20claims%20tests%20were%20added%20%E2%80%94%20no%20test%20files%20in%20the%20diff**%0A%0AThe%20description%20says%20%22Adds%20focused%20tests%20for%20the%20production%20no-op%20paths%2C%22%20but%20no%20test%20files%20appear%20in%20the%20changeset%20%289%20files%20changed%2C%20all%20source%29.%20The%20existing%20suites%20in%20%60src%2Fhooks%2F__tests__%2Futils.test.ts%60%20and%20%60src%2Fhooks%2F__tests__%2FuseGT.test.ts%60%20don't%20cover%20the%20%60process.env.NODE_ENV%20%3D%3D%3D%20'production'%60%20short-circuit.%20Without%20a%20test%20asserting%20that%20%60isDevHotReloadEnabled%28%29%60%20is%20never%20reached%20and%20the%20%60useEffect%60%20body%20is%20skipped%20when%20%60NODE_ENV%60%20is%20%60'production'%60%2C%20a%20future%20refactor%20could%20accidentally%20reintroduce%20the%20call%20and%20the%20DCE%20win%20would%20silently%20regress.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=generaltranslation%2Fgt&pr=1811&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodexDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"><img
alt="Fix in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"></picture></a>

</details>

<!-- /greptile_failed_comments -->

<a
href="https://app.greptile.com/ide/claude-code?prompt=Fix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Apackages%2Freact-core%2Fsrc%2Fhooks%2Futils%2Fmissing-translation.ts%3A101-139%0A**PR%20description%20claims%20tests%20were%20added%20%E2%80%94%20no%20test%20files%20in%20the%20diff**%0A%0AThe%20description%20says%20%22Adds%20focused%20tests%20for%20the%20production%20no-op%20paths%2C%22%20but%20no%20test%20files%20appear%20in%20the%20changeset%20%289%20files%20changed%2C%20all%20source%29.%20The%20existing%20suites%20in%20%60src%2Fhooks%2F__tests__%2Futils.test.ts%60%20and%20%60src%2Fhooks%2F__tests__%2FuseGT.test.ts%60%20don't%20cover%20the%20%60process.env.NODE_ENV%20%3D%3D%3D%20'production'%60%20short-circuit.%20Without%20a%20test%20asserting%20that%20%60isDevHotReloadEnabled%28%29%60%20is%20never%20reached%20and%20the%20%60useEffect%60%20body%20is%20skipped%20when%20%60NODE_ENV%60%20is%20%60'production'%60%2C%20a%20future%20refactor%20could%20accidentally%20reintroduce%20the%20call%20and%20the%20DCE%20win%20would%20silently%20regress.%0A%0A&repo=generaltranslation%2Fgt&pr=1811&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaudeDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=6"><img
alt="Fix All in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=6"></picture></a>
<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22generaltranslation%2Fgt%22%20on%20the%20existing%20branch%20%22e%2Fodysseus%2Fdev-hot-reload-dce%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22e%2Fodysseus%2Fdev-hot-reload-dce%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Apackages%2Freact-core%2Fsrc%2Fhooks%2Futils%2Fmissing-translation.ts%3A101-139%0A**PR%20description%20claims%20tests%20were%20added%20%E2%80%94%20no%20test%20files%20in%20the%20diff**%0A%0AThe%20description%20says%20%22Adds%20focused%20tests%20for%20the%20production%20no-op%20paths%2C%22%20but%20no%20test%20files%20appear%20in%20the%20changeset%20%289%20files%20changed%2C%20all%20source%29.%20The%20existing%20suites%20in%20%60src%2Fhooks%2F__tests__%2Futils.test.ts%60%20and%20%60src%2Fhooks%2F__tests__%2FuseGT.test.ts%60%20don't%20cover%20the%20%60process.env.NODE_ENV%20%3D%3D%3D%20'production'%60%20short-circuit.%20Without%20a%20test%20asserting%20that%20%60isDevHotReloadEnabled%28%29%60%20is%20never%20reached%20and%20the%20%60useEffect%60%20body%20is%20skipped%20when%20%60NODE_ENV%60%20is%20%60'production'%60%2C%20a%20future%20refactor%20could%20accidentally%20reintroduce%20the%20call%20and%20the%20DCE%20win%20would%20silently%20regress.%0A%0A&repo=generaltranslation%2Fgt&pr=1811&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img
alt="Fix All in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a>

<details><summary>Prompt To Fix All With AI</summary>

`````markdown
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
packages/react-core/src/hooks/utils/missing-translation.ts:101-139
**PR description claims tests were added — no test files in the diff**

The description says "Adds focused tests for the production no-op paths," but no test files appear in the changeset (9 files changed, all source). The existing suites in `src/hooks/__tests__/utils.test.ts` and `src/hooks/__tests__/useGT.test.ts` don't cover the `process.env.NODE_ENV === 'production'` short-circuit. Without a test asserting that `isDevHotReloadEnabled()` is never reached and the `useEffect` body is skipped when `NODE_ENV` is `'production'`, a future refactor could accidentally reintroduce the call and the DCE win would silently regress.


`````

</details>

<sub>Reviews (2): Last reviewed commit: ["perf(react-core): make dev
hot-reload
pa..."](ecb085a)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=41721632)</sub>

<!-- /greptile_comment -->

Co-authored-by: Ernest McCarter <ernest@generaltranslation.com>
## TL;DR

Follow-up to #1811. This moves the remaining dev hot-reload hook
implementations behind module-level production stubs so production
bundlers can drop more dev-only hot-reload code.

## Code Changes

- Exports a production no-op implementation of
`useSubscribeToTrackedLookups`, while preserving the existing dev
subscription implementation.
- Exports production no-op missing-translation handlers, while
preserving the existing dev queue implementation.
- Adds focused tests that production does not subscribe and development
still filters tracked lookup events.
- Adds a changeset for `@generaltranslation/react-core`.

## Bundle Check

Measured against temp tarball installs in `~/code/bengubler.com`,
comparing this branch against #1811's rebased branch.

Commands used:

```sh
pnpm --filter @generaltranslation/react-core test
pnpm --filter @generaltranslation/react-core typecheck
pnpm lint

# In temp copies of ~/code/bengubler.com with gt packages installed from local tarballs:
pnpm install --force --dir /tmp/gt-pr-1771-followup-measure/baseline-app
pnpm install --force --dir /tmp/gt-pr-1771-followup-measure/experiment-app
pnpm exec next experimental-analyze --output
NEXT_TELEMETRY_DISABLED=1 pnpm exec next build
```

Observed impact vs #1811:

- Homepage analyzer client JS: -701 raw bytes / -272 analyzer-compressed
bytes; GT-attributed: -698 raw / -274 compressed.
- Emitted browser static JS: -699 raw bytes / -104 gzip bytes.
- Route analyzer aggregate across 23 route records: GT-attributed -20.0
KB raw / -7.8 KB compressed. This is route-attributed analyzer output,
not a single browser payload.

## Notes / Flags

This intentionally keeps dev behavior in the dev implementation, but
makes the production export a no-op at module scope so bundlers have a
cleaner DCE target.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR follows up on #1811 by applying the production-stub/DCE pattern
to `useSubscribeToTrackedLookups` and the three `useHandleMissing*`
hooks in `missing-translation.ts`. Each dev implementation is renamed
with a `Dev` suffix, a module-level production no-op is assigned for the
`Prod` variant, and the export is a module-level conditional so bundlers
can dead-code-eliminate the dev branch.

- `useSubscribeToTrackedLookups.ts`: production export is now `() =>
{}`, preventing `useSyncExternalStore` and event subscription overhead
in production builds; dev path is unchanged.
- `missing-translation.ts`: all three handler hooks return stable
module-level no-op functions in production, preserving the dev
hot-reload queue only for development; call sites in `external-store.ts`
and `useTrackedTranslationResolver.ts` are already guarded by
`process.env.NODE_ENV !== 'production'` checks before invoking these
handlers, so no behavioral change occurs.
- New test file verifies the production no-op and dev event-filtering
behaviors for `useSubscribeToTrackedLookups`.

<details open><summary><h3>Confidence Score: 5/5</h3></summary>

Safe to merge; all call sites already guard with process.env.NODE_ENV
!== 'production' before invoking these handlers, so the production
no-ops introduce no behavioral change.

The module-level conditional assignments are a well-understood bundler
DCE pattern, and cross-checking the call sites in external-store.ts and
useTrackedTranslationResolver.ts confirms the production no-ops are
never reached by paths that would have exercised the dev queue or custom
handler. The new tests cover the production and dev branches of
useSubscribeToTrackedLookups correctly. The only gap is parallel test
coverage for the missing-translation.ts stubs.

missing-translation.ts would benefit from tests mirroring those added
for useSubscribeToTrackedLookups.
</details>

<details><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
|
packages/react-core/src/hooks/external-store/useSubscribeToTrackedLookups.ts
| Renames dev implementation to useSubscribeToTrackedLookupsDev, adds a
module-level production no-op, and exports the appropriate variant based
on process.env.NODE_ENV for DCE. |
| packages/react-core/src/hooks/utils/missing-translation.ts | Applies
the same production-stub pattern to all three missing-translation
handler hooks; production variants return stable module-level no-ops,
dev variants retain full hook logic. |
|
packages/react-core/src/hooks/external-store/__tests__/useSubscribeToTrackedLookups.test.ts
| New test file verifying production no-op (no subscriptions, no
useSyncExternalStore) and dev filtering (matching key triggers listener,
non-matching does not). |
| .changeset/dev-hot-reload-production-stubs.md | Patch-level changeset
entry for @generaltranslation/react-core. |

</details>

<details><summary><h3>Flowchart</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Module Evaluation] --> B{NODE_ENV === production?}
    B -- yes --> C[Prod no-op variants\nAll four hooks return stable empty functions]
    B -- no --> D[Dev variants\nuseSubscribeToTrackedLookupsDev\nuseHandleMissingTranslationDev\nuseHandleMissingDictionaryEntryDev\nuseHandleMissingDictionaryObjectDev]
    C --> E[Bundler DCE eliminates\nDev variants and all\ndev-only dependencies]
    D --> F[useDevHotReloadQueue\nuseGTContext\nuseSyncExternalStore\nuseEffect]
```

</a>
<a href="#gh-dark-mode-only">

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[Module Evaluation] --> B{NODE_ENV === production?}
    B -- yes --> C[Prod no-op variants\nAll four hooks return stable empty functions]
    B -- no --> D[Dev variants\nuseSubscribeToTrackedLookupsDev\nuseHandleMissingTranslationDev\nuseHandleMissingDictionaryEntryDev\nuseHandleMissingDictionaryObjectDev]
    C --> E[Bundler DCE eliminates\nDev variants and all\ndev-only dependencies]
    D --> F[useDevHotReloadQueue\nuseGTContext\nuseSyncExternalStore\nuseEffect]
```

</a>
</details>

<a
href="https://app.greptile.com/ide/claude-code?prompt=Fix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Apackages%2Freact-core%2Fsrc%2Fhooks%2Futils%2Fmissing-translation.ts%3A114-127%0A**No%20tests%20for%20the%20%60missing-translation.ts%60%20production%20stubs**%0A%0AThe%20PR%20adds%20a%20focused%20test%20suite%20for%20%60useSubscribeToTrackedLookups%60%20covering%20both%20the%20production%20no-op%20and%20development%20filtering%20paths%2C%20but%20the%20identical%20%22production%20returns%20stable%20noop%2C%20dev%20calls%20hooks%22%20pattern%20introduced%20for%20%60useHandleMissingTranslation%60%2C%20%60useHandleMissingDictionaryEntry%60%2C%20and%20%60useHandleMissingDictionaryObject%60%20has%20no%20corresponding%20tests.%20Since%20%60vi.resetModules%28%29%60%20%2B%20dynamic%20import%20is%20already%20the%20established%20pattern%20in%20the%20new%20test%20file%2C%20adding%20a%20parallel%20set%20of%20tests%20for%20these%20three%20exports%20would%20complete%20the%20coverage%20story.%0A%0A&repo=generaltranslation%2Fgt&pr=1812&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaudeDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=6"><img
alt="Fix All in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=6"></picture></a>
<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22generaltranslation%2Fgt%22%20on%20the%20existing%20branch%20%22bg%2Fdev-hot-reload-dce-followup%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22bg%2Fdev-hot-reload-dce-followup%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Apackages%2Freact-core%2Fsrc%2Fhooks%2Futils%2Fmissing-translation.ts%3A114-127%0A**No%20tests%20for%20the%20%60missing-translation.ts%60%20production%20stubs**%0A%0AThe%20PR%20adds%20a%20focused%20test%20suite%20for%20%60useSubscribeToTrackedLookups%60%20covering%20both%20the%20production%20no-op%20and%20development%20filtering%20paths%2C%20but%20the%20identical%20%22production%20returns%20stable%20noop%2C%20dev%20calls%20hooks%22%20pattern%20introduced%20for%20%60useHandleMissingTranslation%60%2C%20%60useHandleMissingDictionaryEntry%60%2C%20and%20%60useHandleMissingDictionaryObject%60%20has%20no%20corresponding%20tests.%20Since%20%60vi.resetModules%28%29%60%20%2B%20dynamic%20import%20is%20already%20the%20established%20pattern%20in%20the%20new%20test%20file%2C%20adding%20a%20parallel%20set%20of%20tests%20for%20these%20three%20exports%20would%20complete%20the%20coverage%20story.%0A%0A&repo=generaltranslation%2Fgt&pr=1812&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img
alt="Fix All in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a>

<details><summary>Prompt To Fix All With AI</summary>

`````markdown
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
packages/react-core/src/hooks/utils/missing-translation.ts:114-127
**No tests for the `missing-translation.ts` production stubs**

The PR adds a focused test suite for `useSubscribeToTrackedLookups` covering both the production no-op and development filtering paths, but the identical "production returns stable noop, dev calls hooks" pattern introduced for `useHandleMissingTranslation`, `useHandleMissingDictionaryEntry`, and `useHandleMissingDictionaryObject` has no corresponding tests. Since `vi.resetModules()` + dynamic import is already the established pattern in the new test file, adding a parallel set of tests for these three exports would complete the coverage story.

`````

</details>

<sub>Reviews (2): Last reviewed commit: ["perf(react-core): stub dev
hot-reload
ho..."](5337577)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=41721676)</sub>

> Greptile also left **1 inline comment** on this PR.

<!-- /greptile_comment -->

---------

Co-authored-by: Ernest McCarter <ernest@generaltranslation.com>
)

## TL;DR

Clean up the @generaltranslation/react-core public API surface for the
next major by removing dead helpers and internal plumbing from public
entrypoints.

## Code Changes

- Removed the dead react-core dictionary utility exports, modules, and
tests.
- Stopped exporting JSX serialization internals from
@generaltranslation/react-core/pure while keeping the internals
available to react-core modules.
- Removed the requested singleton/plumbing exports and
useShouldTranslate from public react-core entrypoints.
- Kept only internalInitializeGTSRA in react-core /pure and aliases it
locally as initializeGT in gt-react RSC.
- Repointed gt-next type consumers of removed react-core legacy types to
local equivalents.

## Notes / Flags

- Downstream grep found gt-next consumers of RenderMethod, CustomLoader,
and _Messages from @generaltranslation/react-core/pure; those were
repointed locally instead of keeping the react-core exports.
- components-rsc still exports getPluralBranch, but now sources it
directly from the module file instead of ./pure.
- Sibling PRs touch packages/react/src/index.rsc.ts and react-core
hooks.ts/pure.ts; trivial merge conflicts are expected.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

Cleans up the `@generaltranslation/react-core` public API surface by
deleting dead dictionary utilities (source files, tests, and exports),
removing JSX serialization internals and singleton-plumbing exports from
`/pure`, and dropping `useShouldTranslate` from the hooks entrypoint.
Downstream consumers in `gt-next` and `gt-react` are updated to local
type equivalents or direct module aliases.

- **`react-core/pure.ts`**: Removes ~17 exports (dictionary helpers,
`initializeGT` alias, `setI18nConfig`, `setReadonlyConditionStore`,
`WritableConditionStore`, `DictionaryLookup`, `TranslateLookup`, and
several types); retains only the minimal surface needed by sibling
packages.
- **`gt-react`**: Re-aliases `internalInitializeGTSRA as initializeGT`
in its own RSC entrypoint so the public API is unchanged for consumers.
- **`gt-next`**: Replaces the now-removed `_Messages`, `RenderMethod`,
and `CustomLoader` imports from `react-core/pure` with structurally
identical local type definitions.

<details open><summary><h3>Confidence Score: 4/5</h3></summary>

The code changes themselves are safe — all internal callers were
verified and the migrated types are structurally identical to the
removed originals. The only concern is the changeset version type, which
is a process issue rather than a runtime one.

All type migrations check out, no internal react-core module still
imports from the deleted dictionary source files, and the `initializeGT`
alias is correctly re-created in gt-react. The single flag is the
changeset marking multiple public API removals as `patch`; depending on
the team's pre-release exit strategy this could produce an incorrect
final version bump.

`.changeset/clean-react-core-api-surface.md` — the version bump type
warrants a second look before the pre-release is finalized.
</details>

<details><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| .changeset/clean-react-core-api-surface.md | Changeset marks breaking
public API removals as `patch` rather than `major`, which will produce
an incorrect semver bump when the pre-release is finalized. |
| packages/react-core/src/pure.ts | Strips dead dictionary helpers, JSX
serialization internals, singleton plumbing, and the `initializeGT`
alias from the public entrypoint; remaining exports are clean and
internally consistent. |
| packages/react-core/src/hooks.ts | Removes `useShouldTranslate` from
the public hooks entrypoint; the hook still exists internally and is
used by `useGT`, `useTranslations`, etc. via direct module imports. |
| packages/react-core/src/components-rsc.ts | Re-sources
`getPluralBranch` directly from its module and
`RelativeTimeFormatOptions`/`RenderVariable` directly from
`./utils/types` instead of re-exporting through `./pure`; no functional
change. |
| packages/react/src/index.rsc.ts | Aliases `internalInitializeGTSRA` as
`initializeGT` locally, preserving the public `gt-react` API after the
`initializeGT` alias was removed from `react-core/pure`. |
| packages/next/src/index.types.ts | Replaces the removed `_Messages`
import with a locally-defined `Message`/`Messages` pair that is
structurally identical; no public API change for `gt-next` consumers. |
| packages/next/src/config-dir/props/withGTConfigProps.ts | Adds a local
`RenderMethod` type (`'skeleton' | 'replace' | 'default'`) that is
structurally identical to the removed `react-core/pure` export. |
| packages/next/src/resolvers/resolveDictionaryLoader.ts | Replaces the
`CustomLoader` import from `react-core/pure` with a local type
definition; the same type is now duplicated in
`resolveTranslationLoader.ts`. |
| packages/next/src/resolvers/resolveTranslationLoader.ts | Same
`CustomLoader` type inlined here as in `resolveDictionaryLoader.ts`;
minor duplication introduced by removing the shared react-core export. |

</details>

<details><summary><h3>Flowchart</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["@generaltranslation/react-core/pure\n(new, trimmed surface)"] -->|"internalInitializeGTSRA"| B["gt-react/index.rsc.ts\nalias → initializeGT ✅"]
    A -->|"getI18nConfig, initializeI18nConfig"| C["gt-next/setup/initGT.ts"]
    A -->|"getReadonlyConditionStore"| D["gt-next internal"]

    E["react-core/hooks.ts\n(removed useShouldTranslate)"] -->|"still used internally"| F["hooks/useGT.ts\nhooks/useTranslations.ts\n(direct module imports)"]

    G["Deleted dictionary files\n(getDictionaryEntry, flattenDictionary, etc.)"] -->|"replaced by"| H["gt-i18n/internal\ngetDictionaryEntry, isDictionaryValue"]

    I["gt-next local types"] -->|"RenderMethod"| J["withGTConfigProps.ts"]
    I -->|"CustomLoader ⚠️ duplicated"| K["resolveDictionaryLoader.ts\nresolveTranslationLoader.ts"]
    I -->|"Message / Messages"| L["index.types.ts"]
```

</a>
<a href="#gh-dark-mode-only">

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["@generaltranslation/react-core/pure\n(new, trimmed surface)"] -->|"internalInitializeGTSRA"| B["gt-react/index.rsc.ts\nalias → initializeGT ✅"]
    A -->|"getI18nConfig, initializeI18nConfig"| C["gt-next/setup/initGT.ts"]
    A -->|"getReadonlyConditionStore"| D["gt-next internal"]

    E["react-core/hooks.ts\n(removed useShouldTranslate)"] -->|"still used internally"| F["hooks/useGT.ts\nhooks/useTranslations.ts\n(direct module imports)"]

    G["Deleted dictionary files\n(getDictionaryEntry, flattenDictionary, etc.)"] -->|"replaced by"| H["gt-i18n/internal\ngetDictionaryEntry, isDictionaryValue"]

    I["gt-next local types"] -->|"RenderMethod"| J["withGTConfigProps.ts"]
    I -->|"CustomLoader ⚠️ duplicated"| K["resolveDictionaryLoader.ts\nresolveTranslationLoader.ts"]
    I -->|"Message / Messages"| L["index.types.ts"]
```

</a>
</details>

<a
href="https://app.greptile.com/ide/claude-code?prompt=Fix%20the%20following%202%20code%20review%20issues.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%202%0A.changeset%2Fclean-react-core-api-surface.md%3A1-11%0A**Breaking%20change%20marked%20as%20patch**%0A%0AThe%20changeset%20marks%20%60%40generaltranslation%2Freact-core%60%20as%20%60patch%60%2C%20but%20this%20PR%20removes%20multiple%20items%20from%20the%20public%20API%3A%20%60useShouldTranslate%60%2C%20the%20%60initializeGT%60%20alias%2C%20%60setI18nConfig%60%2C%20%60setReadonlyConditionStore%60%2C%20%60WritableConditionStore%60%2C%20%60getI18nStore%60%2C%20%60isI18nStoreInitialized%60%2C%20%60DictionaryLookup%60%2C%20%60TranslateLookup%60%2C%20and%20several%20dictionary%20helper%20exports%20and%20types.%20In%20Changesets%20pre-release%20mode%20the%20individual%20bump%20type%20still%20feeds%20into%20the%20final%20version%20calculation%20when%20exiting%20pre-release%3B%20a%20%60patch%60-only%20changeset%20would%20result%20in%20a%20patch-level%20bump%20rather%20than%20the%20major%20bump%20these%20removals%20require.%0A%0A%23%23%23%20Issue%202%20of%202%0Apackages%2Fnext%2Fsrc%2Fresolvers%2FresolveDictionaryLoader.ts%3A1-3%0AThe%20same%20%60CustomLoader%60%20type%20is%20now%20defined%20independently%20in%20both%20resolver%20files.%20Consider%20extracting%20it%20to%20a%20shared%20location%20%28e.g.%2C%20a%20%60types.ts%60%20in%20the%20resolvers%20directory%29%20to%20prevent%20the%20two%20definitions%20drifting%20apart.%0A%0A%60%60%60suggestion%0Aimport%20%7B%20unresolvedCustomLoadDictionaryError%20%7D%20from%20'..%2Ferrors%2FcreateErrors'%3B%0Aimport%20type%20%7B%20CustomLoader%20%7D%20from%20'.%2Ftypes'%3B%0A%60%60%60%0A%0A&repo=generaltranslation%2Fgt&pr=1815&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaudeDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=6"><img
alt="Fix All in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=6"></picture></a>
<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22generaltranslation%2Fgt%22%20on%20the%20existing%20branch%20%22bg%2Freact-core-api-cleanup%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22bg%2Freact-core-api-cleanup%22.%0A%0AFix%20the%20following%202%20code%20review%20issues.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%202%0A.changeset%2Fclean-react-core-api-surface.md%3A1-11%0A**Breaking%20change%20marked%20as%20patch**%0A%0AThe%20changeset%20marks%20%60%40generaltranslation%2Freact-core%60%20as%20%60patch%60%2C%20but%20this%20PR%20removes%20multiple%20items%20from%20the%20public%20API%3A%20%60useShouldTranslate%60%2C%20the%20%60initializeGT%60%20alias%2C%20%60setI18nConfig%60%2C%20%60setReadonlyConditionStore%60%2C%20%60WritableConditionStore%60%2C%20%60getI18nStore%60%2C%20%60isI18nStoreInitialized%60%2C%20%60DictionaryLookup%60%2C%20%60TranslateLookup%60%2C%20and%20several%20dictionary%20helper%20exports%20and%20types.%20In%20Changesets%20pre-release%20mode%20the%20individual%20bump%20type%20still%20feeds%20into%20the%20final%20version%20calculation%20when%20exiting%20pre-release%3B%20a%20%60patch%60-only%20changeset%20would%20result%20in%20a%20patch-level%20bump%20rather%20than%20the%20major%20bump%20these%20removals%20require.%0A%0A%23%23%23%20Issue%202%20of%202%0Apackages%2Fnext%2Fsrc%2Fresolvers%2FresolveDictionaryLoader.ts%3A1-3%0AThe%20same%20%60CustomLoader%60%20type%20is%20now%20defined%20independently%20in%20both%20resolver%20files.%20Consider%20extracting%20it%20to%20a%20shared%20location%20%28e.g.%2C%20a%20%60types.ts%60%20in%20the%20resolvers%20directory%29%20to%20prevent%20the%20two%20definitions%20drifting%20apart.%0A%0A%60%60%60suggestion%0Aimport%20%7B%20unresolvedCustomLoadDictionaryError%20%7D%20from%20'..%2Ferrors%2FcreateErrors'%3B%0Aimport%20type%20%7B%20CustomLoader%20%7D%20from%20'.%2Ftypes'%3B%0A%60%60%60%0A%0A&repo=generaltranslation%2Fgt&pr=1815&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img
alt="Fix All in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a>

<details><summary>Prompt To Fix All With AI</summary>

`````markdown
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
.changeset/clean-react-core-api-surface.md:1-11
**Breaking change marked as patch**

The changeset marks `@generaltranslation/react-core` as `patch`, but this PR removes multiple items from the public API: `useShouldTranslate`, the `initializeGT` alias, `setI18nConfig`, `setReadonlyConditionStore`, `WritableConditionStore`, `getI18nStore`, `isI18nStoreInitialized`, `DictionaryLookup`, `TranslateLookup`, and several dictionary helper exports and types. In Changesets pre-release mode the individual bump type still feeds into the final version calculation when exiting pre-release; a `patch`-only changeset would result in a patch-level bump rather than the major bump these removals require.

### Issue 2 of 2
packages/next/src/resolvers/resolveDictionaryLoader.ts:1-3
The same `CustomLoader` type is now defined independently in both resolver files. Consider extracting it to a shared location (e.g., a `types.ts` in the resolvers directory) to prevent the two definitions drifting apart.

```suggestion
import { unresolvedCustomLoadDictionaryError } from
'../errors/createErrors';
import type { CustomLoader } from './types';
```

`````

</details>

<sub>Reviews (1): Last reviewed commit: ["feat!: clean up react-core
public
api"](44747a9)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=41726635)</sub>

> Greptile also left **2 inline comments** on this PR.

<!-- /greptile_comment -->
## TL;DR

Prune dead render internals from the `gt-react` react-server entry and
align its type exports with the other `gt-react` entries.

## Code Changes

- Removed RSC-only render helper/internal component exports from
`packages/react/src/index.rsc.ts`.
- Kept compiler-injected internals available: `GtInternalTranslateJsx`,
`GtInternalVar`, and runtime translate exports.
- Added `RenderPipeline` and `RenderPreparedT` type exports to the
react-server entry.
- Updated the RSC surface test and added a `gt-react` changeset.

## Notes / Flags

Sibling PRs touch other parts of `index.rsc.ts` (react-core cleanup,
version-id removal); trivial merge conflicts expected.

Verification: `pnpm --filter gt-react... build`, `pnpm --filter gt-react
test`, `pnpm lint:fix`, `pnpm format:fix`.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR prunes the `gt-react` react-server (`index.rsc.ts`) entry by
removing RSC-only render internals that are no longer needed there,
keeping only the compiler-injected translation exports
(`GtInternalTranslateJsx`, `GtInternalVar`) and aligning the type
surface with the other `gt-react` entries by adding `RenderPipeline` and
`RenderPreparedT` type exports.

<details open><summary><h3>Confidence Score: 4/5</h3></summary>

The code changes in `index.rsc.ts` are clean and internally consistent,
but the changeset classifies a removal of public exports as `patch`,
which could mislead consumers relying on semver.

The implementation itself is straightforward — symbols are removed and
the remaining surface is coherent. The only meaningful concern is that
multiple non-`GtInternal`-prefixed exports are dropped while the
changeset says `patch`. If any downstream consumer imports those symbols
they will get a broken import without any semver signal.

`.changeset/prune-react-rsc-entry.md` — the version bump type should be
reviewed before merging.
</details>

<details><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| .changeset/prune-react-rsc-entry.md | Describes the surface pruning
correctly, but classifies as `patch` while the diff removes multiple
public (non-`GtInternal`) exports — a breaking change that should be
`major`. |
| packages/react/src/index.rsc.ts | Removes dead RSC-only render
internals and aligns type exports with other entries; `T as
GtInternalTranslateJsx` alias is correctly sourced from `components-rsc`
and the remaining exports look consistent. |
| packages/react/src/__tests__/context-rsc.test.ts | Correctly flips
removed exports to negative assertions and adds `GtInternalTranslateJsx`
check; missing positive assertions for several retained exports
(`createRenderPipeline`, `t`, etc.). |

</details>

<a
href="https://app.greptile.com/ide/claude-code?prompt=Fix%20the%20following%202%20code%20review%20issues.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%202%0A.changeset%2Fprune-react-rsc-entry.md%3A2%0A**Changeset%20type%20conflicts%20with%20breaking-change%20indicator%20in%20the%20PR%20title**%0A%0AThe%20changeset%20marks%20this%20as%20%60patch%60%2C%20but%20the%20PR%20title%20carries%20the%20%60feat!%60%20suffix%20%28conventional-commits%20notation%20for%20a%20breaking%20change%29%20and%20the%20diff%20removes%20several%20previously%20public%2C%20non-%60GtInternal%60-prefixed%20exports%20from%20the%20RSC%20entry%3A%20%60renderVariable%60%2C%20%60createRenderVariable%60%2C%20%60renderDefaultChildren%60%2C%20%60renderPreparedT%60%2C%20%60renderTranslatedChildren%60%2C%20%60getPluralBranch%60%2C%20%60getShouldTranslate%60%2C%20%60prepareT%60%2C%20and%20%60getReadonlyConditionStore%60.%20Any%20consumer%20importing%20those%20symbols%20from%20the%20react-server%20entry%20will%20receive%20an%20unresolved-export%20error%20after%20upgrading.%20In%20changesets%20terminology%20this%20is%20a%20%60major%60%20bump%20%28or%20at%20minimum%20%60minor%60%20if%20the%20team%20considers%20the%20RSC%20surface%20fully%20internal%29%3B%20shipping%20it%20as%20%60patch%60%20risks%20silent%20breakage%20for%20downstream%20consumers%20who%20rely%20on%20semver.%0A%0A%23%23%23%20Issue%202%20of%202%0Apackages%2Freact%2Fsrc%2F__tests__%2Fcontext-rsc.test.ts%3A17-25%0A**Retained%20value%20exports%20not%20covered%20by%20the%20surface%20test**%0A%0AAfter%20this%20change%20%60createRenderPipeline%60%2C%20%60t%60%2C%20%60getTranslationsSnapshot%60%2C%20%60getReactI18nCache%60%2C%20and%20%60setReactI18nCache%60%20are%20still%20exported%20from%20the%20RSC%20entry%2C%20but%20the%20test%20does%20not%20assert%20their%20presence.%20Because%20the%20test%20is%20the%20canonical%20surface%20contract%20for%20this%20entry%2C%20a%20future%20refactor%20that%20accidentally%20drops%20one%20of%20these%20would%20go%20undetected.%20Adding%20positive%20%60toBeTypeOf%28'function'%29%60%20checks%20for%20the%20remaining%20exports%20that%20are%20meant%20to%20stay%20would%20make%20the%20test%20more%20complete.%0A%0A&repo=generaltranslation%2Fgt&pr=1817&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaudeDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=6"><img
alt="Fix All in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=6"></picture></a>
<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22generaltranslation%2Fgt%22%20on%20the%20existing%20branch%20%22bg%2Fprune-gt-react-rsc-entry%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22bg%2Fprune-gt-react-rsc-entry%22.%0A%0AFix%20the%20following%202%20code%20review%20issues.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%202%0A.changeset%2Fprune-react-rsc-entry.md%3A2%0A**Changeset%20type%20conflicts%20with%20breaking-change%20indicator%20in%20the%20PR%20title**%0A%0AThe%20changeset%20marks%20this%20as%20%60patch%60%2C%20but%20the%20PR%20title%20carries%20the%20%60feat!%60%20suffix%20%28conventional-commits%20notation%20for%20a%20breaking%20change%29%20and%20the%20diff%20removes%20several%20previously%20public%2C%20non-%60GtInternal%60-prefixed%20exports%20from%20the%20RSC%20entry%3A%20%60renderVariable%60%2C%20%60createRenderVariable%60%2C%20%60renderDefaultChildren%60%2C%20%60renderPreparedT%60%2C%20%60renderTranslatedChildren%60%2C%20%60getPluralBranch%60%2C%20%60getShouldTranslate%60%2C%20%60prepareT%60%2C%20and%20%60getReadonlyConditionStore%60.%20Any%20consumer%20importing%20those%20symbols%20from%20the%20react-server%20entry%20will%20receive%20an%20unresolved-export%20error%20after%20upgrading.%20In%20changesets%20terminology%20this%20is%20a%20%60major%60%20bump%20%28or%20at%20minimum%20%60minor%60%20if%20the%20team%20considers%20the%20RSC%20surface%20fully%20internal%29%3B%20shipping%20it%20as%20%60patch%60%20risks%20silent%20breakage%20for%20downstream%20consumers%20who%20rely%20on%20semver.%0A%0A%23%23%23%20Issue%202%20of%202%0Apackages%2Freact%2Fsrc%2F__tests__%2Fcontext-rsc.test.ts%3A17-25%0A**Retained%20value%20exports%20not%20covered%20by%20the%20surface%20test**%0A%0AAfter%20this%20change%20%60createRenderPipeline%60%2C%20%60t%60%2C%20%60getTranslationsSnapshot%60%2C%20%60getReactI18nCache%60%2C%20and%20%60setReactI18nCache%60%20are%20still%20exported%20from%20the%20RSC%20entry%2C%20but%20the%20test%20does%20not%20assert%20their%20presence.%20Because%20the%20test%20is%20the%20canonical%20surface%20contract%20for%20this%20entry%2C%20a%20future%20refactor%20that%20accidentally%20drops%20one%20of%20these%20would%20go%20undetected.%20Adding%20positive%20%60toBeTypeOf%28'function'%29%60%20checks%20for%20the%20remaining%20exports%20that%20are%20meant%20to%20stay%20would%20make%20the%20test%20more%20complete.%0A%0A&repo=generaltranslation%2Fgt&pr=1817&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img
alt="Fix All in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a>

<details><summary>Prompt To Fix All With AI</summary>

`````markdown
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
.changeset/prune-react-rsc-entry.md:2
**Changeset type conflicts with breaking-change indicator in the PR title**

The changeset marks this as `patch`, but the PR title carries the `feat!` suffix (conventional-commits notation for a breaking change) and the diff removes several previously public, non-`GtInternal`-prefixed exports from the RSC entry: `renderVariable`, `createRenderVariable`, `renderDefaultChildren`, `renderPreparedT`, `renderTranslatedChildren`, `getPluralBranch`, `getShouldTranslate`, `prepareT`, and `getReadonlyConditionStore`. Any consumer importing those symbols from the react-server entry will receive an unresolved-export error after upgrading. In changesets terminology this is a `major` bump (or at minimum `minor` if the team considers the RSC surface fully internal); shipping it as `patch` risks silent breakage for downstream consumers who rely on semver.

### Issue 2 of 2
packages/react/src/__tests__/context-rsc.test.ts:17-25
**Retained value exports not covered by the surface test**

After this change `createRenderPipeline`, `t`, `getTranslationsSnapshot`, `getReactI18nCache`, and `setReactI18nCache` are still exported from the RSC entry, but the test does not assert their presence. Because the test is the canonical surface contract for this entry, a future refactor that accidentally drops one of these would go undetected. Adding positive `toBeTypeOf('function')` checks for the remaining exports that are meant to stay would make the test more complete.

`````

</details>

<sub>Reviews (1): Last reviewed commit: ["feat!: prune gt-react RSC
render
interna..."](05107e7)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=41726916)</sub>

> Greptile also left **2 inline comments** on this PR.

<!-- /greptile_comment -->
## TL;DR

Clean up the gt-next public API surface for the next major prerelease.

## Code Changes

- Remove the deprecated initGT config alias and its config tests.
- Remove the redundant gt-next/types subpath from package metadata,
size-limit tracking, and source.
- Move the hidden dictionary and loader subpaths to gt-next/internal/*
and update webpack/Turbopack alias plumbing plus runtime require()
calls.
- Fix the next-ssg example getLocales import and remove CLI setup
detection for the removed initGT alias.
- Add a prerelease patch changeset for gt-next and gt.

## Notes / Flags

- Rebased onto origin/odysseus at 5736d58 using 794920a as the old
base.
- Verified with pnpm --filter gt-next test after refreshing install with
pnpm install --force --child-concurrency=1 --network-concurrency=1.
- Earlier next-ssg typecheck passed before the rebase; next-ssg build is
still blocked by Next 16 Turbopack workspace-root inference in this
example, before app compilation.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR cleans up the `gt-next` public API surface ahead of the next
major prerelease by removing the deprecated `initGT` config alias, the
redundant `gt-next/types` subpath, and migrating three hidden internal
entry points (`_dictionary`, `_load-translations`, `_load-dictionary`)
under a unified `gt-next/internal/*` namespace.

- All internal `require()` call sites, webpack/Turbopack alias keys,
`package.json` exports, `typesVersions`, size-limit config, and tests
are updated in lockstep to use the new `internal/*` paths.
- The deprecated `initGT` wrapper (backward-compat alias for
`withGTConfig`) is removed from `config.ts` and the CLI's `handleInitGT`
no longer treats `initGT` as a valid existing setup, along with the
corresponding test coverage.
- The `next-ssg` example consolidates `getLocales` and `T` into a single
`gt-next` import; both symbols are confirmed exported from every
relevant entry point (`index.server`, `index.rsc`, `index.client`).

<details open><summary><h3>Confidence Score: 5/5</h3></summary>

This PR is safe to merge — all alias renames are applied consistently
across webpack, Turbopack, runtime require() call sites, package.json
exports, typesVersions, size-limit config, and tests in a single pass.

The change is a straightforward namespace migration (three internal
module paths) plus the removal of two explicitly deprecated exports.
Every site that referenced the old paths has been updated, the example
import consolidation is valid against all three entry points, and the
deleted types file's exports remain reachable via the main entry. No
logic is altered beyond the removed backward-compat wrapper.

No files require special attention. The most load-bearing file is
packages/next/src/config.ts (webpack + Turbopack alias injection), and
both branches were updated consistently.
</details>

<details><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| packages/next/src/config.ts | Removes initGT export and renames all
three internal alias keys from gt-next/_* to gt-next/internal/_* in both
webpack and Turbopack config branches; changes are internally
consistent. |
| packages/next/package.json | Removes ./types export entry and renames
_dictionary, _load-translations, _load-dictionary to internal/* in
exports, typesVersions, and compilerOptions.paths; all three sections
are consistently updated. |
| packages/next/src/__tests__/config.test.ts | Removes section 18
(initGT backward-compat tests) and updates alias assertions in sections
16/17 to use the new gt-next/internal/_dictionary key. |
| packages/cli/src/next/parse/handleInitGT.ts | Removes hasInitGT
tracking and its three detection branches; early-return guard now checks
only hasGTConfig. |
| packages/next/src/dictionary/getDictionary.ts | Two
require('gt-next/_dictionary') calls updated to
gt-next/internal/_dictionary; logic unchanged. |

</details>

<details><summary><h3>Flowchart</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[withGTConfig] --> B{Dictionary path set?}
    B -- Yes --> C["webpack: alias gt-next/internal/_dictionary"]
    B -- Yes --> D["turbo: alias gt-next/internal/_dictionary"]
    B -- No --> E[skip alias]
    A --> F{Custom load-translations?}
    F -- Yes --> G["alias gt-next/internal/_load-translations"]
    F -- No --> H[skip]
    A --> I{Custom load-dictionary?}
    I -- Yes --> J["alias gt-next/internal/_load-dictionary"]
    I -- No --> K[skip]
    subgraph Runtime require calls
      L["getDictionary.ts require('gt-next/internal/_dictionary')"]
      M["resolveDictionaryLoader.ts require('gt-next/internal/_load-dictionary')"]
      N["resolveTranslationLoader.ts require('gt-next/internal/_load-translations')"]
    end
    C --> L
    D --> L
    G --> N
    J --> M
    subgraph Removed
      O["initGT alias (config.ts)"]
      P["gt-next/types subpath"]
      Q["gt-next/_dictionary subpath"]
      R["gt-next/_load-translations subpath"]
      S["gt-next/_load-dictionary subpath"]
    end
```

</a>
<a href="#gh-dark-mode-only">

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[withGTConfig] --> B{Dictionary path set?}
    B -- Yes --> C["webpack: alias gt-next/internal/_dictionary"]
    B -- Yes --> D["turbo: alias gt-next/internal/_dictionary"]
    B -- No --> E[skip alias]
    A --> F{Custom load-translations?}
    F -- Yes --> G["alias gt-next/internal/_load-translations"]
    F -- No --> H[skip]
    A --> I{Custom load-dictionary?}
    I -- Yes --> J["alias gt-next/internal/_load-dictionary"]
    I -- No --> K[skip]
    subgraph Runtime require calls
      L["getDictionary.ts require('gt-next/internal/_dictionary')"]
      M["resolveDictionaryLoader.ts require('gt-next/internal/_load-dictionary')"]
      N["resolveTranslationLoader.ts require('gt-next/internal/_load-translations')"]
    end
    C --> L
    D --> L
    G --> N
    J --> M
    subgraph Removed
      O["initGT alias (config.ts)"]
      P["gt-next/types subpath"]
      Q["gt-next/_dictionary subpath"]
      R["gt-next/_load-translations subpath"]
      S["gt-next/_load-dictionary subpath"]
    end
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["feat!: clean up gt-next public
API
surfa..."](9adf829)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=41726798)</sub>

<!-- /greptile_comment -->
## TL;DR

Remove inert top-level `compilerOptions` fields from package manifests.
These fields are tsconfig-only metadata and are not read from
`package.json` anywhere in the repo.

## Code Changes

- Deleted top-level `compilerOptions` blocks from `gt-next`, `gt-react`,
`@generaltranslation/react-core`, `generaltranslation`, `gt-i18n`,
`gt-node`, `@generaltranslation/format`, `@generaltranslation/mcp`, and
`locadex` package manifests.
- Re-verified package metadata readers, build scripts, tsdown configs,
turbo config, and scripts do not consume `compilerOptions` from
`package.json`.
- No changeset: manifest-only cleanup with no published behavior change.

## Notes / Flags

Sibling PRs also edit `packages/i18n/package.json` and
`packages/next/package.json` for subpath removals; trivial merge
conflicts are expected.

Verification:

- `pnpm install --force --store-dir
/private/tmp/gt-remove-inert-compiler-options-pnpm-store`
- `pnpm lint:fix`
- `pnpm format:fix`
- `pnpm --filter @generaltranslation/format... --filter
generaltranslation... --filter gt-i18n... --filter gt-node... --filter
@generaltranslation/react-core... --filter gt-react... --filter
gt-next... --filter @generaltranslation/mcp... --filter locadex...
build`
- `pnpm --filter gt-next --filter gt-react --filter
@generaltranslation/react-core --filter generaltranslation --filter
gt-i18n --filter gt-node --filter @generaltranslation/format --filter
@generaltranslation/mcp --filter locadex test`

Default-store `pnpm install --force` hit pnpm global-store `ENOTEMPTY`
rename errors twice at the final link step; rerunning with an isolated
temporary store completed successfully.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR removes top-level `compilerOptions` blocks from nine
`package.json` files across the monorepo. These fields are tsconfig-only
metadata and have no effect when placed in a package manifest — no build
tool, bundler, or runtime reads them from there.

- **Nine packages cleaned up**: `gt-next`, `gt-react`,
`@generaltranslation/react-core`, `generaltranslation`, `gt-i18n`,
`gt-node`, `@generaltranslation/format`, `@generaltranslation/mcp`, and
`locadex` each had either populated `compilerOptions.paths` blocks or
empty `compilerOptions: {}` objects removed.
- **No behavior change**: The actual subpath exports remain intact in
each package's `exports` field; only the dead metadata is deleted.

<details open><summary><h3>Confidence Score: 5/5</h3></summary>

Safe to merge — changes are purely additive deletions of dead metadata
with no effect on build output, published exports, or runtime behavior.

Every touched file is a package manifest, and every removed field
(compilerOptions) is a tsconfig-only construct that Node, pnpm, tsdown,
and turbo all ignore when reading package.json. The exports maps that
actually govern subpath resolution are untouched across all nine
packages.

No files require special attention.
</details>

<details><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| packages/next/package.json | Removed the largest compilerOptions block
(10 subpath entries for gt-next/*); no published behavior change. |
| packages/core/package.json | Removed inert top-level compilerOptions
block with baseUrl/paths entries — these fields are not read by any
build tooling from package.json. |
| packages/react-core/package.json | Removed inert compilerOptions block
with four @generaltranslation/react-core subpath entries. |
| packages/i18n/package.json | Removed inert compilerOptions block with
four subpath path aliases; no build behavior change. |
| packages/node/package.json | Removed inert compilerOptions block with
two gt-node subpath entries. |
| packages/format/package.json | Removed inert compilerOptions block
with two subpath path aliases that had no effect outside a tsconfig. |
| packages/react/package.json | Removed inert compilerOptions block with
a single gt-react/macros path alias. |
| packages/locadex/package.json | Removed empty compilerOptions: {}
field — purely cosmetic cleanup. |
| packages/mcp/package.json | Removed empty compilerOptions: {} field —
purely cosmetic cleanup. |

</details>

<details><summary><h3>Flowchart</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[package.json] --> B["exports field (kept)"]
    A --> C["compilerOptions field (removed)"]
    B --> D["Node / pnpm / bundler subpath resolution"]
    C --> E["tsconfig.json — where compilerOptions belongs"]
    style C stroke:#f66,stroke-dasharray:5 5
    style E stroke:#999,fill:#f9f9f9
```

</a>
<a href="#gh-dark-mode-only">

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[package.json] --> B["exports field (kept)"]
    A --> C["compilerOptions field (removed)"]
    B --> D["Node / pnpm / bundler subpath resolution"]
    C --> E["tsconfig.json — where compilerOptions belongs"]
    style C stroke:#f66,stroke-dasharray:5 5
    style E stroke:#999,fill:#f9f9f9
```

</a>
</details>

<sub>Reviews (2): Last reviewed commit: ["chore: remove inert compiler
options
fro..."](1ce68d0)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=41726692)</sub>

<!-- /greptile_comment -->
## Summary
- remove the deprecated `@generaltranslation/next-internal` and
`@generaltranslation/gt-next-lint` packages
- clean workspace/package references, changeset prerelease metadata,
CI/docs config, and lockfile entries
- remove the obsolete next-internal scheduled workflow
- add a `gt-next` patch changeset

## Testing
- `pnpm turbo run build --filter='gt-next^...'`\n- `pnpm --filter
gt-next typecheck`\n- `pnpm --filter gt-next test:js`\n- `pnpm --filter
gt-next build:no-swc-plugin`\n- `pnpm oxfmt --check
.changeset/clean-next-internal-packages.md
.changeset/odysseus-all-packages-patch.md .changeset/pre.json
.claude/CLAUDE.md .claude/rules/linter-plugins.md
.github/workflows/ci.yml packages/next/CHANGELOG.md
packages/next/package.json pnpm-lock.yaml examples/next-ssg/package.json
tests/apps/next/middleware/runBenchE2E.mjs`\n- `rg -n --hidden --glob
'!.git' --glob '!.git/**'
\"getRootParam|_getRootParam|@generaltranslation/next-internal|next-internal|@generaltranslation/gt-next-lint|gt-next-lint|packages/next-lint|packages/next-internal\"
.`\n

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR removes the deprecated `@generaltranslation/next-internal` and
`@generaltranslation/gt-next-lint` packages and consolidates the sole
surviving export (`getRootParam`) directly into
`gt-next/internal/_getRootParam`. It is primarily a cleanup: ~4 000
lines deleted and only ~120 added.

- **New file**: `packages/next/src/internal/_getRootParam.ts` inlines
all logic from the five separate files that made up `next-internal`,
tightening the typings (`any` → `unknown`) while keeping the same
runtime behaviour.
- **Package wiring**: `packages/next/package.json` adds the new
`./internal/_getRootParam` export (with `\"types\"` in the `exports`
map) and removes the `@generaltranslation/next-internal` workspace
dependency; `pnpm-lock.yaml` and the bench runner are updated
accordingly.

<details open><summary><h3>Confidence Score: 4/5</h3></summary>

Safe to merge — this is a consolidation of existing logic with no
functional changes.

The new _getRootParam.ts is a faithful copy of the old next-internal
split-file implementation, with tighter TypeScript types as the only
meaningful delta. All workspace references and the lockfile are cleaned
up correctly. The two gaps are: the exports map inconsistency where
_getRootParam has a types field the sibling entries lack, and the
removal of 148 lines of Playwright E2E coverage with nothing replacing
it. Neither blocks a merge, but the missing tests leave the moved code
without runtime verification.

packages/next/src/internal/_getRootParam.ts has no test coverage after
the E2E suite was removed; packages/next/package.json has a minor
export-map inconsistency worth addressing.
</details>


<details><summary><h3>Important Files Changed</h3></summary>




| Filename | Overview |
|----------|----------|
| packages/next/src/internal/_getRootParam.ts | New file consolidating
getRootParam logic from next-internal; index=0 explicit-vs-default
ambiguity is inherited pre-existing behaviour and the E2E test suite was
removed with no replacement. |
| packages/next/package.json | Adds ./internal/_getRootParam export with
a types field that the parallel _getLocale/_getRegion exports lack;
removes next-internal workspace dependency. |
| examples/next-ssg/package.json | Drops the
@generaltranslation/next-internal dependency; verified no source files
in the example still import from it. |
| tests/apps/next/middleware/runBenchE2E.mjs | Removes next-internal
from the bench E2E packed dependencies list; straightforward cleanup. |

</details>


<details><summary><h3>Flowchart</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["getRootParam(param, index=0)"] --> B["workUnitAsyncStorage.getStore()"]
    B -->|"no store"| Z["return undefined"]
    B -->|"store"| C["extractImplicitTags(store)"]
    C -->|"null / empty"| Z
    C -->|"tags"| D{"index == 0 (falsy)?"}
    D -->|"yes"| E["findParamIndexFromImplicitTags(tags, param)"]
    E -->|"-1 (not found)"| Z
    E -->|"n >= 1"| F["index = n"]
    D -->|"no (explicit)"| F
    F --> G["extractParamFromImplicitTags(tags, index)"]
    G -->|"last implicit tag split('/')[index]"| H["return value"]
```

</a>
<a href="#gh-dark-mode-only">

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["getRootParam(param, index=0)"] --> B["workUnitAsyncStorage.getStore()"]
    B -->|"no store"| Z["return undefined"]
    B -->|"store"| C["extractImplicitTags(store)"]
    C -->|"null / empty"| Z
    C -->|"tags"| D{"index == 0 (falsy)?"}
    D -->|"yes"| E["findParamIndexFromImplicitTags(tags, param)"]
    E -->|"-1 (not found)"| Z
    E -->|"n >= 1"| F["index = n"]
    D -->|"no (explicit)"| F
    F --> G["extractParamFromImplicitTags(tags, index)"]
    G -->|"last implicit tag split('/')[index]"| H["return value"]
```

</a>
</details>


<!-- greptile_failed_comments -->
<details open><summary><h3>Comments Outside Diff (3)</h3></summary>

1. `packages/next/package.json`, line 124-132
([link](https://github.com/generaltranslation/gt/blob/0f8da5889a4c6cf3ed4428cfede7792c301b18f8/packages/next/package.json#L124-L132))

<a href="#"><img alt="P2"
src="https://greptile-static-assets.s3.amazonaws.com/badges/p2.svg?v=9"
align="top"></a> The new `./internal/_getRootParam` export includes a
`"types"` key in the `exports` map, but the sibling entries
`./internal/_getLocale` and `./internal/_getRegion` do not. Modern
TypeScript resolvers (using `moduleResolution: "bundler"` or `"node16"`)
prefer the `exports` `"types"` field over `typesVersions`. Having it on
one entry and not the others creates an inconsistency that could cause
subtly different resolution behaviour depending on which internal
subpath a consumer imports.

   

   <details><summary>Prompt To Fix With AI</summary>

   `````markdown
   This is a comment left during a code review.
   Path: packages/next/package.json
   Line: 124-132

   Comment:
The new `./internal/_getRootParam` export includes a `"types"` key in
the `exports` map, but the sibling entries `./internal/_getLocale` and
`./internal/_getRegion` do not. Modern TypeScript resolvers (using
`moduleResolution: "bundler"` or `"node16"`) prefer the `exports`
`"types"` field over `typesVersions`. Having it on one entry and not the
others creates an inconsistency that could cause subtly different
resolution behaviour depending on which internal subpath a consumer
imports.

   

   How can I resolve this? If you propose a fix, please make it concise.
   `````
   </details>

Note: If this suggestion doesn't match your team's coding style, reply
to this and let me know. I'll remember it for next time!

<a
href="https://app.greptile.com/ide/claude-code?prompt=This%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20packages%2Fnext%2Fpackage.json%0ALine%3A%20124-132%0A%0AComment%3A%0AThe%20new%20%60.%2Finternal%2F_getRootParam%60%20export%20includes%20a%20%60%22types%22%60%20key%20in%20the%20%60exports%60%20map%2C%20but%20the%20sibling%20entries%20%60.%2Finternal%2F_getLocale%60%20and%20%60.%2Finternal%2F_getRegion%60%20do%20not.%20Modern%20TypeScript%20resolvers%20%28using%20%60moduleResolution%3A%20%22bundler%22%60%20or%20%60%22node16%22%60%29%20prefer%20the%20%60exports%60%20%60%22types%22%60%20field%20over%20%60typesVersions%60.%20Having%20it%20on%20one%20entry%20and%20not%20the%20others%20creates%20an%20inconsistency%20that%20could%20cause%20subtly%20different%20resolution%20behaviour%20depending%20on%20which%20internal%20subpath%20a%20consumer%20imports.%0A%0A%60%60%60suggestion%0A%20%20%20%20%22.%2Finternal%2F_getRegion%22%3A%20%7B%0A%20%20%20%20%20%20%22types%22%3A%20%22.%2Fdist%2Finternal%2F_getRegion.d.ts%22%2C%0A%20%20%20%20%20%20%22import%22%3A%20%22.%2Fdist%2Finternal%2F_getRegion.mjs%22%2C%0A%20%20%20%20%20%20%22default%22%3A%20%22.%2Fdist%2Finternal%2F_getRegion.js%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22.%2Finternal%2F_getRootParam%22%3A%20%7B%0A%20%20%20%20%20%20%22types%22%3A%20%22.%2Fdist%2Finternal%2F_getRootParam.d.ts%22%2C%0A%20%20%20%20%20%20%22import%22%3A%20%22.%2Fdist%2Finternal%2F_getRootParam.mjs%22%2C%0A%20%20%20%20%20%20%22default%22%3A%20%22.%2Fdist%2Finternal%2F_getRootParam.js%22%0A%20%20%20%20%7D%0A%60%60%60%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=generaltranslation%2Fgt&pr=1824&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaudeDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=6"><img
alt="Fix in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=6"></picture></a>
<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22generaltranslation%2Fgt%22%20on%20the%20existing%20branch%20%22e%2Fodysseus%2Fremove-next-internal-next-lint%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22e%2Fodysseus%2Fremove-next-internal-next-lint%22.%0A%0AThis%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20packages%2Fnext%2Fpackage.json%0ALine%3A%20124-132%0A%0AComment%3A%0AThe%20new%20%60.%2Finternal%2F_getRootParam%60%20export%20includes%20a%20%60%22types%22%60%20key%20in%20the%20%60exports%60%20map%2C%20but%20the%20sibling%20entries%20%60.%2Finternal%2F_getLocale%60%20and%20%60.%2Finternal%2F_getRegion%60%20do%20not.%20Modern%20TypeScript%20resolvers%20%28using%20%60moduleResolution%3A%20%22bundler%22%60%20or%20%60%22node16%22%60%29%20prefer%20the%20%60exports%60%20%60%22types%22%60%20field%20over%20%60typesVersions%60.%20Having%20it%20on%20one%20entry%20and%20not%20the%20others%20creates%20an%20inconsistency%20that%20could%20cause%20subtly%20different%20resolution%20behaviour%20depending%20on%20which%20internal%20subpath%20a%20consumer%20imports.%0A%0A%60%60%60suggestion%0A%20%20%20%20%22.%2Finternal%2F_getRegion%22%3A%20%7B%0A%20%20%20%20%20%20%22types%22%3A%20%22.%2Fdist%2Finternal%2F_getRegion.d.ts%22%2C%0A%20%20%20%20%20%20%22import%22%3A%20%22.%2Fdist%2Finternal%2F_getRegion.mjs%22%2C%0A%20%20%20%20%20%20%22default%22%3A%20%22.%2Fdist%2Finternal%2F_getRegion.js%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22.%2Finternal%2F_getRootParam%22%3A%20%7B%0A%20%20%20%20%20%20%22types%22%3A%20%22.%2Fdist%2Finternal%2F_getRootParam.d.ts%22%2C%0A%20%20%20%20%20%20%22import%22%3A%20%22.%2Fdist%2Finternal%2F_getRootParam.mjs%22%2C%0A%20%20%20%20%20%20%22default%22%3A%20%22.%2Fdist%2Finternal%2F_getRootParam.js%22%0A%20%20%20%20%7D%0A%60%60%60%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=generaltranslation%2Fgt&pr=1824&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodexDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"><img
alt="Fix in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"></picture></a>


2. `packages/next/src/internal/_getRootParam.ts`, line 48
([link](https://github.com/generaltranslation/gt/blob/0f8da5889a4c6cf3ed4428cfede7792c301b18f8/packages/next/src/internal/_getRootParam.ts#L48))

<a href="#"><img alt="P2"
src="https://greptile-static-assets.s3.amazonaws.com/badges/p2.svg?v=9"
align="top"></a> **`index = 0` is indistinguishable from the default**

`0 ||= findParamIndexFromImplicitTags(...)` evaluates the right-hand
side whenever `index` is `0`, whether the caller omitted the argument
(default `0`) or explicitly passed `0`. A caller who passes
`getRootParam('locale', 0)` expecting position 0 in the segments array
(i.e. the `_N_T_` prefix) will silently have their value overwritten.
The existing JSDoc comment "0 is the request url" hints this is
intentional, but the signature `index: number = 0` gives no indication.
Consider using `undefined` as the default sentinel so explicit zeros are
preserved, or document the restriction clearly. This is inherited from
the old package but is worth fixing now that the code is being moved.

   <details><summary>Prompt To Fix With AI</summary>

   `````markdown
   This is a comment left during a code review.
   Path: packages/next/src/internal/_getRootParam.ts
   Line: 48

   Comment:
   **`index = 0` is indistinguishable from the default**

`0 ||= findParamIndexFromImplicitTags(...)` evaluates the right-hand
side whenever `index` is `0`, whether the caller omitted the argument
(default `0`) or explicitly passed `0`. A caller who passes
`getRootParam('locale', 0)` expecting position 0 in the segments array
(i.e. the `_N_T_` prefix) will silently have their value overwritten.
The existing JSDoc comment "0 is the request url" hints this is
intentional, but the signature `index: number = 0` gives no indication.
Consider using `undefined` as the default sentinel so explicit zeros are
preserved, or document the restriction clearly. This is inherited from
the old package but is worth fixing now that the code is being moved.

   How can I resolve this? If you propose a fix, please make it concise.
   `````
   </details>

<a
href="https://app.greptile.com/ide/claude-code?prompt=This%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20packages%2Fnext%2Fsrc%2Finternal%2F_getRootParam.ts%0ALine%3A%2048%0A%0AComment%3A%0A**%60index%20%3D%200%60%20is%20indistinguishable%20from%20the%20default**%0A%0A%600%20%7C%7C%3D%20findParamIndexFromImplicitTags%28...%29%60%20evaluates%20the%20right-hand%20side%20whenever%20%60index%60%20is%20%600%60%2C%20whether%20the%20caller%20omitted%20the%20argument%20%28default%20%600%60%29%20or%20explicitly%20passed%20%600%60.%20A%20caller%20who%20passes%20%60getRootParam%28'locale'%2C%200%29%60%20expecting%20position%200%20in%20the%20segments%20array%20%28i.e.%20the%20%60_N_T_%60%20prefix%29%20will%20silently%20have%20their%20value%20overwritten.%20The%20existing%20JSDoc%20comment%20%220%20is%20the%20request%20url%22%20hints%20this%20is%20intentional%2C%20but%20the%20signature%20%60index%3A%20number%20%3D%200%60%20gives%20no%20indication.%20Consider%20using%20%60undefined%60%20as%20the%20default%20sentinel%20so%20explicit%20zeros%20are%20preserved%2C%20or%20document%20the%20restriction%20clearly.%20This%20is%20inherited%20from%20the%20old%20package%20but%20is%20worth%20fixing%20now%20that%20the%20code%20is%20being%20moved.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=generaltranslation%2Fgt&pr=1824&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaudeDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=6"><img
alt="Fix in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=6"></picture></a>
<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22generaltranslation%2Fgt%22%20on%20the%20existing%20branch%20%22e%2Fodysseus%2Fremove-next-internal-next-lint%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22e%2Fodysseus%2Fremove-next-internal-next-lint%22.%0A%0AThis%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20packages%2Fnext%2Fsrc%2Finternal%2F_getRootParam.ts%0ALine%3A%2048%0A%0AComment%3A%0A**%60index%20%3D%200%60%20is%20indistinguishable%20from%20the%20default**%0A%0A%600%20%7C%7C%3D%20findParamIndexFromImplicitTags%28...%29%60%20evaluates%20the%20right-hand%20side%20whenever%20%60index%60%20is%20%600%60%2C%20whether%20the%20caller%20omitted%20the%20argument%20%28default%20%600%60%29%20or%20explicitly%20passed%20%600%60.%20A%20caller%20who%20passes%20%60getRootParam%28'locale'%2C%200%29%60%20expecting%20position%200%20in%20the%20segments%20array%20%28i.e.%20the%20%60_N_T_%60%20prefix%29%20will%20silently%20have%20their%20value%20overwritten.%20The%20existing%20JSDoc%20comment%20%220%20is%20the%20request%20url%22%20hints%20this%20is%20intentional%2C%20but%20the%20signature%20%60index%3A%20number%20%3D%200%60%20gives%20no%20indication.%20Consider%20using%20%60undefined%60%20as%20the%20default%20sentinel%20so%20explicit%20zeros%20are%20preserved%2C%20or%20document%20the%20restriction%20clearly.%20This%20is%20inherited%20from%20the%20old%20package%20but%20is%20worth%20fixing%20now%20that%20the%20code%20is%20being%20moved.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=generaltranslation%2Fgt&pr=1824&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodexDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"><img
alt="Fix in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"></picture></a>


3. `packages/next/src/internal/_getRootParam.ts`, line 1
([link](https://github.com/generaltranslation/gt/blob/0f8da5889a4c6cf3ed4428cfede7792c301b18f8/packages/next/src/internal/_getRootParam.ts#L1))

<a href="#"><img alt="P2"
src="https://greptile-static-assets.s3.amazonaws.com/badges/p2.svg?v=9"
align="top"></a> **E2E coverage removed with no replacement**

`packages/next-internal/tests/latest/e2e/getRootParam.spec.ts` had 148
lines of Playwright tests exercising the actual runtime behaviour of
`getRootParam` across different route shapes (plain `[locale]`, nested
`[locale]/[region]`, route groups `(dashboard)/[locale]`). That entire
test file is deleted here and there is no equivalent test in
`packages/next/src/__tests__/` or `tests/apps/next/`. The new file has
no unit or integration test coverage at all.

   <details><summary>Prompt To Fix With AI</summary>

   `````markdown
   This is a comment left during a code review.
   Path: packages/next/src/internal/_getRootParam.ts
   Line: 1

   Comment:
   **E2E coverage removed with no replacement**

`packages/next-internal/tests/latest/e2e/getRootParam.spec.ts` had 148
lines of Playwright tests exercising the actual runtime behaviour of
`getRootParam` across different route shapes (plain `[locale]`, nested
`[locale]/[region]`, route groups `(dashboard)/[locale]`). That entire
test file is deleted here and there is no equivalent test in
`packages/next/src/__tests__/` or `tests/apps/next/`. The new file has
no unit or integration test coverage at all.

   How can I resolve this? If you propose a fix, please make it concise.
   `````
   </details>

<a
href="https://app.greptile.com/ide/claude-code?prompt=This%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20packages%2Fnext%2Fsrc%2Finternal%2F_getRootParam.ts%0ALine%3A%201%0A%0AComment%3A%0A**E2E%20coverage%20removed%20with%20no%20replacement**%0A%0A%60packages%2Fnext-internal%2Ftests%2Flatest%2Fe2e%2FgetRootParam.spec.ts%60%20had%20148%20lines%20of%20Playwright%20tests%20exercising%20the%20actual%20runtime%20behaviour%20of%20%60getRootParam%60%20across%20different%20route%20shapes%20%28plain%20%60%5Blocale%5D%60%2C%20nested%20%60%5Blocale%5D%2F%5Bregion%5D%60%2C%20route%20groups%20%60%28dashboard%29%2F%5Blocale%5D%60%29.%20That%20entire%20test%20file%20is%20deleted%20here%20and%20there%20is%20no%20equivalent%20test%20in%20%60packages%2Fnext%2Fsrc%2F__tests__%2F%60%20or%20%60tests%2Fapps%2Fnext%2F%60.%20The%20new%20file%20has%20no%20unit%20or%20integration%20test%20coverage%20at%20all.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=generaltranslation%2Fgt&pr=1824&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaudeDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=6"><img
alt="Fix in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=6"></picture></a>
<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22generaltranslation%2Fgt%22%20on%20the%20existing%20branch%20%22e%2Fodysseus%2Fremove-next-internal-next-lint%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22e%2Fodysseus%2Fremove-next-internal-next-lint%22.%0A%0AThis%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20packages%2Fnext%2Fsrc%2Finternal%2F_getRootParam.ts%0ALine%3A%201%0A%0AComment%3A%0A**E2E%20coverage%20removed%20with%20no%20replacement**%0A%0A%60packages%2Fnext-internal%2Ftests%2Flatest%2Fe2e%2FgetRootParam.spec.ts%60%20had%20148%20lines%20of%20Playwright%20tests%20exercising%20the%20actual%20runtime%20behaviour%20of%20%60getRootParam%60%20across%20different%20route%20shapes%20%28plain%20%60%5Blocale%5D%60%2C%20nested%20%60%5Blocale%5D%2F%5Bregion%5D%60%2C%20route%20groups%20%60%28dashboard%29%2F%5Blocale%5D%60%29.%20That%20entire%20test%20file%20is%20deleted%20here%20and%20there%20is%20no%20equivalent%20test%20in%20%60packages%2Fnext%2Fsrc%2F__tests__%2F%60%20or%20%60tests%2Fapps%2Fnext%2F%60.%20The%20new%20file%20has%20no%20unit%20or%20integration%20test%20coverage%20at%20all.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=generaltranslation%2Fgt&pr=1824&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodexDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"><img
alt="Fix in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"></picture></a>

</details>

<!-- /greptile_failed_comments -->

<a
href="https://app.greptile.com/ide/claude-code?prompt=Fix%20the%20following%203%20code%20review%20issues.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%203%0Apackages%2Fnext%2Fpackage.json%3A124-132%0AThe%20new%20%60.%2Finternal%2F_getRootParam%60%20export%20includes%20a%20%60%22types%22%60%20key%20in%20the%20%60exports%60%20map%2C%20but%20the%20sibling%20entries%20%60.%2Finternal%2F_getLocale%60%20and%20%60.%2Finternal%2F_getRegion%60%20do%20not.%20Modern%20TypeScript%20resolvers%20%28using%20%60moduleResolution%3A%20%22bundler%22%60%20or%20%60%22node16%22%60%29%20prefer%20the%20%60exports%60%20%60%22types%22%60%20field%20over%20%60typesVersions%60.%20Having%20it%20on%20one%20entry%20and%20not%20the%20others%20creates%20an%20inconsistency%20that%20could%20cause%20subtly%20different%20resolution%20behaviour%20depending%20on%20which%20internal%20subpath%20a%20consumer%20imports.%0A%0A%60%60%60suggestion%0A%20%20%20%20%22.%2Finternal%2F_getRegion%22%3A%20%7B%0A%20%20%20%20%20%20%22types%22%3A%20%22.%2Fdist%2Finternal%2F_getRegion.d.ts%22%2C%0A%20%20%20%20%20%20%22import%22%3A%20%22.%2Fdist%2Finternal%2F_getRegion.mjs%22%2C%0A%20%20%20%20%20%20%22default%22%3A%20%22.%2Fdist%2Finternal%2F_getRegion.js%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22.%2Finternal%2F_getRootParam%22%3A%20%7B%0A%20%20%20%20%20%20%22types%22%3A%20%22.%2Fdist%2Finternal%2F_getRootParam.d.ts%22%2C%0A%20%20%20%20%20%20%22import%22%3A%20%22.%2Fdist%2Finternal%2F_getRootParam.mjs%22%2C%0A%20%20%20%20%20%20%22default%22%3A%20%22.%2Fdist%2Finternal%2F_getRootParam.js%22%0A%20%20%20%20%7D%0A%60%60%60%0A%0A%23%23%23%20Issue%202%20of%203%0Apackages%2Fnext%2Fsrc%2Finternal%2F_getRootParam.ts%3A48%0A**%60index%20%3D%200%60%20is%20indistinguishable%20from%20the%20default**%0A%0A%600%20%7C%7C%3D%20findParamIndexFromImplicitTags%28...%29%60%20evaluates%20the%20right-hand%20side%20whenever%20%60index%60%20is%20%600%60%2C%20whether%20the%20caller%20omitted%20the%20argument%20%28default%20%600%60%29%20or%20explicitly%20passed%20%600%60.%20A%20caller%20who%20passes%20%60getRootParam%28'locale'%2C%200%29%60%20expecting%20position%200%20in%20the%20segments%20array%20%28i.e.%20the%20%60_N_T_%60%20prefix%29%20will%20silently%20have%20their%20value%20overwritten.%20The%20existing%20JSDoc%20comment%20%220%20is%20the%20request%20url%22%20hints%20this%20is%20intentional%2C%20but%20the%20signature%20%60index%3A%20number%20%3D%200%60%20gives%20no%20indication.%20Consider%20using%20%60undefined%60%20as%20the%20default%20sentinel%20so%20explicit%20zeros%20are%20preserved%2C%20or%20document%20the%20restriction%20clearly.%20This%20is%20inherited%20from%20the%20old%20package%20but%20is%20worth%20fixing%20now%20that%20the%20code%20is%20being%20moved.%0A%0A%23%23%23%20Issue%203%20of%203%0Apackages%2Fnext%2Fsrc%2Finternal%2F_getRootParam.ts%3A1%0A**E2E%20coverage%20removed%20with%20no%20replacement**%0A%0A%60packages%2Fnext-internal%2Ftests%2Flatest%2Fe2e%2FgetRootParam.spec.ts%60%20had%20148%20lines%20of%20Playwright%20tests%20exercising%20the%20actual%20runtime%20behaviour%20of%20%60getRootParam%60%20across%20different%20route%20shapes%20%28plain%20%60%5Blocale%5D%60%2C%20nested%20%60%5Blocale%5D%2F%5Bregion%5D%60%2C%20route%20groups%20%60%28dashboard%29%2F%5Blocale%5D%60%29.%20That%20entire%20test%20file%20is%20deleted%20here%20and%20there%20is%20no%20equivalent%20test%20in%20%60packages%2Fnext%2Fsrc%2F__tests__%2F%60%20or%20%60tests%2Fapps%2Fnext%2F%60.%20The%20new%20file%20has%20no%20unit%20or%20integration%20test%20coverage%20at%20all.%0A%0A&repo=generaltranslation%2Fgt&pr=1824&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaudeDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=6"><img
alt="Fix All in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=6"></picture></a>
<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22generaltranslation%2Fgt%22%20on%20the%20existing%20branch%20%22e%2Fodysseus%2Fremove-next-internal-next-lint%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22e%2Fodysseus%2Fremove-next-internal-next-lint%22.%0A%0AFix%20the%20following%203%20code%20review%20issues.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%203%0Apackages%2Fnext%2Fpackage.json%3A124-132%0AThe%20new%20%60.%2Finternal%2F_getRootParam%60%20export%20includes%20a%20%60%22types%22%60%20key%20in%20the%20%60exports%60%20map%2C%20but%20the%20sibling%20entries%20%60.%2Finternal%2F_getLocale%60%20and%20%60.%2Finternal%2F_getRegion%60%20do%20not.%20Modern%20TypeScript%20resolvers%20%28using%20%60moduleResolution%3A%20%22bundler%22%60%20or%20%60%22node16%22%60%29%20prefer%20the%20%60exports%60%20%60%22types%22%60%20field%20over%20%60typesVersions%60.%20Having%20it%20on%20one%20entry%20and%20not%20the%20others%20creates%20an%20inconsistency%20that%20could%20cause%20subtly%20different%20resolution%20behaviour%20depending%20on%20which%20internal%20subpath%20a%20consumer%20imports.%0A%0A%60%60%60suggestion%0A%20%20%20%20%22.%2Finternal%2F_getRegion%22%3A%20%7B%0A%20%20%20%20%20%20%22types%22%3A%20%22.%2Fdist%2Finternal%2F_getRegion.d.ts%22%2C%0A%20%20%20%20%20%20%22import%22%3A%20%22.%2Fdist%2Finternal%2F_getRegion.mjs%22%2C%0A%20%20%20%20%20%20%22default%22%3A%20%22.%2Fdist%2Finternal%2F_getRegion.js%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22.%2Finternal%2F_getRootParam%22%3A%20%7B%0A%20%20%20%20%20%20%22types%22%3A%20%22.%2Fdist%2Finternal%2F_getRootParam.d.ts%22%2C%0A%20%20%20%20%20%20%22import%22%3A%20%22.%2Fdist%2Finternal%2F_getRootParam.mjs%22%2C%0A%20%20%20%20%20%20%22default%22%3A%20%22.%2Fdist%2Finternal%2F_getRootParam.js%22%0A%20%20%20%20%7D%0A%60%60%60%0A%0A%23%23%23%20Issue%202%20of%203%0Apackages%2Fnext%2Fsrc%2Finternal%2F_getRootParam.ts%3A48%0A**%60index%20%3D%200%60%20is%20indistinguishable%20from%20the%20default**%0A%0A%600%20%7C%7C%3D%20findParamIndexFromImplicitTags%28...%29%60%20evaluates%20the%20right-hand%20side%20whenever%20%60index%60%20is%20%600%60%2C%20whether%20the%20caller%20omitted%20the%20argument%20%28default%20%600%60%29%20or%20explicitly%20passed%20%600%60.%20A%20caller%20who%20passes%20%60getRootParam%28'locale'%2C%200%29%60%20expecting%20position%200%20in%20the%20segments%20array%20%28i.e.%20the%20%60_N_T_%60%20prefix%29%20will%20silently%20have%20their%20value%20overwritten.%20The%20existing%20JSDoc%20comment%20%220%20is%20the%20request%20url%22%20hints%20this%20is%20intentional%2C%20but%20the%20signature%20%60index%3A%20number%20%3D%200%60%20gives%20no%20indication.%20Consider%20using%20%60undefined%60%20as%20the%20default%20sentinel%20so%20explicit%20zeros%20are%20preserved%2C%20or%20document%20the%20restriction%20clearly.%20This%20is%20inherited%20from%20the%20old%20package%20but%20is%20worth%20fixing%20now%20that%20the%20code%20is%20being%20moved.%0A%0A%23%23%23%20Issue%203%20of%203%0Apackages%2Fnext%2Fsrc%2Finternal%2F_getRootParam.ts%3A1%0A**E2E%20coverage%20removed%20with%20no%20replacement**%0A%0A%60packages%2Fnext-internal%2Ftests%2Flatest%2Fe2e%2FgetRootParam.spec.ts%60%20had%20148%20lines%20of%20Playwright%20tests%20exercising%20the%20actual%20runtime%20behaviour%20of%20%60getRootParam%60%20across%20different%20route%20shapes%20%28plain%20%60%5Blocale%5D%60%2C%20nested%20%60%5Blocale%5D%2F%5Bregion%5D%60%2C%20route%20groups%20%60%28dashboard%29%2F%5Blocale%5D%60%29.%20That%20entire%20test%20file%20is%20deleted%20here%20and%20there%20is%20no%20equivalent%20test%20in%20%60packages%2Fnext%2Fsrc%2F__tests__%2F%60%20or%20%60tests%2Fapps%2Fnext%2F%60.%20The%20new%20file%20has%20no%20unit%20or%20integration%20test%20coverage%20at%20all.%0A%0A&repo=generaltranslation%2Fgt&pr=1824&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img
alt="Fix All in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a>

<details><summary>Prompt To Fix All With AI</summary>

`````markdown
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
packages/next/package.json:124-132
The new `./internal/_getRootParam` export includes a `"types"` key in the `exports` map, but the sibling entries `./internal/_getLocale` and `./internal/_getRegion` do not. Modern TypeScript resolvers (using `moduleResolution: "bundler"` or `"node16"`) prefer the `exports` `"types"` field over `typesVersions`. Having it on one entry and not the others creates an inconsistency that could cause subtly different resolution behaviour depending on which internal subpath a consumer imports.

```suggestion
    "./internal/_getRegion": {
      "types": "./dist/internal/_getRegion.d.ts",
      "import": "./dist/internal/_getRegion.mjs",
      "default": "./dist/internal/_getRegion.js"
    },
    "./internal/_getRootParam": {
      "types": "./dist/internal/_getRootParam.d.ts",
      "import": "./dist/internal/_getRootParam.mjs",
      "default": "./dist/internal/_getRootParam.js"
    }
```

### Issue 2 of 3
packages/next/src/internal/_getRootParam.ts:48
**`index = 0` is indistinguishable from the default**

`0 ||= findParamIndexFromImplicitTags(...)` evaluates the right-hand side whenever `index` is `0`, whether the caller omitted the argument (default `0`) or explicitly passed `0`. A caller who passes `getRootParam('locale', 0)` expecting position 0 in the segments array (i.e. the `_N_T_` prefix) will silently have their value overwritten. The existing JSDoc comment "0 is the request url" hints this is intentional, but the signature `index: number = 0` gives no indication. Consider using `undefined` as the default sentinel so explicit zeros are preserved, or document the restriction clearly. This is inherited from the old package but is worth fixing now that the code is being moved.

### Issue 3 of 3
packages/next/src/internal/_getRootParam.ts:1
**E2E coverage removed with no replacement**

`packages/next-internal/tests/latest/e2e/getRootParam.spec.ts` had 148 lines of Playwright tests exercising the actual runtime behaviour of `getRootParam` across different route shapes (plain `[locale]`, nested `[locale]/[region]`, route groups `(dashboard)/[locale]`). That entire test file is deleted here and there is no equivalent test in `packages/next/src/__tests__/` or `tests/apps/next/`. The new file has no unit or integration test coverage at all.


`````

</details>

<sub>Reviews (1): Last reviewed commit: ["fix: remove deprecated next
packages"](0f8da58)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=41739002)</sub>

<!-- /greptile_comment -->
…port (#1814)

## Summary
- vendor the small FormatJS ICU AST printer into `packages/core`
(`src/derive/utils/printIcuAst.ts`, adapted from
`@formatjs/icu-messageformat-parser/printer.js`, MIT) and point
`condenseVars` at it
- drop the `@formatjs/icu-messageformat-parser/printer.js` import from
the built `internal.mjs`/`internal.cjs`, fixing TanStack Start/Vite dev
where the browser received the raw CommonJS module (`exports is not
defined` / `does not provide an export named 'printAST'`)
- add regression tests: pinned `condenseVars` serialization outputs
(generated against the original FormatJS printer before the swap),
byte-for-byte equivalence of the vendored printer vs FormatJS `printAST`
across a broad ICU corpus (with and without parsed skeletons), and an
ESM-graph test that `dist/internal.mjs` no longer imports the CJS
printer subpath
- add a patch changeset for `generaltranslation`

## Why vendoring
- Runtime CJS interop (`require()` / namespace-import fallbacks) is not
browser-safe for `internal.mjs`: Vite dev serves the CJS `printer.js` to
the browser unchanged, where `exports` does not exist.
- Importing FormatJS's ESM `lib/printer.js` instead is not viable
either: its extensionless relative imports (`./types`) fail Node/Vite
module resolution in TanStack Start SSR.
- Bundling the CJS printer into our ESM build (previous revision of this
PR) worked but pulled in the `tslib` CJS wrapper and grew
`dist/internal.mjs` from `12.82 kB` raw / `3.79 kB` gzip to `38.32 kB`
raw / `10.93 kB` gzip.
- Vendoring keeps `printAST` behavior byte-identical (so `condenseVars`
output and hashes are unchanged) at `16.58 kB` raw / `5.32 kB` gzip
(including the vendored file's MIT notice, preserved in the built
output), and only imports `TYPE`/`SKELETON_TYPE` from the package root,
which was already an import of `internal.mjs`.

## Testing
- `pnpm --filter generaltranslation build`
- `pnpm exec vitest run --config=./vitest.config.ts
src/derive/__tests__/condenseVars.test.ts
src/__tests__/core-esm.test.ts` in `packages/core`
- `pnpm --filter generaltranslation typecheck`
- `pnpm --filter generaltranslation test` (594 passed; existing
`condenseVars` tests unchanged from `odysseus`)
- new regression tests were run against the original FormatJS printer
first (green), then against the vendored printer (green, identical
outputs)
- reproduced the bug in `base/tanstack-start` with published
`generaltranslation@9.0.0-odysseus.5`: Vite dev served raw CJS
`printer.js` (`exports.printAST = ...`) to the client
- packed this branch's `generaltranslation` tarball and overrode it in
`base/tanstack-start`: dev server on port `34817` returned `200` for
`/`, `/ssr`, `/spa`; crawled all 167 modules of the dev client graph —
no `printer.js` module and no raw-CJS module served
- `pnpm build` + `vite preview` on port `34818`: `/`, `/ssr`, `/spa`
returned `200`
## TL;DR

Remove the deprecated `useGTClass` hook from public React, React Native,
and Next entry points.

## Code Changes

- Removed the `useGTClass` hook implementation and
`@generaltranslation/react-core/hooks` export.
- Removed `useGTClass` re-exports from `gt-react`, `gt-react-native`,
and `gt-next` entry points, including the RSC/type surfaces.
- Updated the `gt-next` RSC surface test and added a breaking changeset.

## Notes / Flags

- PR branch was force-corrected to be based on the actual remote
`odysseus` tip after the first push accidentally included local-only
odysseus history. It now contains 1 commit and 13 changed files.
- Earlier local verification on the same source edits passed: `pnpm
--filter @generaltranslation/react-core test`, `pnpm --filter gt-react
test`, `pnpm --filter gt-react-native test`, `pnpm --filter gt-next
test`, `pnpm lint:fix`, `pnpm format:fix`.
- `pnpm build` was blocked by a pre-existing `gt-sanity` build failure
from a missing `@microsoft/api-extractor` module in the shared pnpm
store. Minimal dependency/package builds were run instead; `gt-next`
JS/SWC build completed, but `emit-types` reports existing Next
type-resolution errors.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR removes the deprecated `useGTClass` hook and `getGTClass` helper
from the public APIs of `@generaltranslation/react-core`, `gt-react`,
`gt-react-native`, and `gt-next`, and replaces them with the new
`resolveCanonicalLocale` helper (introduced via a companion changeset).
Two major changesets document the breaks.

- `useGTClass` and `getGTClass` are removed consistently from all
client, server, RSC, and types entry points across `gt-react`,
`gt-react-native`, and `gt-next`.
- `resolveCanonicalLocale` is added to every package's public surface
and re-exported through the correct depth (`gt-i18n` → `react-core/pure`
→ `gt-react` → `gt-next`, with `gt-next/server` importing directly from
`gt-i18n` to avoid the React layer).
- The `gt-next` RSC test is updated to assert `resolveCanonicalLocale`
instead of `useGTClass`, and the `useShouldTranslate` hook is now the
named export that occupies the `useGTClass` slot in
`@generaltranslation/react-core/hooks`.

<details open><summary><h3>Confidence Score: 5/5</h3></summary>

Safe to merge — the change is a straightforward removal of a deprecated
hook and helper, with consistent updates across every public entry point
and a matching test update.

All four package surfaces (client, server, RSC, types) are updated in
lockstep. The new resolveCanonicalLocale helper traces cleanly through
gt-i18n → react-core/pure → gt-react → gt-next with no broken links. The
RSC surface test is updated to assert the new export identity. No logic
changes, only export-surface cleanup.

packages/react-core/src/hooks.ts — useShouldTranslate now occupies the
slot previously held by useGTClass in the public
@generaltranslation/react-core/hooks export, but the changeset does not
mention this addition.
</details>

<details><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| packages/react-core/src/hooks.ts | Swaps the useGTClass export for
useShouldTranslate in the @generaltranslation/react-core/hooks public
surface; useShouldTranslate is not mentioned in either changeset. |
| packages/react-core/src/hooks/utils.ts | Deletes the useGTClass
implementation; useShouldTranslate, useLocaleProperties, and
useLocaleDirection remain and are correct. |
| packages/i18n/src/helpers/locale.ts | Replaces getGTClass with
resolveCanonicalLocale; delegates to
getI18nConfig().resolveCanonicalLocale() correctly. |
| packages/next/src/server.ts | Adds resolveCanonicalLocale re-export
from gt-i18n directly, appropriate for the non-React server entry point.
|
| packages/next/src/__tests__/rscComponentWrappers.test.tsx | Updates
mock and assertions: removes getGTClass/useGTClass, adds
resolveCanonicalLocale identity check against the gt-react mock;
coverage aligns with changes. |
| packages/next/src/index.rsc.ts | Correctly removes useGTClass from
hooks re-export and swaps getGTClass for resolveCanonicalLocale in
function re-exports from gt-react. |
| packages/next/src/index.types.ts | Removes the useGTClass stub and the
getGTClass re-export; adds resolveCanonicalLocale; type surface is
consistent. |
| packages/react-native/src/index.tsx | Removes useGTClass and
getGTClass, adds resolveCanonicalLocale from react-core/pure; consistent
with gt-react surface. |
| .changeset/remove-use-gt-class.md | Documents the useGTClass removal
correctly, but useShouldTranslate's addition to
@generaltranslation/react-core/hooks is not mentioned. |
| .changeset/add-resolve-canonical-locale.md | Documents
resolveCanonicalLocale addition and getGTClass removal across all
affected packages. |

</details>

<details><summary><h3>Flowchart</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["gt-i18n\n(resolveCanonicalLocale)"]
    B["@generaltranslation/react-core/pure\n(re-exports resolveCanonicalLocale)"]
    C["gt-react\n(re-exports resolveCanonicalLocale)"]
    D["gt-react-native\n(re-exports resolveCanonicalLocale)"]
    E["gt-next index.client/server/rsc/types\n(re-exports resolveCanonicalLocale via gt-react)"]
    F["gt-next server.ts\n(re-exports resolveCanonicalLocale directly)"]

    A --> B
    B --> C
    C --> D
    C --> E
    A --> F

    style A fill:#e8f5e9
    style F fill:#fff9c4
    style E fill:#e3f2fd
```

</a>
<a href="#gh-dark-mode-only">

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["gt-i18n\n(resolveCanonicalLocale)"]
    B["@generaltranslation/react-core/pure\n(re-exports resolveCanonicalLocale)"]
    C["gt-react\n(re-exports resolveCanonicalLocale)"]
    D["gt-react-native\n(re-exports resolveCanonicalLocale)"]
    E["gt-next index.client/server/rsc/types\n(re-exports resolveCanonicalLocale via gt-react)"]
    F["gt-next server.ts\n(re-exports resolveCanonicalLocale directly)"]

    A --> B
    B --> C
    C --> D
    C --> E
    A --> F

    style A fill:#e8f5e9
    style F fill:#fff9c4
    style E fill:#e3f2fd
```

</a>
</details>

<sub>Reviews (2): Last reviewed commit: ["feat!: add
resolveCanonicalLocale
helper..."](dc98754)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=41733379)</sub>

<!-- /greptile_comment -->
## TL;DR

Clean up the `generaltranslation` public API surface for the next major
release.

## Code Changes

- Remove the unused `generaltranslation/core` subpath, source entry,
size-limit entry, and ESM export test.
- Remove stale endpoint types and rename the live `GT.enqueueFiles`
options type to `EnqueueFilesOptions`.
- Move `API_VERSION` to `generaltranslation/internal` and update the CLI
consumer.
- Drop duplicate `ApiError` accessors and prune dead `/internal`
exports.
- Export `derive`, `declareVar`, and `decodeVars` from the public
`generaltranslation` root, and repoint `gt-i18n` to that public entry.

## Notes / Flags

- Verification: `pnpm --filter generaltranslation test`, `pnpm --filter
gt test`, `pnpm lint:fix`, `pnpm format:fix`.
- The default shared pnpm store hit `ENOTEMPTY` during install, so
verification used an isolated temporary pnpm store under `/private/tmp`.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR trims the `generaltranslation` public API surface in preparation
for the next major release by removing the `/core` subpath, deleting
stale endpoint types, renaming `EnqueueOptions` → `EnqueueFilesOptions`,
moving `API_VERSION` to `/internal`, and promoting the derivation
helpers (`derive`, `declareVar`, `decodeVars`) from `/internal` to the
public root.

- **Subpath removal**: `generaltranslation/core` entry, its build
target, size-limit entry, and ESM smoke test are all deleted; the
`tsdown` config is updated in lockstep.
- **Type cleanup**: `EnqueueEntriesOptions/Result`,
`FetchTranslationsOptions/Result`, `RetrievedTranslations`,
`TranslationStatusResult`, `FileTranslationQuery`, and
`RequiredEnqueueFilesOptions` are dropped; grep confirms none are
consumed outside `packages/core` itself.
- **Public surface expansion**: `derive`, `declareVar`, `decodeVars`
move from `/internal` to the public root; `gt-i18n` is updated to import
from the public entry, while `/internal` consumers are left untouched
(both exports remain in `internal.ts`).

<details open><summary><h3>Confidence Score: 5/5</h3></summary>

Safe to merge — all removed symbols were confirmed unused outside of
packages/core, every updated import path resolves correctly, and the
derivation helpers remain accessible from both the public root and
/internal for existing consumers.

The changes are a straightforward deletion of dead code and
reorganization of export paths. A codebase-wide grep confirmed that none
of the removed types are consumed anywhere outside the core package
itself. The validateFileFormatTransforms, defaultTimeout, and
VAR_NAME_IDENTIFIER removals from /internal are likewise safe — no
external package imported them via that path. The only cross-package
import that changed (API_VERSION in the CLI) is correctly updated.

No files require special attention. The changeset bump type question was
raised in a prior review thread and is the only open item.
</details>

<details><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| packages/core/src/index.ts | Promotes derive/declareVar/decodeVars to
public root, renames EnqueueOptions to EnqueueFilesOptions throughout,
and removes the API_VERSION re-export; all call sites updated correctly.
|
| packages/core/src/internal.ts | Removes validateFileFormatTransforms
and defaultTimeout from /internal exports, drops VAR_NAME_IDENTIFIER,
and adds API_VERSION; no external consumer was importing any of the
three removed symbols from generaltranslation/internal. |
| packages/core/src/types.ts | Drops stale type re-exports; redirects
EnqueueFilesOptions to the new translate/enqueueFiles source; unused
FormatJsxChildren/FormatVariable aliases removed. |
| packages/core/src/translate/enqueueFiles.ts | Type renamed from
EnqueueOptions to EnqueueFilesOptions; fields
description/version/_versionId (already unused in the request body)
removed; function logic unchanged. |
| packages/core/src/errors/ApiError.ts | Removes getCode() and
getMessage() accessor methods; code and message are public fields so
callers can still access them directly. |
| packages/i18n/src/index.ts | Switches derive/declareVar/decodeVars
import from generaltranslation/internal to the public generaltranslation
root; all three remain exported from both locations so existing
/internal consumers are unaffected. |
| packages/cli/src/utils/fetch.ts | One-line import update: API_VERSION
now sourced from generaltranslation/internal rather than the public
root, matching the internal.ts change. |
| .changeset/core-api-surface-cleanup.md | Records patch bumps for
generaltranslation, gt-i18n, and gt; the bump type versus the nature of
the removals has been flagged in a prior review thread. |
| packages/core/tsdown.config.mts | Removes src/core.ts from the build
entry list, aligned with the /core subpath deletion. |
| packages/core/package.json | Drops the ./core exports block and its
typesVersions entry; remaining subpaths are unchanged. |

</details>

<details><summary><h3>Flowchart</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph Before["Before (public exports)"]
        A1["generaltranslation (root)"]
        A2["generaltranslation/core"]
        A3["generaltranslation/internal"]
        A1 -->|"API_VERSION"| CLI1["CLI"]
        A2 -->|"formatMessage, standardizeLocale, ..."| Consumer1["External consumers"]
        A3 -->|"derive, declareVar, decodeVars"| GT_I18N1["gt-i18n"]
        A3 -->|"validateFileFormatTransforms, defaultTimeout, VAR_NAME_IDENTIFIER"| Internal1["(leaked internals)"]
    end

    subgraph After["After (public exports)"]
        B1["generaltranslation (root)"]
        B2["generaltranslation/internal"]
        B1 -->|"derive, declareVar, decodeVars"| GT_I18N2["gt-i18n"]
        B2 -->|"API_VERSION"| CLI2["CLI"]
        B2 -->|"derive, declareVar, decodeVars"| Other["other /internal consumers (unchanged)"]
        DELETED["generaltranslation/core removed"]
    end
```

</a>
<a href="#gh-dark-mode-only">

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    subgraph Before["Before (public exports)"]
        A1["generaltranslation (root)"]
        A2["generaltranslation/core"]
        A3["generaltranslation/internal"]
        A1 -->|"API_VERSION"| CLI1["CLI"]
        A2 -->|"formatMessage, standardizeLocale, ..."| Consumer1["External consumers"]
        A3 -->|"derive, declareVar, decodeVars"| GT_I18N1["gt-i18n"]
        A3 -->|"validateFileFormatTransforms, defaultTimeout, VAR_NAME_IDENTIFIER"| Internal1["(leaked internals)"]
    end

    subgraph After["After (public exports)"]
        B1["generaltranslation (root)"]
        B2["generaltranslation/internal"]
        B1 -->|"derive, declareVar, decodeVars"| GT_I18N2["gt-i18n"]
        B2 -->|"API_VERSION"| CLI2["CLI"]
        B2 -->|"derive, declareVar, decodeVars"| Other["other /internal consumers (unchanged)"]
        DELETED["generaltranslation/core removed"]
    end
```

</a>
</details>

<sub>Reviews (2): Last reviewed commit: ["feat!: clean up
generaltranslation
publi..."](36844ab)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=41726727)</sub>

<!-- /greptile_comment -->
## TL;DR

Clean up the `gt-i18n` API surface by removing dead subpaths, internal
exports, unused types/methods, and stale lint config.

## Code Changes

- Removed the `gt-i18n/fallbacks` package subpath and its
size-limit/build metadata while leaving fallback helpers on the root
entrypoint.
- Pruned dead `gt-i18n/internal` exports and deleted the
`getGTServicesEnabled` implementation/test.
- Removed duplicate locale helpers from `gt-i18n/internal`; updated
React RSC imports to use root `gt-i18n` for moved symbols.
- Removed dead `I18nConfig` methods, the dead JSX resolver type,
public/internal type surface noise, and the stale i18n-context oxlint
override.
- Moved lookup option normalization into
`@generaltranslation/react-core` for its remaining internal use.

## Notes / Flags

- Per coordination note, this PR does not touch `getVersionId` or
`getGTClass`; both remain in their existing root and `/internal`
positions.
- Verification run: `pnpm build`, `pnpm --filter gt-i18n test`, `pnpm
--filter @generaltranslation/react-core test`, `pnpm --filter gt-react
test`, `pnpm lint:fix`, `pnpm format:fix`.
- `pnpm lint:fix` completed with warnings only; warnings were
pre-existing/outside this API cleanup.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR trims the `gt-i18n` public API surface as a major-version
cleanup: it removes the `./fallbacks` subpath, prunes dead exports from
`gt-i18n/internal` (locale helpers, resolve helpers,
`getGTServicesEnabled`, `isI18nConfigInitialized`), narrows public type
exports, and removes dead `I18nConfig` methods. Consumer packages
(`gt-react`, `react-core`) are updated to use the new import paths.

- **Fallbacks subpath removed**: `gtFallback`/`mFallback` remain
accessible via the root `gt-i18n` entry; the dedicated `./fallbacks`
subpath and its build metadata are gone.
- **Locale helpers re-homed**: `getLocale`, `getRegion`, and friends are
removed from `gt-i18n/internal` and consumed directly from the `gt-i18n`
root in `index.rsc.ts` and downstream packages.
- **Broken `getGTClass` re-export**: `internal.ts` now exports
`getGTClass` from `./helpers/locale`, but that function is not defined
there — it is only a method on `I18nConfig`. No current consumer imports
it as a standalone function, so there is no runtime regression today,
but the declared API is invalid.

<details open><summary><h3>Confidence Score: 4/5</h3></summary>

Safe to merge with caution — one broken re-export in `gt-i18n/internal`
should be fixed before shipping downstream.

The bulk of the cleanup is straightforward and well-verified by the
existing test suite. The single actionable concern is the `export {
getGTClass } from './helpers/locale'` line in `internal.ts`:
`getGTClass` is not an exported function in that file, so the
declaration is invalid and any future consumer importing it would
receive `undefined`. No existing code does so today, preventing a
runtime regression right now, but it leaves a hole in the published API
that is easy to miss.

packages/i18n/src/internal.ts — the `getGTClass` re-export from
`helpers/locale` needs a corresponding standalone wrapper function or a
corrected source module.
</details>

<details><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| packages/i18n/src/internal.ts | Removes several exports (locale
helpers, resolveJsx*, interpolateIcuMessage, getGTServicesEnabled,
isI18nConfigInitialized), but adds a broken re-export: `getGTClass` from
`helpers/locale` where that function doesn't exist. |
| packages/react/src/index.rsc.ts | Moved `getLocale`/`getRegion`
imports from `gt-i18n/internal` to the `gt-i18n` root; both are properly
exported there. |
| packages/react-core/src/functions/translation/t.ts | Moves
`LookupOptionsFor` import from `gt-i18n/types` to
`gt-i18n/internal/types`; correct and consistent with the type
relocation. |
| packages/i18n/src/internal-types.ts | Narrows the config type
re-export from `export type *` to just `GTConfig`, preventing
`RenderMethod` from leaking into `gt-i18n/internal/types`. |
| packages/i18n/package.json | Removes the `./fallbacks` subpath export
and its typesVersions entry; fallback helpers remain accessible via the
root entry. |
| packages/i18n/src/types.ts | Removes `ResolveJsxTranslationFunction`,
`TranslationMetadata`, `TranslationOptions`, `LookupOptions`, and
`NormalizedLookupOptions` from the public `gt-i18n/types` surface;
expected as a major-version cleanup. |

</details>

<details><summary><h3>Flowchart</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["gt-i18n (root)"] -->|"getLocale, getRegion, getLocales\ngtFallback, mFallback (was ./fallbacks)"| B["Consumers"]
    C["gt-i18n/internal"] -->|"createLookupOptions\nrenderDictionaryEntry/Object\nI18nCache, I18nConfig, ..."| B
    C -->|"getGTClass ❌ (broken export)\npoints to helpers/locale\nwhere it doesn't exist"| D["undefined at runtime"]
    E["gt-i18n/internal/types"] -->|"LookupOptions\nNormalizedLookupOptions\nTranslationMetadata"| B
    F["gt-i18n/types"] -->|"GTTranslationOptions\nJsxTranslationOptions\n..."| B
    G["gt-react RSC (index.rsc.ts)"] -->|"getLocale, getRegion\n(moved from internal → root)"| A
    G -->|"getGT, getI18nConfig, ..."| C
```

</a>
<a href="#gh-dark-mode-only">

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["gt-i18n (root)"] -->|"getLocale, getRegion, getLocales\ngtFallback, mFallback (was ./fallbacks)"| B["Consumers"]
    C["gt-i18n/internal"] -->|"createLookupOptions\nrenderDictionaryEntry/Object\nI18nCache, I18nConfig, ..."| B
    C -->|"getGTClass ❌ (broken export)\npoints to helpers/locale\nwhere it doesn't exist"| D["undefined at runtime"]
    E["gt-i18n/internal/types"] -->|"LookupOptions\nNormalizedLookupOptions\nTranslationMetadata"| B
    F["gt-i18n/types"] -->|"GTTranslationOptions\nJsxTranslationOptions\n..."| B
    G["gt-react RSC (index.rsc.ts)"] -->|"getLocale, getRegion\n(moved from internal → root)"| A
    G -->|"getGT, getI18nConfig, ..."| C
```

</a>
</details>

<sub>Reviews (2): Last reviewed commit: ["fix: remove stale gt-i18n
internal
expor..."](06ccb9a)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=41726783)</sub>

<!-- /greptile_comment -->
#1825)

## TL;DR

Remove the `useShouldTranslate` export that #1816 accidentally re-added
to the public `@generaltranslation/react-core/hooks` entry.

## Code Changes

- Drop `useShouldTranslate` from the export list in
`packages/react-core/src/hooks.ts`. The hook remains available
internally from `./hooks/utils`.
- Add a patch changeset for `@generaltranslation/react-core`.

## Notes / Flags

- #1815 had already removed `useShouldTranslate` from `/hooks` (see
`.changeset/clean-react-core-api-surface.md`); the export slipped back
in via a conflict resolution when #1816 replaced `useGTClass` in the
same export slot.
- No sibling package (`gt-react`, `gt-react-native`, `gt-next`)
re-exports it, so this is the only site.
- Verification: `pnpm --filter @generaltranslation/react-core test` (46
tests pass), `oxfmt --check` on changed files.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR removes the accidental re-export of `useShouldTranslate` from
the public `@generaltranslation/react-core/hooks` entry point. The hook
was originally removed in #1815 but slipped back in during a conflict
resolution in #1816 when `useGTClass` was replaced in the same export
slot.

- **`packages/react-core/src/hooks.ts`**: Drops `useShouldTranslate`
from the `./hooks/utils` re-export group; the hook remains available
internally and all other public exports are unaffected.
- **`.changeset/remove-use-should-translate-export.md`**: Adds a
patch-level changeset accurately describing the removal as fixing an
accidental public exposure of an internal hook.

<details open><summary><h3>Confidence Score: 5/5</h3></summary>

Safe to merge — a one-line removal of an unintended export with a
correct changeset and no impact on internal consumers.

The change is a single-line deletion from a public re-export group.
`useShouldTranslate` continues to exist in `./hooks/utils` for internal
use, so no internal callers break. No sibling packages re-export the
hook, and the changeset correctly marks this as a patch. There are no
logic changes, no new code paths, and nothing that could introduce a
regression.

No files require special attention.
</details>

<details><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| packages/react-core/src/hooks.ts | Removes `useShouldTranslate` from
the public hooks entry point; all remaining exports and formatting are
correct. |
| .changeset/remove-use-should-translate-export.md | Adds a patch-level
changeset for `@generaltranslation/react-core` accurately describing the
removed accidental export. |

</details>

<sub>Reviews (1): Last reviewed commit: ["fix: remove accidental
useShouldTranslat..."](081907d)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=41757259)</sub>

<!-- /greptile_comment -->
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 odysseus, this PR
will be updated.

⚠️⚠️⚠️⚠️⚠️⚠️

`odysseus` is currently in **pre mode** so this branch has prereleases
rather than normal releases. If you want to exit prereleases, run
`changeset pre exit` on `odysseus`.

⚠️⚠️⚠️⚠️⚠️⚠️

# Releases
## gt-i18n@1.0.0-odysseus.9

### Major Changes

- 463a8db: Add a config-aware `resolveCanonicalLocale` helper and remove
the public `getGTClass` helper.
- 1f53e42: Clean up the `gt-i18n` public API surface by removing dead
subpaths, internal exports, and unused types.

### Patch Changes

- b72c30b: Clean up the `generaltranslation` public API surface for the
next major.

Removes the unused `generaltranslation/core` subpath, stale endpoint
types, duplicate `ApiError` accessors, and dead `/internal` exports.
Moves `API_VERSION` to `generaltranslation/internal`, exports the
derivation helpers from the public root, and points `gt-i18n` at that
public entry.

- bea8233: Statically gate dev hot-reload code paths (tracked resolver
invalidation, missing-translation queue, T hot-reload fallbacks, getGT
dev preload) behind `process.env.NODE_ENV !== 'production'` so bundlers
can drop them from production builds. Behavior is unchanged: the
existing runtime `isDevHotReloadEnabled()` check still applies in
development.
- Updated dependencies [b72c30b]
- Updated dependencies [d5cf2d3]
  - generaltranslation@9.0.0-odysseus.6
  - @generaltranslation/supported-locales@2.1.2-odysseus.6
## gt-next@11.0.0-odysseus.16

### Major Changes

- 463a8db: Add a config-aware `resolveCanonicalLocale` helper and remove
the public `getGTClass` helper.
- 463a8db: Remove the deprecated `useGTClass` hook from public entry
points.
- 40db0c5: Remove `useVersionId` from public package entrypoints.

The `getVersionId` helper remains available from public function
entrypoints and `gt-i18n/internal`.

### Patch Changes

- 1a483ae: Remove deprecated Next internal packages.
- ce8a665: Clean up the `gt-next` API surface for the next major
prerelease.

Removes the deprecated `initGT` config alias and the redundant
`gt-next/types` subpath. Moves the hidden dictionary and loader subpaths
under `gt-next/internal/*`, updates the Next config alias plumbing to
match, and adjusts CLI setup detection so it no longer treats `initGT`
as a valid existing config wrapper.

- Updated dependencies [463a8db]
- Updated dependencies [b72c30b]
- Updated dependencies [bea8233]
- Updated dependencies [5736d58]
- Updated dependencies [1f53e42]
- Updated dependencies [7744c55]
- Updated dependencies [463a8db]
- Updated dependencies [e343775]
- Updated dependencies [40db0c5]
- Updated dependencies [d5cf2d3]
  - gt-i18n@1.0.0-odysseus.9
  - @generaltranslation/react-core@11.0.0-odysseus.16
  - gt-react@11.0.0-odysseus.16
  - generaltranslation@9.0.0-odysseus.6
  - @generaltranslation/compiler@1.3.25-odysseus.8
  - @generaltranslation/supported-locales@2.1.2-odysseus.6
## gt-react@11.0.0-odysseus.16

### Major Changes

- 463a8db: Add a config-aware `resolveCanonicalLocale` helper and remove
the public `getGTClass` helper.
- 463a8db: Remove the deprecated `useGTClass` hook from public entry
points.
- 40db0c5: Remove `useVersionId` from public package entrypoints.

The `getVersionId` helper remains available from public function
entrypoints and `gt-i18n/internal`.

### Patch Changes

- 1f53e42: Clean up the `gt-i18n` public API surface by removing dead
subpaths, internal exports, and unused types.
- 7744c55: Remove RSC-only render internals from the `gt-react`
react-server entry while keeping the compiler-injected internal
translation exports available. The react-server declaration surface now
also includes `RenderPipeline` and `RenderPreparedT`, matching the other
`gt-react` entries.
- Updated dependencies [463a8db]
- Updated dependencies [b72c30b]
- Updated dependencies [bea8233]
- Updated dependencies [5736d58]
- Updated dependencies [1f53e42]
- Updated dependencies [463a8db]
- Updated dependencies [e343775]
- Updated dependencies [40db0c5]
- Updated dependencies [d5cf2d3]
  - gt-i18n@1.0.0-odysseus.9
  - @generaltranslation/react-core@11.0.0-odysseus.16
  - generaltranslation@9.0.0-odysseus.6
  - @generaltranslation/supported-locales@2.1.2-odysseus.6
## @generaltranslation/react-core@11.0.0-odysseus.16

### Major Changes

- 463a8db: Add a config-aware `resolveCanonicalLocale` helper and remove
the public `getGTClass` helper.
- 463a8db: Remove the deprecated `useGTClass` hook from public entry
points.
- 40db0c5: Remove `useVersionId` from public package entrypoints.

The `getVersionId` helper remains available from public function
entrypoints and `gt-i18n/internal`.

### Patch Changes

- bea8233: Statically gate dev hot-reload code paths (tracked resolver
invalidation, missing-translation queue, T hot-reload fallbacks, getGT
dev preload) behind `process.env.NODE_ENV !== 'production'` so bundlers
can drop them from production builds. Behavior is unchanged: the
existing runtime `isDevHotReloadEnabled()` check still applies in
development.
- 5736d58: Use production no-op stubs for dev hot-reload hooks so
bundlers can drop more dev-only hot-reload code.
- 1f53e42: Clean up the `gt-i18n` public API surface by removing dead
subpaths, internal exports, and unused types.
- e343775: Remove the accidental `useShouldTranslate` export from
`@generaltranslation/react-core/hooks`. The hook is an internal
implementation detail and was never meant to be public.
- Updated dependencies [463a8db]
- Updated dependencies [b72c30b]
- Updated dependencies [bea8233]
- Updated dependencies [1f53e42]
- Updated dependencies [d5cf2d3]
  - gt-i18n@1.0.0-odysseus.9
  - generaltranslation@9.0.0-odysseus.6
  - @generaltranslation/supported-locales@2.1.2-odysseus.6
## gt-react-native@11.0.0-odysseus.16

### Major Changes

- 463a8db: Add a config-aware `resolveCanonicalLocale` helper and remove
the public `getGTClass` helper.
- 463a8db: Remove the deprecated `useGTClass` hook from public entry
points.
- 40db0c5: Remove `useVersionId` from public package entrypoints.

The `getVersionId` helper remains available from public function
entrypoints and `gt-i18n/internal`.

### Patch Changes

- Updated dependencies [463a8db]
- Updated dependencies [b72c30b]
- Updated dependencies [bea8233]
- Updated dependencies [5736d58]
- Updated dependencies [1f53e42]
- Updated dependencies [463a8db]
- Updated dependencies [e343775]
- Updated dependencies [40db0c5]
- Updated dependencies [d5cf2d3]
  - gt-i18n@1.0.0-odysseus.9
  - @generaltranslation/react-core@11.0.0-odysseus.16
  - generaltranslation@9.0.0-odysseus.6
  - @generaltranslation/supported-locales@2.1.2-odysseus.6
## gt@2.14.51-odysseus.7

### Patch Changes

- b72c30b: Clean up the `generaltranslation` public API surface for the
next major.

Removes the unused `generaltranslation/core` subpath, stale endpoint
types, duplicate `ApiError` accessors, and dead `/internal` exports.
Moves `API_VERSION` to `generaltranslation/internal`, exports the
derivation helpers from the public root, and points `gt-i18n` at that
public entry.

- ce8a665: Clean up the `gt-next` API surface for the next major
prerelease.

Removes the deprecated `initGT` config alias and the redundant
`gt-next/types` subpath. Moves the hidden dictionary and loader subpaths
under `gt-next/internal/*`, updates the Next config alias plumbing to
match, and adjusts CLI setup detection so it no longer treats `initGT`
as a valid existing config wrapper.

- Updated dependencies [b72c30b]
- Updated dependencies [d5cf2d3]
  - generaltranslation@9.0.0-odysseus.6
  - @generaltranslation/python-extractor@0.2.23-odysseus.6
  - @generaltranslation/supported-locales@2.1.2-odysseus.6
## @generaltranslation/compiler@1.3.25-odysseus.8

### Patch Changes

- Updated dependencies [b72c30b]
- Updated dependencies [d5cf2d3]
  - generaltranslation@9.0.0-odysseus.6
## generaltranslation@9.0.0-odysseus.6

### Patch Changes

- b72c30b: Clean up the `generaltranslation` public API surface for the
next major.

Removes the unused `generaltranslation/core` subpath, stale endpoint
types, duplicate `ApiError` accessors, and dead `/internal` exports.
Moves `API_VERSION` to `generaltranslation/internal`, exports the
derivation helpers from the public root, and points `gt-i18n` at that
public entry.

- d5cf2d3: Vendor the FormatJS ICU AST printer so the ESM internal build
no longer imports the CommonJS `printer.js` subpath, which Vite-based
dev servers (e.g. TanStack Start) cannot load. Serialized output is
byte-identical, so hashes are unchanged.
## gtx-cli@2.14.51-odysseus.7

### Patch Changes

- Updated dependencies [b72c30b]
- Updated dependencies [ce8a665]
  - gt@2.14.51-odysseus.7
## locadex@1.0.186-odysseus.7

### Patch Changes

- Updated dependencies [b72c30b]
- Updated dependencies [ce8a665]
  - gt@2.14.51-odysseus.7
## gt-node@1.0.0-odysseus.9

### Patch Changes

- Updated dependencies [463a8db]
- Updated dependencies [b72c30b]
- Updated dependencies [bea8233]
- Updated dependencies [1f53e42]
- Updated dependencies [d5cf2d3]
  - gt-i18n@1.0.0-odysseus.9
  - generaltranslation@9.0.0-odysseus.6
## @generaltranslation/python-extractor@0.2.23-odysseus.6

### Patch Changes

- Updated dependencies [b72c30b]
- Updated dependencies [d5cf2d3]
  - generaltranslation@9.0.0-odysseus.6
## gt-sanity@2.0.18-odysseus.8

### Patch Changes

- Updated dependencies [b72c30b]
- Updated dependencies [d5cf2d3]
  - generaltranslation@9.0.0-odysseus.6
## @generaltranslation/supported-locales@2.1.2-odysseus.6

### Patch Changes

- Updated dependencies [b72c30b]
- Updated dependencies [d5cf2d3]
  - generaltranslation@9.0.0-odysseus.6
## gt-tanstack-start@11.0.0-odysseus.16

### Patch Changes

- Updated dependencies [463a8db]
- Updated dependencies [b72c30b]
- Updated dependencies [bea8233]
- Updated dependencies [5736d58]
- Updated dependencies [1f53e42]
- Updated dependencies [7744c55]
- Updated dependencies [463a8db]
- Updated dependencies [e343775]
- Updated dependencies [40db0c5]
- Updated dependencies [d5cf2d3]
  - gt-i18n@1.0.0-odysseus.9
  - @generaltranslation/react-core@11.0.0-odysseus.16
  - gt-react@11.0.0-odysseus.16
  - generaltranslation@9.0.0-odysseus.6

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## Summary
- alias gt-react's type-only initializeGT export to the local SRA
initializer
- add a patch changeset for gt-react

## Verification
- pnpm --filter gt-react typecheck

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR fixes the `initializeGT` type export in `gt-react` by aliasing
it to the local `initializeGTSRA` initializer instead of incorrectly
re-exporting from `@generaltranslation/react-core/pure`. The
`index.types.ts` file is used as the declared types for both the server
(`index.server.ts`) and browser (`index.client.ts`) runtime entry
points.

- **Server alignment**: `index.server.ts` already exports
`initializeGTSRA as initializeGT`, so `index.types.ts` now correctly
reflects the real server-side implementation.
- **Browser alignment**: The browser runtime (`index.client.ts`) uses
`initializeGTSRAClient as initializeGT`, which shares the same type
signature as `initializeGTSRA` (`(config: I18nConfigParams &
ReactI18nCacheParams) => void`), so the shared types file remains
accurate for browser consumers as well.
- A patch changeset is included to version-bump `gt-react`
appropriately.

<details open><summary><h3>Confidence Score: 5/5</h3></summary>

A minimal, targeted types-only fix with no runtime behavior changes.

The change removes an outdated re-export of `initializeGT` from the
upstream `react-core/pure` package and replaces it with a direct alias
of the local `initializeGTSRA` function. Both the server
(`index.server.ts`) and browser (`index.client.ts`) runtimes already
resolve `initializeGT` to functions with the identical TypeScript
signature `(config: I18nConfigParams & ReactI18nCacheParams) => void`,
so the new types file faithfully reflects what consumers receive at
runtime. No production logic is changed.

No files require special attention. The two touched files
(`index.types.ts` and the changeset) are straightforward.
</details>

<details><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| packages/react/src/index.types.ts | Replaces the previously incorrect
`initializeGT` re-export (from react-core/pure) with a local alias of
`initializeGTSRA`, aligning declared types with the actual server and
browser runtime implementations. |
| .changeset/fix-react-initialize-gt-types.md | Adds a patch changeset
for `gt-react` describing the shipped-types fix. |

</details>

<details><summary><h3>Sequence Diagram</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Consumer as gt-react Consumer
    participant Types as index.types.ts (types)
    participant Server as index.server.ts (runtime)
    participant Client as index.client.ts (browser runtime)
    participant SRA as initializeGTSRA
    participant SRAClient as initializeGTSRAClient

    note over Types,SRA: Before this PR
    Consumer->>Types: import initializeGT
    Types-->>Consumer: initializeGT (from react-core/pure — wrong type)
    Consumer->>Server: call initializeGT (runtime)
    Server->>SRA: initializeGTSRA (actual impl)

    note over Types,SRA: After this PR
    Consumer->>Types: import initializeGT
    Types-->>Consumer: initializeGT (aliased to initializeGTSRA — correct type)
    Consumer->>Server: call initializeGT (runtime)
    Server->>SRA: initializeGTSRA ✅ types match
    Consumer->>Client: call initializeGT (browser runtime)
    Client->>SRAClient: initializeGTSRAClient (same signature) ✅ types match
```

</a>
<a href="#gh-dark-mode-only">

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Consumer as gt-react Consumer
    participant Types as index.types.ts (types)
    participant Server as index.server.ts (runtime)
    participant Client as index.client.ts (browser runtime)
    participant SRA as initializeGTSRA
    participant SRAClient as initializeGTSRAClient

    note over Types,SRA: Before this PR
    Consumer->>Types: import initializeGT
    Types-->>Consumer: initializeGT (from react-core/pure — wrong type)
    Consumer->>Server: call initializeGT (runtime)
    Server->>SRA: initializeGTSRA (actual impl)

    note over Types,SRA: After this PR
    Consumer->>Types: import initializeGT
    Types-->>Consumer: initializeGT (aliased to initializeGTSRA — correct type)
    Consumer->>Server: call initializeGT (runtime)
    Server->>SRA: initializeGTSRA ✅ types match
    Consumer->>Client: call initializeGT (browser runtime)
    Client->>SRAClient: initializeGTSRAClient (same signature) ✅ types match
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["fix: repair gt-react
initializeGT
types"](b27c155)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=41762381)</sub>

<!-- /greptile_comment -->
## Summary

- Mark Changesets prerelease mode as `exit` so the normal `main` release
workflow can generate the stable release PR after `odysseus` merges.
- Stop the release workflow from triggering on `odysseus`, preventing
another Odysseus prerelease run once pre mode has exited.

## Validation

- `pnpm exec oxfmt --check .changeset/pre.json
.github/workflows/release.yml`
- `git diff --check`
- `pnpm exec changeset status --since origin/main --verbose`
- Throwaway worktree: ran `pnpm run version-packages` with
`GITHUB_TOKEN` to confirm Changesets removes `.changeset/pre.json`,
consumes queued changesets, and produces stable package versions.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR exits the Changesets prerelease mode for the `odysseus` release
and stops the release workflow from firing on the `odysseus` branch,
preparing the repo for a stable publish once `odysseus` merges to
`main`.

- **`.changeset/pre.json`**: Flips `mode` from `\"pre\"` to `\"exit\"`,
so the next `version-packages` run on `main` will consume all 60+ queued
changesets and produce stable semver versions rather than another
prerelease.
- **`.github/workflows/release.yml`**: Removes `odysseus` from the
`on.push.branches` trigger, preventing any spurious prerelease CI run
now that exit mode is set. The existing `odysseus-release` job (`if:
github.ref_name == 'odysseus'`) becomes unreachable dead code but causes
no harm.

<details open><summary><h3>Confidence Score: 5/5</h3></summary>

Two-line config-only change with no production logic modified; safe to
merge.

Both changes are mechanical and well-scoped: flipping a single JSON
field in pre.json and removing one branch from a workflow trigger. The
author validated the end-to-end behavior in a throwaway worktree before
opening the PR. The odysseus-release job left in the workflow is
harmless dead code — it can only fire when ref_name == 'odysseus', which
can no longer happen since odysseus was removed from the trigger list.

No files require special attention.
</details>

<details><summary><h3>Important Files Changed</h3></summary>

| Filename | Overview |
|----------|----------|
| .changeset/pre.json | Sets Changesets mode from "pre" to "exit",
signaling the next version-packages run should consume all queued
changesets and produce stable (non-prerelease) versions. |
| .github/workflows/release.yml | Removes the `odysseus` branch from the
`on.push.branches` trigger, preventing the workflow from running on any
further pushes to `odysseus`. The `odysseus-release` job remains in the
file but is now unreachable dead code since no push to `odysseus` can
trigger the workflow. |

</details>

<details><summary><h3>Sequence Diagram</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Dev as Developer
    participant Odysseus as odysseus branch
    participant Main as main branch
    participant CS as Changesets Action
    participant NPM as npm registry

    Dev->>Odysseus: Merge this PR (mode: exit, remove odysseus trigger)
    Note over Odysseus: pre.json mode = "exit"<br/>No more CI runs on odysseus

    Odysseus->>Main: "Merge odysseus -> main"
    Main->>CS: Push triggers Release workflow (main only)
    CS->>CS: Detects exit mode in pre.json
    CS->>Main: Opens stable release PR (consumes queued changesets, removes pre.json)
    Main->>CS: Release PR merged
    CS->>NPM: Publishes stable package versions
```

</a>
<a href="#gh-dark-mode-only">

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Dev as Developer
    participant Odysseus as odysseus branch
    participant Main as main branch
    participant CS as Changesets Action
    participant NPM as npm registry

    Dev->>Odysseus: Merge this PR (mode: exit, remove odysseus trigger)
    Note over Odysseus: pre.json mode = "exit"<br/>No more CI runs on odysseus

    Odysseus->>Main: "Merge odysseus -> main"
    Main->>CS: Push triggers Release workflow (main only)
    CS->>CS: Detects exit mode in pre.json
    CS->>Main: Opens stable release PR (consumes queued changesets, removes pre.json)
    Main->>CS: Release PR merged
    CS->>NPM: Publishes stable package versions
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["chore: exit odysseus
prerelease
mode"](13e425c)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=41721295)</sub>

<!-- /greptile_comment -->
…n-post-squash

chore: merge main into odysseus (history reconciliation after squash)
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.

7 participants