Skip to content

fix: remove unused gt-i18n internal entrypoints - #1714

Open
eoinest wants to merge 168 commits into
mainfrom
e/odysseus/remove-unused-i18n-helpers
Open

fix: remove unused gt-i18n internal entrypoints#1714
eoinest wants to merge 168 commits into
mainfrom
e/odysseus/remove-unused-i18n-helpers

Conversation

@eoinest

@eoinest eoinest commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Summary

  • remove unused JSX helper functions from gt-i18n internals
  • stop exporting translation helper implementations from gt-i18n/internal except createLookupOptions
  • remove the gt-i18n/fallbacks package entrypoint while keeping fallback functions on the main entrypoint

Testing

  • pnpm --filter gt-i18n test
  • pnpm build
  • pnpm lint

No changeset added per request.

Greptile Summary

This PR cleans up the gt-i18n package by removing two redundant public API surfaces: the gt-i18n/fallbacks sub-entrypoint (whose exports already live on the main index) and the six resolve-helper function exports from gt-i18n/internal. The change is internally consistent across all affected layers — build config, package.json exports, source files, and tests all align.

  • Deletes src/fallbacks.ts and all references to the ./fallbacks entrypoint; gtFallback and mFallback remain accessible via the main gt-i18n import.
  • Narrows gt-i18n/internal to export only createLookupOptions from helpers.ts; resolveJsx and resolveJsxWithFallback are fully removed from source, while the remaining resolve helpers are kept as package-internal utilities.
  • Removes the corresponding size-limit entry and build target for fallbacks.

Confidence Score: 5/5

Safe to merge — all changes are removals of redundant or unused exports, and every layer (build config, package.json, source, tests) is updated consistently.

The diff is a pure subtraction: no new logic is introduced, the deleted functions were unused externally, and the fallback functions remain accessible on the main entrypoint. The build config, exports map, size-limit config, and test file all agree with the source changes.

No files require special attention.

Important Files Changed

Filename Overview
.size-limit.cjs Removes the gt-i18n/fallbacks entry from size-limit checks, consistent with removing that entrypoint.
packages/i18n/package.json Removes the ./fallbacks export entry, its typesVersions entry, and the gt-i18n/fallbacks path alias. Consistent with the deleted fallbacks.ts entry file.
packages/i18n/src/fallbacks.ts File deleted. Both gtFallback and mFallback are already re-exported from the main index.ts, so the dedicated entrypoint was redundant.
packages/i18n/src/internal.ts Stops re-exporting resolve helper functions from gt-i18n/internal, retaining only createLookupOptions. Narrowing of the public API surface.
packages/i18n/src/translation-functions/internal/helpers.ts Deletes resolveJsx and resolveJsxWithFallback; remaining functions (resolveJsxWithRuntimeFallback, resolveStringContent, etc.) are kept for internal use but no longer re-exported from the package boundary.
packages/i18n/src/translation-functions/internal/tests/helpers.test.ts Removes tests for the deleted resolveJsx function; remaining tests import directly from helpers.ts and are unaffected.
packages/i18n/tsdown.config.mts Removes src/fallbacks.ts from the list of build entry points, matching the package.json export removal.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph Before
        A[gt-i18n] -->|main index| B[gtFallback / mFallback / t / msg / ...]
        A -->|gt-i18n/fallbacks| C[gtFallback / mFallback]
        A -->|gt-i18n/internal| D[createLookupOptions\nresolveJsx\nresolveJsxWithFallback\nresolveJsxWithRuntimeFallback\nresolveStringContent\nresolveStringContentWithFallback\nresolveStringContentWithRuntimeFallback\n...]
    end

    subgraph After
        E[gt-i18n] -->|main index| F[gtFallback / mFallback / t / msg / ...]
        E -->|gt-i18n/internal| G[createLookupOptions\n...]
    end
Loading
%%{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
        A[gt-i18n] -->|main index| B[gtFallback / mFallback / t / msg / ...]
        A -->|gt-i18n/fallbacks| C[gtFallback / mFallback]
        A -->|gt-i18n/internal| D[createLookupOptions\nresolveJsx\nresolveJsxWithFallback\nresolveJsxWithRuntimeFallback\nresolveStringContent\nresolveStringContentWithFallback\nresolveStringContentWithRuntimeFallback\n...]
    end

    subgraph After
        E[gt-i18n] -->|main index| F[gtFallback / mFallback / t / msg / ...]
        E -->|gt-i18n/internal| G[createLookupOptions\n...]
    end
Loading

Reviews (1): Last reviewed commit: "fix: remove unused gt-i18n internal entr..." | Re-trigger Greptile

eoinest and others added 27 commits June 27, 2026 03:35
## Summary
- Delete internal barrel-only `index.ts` and barrel `types.ts` files
outside package entrypoints.
- Rewrite imports and entrypoint re-exports to point directly at
defining source files.
- Preserve package entrypoints such as root `src/index.ts` and public
`src/types.ts` exports.
- Add patch changeset `.changeset/remove-source-barrel-exports.md`.

## Testing
- `pnpm build`
- `pnpm --filter @generaltranslation/compiler --filter
generaltranslation --filter gt-i18n --filter gt-node --filter gt-sanity
test`
- `pnpm lint`

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1677"><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=1785119624&installation_id=127936663&pr_number=1677&repository=generaltranslation%2Fgt&return_to=https%3A%2F%2Fgithub.com%2Fgeneraltranslation%2Fgt%2Fpull%2F1677&signature=811838818a55cee8af653538368b8cc8125df83bcb381038594fde160bda29cd"><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 refactor removes internal barrel-only `index.ts` and `types.ts`
files scattered throughout the monorepo's packages (`cli`, `compiler`,
`core`, `i18n`, `node`, `sanity`) and replaces them with direct imports
pointing at the defining source files. Public package entrypoints
(`src/index.ts`, `src/types.ts`, `src/internal.ts`, `src/fallbacks.ts`)
are preserved and updated in place.

- Barrel files deleted include `packages/i18n/src/i18n-cache/index.ts`,
`packages/node/src/helpers/index.ts`,
`packages/sanity/src/serialization/index.ts`, and 10+ others across the
packages; all call-sites within the repo are updated in the same commit.
- Multi-level re-export chains (e.g. `src/index.ts` →
`translation-functions/derive/index.ts` → `generaltranslation/internal`)
are collapsed into single-hop `export { ... } from
'generaltranslation/internal'` statements.
- Test files are updated in lock-step to import from concrete source
paths, and a search across all packages finds no remaining consumers of
the deleted barrel modules.

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

All barrel files are cleanly removed with every call-site in the repo
updated in lock-step; no export gaps found.

The change is purely structural — no logic is added or removed. A manual
cross-check of every deleted barrel against the rest of the codebase
found no remaining consumers, and the multi-hop re-export chains are
faithfully collapsed into equivalent single-hop exports. Tests and the
public package entrypoints are untouched in semantics.

