docs: document package src entrypoint layout#1763
Open
ErnestM1234 wants to merge 191 commits into
Open
Conversation
## 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>
6b64cf2 to
07aea99
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
srcfiles are reserved for consumer entrypointsTesting
Greptile Summary
This PR adds consistent documentation across
.claude/agent-guide files declaring that top-levelsrcfiles in every package are reserved for package entrypoints (e.g.index.ts,main.ts, subpath-exported files) and that all implementation logic belongs insrcsubdirectories..claude/CLAUDE.md, all five area rule files (cli.md,compiler.md,core.md,linter-plugins.md,react-packages.md), and theimplement-featureskill.packages/compiler/.claude/CLAUDE.mdto show a "target organization" code-org tree (replacingconfig.tswithconfig/), labels the existingsrc/config.tsas 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.tsfrom the desiredconfig/subdirectory. Verified against the actualpackages/compiler/src/layout — onlyindex.tsandconfig.tsexist at the root, matching the documentation exactly.No files require special attention.
Important Files Changed
src/generated/is already a subdirectory, so no conflict with the new rule.src/root; matches the actual layout (onlyindex.tsand the legacyconfig.tsexist at the root).index.ts,internal.ts,types.ts); clear and accurate.src/rules/,src/utils/); consistent with other rule files..tsand.tsxfiles; consistent and accurate for the React package family.config.tsas a legacy location, and updates the config section reference; verified against the actualsrc/layout (onlyindex.tsandconfig.tsat 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]%%{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]Reviews (2): Last reviewed commit: "docs: document package src entrypoint la..." | Re-trigger Greptile