Skip to content

docs: document package src entrypoint layout#1763

Open
ErnestM1234 wants to merge 191 commits into
mainfrom
e/odysseus/agent-guides-src-entrypoints
Open

docs: document package src entrypoint layout#1763
ErnestM1234 wants to merge 191 commits into
mainfrom
e/odysseus/agent-guides-src-entrypoints

Conversation

@ErnestM1234

@ErnestM1234 ErnestM1234 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Document that top-level package src files are reserved for consumer entrypoints
  • Add package-area reminders for React, core, CLI, compiler, and linter packages
  • Update the compiler-local agent guide to treat non-entrypoint top-level files as legacy

Testing

  • Not run (documentation-only change).

Greptile Summary

This PR adds consistent documentation across .claude/ agent-guide files declaring that top-level src files in every package are reserved for package entrypoints (e.g. index.ts, main.ts, subpath-exported files) and that all implementation logic belongs in src subdirectories.

  • Adds an identical entrypoint-layout rule to .claude/CLAUDE.md, all five area rule files (cli.md, compiler.md, core.md, linter-plugins.md, react-packages.md), and the implement-feature skill.
  • Updates packages/compiler/.claude/CLAUDE.md to show a "target organization" code-org tree (replacing config.ts with config/), labels the existing src/config.ts as a legacy location, and clarifies that non-entrypoint top-level files are not precedents for new code.

Confidence Score: 5/5

Documentation-only change with no runtime impact; safe to merge.

All eight changed files are agent-guide markdown files. The new entrypoint-layout rule is applied consistently across every relevant rule file and skill, and the compiler-local guide correctly distinguishes the current legacy config.ts from the desired config/ subdirectory. Verified against the actual packages/compiler/src/ layout — only index.ts and config.ts exist at the root, matching the documentation exactly.

No files require special attention.

Important Files Changed

Filename Overview
.claude/CLAUDE.md Adds the new entrypoint-layout convention to the global Code Conventions section; change is accurate and consistent with the rest of the file.
.claude/rules/cli.md Appends subdirectory guidance to the CLI entry-point note; src/generated/ is already a subdirectory, so no conflict with the new rule.
.claude/rules/compiler.md Adds entrypoint-only rule for the compiler's src/ root; matches the actual layout (only index.ts and the legacy config.ts exist at the root).
.claude/rules/core.md Adds the entrypoint-only rule with concrete examples (index.ts, internal.ts, types.ts); clear and accurate.
.claude/rules/linter-plugins.md Adds entrypoint rule with example subdirectory names (src/rules/, src/utils/); consistent with other rule files.
.claude/rules/react-packages.md Adds entrypoint-only rule for .ts and .tsx files; consistent and accurate for the React package family.
.claude/skills/implement-feature.md Adds a layout-check reminder to Phase 3 implementation guidance; well-placed and consistent with the other rule additions.
packages/compiler/.claude/CLAUDE.md Adds "target organization" framing, relabels config.ts as a legacy location, and updates the config section reference; verified against the actual src/ layout (only index.ts and config.ts at the root).

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[New file needed in a package] --> B{Is it a package entrypoint?\ne.g. referenced in package.json\nexports / bin / documented subpath}
    B -- Yes --> C[Place at src/ root\ne.g. src/index.ts, src/main.ts]
    B -- No --> D[Place under a src/ subdirectory\ne.g. src/utils/, src/config/,\nsrc/rules/, src/passes/]
    D --> E[Implementation logic\nHelpers / Config / Types\nComponents / Hooks / Commands]
    C --> F[Package entrypoints\nConsumed via package.json exports\nor bin entries]
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
    A[New file needed in a package] --> B{Is it a package entrypoint?\ne.g. referenced in package.json\nexports / bin / documented subpath}
    B -- Yes --> C[Place at src/ root\ne.g. src/index.ts, src/main.ts]
    B -- No --> D[Place under a src/ subdirectory\ne.g. src/utils/, src/config/,\nsrc/rules/, src/passes/]
    D --> E[Implementation logic\nHelpers / Config / Types\nComponents / Hooks / Commands]
    C --> F[Package entrypoints\nConsumed via package.json exports\nor bin entries]
Loading

Reviews (2): Last reviewed commit: "docs: document package src entrypoint la..." | Re-trigger Greptile

bgub and others added 23 commits June 29, 2026 19:25
## Summary
- key generated GTJSON/source entries by content hash instead of custom
id
- keep custom ids as metadata while excluding them from calculated
hashes
- remove id-based duplicate rejection now that ids are metadata-only

## Tests
- pnpm --filter gt test -- src/translation/__tests__/parse.test.ts
src/extraction/__tests__/postProcess.test.ts
src/formats/files/__tests__/collectFiles.test.ts
- pnpm --filter gt typecheck
- pnpm --filter @generaltranslation/compiler test --
src/utils/__tests__/calculateHash.test.ts
- pnpm --filter @generaltranslation/compiler typecheck
- pnpm --filter generaltranslation test --
src/translate/__tests__/translateMany.test.ts
- pnpm --filter generaltranslation typecheck
- pnpm --filter gt-i18n typecheck
- pnpm --filter @generaltranslation/react-core typecheck

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR changes how translation entries are keyed: from using a custom
`id` (when present) as the primary lookup key to using a content-based
hash that excludes the `id`. The `id` is now kept purely as metadata to
aid debugging and duplicate validation, but it no longer participates in
hash computation.

- All hash-computation call sites (`calculateHashes`,
`createDictionaryUpdates`, `hashMessage`, `registerUseGTCallback`,
`registerStandaloneTranslation`, `translateMany`) remove `id` from the
fields passed to `hashSource`, making hashes stable across different
user-supplied IDs.
- `collectFiles.ts` and `inline.ts` are updated to key data exclusively
by hash rather than falling back to `id`; `parse.ts` retains ID
validation but now only rejects entries whose IDs map to *different*
hashes (conflicting content), rather than treating the ID itself as the
storage key.
- New tests explicitly verify that two entries with different IDs but
identical content produce identical hashes.

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

Safe to merge; the change is consistently applied across all
hash-computation sites and the ID validation in parse.ts correctly
catches conflicting-id errors without relying on id as a storage key.

All six call sites that previously included `id` in hash computation
have been updated in lockstep. Dictionary entries, inline entries,
runtime translation, and the i18n utility all follow the same new
contract. New tests explicitly verify the id-exclusion behavior and the
conflicting-id error path still fires correctly.

No files require special attention.
</details>


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




| Filename | Overview |
|----------|----------|
| packages/core/src/translate/translateMany.ts | Replaces the broad
`...metadata` spread in the fallback hash computation with explicit
`context` and `maxChars` fields, correctly excluding `id` and other
irrelevant metadata fields from the hash. |
| packages/cli/src/translation/parse.ts | Retains ID-conflict validation
(same id, different hashes → error + filter) while removing the
id-as-primary-key role; the filter and error path remain semantically
correct under the new scheme. |
| packages/compiler/src/utils/calculateHash.ts | Removes `id` from the
parameter type and both `_hashSource` call sites; the previously noted
stale `id?: string` in the type signature is now fully cleaned up. |
| packages/i18n/src/utils/hashMessage.ts | Removes `$id` from the
`hashSource` call; the `$_hash` fast-path and `$context`/`$maxChars`
handling are unchanged. |
| packages/cli/src/formats/files/collectFiles.ts | Now keys both
`fileData` and `fileMetadata` exclusively by hash; entries without a
computed hash are silently dropped, which is safe because all pipeline
stages guarantee a hash before reaching this point. |
| packages/cli/src/extraction/postProcess.ts | Removes the `id` field
from the `hashSource` call in `calculateHashes`, making this the
canonical point where id-agnostic hashes are computed for inline
updates. |
| packages/cli/src/cli/inline.ts | Removes the `id`-first keying branch
in `handleGenerateSourceCommand`; safe because
`aggregateInlineTranslations` always populates `metadata.hash` before
this loop runs. |

</details>


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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Source entry\n(source, id?, context?, maxChars?)"] --> B["hashSource()\nexcludes id"]
    B --> C["content hash H"]
    C --> D{hash already\nprecomputed?}
    D -- "yes (metadata.hash)" --> E["use precomputed hash"]
    D -- "no" --> B
    E --> F["fileData[H] = source\nfileMetadata[H] = {id, hash, ...}"]
    F --> G["Upload to GT API\nkeyed by H"]
    G --> H["Translation result\nkeyed by H"]

    subgraph "ID Validation (parse.ts)"
        I["Same id, same hash"] --> J["Both pass through\n(deduplicated downstream by H)"]
        K["Same id, diff hash"] --> L["Error + filtered out"]
    end

    A --> I
    A --> K
```

</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["Source entry\n(source, id?, context?, maxChars?)"] --> B["hashSource()\nexcludes id"]
    B --> C["content hash H"]
    C --> D{hash already\nprecomputed?}
    D -- "yes (metadata.hash)" --> E["use precomputed hash"]
    D -- "no" --> B
    E --> F["fileData[H] = source\nfileMetadata[H] = {id, hash, ...}"]
    F --> G["Upload to GT API\nkeyed by H"]
    G --> H["Translation result\nkeyed by H"]

    subgraph "ID Validation (parse.ts)"
        I["Same id, same hash"] --> J["Both pass through\n(deduplicated downstream by H)"]
        K["Same id, diff hash"] --> L["Error + filtered out"]
    end

    A --> I
    A --> K
```

</a>
</details>


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