No files require special attention; all 44 changed files consistently
apply the same mechanical import-path update.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/i18n/src/internal.ts | Expands two barrel-level wildcard
re-exports into 10+ named direct exports, preserving the exact same
public API surface. |
| packages/i18n/src/index.ts | Replaces barrel re-exports for msg,
derive, fallbacks, and helpers with direct file imports; collapses
derive chain to a single hop from generaltranslation/internal. |
| packages/node/src/index.ts | Expands three barrel re-exports (setup,
translation-functions, helpers) into explicit named exports; all symbols
from the old barrels are accounted for. |
| packages/sanity/src/index.ts | Updates imports of
BaseDocumentSerializer, BaseDocumentDeserializer, BaseDocumentMerger,
and related types to point directly at their defining files after the
serialization barrel is deleted. |
| packages/compiler/src/passes/basePass.ts | Replaces namespace import
`import * as p from '../processing'` with 14 individual named imports
from specific files; functional behavior is identical. |
| packages/core/src/internal.ts | Inlines the seven exports from the
deleted derive/index.ts barrel directly, preserving the same public
surface. |
| packages/sanity/src/serialization/index.ts | Deleted — all prior
consumers within the package have been updated to import from the
concrete source files directly. |
| packages/node/src/types.ts | Inlines six type re-exports from the
deleted translation-functions/types.ts barrel directly from
gt-i18n/types, preserving the full type surface. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph Before["Before: Multi-hop barrel chains"]
        A1["node/src/index.ts"] -->|"export * from"| B1["node/src/translation-functions/index.ts"]
        B1 -->|"export from"| C1["gt-i18n (index)"]
        A1 -->|"export * from"| B2["node/src/helpers/index.ts"]
        B2 -->|"export from"| C1
        A1 -->|"export * from"| B3["node/src/setup/index.ts"]
        B3 -->|"export from"| D1["setup/initializeGT.ts"]

        E1["i18n/src/index.ts"] -->|"export * from"| F1["translation-functions/derive/index.ts"]
        F1 -->|"export from"| G1["generaltranslation/internal"]

        H1["sanity/src/index.ts"] -->|"from"| I1["serialization/index.ts"]
        I1 -->|"export from"| J1["serialization/BaseDocumentMerger.ts"]
    end

    subgraph After["After: Direct single-hop imports"]
        A2["node/src/index.ts"] -->|"export from"| C2["gt-i18n (index)"]
        A2 -->|"export from"| D2["setup/initializeGT.ts"]
        A2 -->|"export from"| D3["setup/withGT.ts"]
        A2 -->|"export from"| E2["helpers/getRequestLocale.ts"]

        F2["i18n/src/index.ts"] -->|"export from"| G2["generaltranslation/internal"]

        H2["sanity/src/index.ts"] -->|"from"| J2["serialization/BaseDocumentMerger.ts"]
        H2 -->|"from"| K2["serialization/serialize/index.ts"]
        H2 -->|"from"| L2["serialization/deserialize/BaseDocumentDeserializer.ts"]
    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: Multi-hop barrel chains"]
        A1["node/src/index.ts"] -->|"export * from"| B1["node/src/translation-functions/index.ts"]
        B1 -->|"export from"| C1["gt-i18n (index)"]
        A1 -->|"export * from"| B2["node/src/helpers/index.ts"]
        B2 -->|"export from"| C1
        A1 -->|"export * from"| B3["node/src/setup/index.ts"]
        B3 -->|"export from"| D1["setup/initializeGT.ts"]

        E1["i18n/src/index.ts"] -->|"export * from"| F1["translation-functions/derive/index.ts"]
        F1 -->|"export from"| G1["generaltranslation/internal"]

        H1["sanity/src/index.ts"] -->|"from"| I1["serialization/index.ts"]
        I1 -->|"export from"| J1["serialization/BaseDocumentMerger.ts"]
    end

    subgraph After["After: Direct single-hop imports"]
        A2["node/src/index.ts"] -->|"export from"| C2["gt-i18n (index)"]
        A2 -->|"export from"| D2["setup/initializeGT.ts"]
        A2 -->|"export from"| D3["setup/withGT.ts"]
        A2 -->|"export from"| E2["helpers/getRequestLocale.ts"]

        F2["i18n/src/index.ts"] -->|"export from"| G2["generaltranslation/internal"]

        H2["sanity/src/index.ts"] -->|"from"| J2["serialization/BaseDocumentMerger.ts"]
        H2 -->|"from"| K2["serialization/serialize/index.ts"]
        H2 -->|"from"| L2["serialization/deserialize/BaseDocumentDeserializer.ts"]
    end
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["refactor: remove internal
barrel
exports"](1e56780)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40241819)</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@2.14.51-odysseus.1

### Patch Changes

- [#1677](#1677)
[`87d6320`](87d6320)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove internal
source barrel exports and update imports to reference defining files
directly.

- Updated dependencies
[[`87d6320`](87d6320)]:
  - generaltranslation@9.0.0-odysseus.1
  - @generaltranslation/python-extractor@0.2.23-odysseus.1
  - @generaltranslation/supported-locales@2.1.2-odysseus.1
## @generaltranslation/compiler@1.3.25-odysseus.1

### Patch Changes

- [#1677](#1677)
[`87d6320`](87d6320)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove internal
source barrel exports and update imports to reference defining files
directly.

- Updated dependencies
[[`87d6320`](87d6320)]:
  - generaltranslation@9.0.0-odysseus.1
## generaltranslation@9.0.0-odysseus.1

### Patch Changes

- [#1677](#1677)
[`87d6320`](87d6320)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove internal
source barrel exports and update imports to reference defining files
directly.
## gtx-cli@2.14.51-odysseus.1

### Patch Changes

- Updated dependencies
[[`87d6320`](87d6320)]:
  - gt@2.14.51-odysseus.1
## gt-i18n@1.0.0-odysseus.1

### Patch Changes

- [#1677](#1677)
[`87d6320`](87d6320)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove internal
source barrel exports and update imports to reference defining files
directly.

- Updated dependencies
[[`87d6320`](87d6320)]:
  - generaltranslation@9.0.0-odysseus.1
  - @generaltranslation/supported-locales@2.1.2-odysseus.1
## locadex@1.0.186-odysseus.1

### Patch Changes

- Updated dependencies
[[`87d6320`](87d6320)]:
  - gt@2.14.51-odysseus.1
## gt-next@11.0.0-odysseus.4

### Patch Changes

- Updated dependencies
[[`87d6320`](87d6320)]:
  - @generaltranslation/compiler@1.3.25-odysseus.1
  - generaltranslation@9.0.0-odysseus.1
  - gt-i18n@1.0.0-odysseus.1
  - gt-react@11.0.0-odysseus.4
  - @generaltranslation/react-core@11.0.0-odysseus.4
  - @generaltranslation/supported-locales@2.1.2-odysseus.1
## @generaltranslation/gt-next-lint@15.0.0-odysseus.4

### Patch Changes

- Updated dependencies []:
  - gt-next@11.0.0-odysseus.4
## gt-node@1.0.0-odysseus.1

### Patch Changes

- [#1677](#1677)
[`87d6320`](87d6320)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove internal
source barrel exports and update imports to reference defining files
directly.

- Updated dependencies
[[`87d6320`](87d6320)]:
  - generaltranslation@9.0.0-odysseus.1
  - gt-i18n@1.0.0-odysseus.1
## @generaltranslation/python-extractor@0.2.23-odysseus.1

### Patch Changes

- Updated dependencies
[[`87d6320`](87d6320)]:
  - generaltranslation@9.0.0-odysseus.1
## gt-react@11.0.0-odysseus.4

### Patch Changes

- Updated dependencies
[[`87d6320`](87d6320)]:
  - generaltranslation@9.0.0-odysseus.1
  - gt-i18n@1.0.0-odysseus.1
  - @generaltranslation/react-core@11.0.0-odysseus.4
  - @generaltranslation/supported-locales@2.1.2-odysseus.1
## @generaltranslation/react-core@11.0.0-odysseus.4

### Patch Changes

- Updated dependencies
[[`87d6320`](87d6320)]:
  - generaltranslation@9.0.0-odysseus.1
  - gt-i18n@1.0.0-odysseus.1
  - @generaltranslation/supported-locales@2.1.2-odysseus.1
## gt-react-native@11.0.0-odysseus.4

### Patch Changes

- Updated dependencies
[[`87d6320`](87d6320)]:
  - generaltranslation@9.0.0-odysseus.1
  - gt-i18n@1.0.0-odysseus.1
  - @generaltranslation/react-core@11.0.0-odysseus.4
  - @generaltranslation/supported-locales@2.1.2-odysseus.1
## gt-sanity@2.0.18-odysseus.3

### Patch Changes

- [#1677](#1677)
[`87d6320`](87d6320)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove internal
source barrel exports and update imports to reference defining files
directly.

- Updated dependencies
[[`87d6320`](87d6320)]:
  - generaltranslation@9.0.0-odysseus.1
## @generaltranslation/supported-locales@2.1.2-odysseus.1

### Patch Changes

- Updated dependencies
[[`87d6320`](87d6320)]:
  - generaltranslation@9.0.0-odysseus.1
## gt-tanstack-start@11.0.0-odysseus.4

### Patch Changes

- Updated dependencies
[[`87d6320`](87d6320)]:
  - generaltranslation@9.0.0-odysseus.1
  - gt-i18n@1.0.0-odysseus.1
  - gt-react@11.0.0-odysseus.4
  - @generaltranslation/react-core@11.0.0-odysseus.4

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1682"><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=1785123539&installation_id=127936663&pr_number=1682&repository=generaltranslation%2Fgt&return_to=https%3A%2F%2Fgithub.com%2Fgeneraltranslation%2Fgt%2Fpull%2F1682&signature=f79d7524f1943dddc089904896641070e1d7c91e85829ccbc7e97a05a6f1af11"><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 -->

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## Summary
- Organize entrypoint exports into component, hook, function, type, and
helper sections.
- Replace re-export-only imports with direct `export ... from` syntax
where the binding is not needed locally.
- Preserve the existing export surface.
- Add patch changeset `.changeset/organize-entrypoint-exports.md`.

## Testing
- `pnpm build`
- `pnpm lint`
- `pnpm --filter generaltranslation test`
- `pnpm --filter gt-next test:js`
- `pnpm --filter gt-react-native test`
- `pnpm --filter gt-sanity test`
- export-name comparison against
`origin/e/odysseus/remove-source-barrel-exports`

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1678"><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=1785120739&installation_id=127936663&pr_number=1678&repository=generaltranslation%2Fgt&return_to=https%3A%2F%2Fgithub.com%2Fgeneraltranslation%2Fgt%2Fpull%2F1678&signature=e72ed5832a40b17bd2c8b3f927104c075ca0d49cef814532bd4d3c26524ac592"><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 reorganizes the entrypoint exports across 9 packages by grouping
them into labeled sections (Components, Hooks, Functions, Types) and
converting the `import … + export {}` pattern to direct `export … from`
syntax where no local binding is needed. No behavioral or API surface
changes are intended.

- **`packages/core`** (`id.ts`, `internal.ts`) and **`packages/format`**
(`types.ts`) now use `export { default as … }` for default-export
re-exports and `export type {}` for pure type re-exports, which is
semantically equivalent to the prior pattern.
- **`packages/next`** (`index.client.ts`, `index.rsc.ts`,
`index.server.ts`), **`packages/react-native`**, and
**`packages/sanity`** now have each entrypoint organized into clearly
labeled sections; modules that are consumed locally *and* re-exported
(e.g., `translateAction`, `documentInternationalization` in sanity)
correctly keep their top-level `import` and use a bare `export { name }`
re-export instead of `export … from`.

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

Safe to merge — purely organizational, no logic or API surface changes.

Every changed file is a package entrypoint barrel. The refactor converts
local import+re-export pairs into direct export … from statements and
groups the results into labeled sections. Default-export re-exports
(getPluralForm, hashTemplate, isVariable, TranslationsTab) were verified
against their source files and all have the expected default exports.
Modules that are consumed locally inside the gtPlugin closure
(translateAction, documentInternationalization) correctly retain their
top-level imports alongside the bare re-export. The export surface was
manually cross-checked against the base branch for all nine files and no
additions or removals were found.

No files require special attention.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/core/src/id.ts | Converts import+re-export of
hashSource/hashString/hashTemplate to direct export … from syntax; both
source files have confirmed default/named exports. |
| packages/core/src/internal.ts | Switches to direct export … from for
all re-exports;
JsxChildren/_Content/JsxChild/JsxElement/LocaleProperties are now
correctly marked export type (they are pure interfaces); runtime values
(isVariable, encode/decode, etc.) keep value exports. |
| packages/format/src/types.ts | Each type now exports directly from its
canonical source module; CustomMapping, CutoffFormatOptions, Variable,
VariableType, LocaleProperties all preserved; HTML_CONTENT_PROPS value
export unchanged. |
| packages/next/src/index.client.ts | Large gt-react import block
replaced with three direct export sections; local type imports
(GetServerSideProps, WithGTServerSideProps) still present for the
parseLocale/withGTServerSideProps stub functions. |
| packages/next/src/index.rsc.ts | Individual per-component export lines
replace a single combined block; getTranslationsSnapshotRscError import
moved before initializeGT() in source order, but static imports are
always hoisted in ESM so execution order is unchanged. |
| packages/next/src/index.server.ts | parseLocale and
withGTServerSideProps converted from local import+export to direct
export … from; all Components/Hooks/Functions from gt-react preserved
with same names. |
| packages/react-native/src/index.tsx | Two separate hook export blocks
from react-core/hooks consolidated into one alphabetical block;
GTProvider, useSetLocale/Region/EnableI18n,
useLocaleSelector/RegionSelector, useLocaleDirection/VersionId still
exported from their original local modules. |
| packages/sanity/src/index.ts | Imports used locally in the gtPlugin
closure (translateAction, documentInternationalization,
TranslationsTool, SECRETS_NAMESPACE, etc.) are kept as top-level
imports; items only re-exported are converted to direct export … from. |

</details>

<sub>Reviews (1): Last reviewed commit: ["refactor: organize entrypoint
exports"](f5c6c5a)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40242913)</sub>

<!-- /greptile_comment -->
## Summary
- Convert default source exports to named exports in core, next,
react-core, and react-native source files
- Update internal imports, re-exports, and Vitest mocks to use named
exports
- Keep `gt-next/link` default-only to match `next/link`, so swapping
imports only changes the package path
- Keep Next generated fallback modules compatible with both default and
named dictionary/loader exports
- Change `gt-react-native/plugin` to expose the named `plugin` export

## Testing
- pnpm lint
- pnpm build
- pnpm --filter generaltranslation typecheck
- pnpm --filter @generaltranslation/react-core typecheck
- pnpm --filter gt-react build
- pnpm --filter gt-next typecheck
- pnpm --filter gt-react-native typecheck
- pnpm --filter gt-node typecheck
- pnpm --filter gt-tanstack-start typecheck
- pnpm --filter generaltranslation test
- pnpm --filter @generaltranslation/react-core test
- pnpm --filter gt-next test:js
- pnpm --filter gt-react-native test

Note: `pnpm typecheck` currently fails on
`packages/react/src/i18n-cache/BrowserI18nCache.ts` because
`ImportMeta.env` is not typed on this branch; focused typechecks above
pass after building `gt-react`.

Changeset added: `.changeset/remove-default-source-exports.md`.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR mechanically converts `export default` to named exports across
`packages/core`, `packages/next`, `packages/react-core`, and
`packages/react-native`. All internal imports are updated to match, and
consumer code that dynamically `require()`s these modules already has
backward-compatible resolution (`?.default || ?.namedExport`).

- **Internal source modules** (`translate/`, `utils/`,
`react-core/utils/`) are pure refactors with no behavior change — every
call site is updated in the same PR.
- **`gt-next/link`** keeps a default export (to match `next/link`) but
drops the re-exported named `Link`; all in-repo consumers use `import
Link from 'gt-next/link'` (default), so no breakage.
- **`gt-react-native/plugin`** moves from a default export to a named
`plugin` export, which is a breaking public-API change documented in the
changeset.

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

Safe to merge — this is a mechanical export style refactor with no
behavior changes in internal logic and explicit backward-compatible
fallbacks in every dynamic consumer.

Every changed file follows the same pattern: export default
function/const → export function/const. All internal call sites are
updated in the same PR. Dynamic consumers (getDictionary.ts,
resolveDictionaryLoader.ts, resolveTranslationLoader.ts, initGT.rsc.ts)
already resolve both .default and the new named export. The two
public-API breaks (gt-react-native/plugin default→named, gt-next/link
dropping named Link) are intentional, pre-release, and documented in the
changeset.

No files require special attention. The most externally visible changes
are in packages/react-native/src/plugin.ts (public API) and
packages/next/src/link.ts (drops named re-export), both of which are
intentional and documented.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/next/src/link.ts | Drops the named `Link` re-export; only
default export remains to mirror `next/link`. All in-repo usages use the
default import. |
| packages/react-native/src/plugin.ts | Public entrypoint
`gt-react-native/plugin` now exports named `plugin` instead of default;
breaking change documented in the changeset. |
| packages/react-native/src/plugin-dir/index.ts | Babel plugin function
renamed from anonymous default to named `plugin` export; re-exported
cleanly from `plugin.ts`. |
| packages/next/src/dictionary/getDictionary.ts | Backward-compatible
resolution: tries `.default` first then `.dictionary` for TS/JS
dictionaries; handles both old and new generated module shapes. |
| packages/next/src/_dictionary.ts | Fallback sentinel changed from
`export default {}` to `export const dictionary = {}`; still throws on
evaluation so the catch block in getDictionary handles it identically. |
| packages/next/src/_load-dictionary.ts | Fallback sentinel changed to
`export const loadDictionary = undefined`; `resolveDictionaryLoader.ts`
already checks `?.default || ?.loadDictionary` for compatibility. |
| packages/next/src/_load-translations.ts | Identical pattern to
`_load-dictionary.ts`; `resolveTranslationLoader.ts` handles both
`.default` and `.loadTranslations`. |
| packages/react-native/src/NativeGtReactNative.ts | TurboModule
instance moved from default export to named `GtReactNative`; both
consumer files (`getNativeLocales.ts`, `nativeStore.ts`) updated in the
same PR. |
| packages/core/src/translate/translateMany.ts | Function overload pair
correctly converted from `export default` to named `export`; both
overload signature and implementation updated consistently. |
| packages/core/src/index.ts | All default-import callers updated to
named-import destructuring; no missed imports found. |
| packages/react-core/src/pure.ts | All `export { default as X }`
re-exports converted to `export { X }`; consistent with updated source
files. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["gt-next/link\n(public entrypoint)"] -->|"export { Link as default }"| B["link/Link.tsx\nnamed export only"]
    C["gt-react-native/plugin\n(public entrypoint)"] -->|"export { plugin }"| D["plugin-dir/index.ts\nexport function plugin()"]
    E["gt-next/_dictionary\n(webpack alias / fallback)"] -->|"bundledDictionary.default\n|| bundledDictionary.dictionary"| F["getDictionary.ts\nbackward-compatible resolution"]
    G["gt-next/_load-dictionary\n(webpack alias / fallback)"] -->|"?.default || ?.loadDictionary"| H["resolveDictionaryLoader.ts\nbackward-compatible resolution"]
    I["gt-next/_load-translations\n(webpack alias / fallback)"] -->|"?.default || ?.loadTranslations"| J["resolveTranslationLoader.ts\nbackward-compatible resolution"]
    K["gt-next/internal/_getLocale\ngt-next/internal/_getRegion"] -->|"?.default || ?.getLocale/.getRegion"| L["initGT.rsc.ts\nbackward-compatible resolution"]

    style A fill:#ffd700,color:#000
    style C fill:#ffd700,color:#000
    style F fill:#90ee90,color:#000
    style H fill:#90ee90,color:#000
    style J fill:#90ee90,color:#000
    style L fill:#90ee90,color:#000
```

</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-next/link\n(public entrypoint)"] -->|"export { Link as default }"| B["link/Link.tsx\nnamed export only"]
    C["gt-react-native/plugin\n(public entrypoint)"] -->|"export { plugin }"| D["plugin-dir/index.ts\nexport function plugin()"]
    E["gt-next/_dictionary\n(webpack alias / fallback)"] -->|"bundledDictionary.default\n|| bundledDictionary.dictionary"| F["getDictionary.ts\nbackward-compatible resolution"]
    G["gt-next/_load-dictionary\n(webpack alias / fallback)"] -->|"?.default || ?.loadDictionary"| H["resolveDictionaryLoader.ts\nbackward-compatible resolution"]
    I["gt-next/_load-translations\n(webpack alias / fallback)"] -->|"?.default || ?.loadTranslations"| J["resolveTranslationLoader.ts\nbackward-compatible resolution"]
    K["gt-next/internal/_getLocale\ngt-next/internal/_getRegion"] -->|"?.default || ?.getLocale/.getRegion"| L["initGT.rsc.ts\nbackward-compatible resolution"]

    style A fill:#ffd700,color:#000
    style C fill:#ffd700,color:#000
    style F fill:#90ee90,color:#000
    style H fill:#90ee90,color:#000
    style J fill:#90ee90,color:#000
    style L fill:#90ee90,color:#000
```

</a>
</details>

<sub>Reviews (2): Last reviewed commit: ["fix: preserve default link
export"](b55b9c4)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40241802)</sub>

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

Removes `@deprecated` symbols that have **no remaining consumers
anywhere in the monorepo** — the kind of public-API shedding appropriate
for the odysseus major.

**core (`generaltranslation`)**
- Deprecated types `_Content`, `Update`, `Request`,
`ContentTranslationResult`, `IcuTranslationResult`,
`JsxTranslationResult`
- The `_Content` re-export from `generaltranslation/internal`

**gt-i18n**
- Renamed-alias re-exports: `I18nManager`, `getI18nManager`,
`setI18nManager`, `I18nManagerConstructorParams`, `I18nManagerConfig`
(use `I18nCache` / `getI18nCache` / `setI18nCache` /
`I18nCacheConstructorParams` / `I18nCacheConfig`)
- The all-deprecated wrapper files `sync-translation-resolution.ts`
(`resolveTranslationSync`, `resolveTranslationSyncWithFallback`) and
`jsx-resolution.ts` (`resolveJsxTranslation`), their barrel exports, and
the standalone test (the non-deprecated `resolveTranslation` /
`resolveJsx` and the separate `I18nCache.resolveTranslationSync` method
are untouched)

Net **−273 lines**.

## Verification

- Full monorepo build passes (21/21).
- Tests pass: core 432, gt-i18n 245, gt-node, react-core 267, gt-react
12, gt-next 191.
- Repo-wide grep (incl. `examples/`, `tests/apps/`, docs, JSON) confirms
zero references to every removed symbol. `Update`/`Request`
name-collisions were checked and are unrelated (web `Request`,
`NextRequest`, etc.).

## Deliberately NOT removed (still live — need a real decision, not
cleanup)

These are deprecated but still wired in, so they're left for separate
review:
- `internalInitializeGTSPA` (re-exported by `react-core/pure`, used by
gt-react)
- core enqueue `_versionId` / `description` (still used across the CLI)
- next `STATIC_REQUEST_FUNCTIONS` / `StaticRequestFunctions` /
`experimentalLocaleResolutionParam` (used by config resolution)
- `I18nCache` lifecycle hooks (`createLifecycleCallbacks`,
`LifecycleCallbacks`, `lifecycle` field)
- Deprecated option fields (`context` / `$_locales` / `$_source`, cli
`maxChars` / `variablesOptions`) that may still be read at runtime for
back-compat

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1674"><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=1785119029&installation_id=127936663&pr_number=1674&repository=generaltranslation%2Fgt&return_to=https%3A%2F%2Fgithub.com%2Fgeneraltranslation%2Fgt%2Fpull%2F1674&signature=23dc09ea52f6cb562ac592f143987364f8b63b6314953604874808046376cc40"><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 removes deprecated public API symbols from the
`generaltranslation` core and `gt-i18n` packages as part of the odysseus
major-version cleanup. No logic changes are made — every removed symbol
was verified to have zero consumers in the monorepo before deletion.

- **core**: Drops deprecated types `_Content`, `Update`, `Request`,
`ContentTranslationResult`, `IcuTranslationResult`, and
`JsxTranslationResult`, plus the `_Content` re-export from
`generaltranslation/internal`.
- **gt-i18n**: Removes the `I18nManager` / `getI18nManager` /
`setI18nManager` renamed aliases and their type counterparts, deletes
the `sync-translation-resolution.ts` and `jsx-resolution.ts` deprecated
wrapper files with their barrel exports and test, and updates two JSDoc
comments that still referenced the old function name.

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

Pure dead-code removal with no logic changes; canonical replacements for
every removed symbol remain in place and all monorepo consumers have
been verified clean.

Every deleted symbol was either a thin wrapper that delegated directly
to an existing non-deprecated function, or a type alias for an existing
type. The underlying implementations (`I18nCache`, `getI18nCache`,
`setI18nCache`, `resolveJsx`, `resolveTranslation`, etc.) are untouched.
The PR description documents a full monorepo build and test pass (21/21
packages, all test suites green) and a repo-wide grep confirming zero
references to any removed symbol.

No files require special attention — all changes are deletions of
confirmed-dead code.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/core/src/types.ts | Removes six deprecated type definitions
(`_Content`, `Update`, `Request`, `ContentTranslationResult`,
`IcuTranslationResult`, `JsxTranslationResult`) — pure deletion with no
logic change. |
| packages/core/src/internal.ts | Drops `_Content` from the type import
and the `internal` barrel export; no other changes. |
| packages/i18n/src/internal.ts | Removes three deprecated re-exports
(`I18nManager`, `getI18nManager`, `setI18nManager`); the underlying
`I18nCache`, `getI18nCache`, and `setI18nCache` exports remain
untouched. |
| packages/i18n/src/internal-types.ts | Removes deprecated type aliases
`I18nManagerConstructorParams` and `I18nManagerConfig`; canonical types
`I18nCacheConstructorParams` and `I18nCacheConfig` are still exported
above. |
|
packages/i18n/src/translation-functions/internal/sync-translation-resolution.ts
| Deleted entirely — contained only `resolveTranslationSync` and
`resolveTranslationSyncWithFallback`, both deprecated thin wrappers over
`helpers.ts`. |
| packages/i18n/src/translation-functions/internal/jsx-resolution.ts |
Deleted entirely — contained only `resolveJsxTranslation`, a deprecated
one-line wrapper over `resolveJsx`. |
|
packages/i18n/src/translation-functions/internal/__tests__/resolveTranslationSync.test.ts
| Deleted — the four test cases covered `resolveTranslationSync` which
no longer exists. |
| packages/i18n/src/translation-functions/internal/index.ts | Removes
the two barrel re-exports for the deleted `sync-translation-resolution`
and `jsx-resolution` modules. |
| packages/i18n/src/translation-functions/types/functions.ts | Updates a
JSDoc comment to reference `resolveJsx()` instead of the now-deleted
`resolveJsxTranslation()`. |
| packages/i18n/src/translation-functions/types/options.ts | Updates a
JSDoc comment to reference `resolveJsx()` instead of the now-deleted
`resolveJsxTranslation()`. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph core["generaltranslation (core)"]
        direction TB
        A["types.ts\n❌ _Content\n❌ Update\n❌ Request\n❌ ContentTranslationResult\n❌ IcuTranslationResult\n❌ JsxTranslationResult"]
        B["internal.ts\n❌ re-export _Content"]
    end

    subgraph i18n["gt-i18n"]
        direction TB
        C["internal.ts\n❌ I18nManager alias\n❌ getI18nManager alias\n❌ setI18nManager alias"]
        D["internal-types.ts\n❌ I18nManagerConstructorParams alias\n❌ I18nManagerConfig alias"]
        E["sync-translation-resolution.ts\n❌ resolveTranslationSync\n❌ resolveTranslationSyncWithFallback"]
        F["jsx-resolution.ts\n❌ resolveJsxTranslation"]
        G["internal/index.ts\n❌ barrel exports for E & F"]
        H["__tests__/resolveTranslationSync.test.ts\n❌ deleted test file"]
    end

    subgraph keep["Still live (out of scope)"]
        I18nCache["I18nCache ✅"]
        getI18nCache["getI18nCache ✅"]
        setI18nCache["setI18nCache ✅"]
        resolveJsx["resolveJsx ✅"]
        resolveTranslation["resolveTranslation ✅"]
    end

    E --> G
    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
    subgraph core["generaltranslation (core)"]
        direction TB
        A["types.ts\n❌ _Content\n❌ Update\n❌ Request\n❌ ContentTranslationResult\n❌ IcuTranslationResult\n❌ JsxTranslationResult"]
        B["internal.ts\n❌ re-export _Content"]
    end

    subgraph i18n["gt-i18n"]
        direction TB
        C["internal.ts\n❌ I18nManager alias\n❌ getI18nManager alias\n❌ setI18nManager alias"]
        D["internal-types.ts\n❌ I18nManagerConstructorParams alias\n❌ I18nManagerConfig alias"]
        E["sync-translation-resolution.ts\n❌ resolveTranslationSync\n❌ resolveTranslationSyncWithFallback"]
        F["jsx-resolution.ts\n❌ resolveJsxTranslation"]
        G["internal/index.ts\n❌ barrel exports for E & F"]
        H["__tests__/resolveTranslationSync.test.ts\n❌ deleted test file"]
    end

    subgraph keep["Still live (out of scope)"]
        I18nCache["I18nCache ✅"]
        getI18nCache["getI18nCache ✅"]
        setI18nCache["setI18nCache ✅"]
        resolveJsx["resolveJsx ✅"]
        resolveTranslation["resolveTranslation ✅"]
    end

    E --> G
    F --> G
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["refactor: remove dead
@deprecated
public..."](800d6e6)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40241227)</sub>

<!-- /greptile_comment -->
## Summary
- pass `cacheExpiryTime: null` when initializing client-side i18n caches
in gt-react
- route gt-next browser/client-boundary initialization through a client
initializer that disables cache expiry

## Testing
- `pnpm --filter gt-react... build`
- `pnpm --filter gt-next typecheck`
- `pnpm --filter gt-react test`
- `pnpm --filter gt-next test:js`
- `pnpm lint`

Note: `pnpm --filter gt-react typecheck` is still blocked by the
existing `ImportMeta.env` typing issue in `BrowserI18nCache.ts`.

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1685"><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=1785345577&installation_id=127936663&pr_number=1685&repository=generaltranslation%2Fgt&return_to=https%3A%2F%2Fgithub.com%2Fgeneraltranslation%2Fgt%2Fpull%2F1685&signature=5f4723f456084250913d0be547530fa50d6718fc9d3e22a2b2430b5b15ae684e"><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 disables client-side i18n cache expiry in both `gt-react` and
`gt-next` by introducing thin wrapper initializers that force
`cacheExpiryTime: null` on every client-side cache construction,
preventing translations from being evicted while the browser session is
alive.

- **`gt-react`**: A new `initializeGTClient.ts` wraps
`internalInitializeGTSRA` with `cacheExpiryTime: null`, and
`initializeGTSPA.ts` is updated to pass the same override to
`BrowserI18nCache`. The public `initializeGT` export from `gt-react`'s
client barrel now points to this new wrapper instead of re-exporting
from `@generaltranslation/react-core/pure`.
- **`gt-next`**: A new `initGT.client.ts` wrapper calls `getParams()`
and forwards the params to the core initializer with
`nextI18nCacheParams.cacheExpiryTime` overridden to `null`. Both
`index.client.ts` and `client-boundary.tsx` are updated to import from
this new client-specific module.

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

Safe to merge — the changes are small, mechanically consistent wrappers
that apply a single override (cacheExpiryTime: null) to every
client-side cache initialisation path.

All six changed files follow the same straightforward pattern: introduce
a thin wrapper or change an import to route through a wrapper that
forces cacheExpiryTime to null. No new logic branches, no altered data
flow outside the cache, and the full test suite is reported green by the
author.

No files require special attention. The pre-existing ImportMeta.env
typing issue in BrowserI18nCache.ts (blocking gt-react typecheck) is
explicitly acknowledged in the PR description and is unrelated to these
changes.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/next/src/setup/initGT.client.ts | New wrapper that reads
params via getParams() and forwards them to the core initializer with
cacheExpiryTime forced to null; logic is correct and TypeScript-clean
(gt-next typecheck passes). |
| packages/next/src/index.client.ts | One-line import path change from
initGT to initGT.client; straightforward and correct. |
| packages/next/src/utils/client-boundary.tsx | Import path updated to
use the new client-specific initializer so the boundary component now
benefits from disabled cache expiry. |
| packages/react/src/setup/initializeGTClient.ts | New thin wrapper that
hardcodes cacheExpiryTime: null on top of any caller-supplied config
before delegating to internalInitializeGTSRA; correctly typed and
appropriately scoped. |
| packages/react/src/index.client.ts | Swaps the initializeGT re-export
from the react-core/pure barrel to the new initializeGTClient wrapper,
ensuring all gt-react consumers get cache-expiry-disabled behaviour by
default. |
| packages/react/src/setup/initializeGTSPA.ts | SPA initializer now
passes cacheExpiryTime: null when constructing BrowserI18nCache,
consistent with the broader client-side cache expiry fix. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant CI as Client Entry (index.client.ts)
    participant CB as ClientBoundary (client-boundary.tsx)
    participant GTC as initGT.client.ts (new)
    participant GT as initGT.ts (core)
    participant NIC as NextI18nCache

    Note over CI,NIC: gt-next client initialization (after PR)

    CI->>GTC: initializeGT()
    CB->>GTC: initializeGT()
    GTC->>GTC: getParams()
    GTC->>GT: coreInitializeGT with cacheExpiryTime null
    GT->>NIC: new NextI18nCache(nextI18nCacheParams)
    Note right of NIC: cacheExpiryTime = null, no expiry

    participant GTCR as initializeGTClient.ts (new)
    participant SRA as internalInitializeGTSRA
    participant GSPA as initializeGTSPA.ts
    participant BIC as BrowserI18nCache

    Note over CI,BIC: gt-react client initialization (after PR)

    CI->>GTCR: initializeGT(config)
    GTCR->>SRA: internalInitializeGTSRA with cacheExpiryTime null
    Note right of SRA: cacheExpiryTime = null, no expiry

    CI->>GSPA: initializeGTSPA(config)
    GSPA->>BIC: new BrowserI18nCache with cacheExpiryTime null
    Note right of BIC: cacheExpiryTime = null, no expiry
```

</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 CI as Client Entry (index.client.ts)
    participant CB as ClientBoundary (client-boundary.tsx)
    participant GTC as initGT.client.ts (new)
    participant GT as initGT.ts (core)
    participant NIC as NextI18nCache

    Note over CI,NIC: gt-next client initialization (after PR)

    CI->>GTC: initializeGT()
    CB->>GTC: initializeGT()
    GTC->>GTC: getParams()
    GTC->>GT: coreInitializeGT with cacheExpiryTime null
    GT->>NIC: new NextI18nCache(nextI18nCacheParams)
    Note right of NIC: cacheExpiryTime = null, no expiry

    participant GTCR as initializeGTClient.ts (new)
    participant SRA as internalInitializeGTSRA
    participant GSPA as initializeGTSPA.ts
    participant BIC as BrowserI18nCache

    Note over CI,BIC: gt-react client initialization (after PR)

    CI->>GTCR: initializeGT(config)
    GTCR->>SRA: internalInitializeGTSRA with cacheExpiryTime null
    Note right of SRA: cacheExpiryTime = null, no expiry

    CI->>GSPA: initializeGTSPA(config)
    GSPA->>BIC: new BrowserI18nCache with cacheExpiryTime null
    Note right of BIC: cacheExpiryTime = null, no expiry
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["fix: disable client i18n cache
expiry"](61df180)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40581150)</sub>

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

Removes deprecated translation options from `gt-i18n` as part of the
Odysseus major-version cleanup:

- **`context` dictionary option** → use `$context`. Removed from
`DictionaryOptions`, plus the fallback mapping in
`resolveDictionaryLookupOptions` and the validation branch in
`isDictionaryOptions`.
- **`$_locales` inline option** → use `$locale`. Removed from
`InlineTranslationOptionsFields`, the `$locale ?? $_locales` fallbacks
in ICU/string interpolation, and the exclusion list in
`extractVariables`.

## Stale comment/doc cleanup

These reference the same options and were updated for consistency (no
behavior change):

- `next/swc-plugin` comments now reference `$id`/`$context`/`$maxChars`.
- `@generaltranslation/compiler` `StringCollector` —
`TranslationContent` (extracted from `t()` calls) comments now use
`$`-prefixed keys. The parser already reads
`$context`/`$id`/`$maxChars`.
- `next` `tx()` JSDoc corrected to the actual `TxOptions` shape
(`$locale`/`$context`/`$maxChars`), and the
`variables`/`variableOptions` docs fixed to flat top-level variables
(`TxOptions extends FormatVariables`).

Left intentionally bare (not the i18n message-options form):
- JSX-prop `context` (`<T context="...">`, `TranslationJsx`).
- Backend translation-API request metadata `context` (`gt.translate` /
`EntryMetadata`).

## Testing

- `pnpm --filter gt-i18n test` → 244/244 passing.

A changeset (`gt-i18n` major) is included documenting the breaking
removal.

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1687"><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=1785348313&installation_id=127936663&pr_number=1687&repository=generaltranslation%2Fgt&return_to=https%3A%2F%2Fgithub.com%2Fgeneraltranslation%2Fgt%2Fpull%2F1687&signature=ec3064c77242644ba9591dbed52aea3eadf4e7bb487ad4ed311b65d1c215e3c7"><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 removes two deprecated translation options from `gt-i18n` as
part of the Odysseus major-version cleanup: the `context` dictionary key
(replaced by `$context`) and the `$_locales` inline option (replaced by
`$locale`). Comment and JSDoc updates in `next/tx.ts`, the SWC plugin,
and `@generaltranslation/compiler` are also included to align
documentation with the already-live `$`-prefixed API.

- **`context` removal**: `DictionaryOptions` no longer carries
`context`; `resolveDictionaryLookupOptions` no longer maps `context →
$context`; `isDictionaryOptions` no longer validates the `context`
string field. JS callers that still pass `context:` after upgrading will
have it leak as an unknown key (and potentially a template variable)
rather than being silently dropped — a silent regression for un-migrated
users, but intentional at a major version boundary.
- **`$_locales` removal**: Dropped from
`InlineTranslationOptionsFields`, both interpolation fallbacks, and the
`extractVariables` exclusion list. Any un-migrated JS caller passing
`$_locales` will now have that key treated as a user-defined template
variable instead of being ignored.
- All 244 tests pass; a major-version changeset is included.

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

Safe to merge for the Odysseus major version — all breaking removals are
intentional and the test suite passes cleanly.

The changes are a straightforward deprecation removal with 244 passing
tests. The one subtlety worth noting is that un-migrated JS callers
passing the old `context:` key will now have that value leak through
`resolveDictionaryLookupOptions` as part of `rest` rather than being
explicitly stripped. This means `context` could surface as a template
variable name in messages that happen to contain a `{context}`
placeholder — a quiet behavioral change rather than a hard error. The
same applies to `$_locales` no longer being excluded from
`extractVariables`. Both are expected consequences of a major-version
break, but neither has a dedicated migration-path test to document the
new runtime behavior for un-migrated callers.


`packages/i18n/src/i18n-cache/translations-manager/utils/dictionary-helpers.ts`
— the `resolveDictionaryLookupOptions` change silently changes how old
`context:` keys are handled at runtime.
</details>


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




| Filename | Overview |
|----------|----------|
|
packages/i18n/src/i18n-cache/translations-manager/utils/dictionary-helpers.ts
| Removes deprecated `context`→`$context` mapping in
`resolveDictionaryLookupOptions` and the `context` string validation in
`isDictionaryOptions`. Old JS callers passing `context:` will now have
it leak into `rest` as an unknown key instead of being silently dropped
or mapped. |
| packages/i18n/src/translation-functions/types/options.ts | Removes
deprecated `context` from `DictionaryOptions` and `$_locales` from
`InlineTranslationOptionsFields`. Clean type-level enforcement of the
new API surface. |
| packages/i18n/src/utils/extractVariables.ts | Removes `$_locales` from
the GT-reserved key exclusion list. Any caller (JS runtime) still
passing `$_locales` will now have that key treated as a user template
variable rather than silently dropped. |
|
packages/i18n/src/translation-functions/utils/interpolation/interpolateIcuMessage.ts
| Drops `$_locales` fallback from locale resolution — `options.$locale`
is now the only locale source passed to the ICU formatter. |
| packages/next/src/server-dir/runtime/tx.ts | JSDoc corrected to the
actual `TxOptions` shape (`$locale`, `$context`, `$maxChars`) and
variable interpolation docs updated to reflect flat top-level key
passing. No logic changes. |
| packages/compiler/src/state/StringCollector.ts | JSDoc comments
updated to use `$id`/`$context`/`$maxChars` in examples — no logic
change. |
| .changeset/remove-deprecated-context-locales-options.md |
Major-version changeset for `gt-i18n` documenting both breaking removals
clearly. |

</details>


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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Dictionary entry\n['Hello', options]"] --> B{isDictionaryOptions?}
    B -- "pass" --> C[resolveDictionaryLookupOptions]
    C --> D["Destructure: { $format, ...rest }"]
    D --> E["Return: { ...rest, $format: ICU }"]

    E --> F{context key present\nin old JS dict?}
    F -- "yes (un-migrated)" --> G["context leaks into rest\n→ treated as template variable"]
    F -- "no" --> H["Clean lookup options\n$context/$format/$maxChars"]

    I["Inline call: gt(msg, options)"] --> J[extractVariables]
    J --> K{$_locales in options?}
    K -- "yes (un-migrated)" --> L["Included as template variable\n(no longer filtered)"]
    K -- "no" --> M["Only user variables returned"]

    N["interpolateIcuMessage / interpolateStringMessage"] --> O["options.$locale\n(no $_locales fallback)"]
```

</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["Dictionary entry\n['Hello', options]"] --> B{isDictionaryOptions?}
    B -- "pass" --> C[resolveDictionaryLookupOptions]
    C --> D["Destructure: { $format, ...rest }"]
    D --> E["Return: { ...rest, $format: ICU }"]

    E --> F{context key present\nin old JS dict?}
    F -- "yes (un-migrated)" --> G["context leaks into rest\n→ treated as template variable"]
    F -- "no" --> H["Clean lookup options\n$context/$format/$maxChars"]

    I["Inline call: gt(msg, options)"] --> J[extractVariables]
    J --> K{$_locales in options?}
    K -- "yes (un-migrated)" --> L["Included as template variable\n(no longer filtered)"]
    K -- "no" --> M["Only user variables returned"]

    N["interpolateIcuMessage / interpolateStringMessage"] --> O["options.$locale\n(no $_locales fallback)"]
```

</a>
</details>


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

1. `packages/i18n/src/utils/extractVariables.ts`, line 14-24
([link](https://github.com/generaltranslation/gt/blob/ffc7be81dd257454414f23decdb048dae185ab83/packages/i18n/src/utils/extractVariables.ts#L14-L24))

<a href="#"><img alt="P2"
src="https://greptile-static-assets.s3.amazonaws.com/badges/p2.svg?v=9"
align="top"></a> **`$_locales` no longer filtered — becomes a live
template variable**

`$_locales` was previously excluded from `extractVariables` so it could
never accidentally appear as an interpolation variable. After this
removal, any un-migrated JS caller that still passes `$_locales` will
have it treated as a user-defined placeholder. If the message string
contains `{$_locales}` (unlikely but possible), it would be interpolated
with the locale value instead of raising a missing-variable error. This
is consistent with the broader deprecation removal, but unlike the
`$locale` key (which remains excluded), there is no longer any guard
that prevents the old key from leaking into rendered output.

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

   `````markdown
   This is a comment left during a code review.
   Path: packages/i18n/src/utils/extractVariables.ts
   Line: 14-24

   Comment:
   **`$_locales` no longer filtered — becomes a live template variable**

`$_locales` was previously excluded from `extractVariables` so it could
never accidentally appear as an interpolation variable. After this
removal, any un-migrated JS caller that still passes `$_locales` will
have it treated as a user-defined placeholder. If the message string
contains `{$_locales}` (unlikely but possible), it would be interpolated
with the locale value instead of raising a missing-variable error. This
is consistent with the broader deprecation removal, but unlike the
`$locale` key (which remains excluded), there is no longer any guard
that prevents the old key from leaking into rendered output.

   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%2Fi18n%2Fsrc%2Futils%2FextractVariables.ts%0ALine%3A%2014-24%0A%0AComment%3A%0A**%60%24_locales%60%20no%20longer%20filtered%20%E2%80%94%20becomes%20a%20live%20template%20variable**%0A%0A%60%24_locales%60%20was%20previously%20excluded%20from%20%60extractVariables%60%20so%20it%20could%20never%20accidentally%20appear%20as%20an%20interpolation%20variable.%20After%20this%20removal%2C%20any%20un-migrated%20JS%20caller%20that%20still%20passes%20%60%24_locales%60%20will%20have%20it%20treated%20as%20a%20user-defined%20placeholder.%20If%20the%20message%20string%20contains%20%60%7B%24_locales%7D%60%20%28unlikely%20but%20possible%29%2C%20it%20would%20be%20interpolated%20with%20the%20locale%20value%20instead%20of%20raising%20a%20missing-variable%20error.%20This%20is%20consistent%20with%20the%20broader%20deprecation%20removal%2C%20but%20unlike%20the%20%60%24locale%60%20key%20%28which%20remains%20excluded%29%2C%20there%20is%20no%20longer%20any%20guard%20that%20prevents%20the%20old%20key%20from%20leaking%20into%20rendered%20output.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=generaltranslation%2Fgt&pr=1687&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaudeDark.svg?v=3"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=3"><img
alt="Fix in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=3"
height="20"></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%22refactor%2Fremove-deprecated-i18n-options%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22refactor%2Fremove-deprecated-i18n-options%22.%0A%0AThis%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20packages%2Fi18n%2Fsrc%2Futils%2FextractVariables.ts%0ALine%3A%2014-24%0A%0AComment%3A%0A**%60%24_locales%60%20no%20longer%20filtered%20%E2%80%94%20becomes%20a%20live%20template%20variable**%0A%0A%60%24_locales%60%20was%20previously%20excluded%20from%20%60extractVariables%60%20so%20it%20could%20never%20accidentally%20appear%20as%20an%20interpolation%20variable.%20After%20this%20removal%2C%20any%20un-migrated%20JS%20caller%20that%20still%20passes%20%60%24_locales%60%20will%20have%20it%20treated%20as%20a%20user-defined%20placeholder.%20If%20the%20message%20string%20contains%20%60%7B%24_locales%7D%60%20%28unlikely%20but%20possible%29%2C%20it%20would%20be%20interpolated%20with%20the%20locale%20value%20instead%20of%20raising%20a%20missing-variable%20error.%20This%20is%20consistent%20with%20the%20broader%20deprecation%20removal%2C%20but%20unlike%20the%20%60%24locale%60%20key%20%28which%20remains%20excluded%29%2C%20there%20is%20no%20longer%20any%20guard%20that%20prevents%20the%20old%20key%20from%20leaking%20into%20rendered%20output.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=generaltranslation%2Fgt&pr=1687&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodexDark.svg?v=3"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=3"><img
alt="Fix in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=3"
height="20"></picture></a>

</details>

<!-- /greptile_failed_comments -->

<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%2Fi18n%2Fsrc%2Fi18n-cache%2Ftranslations-manager%2Futils%2Fdictionary-helpers.ts%3A116-124%0A**Old%20%60context%60%20key%20now%20leaks%20into%20lookup%20options**%0A%0APreviously%2C%20%60context%60%20was%20explicitly%20destructured%20out%20of%20%60options%60%20before%20the%20spread%2C%20so%20it%20was%20always%20stripped%20from%20the%20returned%20object.%20After%20this%20change%2C%20any%20object%20that%20still%20carries%20a%20%60context%60%20property%20%28e.g.%20a%20JS%20dictionary%20written%20before%20the%20migration%29%20will%20have%20%60context%60%20included%20in%20%60rest%60%20and%20therefore%20spread%20verbatim%20into%20the%20%60DictionaryLookupOptions%60%20result.%20Downstream%20consumers%20that%20treat%20unknown%20keys%20as%20template%20variables%20will%20then%20expose%20%60context%60%20as%20an%20interpolation%20variable%20%E2%80%94%20if%20the%20message%20contains%20%60%7Bcontext%7D%60%2C%20it%20would%20be%20silently%20filled%20with%20the%20old%20metadata%20string%20rather%20than%20surfacing%20an%20error.%20A%20one-liner%20%60const%20%7B%20%24format%2C%20context%3A%20_context%2C%20...rest%20%7D%20%3D%20options%3B%60%20would%20preserve%20the%20old%20strip-and-discard%20behavior%20without%20resurrecting%20the%20compatibility%20mapping.%0A%0A%23%23%23%20Issue%202%20of%202%0Apackages%2Fi18n%2Fsrc%2Futils%2FextractVariables.ts%3A14-24%0A**%60%24_locales%60%20no%20longer%20filtered%20%E2%80%94%20becomes%20a%20live%20template%20variable**%0A%0A%60%24_locales%60%20was%20previously%20excluded%20from%20%60extractVariables%60%20so%20it%20could%20never%20accidentally%20appear%20as%20an%20interpolation%20variable.%20After%20this%20removal%2C%20any%20un-migrated%20JS%20caller%20that%20still%20passes%20%60%24_locales%60%20will%20have%20it%20treated%20as%20a%20user-defined%20placeholder.%20If%20the%20message%20string%20contains%20%60%7B%24_locales%7D%60%20%28unlikely%20but%20possible%29%2C%20it%20would%20be%20interpolated%20with%20the%20locale%20value%20instead%20of%20raising%20a%20missing-variable%20error.%20This%20is%20consistent%20with%20the%20broader%20deprecation%20removal%2C%20but%20unlike%20the%20%60%24locale%60%20key%20%28which%20remains%20excluded%29%2C%20there%20is%20no%20longer%20any%20guard%20that%20prevents%20the%20old%20key%20from%20leaking%20into%20rendered%20output.%0A%0A&repo=generaltranslation%2Fgt&pr=1687&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://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22generaltranslation%2Fgt%22%20on%20the%20existing%20branch%20%22refactor%2Fremove-deprecated-i18n-options%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22refactor%2Fremove-deprecated-i18n-options%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%2Fi18n%2Fsrc%2Fi18n-cache%2Ftranslations-manager%2Futils%2Fdictionary-helpers.ts%3A116-124%0A**Old%20%60context%60%20key%20now%20leaks%20into%20lookup%20options**%0A%0APreviously%2C%20%60context%60%20was%20explicitly%20destructured%20out%20of%20%60options%60%20before%20the%20spread%2C%20so%20it%20was%20always%20stripped%20from%20the%20returned%20object.%20After%20this%20change%2C%20any%20object%20that%20still%20carries%20a%20%60context%60%20property%20%28e.g.%20a%20JS%20dictionary%20written%20before%20the%20migration%29%20will%20have%20%60context%60%20included%20in%20%60rest%60%20and%20therefore%20spread%20verbatim%20into%20the%20%60DictionaryLookupOptions%60%20result.%20Downstream%20consumers%20that%20treat%20unknown%20keys%20as%20template%20variables%20will%20then%20expose%20%60context%60%20as%20an%20interpolation%20variable%20%E2%80%94%20if%20the%20message%20contains%20%60%7Bcontext%7D%60%2C%20it%20would%20be%20silently%20filled%20with%20the%20old%20metadata%20string%20rather%20than%20surfacing%20an%20error.%20A%20one-liner%20%60const%20%7B%20%24format%2C%20context%3A%20_context%2C%20...rest%20%7D%20%3D%20options%3B%60%20would%20preserve%20the%20old%20strip-and-discard%20behavior%20without%20resurrecting%20the%20compatibility%20mapping.%0A%0A%23%23%23%20Issue%202%20of%202%0Apackages%2Fi18n%2Fsrc%2Futils%2FextractVariables.ts%3A14-24%0A**%60%24_locales%60%20no%20longer%20filtered%20%E2%80%94%20becomes%20a%20live%20template%20variable**%0A%0A%60%24_locales%60%20was%20previously%20excluded%20from%20%60extractVariables%60%20so%20it%20could%20never%20accidentally%20appear%20as%20an%20interpolation%20variable.%20After%20this%20removal%2C%20any%20un-migrated%20JS%20caller%20that%20still%20passes%20%60%24_locales%60%20will%20have%20it%20treated%20as%20a%20user-defined%20placeholder.%20If%20the%20message%20string%20contains%20%60%7B%24_locales%7D%60%20%28unlikely%20but%20possible%29%2C%20it%20would%20be%20interpolated%20with%20the%20locale%20value%20instead%20of%20raising%20a%20missing-variable%20error.%20This%20is%20consistent%20with%20the%20broader%20deprecation%20removal%2C%20but%20unlike%20the%20%60%24locale%60%20key%20%28which%20remains%20excluded%29%2C%20there%20is%20no%20longer%20any%20guard%20that%20prevents%20the%20old%20key%20from%20leaking%20into%20rendered%20output.%0A%0A&repo=generaltranslation%2Fgt&pr=1687&platform=github"><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/i18n/src/i18n-cache/translations-manager/utils/dictionary-helpers.ts:116-124
**Old `context` key now leaks into lookup options**

Previously, `context` was explicitly destructured out of `options` before the spread, so it was always stripped from the returned object. After this change, any object that still carries a `context` property (e.g. a JS dictionary written before the migration) will have `context` included in `rest` and therefore spread verbatim into the `DictionaryLookupOptions` result. Downstream consumers that treat unknown keys as template variables will then expose `context` as an interpolation variable — if the message contains `{context}`, it would be silently filled with the old metadata string rather than surfacing an error. A one-liner `const { $format, context: _context, ...rest } = options;` would preserve the old strip-and-discard behavior without resurrecting the compatibility mapping.

### Issue 2 of 2
packages/i18n/src/utils/extractVariables.ts:14-24
**`$_locales` no longer filtered — becomes a live template variable**

`$_locales` was previously excluded from `extractVariables` so it could never accidentally appear as an interpolation variable. After this removal, any un-migrated JS caller that still passes `$_locales` will have it treated as a user-defined placeholder. If the message string contains `{$_locales}` (unlikely but possible), it would be interpolated with the locale value instead of raising a missing-variable error. This is consistent with the broader deprecation removal, but unlike the `$locale` key (which remains excluded), there is no longer any guard that prevents the old key from leaking into rendered output.


`````

</details>

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

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

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

`gt-next` was published **CJS-only** (no `import` export condition).
Because the app entry imports `gt-next`, bundlers resolved the whole gt
dependency graph — `gt-react`, `@generaltranslation/react-core`,
`generaltranslation`, `gt-i18n`, `@generaltranslation/format` — through
the `require` condition, pulling CJS variants onto the client. CJS can't
be tree-shaken, so the browser received `gt-next`'s own server/error
code (e.g. ~11 kB of `createErrors` diagnostic strings) plus unused
exports from every dependency.

This PR gives `gt-next` a **dual ESM/CJS build**: it now emits unbundled
`.mjs` alongside `.js`, and every `exports` subpath gains an `import`
condition (preserving `react-server`/`browser`/`default` ordering).
Bundlers now resolve the gt graph as ESM, enabling tree-shaking across
all gt packages.

No public API changes — purely packaging.

## Measured impact

Built a real Next.js app (Turbopack) against these packages and
attributed bundle bytes per module via `next experimental-analyze`. gt's
**client** footprint (deduped across routes):

| | gt total raw | gt total gz |
|---|---|---|
| before (CJS) | 304.9 kB | 96.0 kB |
| after (ESM) | 236.0 kB | **73.9 kB (−23%)** |

`gt-next`'s own client code drops to **0** (including the leaked error
strings); `generaltranslation`, `gt-i18n`, and `gt-react` each shed
their dead exports.

## Notes

- This is the first of two related changes. A follow-up PR will unbundle
`@generaltranslation/react-core` so its `pure`/`components` entries can
also tree-shake — that change reverses an existing "independent
entrypoints" guard and is being reviewed separately. Layered on this PR
it takes the combined reduction to ~40% gz.
- Mirrors the dual-format setup already used by `gt-react`
(`createUseClientBoundaryPlugin` with `.js`/`.mjs` output extensions).

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR gives `gt-next` a dual ESM/CJS build by adding a second tsdown
pass that emits `.mjs` files and wiring every `exports` subpath with an
`import` condition, enabling tree-shaking across the entire gt
dependency graph for downstream bundlers. No public API changes are
made.

- **tsdown config**: A second `createTsdownUnbundleConfig` block is
added with `format: 'esm'`, `clean: false` (to preserve the CJS output),
`outExtensions` mapping to `.mjs`, and `polyfillRequire: false` to
suppress the `createRequire`-from-`node:module` shim that would break
client bundlers (Turbopack/webpack) reachable from ESM init paths.
- **package.json exports**: All subpath exports gain a flat `import`
condition; the root `.` entry nests `import`/`default` inside
`react-server` and `browser` conditions, preserving correct environment
routing.
- **sideEffects**: `index.rsc.*`, `index.client.*`, and
`utils/client-boundary.*` are added to the `sideEffects` list so their
top-level initialization is not eliminated by tree-shaking.

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

Pure packaging change — no runtime logic altered, no API surface
changed, and the dual-build pattern mirrors what gt-react already uses.

All three changed files touch only build configuration and the exports
map. The ESM build is additive (clean: false preserves the CJS
artifacts), polyfillRequire: false is a well-motivated guard against a
concrete Turbopack/webpack breakage, and the sideEffects expansion
correctly covers the newly ESM-exposed init files. TypeScript type
resolution falls back correctly to the CJS .d.ts files when .d.mts
counterparts are absent.

No files require special attention.
</details>


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




| Filename | Overview |
|----------|----------|
| .changeset/gt-next-esm-build.md | Changeset documenting the ESM/CJS
dual build for gt-next; numbers in changeset (~78 kB) differ slightly
from the PR description table (73.9 kB) but this is not a code concern.
|
| packages/next/package.json | Adds `import` conditions to all subpath
exports pointing to .mjs files; correctly expands sideEffects to cover
index.rsc.* and index.client.* (needed for top-level init); top-level
types ordering looks correct; missing legacy "module" field compared to
gt-react (P2, already noted in a prior review). |
| packages/next/tsdown.config.mts | Adds a second ESM build pass (clean:
false to preserve CJS output, polyfillRequire: false to avoid injecting
a node:module shim, .mjs output extension); mirrors the dual-build
pattern used by gt-react. |

</details>


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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Bundler imports gt-next"] --> B{Condition check}
    B -->|react-server| C{import condition?}
    C -->|ESM / import| D["index.rsc.mjs ✅ tree-shakeable"]
    C -->|CJS / default| E["index.rsc.js"]
    B -->|browser| F{import condition?}
    F -->|ESM / import| G["index.client.mjs ✅ tree-shakeable"]
    F -->|CJS / default| H["index.client.js"]
    B -->|server/default| I{import condition?}
    I -->|ESM / import| J["index.server.mjs ✅ tree-shakeable"]
    I -->|CJS / default| K["index.server.js"]
    B -->|TypeScript| L["index.types.d.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["Bundler imports gt-next"] --> B{Condition check}
    B -->|react-server| C{import condition?}
    C -->|ESM / import| D["index.rsc.mjs ✅ tree-shakeable"]
    C -->|CJS / default| E["index.rsc.js"]
    B -->|browser| F{import condition?}
    F -->|ESM / import| G["index.client.mjs ✅ tree-shakeable"]
    F -->|CJS / default| H["index.client.js"]
    B -->|server/default| I{import condition?}
    I -->|ESM / import| J["index.server.mjs ✅ tree-shakeable"]
    I -->|CJS / default| K["index.server.js"]
    B -->|TypeScript| L["index.types.d.ts"]
```

</a>
</details>


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

1. `packages/next/package.json`, line 5
([link](https://github.com/generaltranslation/gt/blob/b0b44e681408927a7cc45f1ca0a5a1434c1f603a/packages/next/package.json#L5))

<a href="#"><img alt="P2"
src="https://greptile-static-assets.s3.amazonaws.com/badges/p2.svg?v=9"
align="top"></a> The `"module"` legacy field is present in `gt-react`
(`"module": "./dist/index.server.mjs"`) but absent from `gt-next`.
Webpack 4 and other bundlers that predate the `"exports"` field use
`"module"` as their ESM signal; without it they fall back to `"main"`
(the CJS variant) and the tree-shaking gains won't materialise in those
environments. Since `gt-next` is Next.js-specific and Next.js itself
uses Webpack 5/Turbopack (both `"exports"`-aware), the practical impact
is low — but adding the field would keep the two packages consistent.

   

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

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

   Comment:
The `"module"` legacy field is present in `gt-react` (`"module":
"./dist/index.server.mjs"`) but absent from `gt-next`. Webpack 4 and
other bundlers that predate the `"exports"` field use `"module"` as
their ESM signal; without it they fall back to `"main"` (the CJS
variant) and the tree-shaking gains won't materialise in those
environments. Since `gt-next` is Next.js-specific and Next.js itself
uses Webpack 5/Turbopack (both `"exports"`-aware), the practical impact
is low — but adding the field would keep the two packages consistent.

   

   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%205%0A%0AComment%3A%0AThe%20%60%22module%22%60%20legacy%20field%20is%20present%20in%20%60gt-react%60%20%28%60%22module%22%3A%20%22.%2Fdist%2Findex.server.mjs%22%60%29%20but%20absent%20from%20%60gt-next%60.%20Webpack%204%20and%20other%20bundlers%20that%20predate%20the%20%60%22exports%22%60%20field%20use%20%60%22module%22%60%20as%20their%20ESM%20signal%3B%20without%20it%20they%20fall%20back%20to%20%60%22main%22%60%20%28the%20CJS%20variant%29%20and%20the%20tree-shaking%20gains%20won't%20materialise%20in%20those%20environments.%20Since%20%60gt-next%60%20is%20Next.js-specific%20and%20Next.js%20itself%20uses%20Webpack%205%2FTurbopack%20%28both%20%60%22exports%22%60-aware%29%2C%20the%20practical%20impact%20is%20low%20%E2%80%94%20but%20adding%20the%20field%20would%20keep%20the%20two%20packages%20consistent.%0A%0A%60%60%60suggestion%0A%20%20%22main%22%3A%20%22dist%2Findex.server.js%22%2C%0A%20%20%22module%22%3A%20%22dist%2Findex.server.mjs%22%2C%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=1688&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaudeDark.svg?v=3"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=3"><img
alt="Fix in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=3"
height="20"></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%2Fodysseus-gt-next-esm%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%2Fodysseus-gt-next-esm%22.%0A%0AThis%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20packages%2Fnext%2Fpackage.json%0ALine%3A%205%0A%0AComment%3A%0AThe%20%60%22module%22%60%20legacy%20field%20is%20present%20in%20%60gt-react%60%20%28%60%22module%22%3A%20%22.%2Fdist%2Findex.server.mjs%22%60%29%20but%20absent%20from%20%60gt-next%60.%20Webpack%204%20and%20other%20bundlers%20that%20predate%20the%20%60%22exports%22%60%20field%20use%20%60%22module%22%60%20as%20their%20ESM%20signal%3B%20without%20it%20they%20fall%20back%20to%20%60%22main%22%60%20%28the%20CJS%20variant%29%20and%20the%20tree-shaking%20gains%20won't%20materialise%20in%20those%20environments.%20Since%20%60gt-next%60%20is%20Next.js-specific%20and%20Next.js%20itself%20uses%20Webpack%205%2FTurbopack%20%28both%20%60%22exports%22%60-aware%29%2C%20the%20practical%20impact%20is%20low%20%E2%80%94%20but%20adding%20the%20field%20would%20keep%20the%20two%20packages%20consistent.%0A%0A%60%60%60suggestion%0A%20%20%22main%22%3A%20%22dist%2Findex.server.js%22%2C%0A%20%20%22module%22%3A%20%22dist%2Findex.server.mjs%22%2C%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=1688&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodexDark.svg?v=3"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=3"><img
alt="Fix in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=3"
height="20"></picture></a>
</details>

<!-- /greptile_failed_comments -->

<sub>Reviews (3): Last reviewed commit: ["fix(gt-next): mark
client-boundary as
ha..."](006591d)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40606533)</sub>

<!-- /greptile_comment -->
## Summary
- replace deprecated inline/dictionary option aliases with focused
translation option types
- type dictionary t() options as interpolation variables and dictionary
leaf metadata separately
- trim higher-level public type barrels to expose only
GTTranslationOptions and RuntimeTranslationOptions

## Tests
- pnpm --filter gt-i18n typecheck
- pnpm --filter @generaltranslation/react-core typecheck
- pnpm --filter gt-next typecheck
- pnpm --filter gt-react-native typecheck
- pnpm --filter gt-node typecheck
- pnpm --filter gt-i18n test

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR refactors the translation option type system in the `gt-i18n`
monorepo, replacing a set of deprecated alias types
(`InlineTranslationOptions`, `InlineResolveOptions`,
`DictionaryTranslationOptions`, `BaseTranslationOptions`,
`ResolutionOptions`, `DictionaryOptions`) with a cleaner, focused
hierarchy (`GTTranslationOptions`, `TranslationVariables`,
`TranslationMetadata`, `TranslationOptions`, `LookupOptionsFor`). It
also trims the public-facing type barrels to expose only
`GTTranslationOptions` and `RuntimeTranslationOptions`, hiding internal
plumbing types.

- **Type hierarchy flattened and renamed**:
`InlineTranslationOptionsFields` → `TranslationMetadata`;
`InlineTranslationOptions` → internal `TranslationOptions`; user-facing
`GTTranslationOptions` now deliberately excludes `$_fallback` and
`$_source` while keeping `$_hash`.
- **`t()` options narrowed**: Dictionary `t()` and `useTranslations()`
now accept `TranslationVariables` (plain `Record<string, unknown>`)
instead of `DictionaryTranslationOptions`, reflecting that metadata
lives on the dictionary leaf, not the call site.
- **`MFunctionType` tightened**: The previous `Record<string, any>`
escape-hatch on `m()`'s `options` parameter is replaced with the proper
`GTTranslationOptions`.

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

Safe to merge — this is a pure type-level refactoring with no runtime
logic changes, and the new type hierarchy is structurally equivalent to
what it replaces.

All renamed types resolve to the same structural shapes as their
predecessors at the TypeScript level. The narrowing of
DictionaryLookupOptions (dropping $id, $locale, $_hash fields never
actually used in the dictionary path) is intentional and correct. The
MFunctionType fix (replacing Record<string, any> with
GTTranslationOptions) is a strict improvement. The major-version
changeset is correct since public-facing type names changed.

No files require special attention. The options.ts rewrite is the most
impactful file and it reads cleanly.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/i18n/src/translation-functions/types/options.ts | Core type
definitions refactored cleanly; new hierarchy is structurally equivalent
to old one; DictionaryLookupOptions intentionally narrowed to remove
fields unused in the dictionary path. |
| packages/i18n/src/translation-functions/types/functions.ts |
MFunctionType now uses GTTranslationOptions instead of Record<string,
any>; all function types updated consistently with the new type names. |
| packages/i18n/src/types.ts | Public barrel trimmed correctly; internal
types like DictionaryLookupOptions removed from public exports; new
types like LookupOptionsFor and DictionaryEntryOptions added. |
|
packages/i18n/src/i18n-cache/translations-manager/utils/dictionary-helpers.ts
| isDictionaryOptions renamed to isDictionaryLeafOptions; now imports
DictionaryEntryOptions/DictionaryLookupOptions from central options.ts
rather than defining them locally. |
| packages/i18n/src/translation-functions/internal/helpers.ts |
ResolutionOptions replaced by LookupOptionsFor across all six resolve
functions; behaviorally equivalent. |
| packages/react-core/src/hooks/useTranslations.ts |
DictionaryTranslationOptions replaced by TranslationVariables in
useTranslations and UseTranslationsFunction; structurally identical
types. |
| packages/i18n/src/translation-functions/msg/decodeOptions.ts | Return
type widened from InlineTranslationOptions to TranslationOptions (the
full internal shape), which is correct since decoded options can carry
any metadata field. |
| .changeset/simplify-translation-option-types.md | All six affected
packages correctly marked as major version bumps in the changeset. |

</details>

<details><summary><h3>Class Diagram</h3></summary>

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
classDiagram
    class TranslationVariables {
        <<Record~string,unknown~>>
    }
    class TranslationMetadata {
        +$context?: string
        +$id?: string
        +$format?: StringFormat
        +$locale?: string
        +$_hash?: string
        +$_fallback?: string
        +$_source?: string
        +$maxChars?: number
    }
    class TranslationOptions {
        <<internal full shape>>
    }
    class GTTranslationOptions {
        <<user-facing gt() m()>>
        +$context?: string
        +$id?: string
        +$format?: StringFormat
        +$locale?: string
        +$_hash?: string
        +$maxChars?: number
    }
    class DictionaryEntryOptions {
        <<dictionary leaf metadata>>
        +$context?: string
        +$format?: StringFormat
        +$maxChars?: number
    }
    class DictionaryLookupOptions {
        <<internal>>
        +$format: StringFormat
    }
    class RuntimeTranslationOptions {
        <<user-facing tx()>>
        +$format?: DataFormat
    }
    class EncodedTranslationOptions {
        <<msg() output>>
        +$_hash: string
        +$_source: string
    }
    class LookupOptionsFor~T~ {
        <<generic resolution>>
    }
    TranslationVariables <|-- TranslationOptions : intersects
    TranslationMetadata <|-- TranslationOptions : intersects
    TranslationVariables <|-- GTTranslationOptions : intersects
    TranslationMetadata <|-- GTTranslationOptions : Pick subset
    GTTranslationOptions <|-- EncodedTranslationOptions : extends
    TranslationVariables <|-- DictionaryEntryOptions : intersects
    TranslationMetadata <|-- DictionaryEntryOptions : Pick subset
    DictionaryEntryOptions <|-- DictionaryLookupOptions : extends
    TranslationVariables <|-- RuntimeTranslationOptions : intersects
    TranslationMetadata <|-- RuntimeTranslationOptions : Omit~$id,$format~
    TranslationOptions <|-- LookupOptionsFor~T~ : when T is StringFormat
```

</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"}}}%%
classDiagram
    class TranslationVariables {
        <<Record~string,unknown~>>
    }
    class TranslationMetadata {
        +$context?: string
        +$id?: string
        +$format?: StringFormat
        +$locale?: string
        +$_hash?: string
        +$_fallback?: string
        +$_source?: string
        +$maxChars?: number
    }
    class TranslationOptions {
        <<internal full shape>>
    }
    class GTTranslationOptions {
        <<user-facing gt() m()>>
        +$context?: string
        +$id?: string
        +$format?: StringFormat
        +$locale?: string
        +$_hash?: string
        +$maxChars?: number
    }
    class DictionaryEntryOptions {
        <<dictionary leaf metadata>>
        +$context?: string
        +$format?: StringFormat
        +$maxChars?: number
    }
    class DictionaryLookupOptions {
        <<internal>>
        +$format: StringFormat
    }
    class RuntimeTranslationOptions {
        <<user-facing tx()>>
        +$format?: DataFormat
    }
    class EncodedTranslationOptions {
        <<msg() output>>
        +$_hash: string
        +$_source: string
    }
    class LookupOptionsFor~T~ {
        <<generic resolution>>
    }
    TranslationVariables <|-- TranslationOptions : intersects
    TranslationMetadata <|-- TranslationOptions : intersects
    TranslationVariables <|-- GTTranslationOptions : intersects
    TranslationMetadata <|-- GTTranslationOptions : Pick subset
    GTTranslationOptions <|-- EncodedTranslationOptions : extends
    TranslationVariables <|-- DictionaryEntryOptions : intersects
    TranslationMetadata <|-- DictionaryEntryOptions : Pick subset
    DictionaryEntryOptions <|-- DictionaryLookupOptions : extends
    TranslationVariables <|-- RuntimeTranslationOptions : intersects
    TranslationMetadata <|-- RuntimeTranslationOptions : Omit~$id,$format~
    TranslationOptions <|-- LookupOptionsFor~T~ : when T is StringFormat
```

</a>
</details>

<sub>Reviews (3): Last reviewed commit: ["refactor: simplify translation
option
ty..."](4417d04)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40623023)</sub>

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

Each `@generaltranslation/react-core` entrypoint (`pure`, `hooks`,
`components`, `components-rsc`, `cookies`) was built as a **single
pre-bundled, minified file**, so importing one component pulled the
whole entry and a downstream bundler couldn't drop unused code.

This PR switches react-core to an **unbundled** build (per-module
output, ESM + CJS): entrypoints become thin re-export barrels over
granular sibling modules. Output filenames change from
`*.cjs.min.cjs`/`*.esm.min.mjs` to `*.cjs`/`*.mjs`, resolved through the
`exports` map — no consumer-facing API change.

## Measured impact

When react-core is consumed via ESM, this lets the bundler tree-shake
the unused half of `pure`/`components`. react-core's **client**
footprint (real Next.js app, `next experimental-analyze`):

| | react-core client raw | react-core client gz |
|---|---|---|
| bundled (before) | 158.2 kB | 49.1 kB |
| unbundled (after) | **82.0 kB** | **33.0 kB** |

> ⚠️ This reduction only materializes when react-core is resolved as
**ESM**. CJS can't be tree-shaken, so on its own this PR barely moves
gzip (it just de-duplicates raw text). It pays off layered on #1688
(`gt-next` ESM build); together the two cut gt's total client bundle
~40% gzip.

## Reviewer note — intentional architecture reversal

This reverses the previous "independent entrypoints **without shared
chunks**" design. The `react-core-package.test.ts` guard that enforced
per-entry bundling is rewritten to assert the new unbundled layout
(entrypoints present in both formats; many granular runtime modules
emitted). The two behavioral export-loading tests are unchanged. All 267
react-core tests pass.

## Validation

- `pnpm --filter @generaltranslation/react-core test` → 267 passing
- Full app build (this + #1688) compiles and runs; gt-react/gt-next
consume the unbundled subpaths via the `exports` map with no changes.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR switches `@generaltranslation/react-core` from a per-entrypoint
pre-bundled build to an unbundled (per-module) ESM + CJS output,
enabling downstream bundlers to tree-shake unused components and hooks.
The measured client footprint drops from 158 kB → 82 kB raw (49 kB → 33
kB gzip) when consumed as ESM.

- **Build config** (`tsdown.config.mts`): replaces
`createTsdownMinifiedDualFormatConfig` with two
`createTsdownUnbundleConfig` calls (CJS with `dts:true`, ESM with
`clean:false`); `@generaltranslation/format` and `generaltranslation`
subpath imports are intentionally externalized instead of inlined.
- **Package exports** (`package.json`): filename extensions updated from
`*.cjs.min.cjs`/`*.esm.min.mjs` to `*.cjs`/`*.mjs`; `sideEffects: false`
is already set, which is required for tree-shaking to work.
- **Tests**: TypeScript AST-based bundling assertion removed and
replaced with a file-count heuristic asserting the unbundled layout; the
two behavioral load tests (CJS and ESM named-export checks) are kept
unchanged.

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

Safe to merge — the change is a pure build-output restructuring with no
runtime logic changes and no public API surface modifications.

The only changes are to the build configuration, the exports map
filename extensions, the size-limit path, and the test assertions. The
two behavioral load tests that verify named exports from both CJS and
ESM entrypoints are unchanged and confirmed passing (267 tests). The
`sideEffects: false` flag that makes tree-shaking effective was already
present. The dependency externalization (`@generaltranslation/format`,
`generaltranslation` subpaths) is intentional and documented in the
changeset, and both packages remain listed as `dependencies` in
`package.json` so they are guaranteed to be installed.

No files require special attention.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/react-core/tsdown.config.mts | Switches from
createTsdownMinifiedDualFormatConfig to createTsdownUnbundleConfig; CJS
gets dts:true, ESM gets clean:false; both get minify:true spread in. No
alwaysBundle overrides needed since generaltranslation/format subpaths
are now intentionally externalized. |
| packages/react-core/package.json | Exports map updated from
*.cjs.min.cjs/esm.min.mjs to *.cjs/*.mjs; all five entrypoints updated
consistently; no other consumer-facing changes. |
| packages/react-core/src/__tests__/react-core-package.test.ts | Test
rewritten to assert unbundled layout: barrel presence in both formats
plus a file-count check; TypeScript AST-based bundling check removed;
two behavioral load tests are unchanged. |
| .size-limit.cjs | Path updated from *.esm.min.mjs to *.mjs to match
new output extensions; 48 kB limit preserved. |
| .changeset/react-core-unbundle.md | New patch-level changeset
describing the unbundled build, removed format sub-dependency inlining,
and filename extension changes. |

</details>

<sub>Reviews (2): Last reviewed commit: ["perf(react-core): unbundle
build output
..."](c6441df)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40606757)</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.2

### Major Changes

- [#1687](#1687)
[`41c938c`](41c938c)
Thanks [@bgub](https://github.com/bgub)! - Remove deprecated translation
options. The `context` dictionary option has been removed in favor of
`$context`, and the `$_locales` inline option has been removed in favor
of `$locale`.

- [#1690](#1690)
[`b3c3b9a`](b3c3b9a)
Thanks [@bgub](https://github.com/bgub)! - Simplify translation option
types. Replace deprecated inline and dictionary option aliases with
`GTTranslationOptions`, use interpolation variables for dictionary `t()`
options, and trim higher-level type exports to avoid exposing internal
translation option fields.

### Patch Changes

- Updated dependencies
[[`4b97bc3`](4b97bc3),
[`020c6bd`](020c6bd)]:
  - @generaltranslation/format@0.1.2-odysseus.1
  - generaltranslation@9.0.0-odysseus.2
  - @generaltranslation/supported-locales@2.1.2-odysseus.2
## gt-next@11.0.0-odysseus.5

### Major Changes

- [#1690](#1690)
[`b3c3b9a`](b3c3b9a)
Thanks [@bgub](https://github.com/bgub)! - Simplify translation option
types. Replace deprecated inline and dictionary option aliases with
`GTTranslationOptions`, use interpolation variables for dictionary `t()`
options, and trim higher-level type exports to avoid exposing internal
translation option fields.

### Patch Changes

- [#1685](#1685)
[`795147f`](795147f)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Allow client
i18n cache expiry to default to no expiry while preserving explicit
cache expiry configuration.

- [#1688](#1688)
[`2836b96`](2836b96)
Thanks [@bgub](https://github.com/bgub)! - Ship a dual ESM/CJS build for
`gt-next` and add `import` export conditions.

Previously `gt-next` was published as CJS only (no `import` condition),
so bundlers resolved the entire gt dependency graph (`gt-react`,
`@generaltranslation/react-core`, `generaltranslation`, `gt-i18n`,
`@generaltranslation/format`) through the `require` condition. That
forced CJS variants onto the client, which cannot be tree-shaken —
shipping `gt-next`'s own server/error code and unused dependency exports
to the browser.

`gt-next` now emits unbundled `.mjs` output alongside the existing `.js`
output, and every `exports` subpath exposes an `import` condition.
Bundlers now resolve the gt graph as ESM, enabling tree-shaking across
all gt packages. Measured on a real Next.js app, this cuts gt's total
client bundle by ~19% gzip (≈96 kB → ≈78 kB) with no API changes.

The ESM build sets `polyfillRequire: false` so rolldown does not inject
a `createRequire`-from-`node:module` shim (server-only `require()` calls
are provided `require` by the bundler), and marks the
`index.rsc`/`index.client` entrypoints as having side effects so their
top-level initialization is not tree-shaken away.

- [#1678](#1678)
[`4b97bc3`](4b97bc3)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Organize
package entrypoint exports and replace re-export-only imports with
direct export declarations.

- [#1676](#1676)
[`020c6bd`](020c6bd)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove default
exports from package entrypoints and internal source modules.

Use named imports for affected public entrypoints, including `import {
plugin } from 'gt-react-native/plugin'`. The `gt-next/link` entrypoint
keeps its default export to match `next/link`.

- Updated dependencies
[[`795147f`](795147f),
[`4b97bc3`](4b97bc3),
[`020c6bd`](020c6bd),
[`41c938c`](41c938c),
[`b3c3b9a`](b3c3b9a)]:
  - gt-react@11.0.0-odysseus.5
  - @generaltranslation/format@0.1.2-odysseus.1
  - generaltranslation@9.0.0-odysseus.2
  - @generaltranslation/react-core@11.0.0-odysseus.5
  - gt-i18n@1.0.0-odysseus.2
  - @generaltranslation/compiler@1.3.25-odysseus.2
  - @generaltranslation/supported-locales@2.1.2-odysseus.2
## gt-node@1.0.0-odysseus.2

### Major Changes

- [#1690](#1690)
[`b3c3b9a`](b3c3b9a)
Thanks [@bgub](https://github.com/bgub)! - Simplify translation option
types. Replace deprecated inline and dictionary option aliases with
`GTTranslationOptions`, use interpolation variables for dictionary `t()`
options, and trim higher-level type exports to avoid exposing internal
translation option fields.

### Patch Changes

- Updated dependencies
[[`4b97bc3`](4b97bc3),
[`020c6bd`](020c6bd),
[`41c938c`](41c938c),
[`b3c3b9a`](b3c3b9a)]:
  - generaltranslation@9.0.0-odysseus.2
  - gt-i18n@1.0.0-odysseus.2
## gt-react@11.0.0-odysseus.5

### Major Changes

- [#1690](#1690)
[`b3c3b9a`](b3c3b9a)
Thanks [@bgub](https://github.com/bgub)! - Simplify translation option
types. Replace deprecated inline and dictionary option aliases with
`GTTranslationOptions`, use interpolation variables for dictionary `t()`
options, and trim higher-level type exports to avoid exposing internal
translation option fields.

### Patch Changes

- [#1685](#1685)
[`795147f`](795147f)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Allow client
i18n cache expiry to default to no expiry while preserving explicit
cache expiry configuration.

- [#1676](#1676)
[`020c6bd`](020c6bd)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove default
exports from package entrypoints and internal source modules.

Use named imports for affected public entrypoints, including `import {
plugin } from 'gt-react-native/plugin'`. The `gt-next/link` entrypoint
keeps its default export to match `next/link`.

- Updated dependencies
[[`4b97bc3`](4b97bc3),
[`020c6bd`](020c6bd),
[`41c938c`](41c938c),
[`b3c3b9a`](b3c3b9a)]:
  - @generaltranslation/format@0.1.2-odysseus.1
  - generaltranslation@9.0.0-odysseus.2
  - @generaltranslation/react-core@11.0.0-odysseus.5
  - gt-i18n@1.0.0-odysseus.2
  - @generaltranslation/supported-locales@2.1.2-odysseus.2
## @generaltranslation/react-core@11.0.0-odysseus.5

### Major Changes

- [#1690](#1690)
[`b3c3b9a`](b3c3b9a)
Thanks [@bgub](https://github.com/bgub)! - Simplify translation option
types. Replace deprecated inline and dictionary option aliases with
`GTTranslationOptions`, use interpolation variables for dictionary `t()`
options, and trim higher-level type exports to avoid exposing internal
translation option fields.

### Patch Changes

- [#1676](#1676)
[`020c6bd`](020c6bd)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove default
exports from package entrypoints and internal source modules.

Use named imports for affected public entrypoints, including `import {
plugin } from 'gt-react-native/plugin'`. The `gt-next/link` entrypoint
keeps its default export to match `next/link`.

- Updated dependencies
[[`4b97bc3`](4b97bc3),
[`020c6bd`](020c6bd),
[`41c938c`](41c938c),
[`b3c3b9a`](b3c3b9a)]:
  - @generaltranslation/format@0.1.2-odysseus.1
  - generaltranslation@9.0.0-odysseus.2
  - gt-i18n@1.0.0-odysseus.2
  - @generaltranslation/supported-locales@2.1.2-odysseus.2
## gt-react-native@11.0.0-odysseus.5

### Major Changes

- [#1690](#1690)
[`b3c3b9a`](b3c3b9a)
Thanks [@bgub](https://github.com/bgub)! - Simplify translation option
types. Replace deprecated inline and dictionary option aliases with
`GTTranslationOptions`, use interpolation variables for dictionary `t()`
options, and trim higher-level type exports to avoid exposing internal
translation option fields.

### Patch Changes

- [#1678](#1678)
[`4b97bc3`](4b97bc3)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Organize
package entrypoint exports and replace re-export-only imports with
direct export declarations.

- [#1676](#1676)
[`020c6bd`](020c6bd)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove default
exports from package entrypoints and internal source modules.

Use named imports for affected public entrypoints, including `import {
plugin } from 'gt-react-native/plugin'`. The `gt-next/link` entrypoint
keeps its default export to match `next/link`.

- Updated dependencies
[[`4b97bc3`](4b97bc3),
[`020c6bd`](020c6bd),
[`41c938c`](41c938c),
[`b3c3b9a`](b3c3b9a)]:
  - @generaltranslation/format@0.1.2-odysseus.1
  - generaltranslation@9.0.0-odysseus.2
  - @generaltranslation/react-core@11.0.0-odysseus.5
  - gt-i18n@1.0.0-odysseus.2
  - @generaltranslation/supported-locales@2.1.2-odysseus.2
## gt@2.14.51-odysseus.2

### Patch Changes

- Updated dependencies
[[`4b97bc3`](4b97bc3),
[`020c6bd`](020c6bd)]:
  - @generaltranslation/format@0.1.2-odysseus.1
  - generaltranslation@9.0.0-odysseus.2
  - @generaltranslation/python-extractor@0.2.23-odysseus.2
  - @generaltranslation/supported-locales@2.1.2-odysseus.2
## @generaltranslation/compiler@1.3.25-odysseus.2

### Patch Changes

- Updated dependencies
[[`4b97bc3`](4b97bc3),
[`020c6bd`](020c6bd)]:
  - @generaltranslation/format@0.1.2-odysseus.1
  - generaltranslation@9.0.0-odysseus.2
## generaltranslation@9.0.0-odysseus.2

### Patch Changes

- [#1678](#1678)
[`4b97bc3`](4b97bc3)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Organize
package entrypoint exports and replace re-export-only imports with
direct export declarations.

- [#1676](#1676)
[`020c6bd`](020c6bd)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove default
exports from package entrypoints and internal source modules.

Use named imports for affected public entrypoints, including `import {
plugin } from 'gt-react-native/plugin'`. The `gt-next/link` entrypoint
keeps its default export to match `next/link`.

- Updated dependencies
[[`4b97bc3`](4b97bc3)]:
  - @generaltranslation/format@0.1.2-odysseus.1
## @generaltranslation/format@0.1.2-odysseus.1

### Patch Changes

- [#1678](#1678)
[`4b97bc3`](4b97bc3)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Organize
package entrypoint exports and replace re-export-only imports with
direct export declarations.
## gtx-cli@2.14.51-odysseus.2

### Patch Changes

- Updated dependencies []:
  - gt@2.14.51-odysseus.2
## locadex@1.0.186-odysseus.2

### Patch Changes

- Updated dependencies []:
  - gt@2.14.51-odysseus.2
## @generaltranslation/gt-next-lint@15.0.0-odysseus.5

### Patch Changes

- Updated dependencies
[[`795147f`](795147f),
[`2836b96`](2836b96),
[`4b97bc3`](4b97bc3),
[`020c6bd`](020c6bd),
[`b3c3b9a`](b3c3b9a)]:
  - gt-next@11.0.0-odysseus.5
## @generaltranslation/python-extractor@0.2.23-odysseus.2

### Patch Changes

- Updated dependencies
[[`4b97bc3`](4b97bc3),
[`020c6bd`](020c6bd)]:
  - generaltranslation@9.0.0-odysseus.2
## gt-sanity@2.0.18-odysseus.4

### Patch Changes

- [#1678](#1678)
[`4b97bc3`](4b97bc3)
Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Organize
package entrypoint exports and replace re-export-only imports with
direct export declarations.

- Updated dependencies
[[`4b97bc3`](4b97bc3),
[`020c6bd`](020c6bd)]:
  - generaltranslation@9.0.0-odysseus.2
## @generaltranslation/supported-locales@2.1.2-odysseus.2

### Patch Changes

- Updated dependencies
[[`4b97bc3`](4b97bc3),
[`020c6bd`](020c6bd)]:
  - generaltranslation@9.0.0-odysseus.2
## gt-tanstack-start@11.0.0-odysseus.5

### Patch Changes

- Updated dependencies
[[`795147f`](795147f),
[`4b97bc3`](4b97bc3),
[`020c6bd`](020c6bd),
[`41c938c`](41c938c),
[`b3c3b9a`](b3c3b9a)]:
  - gt-react@11.0.0-odysseus.5
  - generaltranslation@9.0.0-odysseus.2
  - @generaltranslation/react-core@11.0.0-odysseus.5
  - gt-i18n@1.0.0-odysseus.2

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## Summary
- Add `scripts/version-packages-odysseus.sh` for the Odysseus release
action.
- The script rewrites `.changeset/config.json` to use `baseBranch:
odysseus` and `@changesets/cli/changelog`, marks the config file
assume-unchanged, then runs `pnpm run version-packages`.
- Configure `changesets/action` to call the script via `version: bash
scripts/version-packages-odysseus.sh`, so the rewrite happens after the
action resets the release branch.

## Testing
- `bash -n scripts/version-packages-odysseus.sh`
- `pnpm exec oxfmt --check .github/workflows/release.yml
scripts/version-packages-odysseus.sh`
- In a temp worktree at this PR head, ran `bash
scripts/version-packages-odysseus.sh`; it completed successfully,
generated the expected release files, and `.changeset/config.json` had
no diff.

## Notes
The previous workflow step did run, but `changesets/action` then
performed `git reset --hard <headSha>` before invoking `version`, which
discarded the config rewrite. The script is called from `version`, after
that reset.
## Summary
- Add a patch changeset for `@generaltranslation/react-core` to trigger
a new Odysseus prerelease path.
- Rely on the Odysseus fixed package group to include the related
React/Next packages during versioning.

## Testing
- `pnpm changeset status --since=origin/odysseus`
## Summary

Removes a dead, self-referential dictionary-injection cluster from
`@generaltranslation/react-core`. These 8 modules were exported from the
client-shipped `/pure` entry but have **zero consumers** anywhere in the
monorepo (verified by grep across all `packages/*/src`): they only
imported each other.

Deleted:
- `collectUntranslatedEntries`, `injectAndMerge`, `injectEntry`,
`injectFallbacks`, `injectHashes`, `injectTranslations`,
`getSubtree`/`getSubtreeWithCreation`, `stripMetadataFromEntries` (+
their `__tests__`)
- the 9 corresponding exports in `src/pure.ts`

~415 LOC of dead code removed from `/pure`. The still-used dictionary
helpers (`getDictionaryEntry`, `getEntryAndMetadata`,
`mergeDictionaries`, `flattenDictionary`, `indexDict`,
`isDictionaryEntry`) are untouched.

## Verification
- `src/pure.ts` was the only importer of all 8 modules; the kept
dictionary files don't depend on any of them.
- react-core builds; 139 tests pass (the removed tests only covered the
deleted modules).
- `gt-react` and `gt-next` (the `/pure` consumers) build clean.

Part of an odysseus (next-major) dead-code/trim sweep.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR removes 8 dead dictionary-injection helper modules from
`@generaltranslation/react-core/pure`, along with their corresponding
test files. No consumer anywhere in the monorepo referenced any of the
deleted exports; they only imported each other.

- Removes `collectUntranslatedEntries`, `injectAndMerge`, `injectEntry`,
`injectFallbacks`, `injectHashes`, `injectTranslations`,
`getSubtree`/`getSubtreeWithCreation`, and `stripMetadataFromEntries`
(source + tests) — ~415 LOC total.
- Strips the 9 corresponding exports from `src/pure.ts`; all still-used
dictionary helpers (`getDictionaryEntry`, `getEntryAndMetadata`,
`mergeDictionaries`, `flattenDictionary`, `indexDict`,
`isDictionaryEntry`) are untouched.
- The changeset is marked `patch` within the active `odysseus`
pre-release, which already carries a major-version bump via a separate
changeset, so no semver concern.

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

Safe to merge — this is a pure deletion of exports and source files that
have zero consumers in the monorepo.

All 8 deleted modules were verified unused across every package in the
monorepo. The surviving exports in pure.ts are untouched, and the
downstream consumers (gt-react, gt-next) import none of the removed
symbols. Test coverage for the deleted code is removed alongside the
source, leaving no orphaned references.

No files require special attention.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/react-core/src/pure.ts | Removes 9 export lines pointing to
the deleted modules; all remaining exports are untouched and verified
still-used. |
| .changeset/trim-react-core-dead-dictionaries.md | Changeset correctly
scoped to @generaltranslation/react-core as patch; acceptable within the
active odysseus pre-release that already carries a major bump. |
|
packages/react-core/src/utils/dictionaries/collectUntranslatedEntries.ts
| Deleted source file — confirmed no consumers in the monorepo. |
| packages/react-core/src/utils/dictionaries/injectAndMerge.ts | Deleted
source file — confirmed no consumers in the monorepo. |
| packages/react-core/src/utils/dictionaries/getSubtree.ts | Deleted
source file — confirmed no consumers in the monorepo. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["@generaltranslation/react-core/pure"] --> B["Kept: getDictionaryEntry"]
    A --> C["Kept: getEntryAndMetadata"]
    A --> D["Kept: mergeDictionaries"]
    A --> E["Kept: flattenDictionary"]
    A --> F["Kept: isDictionaryEntry"]
    A --> G["Kept: isValidDictionaryEntry"]

    H["REMOVED: collectUntranslatedEntries"] -.->|"no consumers"| X["❌ Dead cluster"]
    I["REMOVED: injectAndMerge"] -.-> X
    J["REMOVED: injectEntry"] -.-> X
    K["REMOVED: injectFallbacks"] -.-> X
    L["REMOVED: injectHashes"] -.-> X
    M["REMOVED: injectTranslations"] -.-> X
    N["REMOVED: getSubtree / getSubtreeWithCreation"] -.-> X
    O["REMOVED: stripMetadataFromEntries"] -.-> X

    A --> P["gt-react (consumer)"]
    A --> Q["gt-next (consumer)"]
```

</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"] --> B["Kept: getDictionaryEntry"]
    A --> C["Kept: getEntryAndMetadata"]
    A --> D["Kept: mergeDictionaries"]
    A --> E["Kept: flattenDictionary"]
    A --> F["Kept: isDictionaryEntry"]
    A --> G["Kept: isValidDictionaryEntry"]

    H["REMOVED: collectUntranslatedEntries"] -.->|"no consumers"| X["❌ Dead cluster"]
    I["REMOVED: injectAndMerge"] -.-> X
    J["REMOVED: injectEntry"] -.-> X
    K["REMOVED: injectFallbacks"] -.-> X
    L["REMOVED: injectHashes"] -.-> X
    M["REMOVED: injectTranslations"] -.-> X
    N["REMOVED: getSubtree / getSubtreeWithCreation"] -.-> X
    O["REMOVED: stripMetadataFromEntries"] -.-> X

    A --> P["gt-react (consumer)"]
    A --> Q["gt-next (consumer)"]
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["refactor(react-core): remove
dead
dictio..."](21e5e12)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40685657)</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-next@11.0.0-odysseus.6

### Patch Changes

- Updated dependencies [c1aa794]
- Updated dependencies [e0ace5b]
  - @generaltranslation/react-core@11.0.0-odysseus.6
  - gt-react@11.0.0-odysseus.6
## @generaltranslation/gt-next-lint@15.0.0-odysseus.6

### Patch Changes

- gt-next@11.0.0-odysseus.6
## gt-react@11.0.0-odysseus.6

### Patch Changes

- Updated dependencies [c1aa794]
- Updated dependencies [e0ace5b]
  - @generaltranslation/react-core@11.0.0-odysseus.6
## @generaltranslation/react-core@11.0.0-odysseus.6

### Patch Changes

- c1aa794: Trigger a new Odysseus prerelease after updating the release
workflow.
- e0ace5b: Build `@generaltranslation/react-core` as unbundled,
tree-shakeable modules.

Each entrypoint (`pure`, `hooks`, `components`, `components-rsc`,
`cookies`) was previously emitted as a single pre-bundled, minified
file, so a consumer importing one component pulled the entire entry. The
package now builds unbundled (per-module) output in both ESM and CJS:
entrypoints are thin re-export barrels over granular sibling modules,
allowing a downstream bundler to drop unused components and hooks.

The build also stops inlining
`generaltranslation`/`@generaltranslation/format` into react-core's
output, so they resolve to their single shared copy instead of being
duplicated in react-core (they are already loaded standalone). This
removes the duplication and keeps the per-module declarations
referencing the dependency packages directly, so inferred types stay
portable for downstream packages.

When consumed via ESM (see the companion `gt-next` ESM change),
tree-shaking plus de-duplication cuts react-core's client footprint
substantially. Output filenames change from
`*.cjs.min.cjs`/`*.esm.min.mjs` to `*.cjs`/`*.mjs` (resolved through the
`exports` map, so no consumer-facing API change). The package-shape test
is updated to assert the new unbundled layout.
## gt-react-native@11.0.0-odysseus.6

### Patch Changes

- Updated dependencies [c1aa794]
- Updated dependencies [e0ace5b]
  - @generaltranslation/react-core@11.0.0-odysseus.6
## gt-tanstack-start@11.0.0-odysseus.6

### Patch Changes

- Updated dependencies [c1aa794]
- Updated dependencies [e0ace5b]
  - @generaltranslation/react-core@11.0.0-odysseus.6
  - gt-react@11.0.0-odysseus.6

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

Removes the v8-era backwards-compatibility shim from
`generaltranslation`. Deletes `src/backwards-compatability/` and its 26
re-exports from `generaltranslation/internal`:
- `dataConversion.ts` — `getNew*`/`getOld*` JSX/variable/branch/GTProp
format converters
- `oldTypes.ts` — `Old*` type definitions
- `typeChecking.ts` — `isOld*`/`isNew*` guards
- `oldHashJsxChildren.ts` — `oldHashJsxChildren`/`oldHashString` (legacy
hashers)

These bridged the pre-v8 JSX/variable format, which is no longer
produced. **Verified zero consumers** across all `packages/*/src` — the
only references were `internal.ts` (the barrel) itself. ~477 LOC removed
from the `/internal` entry.

`@noble/hashes` stays a dependency (the live `id/hashSource.ts` still
uses it).

## Verification
- grep across the monorepo: none of the 26 symbols (or the module paths)
are imported anywhere outside `backwards-compatability/` +
`internal.ts`.
- `generaltranslation` builds; **432 tests pass** (3 skipped).
- Dependents build clean: `gt-i18n`, `@generaltranslation/react-core`,
`gt-react`, `gt-next`.

Part of an odysseus (next-major) dead-code/legacy-removal sweep.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR removes the v8-era backwards-compatibility shim from
`generaltranslation` — 4 source files and 26 re-exports are deleted from
the `generaltranslation/internal` entry point. The PR description
confirms zero consumers in the monorepo and all dependent packages build
clean after the removal.

- Deletes `packages/core/src/backwards-compatability/` (dataConversion,
oldTypes, typeChecking, oldHashJsxChildren) and scrubs their 26
re-exports from `src/internal.ts`.
- The `patch` changeset bump is safe here because a separate
`odysseus-major-version-bumps.md` changeset already carries a `major`
bump for `generaltranslation`, and changesets tooling always uses the
highest bump across all pending changesets.

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

Safe to merge — this is a pure deletion of dead code with no active
consumers anywhere in the monorepo.

All four deleted files were confirmed to have zero imports outside their
own directory and the internal barrel. The remaining exports in
internal.ts are untouched. The @noble/hashes dependency is retained for
the live hash implementation. The patch changeset bump is harmless
because a separate odysseus-major-version-bumps.md already locks in a
major bump for generaltranslation.

No files require special attention.
</details>

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

| Filename | Overview |
|----------|----------|
| .changeset/trim-core-backwards-compat.md | Adds a patch changeset;
safe because odysseus-major-version-bumps.md already ensures a major
bump for this package. |
| packages/core/src/backwards-compatability/dataConversion.ts | Deleted
— 14 old↔new JSX/variable format converter functions with zero remaining
consumers. |
| packages/core/src/backwards-compatability/oldHashJsxChildren.ts |
Deleted — legacy oldHashJsxChildren and oldHashString functions;
@noble/hashes stays as a live dependency via id/hashSource.ts. |
| packages/core/src/backwards-compatability/oldTypes.ts | Deleted — Old*
type definitions (OldBranchType, OldGTProp, OldJsxElement,
OldVariableObject, etc.) no longer needed. |
| packages/core/src/backwards-compatability/typeChecking.ts | Deleted —
isOld*/isNew* type guards for the old JSX format, no longer referenced
anywhere. |
| packages/core/src/internal.ts | Removed 26 backwards-compat
re-exports; remaining exports are unaffected. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["generaltranslation/internal"] --> B["Active Exports (kept)"]
    A --> C["backwards-compatability/ (deleted)"]

    B --> B1["settings, logging, locales"]
    B --> B2["utils: isVariable, minify, base64, etc."]
    B --> B3["derive: decodeVars, declareVar, derive, indexVars, extractVars, condenseVars"]

    C --> C1["dataConversion.ts\n14 getNew*/getOld* converters"]
    C --> C2["oldTypes.ts\n7 Old* type definitions"]
    C --> C3["typeChecking.ts\n3 isOld*/isNew* guards"]
    C --> C4["oldHashJsxChildren.ts\noldHashJsxChildren + oldHashString"]

    style C fill:#ffcccc,stroke:#cc0000
    style C1 fill:#ffdddd
    style C2 fill:#ffdddd
    style C3 fill:#ffdddd
    style C4 fill:#ffdddd
    style B fill:#ccffcc,stroke:#006600
```

</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/internal"] --> B["Active Exports (kept)"]
    A --> C["backwards-compatability/ (deleted)"]

    B --> B1["settings, logging, locales"]
    B --> B2["utils: isVariable, minify, base64, etc."]
    B --> B3["derive: decodeVars, declareVar, derive, indexVars, extractVars, condenseVars"]

    C --> C1["dataConversion.ts\n14 getNew*/getOld* converters"]
    C --> C2["oldTypes.ts\n7 Old* type definitions"]
    C --> C3["typeChecking.ts\n3 isOld*/isNew* guards"]
    C --> C4["oldHashJsxChildren.ts\noldHashJsxChildren + oldHashString"]

    style C fill:#ffcccc,stroke:#cc0000
    style C1 fill:#ffdddd
    style C2 fill:#ffdddd
    style C3 fill:#ffdddd
    style C4 fill:#ffdddd
    style B fill:#ccffcc,stroke:#006600
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["refactor(core): remove v8
backwards-comp..."](bacce40)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40685817)</sub>

<!-- /greptile_comment -->
Three files with **zero importers** anywhere (grep-verified):
gt-tanstack-start `condition-store/WritableConditionStore.ts` (orphaned
local copy — the package uses gt-i18n's writable store), gt-react-native
`utils/utils.ts` (`readAuthFromEnv`), and gt-i18n
`translations-manager/utils/types/translations-manager.ts`
(`TranslationsManagerConfig` type). All three packages build clean. Part
of the odysseus dead-code sweep.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR removes three orphaned source files that had zero importers
anywhere in their respective packages, as part of the odysseus dead-code
sweep. All three packages continue to build cleanly after the deletions.

-
**`packages/tanstack-start/src/condition-store/WritableConditionStore.ts`**:
A local duplicate of the writable condition store singleton already
provided by `gt-i18n/internal`; the package never wired this copy up.
- **`packages/react-native/src/utils/utils.ts`**: Contained a
`readAuthFromEnv` helper with no callers anywhere in the package.
-
**`packages/i18n/src/i18n-cache/translations-manager/utils/types/translations-manager.ts`**:
An unreferenced `TranslationsManagerConfig` type definition that was
never imported.

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

All three deletions are verified dead code with zero importers in their
packages — this change carries no functional risk.

Each deleted file was grep-confirmed to have no consumers anywhere in
its package or in the wider monorepo. The tanstack-start file was a
duplicate of functionality already provided by gt-i18n/internal, the
react-native helper had no callers, and the i18n type was never
imported. A changeset is included for all three packages.

No files require special attention.
</details>

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

| Filename | Overview |
|----------|----------|
| .changeset/trim-orphan-files.md | New changeset documenting the
patch-level deletion of three dead files across gt-tanstack-start,
gt-react-native, and gt-i18n. |
|
packages/i18n/src/i18n-cache/translations-manager/utils/types/translations-manager.ts
| Deleted unreferenced TranslationsManagerConfig type — grep-confirmed
zero importers in the entire i18n package. |
| packages/react-native/src/utils/utils.ts | Deleted orphaned
readAuthFromEnv function — grep-confirmed zero consumers in the entire
react-native package. |
| packages/tanstack-start/src/condition-store/WritableConditionStore.ts
| Deleted orphaned local WritableConditionStore singleton — the package
already uses the equivalent export from gt-i18n/internal, so this
duplicate was dead code. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Dead-code sweep"] --> B["gt-tanstack-start"]
    A --> C["gt-react-native"]
    A --> D["gt-i18n"]

    B --> B1["condition-store/WritableConditionStore.ts\n(duplicate of gt-i18n/internal export)"]
    B1 --> B2["🗑 Deleted — 0 importers"]

    C --> C1["utils/utils.ts\n(readAuthFromEnv)"]
    C1 --> C2["🗑 Deleted — 0 importers"]

    D --> D1["translations-manager/utils/types/translations-manager.ts\n(TranslationsManagerConfig type)"]
    D1 --> D2["🗑 Deleted — 0 importers"]
```

</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["Dead-code sweep"] --> B["gt-tanstack-start"]
    A --> C["gt-react-native"]
    A --> D["gt-i18n"]

    B --> B1["condition-store/WritableConditionStore.ts\n(duplicate of gt-i18n/internal export)"]
    B1 --> B2["🗑 Deleted — 0 importers"]

    C --> C1["utils/utils.ts\n(readAuthFromEnv)"]
    C1 --> C2["🗑 Deleted — 0 importers"]

    D --> D1["translations-manager/utils/types/translations-manager.ts\n(TranslationsManagerConfig type)"]
    D1 --> D2["🗑 Deleted — 0 importers"]
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["refactor: remove three
orphaned dead
fil..."](824bfda)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40687047)</sub>

<!-- /greptile_comment -->
`hashTemplate` (`generaltranslation/id`) has **zero consumers** anywhere
(grep-verified). Deletes the file + its barrel export;
`hashSource`/`hashString` untouched. core builds + tests pass;
dependents build. Part of the odysseus dead-code sweep.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

Removes the `hashTemplate` function and its barrel export from
`generaltranslation/id`. A codebase-wide grep confirms zero consumers of
this export remain after the deletion.

- Deletes `packages/core/src/id/hashTemplate.ts` (a thin wrapper around
`stableStringify` + `hashString`) and removes its re-export from
`packages/core/src/id.ts`.
- Adds a patch-level changeset entry; `hashSource` and `hashString` are
unaffected.

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

Safe to merge — removes a dead export with no remaining consumers in the
repository.

The deleted function was a thin, self-contained wrapper with zero
callers anywhere in the codebase. The remaining exports in the barrel
file are untouched, the changeset is correctly scoped as a patch, and no
dependents reference the removed symbol.

No files require special attention.
</details>

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

| Filename | Overview |
|----------|----------|
| .changeset/trim-core-hashtemplate.md | New changeset documenting the
patch-level removal of hashTemplate from the generaltranslation package.
|
| packages/core/src/id.ts | Barrel export for the id subpath — removes
the hashTemplate re-export; hashSource and hashString remain untouched.
|
| packages/core/src/id/hashTemplate.ts | Deleted file — contained the
hashTemplate implementation (a thin wrapper around stableStringify +
hashString). Confirmed zero consumers remain in the repo. |

</details>

<sub>Reviews (1): Last reviewed commit: ["refactor(core): remove unused
hashTempla..."](520b242)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40686968)</sub>

<!-- /greptile_comment -->
Removes `isVariableObject`, `renderSkeleton`, and `reactHasUse` (+ their
modules) from `@generaltranslation/react-core/pure` — **zero consumers**
anywhere (grep-verified). More dead code off the client-shipped `/pure`
entry. react-core + gt-react + gt-next build; react-core tests pass.
(Companion to #1699.) Part of the odysseus dead-code sweep.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR removes three unused exports — `isVariableObject`,
`renderSkeleton`, and `reactHasUse` — along with their source files from
the `@generaltranslation/react-core/pure` client-shipped entry point.
Grep-verification confirms no consumers exist anywhere in the monorepo.

- `pure.ts`: three `export { … }` lines removed; the remaining exports
are unaffected.
- Three source files deleted: `isVariableObject.ts`,
`renderSkeleton.tsx`, and `reactHasUse.ts`, each confirmed orphaned.
- A patch-level changeset entry documents the removal for downstream
consumers.

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

Safe to merge — strictly removes dead code with no remaining consumers
in the monorepo.

All three deleted symbols (`isVariableObject`, `renderSkeleton`,
`reactHasUse`) have zero import sites anywhere in the repository,
confirmed by grep. The pure.ts entry point drops only the three export
lines and is otherwise unchanged. The changeset is correctly marked as a
patch. There are no logic changes and no risk of breakage for existing
consumers.

No files require special attention.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/react-core/src/pure.ts | Three dead export lines removed;
remaining exports intact and unaffected. |
| packages/react-core/src/utils/promises/reactHasUse.ts | File deleted;
boolean utility had zero consumers in the monorepo. |
| packages/react-core/src/utils/rendering/isVariableObject.ts | File
deleted; type-guard had zero consumers in the monorepo. |
| packages/react-core/src/utils/rendering/renderSkeleton.tsx | File
deleted; skeleton renderer returned a single empty string and had zero
consumers. |
| .changeset/trim-react-core-pure-exports.md | Patch-level changeset
entry accurately describes the three removed exports. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["@generaltranslation/react-core/pure"] --> B["pure.ts (entry point)"]
    B --> C["Remaining exports\n(dictionaries, rendering utils, types…)"]
    B -. "removed" .-> D["isVariableObject\n❌ deleted"]
    B -. "removed" .-> E["renderSkeleton\n❌ deleted"]
    B -. "removed" .-> F["reactHasUse\n❌ deleted"]
    style D stroke:#f66,stroke-dasharray:5 5
    style E stroke:#f66,stroke-dasharray:5 5
    style F stroke:#f66,stroke-dasharray:5 5
```

</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"] --> B["pure.ts (entry point)"]
    B --> C["Remaining exports\n(dictionaries, rendering utils, types…)"]
    B -. "removed" .-> D["isVariableObject\n❌ deleted"]
    B -. "removed" .-> E["renderSkeleton\n❌ deleted"]
    B -. "removed" .-> F["reactHasUse\n❌ deleted"]
    style D stroke:#f66,stroke-dasharray:5 5
    style E stroke:#f66,stroke-dasharray:5 5
    style F stroke:#f66,stroke-dasharray:5 5
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["refactor(react-core): remove
unused
/pur..."](b8c1840)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40686898)</sub>

<!-- /greptile_comment -->
Removes `condition-store/localeResolver.ts` and its `gt-i18n/internal`
exports (`determineSupportedLocale`, `resolveSupportedLocale`,
`createLocaleResolver`). These were thin wrappers over
`getI18nConfig().<method>()` with **zero consumers** — callers use the
`I18nConfig` methods directly. Verified via grep across all packages;
the `LocaleCandidates` type re-export is preserved (sourced from
`I18nConfig`). gt-i18n + react-core + gt-next + gt-react-native build;
238 gt-i18n tests pass. Part of the odysseus dead-code sweep.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR removes the `condition-store/localeResolver.ts` module and its
three `/internal` exports (`determineSupportedLocale`,
`resolveSupportedLocale`, `createLocaleResolver`) from `gt-i18n`, along
with their test file and changeset entry. The functions were thin
wrappers over `getI18nConfig().<method>()` with no consumers across the
monorepo — verified here as well.

- `packages/i18n/src/condition-store/localeResolver.ts` and its tests
are deleted; the `LocaleCandidates` type re-export in `internal.ts` is
redirected to its real source (`i18n-config/I18nConfig`), preserving the
public API.
- The only existing caller
(`tanstack-start/src/functions/parseLocale.ts`) already calls
`getI18nConfig().resolveSupportedLocale()` directly, confirming no
breakage.

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

Safe to merge — removes dead code only, with no callers anywhere in the
monorepo.

All three deleted functions were pure pass-throughs to getI18nConfig()
methods. The one external caller (tanstack-start/parseLocale.ts) already
calls the underlying I18nConfig methods directly and is unaffected. The
LocaleCandidates type re-export is correctly preserved from its real
source. No logic changes, no API breakage.

No files require special attention.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/i18n/src/condition-store/localeResolver.ts | Deleted — three
thin wrapper functions with no consumers; safe removal. |
| packages/i18n/src/condition-store/__tests__/localeResolver.test.ts |
Deleted — test file for the removed module; no residual coverage gaps
since the underlying I18nConfig methods retain their own tests. |
| packages/i18n/src/internal.ts | Removed three named exports from the
deleted module; `LocaleCandidates` type re-export is correctly
redirected to its canonical source. |
| .changeset/trim-i18n-localeresolver.md | Patch-level changeset entry;
description is accurate and complete. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["gt-i18n/internal (public entry)"] --> B["LocaleCandidates type\n(re-exported from I18nConfig)"]
    A -. "REMOVED" .-> C["determineSupportedLocale\nresolveSupportedLocale\ncreateLocaleResolver"]
    C -. "were wrappers over" .-> D["getI18nConfig()"]
    D --> E["I18nConfig instance\n.determineSupportedLocale()\n.resolveSupportedLocale()"]
    F["tanstack-start/parseLocale.ts"] --> D
    F -- "calls directly" --> E
```

</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/internal (public entry)"] --> B["LocaleCandidates type\n(re-exported from I18nConfig)"]
    A -. "REMOVED" .-> C["determineSupportedLocale\nresolveSupportedLocale\ncreateLocaleResolver"]
    C -. "were wrappers over" .-> D["getI18nConfig()"]
    D --> E["I18nConfig instance\n.determineSupportedLocale()\n.resolveSupportedLocale()"]
    F["tanstack-start/parseLocale.ts"] --> D
    F -- "calls directly" --> E
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["refactor(gt-i18n): remove
unused
localeR..."](04e6541)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40686757)</sub>

<!-- /greptile_comment -->
Removes 8 long-`@deprecated` `I18nCache` methods that duplicated
`I18nConfig`/loader APIs and had **no callers**: `getDefaultLocale`,
`getLocales`, `getCustomMapping`, `getGTClass`, `getTranslationLoader`,
`resolveTranslationSync`, `getTranslations`, `getTranslationResolver`.
The TS build across gt-i18n + all consumers confirms nothing called
them. Removes now-unused imports and the tests that covered the removed
methods; 236 gt-i18n tests pass. Part of the odysseus dead-code sweep
(major version — deprecated API removal).

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR removes 8 long-deprecated `I18nCache` methods that were thin
pass-throughs to `I18nConfig` or existing cache methods
(`lookupTranslation`, `loadTranslations`, `getLookupTranslation`), along
with their unused imports (`GT`, `TranslationsLoader`) and the tests
that covered them.

- **`I18nCache.ts`**: Deletes `getDefaultLocale`, `getLocales`,
`getCustomMapping`, `getGTClass`, `getTranslationLoader`,
`resolveTranslationSync`, `getTranslations`, and
`getTranslationResolver`. No other logic is touched.
- **Tests**: Removes the dedicated `resolveTranslationSync.test.ts` file
entirely and strips the corresponding assertions from
`I18nCache.test.ts`; the 236 remaining tests continue to cover all
active behavior.
- **Changeset**: Typed as `patch`, which is safe because
`odysseus-major-version-bumps.md` already carries a `major` bump for
`gt-i18n` that takes precedence at release time.

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

Safe to merge — removes only dead, deprecated pass-through methods with
no callers in the codebase.

Every removed method was a one-liner delegating to either
getI18nConfig() or an existing I18nCache method; no business logic was
changed. The corresponding tests are correctly removed. The patch
changeset is absorbed by the existing major odysseus bump, so semver is
unaffected. No imports, types, or runtime paths outside the deleted code
are touched.

No files require special attention.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/i18n/src/i18n-cache/I18nCache.ts | Removes 8 deprecated
pass-through methods and their now-unused GT/TranslationsLoader imports;
remaining code is untouched. |
| packages/i18n/src/i18n-cache/__tests__/I18nCache.test.ts | Removes
tests for the 8 deleted methods; the remaining test suite continues to
cover active I18nCache behavior. |
| packages/i18n/src/i18n-cache/__tests__/resolveTranslationSync.test.ts
| Entire file deleted — it tested only resolveTranslationSync and
getTranslations, both of which are removed in this PR. |
| .changeset/trim-i18ncache-deprecated.md | Changeset typed as patch;
safe because odysseus-major-version-bumps.md already carries a major
bump for gt-i18n that will take precedence. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph BEFORE["Before (deprecated methods present)"]
        A1[Caller] -->|getDefaultLocale / getLocales / getCustomMapping| B1[I18nCache]
        A2[Caller] -->|getGTClass| B1
        A3[Caller] -->|getTranslationLoader| B1
        A4[Caller] -->|resolveTranslationSync| B1
        A5[Caller] -->|getTranslations / getTranslationResolver| B1
        B1 -->|delegates| C1[getI18nConfig]
        B1 -->|delegates| C2[lookupTranslation / loadTranslations / getLookupTranslation]
    end

    subgraph AFTER["After (deprecated methods removed)"]
        D1[Caller] -->|getI18nConfig directly| E1[I18nConfig]
        D2[Caller] -->|lookupTranslation / loadTranslations / getLookupTranslation| E2[I18nCache active API]
    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 (deprecated methods present)"]
        A1[Caller] -->|getDefaultLocale / getLocales / getCustomMapping| B1[I18nCache]
        A2[Caller] -->|getGTClass| B1
        A3[Caller] -->|getTranslationLoader| B1
        A4[Caller] -->|resolveTranslationSync| B1
        A5[Caller] -->|getTranslations / getTranslationResolver| B1
        B1 -->|delegates| C1[getI18nConfig]
        B1 -->|delegates| C2[lookupTranslation / loadTranslations / getLookupTranslation]
    end

    subgraph AFTER["After (deprecated methods removed)"]
        D1[Caller] -->|getI18nConfig directly| E1[I18nConfig]
        D2[Caller] -->|lookupTranslation / loadTranslations / getLookupTranslation| E2[I18nCache active API]
    end
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["refactor(gt-i18n): remove
deprecated
I18..."](35ba67c)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40687579)</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@2.14.51-odysseus.3

### Patch Changes

- Updated dependencies [b1eef00]
  - generaltranslation@9.0.0-odysseus.3
  - @generaltranslation/python-extractor@0.2.23-odysseus.3
  - @generaltranslation/supported-locales@2.1.2-odysseus.3
## @generaltranslation/compiler@1.3.25-odysseus.3

### Patch Changes

- Updated dependencies [b1eef00]
  - generaltranslation@9.0.0-odysseus.3
## generaltranslation@9.0.0-odysseus.3

### Patch Changes

- b1eef00: Remove the v8-era backwards-compatibility shim from
`generaltranslation`.

Deletes `src/backwards-compatability/` (`dataConversion`, `oldTypes`,
`typeChecking`, `oldHashJsxChildren`) and its 26 re-exports from
`generaltranslation/internal` — the old↔new JSX/variable-format
converters, legacy type guards, and the legacy hashers. These had no
consumers anywhere in the libraries; the old format they bridged is no
longer produced. Safe to drop in the next major. ~477 LOC removed from
the `/internal` entry.
## gtx-cli@2.14.51-odysseus.3

### Patch Changes

- gt@2.14.51-odysseus.3
## gt-i18n@1.0.0-odysseus.3

### Patch Changes

- b765174: Remove three orphaned, never-imported files:
- `gt-tanstack-start`: `condition-store/WritableConditionStore.ts` (an
orphaned local copy; the package uses gt-i18n's writable condition
store).
- `gt-react-native`: `utils/utils.ts` (`readAuthFromEnv`, no consumers).
- `gt-i18n`:
`i18n-cache/translations-manager/utils/types/translations-manager.ts`
(unreferenced `TranslationsManagerConfig` type).

- Updated dependencies [b1eef00]
  - generaltranslation@9.0.0-odysseus.3
  - @generaltranslation/supported-locales@2.1.2-odysseus.3
## locadex@1.0.186-odysseus.3

### Patch Changes

- gt@2.14.51-odysseus.3
## gt-next@11.0.0-odysseus.7

### Patch Changes

- Updated dependencies [b1eef00]
- Updated dependencies [b765174]
- Updated dependencies [07bfb00]
  - generaltranslation@9.0.0-odysseus.3
  - gt-i18n@1.0.0-odysseus.3
  - @generaltranslation/react-core@11.0.0-odysseus.7
  - @generaltranslation/compiler@1.3.25-odysseus.3
  - gt-react@11.0.0-odysseus.7
  - @generaltranslation/supported-locales@2.1.2-odysseus.3
## @generaltranslation/gt-next-lint@15.0.0-odysseus.7

### Patch Changes

- gt-next@11.0.0-odysseus.7
## gt-node@1.0.0-odysseus.3

### Patch Changes

- Updated dependencies [b1eef00]
- Updated dependencies [b765174]
  - generaltranslation@9.0.0-odysseus.3
  - gt-i18n@1.0.0-odysseus.3
## @generaltranslation/python-extractor@0.2.23-odysseus.3

### Patch Changes

- Updated dependencies [b1eef00]
  - generaltranslation@9.0.0-odysseus.3
## gt-react@11.0.0-odysseus.7

### Patch Changes

- Updated dependencies [b1eef00]
- Updated dependencies [b765174]
- Updated dependencies [07bfb00]
  - generaltranslation@9.0.0-odysseus.3
  - gt-i18n@1.0.0-odysseus.3
  - @generaltranslation/react-core@11.0.0-odysseus.7
  - @generaltranslation/supported-locales@2.1.2-odysseus.3
## @generaltranslation/react-core@11.0.0-odysseus.7

### Patch Changes

- 07bfb00: Remove the unused dictionary-injection helpers from
`@generaltranslation/react-core/pure`.

`collectUntranslatedEntries`, `injectAndMerge`, `injectEntry`,
`injectFallbacks`, `injectHashes`, `injectTranslations`, `getSubtree`,
`getSubtreeWithCreation`, and `stripMetadataFromEntries` were a
self-referential cluster with no consumers anywhere in the library or
its packages. Removing them (and their modules/tests) trims ~415 LOC of
dead code from the client-shipped `/pure` entry. The still-used
dictionary helpers (`getDictionaryEntry`, `getEntryAndMetadata`,
`mergeDictionaries`, `flattenDictionary`, `indexDict`,
`isDictionaryEntry`) are unchanged.

- Updated dependencies [b1eef00]
- Updated dependencies [b765174]
  - generaltranslation@9.0.0-odysseus.3
  - gt-i18n@1.0.0-odysseus.3
  - @generaltranslation/supported-locales@2.1.2-odysseus.3
## gt-react-native@11.0.0-odysseus.7

### Patch Changes

- b765174: Remove three orphaned, never-imported files:
- `gt-tanstack-start`: `condition-store/WritableConditionStore.ts` (an
orphaned local copy; the package uses gt-i18n's writable condition
store).
- `gt-react-native`: `utils/utils.ts` (`readAuthFromEnv`, no consumers).
- `gt-i18n`:
`i18n-cache/translations-manager/utils/types/translations-manager.ts`
(unreferenced `TranslationsManagerConfig` type).

- Updated dependencies [b1eef00]
- Updated dependencies [b765174]
- Updated dependencies [07bfb00]
  - generaltranslation@9.0.0-odysseus.3
  - gt-i18n@1.0.0-odysseus.3
  - @generaltranslation/react-core@11.0.0-odysseus.7
  - @generaltranslation/supported-locales@2.1.2-odysseus.3
## gt-sanity@2.0.18-odysseus.5

### Patch Changes

- Updated dependencies [b1eef00]
  - generaltranslation@9.0.0-odysseus.3
## @generaltranslation/supported-locales@2.1.2-odysseus.3

### Patch Changes

- Updated dependencies [b1eef00]
  - generaltranslation@9.0.0-odysseus.3
## gt-tanstack-start@11.0.0-odysseus.7

### Patch Changes

- b765174: Remove three orphaned, never-imported files:
- `gt-tanstack-start`: `condition-store/WritableConditionStore.ts` (an
orphaned local copy; the package uses gt-i18n's writable condition
store).
- `gt-react-native`: `utils/utils.ts` (`readAuthFromEnv`, no consumers).
- `gt-i18n`:
`i18n-cache/translations-manager/utils/types/translations-manager.ts`
(unreferenced `TranslationsManagerConfig` type).

- Updated dependencies [b1eef00]
- Updated dependencies [b765174]
- Updated dependencies [07bfb00]
  - generaltranslation@9.0.0-odysseus.3
  - gt-i18n@1.0.0-odysseus.3
  - @generaltranslation/react-core@11.0.0-odysseus.7
  - gt-react@11.0.0-odysseus.7

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
`validateLocales` was defined but never wired into config validation
(which runs
`validateLoadTranslations`/`validateTranslationApi`/`validateDictionary`)
and has **zero consumers** anywhere (grep-verified). Deletes the file +
its test. gt-i18n builds and tests pass. Part of the odysseus dead-code
sweep.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR removes the `validateLocales` function and its test from
`gt-i18n` as part of a dead-code sweep. The function validated BCP 47
locale codes but was never wired into `validateConfig`, which only calls
`validateLoadTranslations`, `validateTranslationApi`, and
`validateDictionary`.

- Deletes `validateLocales.ts` and its accompanying Vitest test file —
confirmed zero consumers in the repo.
- Adds a patch-level changeset entry documenting the removal.

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

Straightforward dead-code removal with no runtime impact — the deleted
function was never invoked by any code path.

The deleted file was never imported by validateConfig or any other
module; the grep confirms zero consumers remain. Removing it and its
test leaves the validation pipeline unchanged.

No files require special attention.
</details>

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

| Filename | Overview |
|----------|----------|
|
packages/i18n/src/i18n-cache/validation/config-validation/validateLocales.ts
| Dead-code validator deleted; confirmed it was never imported by
validateConfig or any other consumer. |
|
packages/i18n/src/i18n-cache/validation/config-validation/__tests__/validateLocales.test.ts
| Test file for the deleted validator removed; no orphaned references
remain. |
| .changeset/trim-i18n-validatelocales.md | Patch-level changeset entry
accurately describes the removal. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[validateConfig] --> B[validateLoadTranslations]
    A --> C[validateTranslationApi]
    A --> D[validateDictionary]
    E["validateLocales (deleted)"] -.->|"was never called"| A
    style E stroke-dasharray: 5 5,color:#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[validateConfig] --> B[validateLoadTranslations]
    A --> C[validateTranslationApi]
    A --> D[validateDictionary]
    E["validateLocales (deleted)"] -.->|"was never called"| A
    style E stroke-dasharray: 5 5,color:#999,fill:#f9f9f9
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["refactor(gt-i18n): remove
unused
validat..."](43fb20e)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40686819)</sub>

<!-- /greptile_comment -->
Removes 21 error/warning builders from `errors/createErrors.ts` that
have **zero consumers** anywhere (grep-verified each). ~155 LOC of dead
error-string code, some of which shipped to bundles. The 29 still-used
builders are unchanged. gt-next builds; 191 tests pass. Part of the
odysseus dead-code sweep.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR removes 21 dead error/warning builder functions from
`packages/next/src/errors/createErrors.ts` (~155 LOC), along with the
now-unused `formatDiagnosticErrorDetails` import. The 29 remaining
builders are untouched and the changeset is correctly scoped as a patch.

- **Dead code removed**: 21 exported functions
(`createDictionaryTranslationError`, `gtProviderUseClientError`,
`noInitGTWarn`, `runtimeTranslationTimeoutWarning`, and 17 others) that
had zero consumers in the repo were deleted.
- **Import cleaned up**: `formatDiagnosticErrorDetails` was the only
import whose sole callers (`createStringRenderError` /
`createStringRenderWarning`) were among the deleted functions; it was
correctly removed in the same commit.

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

Pure dead-code removal with no changes to active error paths; safe to
merge.

Every deleted symbol was confirmed to have zero consumers, the unused
import was correctly cleaned up in the same commit, and the 29
still-used builders are untouched.

No files require special attention.
</details>


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




| Filename | Overview |
|----------|----------|
| packages/next/src/errors/createErrors.ts | Removes 21 unused exported
error/warning builders and the now-orphaned
`formatDiagnosticErrorDetails` import; all 29 remaining builders and
their consumers are unchanged. |
| .changeset/trim-next-createerrors.md | Correct patch-level changeset
enumerating all 21 removed symbols; no issues. |

</details>


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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[createErrors.ts\n29 remaining builders] --> B[createGtNextDiagnostic]
    A --> C[createGtNextPluginDiagnostic]
    B --> D[diagnostics.ts]
    C --> D

    DEL["❌ Removed — 21 unused builders\n(createStringRenderError, gtProviderUseClientError,\nnoInitGTWarn, runtimeTranslationTimeoutWarning,\ncreateStringRenderWarning, dictionaryDisabledError,\ncreateTranslationLoadingWarning, … +14 more)"]
    DEL -. was calling .-> FMT["❌ formatDiagnosticErrorDetails\n(import also removed)"]
    FMT -. was imported from .-> D
```

</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[createErrors.ts\n29 remaining builders] --> B[createGtNextDiagnostic]
    A --> C[createGtNextPluginDiagnostic]
    B --> D[diagnostics.ts]
    C --> D

    DEL["❌ Removed — 21 unused builders\n(createStringRenderError, gtProviderUseClientError,\nnoInitGTWarn, runtimeTranslationTimeoutWarning,\ncreateStringRenderWarning, dictionaryDisabledError,\ncreateTranslationLoadingWarning, … +14 more)"]
    DEL -. was calling .-> FMT["❌ formatDiagnosticErrorDetails\n(import also removed)"]
    FMT -. was imported from .-> D
```

</a>
</details>


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

1. `packages/next/src/errors/createErrors.ts`, line 4-8
([link](https://github.com/generaltranslation/gt/blob/3d7fd6cda7f5364f90381634aa4975fa717c1616/packages/next/src/errors/createErrors.ts#L4-L8))

<a href="#"><img alt="P2"
src="https://greptile-static-assets.s3.amazonaws.com/badges/p2.svg?v=9"
align="top"></a> The `formatDiagnosticErrorDetails` import is now
unused. The only two callers — `createStringRenderError` and
`createStringRenderWarning` — were both removed in this PR, leaving the
import as dead code. TypeScript (and any lint rule for `no-unused-vars`)
will flag this.

   

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

   `````markdown
   This is a comment left during a code review.
   Path: packages/next/src/errors/createErrors.ts
   Line: 4-8

   Comment:
The `formatDiagnosticErrorDetails` import is now unused. The only two
callers — `createStringRenderError` and `createStringRenderWarning` —
were both removed in this PR, leaving the import as dead code.
TypeScript (and any lint rule for `no-unused-vars`) will flag this.

   

   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%2Ferrors%2FcreateErrors.ts%0ALine%3A%204-8%0A%0AComment%3A%0AThe%20%60formatDiagnosticErrorDetails%60%20import%20is%20now%20unused.%20The%20only%20two%20callers%20%E2%80%94%20%60createStringRenderError%60%20and%20%60createStringRenderWarning%60%20%E2%80%94%20were%20both%20removed%20in%20this%20PR%2C%20leaving%20the%20import%20as%20dead%20code.%20TypeScript%20%28and%20any%20lint%20rule%20for%20%60no-unused-vars%60%29%20will%20flag%20this.%0A%0A%60%60%60suggestion%0Aimport%20%7B%0A%20%20createGtNextDiagnostic%2C%0A%20%20createGtNextPluginDiagnostic%2C%0A%7D%20from%20'.%2Fdiagnostics'%3B%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=1707&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaudeDark.svg?v=3"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=3"><img
alt="Fix in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=3"
height="20"></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%2Fodysseus-trim-next-createerrors%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%2Fodysseus-trim-next-createerrors%22.%0A%0AThis%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20packages%2Fnext%2Fsrc%2Ferrors%2FcreateErrors.ts%0ALine%3A%204-8%0A%0AComment%3A%0AThe%20%60formatDiagnosticErrorDetails%60%20import%20is%20now%20unused.%20The%20only%20two%20callers%20%E2%80%94%20%60createStringRenderError%60%20and%20%60createStringRenderWarning%60%20%E2%80%94%20were%20both%20removed%20in%20this%20PR%2C%20leaving%20the%20import%20as%20dead%20code.%20TypeScript%20%28and%20any%20lint%20rule%20for%20%60no-unused-vars%60%29%20will%20flag%20this.%0A%0A%60%60%60suggestion%0Aimport%20%7B%0A%20%20createGtNextDiagnostic%2C%0A%20%20createGtNextPluginDiagnostic%2C%0A%7D%20from%20'.%2Fdiagnostics'%3B%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=1707&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodexDark.svg?v=3"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=3"><img
alt="Fix in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=3"
height="20"></picture></a>
</details>

<!-- /greptile_failed_comments -->

<sub>Reviews (2): Last reviewed commit: ["refactor(gt-next): drop
now-unused
forma..."](646c8b8)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40687204)</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@2.14.51-odysseus.4

### Patch Changes

- Updated dependencies [26faa87]
  - generaltranslation@9.0.0-odysseus.4
  - @generaltranslation/python-extractor@0.2.23-odysseus.4
  - @generaltranslation/supported-locales@2.1.2-odysseus.4
## @generaltranslation/compiler@1.3.25-odysseus.4

### Patch Changes

- Updated dependencies [26faa87]
  - generaltranslation@9.0.0-odysseus.4
## generaltranslation@9.0.0-odysseus.4

### Patch Changes

- 26faa87: Remove the unused `hashTemplate` export from
`generaltranslation/id`. It had no consumers anywhere in the libraries.
`hashSource`/`hashString` are unchanged.
## gtx-cli@2.14.51-odysseus.4

### Patch Changes

- gt@2.14.51-odysseus.4
## gt-i18n@1.0.0-odysseus.4

### Patch Changes

- 270b821: Remove the unused `condition-store/localeResolver` module
from `gt-i18n/internal`.

`determineSupportedLocale`, `resolveSupportedLocale`, and
`createLocaleResolver` were thin wrappers over
`getI18nConfig().<method>()`. They had no consumers — callers (e.g.
tanstack-start) use the `I18nConfig` methods directly via
`getI18nConfig()`. Removing the module trims dead indirection from the
`/internal` entry; the `LocaleCandidates` type re-export is unaffected
(re-exported from its real source).

- bffaa67: Remove the unused `validateLocales` config validator from
`gt-i18n`.

`validateLocales` was defined but never called (config validation runs
`validateLoadTranslations`, `validateTranslationApi`, and
`validateDictionary`) and had no consumers anywhere. Dead code removed.

- d602065: Remove deprecated methods from `gt-i18n`'s `I18nCache`.

Dropped the long-`@deprecated` cache methods that duplicated
`I18nConfig`/loader APIs: `getDefaultLocale`, `getLocales`,
`getCustomMapping`, `getGTClass`, `getTranslationLoader`,
`resolveTranslationSync`, `getTranslations`, and
`getTranslationResolver`. None were called anywhere (consumers use
`getI18nConfig()` / `lookupTranslation` / `loadTranslations`). Removes
the methods, their now-unused imports, and the tests that covered them.

- Updated dependencies [26faa87]
  - generaltranslation@9.0.0-odysseus.4
  - @generaltranslation/supported-locales@2.1.2-odysseus.4
## locadex@1.0.186-odysseus.4

### Patch Changes

- gt@2.14.51-odysseus.4
## gt-next@11.0.0-odysseus.8

### Patch Changes

- Updated dependencies [26faa87]
- Updated dependencies [270b821]
- Updated dependencies [bffaa67]
- Updated dependencies [d602065]
- Updated dependencies [6da26e8]
  - generaltranslation@9.0.0-odysseus.4
  - gt-i18n@1.0.0-odysseus.4
  - @generaltranslation/react-core@11.0.0-odysseus.8
  - @generaltranslation/compiler@1.3.25-odysseus.4
  - gt-react@11.0.0-odysseus.8
  - @generaltranslation/supported-locales@2.1.2-odysseus.4
## @generaltranslation/gt-next-lint@15.0.0-odysseus.8

### Patch Changes

- gt-next@11.0.0-odysseus.8
## gt-node@1.0.0-odysseus.4

### Patch Changes

- Updated dependencies [26faa87]
- Updated dependencies [270b821]
- Updated dependencies [bffaa67]
- Updated dependencies [d602065]
  - generaltranslation@9.0.0-odysseus.4
  - gt-i18n@1.0.0-odysseus.4
## @generaltranslation/python-extractor@0.2.23-odysseus.4

### Patch Changes

- Updated dependencies [26faa87]
  - generaltranslation@9.0.0-odysseus.4
## gt-react@11.0.0-odysseus.8

### Patch Changes

- Updated dependencies [26faa87]
- Updated dependencies [270b821]
- Updated dependencies [bffaa67]
- Updated dependencies [d602065]
- Updated dependencies [6da26e8]
  - generaltranslation@9.0.0-odysseus.4
  - gt-i18n@1.0.0-odysseus.4
  - @generaltranslation/react-core@11.0.0-odysseus.8
  - @generaltranslation/supported-locales@2.1.2-odysseus.4
## @generaltranslation/react-core@11.0.0-odysseus.8

### Patch Changes

- 6da26e8: Remove three unused exports from
`@generaltranslation/react-core/pure`: `isVariableObject`,
`renderSkeleton`, and `reactHasUse`. None had consumers anywhere in the
libraries. Trims dead code from the client-shipped `/pure` entry.
- Updated dependencies [26faa87]
- Updated dependencies [270b821]
- Updated dependencies [bffaa67]
- Updated dependencies [d602065]
  - generaltranslation@9.0.0-odysseus.4
  - gt-i18n@1.0.0-odysseus.4
  - @generaltranslation/supported-locales@2.1.2-odysseus.4
## gt-react-native@11.0.0-odysseus.8

### Patch Changes

- Updated dependencies [26faa87]
- Updated dependencies [270b821]
- Updated dependencies [bffaa67]
- Updated dependencies [d602065]
- Updated dependencies [6da26e8]
  - generaltranslation@9.0.0-odysseus.4
  - gt-i18n@1.0.0-odysseus.4
  - @generaltranslation/react-core@11.0.0-odysseus.8
  - @generaltranslation/supported-locales@2.1.2-odysseus.4
## gt-sanity@2.0.18-odysseus.6

### Patch Changes

- Updated dependencies [26faa87]
  - generaltranslation@9.0.0-odysseus.4
## @generaltranslation/supported-locales@2.1.2-odysseus.4

### Patch Changes

- Updated dependencies [26faa87]
  - generaltranslation@9.0.0-odysseus.4
## gt-tanstack-start@11.0.0-odysseus.8

### Patch Changes

- Updated dependencies [26faa87]
- Updated dependencies [270b821]
- Updated dependencies [bffaa67]
- Updated dependencies [d602065]
- Updated dependencies [6da26e8]
  - generaltranslation@9.0.0-odysseus.4
  - gt-i18n@1.0.0-odysseus.4
  - @generaltranslation/react-core@11.0.0-odysseus.8
  - gt-react@11.0.0-odysseus.8

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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-next@11.0.0-odysseus.9

### Patch Changes

- cf3e961: Remove 21 unused error/warning builders from `gt-next`'s
`errors/createErrors.ts`.

The following had no consumers anywhere:
`createDictionaryTranslationError`,
`createInvalidDictionaryEntryWarning`,
`createInvalidDictionaryTranslationEntryWarning`,
`createInvalidIcuDictionaryEntryError`,
`createInvalidIcuDictionaryEntryWarning`,
`createMismatchingHashWarning`, `createNoEntryFoundWarning`,
`createRequiredPrefixError`, `createStringRenderError`,
`createStringRenderWarning`, `createStringTranslationError`,
`createTranslationLoadingWarning`, `dictionaryDisabledError`,
`dictionaryNotFoundWarning`, `gtProviderUseClientError`,
`missingVariablesError`, `noInitGTWarn`,
`runtimeTranslationTimeoutWarning`, `txUseClientError`,
`unresolvedGetLocaleBuildError`, `usingDefaultsWarning`. ~155 LOC of
dead error-string code removed.
  - @generaltranslation/react-core@11.0.0-odysseus.9
  - gt-react@11.0.0-odysseus.9
## @generaltranslation/gt-next-lint@15.0.0-odysseus.9

### Patch Changes

- Updated dependencies [cf3e961]
  - gt-next@11.0.0-odysseus.9
## gt-react@11.0.0-odysseus.9

### Patch Changes

- @generaltranslation/react-core@11.0.0-odysseus.9
## gt-react-native@11.0.0-odysseus.9

### Patch Changes

- @generaltranslation/react-core@11.0.0-odysseus.9
## gt-tanstack-start@11.0.0-odysseus.9

### Patch Changes

- @generaltranslation/react-core@11.0.0-odysseus.9
- gt-react@11.0.0-odysseus.9
## @generaltranslation/react-core@11.0.0-odysseus.9

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@eoinest
eoinest requested a review from a team as a code owner June 30, 2026 02:07
Base automatically changed from odysseus to main July 4, 2026 02:24
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.

3 participants