1. `packages/react-core/src/utils/dictionaries/injectHashes.ts`, line
13-40
([link](https://github.com/generaltranslation/gt/blob/100b40afe648c7e2d60756415c1284d39e396b72/packages/react-core/src/utils/dictionaries/injectHashes.ts#L13-L40))

<a href="#"><img alt="P2"
src="https://greptile-static-assets.s3.amazonaws.com/badges/p2.svg?v=9"
align="top"></a> The `id` parameter and `wholeId` variable are now
functionally dead code: `wholeId` is built on every iteration and passed
to recursive calls, but nothing in the recursion chain uses it to affect
the hash output. Passing `injectHashes(dict, 'custom.prefix')` produces
identical hashes to `injectHashes(dict)` (confirmed by the updated
test). The parameter and variable can be removed entirely to avoid
confusion.

   

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

   `````markdown
   This is a comment left during a code review.
   Path: packages/react-core/src/utils/dictionaries/injectHashes.ts
   Line: 13-40

   Comment:
The `id` parameter and `wholeId` variable are now functionally dead
code: `wholeId` is built on every iteration and passed to recursive
calls, but nothing in the recursion chain uses it to affect the hash
output. Passing `injectHashes(dict, 'custom.prefix')` produces identical
hashes to `injectHashes(dict)` (confirmed by the updated test). The
parameter and variable can be removed entirely to avoid confusion.

   

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

<a
href="https://app.greptile.com/ide/claude-code?prompt=This%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20packages%2Freact-core%2Fsrc%2Futils%2Fdictionaries%2FinjectHashes.ts%0ALine%3A%2013-40%0A%0AComment%3A%0AThe%20%60id%60%20parameter%20and%20%60wholeId%60%20variable%20are%20now%20functionally%20dead%20code%3A%20%60wholeId%60%20is%20built%20on%20every%20iteration%20and%20passed%20to%20recursive%20calls%2C%20but%20nothing%20in%20the%20recursion%20chain%20uses%20it%20to%20affect%20the%20hash%20output.%20Passing%20%60injectHashes%28dict%2C%20'custom.prefix'%29%60%20produces%20identical%20hashes%20to%20%60injectHashes%28dict%29%60%20%28confirmed%20by%20the%20updated%20test%29.%20The%20parameter%20and%20variable%20can%20be%20removed%20entirely%20to%20avoid%20confusion.%0A%0A%60%60%60suggestion%0Aexport%20function%20injectHashes%28%0A%20%20dictionary%3A%20Dictionary%0A%29%3A%20%7B%20dictionary%3A%20Dictionary%3B%20updateDictionary%3A%20boolean%20%7D%20%7B%0A%20%20let%20updateDictionary%20%3D%20false%3B%0A%20%20Object.entries%28dictionary%29.forEach%28%28%5Bkey%2C%20value%5D%29%20%3D%3E%20%7B%0A%20%20%20%20if%20%28isDictionaryEntry%28value%29%29%20%7B%0A%20%20%20%20%20%20%2F%2F%20eslint-disable-next-line%20prefer-const%0A%20%20%20%20%20%20let%20%7B%20entry%2C%20metadata%20%7D%20%3D%20getEntryAndMetadata%28value%29%3B%0A%20%20%20%20%20%20if%20%28!metadata%3F.%24_hash%29%20%7B%0A%20%20%20%20%20%20%20%20metadata%20%7C%7C%3D%20%7B%7D%3B%0A%20%20%20%20%20%20%20%20metadata.%24_hash%20%3D%20hashSource%28%7B%0A%20%20%20%20%20%20%20%20%20%20source%3A%20indexVars%28entry%29%2C%0A%20%20%20%20%20%20%20%20%20%20...%28metadata%3F.%24context%20%26%26%20%7B%20context%3A%20metadata.%24context%20%7D%29%2C%0A%20%20%20%20%20%20%20%20%20%20...%28metadata%3F.%24maxChars%20!%3D%20null%20%26%26%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20maxChars%3A%20Math.abs%28metadata.%24maxChars%29%2C%0A%20%20%20%20%20%20%20%20%20%20%7D%29%2C%0A%20%20%20%20%20%20%20%20%20%20dataFormat%3A%20'ICU'%2C%0A%20%20%20%20%20%20%20%20%7D%29%3B%0A%20%20%20%20%20%20%20%20set%28dictionary%2C%20key%2C%20%5Bentry%2C%20metadata%5D%29%3B%0A%20%20%20%20%20%20%20%20updateDictionary%20%3D%20true%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20const%20%7B%20updateDictionary%3A%20updateFlag%20%7D%20%3D%20injectHashes%28value%29%3B%0A%20%20%20%20%20%20updateDictionary%20%3D%20updateDictionary%20%7C%7C%20updateFlag%3B%0A%20%20%20%20%7D%0A%20%20%7D%29%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=1696&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%2Fhash-translation-keys%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%2Fhash-translation-keys%22.%0A%0AThis%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20packages%2Freact-core%2Fsrc%2Futils%2Fdictionaries%2FinjectHashes.ts%0ALine%3A%2013-40%0A%0AComment%3A%0AThe%20%60id%60%20parameter%20and%20%60wholeId%60%20variable%20are%20now%20functionally%20dead%20code%3A%20%60wholeId%60%20is%20built%20on%20every%20iteration%20and%20passed%20to%20recursive%20calls%2C%20but%20nothing%20in%20the%20recursion%20chain%20uses%20it%20to%20affect%20the%20hash%20output.%20Passing%20%60injectHashes%28dict%2C%20'custom.prefix'%29%60%20produces%20identical%20hashes%20to%20%60injectHashes%28dict%29%60%20%28confirmed%20by%20the%20updated%20test%29.%20The%20parameter%20and%20variable%20can%20be%20removed%20entirely%20to%20avoid%20confusion.%0A%0A%60%60%60suggestion%0Aexport%20function%20injectHashes%28%0A%20%20dictionary%3A%20Dictionary%0A%29%3A%20%7B%20dictionary%3A%20Dictionary%3B%20updateDictionary%3A%20boolean%20%7D%20%7B%0A%20%20let%20updateDictionary%20%3D%20false%3B%0A%20%20Object.entries%28dictionary%29.forEach%28%28%5Bkey%2C%20value%5D%29%20%3D%3E%20%7B%0A%20%20%20%20if%20%28isDictionaryEntry%28value%29%29%20%7B%0A%20%20%20%20%20%20%2F%2F%20eslint-disable-next-line%20prefer-const%0A%20%20%20%20%20%20let%20%7B%20entry%2C%20metadata%20%7D%20%3D%20getEntryAndMetadata%28value%29%3B%0A%20%20%20%20%20%20if%20%28!metadata%3F.%24_hash%29%20%7B%0A%20%20%20%20%20%20%20%20metadata%20%7C%7C%3D%20%7B%7D%3B%0A%20%20%20%20%20%20%20%20metadata.%24_hash%20%3D%20hashSource%28%7B%0A%20%20%20%20%20%20%20%20%20%20source%3A%20indexVars%28entry%29%2C%0A%20%20%20%20%20%20%20%20%20%20...%28metadata%3F.%24context%20%26%26%20%7B%20context%3A%20metadata.%24context%20%7D%29%2C%0A%20%20%20%20%20%20%20%20%20%20...%28metadata%3F.%24maxChars%20!%3D%20null%20%26%26%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20maxChars%3A%20Math.abs%28metadata.%24maxChars%29%2C%0A%20%20%20%20%20%20%20%20%20%20%7D%29%2C%0A%20%20%20%20%20%20%20%20%20%20dataFormat%3A%20'ICU'%2C%0A%20%20%20%20%20%20%20%20%7D%29%3B%0A%20%20%20%20%20%20%20%20set%28dictionary%2C%20key%2C%20%5Bentry%2C%20metadata%5D%29%3B%0A%20%20%20%20%20%20%20%20updateDictionary%20%3D%20true%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20const%20%7B%20updateDictionary%3A%20updateFlag%20%7D%20%3D%20injectHashes%28value%29%3B%0A%20%20%20%20%20%20updateDictionary%20%3D%20updateDictionary%20%7C%7C%20updateFlag%3B%0A%20%20%20%20%7D%0A%20%20%7D%29%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=1696&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: remove ignored compiler
hash id
par..."](b193060)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40680642)</sub>

<!-- /greptile_comment -->
…1709)

`getDomain` was scaffolded but never wired to any runtime consumer —
there's no `getDomain()` request helper, nothing reads
`_GENERALTRANSLATION_CUSTOM_GET_DOMAIN_ENABLED`, and no package imports
it (grep-verified). Removes: the throw-only `internal/_getDomain` stub +
its `./internal/_getDomain` export (and typesVersions/paths), the
`getDomainPath` config prop, the `getDomain` entries in the
request-function registry/aliases/config-key map, and the dead build env
var. `getLocale`/`getRegion` are untouched. Static (`getStaticDomain`) +
experimental references are left for the follow-up SSG/experimental
cleanup. gt-next builds; 191 tests pass (updated the
env-var-completeness test). Part of the odysseus dead-code sweep.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR removes dead-code scaffolding for a `getDomain` request function
that was never wired to a runtime consumer in `gt-next`. Every reference
to `getDomain` in the request-function registry, config-key map, build
env var, package exports, type declarations, and the throw-only stub
module is cleaned up in one coherent sweep.

- Deletes `packages/next/src/internal/_getDomain.ts` (stub that always
threw), removes its `package.json` exports/typesVersions/paths entries,
and drops the `./internal/_getDomain` size-limit entry.
- Removes `getDomainPath` from `BaseWithGTConfigProps`,
`REQUEST_FUNCTION_TO_CONFIG_KEY`, `REQUEST_FUNCTION_ALIASES`,
`REQUEST_FUNCTIONS`, and the
`_GENERALTRANSLATION_CUSTOM_GET_DOMAIN_ENABLED` build env var from
`withGTConfig`.
- Updates the env-var-completeness test to match; `getStaticDomain` and
experimental-feature references are explicitly deferred to a follow-up
cleanup.

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

Safe to merge — removes code that was never reachable at runtime.

Every deleted symbol (getDomain registry entry, getDomainPath prop,
_getDomain stub, build env var, package exports) was scaffolding that
was never consumed by any runtime path. The remaining
getLocale/getRegion plumbing is untouched, getStaticDomain references
are intentionally preserved, and the test suite was updated to match.
There are no behavior changes, no API surface breaks for published
consumers, and no missing cleanup in the changed files.

No files require special attention.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/next/src/internal/_getDomain.ts | Deleted — throw-only stub
that was never called by any consumer; safe to remove. |
| packages/next/package.json | Removes the ./internal/_getDomain export,
typesVersions, and paths entry; consistent with the deleted source file.
|
| packages/next/src/config-dir/props/withGTConfigProps.ts | Removes
getDomainPath from BaseWithGTConfigProps and
REQUEST_FUNCTION_TO_CONFIG_KEY; clean removal. |
| packages/next/src/config-dir/utils/resolveRequestFunctionPaths.ts |
Removes getDomain from REQUEST_FUNCTION_ALIASES; getStaticDomain alias
is correctly preserved. |
| packages/next/src/config.ts | Removes the getDomainPath JSDoc param
and _GENERALTRANSLATION_CUSTOM_GET_DOMAIN_ENABLED env-var injection;
static/experimental variants left intact. |
| packages/next/src/request/types.ts | Removes getDomain from
REQUEST_FUNCTIONS tuple; RequestFunctions type now correctly reflects
only getLocale and getRegion. |
| packages/next/src/__tests__/config.test.ts | Drops
_GENERALTRANSLATION_CUSTOM_GET_DOMAIN_ENABLED from the env-var
completeness assertion; test remains valid. |
| .changeset/trim-next-getdomain.md | Patch-level changeset with
accurate description of the removed scaffolding. |
| .size-limit.cjs | Removes size-limit entry for the now-deleted
internal/_getDomain export; no other changes. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[withGTConfig] --> B{resolveRequestFunctionPaths}
    B --> C[getLocale path]
    B --> D[getRegion path]
    B -.->|REMOVED| E[getDomain path]

    C --> F[_GENERALTRANSLATION_CUSTOM_GET_LOCALE_ENABLED]
    D --> G[_GENERALTRANSLATION_CUSTOM_GET_REGION_ENABLED]
    E -.->|REMOVED| H[_GENERALTRANSLATION_CUSTOM_GET_DOMAIN_ENABLED]

    B --> I[getStaticLocale path]
    B --> J[getStaticRegion path]
    B --> K[getStaticDomain path]

    I --> L[_GENERALTRANSLATION_STATIC_GET_LOCALE_ENABLED]
    J --> M[_GENERALTRANSLATION_STATIC_GET_REGION_ENABLED]
    K --> N[_GENERALTRANSLATION_STATIC_GET_DOMAIN_ENABLED]

    style E fill:#ffcccc,color:#800000
    style H fill:#ffcccc,color:#800000
```

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

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[withGTConfig] --> B{resolveRequestFunctionPaths}
    B --> C[getLocale path]
    B --> D[getRegion path]
    B -.->|REMOVED| E[getDomain path]

    C --> F[_GENERALTRANSLATION_CUSTOM_GET_LOCALE_ENABLED]
    D --> G[_GENERALTRANSLATION_CUSTOM_GET_REGION_ENABLED]
    E -.->|REMOVED| H[_GENERALTRANSLATION_CUSTOM_GET_DOMAIN_ENABLED]

    B --> I[getStaticLocale path]
    B --> J[getStaticRegion path]
    B --> K[getStaticDomain path]

    I --> L[_GENERALTRANSLATION_STATIC_GET_LOCALE_ENABLED]
    J --> M[_GENERALTRANSLATION_STATIC_GET_REGION_ENABLED]
    K --> N[_GENERALTRANSLATION_STATIC_GET_DOMAIN_ENABLED]

    style E fill:#ffcccc,color:#800000
    style H fill:#ffcccc,color:#800000
```

</a>
</details>

<sub>Reviews (2): Last reviewed commit: ["chore: drop
gt-next/internal/\_getDomain
..."](803f44f)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40689026)</sub>

<!-- /greptile_comment -->
…tion (#1712)

Removes the long-`@deprecated`, runtime-dead SSG/experimental config
surface (major version):

- `experimentalEnableSSG`, `experimentalLocaleResolution`/`Param`,
`disableSSGWarnings`, `getStatic*Path` doc props
- `STATIC_REQUEST_FUNCTIONS`/`getStatic*` + their `internal/static/*`
aliases (which **never existed**)
- `plugin/checks/ssgChecks.ts` (whole file) + the experimental branch of
`cacheComponentsChecks`
- the now-unused error/warning builders in `errors/ssg.ts` and
`errors/cacheComponents.ts`
- the build env vars `_GENERALTRANSLATION_ENABLE_SSG`,
`_GENERALTRANSLATION_EXPERIMENTAL_LOCALE_RESOLUTION[_PARAM]`,
`_GENERALTRANSLATION_STATIC_GET_*_ENABLED` — verified **write-only**
(never read at runtime)

**Kept** (live): the cacheComponents checks,
`createCacheComponentsMissingRequestFunctionsWarning`,
`cacheComponentsNonLocalTranslationsWarning`, and
`noLocalesCouldBeDeterminedWarning`. −276 LOC. gt-next builds; 190 tests
pass.

> ⚠️ **Stacked on #1709** (getDomain removal) since they touch
overlapping config regions. Base will be retargeted to `odysseus` once
#1709 merges.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR removes the long-deprecated SSG and experimental
locale-resolution code surface from `gt-next`. All removed symbols
(`experimentalEnableSSG`, `experimentalLocaleResolution`/`Param`,
`STATIC_REQUEST_FUNCTIONS`/`StaticRequestFunctions`, `getStatic*` paths)
were verified write-only at runtime before deletion.

- Deletes `ssgChecks.ts` and its error/warning builders in
`errors/ssg.ts` and `errors/cacheComponents.ts`, trims the
`cacheComponentsChecks` signature (drops `mergedConfig`), removes three
static-function webpack/turbopack aliases and six dead build env vars,
and cleans up the corresponding type/default exports.
- Retains the live `cacheComponentsChecks` logic,
`noLocalesCouldBeDeterminedWarning`, and the
`createCacheComponentsMissingRequestFunctionsWarning` path, all of which
continue to work unchanged.

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

Safe to merge — the change is a clean removal of runtime-dead code with
no functional regressions to the live paths.

All removed symbols were verified write-only at runtime (never read back
after assignment). No references to deleted types, constants, or
functions remain in the codebase. The live cacheComponents checks,
noLocalesCouldBeDeterminedWarning, and webpack/turbopack alias plumbing
for getLocale/getRegion are fully intact. Tests were updated to match
and 190 tests continue to pass.

No files require special attention.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/next/src/plugin/checks/ssgChecks.ts | File deleted entirely;
all callers in config.ts have been removed and no remaining references
exist. |
| packages/next/src/plugin/checks/cacheComponentsChecks.ts | Removed the
experimentalLocaleResolution branch and mergedConfig parameter; live
checks are intact and correct. |
| packages/next/src/config-dir/utils/resolveRequestFunctionPaths.ts |
Removed STATIC_REQUEST_FUNCTIONS loop and static aliases; remaining
REQUEST_FUNCTIONS loop is unchanged. |
| packages/next/src/errors/ssg.ts | Stripped all SSG-specific
error/warning builders; only noLocalesCouldBeDeterminedWarning (still
used at runtime) remains. |
| packages/next/src/errors/cacheComponents.ts | Removed
experimentalLocaleResolution-related errors/warnings; retained active
warning builders. |
| packages/next/src/request/types.ts | Removed STATIC_REQUEST_FUNCTIONS
constant and StaticRequestFunctions type; no remaining imports. |
| packages/next/src/utils/constants.ts | File deleted; its only export
was used only in defaultWithGTConfigProps.ts, which has been updated. |
| packages/next/src/config.ts | Removed ssgChecks call, six static env
vars, and mergedConfig arg from cacheComponentsChecks; remaining build
pipeline is correct. |
| packages/next/src/config-dir/props/withGTConfigProps.ts | Removed
three deprecated experimental props from BaseWithGTConfigProps. |
| packages/next/src/config-dir/props/defaultWithGTConfigProps.ts |
Removed three deprecated default values and their import; type updated
consistently. |
| packages/next/src/__tests__/config.test.ts | Test updated to remove
six deleted env var keys; no coverage gaps on retained env vars. |
|
packages/next/src/plugin/checks/__tests__/cacheComponentsChecks.test.ts
| Removed experimentalLocaleResolution test case; remaining tests cover
the live warning paths. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["withGTConfig()"] --> B["resolveRequestFunctionPaths()"]
    B -->|"getLocale / getRegion only"| C["requestFunctionPaths"]
    A --> D["cacheComponentsChecks()"]
    D --> E{"cacheComponents enabled?"}
    E -->|Yes| F["warn if missing getLocale / getRegion"]
    E -->|Yes| G["warn if no local translations"]
    E -->|No| H["skip"]
    A --> I["emit env vars"]
```

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

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["withGTConfig()"] --> B["resolveRequestFunctionPaths()"]
    B -->|"getLocale / getRegion only"| C["requestFunctionPaths"]
    A --> D["cacheComponentsChecks()"]
    D --> E{"cacheComponents enabled?"}
    E -->|Yes| F["warn if missing getLocale / getRegion"]
    E -->|Yes| G["warn if no local translations"]
    E -->|No| H["skip"]
    A --> I["emit env vars"]
```

</a>
</details>

<sub>Reviews (2): Last reviewed commit: ["refactor(gt-next): remove
deprecated
SSG..."](6679ac7)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40690515)</sub>

<!-- /greptile_comment -->
## Summary
- remove deprecated I18nCache lifecycle constructor callbacks and
lifecycle adapter files
- trim cache subscription constants/types down to
translations-cache-miss
- simplify cache managers by removing unused lifecycle callback plumbing
- update React/React Core/Node params types and tests for the narrower
event API

## Test plan
- pnpm --filter gt-i18n test -- --runInBand
- pnpm --filter gt-i18n typecheck
- git diff --check

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR strips the deprecated lifecycle callback API from `gt-i18n`'s
cache layer, leaving `translations-cache-miss` as the sole subscription
event. All lifecycle plumbing files are deleted and the constructor
params types are de-generified throughout.

- Deletes four `lifecycle-hooks/` files (`createLifecycleCallbacks`,
`subscribeLifecycleCallbacks`, their types, and their tests) and removes
all hit/miss event constants except
`TRANSLATIONS_CACHE_MISS_EVENT_NAME`.
- Simplifies `TranslationsCache`, `DictionaryCache`, `ResourceCache`,
and `LocalesCache` constructors by replacing the `lifecycle` object with
a single `onMiss` / `onTranslationsCacheMiss` callback where needed.
- Updates `I18nCacheConstructorParams` to be non-generic (drops the
`TranslationValue` param and the deprecated `lifecycle` field), and
propagates that simplification to `ReactI18nCacheParams`,
`BrowserI18nCacheParams`, and `InitializeGTParams`.

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

The change is a clean deletion of deprecated code with no functional
regressions on the surviving event path.

All lifecycle plumbing is fully removed with no dangling imports. The
sole surviving event (translations-cache-miss) is correctly wired
through the generic type chain. The only open question is whether a
patch bump is appropriate for the removal of previously-exported symbols
from the internal path — consumers relying on those names would see a
compile break on upgrade.

.changeset/trim-i18n-cache-events.md — confirm the bump type matches
your versioning policy for deprecated internal API removals.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/i18n/src/i18n-cache/event-subscription/types.ts | Trims 8
event constants and the BaseEvent/EventName aliases; renames BaseEvent
to EventMap = object (loosens constraint from Record<string, unknown>).
Only TRANSLATIONS_CACHE_MISS_EVENT_NAME and I18nEvents survive. |
| packages/i18n/src/i18n-cache/I18nCache.ts | Constructor de-generified
to I18nCacheConstructorParams (non-generic); lifecycle wiring removed
and replaced with a direct onTranslationsCacheMiss lambda that emits the
sole remaining event. Type-safe through the TranslationValue generic on
the class itself. |
| packages/i18n/src/i18n-cache/translations-manager/LocalesCache.ts |
Replaces the I18nCacheLifecycleCallbacks bundle with a single
onTranslationsCacheMiss?: LocalesTranslationsCacheMissCallback.
ResourceCache calls for translations/dictionaries no longer receive
lifecycle objects. |
| packages/i18n/src/i18n-cache/translations-manager/TranslationsCache.ts
| Replaces the full LifecycleParam with a simple onMiss?:
TranslationsCacheMissCallback. Only the miss path is retained; the hit
callback is removed. |
| packages/i18n/src/i18n-cache/translations-manager/ResourceCache.ts |
Removes lifecycle param from constructor and deletes onHit/onMiss call
sites. Cache get/load behaviour is unchanged. |
| packages/i18n/src/i18n-cache/types.ts | I18nCacheConstructorParams
loses its TranslationValue generic and the lifecycle field;
LifecycleCallbacks removed from re-exports. |
| packages/i18n/src/internal.ts | Narrows exported event constants from
four to one (TRANSLATIONS_CACHE_MISS_EVENT_NAME). Consumers using the
removed constants via gt-i18n/internal will see a breaking change. |
| .changeset/trim-i18n-cache-events.md | Marks gt-i18n as patch. Removes
exported symbols that were @deprecated; whether patch vs minor is
correct depends on the project's semver policy for internal paths. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant App
    participant I18nCache
    participant LocalesCache
    participant TranslationsCache

    App->>I18nCache: subscribe('translations-cache-miss', cb)
    App->>I18nCache: lookupTranslationWithFallback(locale, msg, opts)
    I18nCache->>LocalesCache: getOrLoadTranslations(locale)
    LocalesCache->>TranslationsCache: lookupOrTranslate(key)
    Note over TranslationsCache: remote fetch resolves
    TranslationsCache->>LocalesCache: onMiss(hash, translation)
    LocalesCache->>I18nCache: onTranslationsCacheMiss(locale, hash, translation)
    I18nCache->>I18nCache: "emit('translations-cache-miss', {locale, hash, translation})"
    I18nCache->>App: "cb({locale, hash, translation})"
```

</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 App
    participant I18nCache
    participant LocalesCache
    participant TranslationsCache

    App->>I18nCache: subscribe('translations-cache-miss', cb)
    App->>I18nCache: lookupTranslationWithFallback(locale, msg, opts)
    I18nCache->>LocalesCache: getOrLoadTranslations(locale)
    LocalesCache->>TranslationsCache: lookupOrTranslate(key)
    Note over TranslationsCache: remote fetch resolves
    TranslationsCache->>LocalesCache: onMiss(hash, translation)
    LocalesCache->>I18nCache: onTranslationsCacheMiss(locale, hash, translation)
    I18nCache->>I18nCache: "emit('translations-cache-miss', {locale, hash, translation})"
    I18nCache->>App: "cb({locale, hash, translation})"
```

</a>
</details>

<a
href="https://app.greptile.com/ide/claude-code?prompt=Fix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0A.changeset%2Ftrim-i18n-cache-events.md%3A1-3%0AThe%20changeset%20is%20marked%20as%20%60patch%60%2C%20but%20this%20removes%20three%20previously-exported%20symbols%20from%20%60gt-i18n%2Finternal%60%20%28%60LOCALES_CACHE_MISS_EVENT_NAME%60%2C%20%60DICTIONARY_CACHE_MISS_EVENT_NAME%60%2C%20%60LOCALES_DICTIONARY_CACHE_MISS_EVENT_NAME%60%29%20and%20one%20from%20%60gt-i18n%2Finternal%2Ftypes%60%20%28%60LifecycleCallbacks%60%29%2C%20along%20with%20the%20%60lifecycle%60%20field%20on%20%60I18nCacheConstructorParams%60.%20Any%20consumer%20that%20imported%20those%20symbols%20%E2%80%94%20even%20though%20they%20were%20%60%40deprecated%60%20%E2%80%94%20will%20get%20a%20compile%20error%20after%20upgrade.%20A%20%60minor%60%20bump%20would%20be%20the%20safer%20choice%20to%20signal%20removal%20of%20previously-published%20API%20surface.%0A%0A%60%60%60suggestion%0A---%0A%22gt-i18n%22%3A%20minor%0A---%0A%60%60%60%0A%0A&repo=generaltranslation%2Fgt&pr=1716&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%22bg%2Fodysseus-trim-i18n-cache-events%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-i18n-cache-events%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0A.changeset%2Ftrim-i18n-cache-events.md%3A1-3%0AThe%20changeset%20is%20marked%20as%20%60patch%60%2C%20but%20this%20removes%20three%20previously-exported%20symbols%20from%20%60gt-i18n%2Finternal%60%20%28%60LOCALES_CACHE_MISS_EVENT_NAME%60%2C%20%60DICTIONARY_CACHE_MISS_EVENT_NAME%60%2C%20%60LOCALES_DICTIONARY_CACHE_MISS_EVENT_NAME%60%29%20and%20one%20from%20%60gt-i18n%2Finternal%2Ftypes%60%20%28%60LifecycleCallbacks%60%29%2C%20along%20with%20the%20%60lifecycle%60%20field%20on%20%60I18nCacheConstructorParams%60.%20Any%20consumer%20that%20imported%20those%20symbols%20%E2%80%94%20even%20though%20they%20were%20%60%40deprecated%60%20%E2%80%94%20will%20get%20a%20compile%20error%20after%20upgrade.%20A%20%60minor%60%20bump%20would%20be%20the%20safer%20choice%20to%20signal%20removal%20of%20previously-published%20API%20surface.%0A%0A%60%60%60suggestion%0A---%0A%22gt-i18n%22%3A%20minor%0A---%0A%60%60%60%0A%0A&repo=generaltranslation%2Fgt&pr=1716&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 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
.changeset/trim-i18n-cache-events.md:1-3
The changeset is marked as `patch`, but this removes three previously-exported symbols from `gt-i18n/internal` (`LOCALES_CACHE_MISS_EVENT_NAME`, `DICTIONARY_CACHE_MISS_EVENT_NAME`, `LOCALES_DICTIONARY_CACHE_MISS_EVENT_NAME`) and one from `gt-i18n/internal/types` (`LifecycleCallbacks`), along with the `lifecycle` field on `I18nCacheConstructorParams`. Any consumer that imported those symbols — even though they were `@deprecated` — will get a compile error after upgrade. A `minor` bump would be the safer choice to signal removal of previously-published API surface.

```suggestion
---
"gt-i18n": minor
---
```

`````

</details>

<sub>Reviews (1): Last reviewed commit: ["refactor(gt-i18n): trim cache
lifecycle
..."](54e113a)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40704542)</sub>

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

<!-- /greptile_comment -->
## Summary
- update the cacheComponents warning to say explicit request functions
are required during prerendering
- remove stale wording about automatic root parameter detection

## Tests
- pnpm --filter gt-next test --
src/plugin/checks/__tests__/cacheComponentsChecks.test.ts
- git diff --check

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR updates one error message string in the `cacheComponents`
diagnostics module, replacing stale deprecation wording with a clearer
explanation of why explicit request functions are required during
prerendering.

- The `wayOut` field in
`createCacheComponentsMissingRequestFunctionsWarning` now reads
"cacheComponents requires explicit request functions because request
values cannot be inferred safely during prerendering," making it more
actionable than the previous reference to deprecated automatic root
parameter detection.

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

This is a one-line string change in a diagnostic helper — no logic is
altered and no runtime behavior changes.

The only change is the wayOut string inside an error-diagnostic factory.
The new wording is more accurate and actionable than what it replaces,
and no code path, type signature, or behavior is affected.

No files require special attention.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/next/src/errors/cacheComponents.ts | Single-line update to
the `wayOut` field of the missing-request-functions diagnostic —
replaces the stale "Automatic root parameter detection is deprecated"
message with a clearer explanation about prerendering safety
requirements. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[cacheComponents enabled] --> B{Explicit request functions configured?}
    B -- Yes --> C[Proceed with prerendering]
    B -- No --> D[createCacheComponentsMissingRequestFunctionsWarning]
    D --> E["whatHappened: cacheComponents enabled but getLocale()/getRegion() not configured"]
    D --> F["wayOut: explicit request functions required — values cannot be inferred during prerendering"]
    D --> G["fix: add getLocale.ts / getRegion.ts or configure getLocalePath / getRegionPath"]
```

</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[cacheComponents enabled] --> B{Explicit request functions configured?}
    B -- Yes --> C[Proceed with prerendering]
    B -- No --> D[createCacheComponentsMissingRequestFunctionsWarning]
    D --> E["whatHappened: cacheComponents enabled but getLocale()/getRegion() not configured"]
    D --> F["wayOut: explicit request functions required — values cannot be inferred during prerendering"]
    D --> G["fix: add getLocale.ts / getRegion.ts or configure getLocalePath / getRegionPath"]
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["fix: clarify cache components
request
fu..."](41aa42b)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40885818)</sub>

<!-- /greptile_comment -->
## Summary
- remove the deprecated `internalInitializeGTSPA` implementation from
`@generaltranslation/react-core/pure`
- stop re-exporting `internalInitializeGTSPA` from `gt-react`
server/types entrypoints
- keep `gt-react`'s public `initializeGTSPA` browser initializer intact
- add a changeset for `@generaltranslation/react-core` and `gt-react`

## Tests
- pnpm --filter @generaltranslation/react-core typecheck
- pnpm --filter @generaltranslation/react-core test
- pnpm --filter gt-react test
- pnpm --filter @generaltranslation/react-core build
- pnpm --filter gt-react build
- git diff --check

## Notes
- `pnpm --filter gt-react typecheck` still fails on the pre-existing
`src/i18n-cache/BrowserI18nCache.ts(98,22): Property env does not exist
on type ImportMeta` issue; this line is unchanged from
`origin/odysseus`.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR removes the deprecated `internalInitializeGTSPA` function from
`@generaltranslation/react-core/pure` and stops re-exporting it from
`gt-react`'s server and types entrypoints. The public `initializeGTSPA`
in `gt-react` is left intact as the supported replacement.

- Deletes `packages/react-core/src/setup/initializeGTSPA.ts` and its
export from `pure.ts`.
- Removes the `internalInitializeGTSPA` re-export from `gt-react`'s
`index.server.ts` and `index.types.ts` surfaces.
- Adds a changeset marking both `@generaltranslation/react-core` and
`gt-react` as `patch`.

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

Safe to merge — the deleted code had no remaining callers in the repo
and the public initializeGTSPA surface is unaffected.

The removal is clean: no references to internalInitializeGTSPA survive
in the codebase after the deletion, and the gt-react public SPA
initializer is untouched. The only open question is whether the patch
bump in the changeset adequately signals to external consumers that a
previously-published symbol has been removed.

.changeset/remove-react-core-spa-initializer.md — worth a second look on
the bump type choice.
</details>

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

| Filename | Overview |
|----------|----------|
| .changeset/remove-react-core-spa-initializer.md | Documents the
removal as a patch bump; removing a re-exported symbol from a published
package is technically a breaking change regardless of deprecation. |
| packages/react-core/src/pure.ts | Drops the internalInitializeGTSPA
export; the rest of the file is untouched and correct. |
| packages/react-core/src/setup/initializeGTSPA.ts | Deprecated file
fully deleted; no remaining references in the codebase. |
| packages/react/src/index.server.ts | Removes the
internalInitializeGTSPA re-export; the public initializeGTSPA is still
re-exported from its own source file. |
| packages/react/src/index.types.ts | Mirrors the server entrypoint
change; internalInitializeGTSPA removed, initializeGTSPA (public)
remains. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["gt-react index.client.ts"] -->|"initializeGTSPA (kept)"| B["packages/react/src/setup/initializeGTSPA.ts"]
    C["gt-react index.server.ts"] -->|"initializeGTSPA (kept)"| B
    D["gt-react index.types.ts"] -->|"initializeGTSPA (kept)"| B
    B --> E["@generaltranslation/react-core/pure"]
    E --> F["BrowserI18nCache / I18nStore / etc."]

    G["@generaltranslation/react-core/pure"] -->|"internalInitializeGTSPA REMOVED"| H["packages/react-core/src/setup/initializeGTSPA.ts DELETED"]
    I["gt-react index.server.ts"] -->|"internalInitializeGTSPA re-export REMOVED"| G
    J["gt-react index.types.ts"] -->|"internalInitializeGTSPA re-export REMOVED"| G
```

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

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["gt-react index.client.ts"] -->|"initializeGTSPA (kept)"| B["packages/react/src/setup/initializeGTSPA.ts"]
    C["gt-react index.server.ts"] -->|"initializeGTSPA (kept)"| B
    D["gt-react index.types.ts"] -->|"initializeGTSPA (kept)"| B
    B --> E["@generaltranslation/react-core/pure"]
    E --> F["BrowserI18nCache / I18nStore / etc."]

    G["@generaltranslation/react-core/pure"] -->|"internalInitializeGTSPA REMOVED"| H["packages/react-core/src/setup/initializeGTSPA.ts DELETED"]
    I["gt-react index.server.ts"] -->|"internalInitializeGTSPA re-export REMOVED"| G
    J["gt-react index.types.ts"] -->|"internalInitializeGTSPA re-export REMOVED"| G
```

</a>
</details>

<a
href="https://app.greptile.com/ide/claude-code?prompt=Fix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0A.changeset%2Fremove-react-core-spa-initializer.md%3A2-3%0A**Changeset%20bump%20type%20may%20be%20too%20low**%0A%0ABoth%20packages%20are%20marked%20as%20%60patch%60%2C%20but%20removing%20a%20re-exported%20symbol%20from%20a%20published%20package%20is%20a%20breaking%20change%20under%20semver%20%E2%80%94%20any%20downstream%20consumer%20that%20imported%20%60internalInitializeGTSPA%60%20directly%20from%20%60gt-react%60's%20server%20or%20types%20entrypoints%20will%20get%20a%20silent%20compile-time%20break%20after%20upgrading.%20The%20%60internal%60%20prefix%20and%20%60%40deprecated%60%20tag%20strongly%20signal%20this%20wasn't%20meant%20for%20external%20use%2C%20but%20they%20don't%20prevent%20consumption.%20If%20there's%20a%20published%20version%20of%20%60gt-react%60%20that%20exposed%20this%20symbol%2C%20consider%20bumping%20to%20%60minor%60%20%28or%20%60major%60%20if%20following%20strict%20semver%29%20to%20surface%20the%20removal%20clearly%20in%20changelogs%20and%20dependency%20ranges.%0A%0A&repo=generaltranslation%2Fgt&pr=1722&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%22bg%2Fremove-react-core-spa-initializer%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%2Fremove-react-core-spa-initializer%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0A.changeset%2Fremove-react-core-spa-initializer.md%3A2-3%0A**Changeset%20bump%20type%20may%20be%20too%20low**%0A%0ABoth%20packages%20are%20marked%20as%20%60patch%60%2C%20but%20removing%20a%20re-exported%20symbol%20from%20a%20published%20package%20is%20a%20breaking%20change%20under%20semver%20%E2%80%94%20any%20downstream%20consumer%20that%20imported%20%60internalInitializeGTSPA%60%20directly%20from%20%60gt-react%60's%20server%20or%20types%20entrypoints%20will%20get%20a%20silent%20compile-time%20break%20after%20upgrading.%20The%20%60internal%60%20prefix%20and%20%60%40deprecated%60%20tag%20strongly%20signal%20this%20wasn't%20meant%20for%20external%20use%2C%20but%20they%20don't%20prevent%20consumption.%20If%20there's%20a%20published%20version%20of%20%60gt-react%60%20that%20exposed%20this%20symbol%2C%20consider%20bumping%20to%20%60minor%60%20%28or%20%60major%60%20if%20following%20strict%20semver%29%20to%20surface%20the%20removal%20clearly%20in%20changelogs%20and%20dependency%20ranges.%0A%0A&repo=generaltranslation%2Fgt&pr=1722&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 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
.changeset/remove-react-core-spa-initializer.md:2-3
**Changeset bump type may be too low**

Both packages are marked as `patch`, but removing a re-exported symbol from a published package is a breaking change under semver — any downstream consumer that imported `internalInitializeGTSPA` directly from `gt-react`'s server or types entrypoints will get a silent compile-time break after upgrading. The `internal` prefix and `@deprecated` tag strongly signal this wasn't meant for external use, but they don't prevent consumption. If there's a published version of `gt-react` that exposed this symbol, consider bumping to `minor` (or `major` if following strict semver) to surface the removal clearly in changelogs and dependency ranges.

`````

</details>

<sub>Reviews (1): Last reviewed commit: ["fix: avoid vite import meta
env
types"](12f8dfd)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40886986)</sub>

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

<!-- /greptile_comment -->
## Summary
- replace direct `import.meta.env` access in `BrowserI18nCache` with the
shared runtime environment helper
- add a `gt-react` patch changeset

## Tests
- pnpm --filter @generaltranslation/react-core build
- pnpm --filter gt-react typecheck
- pnpm --filter gt-react test
- git diff --check

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR removes the direct `import.meta.env?.DEV` access from
`BrowserI18nCache.getLocalStorageTranslationCache` and replaces it with
the shared `getRuntimeEnvironment()` helper from `gt-i18n/internal`,
fixing TypeScript errors that occur when Vite's ambient types are not
present in the project.

- **`BrowserI18nCache.ts`**: The single-line guard
`!import.meta.env?.DEV` is replaced with `getRuntimeEnvironment() !==
'development'`. The helper checks `process.env.NODE_ENV` first (for
webpack/CRA/Node environments), then `import.meta.env.MODE`, then
`import.meta.env.DEV`, defaulting to `'production'` — behavior is
equivalent for Vite and slightly broader for non-Vite bundlers.
- **`.changeset/fix-react-import-meta-env.md`**: A `patch` changeset is
added for `gt-react` to track the release.

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

Safe to merge — a one-line guard swap with no altered control flow in
normal usage.

The change is minimal and the replacement helper consolidates the same
import.meta.env.DEV check alongside additional process.env.NODE_ENV
support. For Vite users the behavior is identical; for non-Vite bundlers
it is strictly more correct. No new runtime paths or error conditions
are introduced.

No files require special attention.
</details>

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

| Filename | Overview |
|----------|----------|
| .changeset/fix-react-import-meta-env.md | Adds a patch changeset entry
for gt-react, documenting the import.meta.env type fix. |
| packages/react/src/i18n-cache/BrowserI18nCache.ts | Replaces the bare
`import.meta.env?.DEV` guard in `getLocalStorageTranslationCache` with
the shared `getRuntimeEnvironment()` helper; imports updated
accordingly. Behavior is equivalent for Vite and improves coverage for
webpack/Node environments. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[getLocalStorageTranslationCache called] --> B{getRuntimeEnvironment}
    B --> C{process.env.NODE_ENV === 'development'?}
    C -- Yes --> D[return 'development']
    C -- No --> E{import.meta.env.MODE exists?}
    E -- Yes --> F{MODE === 'development'?}
    F -- Yes --> D
    F -- No --> G[return 'production']
    E -- No --> H{import.meta.env.DEV === true?}
    H -- Yes --> D
    H -- No --> G
    D --> I[env === 'development' → create/return LocalStorageTranslationCache]
    G --> J[env !== 'development' → return undefined]
```

</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[getLocalStorageTranslationCache called] --> B{getRuntimeEnvironment}
    B --> C{process.env.NODE_ENV === 'development'?}
    C -- Yes --> D[return 'development']
    C -- No --> E{import.meta.env.MODE exists?}
    E -- Yes --> F{MODE === 'development'?}
    F -- Yes --> D
    F -- No --> G[return 'production']
    E -- No --> H{import.meta.env.DEV === true?}
    H -- Yes --> D
    H -- No --> G
    D --> I[env === 'development' → create/return LocalStorageTranslationCache]
    G --> J[env !== 'development' → return undefined]
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["fix: avoid vite import meta
env
types"](c3ac32d)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40888010)</sub>

<!-- /greptile_comment -->
## Summary
- add a shared gt-i18n global singleton helper
- refactor i18n config/cache/condition-store and react-core store
singletons to use it
- preserve internal exports for cross-package singleton sharing

## Tests
- pnpm --filter gt-i18n test
- pnpm --filter @generaltranslation/react-core test
- pnpm --filter gt-i18n typecheck
- pnpm --filter @generaltranslation/react-core typecheck
- git diff --check

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

Introduces a shared `createGlobalSingleton` factory in `gt-i18n` that
centralises the `globalThis.__generaltranslation` registry plumbing
previously duplicated across `i18nConfig`, `i18nCache`,
`conditionStore`, and `react-core`'s `i18nStore`. All four singletons
are refactored to delegate to the new helper, and it is re-exported from
`gt-i18n/internal` so downstream packages can adopt it directly.

- **New factory**
(`packages/i18n/src/globals/createGlobalSingleton.ts`): exposes a
uniform `{ get, set, isInitialized }` interface backed by a namespaced
slot in `globalThis.__generaltranslation`; `get()` and `isInitialized()`
both treat `null` and `undefined` as "not initialized", addressing a
previous inconsistency raised in review.
- **Refactored singletons**: `i18nConfig`, `i18nCache`,
`conditionStore`, and `i18nStore` each replace ~30–50 lines of
near-identical boilerplate with a two-line `createGlobalSingleton` call;
error messages and overwrite warnings are preserved.
- **Internal export**: `createGlobalSingleton` and the `GlobalSingleton`
type are added to `packages/i18n/src/internal.ts`, enabling
cross-package singleton sharing without duplicating the registry logic.

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

Safe to merge — a clean deduplication with no changes to public API
surface or runtime behaviour on the normal path.

All four singletons delegate to the new factory through thin wrappers;
get/set/isInitialized semantics are unchanged for callers. The null-slot
handling in isInitialized() is now correctly addressed (with a matching
test). The only finding is a minor inconsistency in the set()
overwrite-warning guard that only manifests under external registry
tampering.

packages/i18n/src/globals/createGlobalSingleton.ts — the set() overwrite
guard should also exclude null to stay consistent with isInitialized().
</details>

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

| Filename | Overview |
|----------|----------|
| packages/i18n/src/globals/createGlobalSingleton.ts | New shared
utility that consolidates the globalThis.__generaltranslation registry
plumbing. Minor inconsistency: the set() overwrite-warning guard checks
!== undefined while isInitialized() also excludes null. |
| packages/i18n/src/globals/__tests__/createGlobalSingleton.test.ts |
Unit test covering the null-slot edge case; verifies isInitialized()
returns false and get() throws when the registry slot holds null. |
| packages/react-core/src/i18n-store/singleton-operations.ts | Switches
to importing createGlobalSingleton from gt-i18n/internal;
createI18nStoreNotInitializedError() still calls getI18nConfig() which
is the same cascading behavior as before. |
| packages/i18n/src/internal.ts | Exports createGlobalSingleton and
GlobalSingleton type so react-core (and future packages) can import from
gt-i18n/internal. |
| packages/i18n/src/condition-store/createConditionStoreSingleton.ts |
Inline boilerplate replaced by createGlobalSingleton delegation; no
behavioral changes for the normal path. |
| packages/i18n/src/i18n-cache/singleton-operations.ts | Replaced custom
registry boilerplate with createGlobalSingleton; error message preserved
via the notInitialized factory. |
| packages/i18n/src/i18n-config/singleton-operations.ts | Direct method
exports now forward to i18nConfigSingleton; isI18nConfigInitialized is
now exported (was previously present as a named function). |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Consumer calls get / set / isInitialized] --> B[createGlobalSingleton factory]
    B --> C[getNamespace reads globalThis.__generaltranslation namespace bag]
    C --> D{Operation}
    D -->|get| E{slot is undefined or null?}
    E -->|yes| F[invoke notInitialized callback and throw Error]
    E -->|no| G[return value as T]
    D -->|set| H{slot is not undefined AND not equal to next?}
    H -->|yes| I[console.warn overwrite via createDiagnosticMessage]
    H -->|no| J[write next to slot]
    I --> J
    D -->|isInitialized| K{slot is not undefined AND not null?}
    K -->|true| L[return true]
    K -->|false| M[return false]

    subgraph Callers
      N[gt-i18n i18nConfig]
      O[gt-i18n i18nCache]
      P[gt-i18n conditionStore]
      Q[react-core i18nStore]
    end
    Callers --> B
```

</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[Consumer calls get / set / isInitialized] --> B[createGlobalSingleton factory]
    B --> C[getNamespace reads globalThis.__generaltranslation namespace bag]
    C --> D{Operation}
    D -->|get| E{slot is undefined or null?}
    E -->|yes| F[invoke notInitialized callback and throw Error]
    E -->|no| G[return value as T]
    D -->|set| H{slot is not undefined AND not equal to next?}
    H -->|yes| I[console.warn overwrite via createDiagnosticMessage]
    H -->|no| J[write next to slot]
    I --> J
    D -->|isInitialized| K{slot is not undefined AND not null?}
    K -->|true| L[return true]
    K -->|false| M[return false]

    subgraph Callers
      N[gt-i18n i18nConfig]
      O[gt-i18n i18nCache]
      P[gt-i18n conditionStore]
      Q[react-core i18nStore]
    end
    Callers --> B
```

</a>
</details>

<sub>Reviews (2): Last reviewed commit: ["fix: treat null singleton
slots as
unini..."](d0f6666)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40882016)</sub>

<!-- /greptile_comment -->
…ction (#1726)

## Summary

Two previously-working public hooks regressed on `odysseus`:

- **`useVersionId()`** — the client/server entrypoints re-exported
react-core's stub, which unconditionally `throw`s. On stable it returned
`_versionId` from the provider context, so any app calling it now
crashes.
- **`useLocaleDirection()`** — the signature became
`useLocaleDirection(locale: string)` (required arg). On stable it was
`(locale?: string)` defaulting to the current locale; a zero-arg call
now builds a locale-agnostic `GT` and throws
`noTargetLocaleProvidedError`.

## Fix

Add `packages/react/src/hooks/utils.ts` mirroring the existing
`gt-react-native` wrappers:

- `useVersionId()` → returns `getVersionId()`
- `useLocaleDirection(locale?)` → defaults to `useLocale()` when omitted

`index.client.ts`, `index.server.ts`, and `index.types.ts` now export
both hooks from the wrapper instead of `react-core/hooks`.
`index.types.ts` is included because the `browser`/`require`/`import`
conditions draw their `.d.ts` from it — otherwise the runtime would be
fixed but the published types would still advertise the broken
signatures. The `react-server`/RSC entrypoint (`index.rsc.ts`, with its
own `index.rsc.d` types) is intentionally left unchanged, since RSC
genuinely requires an explicit locale and cannot read provider context.

## Verification

- `pnpm --filter gt-react typecheck` — clean
- `pnpm --filter gt-react build` — clean; emitted
`dist/index.client.d.mts` now declares `useLocaleDirection(locale?:
string): 'ltr' | 'rtl'` and `useVersionId(): string | undefined`

Changeset included (`gt-react` patch).

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This patch restores two regressed public hooks in the `odysseus` branch
by fixing their implementations directly in
`@generaltranslation/react-core` rather than adding per-package
wrappers.

- **`useVersionId()`** in `react-core/hooks/utils.ts` is changed from
unconditionally throwing to calling `getVersionId()`, fixing crashes in
any app that calls it through `gt-react` or `gt-react-native`.
- **`useLocaleDirection(locale?)`** in `react-core/hooks/utils.ts` now
calls `useLocale()` internally and falls back to the current locale when
no argument is supplied, restoring the optional-arg signature.
- The `react-native` package's local wrapper file (`hooks/utils.ts`) is
deleted since `react-core` now provides the correct implementation;
`react-native/index.tsx` is updated to re-export directly from
`@generaltranslation/react-core/hooks`. The RSC entrypoint
(`index.rsc.ts`) is intentionally left unchanged—it retains the stricter
required-locale and throwing-`useVersionId` signatures.

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

Safe to merge — the change restores previously-working hook signatures
with a minimal, well-scoped fix in react-core.

Both hooks are fixed at the correct abstraction layer (react-core), and
every downstream entrypoint (gt-react client/server/types,
gt-react-native) automatically benefits without requiring per-package
wrappers. The RSC entrypoint is intentionally left with its stricter
signatures. Hook call ordering in the updated useLocaleDirection is
correct, and the deleted react-native wrapper had no callers outside the
package's own index.

No files require special attention.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/react-core/src/hooks/utils.ts | Core fix: useLocaleDirection
now accepts optional locale (defaulting via useLocale()), and
useVersionId calls getVersionId() instead of throwing. Hook ordering and
memoization are correct. |
| packages/react-native/src/hooks/utils.ts | Deleted — its logic now
lives in react-core; removal is safe since react-native/index.tsx
imports the same symbols from react-core/hooks directly. |
| packages/react-native/src/index.tsx | Re-exports useLocaleDirection
and useVersionId from @generaltranslation/react-core/hooks instead of
the now-deleted local wrapper; public API surface is unchanged. |
| .changeset/fix-react-version-id-locale-direction-hooks.md | Patch
changeset covering react-core, gt-react, and gt-react-native;
description accurately reflects the behavioral fix. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["gt-react / gt-react-native\nconsumer calls useLocaleDirection(locale?)"] --> B{locale provided?}
    B -- yes --> C["resolvedLocale = locale"]
    B -- no --> D["useLocale() → currentLocale\nresolvedLocale = currentLocale"]
    C --> E["useMemo: getI18nConfig()\n.getGTClass()\n.getLocaleDirection(resolvedLocale)"]
    D --> E
    E --> F["returns 'ltr' | 'rtl'"]

    G["consumer calls useVersionId()"] --> H["getVersionId()\n(from gt-i18n/internal)"]
    H --> I["returns string | undefined"]

    J["RSC entrypoint (index.rsc.ts)\nuseVersionId()"] --> K["throws — intentionally\nnot implemented in RSC"]
    L["RSC entrypoint\nuseLocaleDirection(locale: string)"] --> M["requires explicit locale\nno useLocale() 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["gt-react / gt-react-native\nconsumer calls useLocaleDirection(locale?)"] --> B{locale provided?}
    B -- yes --> C["resolvedLocale = locale"]
    B -- no --> D["useLocale() → currentLocale\nresolvedLocale = currentLocale"]
    C --> E["useMemo: getI18nConfig()\n.getGTClass()\n.getLocaleDirection(resolvedLocale)"]
    D --> E
    E --> F["returns 'ltr' | 'rtl'"]

    G["consumer calls useVersionId()"] --> H["getVersionId()\n(from gt-i18n/internal)"]
    H --> I["returns string | undefined"]

    J["RSC entrypoint (index.rsc.ts)\nuseVersionId()"] --> K["throws — intentionally\nnot implemented in RSC"]
    L["RSC entrypoint\nuseLocaleDirection(locale: string)"] --> M["requires explicit locale\nno useLocale() fallback"]
```

</a>
</details>

<sub>Reviews (2): Last reviewed commit: ["fix(gt-react): restore
useVersionId and
..."](922935e)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40908954)</sub>

<!-- /greptile_comment -->
## Summary
- add a react-server-specific types condition for gt-next's root export
- point the condition at `dist/index.rsc.d.ts` so RSC imports no longer
see client-only hooks from `index.types.d.ts`
- add a package export regression test
- add a gt-next patch changeset

## Tests
- pnpm --filter gt-next test -- src/__tests__/packageExports.test.ts
- pnpm --filter gt-next typecheck
- pnpm exec oxlint packages/next/src/__tests__/packageExports.test.ts
- pnpm exec oxfmt --check .changeset/gt-next-react-server-types.md
packages/next/package.json
packages/next/src/__tests__/packageExports.test.ts
- git diff --check

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR fixes incorrect TypeScript types being exposed when `gt-next` is
imported under the `react-server` export condition. By adding a
`"types"` field pointing at `dist/index.rsc.d.ts` inside the
`react-server` export block, TypeScript will now resolve RSC-specific
declarations instead of the general `index.types.d.ts` which includes
client-only hooks.

- **`packages/next/package.json`**: Inserts `"types":
"./dist/index.rsc.d.ts"` as the first key in the `react-server`
condition block, consistent with how other named conditions (e.g.
`./config`, `./server`) order their `types` field ahead of the runtime
entries.
- **`packages/next/src/__tests__/packageExports.test.ts`**: Adds a
regression test that reads `package.json` at test time and asserts both
the RSC-condition `types` path and the fallback `types` path, preventing
silent rollback of this fix.
- **`.changeset/gt-next-react-server-types.md`**: Records a `patch`
changeset describing the fix.

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

Safe to merge — the change is a single-line addition to the exports map
that wires up an already-emitted declaration file, accompanied by a
targeted regression test.

The fix is minimal and mechanical: one new field in `package.json`, a
matching test, and a changeset. `src/index.rsc.ts` already exists and
`tsc --emitDeclarationOnly` will produce `dist/index.rsc.d.ts` as part
of the normal build, so the pointed-at file is not invented. The `types`
key is correctly placed before `import`/`default` inside the
`react-server` condition block, matching the ordering convention used
elsewhere in the exports map. No runtime behavior changes — only
TypeScript's view of the package changes for RSC consumers.

No files require special attention.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/next/package.json | Adds `"types": "./dist/index.rsc.d.ts"`
as the first entry in the `react-server` export condition; ordering is
correct (types before import/default). The corresponding source
`src/index.rsc.ts` exists and the `tsc --emitDeclarationOnly` step will
produce `dist/index.rsc.d.ts` at build time. |
| packages/next/src/__tests__/packageExports.test.ts | New regression
test that reads `package.json` directly and asserts both the
RSC-specific `types` path and the general `types` fallback. The
`packageRoot` path traversal (3× `dirname`) correctly resolves to
`packages/next`. |
| .changeset/gt-next-react-server-types.md | Correct patch-level
changeset for `gt-next` describing the RSC types fix. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["TypeScript imports 'gt-next'"] --> B{Which condition?}
    B -->|react-server condition active| C["types: ./dist/index.rsc.d.ts NEW"]
    B -->|browser condition active| D["(no types field — pre-existing)"]
    B -->|default| E["types: ./dist/index.types.d.ts"]
    C --> F["RSC-safe declarations\n(no client-only hooks)"]
    E --> G["General declarations\n(includes client hooks)"]
```

</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["TypeScript imports 'gt-next'"] --> B{Which condition?}
    B -->|react-server condition active| C["types: ./dist/index.rsc.d.ts NEW"]
    B -->|browser condition active| D["(no types field — pre-existing)"]
    B -->|default| E["types: ./dist/index.types.d.ts"]
    C --> F["RSC-safe declarations\n(no client-only hooks)"]
    E --> G["General declarations\n(includes client hooks)"]
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["fix: use rsc types for gt-next
react-ser..."](15f4c24)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40945802)</sub>

<!-- /greptile_comment -->
## Summary
- move `gtServicesEnabled` onto the shared `createGlobalSingleton`
registry
- preserve the existing
`globalThis.__generaltranslation.i18n.gtServicesEnabled` namespace/key
- keep uninitialized reads defaulting to `false`
- add a gt-i18n patch changeset

## Notes
- Repeated setup with the same resolved boolean remains quiet.
- The shared singleton warning now fires if setup flips the flag between
enabled and disabled in the same JS realm, which should indicate a
meaningful config change rather than normal runtime behavior.

## Tests
- pnpm --filter gt-i18n test --
src/globals/__tests__/getGTServicesEnabled.test.ts
src/i18n-config/__tests__/singleton-operations.test.ts
- pnpm --filter gt-i18n typecheck
- pnpm exec oxlint packages/i18n/src/globals/getGTServicesEnabled.ts
packages/i18n/src/globals/__tests__/getGTServicesEnabled.test.ts
- pnpm exec oxfmt --check .changeset/gt-services-enabled-singleton.md
packages/i18n/src/globals/getGTServicesEnabled.ts
packages/i18n/src/globals/__tests__/getGTServicesEnabled.test.ts
- git diff --check

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR removes the standalone `setupGTServicesEnabled` global and folds
the `gtServicesEnabled` flag directly into the `I18nConfig` class, which
is already managed via the shared `createGlobalSingleton` registry. All
downstream callers (Next, Node, React, React Native) drop their separate
`setupGTServicesEnabled` call and now rely solely on
`initializeI18nConfig`.

- `cacheUrl` is promoted into `I18nConfigParams` so the
`resolveGTServicesEnabled` logic (which needs it) can live entirely
inside `I18nConfig`'s constructor without a separate parameter bag.
- `validateI18nConfigParams` is updated to accept the already-resolved
`gtServicesEnabled` boolean as an explicit argument instead of reading
the old global, eliminating the circular dependency between the
validator and the global setter.
- All tests pass and a new case pins the "returns false before config is
initialized" contract.

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

Safe to merge; the refactoring correctly consolidates a previously
split-brain flag into a single, already-tested singleton.

The change removes a parallel global write and re-homes the flag
computation inside I18nConfig's constructor, which is the natural owner.
All call sites are updated, the validation function is now testable in
isolation, and the uninitialized-default contract is now verified by a
test. No behavioral regressions identified.

packages/next/src/setup/shared.ts — the NextSetupI18nConfigParams alias
can be simplified now that cacheUrl is part of I18nConfigParams, but
this has no runtime impact.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/i18n/src/globals/getGTServicesEnabled.ts | Simplified to a
thin wrapper over the I18nConfig singleton; correctly returns false
before initialization. setupGTServicesEnabled removed. |
| packages/i18n/src/i18n-config/I18nConfig.ts | Adds cacheUrl to
I18nConfigParams, moves resolveGTServicesEnabled logic here, stores
result as a private field. Clean consolidation. |
| packages/i18n/src/i18n-config/validation.ts | Eliminates the global
read in favor of an explicit parameter; no logic change, avoids the need
to read the global singleton during construction. |
| packages/next/src/setup/shared.ts | Removes the separate
gtservicesEnabledParams block; adds cacheUrl directly to
i18nConfigParams. Introduces NextSetupI18nConfigParams which is now
redundant given cacheUrl is already in I18nConfigParams. |
| packages/i18n/src/globals/__tests__/getGTServicesEnabled.test.ts |
Updated to use initializeI18nConfig; adds the previously-missing test
for the uninitialized default (false). Addresses prior review comment. |
| packages/i18n/src/i18n-config/__tests__/singleton-operations.test.ts |
Removes the gtServicesEnabled field from the singleton shape type and
adds a dedicated test verifying the flag is stored and retrievable via
the config singleton. |
| packages/next/src/setup/initGT.ts | Drops the separate
setupGTServicesEnabled call; initializeI18nConfig now owns the full
setup. Correctly uses NextSetupI18nConfigParams. |
| packages/node/src/setup/initializeGT.ts | Removes
setupGTServicesEnabled call; initializeI18nConfig takes full
responsibility. Clean one-line removal. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["initializeGT() / initializeI18nConfig()"] --> B["new I18nConfig(params)"]
    B --> C["resolveGTServicesEnabled(params)\n(getLoadTranslationsType | getTranslationApiType)"]
    C --> D["gtServicesEnabled: boolean"]
    D --> E["validateI18nConfigParams(params, gtServicesEnabled)"]
    D --> F["this.gtServicesEnabled = gtServicesEnabled"]
    B --> G["setI18nConfig(instance)\ncreateGlobalSingleton registry"]
    G --> H["globalThis.__generaltranslation.i18n.i18nConfig"]
    H --> I["getGTServicesEnabled()\n-> isI18nConfigInitialized()\n  ? getI18nConfig().isGTServicesEnabled()\n  : false"]
```

</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["initializeGT() / initializeI18nConfig()"] --> B["new I18nConfig(params)"]
    B --> C["resolveGTServicesEnabled(params)\n(getLoadTranslationsType | getTranslationApiType)"]
    C --> D["gtServicesEnabled: boolean"]
    D --> E["validateI18nConfigParams(params, gtServicesEnabled)"]
    D --> F["this.gtServicesEnabled = gtServicesEnabled"]
    B --> G["setI18nConfig(instance)\ncreateGlobalSingleton registry"]
    G --> H["globalThis.__generaltranslation.i18n.i18nConfig"]
    H --> I["getGTServicesEnabled()\n-> isI18nConfigInitialized()\n  ? getI18nConfig().isGTServicesEnabled()\n  : false"]
```

</a>
</details>

<sub>Reviews (2): Last reviewed commit: ["refactor: store gt services
flag on
i18n..."](eeb2452)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40948338)</sub>

<!-- /greptile_comment -->
## Summary
- replace the hand-rolled react-core context global registry with
createGlobalSingleton
- preserve the existing reactCore/gtContext global slot and lazy
creation behavior

## Testing
- pnpm exec oxlint packages/react-core/src/context/context.ts
- pnpm exec oxfmt --check packages/react-core/src/context/context.ts
- git diff --check
- pnpm --filter @generaltranslation/react-core test
- pnpm --filter @generaltranslation/react-core typecheck
- pnpm --filter gt-react test
- pnpm --filter gt-react typecheck

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR refactors `packages/react-core/src/context/context.ts` to
replace three hand-rolled TypeScript interfaces and the
`getReactCoreGlobals()` helper with the shared `createGlobalSingleton`
utility from `gt-i18n/internal`, reducing boilerplate while preserving
the same `globalThis.__generaltranslation.reactCore.gtContext` slot.

- The module-level `gtContextSingleton` constant mirrors the old
`getReactCoreGlobals()` plumbing exactly — same `namespace`
(`reactCore`) and `key` (`gtContext`) — so the global slot is unchanged
across package instances.
- `getGTContext()` preserves the lazy-creation pattern: it calls
`isInitialized()` before `set()`, so `createContext` is still invoked at
most once, and the new `set()` overwrite-warning path is never reached
through normal usage.

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

Safe to merge — the refactor is a direct mechanical substitution of
equivalent logic with no functional change.

The global slot (__generaltranslation.reactCore.gtContext) is identical
to what the old hand-rolled helper produced. The lazy-init guard
(isInitialized() → set() → get()) matches the old ??= semantics
precisely, and set() is only called when the slot is empty so the new
overwrite-warning path is unreachable in normal use. The removed
TypeScript types were internal implementation detail only. Nothing in
the public API or runtime behavior changes.

No files require special attention.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/react-core/src/context/context.ts | Replaces hand-rolled
global-registry types and helper with createGlobalSingleton;
namespace/key alignment is preserved, lazy-init behavior is equivalent.
|

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Caller
    participant getGTContext
    participant gtContextSingleton
    participant globalThis

    Caller->>getGTContext: getGTContext()
    getGTContext->>gtContextSingleton: isInitialized()
    gtContextSingleton->>globalThis: globalThis.__generaltranslation["reactCore"]["gtContext"]
    globalThis-->>gtContextSingleton: undefined (first call)
    gtContextSingleton-->>getGTContext: false

    getGTContext->>getGTContext: createContext(undefined)
    getGTContext->>gtContextSingleton: set(ctx)
    gtContextSingleton->>globalThis: store ctx at ["reactCore"]["gtContext"]

    getGTContext->>gtContextSingleton: get()
    gtContextSingleton->>globalThis: read ["reactCore"]["gtContext"]
    globalThis-->>gtContextSingleton: ctx
    gtContextSingleton-->>getGTContext: ctx
    getGTContext-->>Caller: ctx

    Note over Caller,globalThis: Subsequent calls — slot already populated
    Caller->>getGTContext: getGTContext()
    getGTContext->>gtContextSingleton: isInitialized()
    gtContextSingleton->>globalThis: read ["reactCore"]["gtContext"]
    globalThis-->>gtContextSingleton: ctx
    gtContextSingleton-->>getGTContext: true
    getGTContext->>gtContextSingleton: get()
    gtContextSingleton-->>getGTContext: ctx
    getGTContext-->>Caller: ctx
```

</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 Caller
    participant getGTContext
    participant gtContextSingleton
    participant globalThis

    Caller->>getGTContext: getGTContext()
    getGTContext->>gtContextSingleton: isInitialized()
    gtContextSingleton->>globalThis: globalThis.__generaltranslation["reactCore"]["gtContext"]
    globalThis-->>gtContextSingleton: undefined (first call)
    gtContextSingleton-->>getGTContext: false

    getGTContext->>getGTContext: createContext(undefined)
    getGTContext->>gtContextSingleton: set(ctx)
    gtContextSingleton->>globalThis: store ctx at ["reactCore"]["gtContext"]

    getGTContext->>gtContextSingleton: get()
    gtContextSingleton->>globalThis: read ["reactCore"]["gtContext"]
    globalThis-->>gtContextSingleton: ctx
    gtContextSingleton-->>getGTContext: ctx
    getGTContext-->>Caller: ctx

    Note over Caller,globalThis: Subsequent calls — slot already populated
    Caller->>getGTContext: getGTContext()
    getGTContext->>gtContextSingleton: isInitialized()
    gtContextSingleton->>globalThis: read ["reactCore"]["gtContext"]
    globalThis-->>gtContextSingleton: ctx
    gtContextSingleton-->>getGTContext: true
    getGTContext->>gtContextSingleton: get()
    gtContextSingleton-->>getGTContext: ctx
    getGTContext-->>Caller: ctx
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["refactor: use shared singleton
for
react..."](46bec0e)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40949786)</sub>

<!-- /greptile_comment -->
## Summary
- re-export the missing platform-neutral
@generaltranslation/react-core/pure helpers from gt-react-native
- expose ReactI18nCache and ReactI18nCacheParams from gt-react-native to
match gt-react parity

## Testing
- pnpm --filter gt-react-native test
- pnpm --filter gt-react-native build
- pnpm exec oxfmt --check packages/react-native/src/index.tsx
- git diff --check
- confirmed the new names appear in
packages/react-native/dist/module/index.d.ts
- AST parity check: no @generaltranslation/react-core/pure exports
remain present in gt-react but missing from gt-react-native

## Notes
- pnpm --filter gt-react-native typecheck currently fails in untouched
src/hooks/selectors.ts with TS2742 about an inferred non-portable return
type.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR adds four previously missing re-exports (`getDefaultLocale`,
`getGTClass`, `getLocales`, `getVersionId`) from
`@generaltranslation/react-core/pure` to the `gt-react-native` public
surface, closing part of the gap with `gt-react`.

- Four helpers that were already available in
`@generaltranslation/react-core/pure` are now forwarded through
`gt-react-native/src/index.tsx`, matching the corresponding block in
`gt-react/src/index.client.ts`.
- `ReactI18nCache` and `ReactI18nCacheParams` are explicitly listed in
the PR description as being added, but no re-export for them appears in
the actual diff; they remain absent from `gt-react-native`.
- `getLocaleProperties` is present in both `pure.ts` and `gt-react`'s
public API but is still not forwarded by `gt-react-native`, making the
"AST parity check: zero gaps remain" claim in the PR description
inaccurate.

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

Safe to merge for the four symbols that were added, but the PR does not
fully deliver on two explicit claims in its description.

The four new re-exports are correct and low-risk. However,
ReactI18nCache and ReactI18nCacheParams are specifically called out in
the PR description as being added, yet they appear nowhere in the diff.
getLocaleProperties is also absent despite the stated AST parity
guarantee. Users or internal tooling that depends on these symbols will
still find them missing from gt-react-native after this PR merges.

packages/react-native/src/index.tsx — needs the ReactI18nCache,
ReactI18nCacheParams, and getLocaleProperties re-exports that are
described but not present.
</details>


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




| Filename | Overview |
|----------|----------|
| packages/react-native/src/index.tsx | Adds four missing re-exports
(getDefaultLocale, getGTClass, getLocales, getVersionId) from
@generaltranslation/react-core/pure, but two items explicitly named in
the PR description (ReactI18nCache, ReactI18nCacheParams) and one more
expected by the parity claim (getLocaleProperties) are still absent. |

</details>


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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["@generaltranslation/react-core/pure"]
    A -->|"getDefaultLocale, getGTClass,\ngetLocales, getVersionId\n(ADDED by this PR)"| B["gt-react-native/src/index.tsx"]
    A -->|"getDefaultLocale, getGTClass,\ngetLocales, getVersionId,\ngetLocaleProperties,\nReactI18nCache, ReactI18nCacheParams\n(already present)"| C["gt-react/src/index.client.ts"]
    A -->|"getLocaleProperties missing\nReactI18nCache missing\nReactI18nCacheParams missing"| B
    B --> D["gt-react-native consumers"]
    C --> E["gt-react consumers"]
```

</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"]
    A -->|"getDefaultLocale, getGTClass,\ngetLocales, getVersionId\n(ADDED by this PR)"| B["gt-react-native/src/index.tsx"]
    A -->|"getDefaultLocale, getGTClass,\ngetLocales, getVersionId,\ngetLocaleProperties,\nReactI18nCache, ReactI18nCacheParams\n(already present)"| C["gt-react/src/index.client.ts"]
    A -->|"getLocaleProperties missing\nReactI18nCache missing\nReactI18nCacheParams missing"| B
    B --> D["gt-react-native consumers"]
    C --> E["gt-react consumers"]
```

</a>
</details>


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

1. `packages/react-native/src/index.tsx`, line 63-73
([link](https://github.com/generaltranslation/gt/blob/302e395609b6783dfa98e5e526bf815ae502bc4c/packages/react-native/src/index.tsx#L63-L73))

<a href="#"><img alt="P1"
src="https://greptile-static-assets.s3.amazonaws.com/badges/p1.svg?v=9"
align="top"></a> **ReactI18nCache / ReactI18nCacheParams not actually
exported**

The PR description states "expose ReactI18nCache and
ReactI18nCacheParams from gt-react-native to match gt-react parity", but
neither symbol appears anywhere in the post-PR `index.tsx`. Both are
exported from `@generaltranslation/react-core/pure` (see `pure.ts` lines
79–81) and are re-exported from `gt-react` (`index.client.ts` lines
116–118), but no corresponding re-export was added here. This leaves a
concrete API gap between `gt-react` and `gt-react-native` despite the
stated goal.

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

   `````markdown
   This is a comment left during a code review.
   Path: packages/react-native/src/index.tsx
   Line: 63-73

   Comment:
   **ReactI18nCache / ReactI18nCacheParams not actually exported**

The PR description states "expose ReactI18nCache and
ReactI18nCacheParams from gt-react-native to match gt-react parity", but
neither symbol appears anywhere in the post-PR `index.tsx`. Both are
exported from `@generaltranslation/react-core/pure` (see `pure.ts` lines
79–81) and are re-exported from `gt-react` (`index.client.ts` lines
116–118), but no corresponding re-export was added here. This leaves a
concrete API gap between `gt-react` and `gt-react-native` despite the
stated goal.

   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%2Freact-native%2Fsrc%2Findex.tsx%0ALine%3A%2063-73%0A%0AComment%3A%0A**ReactI18nCache%20%2F%20ReactI18nCacheParams%20not%20actually%20exported**%0A%0AThe%20PR%20description%20states%20%22expose%20ReactI18nCache%20and%20ReactI18nCacheParams%20from%20gt-react-native%20to%20match%20gt-react%20parity%22%2C%20but%20neither%20symbol%20appears%20anywhere%20in%20the%20post-PR%20%60index.tsx%60.%20Both%20are%20exported%20from%20%60%40generaltranslation%2Freact-core%2Fpure%60%20%28see%20%60pure.ts%60%20lines%2079%E2%80%9381%29%20and%20are%20re-exported%20from%20%60gt-react%60%20%28%60index.client.ts%60%20lines%20116%E2%80%93118%29%2C%20but%20no%20corresponding%20re-export%20was%20added%20here.%20This%20leaves%20a%20concrete%20API%20gap%20between%20%60gt-react%60%20and%20%60gt-react-native%60%20despite%20the%20stated%20goal.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=generaltranslation%2Fgt&pr=1734&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaudeDark.svg?v=4"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=4"><img
alt="Fix in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=4"></picture></a>
<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22generaltranslation%2Fgt%22%20on%20the%20existing%20branch%20%22bg%2Freact-native-pure-parity%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22bg%2Freact-native-pure-parity%22.%0A%0AThis%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20packages%2Freact-native%2Fsrc%2Findex.tsx%0ALine%3A%2063-73%0A%0AComment%3A%0A**ReactI18nCache%20%2F%20ReactI18nCacheParams%20not%20actually%20exported**%0A%0AThe%20PR%20description%20states%20%22expose%20ReactI18nCache%20and%20ReactI18nCacheParams%20from%20gt-react-native%20to%20match%20gt-react%20parity%22%2C%20but%20neither%20symbol%20appears%20anywhere%20in%20the%20post-PR%20%60index.tsx%60.%20Both%20are%20exported%20from%20%60%40generaltranslation%2Freact-core%2Fpure%60%20%28see%20%60pure.ts%60%20lines%2079%E2%80%9381%29%20and%20are%20re-exported%20from%20%60gt-react%60%20%28%60index.client.ts%60%20lines%20116%E2%80%93118%29%2C%20but%20no%20corresponding%20re-export%20was%20added%20here.%20This%20leaves%20a%20concrete%20API%20gap%20between%20%60gt-react%60%20and%20%60gt-react-native%60%20despite%20the%20stated%20goal.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=generaltranslation%2Fgt&pr=1734&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodexDark.svg?v=4"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=4"><img
alt="Fix in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=4"></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%2Freact-native%2Fsrc%2Findex.tsx%3A63-73%0A**ReactI18nCache%20%2F%20ReactI18nCacheParams%20not%20actually%20exported**%0A%0AThe%20PR%20description%20states%20%22expose%20ReactI18nCache%20and%20ReactI18nCacheParams%20from%20gt-react-native%20to%20match%20gt-react%20parity%22%2C%20but%20neither%20symbol%20appears%20anywhere%20in%20the%20post-PR%20%60index.tsx%60.%20Both%20are%20exported%20from%20%60%40generaltranslation%2Freact-core%2Fpure%60%20%28see%20%60pure.ts%60%20lines%2079%E2%80%9381%29%20and%20are%20re-exported%20from%20%60gt-react%60%20%28%60index.client.ts%60%20lines%20116%E2%80%93118%29%2C%20but%20no%20corresponding%20re-export%20was%20added%20here.%20This%20leaves%20a%20concrete%20API%20gap%20between%20%60gt-react%60%20and%20%60gt-react-native%60%20despite%20the%20stated%20goal.%0A%0A%23%23%23%20Issue%202%20of%202%0Apackages%2Freact-native%2Fsrc%2Findex.tsx%3A47-50%0A**getLocaleProperties%20still%20absent%20despite%20parity%20claim**%0A%0A%60gt-react%60%20%28%60index.client.ts%60%20line%2085%29%20exports%20%60getLocaleProperties%60%20from%20%60%40generaltranslation%2Freact-core%2Fpure%60%2C%20and%20%60pure.ts%60%20%28line%20118%29%20confirms%20the%20export%20exists.%20The%20PR%20description%20claims%20%22AST%20parity%20check%3A%20no%20%60%40generaltranslation%2Freact-core%2Fpure%60%20exports%20remain%20present%20in%20gt-react%20but%20missing%20from%20gt-react-native%22%2C%20but%20%60getLocaleProperties%60%20is%20still%20missing%20here.%20Omitting%20it%20leaves%20callers%20who%20upgrade%20from%20%60gt-react%60%20to%20%60gt-react-native%60%20without%20a%20drop-in%20equivalent.%0A%0A%60%60%60suggestion%0A%20%20getDefaultLocale%2C%0A%20%20getFormatLocales%2C%0A%20%20getGTClass%2C%0A%20%20getLocaleProperties%2C%0A%20%20getLocales%2C%0A%60%60%60%0A%0A&repo=generaltranslation%2Fgt&pr=1734&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaudeDark.svg?v=4"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=4"><img
alt="Fix All in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=4"></picture></a>
<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22generaltranslation%2Fgt%22%20on%20the%20existing%20branch%20%22bg%2Freact-native-pure-parity%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22bg%2Freact-native-pure-parity%22.%0A%0AFix%20the%20following%202%20code%20review%20issues.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%202%0Apackages%2Freact-native%2Fsrc%2Findex.tsx%3A63-73%0A**ReactI18nCache%20%2F%20ReactI18nCacheParams%20not%20actually%20exported**%0A%0AThe%20PR%20description%20states%20%22expose%20ReactI18nCache%20and%20ReactI18nCacheParams%20from%20gt-react-native%20to%20match%20gt-react%20parity%22%2C%20but%20neither%20symbol%20appears%20anywhere%20in%20the%20post-PR%20%60index.tsx%60.%20Both%20are%20exported%20from%20%60%40generaltranslation%2Freact-core%2Fpure%60%20%28see%20%60pure.ts%60%20lines%2079%E2%80%9381%29%20and%20are%20re-exported%20from%20%60gt-react%60%20%28%60index.client.ts%60%20lines%20116%E2%80%93118%29%2C%20but%20no%20corresponding%20re-export%20was%20added%20here.%20This%20leaves%20a%20concrete%20API%20gap%20between%20%60gt-react%60%20and%20%60gt-react-native%60%20despite%20the%20stated%20goal.%0A%0A%23%23%23%20Issue%202%20of%202%0Apackages%2Freact-native%2Fsrc%2Findex.tsx%3A47-50%0A**getLocaleProperties%20still%20absent%20despite%20parity%20claim**%0A%0A%60gt-react%60%20%28%60index.client.ts%60%20line%2085%29%20exports%20%60getLocaleProperties%60%20from%20%60%40generaltranslation%2Freact-core%2Fpure%60%2C%20and%20%60pure.ts%60%20%28line%20118%29%20confirms%20the%20export%20exists.%20The%20PR%20description%20claims%20%22AST%20parity%20check%3A%20no%20%60%40generaltranslation%2Freact-core%2Fpure%60%20exports%20remain%20present%20in%20gt-react%20but%20missing%20from%20gt-react-native%22%2C%20but%20%60getLocaleProperties%60%20is%20still%20missing%20here.%20Omitting%20it%20leaves%20callers%20who%20upgrade%20from%20%60gt-react%60%20to%20%60gt-react-native%60%20without%20a%20drop-in%20equivalent.%0A%0A%60%60%60suggestion%0A%20%20getDefaultLocale%2C%0A%20%20getFormatLocales%2C%0A%20%20getGTClass%2C%0A%20%20getLocaleProperties%2C%0A%20%20getLocales%2C%0A%60%60%60%0A%0A&repo=generaltranslation%2Fgt&pr=1734&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=4"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=4"><img
alt="Fix All in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=4"></picture></a>

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

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

---

### Issue 1 of 2
packages/react-native/src/index.tsx:63-73
**ReactI18nCache / ReactI18nCacheParams not actually exported**

The PR description states "expose ReactI18nCache and ReactI18nCacheParams from gt-react-native to match gt-react parity", but neither symbol appears anywhere in the post-PR `index.tsx`. Both are exported from `@generaltranslation/react-core/pure` (see `pure.ts` lines 79–81) and are re-exported from `gt-react` (`index.client.ts` lines 116–118), but no corresponding re-export was added here. This leaves a concrete API gap between `gt-react` and `gt-react-native` despite the stated goal.

### Issue 2 of 2
packages/react-native/src/index.tsx:47-50
**getLocaleProperties still absent despite parity claim**

`gt-react` (`index.client.ts` line 85) exports `getLocaleProperties` from `@generaltranslation/react-core/pure`, and `pure.ts` (line 118) confirms the export exists. The PR description claims "AST parity check: no `@generaltranslation/react-core/pure` exports remain present in gt-react but missing from gt-react-native", but `getLocaleProperties` is still missing here. Omitting it leaves callers who upgrade from `gt-react` to `gt-react-native` without a drop-in equivalent.

```suggestion
  getDefaultLocale,
  getFormatLocales,
  getGTClass,
  getLocaleProperties,
  getLocales,
```


`````

</details>

<sub>Reviews (2): Last reviewed commit: ["fix: mirror pure exports in
react
native"](302e395)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40951736)</sub>

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

<!-- /greptile_comment -->
## Summary
- remove unused CLI console/format exports and an unused auth header
utility
- remove redundant gt-i18n internal type re-export
- remove unused react-core pure/condition-store exports and auth env
types

## Tests
- pnpm --filter gt typecheck
- pnpm --filter gt-i18n typecheck
- pnpm --filter @generaltranslation/react-core typecheck
- git diff --check

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR removes dead internal exports across three packages (`gt`,
`gt-i18n`, `@generaltranslation/react-core`) — string constants, a
utility function, type definitions, and re-export aliases that have no
remaining consumers in the codebase.

- **CLI (`gt`)**: Removes unused `noSupportedFormatError` string, the
`SUPPORTED_DATA_FORMATS` array, and deletes the entire `headers.ts`
utility file containing `getAuthHeaders`.
- **i18n**: Removes a redundant named re-export of `TranslationMetadata`
that was already covered by the preceding `export type *` wildcard.
- **react-core**: Removes the `getConditionStore as
getReadonlyConditionStore` alias (all consumers use the `WithFallback`
variant) and the `AuthFromEnvParams`/`AuthFromEnvReturn` type
definitions and their public re-exports.

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

All removals are confirmed dead code with no remaining consumers — safe
to merge.

Every removed export was verified against the full codebase: no
remaining imports of `noSupportedFormatError`, `SUPPORTED_DATA_FORMATS`,
`getAuthHeaders`, `getReadonlyConditionStore` (bare alias),
`AuthFromEnvParams`, or `AuthFromEnvReturn`. The `TranslationMetadata`
named re-export was redundant due to the existing `export type *`
wildcard. The accompanying typecheck CI steps cover each affected
package.

No files require special attention — all changes are straightforward
dead-code removals.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/cli/src/console/index.ts | Removes `noSupportedFormatError`
constant — confirmed unused across the codebase. |
| packages/cli/src/formats/files/aggregateFiles.ts | Removes
`SUPPORTED_DATA_FORMATS` exported constant — confirmed unused across the
codebase. |
| packages/cli/src/utils/headers.ts | Deletes entire file containing
`getAuthHeaders` utility — confirmed no imports of this file or function
remain anywhere. |
| packages/i18n/src/internal-types.ts | Removes redundant explicit
re-export of `TranslationMetadata`, which is already covered by the
preceding `export type *` wildcard from the same source file. |
| packages/react-core/src/condition-store/singleton-operations.ts |
Removes `getConditionStore as getReadonlyConditionStore` alias from the
export block; all consumers in the codebase use the `WithFallback`
variant, so this alias had zero consumers. |
| packages/react-core/src/pure.ts | Removes `AuthFromEnvParams` and
`AuthFromEnvReturn` type re-exports — both types are being deleted at
source and have no remaining consumers. |
| packages/react-core/src/utils/types.ts | Deletes `AuthFromEnvParams`
and `AuthFromEnvReturn` type definitions — confirmed unused across the
entire codebase. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Dead Export Removal PR] --> B[packages/cli]
    A --> C[packages/i18n]
    A --> D[packages/react-core]

    B --> B1["console/index.ts\n- noSupportedFormatError ❌"]
    B --> B2["formats/files/aggregateFiles.ts\n- SUPPORTED_DATA_FORMATS ❌"]
    B --> B3["utils/headers.ts\n- getAuthHeaders() ❌ (file deleted)"]

    C --> C1["internal-types.ts\n- TranslationMetadata (redundant re-export) ❌\n  already covered by export type *"]

    D --> D1["condition-store/singleton-operations.ts\n- getConditionStore as getReadonlyConditionStore ❌\n  all callers use WithFallback variant"]
    D --> D2["pure.ts\n- AuthFromEnvParams ❌\n- AuthFromEnvReturn ❌"]
    D --> D3["utils/types.ts\n- AuthFromEnvParams type def ❌\n- AuthFromEnvReturn type def ❌"]
```

</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 Export Removal PR] --> B[packages/cli]
    A --> C[packages/i18n]
    A --> D[packages/react-core]

    B --> B1["console/index.ts\n- noSupportedFormatError ❌"]
    B --> B2["formats/files/aggregateFiles.ts\n- SUPPORTED_DATA_FORMATS ❌"]
    B --> B3["utils/headers.ts\n- getAuthHeaders() ❌ (file deleted)"]

    C --> C1["internal-types.ts\n- TranslationMetadata (redundant re-export) ❌\n  already covered by export type *"]

    D --> D1["condition-store/singleton-operations.ts\n- getConditionStore as getReadonlyConditionStore ❌\n  all callers use WithFallback variant"]
    D --> D2["pure.ts\n- AuthFromEnvParams ❌\n- AuthFromEnvReturn ❌"]
    D --> D3["utils/types.ts\n- AuthFromEnvParams type def ❌\n- AuthFromEnvReturn type def ❌"]
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["refactor: remove dead internal
exports"](d5576f6)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40963643)</sub>

<!-- /greptile_comment -->
## Summary
- add explicit portable selector hook result types in react-core
- reuse those types in gt-react-native selector hooks to avoid
non-nameable declaration output
- add a patch changeset for react-core and gt-react-native

## Checks
- pnpm --filter @generaltranslation/react-core typecheck
- pnpm --filter gt-react typecheck
- pnpm --filter gt-react-native typecheck
- pnpm format
- git diff --check

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR adds explicit TypeScript return types to the
`useInternalLocaleSelector` and `useInternalRegionSelector` hooks in
`react-core`, then reuses those exported types in the `gt-react-native`
selector wrappers to fix TS2742 errors that occur in project-reference
builds when TypeScript tries to name inferred types that reach into
non-portable bundled declarations from `generaltranslation`.

- **`react-core`**: Introduces `InternalLocaleSelectorResult` and
`InternalRegionSelectorResult` types, annotates the hook functions with
those types, and re-exports them from the hooks barrel (`hooks.ts`).
- **`gt-react-native`**: Updates `useLocaleSelector` and
`useRegionSelector` to declare explicit return types as intersections of
the newly exported core result types with their respective setter
signatures.
- **Changeset**: A patch bump for both `@generaltranslation/react-core`
and `gt-react-native` is included.

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

Pure TypeScript type-annotation additions with no runtime behavior
changes; safe to merge.

All changes are additive type exports and explicit return-type
annotations. The declared types accurately reflect the objects each hook
already returned. No logic, runtime paths, or public APIs are altered.

No files require special attention.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/react-core/src/hooks/useInternalLocaleSelector.ts | Adds
explicit InternalLocaleSelectorResult type and annotates the function's
return type; types accurately match the actual returned shape. |
| packages/react-core/src/hooks/useInternalRegionSelector.ts | Adds
InternalRegionSelectorResult type and annotates the function's return;
all five fields match the returned object exactly. |
| packages/react-core/src/hooks.ts | Re-exports the two new result types
from the hooks barrel; no functional changes. |
| packages/react-native/src/hooks/selectors.ts | Annotates
useLocaleSelector and useRegionSelector with explicit intersection
return types reusing the newly exported core types; resolves TS2742 for
project-reference builds. |
| .changeset/react-native-selector-return-types.md | Correct patch
changeset targeting both @generaltranslation/react-core and
gt-react-native. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
classDiagram
    class InternalLocaleSelectorResult {
        +string locale
        +string[] locales
        +getLocaleProperties(locale: string) LocaleProperties
    }

    class InternalRegionSelectorResult {
        +string|undefined region
        +string[] regions
        +Map~string,RegionData~ regionData
        +string locale
        +string localeRegion
    }

    class useLocaleSelector {
        +InternalLocaleSelectorResult & setLocale
    }

    class useRegionSelector {
        +InternalRegionSelectorResult & setLocale & setRegion
    }

    useLocaleSelector --|> InternalLocaleSelectorResult : extends
    useRegionSelector --|> InternalRegionSelectorResult : extends
```

</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 InternalLocaleSelectorResult {
        +string locale
        +string[] locales
        +getLocaleProperties(locale: string) LocaleProperties
    }

    class InternalRegionSelectorResult {
        +string|undefined region
        +string[] regions
        +Map~string,RegionData~ regionData
        +string locale
        +string localeRegion
    }

    class useLocaleSelector {
        +InternalLocaleSelectorResult & setLocale
    }

    class useRegionSelector {
        +InternalRegionSelectorResult & setLocale & setRegion
    }

    useLocaleSelector --|> InternalLocaleSelectorResult : extends
    useRegionSelector --|> InternalRegionSelectorResult : extends
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["fix: add portable selector
return
types"](b5303b1)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40965389)</sub>

<!-- /greptile_comment -->
## Summary
- pass prebuilt child renderers into createRenderPreparedT
- keep renderPreparedT shared logic free of child renderer construction
- add a patch changeset for react-core

## Checks
- pnpm --filter @generaltranslation/react-core typecheck
- pnpm --filter @generaltranslation/react-core test
- pnpm format
- git diff --check

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR refactors the render pipeline so that `createRenderPreparedT`
receives already-constructed `renderDefaultChildren` and
`renderTranslatedChildren` instances rather than re-creating them
internally from `renderVariable`. The result is one fewer
`createRenderTranslatedChildren` call per pipeline instantiation and a
cleaner separation of concerns inside `renderPreparedT.shared.ts`.

- `createRenderPipeline.ts` now passes the already-built child renderers
to `createRenderPreparedT`, eliminating the internal construction that
previously happened inside the factory.
- `renderPreparedT.shared.ts` drops its factory imports and accepts the
pre-built renderer functions directly, keeping the module free of any
renderer-construction logic.

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

Safe to merge — purely structural refactor with no behavioral changes to
the rendering logic.

The refactor correctly wires the shared child renderers through
createRenderPipeline and the updated createRenderPreparedT signature.
createRenderTranslatedChildren still constructs its own private
renderDefaultChildren internally (unchanged file), so deduplication is
only partial — the PR achieves its stated goal for renderPreparedT but
leaves one duplicate in renderTranslatedChildren.

renderTranslatedChildren.shared.tsx still builds a private
renderDefaultChildren internally; a follow-up could pass the pre-built
instance in if full sharing is desired.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/react-core/src/utils/rendering/createRenderPipeline.ts |
Updated to pass pre-built renderDefaultChildren and
renderTranslatedChildren to createRenderPreparedT instead of
renderVariable; logic is straightforward and all four pipeline members
are correctly wired. |
| packages/react-core/src/utils/rendering/renderPreparedT.shared.ts |
Factory signature changed from { renderVariable } to {
renderDefaultChildren, renderTranslatedChildren }; now type-imports the
arg types rather than the constructors, and removes internal
child-renderer construction — no logic changes. |
| .changeset/react-core-render-pipeline-dedup.md | Adds a patch
changeset for @generaltranslation/react-core describing the
deduplication of child renderer construction. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[createRenderPipeline] --> B[createRenderVariable\nrenderVariable]
    B --> C[createRenderDefaultChildren\nrenderDefaultChildren ①]
    B --> D[createRenderTranslatedChildren\nrenderTranslatedChildren]
    D --> E[createRenderDefaultChildren\nrenderDefaultChildren ② internal]
    C --> F[createRenderPreparedT\nrenderPreparedT]
    D --> F
    F --> G[RenderPipeline\n renderVariable\n renderDefaultChildren ①\n renderTranslatedChildren\n renderPreparedT]

    style E fill:#ffe0b2,stroke:#f57c00
    style C fill:#c8e6c9,stroke:#388e3c
    style F fill:#c8e6c9,stroke:#388e3c
```

</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[createRenderPipeline] --> B[createRenderVariable\nrenderVariable]
    B --> C[createRenderDefaultChildren\nrenderDefaultChildren ①]
    B --> D[createRenderTranslatedChildren\nrenderTranslatedChildren]
    D --> E[createRenderDefaultChildren\nrenderDefaultChildren ② internal]
    C --> F[createRenderPreparedT\nrenderPreparedT]
    D --> F
    F --> G[RenderPipeline\n renderVariable\n renderDefaultChildren ①\n renderTranslatedChildren\n renderPreparedT]

    style E fill:#ffe0b2,stroke:#f57c00
    style C fill:#c8e6c9,stroke:#388e3c
    style F fill:#c8e6c9,stroke:#388e3c
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["refactor: share render
pipeline child
re..."](142f626)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40971275)</sub>

<!-- /greptile_comment -->
## Summary
- remove stale package metadata for non-emitted subpaths
- preserve gt-next link client-boundary files in sideEffects
- align gt-tanstack-start legacy main/module fields with the server
export fallback
- add a patch changeset for gt-next, gt-react, and gt-tanstack-start

## Checks
- pnpm --filter gt-tanstack-start typecheck
- pnpm --filter gt-tanstack-start build
- pnpm --filter gt-next test -- packageExports
- pnpm --filter gt-react test -- react-package
- pnpm format
- git diff --check

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR cleans up stale package metadata across three packages and fixes
a `main`/`module` field misalignment in `gt-tanstack-start`.

- **`gt-next`**: Adds `./dist/link.*` and `./dist/link/Link.*` to
`sideEffects` to prevent bundlers from tree-shaking client-boundary
files; removes `./compiler` and `./eslint-plugin` subpath exports that
had no emitted build output.
- **`gt-react`**: Removes the stale `./setup` entry from `typesVersions`
and `compilerOptions.paths` — no corresponding `.d.cts` was emitted.
- **`gt-tanstack-start`**: Aligns legacy `main`/`module` fields to point
at `index.server.*` (matching the `exports` default fallback), removes
the empty `src/types.ts` file and its `./types` subpath export, and
drops it from the tsdown build entries.

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

Safe to merge — all changes are metadata cleanup and a legacy
entry-point alignment with no runtime logic touched.

Every changed file is either a package.json, a build config, or an empty
source file. The removed subpath exports (./compiler, ./eslint-plugin,
./setup, ./types) have no consumers anywhere in the repo. The
gt-tanstack-start main/module alignment correctly matches what the
exports default fallback already served, fixing a pre-existing mismatch
rather than introducing a behavior change. The sideEffects additions
protect client-boundary link files from being dropped by tree-shakers.

No files require special attention.
</details>

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

| Filename | Overview |
|----------|----------|
| .changeset/clean-package-config-metadata.md | Patch changeset covering
gt-next, gt-react, and gt-tanstack-start — correctly scoped as a patch
for metadata-only and bug-fix alignment changes. |
| packages/next/package.json | Adds ./dist/link.* and ./dist/link/Link.*
to sideEffects to prevent tree-shaking of client-boundary files; removes
stale ./compiler and ./eslint-plugin subpath exports that had no
corresponding build output. |
| packages/react/package.json | Removes the stale ./setup typesVersions
and compilerOptions.paths entries that had no corresponding emitted
output. |
| packages/tanstack-start/package.json | Aligns legacy main/module
fields with the server export fallback; removes the stale ./types
subpath export and its typesVersions/compilerOptions entries. |
| packages/tanstack-start/src/types.ts | Deleted empty file (zero-byte)
whose corresponding build entry and package.json subpath export are
removed in the same PR. |
| packages/tanstack-start/tsdown.config.mts | Removes src/types.ts from
the build entry list, consistent with the file deletion and package.json
cleanup. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph gt-next
        N1["sideEffects\n+ ./dist/link.*\n+ ./dist/link/Link.*"] --> N2["Client-boundary files\npreserved from tree-shaking"]
        N3["Remove ./compiler export"] --> N4["No emitted build output"]
        N5["Remove ./eslint-plugin export"] --> N4
    end
    subgraph gt-react
        R1["Remove ./setup from\ntypesVersions & paths"] --> R2["No emitted .d.cts"]
    end
    subgraph gt-tanstack-start
        T1["main/module: index.client.*\n→ index.server.*"] --> T2["Aligned with exports\ndefault fallback"]
        T3["Remove ./types subpath"] --> T4["src/types.ts deleted\n(was empty)"]
        T5["tsdown: remove\nsrc/types.ts entry"] --> T4
    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 gt-next
        N1["sideEffects\n+ ./dist/link.*\n+ ./dist/link/Link.*"] --> N2["Client-boundary files\npreserved from tree-shaking"]
        N3["Remove ./compiler export"] --> N4["No emitted build output"]
        N5["Remove ./eslint-plugin export"] --> N4
    end
    subgraph gt-react
        R1["Remove ./setup from\ntypesVersions & paths"] --> R2["No emitted .d.cts"]
    end
    subgraph gt-tanstack-start
        T1["main/module: index.client.*\n→ index.server.*"] --> T2["Aligned with exports\ndefault fallback"]
        T3["Remove ./types subpath"] --> T4["src/types.ts deleted\n(was empty)"]
        T5["tsdown: remove\nsrc/types.ts entry"] --> T4
    end
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["fix: clean up package
metadata"](17799f3)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40967115)</sub>

<!-- /greptile_comment -->
## Summary
- Set translation cache expiry to 0 when Next.js Cache Components are
enabled
- Treat gt-i18n cache entries with expiresAt 0 as immediately expired
without calling Date.now()
- Use a file-level "use cache" remote translation loader for default
Cache Components translation loading, while preserving custom
loadTranslations()
- Add gt-i18n and gt-next patch changesets and focused tests

## Testing
- pnpm exec oxfmt --check packages/next/src/config.ts
packages/next/src/config-dir/props/withGTConfigProps.ts
packages/next/src/errors/cacheComponents.ts
packages/next/src/setup/shared.ts
packages/next/src/setup/__tests__/shared.test.ts
packages/next/src/utils/createCacheComponentsLoadTranslations.ts
packages/next/src/utils/loadCacheComponentsTranslations.ts
packages/next/src/utils/__tests__/createCacheComponentsLoadTranslations.test.ts
packages/i18n/src/i18n-cache/translations-manager/ResourceCache.ts
packages/i18n/src/i18n-cache/translations-manager/__tests__/ResourceCache.test.ts
.changeset/cache-components-disable-expiry.md
- pnpm --filter gt-next test:js -- src/__tests__/config.test.ts
src/setup/__tests__/shared.test.ts
src/utils/__tests__/createCacheComponentsLoadTranslations.test.ts
- pnpm --filter gt-i18n test --
src/i18n-cache/translations-manager/__tests__/ResourceCache.test.ts
src/i18n-cache/__tests__/I18nCache.test.ts
- pnpm --filter gt-next typecheck
- pnpm --filter gt-i18n typecheck
- pnpm --filter gt-i18n build
- pnpm --filter gt-next build:no-swc-plugin
- pnpm build:next-app-router-locale-routing-use-cache
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.5

### Patch Changes

- 4a5f8e8: Remove unused internal exports and dead utility code.
## @generaltranslation/compiler@1.3.25-odysseus.5

### Patch Changes

- 432fa49: Support dev hot reload lookups for server `getGT` strings.

`getGT` can now receive compiler-injected message metadata and prefetch
missing translations through the runtime cache in development. `gt-next`
forwards the server request conditions into this path so App Router
server strings can participate in hot reload translation updates.

Compiler-injected `getGT` and `useGT` preload messages now emit the same
sugar metadata keys used by runtime lookup options.
## gtx-cli@2.14.51-odysseus.5

### Patch Changes

- Updated dependencies [4a5f8e8]
  - gt@2.14.51-odysseus.5
## gt-i18n@1.0.0-odysseus.5

### Patch Changes

- 432fa49: Use Next.js caching semantics for Cache Components by
disabling GT cache expiry and development hot reload runtime
translation.

Async translation and dictionary lookup boundaries now keep synchronous
access to the loaded snapshot, so APIs like `getGT` and
`getTranslations` can still resolve strings after cache expiry is
delegated to Next.js.

Global singleton setup now preserves the first initialized instance
instead of replacing it on later initialization attempts.

- 432fa49: Support dev hot reload lookups for server `getGT` strings.

`getGT` can now receive compiler-injected message metadata and prefetch
missing translations through the runtime cache in development. `gt-next`
forwards the server request conditions into this path so App Router
server strings can participate in hot reload translation updates.

Compiler-injected `getGT` and `useGT` preload messages now emit the same
sugar metadata keys used by runtime lookup options.

- 933916e: Store the GT services enabled flag on the i18n config
singleton.
- 4a5f8e8: Remove unused internal exports and dead utility code.
- 083d306: Remove deprecated i18n cache lifecycle hooks and unused cache
events.

The cache subscription surface now only exposes
`translations-cache-miss`, which is used for runtime translation
updates. Deprecated lifecycle constructor callbacks and unused
locale/dictionary cache hit/miss events have been removed.
## locadex@1.0.186-odysseus.5

### Patch Changes

- Updated dependencies [4a5f8e8]
  - gt@2.14.51-odysseus.5
## gt-next@11.0.0-odysseus.10

### Patch Changes

- 432fa49: Use Next.js caching semantics for Cache Components by
disabling GT cache expiry and development hot reload runtime
translation.

Async translation and dictionary lookup boundaries now keep synchronous
access to the loaded snapshot, so APIs like `getGT` and
`getTranslations` can still resolve strings after cache expiry is
delegated to Next.js.

Global singleton setup now preserves the first initialized instance
instead of replacing it on later initialization attempts.

- 07f74f0: Clean up stale package metadata and align TanStack Start
package entry points.
- 432fa49: Support dev hot reload lookups for server `getGT` strings.

`getGT` can now receive compiler-injected message metadata and prefetch
missing translations through the runtime cache in development. `gt-next`
forwards the server request conditions into this path so App Router
server strings can participate in hot reload translation updates.

Compiler-injected `getGT` and `useGT` preload messages now emit the same
sugar metadata keys used by runtime lookup options.

- 33d4be2: Point the `react-server` export condition at the RSC-specific
declaration file so TypeScript no longer exposes client-only hooks in
React Server Components.
- 75dc650: Remove the unused `getDomain` request-function plumbing from
`gt-next`.

`getDomain` was scaffolded (a throw-only `internal/_getDomain` stub, a
`getDomainPath` config prop, a `getDomain` entry in the request-function
registry, and a `_GENERALTRANSLATION_CUSTOM_GET_DOMAIN_ENABLED` build
env var) but never wired to any runtime consumer — no `getDomain()`
request helper exists and nothing reads the env var. Removes the stub
module, the `./internal/_getDomain` export, the config prop/registry
entries, and the dead env var. `getLocale`/`getRegion` are unchanged.

- 8e0a992: Remove the deprecated SSG and experimental-locale-resolution
code paths from `gt-next`.

Drops the long-deprecated, runtime-dead config surface:
`experimentalEnableSSG`,
`experimentalLocaleResolution`/`experimentalLocaleResolutionParam`, the
static request functions (`STATIC_REQUEST_FUNCTIONS`/`getStatic*` and
their non-existent `internal/static/*` aliases), and
`disableSSGWarnings`/`getStatic*Path` doc props. Removes
`plugin/checks/ssgChecks.ts`, the experimental branch of
`cacheComponentsChecks`, the related error/warning builders, and the
corresponding build-time env vars (`_GENERALTRANSLATION_ENABLE_SSG`,
`_GENERALTRANSLATION_EXPERIMENTAL_LOCALE_RESOLUTION[_PARAM]`,
`_GENERALTRANSLATION_STATIC_GET_*_ENABLED`) — none of which were read at
runtime. The live cacheComponents checks and
`noLocalesCouldBeDeterminedWarning` are retained.

- Updated dependencies [432fa49]
- Updated dependencies [07f74f0]
- Updated dependencies [432fa49]
- Updated dependencies [ee34fea]
- Updated dependencies [bcba6fd]
- Updated dependencies [933916e]
- Updated dependencies [b7b3eaf]
- Updated dependencies [dfb5fc9]
- Updated dependencies [4a5f8e8]
- Updated dependencies [288c9f8]
- Updated dependencies [083d306]
  - gt-i18n@1.0.0-odysseus.5
  - gt-react@11.0.0-odysseus.10
  - @generaltranslation/compiler@1.3.25-odysseus.5
  - @generaltranslation/react-core@11.0.0-odysseus.10
## @generaltranslation/gt-next-lint@15.0.0-odysseus.10

### Patch Changes

- Updated dependencies [432fa49]
- Updated dependencies [07f74f0]
- Updated dependencies [432fa49]
- Updated dependencies [33d4be2]
- Updated dependencies [75dc650]
- Updated dependencies [8e0a992]
  - gt-next@11.0.0-odysseus.10
## gt-node@1.0.0-odysseus.5

### Patch Changes

- Updated dependencies [432fa49]
- Updated dependencies [432fa49]
- Updated dependencies [933916e]
- Updated dependencies [4a5f8e8]
- Updated dependencies [083d306]
  - gt-i18n@1.0.0-odysseus.5
## gt-react@11.0.0-odysseus.10

### Patch Changes

- 07f74f0: Clean up stale package metadata and align TanStack Start
package entry points.
- ee34fea: Use the shared runtime environment helper for browser cache
dev-mode checks so `gt-react` typechecks without Vite ambient types.
- bcba6fd: Fix `useVersionId()` throwing and `useLocaleDirection()`
requiring a locale argument in the client and server entrypoints.

`useVersionId()` now returns the current version id (instead of throwing
the react-core "not implemented" error), and `useLocaleDirection()` once
again accepts an optional locale that defaults to the current locale.
The shared implementation now lives in
`@generaltranslation/react-core/hooks`, so `gt-react` and
`gt-react-native` use the same behavior; the RSC entrypoint keeps its
stricter signatures.

- 288c9f8: Remove the deprecated `internalInitializeGTSPA` export from
`@generaltranslation/react-core/pure` and the downstream `gt-react`
server/types surfaces. Use `initializeGTSPA` from `gt-react` for browser
SPA initialization.
- Updated dependencies [432fa49]
- Updated dependencies [432fa49]
- Updated dependencies [bcba6fd]
- Updated dependencies [933916e]
- Updated dependencies [b7b3eaf]
- Updated dependencies [dfb5fc9]
- Updated dependencies [4a5f8e8]
- Updated dependencies [288c9f8]
- Updated dependencies [083d306]
  - gt-i18n@1.0.0-odysseus.5
  - @generaltranslation/react-core@11.0.0-odysseus.10
## @generaltranslation/react-core@11.0.0-odysseus.10

### Patch Changes

- bcba6fd: Fix `useVersionId()` throwing and `useLocaleDirection()`
requiring a locale argument in the client and server entrypoints.

`useVersionId()` now returns the current version id (instead of throwing
the react-core "not implemented" error), and `useLocaleDirection()` once
again accepts an optional locale that defaults to the current locale.
The shared implementation now lives in
`@generaltranslation/react-core/hooks`, so `gt-react` and
`gt-react-native` use the same behavior; the RSC entrypoint keeps its
stricter signatures.

- b7b3eaf: Share render pipeline child renderers with prepared
translation rendering.
- dfb5fc9: Add portable selector hook return types for React Native
declarations.
- 4a5f8e8: Remove unused internal exports and dead utility code.
- 288c9f8: Remove the deprecated `internalInitializeGTSPA` export from
`@generaltranslation/react-core/pure` and the downstream `gt-react`
server/types surfaces. Use `initializeGTSPA` from `gt-react` for browser
SPA initialization.
- Updated dependencies [432fa49]
- Updated dependencies [432fa49]
- Updated dependencies [933916e]
- Updated dependencies [4a5f8e8]
- Updated dependencies [083d306]
  - gt-i18n@1.0.0-odysseus.5
## gt-react-native@11.0.0-odysseus.10

### Patch Changes

- bcba6fd: Fix `useVersionId()` throwing and `useLocaleDirection()`
requiring a locale argument in the client and server entrypoints.

`useVersionId()` now returns the current version id (instead of throwing
the react-core "not implemented" error), and `useLocaleDirection()` once
again accepts an optional locale that defaults to the current locale.
The shared implementation now lives in
`@generaltranslation/react-core/hooks`, so `gt-react` and
`gt-react-native` use the same behavior; the RSC entrypoint keeps its
stricter signatures.

- dfb5fc9: Add portable selector hook return types for React Native
declarations.
- Updated dependencies [432fa49]
- Updated dependencies [432fa49]
- Updated dependencies [bcba6fd]
- Updated dependencies [933916e]
- Updated dependencies [b7b3eaf]
- Updated dependencies [dfb5fc9]
- Updated dependencies [4a5f8e8]
- Updated dependencies [288c9f8]
- Updated dependencies [083d306]
  - gt-i18n@1.0.0-odysseus.5
  - @generaltranslation/react-core@11.0.0-odysseus.10
## gt-tanstack-start@11.0.0-odysseus.10

### Patch Changes

- 07f74f0: Clean up stale package metadata and align TanStack Start
package entry points.
- Updated dependencies [432fa49]
- Updated dependencies [07f74f0]
- Updated dependencies [432fa49]
- Updated dependencies [ee34fea]
- Updated dependencies [bcba6fd]
- Updated dependencies [933916e]
- Updated dependencies [b7b3eaf]
- Updated dependencies [dfb5fc9]
- Updated dependencies [4a5f8e8]
- Updated dependencies [288c9f8]
- Updated dependencies [083d306]
  - gt-i18n@1.0.0-odysseus.5
  - gt-react@11.0.0-odysseus.10
  - @generaltranslation/react-core@11.0.0-odysseus.10

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## Summary
- Preserve compiler-collected format metadata on useGT/getGT preload
entries.
- Add a regression test for await getGT() with $format: STRING.

## Testing
- pnpm --filter @generaltranslation/compiler test
- pnpm --filter @generaltranslation/compiler typecheck
- pnpm --filter @generaltranslation/compiler format

No changeset added per request.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR fixes a bug where the `format` field was not being included in
the preload metadata injected into `getGT`/`useGT` call expressions
during the compiler's injection pass. It also adds a regression test and
refactors shared test helper logic.

- **`injectCallbackDeclaratorFunctionParameters.ts`**: Adds a `format`
property to the `objectExpression` built for each `translationContent`
entry, matching the same conditional-spread pattern already used for
`id`, `context`, and `maxChars`.
- **`runtimeTranslatePass.test.ts`**: Extracts a reusable
`getObjectPropertyValue` helper, adds a `getPreloadMessageValue` helper
for asserting into the preload array structure, and adds a dedicated
test case verifying `format` is forwarded through the pipeline.

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

Safe to merge — the change is a minimal, well-tested addition of a
missing field to the preload metadata injection.

The production change exactly mirrors the established pattern for other
optional fields and the new test exercises the full compiler pipeline
end-to-end. No existing behaviour is altered; only the previously
dropped `format` field is now forwarded.

No files require special attention. The single style note in the test
helper does not affect correctness.
</details>

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

| Filename | Overview |
|----------|----------|
|
packages/compiler/src/transform/injection/injectCallbackDeclaratorFunctionParameters.ts
| Adds `format` property injection into the preload metadata object;
follows the identical conditional-spread pattern used for other optional
fields (`id`, `context`, `maxChars`) — correct and minimal. |
| packages/compiler/src/passes/__tests__/runtimeTranslatePass.test.ts |
Adds test coverage for the format field in getGT preload metadata; uses
`expect()` assertions inside a utility helper, which can produce
harder-to-diagnose failure messages when assertions fail mid-helper. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Source as Source File
    participant Collection as collectionPass
    participant State as TransformState stringCollector
    participant Injection as injectionPass
    participant AST as Final AST getGT

    Source->>Collection: traverse AST
    Collection->>State: "store content {hash, message, format, ...}"
    Source->>Injection: traverse AST (varDeclarator for getGT)
    Injection->>State: getTranslationContent(id)
    State-->>Injection: "[{hash, message, format, ...}]"
    Injection->>AST: inject arguments as array of objects (now includes format field)
```

</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 Source as Source File
    participant Collection as collectionPass
    participant State as TransformState stringCollector
    participant Injection as injectionPass
    participant AST as Final AST getGT

    Source->>Collection: traverse AST
    Collection->>State: "store content {hash, message, format, ...}"
    Source->>Injection: traverse AST (varDeclarator for getGT)
    Injection->>State: getTranslationContent(id)
    State-->>Injection: "[{hash, message, format, ...}]"
    Injection->>AST: inject arguments as array of objects (now includes format field)
```

</a>
</details>

<a
href="https://app.greptile.com/ide/claude-code?prompt=Fix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Apackages%2Fcompiler%2Fsrc%2Fpasses%2F__tests__%2FruntimeTranslatePass.test.ts%3A160-169%0AUsing%20%60expect%28%29%60%20inside%20a%20non-test%20utility%20function%20can%20produce%20confusing%20failure%20output%20%E2%80%94%20when%20the%20assertion%20throws%2C%20Jest%2FVitest%20reports%20the%20failure%20site%20as%20being%20inside%20%60getPreloadMessageValue%60%2C%20making%20it%20hard%20to%20tell%20which%20test%20case%20failed%20or%20what%20the%20actual%20received%20value%20was.%20Prefer%20returning%20%60undefined%60%20on%20unexpected%20shapes%20and%20letting%20the%20call-site%20assertions%20fail%20with%20clear%20context.%0A%0A%60%60%60suggestion%0Afunction%20getPreloadMessageValue%28%0A%20%20call%3A%20t.CallExpression%2C%0A%20%20key%3A%20string%0A%29%3A%20string%20%7C%20number%20%7C%20undefined%20%7B%0A%20%20const%20arg%20%3D%20call.arguments%5B0%5D%3B%0A%20%20if%20%28!t.isArrayExpression%28arg%29%29%20return%20undefined%3B%0A%20%20const%20message%20%3D%20%28arg%20as%20t.ArrayExpression%29.elements%5B0%5D%3B%0A%20%20if%20%28!t.isObjectExpression%28message%29%29%20return%20undefined%3B%0A%20%20return%20getObjectPropertyValue%28message%20as%20t.ObjectExpression%2C%20key%29%3B%0A%7D%0A%60%60%60%0A%0A&repo=generaltranslation%2Fgt&pr=1743&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaudeDark.svg?v=4"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=4"><img
alt="Fix All in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=4"></picture></a>
<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22generaltranslation%2Fgt%22%20on%20the%20existing%20branch%20%22e%2Fodysseus%2Fgetgt-preload-format%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22e%2Fodysseus%2Fgetgt-preload-format%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Apackages%2Fcompiler%2Fsrc%2Fpasses%2F__tests__%2FruntimeTranslatePass.test.ts%3A160-169%0AUsing%20%60expect%28%29%60%20inside%20a%20non-test%20utility%20function%20can%20produce%20confusing%20failure%20output%20%E2%80%94%20when%20the%20assertion%20throws%2C%20Jest%2FVitest%20reports%20the%20failure%20site%20as%20being%20inside%20%60getPreloadMessageValue%60%2C%20making%20it%20hard%20to%20tell%20which%20test%20case%20failed%20or%20what%20the%20actual%20received%20value%20was.%20Prefer%20returning%20%60undefined%60%20on%20unexpected%20shapes%20and%20letting%20the%20call-site%20assertions%20fail%20with%20clear%20context.%0A%0A%60%60%60suggestion%0Afunction%20getPreloadMessageValue%28%0A%20%20call%3A%20t.CallExpression%2C%0A%20%20key%3A%20string%0A%29%3A%20string%20%7C%20number%20%7C%20undefined%20%7B%0A%20%20const%20arg%20%3D%20call.arguments%5B0%5D%3B%0A%20%20if%20%28!t.isArrayExpression%28arg%29%29%20return%20undefined%3B%0A%20%20const%20message%20%3D%20%28arg%20as%20t.ArrayExpression%29.elements%5B0%5D%3B%0A%20%20if%20%28!t.isObjectExpression%28message%29%29%20return%20undefined%3B%0A%20%20return%20getObjectPropertyValue%28message%20as%20t.ObjectExpression%2C%20key%29%3B%0A%7D%0A%60%60%60%0A%0A&repo=generaltranslation%2Fgt&pr=1743&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=4"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=4"><img
alt="Fix All in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=4"></picture></a>

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

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

---

### Issue 1 of 1
packages/compiler/src/passes/__tests__/runtimeTranslatePass.test.ts:160-169
Using `expect()` inside a non-test utility function can produce confusing failure output — when the assertion throws, Jest/Vitest reports the failure site as being inside `getPreloadMessageValue`, making it hard to tell which test case failed or what the actual received value was. Prefer returning `undefined` on unexpected shapes and letting the call-site assertions fail with clear context.

```suggestion
function getPreloadMessageValue(
  call: t.CallExpression,
  key: string
): string | number | undefined {
  const arg = call.arguments[0];
  if (!t.isArrayExpression(arg)) return undefined;
  const message = (arg as t.ArrayExpression).elements[0];
  if (!t.isObjectExpression(message)) return undefined;
  return getObjectPropertyValue(message as t.ObjectExpression, key);
}
```

`````

</details>

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

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

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

- Stop passing `locale={false}` through to `next/link` after
`gt-next/link` localizes hrefs.
- Add regression coverage that verifies localized links do not forward
`locale` to the underlying Link component.

## Testing

- `pnpm exec oxfmt --check packages/next/src/link/Link.tsx
packages/next/src/link/__tests__/Link.test.tsx`
- `pnpm exec oxlint packages/next/src/link/Link.tsx
packages/next/src/link/__tests__/Link.test.tsx`
- `pnpm --filter gt-next typecheck`
- `pnpm --filter gt-next exec vitest run
src/link/__tests__/Link.test.tsx`
- `pnpm --filter gt-next test:js`
- `pnpm --filter gt-next build:no-swc-plugin`

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR removes the explicit `locale={false}` forwarding to `next/link`
after `gt-next/link` has already localized the href, and adds a
regression test to verify the behavior. The `locale` prop is a Pages
Router i18n feature that is not supported (and could produce warnings)
in the Next.js App Router.

- `renderLink` now omits `locale` entirely from the props passed to
`NextLink`; since `locale` is already destructured out of
`ResolvedLinkProps`, the fix is achieved by simply dropping the explicit
`locale={false}` override.
- Two vitest cases are added: one for the default path (locale
auto-detected from `useLocale`) and one for the opt-out path
(`locale={false}`), both asserting that `locale` does not appear on the
rendered `NextLink` props.

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

Safe to merge — the change is a one-line removal of a prop that was
already redundant and could cause warnings in App Router.

The `locale` prop was already being destructured out of
`ResolvedLinkProps` before `...props` was spread, so the explicit
`locale={false}` override was the only way it reached `NextLink`.
Removing it is a clean, correct fix. The new tests cover both the
default-locale and opt-out paths and confirm `locale` does not appear on
the rendered `NextLink` props.

No files require special attention.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/next/src/link/Link.tsx | Removes the explicit
`locale={false}` prop forwarded to NextLink; locale is already
destructured out and localizeHref handles all prefixing, so the fix is
correct and minimal. |
| packages/next/src/link/__tests__/Link.test.tsx | New test file with
two cases covering the default locale and locale=false paths; mock setup
and assertions correctly validate that locale is not forwarded to
NextLink. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User as User Code
    participant GTLink as gt-next Link
    participant renderLink as renderLink
    participant localizeHref as localizeHref
    participant NextLink as next/link

    User->>GTLink: "href="/home""
    GTLink->>GTLink: "locale = useLocale() returns "fr""
    GTLink->>renderLink: "href="/home", locale="fr", ...props"
    renderLink->>localizeHref: "/home", "fr"
    localizeHref-->>renderLink: "/fr/home"
    renderLink->>NextLink: "href="/fr/home", ...props (locale omitted)"

    User->>GTLink: "href="/legal", locale=false"
    GTLink->>renderLink: "href="/legal", locale=false, ...props"
    renderLink->>localizeHref: "/legal", false
    localizeHref-->>renderLink: "/legal" unchanged
    renderLink->>NextLink: "href="/legal", ...props (locale omitted)"
```

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

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant User as User Code
    participant GTLink as gt-next Link
    participant renderLink as renderLink
    participant localizeHref as localizeHref
    participant NextLink as next/link

    User->>GTLink: "href="/home""
    GTLink->>GTLink: "locale = useLocale() returns "fr""
    GTLink->>renderLink: "href="/home", locale="fr", ...props"
    renderLink->>localizeHref: "/home", "fr"
    localizeHref-->>renderLink: "/fr/home"
    renderLink->>NextLink: "href="/fr/home", ...props (locale omitted)"

    User->>GTLink: "href="/legal", locale=false"
    GTLink->>renderLink: "href="/legal", locale=false, ...props"
    renderLink->>localizeHref: "/legal", false
    localizeHref-->>renderLink: "/legal" unchanged
    renderLink->>NextLink: "href="/legal", ...props (locale omitted)"
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["fix: stop forwarding locale
prop from
ne..."](69b133c)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=41022058)</sub>

<!-- /greptile_comment -->
## Summary\n- make sync `t()` honor the writable condition store's
`enableI18n` flag\n- return source/default-locale output when i18n is
disabled\n- update `t` tests for the condition-store shape and disabled
behavior\n\n## Checks\n- `pnpm --filter gt-i18n typecheck`\n- `pnpm
--filter gt-i18n test -- --runInBand`

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR fixes the synchronous `t()` function to honour the `enableI18n`
flag from the writable condition store, mirroring the guard already
present in async helpers like `getTranslations`, `getMessages`, and
`getGT`. When i18n is disabled both the string-overload and
tagged-template-literal code paths now fall back to
`getDefaultLocale()`, returning source-language output instead of a
translation.

- **`t.ts`**: The condition store is now fetched once per call;
`getEnableI18n()` gates locale resolution in both `t()` and
`handleTaggedTemplateLiteralTranslation()`, and the now-unused
`getLocale` import is replaced with `getDefaultLocale`.
- **`t.test.ts`**: All existing mocks are updated to include
`getEnableI18n`, and a new test asserts that source output is returned
when i18n is disabled — though only for the string overload; the
tagged-template-literal disabled branch has no dedicated test.

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

Safe to merge; the core logic change is straightforward and consistent
with how other translation helpers already handle the enableI18n flag.

Both code paths in t.ts are correctly guarded, and the implementation
matches the existing pattern in the async helpers. The only gap is a
missing test for the tagged-template-literal branch when i18n is
disabled — the feature works, but a future regression there would go
undetected by the suite.

t.test.ts — the tagged-template-literal disabled-i18n scenario has no
test coverage.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/i18n/src/translation-functions/t.ts | Adds enableI18n guard
to both the string and tagged-template-literal code paths; drops unused
getLocale import and reads the condition store once per call. |
| packages/i18n/src/translation-functions/__tests__/t.test.ts | Updates
all existing mocks to include getEnableI18n and adds a new test for the
disabled-i18n string branch; the tagged-template-literal disabled case
is untested. |

</details>

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

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[t called] --> B{string or template?}
    B -->|string| C[get conditionStore]
    B -->|template| D[get conditionStore]
    C --> E{enableI18n?}
    E -->|true| G[use explicit locale or conditionStore locale]
    E -->|false| H[use defaultLocale]
    D --> F{enableI18n?}
    F -->|true| I[use conditionStore locale]
    F -->|false| J[use defaultLocale]
    G --> K[resolveStringContentWithFallback]
    H --> K
    I --> L[resolveStringContent with fallback]
    J --> L
    K --> M[return string]
    L --> M
```

</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[t called] --> B{string or template?}
    B -->|string| C[get conditionStore]
    B -->|template| D[get conditionStore]
    C --> E{enableI18n?}
    E -->|true| G[use explicit locale or conditionStore locale]
    E -->|false| H[use defaultLocale]
    D --> F{enableI18n?}
    F -->|true| I[use conditionStore locale]
    F -->|false| J[use defaultLocale]
    G --> K[resolveStringContentWithFallback]
    H --> K
    I --> L[resolveStringContent with fallback]
    J --> L
    K --> M[return string]
    L --> M
```

</a>
</details>

<a
href="https://app.greptile.com/ide/claude-code?prompt=Fix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Apackages%2Fi18n%2Fsrc%2Ftranslation-functions%2F__tests__%2Ft.test.ts%3A164-183%0A**Missing%20disabled-i18n%20test%20for%20the%20tagged-template%20branch**%0A%0AThe%20new%20%60'returns%20the%20source%20when%20i18n%20is%20disabled'%60%20test%20only%20exercises%20the%20string%20overload%20%28%60t%28message%2C%20options%29%60%29.%20%60handleTaggedTemplateLiteralTranslation%60%20received%20the%20same%20%60getEnableI18n%28%29%60%20gate%2C%20but%20there%20is%20no%20corresponding%20test%20that%20calls%20%60%60%20t%60Hello%20%24%7Bname%7D!%60%20%60%60%20with%20%60getEnableI18n%3A%20%28%29%20%3D%3E%20false%60.%20If%20a%20regression%20is%20introduced%20in%20that%20branch%2C%20the%20suite%20will%20not%20catch%20it.%0A%0A&repo=generaltranslation%2Fgt&pr=1744&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaudeDark.svg?v=4"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=4"><img
alt="Fix All in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=4"></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%2Fenable-i18n-t-disabled%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%2Fenable-i18n-t-disabled%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Apackages%2Fi18n%2Fsrc%2Ftranslation-functions%2F__tests__%2Ft.test.ts%3A164-183%0A**Missing%20disabled-i18n%20test%20for%20the%20tagged-template%20branch**%0A%0AThe%20new%20%60'returns%20the%20source%20when%20i18n%20is%20disabled'%60%20test%20only%20exercises%20the%20string%20overload%20%28%60t%28message%2C%20options%29%60%29.%20%60handleTaggedTemplateLiteralTranslation%60%20received%20the%20same%20%60getEnableI18n%28%29%60%20gate%2C%20but%20there%20is%20no%20corresponding%20test%20that%20calls%20%60%60%20t%60Hello%20%24%7Bname%7D!%60%20%60%60%20with%20%60getEnableI18n%3A%20%28%29%20%3D%3E%20false%60.%20If%20a%20regression%20is%20introduced%20in%20that%20branch%2C%20the%20suite%20will%20not%20catch%20it.%0A%0A&repo=generaltranslation%2Fgt&pr=1744&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=4"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=4"><img
alt="Fix All in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=4"></picture></a>

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

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

---

### Issue 1 of 1
packages/i18n/src/translation-functions/__tests__/t.test.ts:164-183
**Missing disabled-i18n test for the tagged-template branch**

The new `'returns the source when i18n is disabled'` test only exercises the string overload (`t(message, options)`). `handleTaggedTemplateLiteralTranslation` received the same `getEnableI18n()` gate, but there is no corresponding test that calls `` t`Hello ${name}!` `` with `getEnableI18n: () => false`. If a regression is introduced in that branch, the suite will not catch it.

`````

</details>

<sub>Reviews (1): Last reviewed commit: ["fix: respect disabled i18n in
t"](8c74826)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=41005495)</sub>

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

<!-- /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
## @generaltranslation/compiler@1.3.25-odysseus.6

### Patch Changes

- c34cab3: Preserve `$format` in compiler-injected `getGT` and `useGT`
preload metadata so preloaded runtime lookups use the same hash format
as the original translation call.
## gt-next@11.0.0-odysseus.11

### Patch Changes

- fe7dfd3: Stop forwarding `locale={false}` from `gt-next/link` to the
underlying Next.js link after localizing the href.

This avoids React DOM warnings in newer Next.js versions where the
control prop can reach the rendered anchor.

- Updated dependencies [c34cab3]
  - @generaltranslation/compiler@1.3.25-odysseus.6
  - @generaltranslation/react-core@11.0.0-odysseus.11
  - gt-react@11.0.0-odysseus.11
## @generaltranslation/gt-next-lint@15.0.0-odysseus.11

### Patch Changes

- Updated dependencies [fe7dfd3]
  - gt-next@11.0.0-odysseus.11
## gt-react@11.0.0-odysseus.11

### Patch Changes

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

### Patch Changes

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

### Patch Changes

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

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@ErnestM1234 ErnestM1234 requested a review from a team as a code owner July 1, 2026 19:41
@ErnestM1234 ErnestM1234 closed this Jul 1, 2026
@ErnestM1234 ErnestM1234 force-pushed the e/odysseus/agent-guides-src-entrypoints branch from 6b64cf2 to 07aea99 Compare July 1, 2026 19:44
@ErnestM1234 ErnestM1234 reopened this Jul 1, 2026
Base automatically changed from odysseus to main July 4, 2026 02:25
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