fix: remove unused gt-i18n internal entrypoints - #1714
Open
eoinest wants to merge 168 commits into
Open
Conversation
## Summary - Delete internal barrel-only `index.ts` and barrel `types.ts` files outside package entrypoints. - Rewrite imports and entrypoint re-exports to point directly at defining source files. - Preserve package entrypoints such as root `src/index.ts` and public `src/types.ts` exports. - Add patch changeset `.changeset/remove-source-barrel-exports.md`. ## Testing - `pnpm build` - `pnpm --filter @generaltranslation/compiler --filter generaltranslation --filter gt-i18n --filter gt-node --filter gt-sanity test` - `pnpm lint` <!-- codesmith:footer --> --- <a href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1677"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img alt="View with Codesmith" src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a> <a href="https://backend.blacksmith.sh/track/enable-autofix?expires=1785119624&installation_id=127936663&pr_number=1677&repository=generaltranslation%2Fgt&return_to=https%3A%2F%2Fgithub.com%2Fgeneraltranslation%2Fgt%2Fpull%2F1677&signature=811838818a55cee8af653538368b8cc8125df83bcb381038594fde160bda29cd"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img alt="Autofix with Codesmith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a> <sup>Need help on this PR? Tag <code>/codesmith</code> with what you need. Autofix is disabled.</sup> <!-- codesmith:autofix:disabled --> <!-- /codesmith:footer --> <!-- greptile_comment --> <h3>Greptile Summary</h3> This refactor removes internal barrel-only `index.ts` and `types.ts` files scattered throughout the monorepo's packages (`cli`, `compiler`, `core`, `i18n`, `node`, `sanity`) and replaces them with direct imports pointing at the defining source files. Public package entrypoints (`src/index.ts`, `src/types.ts`, `src/internal.ts`, `src/fallbacks.ts`) are preserved and updated in place. - Barrel files deleted include `packages/i18n/src/i18n-cache/index.ts`, `packages/node/src/helpers/index.ts`, `packages/sanity/src/serialization/index.ts`, and 10+ others across the packages; all call-sites within the repo are updated in the same commit. - Multi-level re-export chains (e.g. `src/index.ts` → `translation-functions/derive/index.ts` → `generaltranslation/internal`) are collapsed into single-hop `export { ... } from 'generaltranslation/internal'` statements. - Test files are updated in lock-step to import from concrete source paths, and a search across all packages finds no remaining consumers of the deleted barrel modules. <details open><summary><h3>Confidence Score: 5/5</h3></summary> All barrel files are cleanly removed with every call-site in the repo updated in lock-step; no export gaps found. The change is purely structural — no logic is added or removed. A manual cross-check of every deleted barrel against the rest of the codebase found no remaining consumers, and the multi-hop re-export chains are faithfully collapsed into equivalent single-hop exports. Tests and the public package entrypoints are untouched in semantics. No files require special attention; all 44 changed files consistently apply the same mechanical import-path update. </details> <details><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | packages/i18n/src/internal.ts | Expands two barrel-level wildcard re-exports into 10+ named direct exports, preserving the exact same public API surface. | | packages/i18n/src/index.ts | Replaces barrel re-exports for msg, derive, fallbacks, and helpers with direct file imports; collapses derive chain to a single hop from generaltranslation/internal. | | packages/node/src/index.ts | Expands three barrel re-exports (setup, translation-functions, helpers) into explicit named exports; all symbols from the old barrels are accounted for. | | packages/sanity/src/index.ts | Updates imports of BaseDocumentSerializer, BaseDocumentDeserializer, BaseDocumentMerger, and related types to point directly at their defining files after the serialization barrel is deleted. | | packages/compiler/src/passes/basePass.ts | Replaces namespace import `import * as p from '../processing'` with 14 individual named imports from specific files; functional behavior is identical. | | packages/core/src/internal.ts | Inlines the seven exports from the deleted derive/index.ts barrel directly, preserving the same public surface. | | packages/sanity/src/serialization/index.ts | Deleted — all prior consumers within the package have been updated to import from the concrete source files directly. | | packages/node/src/types.ts | Inlines six type re-exports from the deleted translation-functions/types.ts barrel directly from gt-i18n/types, preserving the full type surface. | </details> <details><summary><h3>Flowchart</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% flowchart TD subgraph Before["Before: Multi-hop barrel chains"] A1["node/src/index.ts"] -->|"export * from"| B1["node/src/translation-functions/index.ts"] B1 -->|"export from"| C1["gt-i18n (index)"] A1 -->|"export * from"| B2["node/src/helpers/index.ts"] B2 -->|"export from"| C1 A1 -->|"export * from"| B3["node/src/setup/index.ts"] B3 -->|"export from"| D1["setup/initializeGT.ts"] E1["i18n/src/index.ts"] -->|"export * from"| F1["translation-functions/derive/index.ts"] F1 -->|"export from"| G1["generaltranslation/internal"] H1["sanity/src/index.ts"] -->|"from"| I1["serialization/index.ts"] I1 -->|"export from"| J1["serialization/BaseDocumentMerger.ts"] end subgraph After["After: Direct single-hop imports"] A2["node/src/index.ts"] -->|"export from"| C2["gt-i18n (index)"] A2 -->|"export from"| D2["setup/initializeGT.ts"] A2 -->|"export from"| D3["setup/withGT.ts"] A2 -->|"export from"| E2["helpers/getRequestLocale.ts"] F2["i18n/src/index.ts"] -->|"export from"| G2["generaltranslation/internal"] H2["sanity/src/index.ts"] -->|"from"| J2["serialization/BaseDocumentMerger.ts"] H2 -->|"from"| K2["serialization/serialize/index.ts"] H2 -->|"from"| L2["serialization/deserialize/BaseDocumentDeserializer.ts"] end ``` </a> <a href="#gh-dark-mode-only"> ```mermaid %%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% flowchart TD subgraph Before["Before: Multi-hop barrel chains"] A1["node/src/index.ts"] -->|"export * from"| B1["node/src/translation-functions/index.ts"] B1 -->|"export from"| C1["gt-i18n (index)"] A1 -->|"export * from"| B2["node/src/helpers/index.ts"] B2 -->|"export from"| C1 A1 -->|"export * from"| B3["node/src/setup/index.ts"] B3 -->|"export from"| D1["setup/initializeGT.ts"] E1["i18n/src/index.ts"] -->|"export * from"| F1["translation-functions/derive/index.ts"] F1 -->|"export from"| G1["generaltranslation/internal"] H1["sanity/src/index.ts"] -->|"from"| I1["serialization/index.ts"] I1 -->|"export from"| J1["serialization/BaseDocumentMerger.ts"] end subgraph After["After: Direct single-hop imports"] A2["node/src/index.ts"] -->|"export from"| C2["gt-i18n (index)"] A2 -->|"export from"| D2["setup/initializeGT.ts"] A2 -->|"export from"| D3["setup/withGT.ts"] A2 -->|"export from"| E2["helpers/getRequestLocale.ts"] F2["i18n/src/index.ts"] -->|"export from"| G2["generaltranslation/internal"] H2["sanity/src/index.ts"] -->|"from"| J2["serialization/BaseDocumentMerger.ts"] H2 -->|"from"| K2["serialization/serialize/index.ts"] H2 -->|"from"| L2["serialization/deserialize/BaseDocumentDeserializer.ts"] end ``` </a> </details> <sub>Reviews (1): Last reviewed commit: ["refactor: remove internal barrel exports"](1e56780) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=40241819)</sub> <!-- /greptile_comment -->
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to odysseus, this PR will be updated.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ `odysseus` is currently in **pre mode** so this branch has prereleases rather than normal releases. If you want to exit prereleases, run `changeset pre exit` on `odysseus`.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ # Releases ## gt@2.14.51-odysseus.1 ### Patch Changes - [#1677](#1677) [`87d6320`](87d6320) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove internal source barrel exports and update imports to reference defining files directly. - Updated dependencies [[`87d6320`](87d6320)]: - generaltranslation@9.0.0-odysseus.1 - @generaltranslation/python-extractor@0.2.23-odysseus.1 - @generaltranslation/supported-locales@2.1.2-odysseus.1 ## @generaltranslation/compiler@1.3.25-odysseus.1 ### Patch Changes - [#1677](#1677) [`87d6320`](87d6320) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove internal source barrel exports and update imports to reference defining files directly. - Updated dependencies [[`87d6320`](87d6320)]: - generaltranslation@9.0.0-odysseus.1 ## generaltranslation@9.0.0-odysseus.1 ### Patch Changes - [#1677](#1677) [`87d6320`](87d6320) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove internal source barrel exports and update imports to reference defining files directly. ## gtx-cli@2.14.51-odysseus.1 ### Patch Changes - Updated dependencies [[`87d6320`](87d6320)]: - gt@2.14.51-odysseus.1 ## gt-i18n@1.0.0-odysseus.1 ### Patch Changes - [#1677](#1677) [`87d6320`](87d6320) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove internal source barrel exports and update imports to reference defining files directly. - Updated dependencies [[`87d6320`](87d6320)]: - generaltranslation@9.0.0-odysseus.1 - @generaltranslation/supported-locales@2.1.2-odysseus.1 ## locadex@1.0.186-odysseus.1 ### Patch Changes - Updated dependencies [[`87d6320`](87d6320)]: - gt@2.14.51-odysseus.1 ## gt-next@11.0.0-odysseus.4 ### Patch Changes - Updated dependencies [[`87d6320`](87d6320)]: - @generaltranslation/compiler@1.3.25-odysseus.1 - generaltranslation@9.0.0-odysseus.1 - gt-i18n@1.0.0-odysseus.1 - gt-react@11.0.0-odysseus.4 - @generaltranslation/react-core@11.0.0-odysseus.4 - @generaltranslation/supported-locales@2.1.2-odysseus.1 ## @generaltranslation/gt-next-lint@15.0.0-odysseus.4 ### Patch Changes - Updated dependencies []: - gt-next@11.0.0-odysseus.4 ## gt-node@1.0.0-odysseus.1 ### Patch Changes - [#1677](#1677) [`87d6320`](87d6320) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove internal source barrel exports and update imports to reference defining files directly. - Updated dependencies [[`87d6320`](87d6320)]: - generaltranslation@9.0.0-odysseus.1 - gt-i18n@1.0.0-odysseus.1 ## @generaltranslation/python-extractor@0.2.23-odysseus.1 ### Patch Changes - Updated dependencies [[`87d6320`](87d6320)]: - generaltranslation@9.0.0-odysseus.1 ## gt-react@11.0.0-odysseus.4 ### Patch Changes - Updated dependencies [[`87d6320`](87d6320)]: - generaltranslation@9.0.0-odysseus.1 - gt-i18n@1.0.0-odysseus.1 - @generaltranslation/react-core@11.0.0-odysseus.4 - @generaltranslation/supported-locales@2.1.2-odysseus.1 ## @generaltranslation/react-core@11.0.0-odysseus.4 ### Patch Changes - Updated dependencies [[`87d6320`](87d6320)]: - generaltranslation@9.0.0-odysseus.1 - gt-i18n@1.0.0-odysseus.1 - @generaltranslation/supported-locales@2.1.2-odysseus.1 ## gt-react-native@11.0.0-odysseus.4 ### Patch Changes - Updated dependencies [[`87d6320`](87d6320)]: - generaltranslation@9.0.0-odysseus.1 - gt-i18n@1.0.0-odysseus.1 - @generaltranslation/react-core@11.0.0-odysseus.4 - @generaltranslation/supported-locales@2.1.2-odysseus.1 ## gt-sanity@2.0.18-odysseus.3 ### Patch Changes - [#1677](#1677) [`87d6320`](87d6320) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove internal source barrel exports and update imports to reference defining files directly. - Updated dependencies [[`87d6320`](87d6320)]: - generaltranslation@9.0.0-odysseus.1 ## @generaltranslation/supported-locales@2.1.2-odysseus.1 ### Patch Changes - Updated dependencies [[`87d6320`](87d6320)]: - generaltranslation@9.0.0-odysseus.1 ## gt-tanstack-start@11.0.0-odysseus.4 ### Patch Changes - Updated dependencies [[`87d6320`](87d6320)]: - generaltranslation@9.0.0-odysseus.1 - gt-i18n@1.0.0-odysseus.1 - gt-react@11.0.0-odysseus.4 - @generaltranslation/react-core@11.0.0-odysseus.4 <!-- codesmith:footer --> --- <a href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1682"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img alt="View with Codesmith" src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a> <a href="https://backend.blacksmith.sh/track/enable-autofix?expires=1785123539&installation_id=127936663&pr_number=1682&repository=generaltranslation%2Fgt&return_to=https%3A%2F%2Fgithub.com%2Fgeneraltranslation%2Fgt%2Fpull%2F1682&signature=f79d7524f1943dddc089904896641070e1d7c91e85829ccbc7e97a05a6f1af11"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img alt="Autofix with Codesmith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a> <sup>Need help on this PR? Tag <code>/codesmith</code> with what you need. Autofix is disabled.</sup> <!-- codesmith:autofix:disabled --> <!-- /codesmith:footer --> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## Summary - Organize entrypoint exports into component, hook, function, type, and helper sections. - Replace re-export-only imports with direct `export ... from` syntax where the binding is not needed locally. - Preserve the existing export surface. - Add patch changeset `.changeset/organize-entrypoint-exports.md`. ## Testing - `pnpm build` - `pnpm lint` - `pnpm --filter generaltranslation test` - `pnpm --filter gt-next test:js` - `pnpm --filter gt-react-native test` - `pnpm --filter gt-sanity test` - export-name comparison against `origin/e/odysseus/remove-source-barrel-exports` <!-- codesmith:footer --> --- <a href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1678"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img alt="View with Codesmith" src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a> <a href="https://backend.blacksmith.sh/track/enable-autofix?expires=1785120739&installation_id=127936663&pr_number=1678&repository=generaltranslation%2Fgt&return_to=https%3A%2F%2Fgithub.com%2Fgeneraltranslation%2Fgt%2Fpull%2F1678&signature=e72ed5832a40b17bd2c8b3f927104c075ca0d49cef814532bd4d3c26524ac592"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img alt="Autofix with Codesmith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a> <sup>Need help on this PR? Tag <code>/codesmith</code> with what you need. Autofix is disabled.</sup> <!-- codesmith:autofix:disabled --> <!-- /codesmith:footer --> <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR reorganizes the entrypoint exports across 9 packages by grouping them into labeled sections (Components, Hooks, Functions, Types) and converting the `import … + export {}` pattern to direct `export … from` syntax where no local binding is needed. No behavioral or API surface changes are intended. - **`packages/core`** (`id.ts`, `internal.ts`) and **`packages/format`** (`types.ts`) now use `export { default as … }` for default-export re-exports and `export type {}` for pure type re-exports, which is semantically equivalent to the prior pattern. - **`packages/next`** (`index.client.ts`, `index.rsc.ts`, `index.server.ts`), **`packages/react-native`**, and **`packages/sanity`** now have each entrypoint organized into clearly labeled sections; modules that are consumed locally *and* re-exported (e.g., `translateAction`, `documentInternationalization` in sanity) correctly keep their top-level `import` and use a bare `export { name }` re-export instead of `export … from`. <details open><summary><h3>Confidence Score: 5/5</h3></summary> Safe to merge — purely organizational, no logic or API surface changes. Every changed file is a package entrypoint barrel. The refactor converts local import+re-export pairs into direct export … from statements and groups the results into labeled sections. Default-export re-exports (getPluralForm, hashTemplate, isVariable, TranslationsTab) were verified against their source files and all have the expected default exports. Modules that are consumed locally inside the gtPlugin closure (translateAction, documentInternationalization) correctly retain their top-level imports alongside the bare re-export. The export surface was manually cross-checked against the base branch for all nine files and no additions or removals were found. No files require special attention. </details> <details><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | packages/core/src/id.ts | Converts import+re-export of hashSource/hashString/hashTemplate to direct export … from syntax; both source files have confirmed default/named exports. | | packages/core/src/internal.ts | Switches to direct export … from for all re-exports; JsxChildren/_Content/JsxChild/JsxElement/LocaleProperties are now correctly marked export type (they are pure interfaces); runtime values (isVariable, encode/decode, etc.) keep value exports. | | packages/format/src/types.ts | Each type now exports directly from its canonical source module; CustomMapping, CutoffFormatOptions, Variable, VariableType, LocaleProperties all preserved; HTML_CONTENT_PROPS value export unchanged. | | packages/next/src/index.client.ts | Large gt-react import block replaced with three direct export sections; local type imports (GetServerSideProps, WithGTServerSideProps) still present for the parseLocale/withGTServerSideProps stub functions. | | packages/next/src/index.rsc.ts | Individual per-component export lines replace a single combined block; getTranslationsSnapshotRscError import moved before initializeGT() in source order, but static imports are always hoisted in ESM so execution order is unchanged. | | packages/next/src/index.server.ts | parseLocale and withGTServerSideProps converted from local import+export to direct export … from; all Components/Hooks/Functions from gt-react preserved with same names. | | packages/react-native/src/index.tsx | Two separate hook export blocks from react-core/hooks consolidated into one alphabetical block; GTProvider, useSetLocale/Region/EnableI18n, useLocaleSelector/RegionSelector, useLocaleDirection/VersionId still exported from their original local modules. | | packages/sanity/src/index.ts | Imports used locally in the gtPlugin closure (translateAction, documentInternationalization, TranslationsTool, SECRETS_NAMESPACE, etc.) are kept as top-level imports; items only re-exported are converted to direct export … from. | </details> <sub>Reviews (1): Last reviewed commit: ["refactor: organize entrypoint exports"](f5c6c5a) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=40242913)</sub> <!-- /greptile_comment -->
## Summary
- Convert default source exports to named exports in core, next,
react-core, and react-native source files
- Update internal imports, re-exports, and Vitest mocks to use named
exports
- Keep `gt-next/link` default-only to match `next/link`, so swapping
imports only changes the package path
- Keep Next generated fallback modules compatible with both default and
named dictionary/loader exports
- Change `gt-react-native/plugin` to expose the named `plugin` export
## Testing
- pnpm lint
- pnpm build
- pnpm --filter generaltranslation typecheck
- pnpm --filter @generaltranslation/react-core typecheck
- pnpm --filter gt-react build
- pnpm --filter gt-next typecheck
- pnpm --filter gt-react-native typecheck
- pnpm --filter gt-node typecheck
- pnpm --filter gt-tanstack-start typecheck
- pnpm --filter generaltranslation test
- pnpm --filter @generaltranslation/react-core test
- pnpm --filter gt-next test:js
- pnpm --filter gt-react-native test
Note: `pnpm typecheck` currently fails on
`packages/react/src/i18n-cache/BrowserI18nCache.ts` because
`ImportMeta.env` is not typed on this branch; focused typechecks above
pass after building `gt-react`.
Changeset added: `.changeset/remove-default-source-exports.md`.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR mechanically converts `export default` to named exports across
`packages/core`, `packages/next`, `packages/react-core`, and
`packages/react-native`. All internal imports are updated to match, and
consumer code that dynamically `require()`s these modules already has
backward-compatible resolution (`?.default || ?.namedExport`).
- **Internal source modules** (`translate/`, `utils/`,
`react-core/utils/`) are pure refactors with no behavior change — every
call site is updated in the same PR.
- **`gt-next/link`** keeps a default export (to match `next/link`) but
drops the re-exported named `Link`; all in-repo consumers use `import
Link from 'gt-next/link'` (default), so no breakage.
- **`gt-react-native/plugin`** moves from a default export to a named
`plugin` export, which is a breaking public-API change documented in the
changeset.
<details open><summary><h3>Confidence Score: 5/5</h3></summary>
Safe to merge — this is a mechanical export style refactor with no
behavior changes in internal logic and explicit backward-compatible
fallbacks in every dynamic consumer.
Every changed file follows the same pattern: export default
function/const → export function/const. All internal call sites are
updated in the same PR. Dynamic consumers (getDictionary.ts,
resolveDictionaryLoader.ts, resolveTranslationLoader.ts, initGT.rsc.ts)
already resolve both .default and the new named export. The two
public-API breaks (gt-react-native/plugin default→named, gt-next/link
dropping named Link) are intentional, pre-release, and documented in the
changeset.
No files require special attention. The most externally visible changes
are in packages/react-native/src/plugin.ts (public API) and
packages/next/src/link.ts (drops named re-export), both of which are
intentional and documented.
</details>
<details><summary><h3>Important Files Changed</h3></summary>
| Filename | Overview |
|----------|----------|
| packages/next/src/link.ts | Drops the named `Link` re-export; only
default export remains to mirror `next/link`. All in-repo usages use the
default import. |
| packages/react-native/src/plugin.ts | Public entrypoint
`gt-react-native/plugin` now exports named `plugin` instead of default;
breaking change documented in the changeset. |
| packages/react-native/src/plugin-dir/index.ts | Babel plugin function
renamed from anonymous default to named `plugin` export; re-exported
cleanly from `plugin.ts`. |
| packages/next/src/dictionary/getDictionary.ts | Backward-compatible
resolution: tries `.default` first then `.dictionary` for TS/JS
dictionaries; handles both old and new generated module shapes. |
| packages/next/src/_dictionary.ts | Fallback sentinel changed from
`export default {}` to `export const dictionary = {}`; still throws on
evaluation so the catch block in getDictionary handles it identically. |
| packages/next/src/_load-dictionary.ts | Fallback sentinel changed to
`export const loadDictionary = undefined`; `resolveDictionaryLoader.ts`
already checks `?.default || ?.loadDictionary` for compatibility. |
| packages/next/src/_load-translations.ts | Identical pattern to
`_load-dictionary.ts`; `resolveTranslationLoader.ts` handles both
`.default` and `.loadTranslations`. |
| packages/react-native/src/NativeGtReactNative.ts | TurboModule
instance moved from default export to named `GtReactNative`; both
consumer files (`getNativeLocales.ts`, `nativeStore.ts`) updated in the
same PR. |
| packages/core/src/translate/translateMany.ts | Function overload pair
correctly converted from `export default` to named `export`; both
overload signature and implementation updated consistently. |
| packages/core/src/index.ts | All default-import callers updated to
named-import destructuring; no missed imports found. |
| packages/react-core/src/pure.ts | All `export { default as X }`
re-exports converted to `export { X }`; consistent with updated source
files. |
</details>
<details><summary><h3>Flowchart</h3></summary>
<a href="#gh-light-mode-only">
```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["gt-next/link\n(public entrypoint)"] -->|"export { Link as default }"| B["link/Link.tsx\nnamed export only"]
C["gt-react-native/plugin\n(public entrypoint)"] -->|"export { plugin }"| D["plugin-dir/index.ts\nexport function plugin()"]
E["gt-next/_dictionary\n(webpack alias / fallback)"] -->|"bundledDictionary.default\n|| bundledDictionary.dictionary"| F["getDictionary.ts\nbackward-compatible resolution"]
G["gt-next/_load-dictionary\n(webpack alias / fallback)"] -->|"?.default || ?.loadDictionary"| H["resolveDictionaryLoader.ts\nbackward-compatible resolution"]
I["gt-next/_load-translations\n(webpack alias / fallback)"] -->|"?.default || ?.loadTranslations"| J["resolveTranslationLoader.ts\nbackward-compatible resolution"]
K["gt-next/internal/_getLocale\ngt-next/internal/_getRegion"] -->|"?.default || ?.getLocale/.getRegion"| L["initGT.rsc.ts\nbackward-compatible resolution"]
style A fill:#ffd700,color:#000
style C fill:#ffd700,color:#000
style F fill:#90ee90,color:#000
style H fill:#90ee90,color:#000
style J fill:#90ee90,color:#000
style L fill:#90ee90,color:#000
```
</a>
<a href="#gh-dark-mode-only">
```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A["gt-next/link\n(public entrypoint)"] -->|"export { Link as default }"| B["link/Link.tsx\nnamed export only"]
C["gt-react-native/plugin\n(public entrypoint)"] -->|"export { plugin }"| D["plugin-dir/index.ts\nexport function plugin()"]
E["gt-next/_dictionary\n(webpack alias / fallback)"] -->|"bundledDictionary.default\n|| bundledDictionary.dictionary"| F["getDictionary.ts\nbackward-compatible resolution"]
G["gt-next/_load-dictionary\n(webpack alias / fallback)"] -->|"?.default || ?.loadDictionary"| H["resolveDictionaryLoader.ts\nbackward-compatible resolution"]
I["gt-next/_load-translations\n(webpack alias / fallback)"] -->|"?.default || ?.loadTranslations"| J["resolveTranslationLoader.ts\nbackward-compatible resolution"]
K["gt-next/internal/_getLocale\ngt-next/internal/_getRegion"] -->|"?.default || ?.getLocale/.getRegion"| L["initGT.rsc.ts\nbackward-compatible resolution"]
style A fill:#ffd700,color:#000
style C fill:#ffd700,color:#000
style F fill:#90ee90,color:#000
style H fill:#90ee90,color:#000
style J fill:#90ee90,color:#000
style L fill:#90ee90,color:#000
```
</a>
</details>
<sub>Reviews (2): Last reviewed commit: ["fix: preserve default link
export"](b55b9c4)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40241802)</sub>
<!-- /greptile_comment -->
## What Removes `@deprecated` symbols that have **no remaining consumers anywhere in the monorepo** — the kind of public-API shedding appropriate for the odysseus major. **core (`generaltranslation`)** - Deprecated types `_Content`, `Update`, `Request`, `ContentTranslationResult`, `IcuTranslationResult`, `JsxTranslationResult` - The `_Content` re-export from `generaltranslation/internal` **gt-i18n** - Renamed-alias re-exports: `I18nManager`, `getI18nManager`, `setI18nManager`, `I18nManagerConstructorParams`, `I18nManagerConfig` (use `I18nCache` / `getI18nCache` / `setI18nCache` / `I18nCacheConstructorParams` / `I18nCacheConfig`) - The all-deprecated wrapper files `sync-translation-resolution.ts` (`resolveTranslationSync`, `resolveTranslationSyncWithFallback`) and `jsx-resolution.ts` (`resolveJsxTranslation`), their barrel exports, and the standalone test (the non-deprecated `resolveTranslation` / `resolveJsx` and the separate `I18nCache.resolveTranslationSync` method are untouched) Net **−273 lines**. ## Verification - Full monorepo build passes (21/21). - Tests pass: core 432, gt-i18n 245, gt-node, react-core 267, gt-react 12, gt-next 191. - Repo-wide grep (incl. `examples/`, `tests/apps/`, docs, JSON) confirms zero references to every removed symbol. `Update`/`Request` name-collisions were checked and are unrelated (web `Request`, `NextRequest`, etc.). ## Deliberately NOT removed (still live — need a real decision, not cleanup) These are deprecated but still wired in, so they're left for separate review: - `internalInitializeGTSPA` (re-exported by `react-core/pure`, used by gt-react) - core enqueue `_versionId` / `description` (still used across the CLI) - next `STATIC_REQUEST_FUNCTIONS` / `StaticRequestFunctions` / `experimentalLocaleResolutionParam` (used by config resolution) - `I18nCache` lifecycle hooks (`createLifecycleCallbacks`, `LifecycleCallbacks`, `lifecycle` field) - Deprecated option fields (`context` / `$_locales` / `$_source`, cli `maxChars` / `variablesOptions`) that may still be read at runtime for back-compat <!-- codesmith:footer --> --- <a href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1674"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img alt="View with Codesmith" src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a> <a href="https://backend.blacksmith.sh/track/enable-autofix?expires=1785119029&installation_id=127936663&pr_number=1674&repository=generaltranslation%2Fgt&return_to=https%3A%2F%2Fgithub.com%2Fgeneraltranslation%2Fgt%2Fpull%2F1674&signature=23dc09ea52f6cb562ac592f143987364f8b63b6314953604874808046376cc40"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img alt="Autofix with Codesmith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a> <sup>Need help on this PR? Tag <code>/codesmith</code> with what you need. Autofix is disabled.</sup> <!-- codesmith:autofix:disabled --> <!-- /codesmith:footer --> <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR removes deprecated public API symbols from the `generaltranslation` core and `gt-i18n` packages as part of the odysseus major-version cleanup. No logic changes are made — every removed symbol was verified to have zero consumers in the monorepo before deletion. - **core**: Drops deprecated types `_Content`, `Update`, `Request`, `ContentTranslationResult`, `IcuTranslationResult`, and `JsxTranslationResult`, plus the `_Content` re-export from `generaltranslation/internal`. - **gt-i18n**: Removes the `I18nManager` / `getI18nManager` / `setI18nManager` renamed aliases and their type counterparts, deletes the `sync-translation-resolution.ts` and `jsx-resolution.ts` deprecated wrapper files with their barrel exports and test, and updates two JSDoc comments that still referenced the old function name. <details open><summary><h3>Confidence Score: 5/5</h3></summary> Pure dead-code removal with no logic changes; canonical replacements for every removed symbol remain in place and all monorepo consumers have been verified clean. Every deleted symbol was either a thin wrapper that delegated directly to an existing non-deprecated function, or a type alias for an existing type. The underlying implementations (`I18nCache`, `getI18nCache`, `setI18nCache`, `resolveJsx`, `resolveTranslation`, etc.) are untouched. The PR description documents a full monorepo build and test pass (21/21 packages, all test suites green) and a repo-wide grep confirming zero references to any removed symbol. No files require special attention — all changes are deletions of confirmed-dead code. </details> <details><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | packages/core/src/types.ts | Removes six deprecated type definitions (`_Content`, `Update`, `Request`, `ContentTranslationResult`, `IcuTranslationResult`, `JsxTranslationResult`) — pure deletion with no logic change. | | packages/core/src/internal.ts | Drops `_Content` from the type import and the `internal` barrel export; no other changes. | | packages/i18n/src/internal.ts | Removes three deprecated re-exports (`I18nManager`, `getI18nManager`, `setI18nManager`); the underlying `I18nCache`, `getI18nCache`, and `setI18nCache` exports remain untouched. | | packages/i18n/src/internal-types.ts | Removes deprecated type aliases `I18nManagerConstructorParams` and `I18nManagerConfig`; canonical types `I18nCacheConstructorParams` and `I18nCacheConfig` are still exported above. | | packages/i18n/src/translation-functions/internal/sync-translation-resolution.ts | Deleted entirely — contained only `resolveTranslationSync` and `resolveTranslationSyncWithFallback`, both deprecated thin wrappers over `helpers.ts`. | | packages/i18n/src/translation-functions/internal/jsx-resolution.ts | Deleted entirely — contained only `resolveJsxTranslation`, a deprecated one-line wrapper over `resolveJsx`. | | packages/i18n/src/translation-functions/internal/__tests__/resolveTranslationSync.test.ts | Deleted — the four test cases covered `resolveTranslationSync` which no longer exists. | | packages/i18n/src/translation-functions/internal/index.ts | Removes the two barrel re-exports for the deleted `sync-translation-resolution` and `jsx-resolution` modules. | | packages/i18n/src/translation-functions/types/functions.ts | Updates a JSDoc comment to reference `resolveJsx()` instead of the now-deleted `resolveJsxTranslation()`. | | packages/i18n/src/translation-functions/types/options.ts | Updates a JSDoc comment to reference `resolveJsx()` instead of the now-deleted `resolveJsxTranslation()`. | </details> <details><summary><h3>Flowchart</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% flowchart TD subgraph core["generaltranslation (core)"] direction TB A["types.ts\n❌ _Content\n❌ Update\n❌ Request\n❌ ContentTranslationResult\n❌ IcuTranslationResult\n❌ JsxTranslationResult"] B["internal.ts\n❌ re-export _Content"] end subgraph i18n["gt-i18n"] direction TB C["internal.ts\n❌ I18nManager alias\n❌ getI18nManager alias\n❌ setI18nManager alias"] D["internal-types.ts\n❌ I18nManagerConstructorParams alias\n❌ I18nManagerConfig alias"] E["sync-translation-resolution.ts\n❌ resolveTranslationSync\n❌ resolveTranslationSyncWithFallback"] F["jsx-resolution.ts\n❌ resolveJsxTranslation"] G["internal/index.ts\n❌ barrel exports for E & F"] H["__tests__/resolveTranslationSync.test.ts\n❌ deleted test file"] end subgraph keep["Still live (out of scope)"] I18nCache["I18nCache ✅"] getI18nCache["getI18nCache ✅"] setI18nCache["setI18nCache ✅"] resolveJsx["resolveJsx ✅"] resolveTranslation["resolveTranslation ✅"] end E --> G F --> G ``` </a> <a href="#gh-dark-mode-only"> ```mermaid %%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% flowchart TD subgraph core["generaltranslation (core)"] direction TB A["types.ts\n❌ _Content\n❌ Update\n❌ Request\n❌ ContentTranslationResult\n❌ IcuTranslationResult\n❌ JsxTranslationResult"] B["internal.ts\n❌ re-export _Content"] end subgraph i18n["gt-i18n"] direction TB C["internal.ts\n❌ I18nManager alias\n❌ getI18nManager alias\n❌ setI18nManager alias"] D["internal-types.ts\n❌ I18nManagerConstructorParams alias\n❌ I18nManagerConfig alias"] E["sync-translation-resolution.ts\n❌ resolveTranslationSync\n❌ resolveTranslationSyncWithFallback"] F["jsx-resolution.ts\n❌ resolveJsxTranslation"] G["internal/index.ts\n❌ barrel exports for E & F"] H["__tests__/resolveTranslationSync.test.ts\n❌ deleted test file"] end subgraph keep["Still live (out of scope)"] I18nCache["I18nCache ✅"] getI18nCache["getI18nCache ✅"] setI18nCache["setI18nCache ✅"] resolveJsx["resolveJsx ✅"] resolveTranslation["resolveTranslation ✅"] end E --> G F --> G ``` </a> </details> <sub>Reviews (1): Last reviewed commit: ["refactor: remove dead @deprecated public..."](800d6e6) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=40241227)</sub> <!-- /greptile_comment -->
## Summary - pass `cacheExpiryTime: null` when initializing client-side i18n caches in gt-react - route gt-next browser/client-boundary initialization through a client initializer that disables cache expiry ## Testing - `pnpm --filter gt-react... build` - `pnpm --filter gt-next typecheck` - `pnpm --filter gt-react test` - `pnpm --filter gt-next test:js` - `pnpm lint` Note: `pnpm --filter gt-react typecheck` is still blocked by the existing `ImportMeta.env` typing issue in `BrowserI18nCache.ts`. <!-- codesmith:footer --> --- <a href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1685"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img alt="View with Codesmith" src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a> <a href="https://backend.blacksmith.sh/track/enable-autofix?expires=1785345577&installation_id=127936663&pr_number=1685&repository=generaltranslation%2Fgt&return_to=https%3A%2F%2Fgithub.com%2Fgeneraltranslation%2Fgt%2Fpull%2F1685&signature=5f4723f456084250913d0be547530fa50d6718fc9d3e22a2b2430b5b15ae684e"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img alt="Autofix with Codesmith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a> <sup>Need help on this PR? Tag <code>/codesmith</code> with what you need. Autofix is disabled.</sup> <!-- codesmith:autofix:disabled --> <!-- /codesmith:footer --> <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR disables client-side i18n cache expiry in both `gt-react` and `gt-next` by introducing thin wrapper initializers that force `cacheExpiryTime: null` on every client-side cache construction, preventing translations from being evicted while the browser session is alive. - **`gt-react`**: A new `initializeGTClient.ts` wraps `internalInitializeGTSRA` with `cacheExpiryTime: null`, and `initializeGTSPA.ts` is updated to pass the same override to `BrowserI18nCache`. The public `initializeGT` export from `gt-react`'s client barrel now points to this new wrapper instead of re-exporting from `@generaltranslation/react-core/pure`. - **`gt-next`**: A new `initGT.client.ts` wrapper calls `getParams()` and forwards the params to the core initializer with `nextI18nCacheParams.cacheExpiryTime` overridden to `null`. Both `index.client.ts` and `client-boundary.tsx` are updated to import from this new client-specific module. <details open><summary><h3>Confidence Score: 5/5</h3></summary> Safe to merge — the changes are small, mechanically consistent wrappers that apply a single override (cacheExpiryTime: null) to every client-side cache initialisation path. All six changed files follow the same straightforward pattern: introduce a thin wrapper or change an import to route through a wrapper that forces cacheExpiryTime to null. No new logic branches, no altered data flow outside the cache, and the full test suite is reported green by the author. No files require special attention. The pre-existing ImportMeta.env typing issue in BrowserI18nCache.ts (blocking gt-react typecheck) is explicitly acknowledged in the PR description and is unrelated to these changes. </details> <details><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | packages/next/src/setup/initGT.client.ts | New wrapper that reads params via getParams() and forwards them to the core initializer with cacheExpiryTime forced to null; logic is correct and TypeScript-clean (gt-next typecheck passes). | | packages/next/src/index.client.ts | One-line import path change from initGT to initGT.client; straightforward and correct. | | packages/next/src/utils/client-boundary.tsx | Import path updated to use the new client-specific initializer so the boundary component now benefits from disabled cache expiry. | | packages/react/src/setup/initializeGTClient.ts | New thin wrapper that hardcodes cacheExpiryTime: null on top of any caller-supplied config before delegating to internalInitializeGTSRA; correctly typed and appropriately scoped. | | packages/react/src/index.client.ts | Swaps the initializeGT re-export from the react-core/pure barrel to the new initializeGTClient wrapper, ensuring all gt-react consumers get cache-expiry-disabled behaviour by default. | | packages/react/src/setup/initializeGTSPA.ts | SPA initializer now passes cacheExpiryTime: null when constructing BrowserI18nCache, consistent with the broader client-side cache expiry fix. | </details> <details><summary><h3>Sequence Diagram</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% sequenceDiagram participant CI as Client Entry (index.client.ts) participant CB as ClientBoundary (client-boundary.tsx) participant GTC as initGT.client.ts (new) participant GT as initGT.ts (core) participant NIC as NextI18nCache Note over CI,NIC: gt-next client initialization (after PR) CI->>GTC: initializeGT() CB->>GTC: initializeGT() GTC->>GTC: getParams() GTC->>GT: coreInitializeGT with cacheExpiryTime null GT->>NIC: new NextI18nCache(nextI18nCacheParams) Note right of NIC: cacheExpiryTime = null, no expiry participant GTCR as initializeGTClient.ts (new) participant SRA as internalInitializeGTSRA participant GSPA as initializeGTSPA.ts participant BIC as BrowserI18nCache Note over CI,BIC: gt-react client initialization (after PR) CI->>GTCR: initializeGT(config) GTCR->>SRA: internalInitializeGTSRA with cacheExpiryTime null Note right of SRA: cacheExpiryTime = null, no expiry CI->>GSPA: initializeGTSPA(config) GSPA->>BIC: new BrowserI18nCache with cacheExpiryTime null Note right of BIC: cacheExpiryTime = null, no expiry ``` </a> <a href="#gh-dark-mode-only"> ```mermaid %%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant CI as Client Entry (index.client.ts) participant CB as ClientBoundary (client-boundary.tsx) participant GTC as initGT.client.ts (new) participant GT as initGT.ts (core) participant NIC as NextI18nCache Note over CI,NIC: gt-next client initialization (after PR) CI->>GTC: initializeGT() CB->>GTC: initializeGT() GTC->>GTC: getParams() GTC->>GT: coreInitializeGT with cacheExpiryTime null GT->>NIC: new NextI18nCache(nextI18nCacheParams) Note right of NIC: cacheExpiryTime = null, no expiry participant GTCR as initializeGTClient.ts (new) participant SRA as internalInitializeGTSRA participant GSPA as initializeGTSPA.ts participant BIC as BrowserI18nCache Note over CI,BIC: gt-react client initialization (after PR) CI->>GTCR: initializeGT(config) GTCR->>SRA: internalInitializeGTSRA with cacheExpiryTime null Note right of SRA: cacheExpiryTime = null, no expiry CI->>GSPA: initializeGTSPA(config) GSPA->>BIC: new BrowserI18nCache with cacheExpiryTime null Note right of BIC: cacheExpiryTime = null, no expiry ``` </a> </details> <sub>Reviews (1): Last reviewed commit: ["fix: disable client i18n cache expiry"](61df180) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=40581150)</sub> <!-- /greptile_comment -->
## Summary Removes deprecated translation options from `gt-i18n` as part of the Odysseus major-version cleanup: - **`context` dictionary option** → use `$context`. Removed from `DictionaryOptions`, plus the fallback mapping in `resolveDictionaryLookupOptions` and the validation branch in `isDictionaryOptions`. - **`$_locales` inline option** → use `$locale`. Removed from `InlineTranslationOptionsFields`, the `$locale ?? $_locales` fallbacks in ICU/string interpolation, and the exclusion list in `extractVariables`. ## Stale comment/doc cleanup These reference the same options and were updated for consistency (no behavior change): - `next/swc-plugin` comments now reference `$id`/`$context`/`$maxChars`. - `@generaltranslation/compiler` `StringCollector` — `TranslationContent` (extracted from `t()` calls) comments now use `$`-prefixed keys. The parser already reads `$context`/`$id`/`$maxChars`. - `next` `tx()` JSDoc corrected to the actual `TxOptions` shape (`$locale`/`$context`/`$maxChars`), and the `variables`/`variableOptions` docs fixed to flat top-level variables (`TxOptions extends FormatVariables`). Left intentionally bare (not the i18n message-options form): - JSX-prop `context` (`<T context="...">`, `TranslationJsx`). - Backend translation-API request metadata `context` (`gt.translate` / `EntryMetadata`). ## Testing - `pnpm --filter gt-i18n test` → 244/244 passing. A changeset (`gt-i18n` major) is included documenting the breaking removal. <!-- codesmith:footer --> --- <a href="https://app.blacksmith.sh/generaltranslation/codesmith/gt/pr/1687"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img alt="View with Codesmith" src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a> <a href="https://backend.blacksmith.sh/track/enable-autofix?expires=1785348313&installation_id=127936663&pr_number=1687&repository=generaltranslation%2Fgt&return_to=https%3A%2F%2Fgithub.com%2Fgeneraltranslation%2Fgt%2Fpull%2F1687&signature=ec3064c77242644ba9591dbed52aea3eadf4e7bb487ad4ed311b65d1c215e3c7"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img alt="Autofix with Codesmith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a> <sup>Need help on this PR? Tag <code>/codesmith</code> with what you need. Autofix is disabled.</sup> <!-- codesmith:autofix:disabled --> <!-- /codesmith:footer --> <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR removes two deprecated translation options from `gt-i18n` as part of the Odysseus major-version cleanup: the `context` dictionary key (replaced by `$context`) and the `$_locales` inline option (replaced by `$locale`). Comment and JSDoc updates in `next/tx.ts`, the SWC plugin, and `@generaltranslation/compiler` are also included to align documentation with the already-live `$`-prefixed API. - **`context` removal**: `DictionaryOptions` no longer carries `context`; `resolveDictionaryLookupOptions` no longer maps `context → $context`; `isDictionaryOptions` no longer validates the `context` string field. JS callers that still pass `context:` after upgrading will have it leak as an unknown key (and potentially a template variable) rather than being silently dropped — a silent regression for un-migrated users, but intentional at a major version boundary. - **`$_locales` removal**: Dropped from `InlineTranslationOptionsFields`, both interpolation fallbacks, and the `extractVariables` exclusion list. Any un-migrated JS caller passing `$_locales` will now have that key treated as a user-defined template variable instead of being ignored. - All 244 tests pass; a major-version changeset is included. <details open><summary><h3>Confidence Score: 4/5</h3></summary> Safe to merge for the Odysseus major version — all breaking removals are intentional and the test suite passes cleanly. The changes are a straightforward deprecation removal with 244 passing tests. The one subtlety worth noting is that un-migrated JS callers passing the old `context:` key will now have that value leak through `resolveDictionaryLookupOptions` as part of `rest` rather than being explicitly stripped. This means `context` could surface as a template variable name in messages that happen to contain a `{context}` placeholder — a quiet behavioral change rather than a hard error. The same applies to `$_locales` no longer being excluded from `extractVariables`. Both are expected consequences of a major-version break, but neither has a dedicated migration-path test to document the new runtime behavior for un-migrated callers. `packages/i18n/src/i18n-cache/translations-manager/utils/dictionary-helpers.ts` — the `resolveDictionaryLookupOptions` change silently changes how old `context:` keys are handled at runtime. </details> <details><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | packages/i18n/src/i18n-cache/translations-manager/utils/dictionary-helpers.ts | Removes deprecated `context`→`$context` mapping in `resolveDictionaryLookupOptions` and the `context` string validation in `isDictionaryOptions`. Old JS callers passing `context:` will now have it leak into `rest` as an unknown key instead of being silently dropped or mapped. | | packages/i18n/src/translation-functions/types/options.ts | Removes deprecated `context` from `DictionaryOptions` and `$_locales` from `InlineTranslationOptionsFields`. Clean type-level enforcement of the new API surface. | | packages/i18n/src/utils/extractVariables.ts | Removes `$_locales` from the GT-reserved key exclusion list. Any caller (JS runtime) still passing `$_locales` will now have that key treated as a user template variable rather than silently dropped. | | packages/i18n/src/translation-functions/utils/interpolation/interpolateIcuMessage.ts | Drops `$_locales` fallback from locale resolution — `options.$locale` is now the only locale source passed to the ICU formatter. | | packages/next/src/server-dir/runtime/tx.ts | JSDoc corrected to the actual `TxOptions` shape (`$locale`, `$context`, `$maxChars`) and variable interpolation docs updated to reflect flat top-level key passing. No logic changes. | | packages/compiler/src/state/StringCollector.ts | JSDoc comments updated to use `$id`/`$context`/`$maxChars` in examples — no logic change. | | .changeset/remove-deprecated-context-locales-options.md | Major-version changeset for `gt-i18n` documenting both breaking removals clearly. | </details> <details><summary><h3>Flowchart</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% flowchart TD A["Dictionary entry\n['Hello', options]"] --> B{isDictionaryOptions?} B -- "pass" --> C[resolveDictionaryLookupOptions] C --> D["Destructure: { $format, ...rest }"] D --> E["Return: { ...rest, $format: ICU }"] E --> F{context key present\nin old JS dict?} F -- "yes (un-migrated)" --> G["context leaks into rest\n→ treated as template variable"] F -- "no" --> H["Clean lookup options\n$context/$format/$maxChars"] I["Inline call: gt(msg, options)"] --> J[extractVariables] J --> K{$_locales in options?} K -- "yes (un-migrated)" --> L["Included as template variable\n(no longer filtered)"] K -- "no" --> M["Only user variables returned"] N["interpolateIcuMessage / interpolateStringMessage"] --> O["options.$locale\n(no $_locales fallback)"] ``` </a> <a href="#gh-dark-mode-only"> ```mermaid %%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% flowchart TD A["Dictionary entry\n['Hello', options]"] --> B{isDictionaryOptions?} B -- "pass" --> C[resolveDictionaryLookupOptions] C --> D["Destructure: { $format, ...rest }"] D --> E["Return: { ...rest, $format: ICU }"] E --> F{context key present\nin old JS dict?} F -- "yes (un-migrated)" --> G["context leaks into rest\n→ treated as template variable"] F -- "no" --> H["Clean lookup options\n$context/$format/$maxChars"] I["Inline call: gt(msg, options)"] --> J[extractVariables] J --> K{$_locales in options?} K -- "yes (un-migrated)" --> L["Included as template variable\n(no longer filtered)"] K -- "no" --> M["Only user variables returned"] N["interpolateIcuMessage / interpolateStringMessage"] --> O["options.$locale\n(no $_locales fallback)"] ``` </a> </details> <!-- greptile_failed_comments --> <details open><summary><h3>Comments Outside Diff (1)</h3></summary> 1. `packages/i18n/src/utils/extractVariables.ts`, line 14-24 ([link](https://github.com/generaltranslation/gt/blob/ffc7be81dd257454414f23decdb048dae185ab83/packages/i18n/src/utils/extractVariables.ts#L14-L24)) <a href="#"><img alt="P2" src="https://greptile-static-assets.s3.amazonaws.com/badges/p2.svg?v=9" align="top"></a> **`$_locales` no longer filtered — becomes a live template variable** `$_locales` was previously excluded from `extractVariables` so it could never accidentally appear as an interpolation variable. After this removal, any un-migrated JS caller that still passes `$_locales` will have it treated as a user-defined placeholder. If the message string contains `{$_locales}` (unlikely but possible), it would be interpolated with the locale value instead of raising a missing-variable error. This is consistent with the broader deprecation removal, but unlike the `$locale` key (which remains excluded), there is no longer any guard that prevents the old key from leaking into rendered output. <details><summary>Prompt To Fix With AI</summary> `````markdown This is a comment left during a code review. Path: packages/i18n/src/utils/extractVariables.ts Line: 14-24 Comment: **`$_locales` no longer filtered — becomes a live template variable** `$_locales` was previously excluded from `extractVariables` so it could never accidentally appear as an interpolation variable. After this removal, any un-migrated JS caller that still passes `$_locales` will have it treated as a user-defined placeholder. If the message string contains `{$_locales}` (unlikely but possible), it would be interpolated with the locale value instead of raising a missing-variable error. This is consistent with the broader deprecation removal, but unlike the `$locale` key (which remains excluded), there is no longer any guard that prevents the old key from leaking into rendered output. How can I resolve this? If you propose a fix, please make it concise. ````` </details> <a href="https://app.greptile.com/ide/claude-code?prompt=This%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20packages%2Fi18n%2Fsrc%2Futils%2FextractVariables.ts%0ALine%3A%2014-24%0A%0AComment%3A%0A**%60%24_locales%60%20no%20longer%20filtered%20%E2%80%94%20becomes%20a%20live%20template%20variable**%0A%0A%60%24_locales%60%20was%20previously%20excluded%20from%20%60extractVariables%60%20so%20it%20could%20never%20accidentally%20appear%20as%20an%20interpolation%20variable.%20After%20this%20removal%2C%20any%20un-migrated%20JS%20caller%20that%20still%20passes%20%60%24_locales%60%20will%20have%20it%20treated%20as%20a%20user-defined%20placeholder.%20If%20the%20message%20string%20contains%20%60%7B%24_locales%7D%60%20%28unlikely%20but%20possible%29%2C%20it%20would%20be%20interpolated%20with%20the%20locale%20value%20instead%20of%20raising%20a%20missing-variable%20error.%20This%20is%20consistent%20with%20the%20broader%20deprecation%20removal%2C%20but%20unlike%20the%20%60%24locale%60%20key%20%28which%20remains%20excluded%29%2C%20there%20is%20no%20longer%20any%20guard%20that%20prevents%20the%20old%20key%20from%20leaking%20into%20rendered%20output.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=generaltranslation%2Fgt&pr=1687&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaudeDark.svg?v=3"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=3"><img alt="Fix in Claude Code" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=3" height="20"></picture></a> <a href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22generaltranslation%2Fgt%22%20on%20the%20existing%20branch%20%22refactor%2Fremove-deprecated-i18n-options%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22refactor%2Fremove-deprecated-i18n-options%22.%0A%0AThis%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20packages%2Fi18n%2Fsrc%2Futils%2FextractVariables.ts%0ALine%3A%2014-24%0A%0AComment%3A%0A**%60%24_locales%60%20no%20longer%20filtered%20%E2%80%94%20becomes%20a%20live%20template%20variable**%0A%0A%60%24_locales%60%20was%20previously%20excluded%20from%20%60extractVariables%60%20so%20it%20could%20never%20accidentally%20appear%20as%20an%20interpolation%20variable.%20After%20this%20removal%2C%20any%20un-migrated%20JS%20caller%20that%20still%20passes%20%60%24_locales%60%20will%20have%20it%20treated%20as%20a%20user-defined%20placeholder.%20If%20the%20message%20string%20contains%20%60%7B%24_locales%7D%60%20%28unlikely%20but%20possible%29%2C%20it%20would%20be%20interpolated%20with%20the%20locale%20value%20instead%20of%20raising%20a%20missing-variable%20error.%20This%20is%20consistent%20with%20the%20broader%20deprecation%20removal%2C%20but%20unlike%20the%20%60%24locale%60%20key%20%28which%20remains%20excluded%29%2C%20there%20is%20no%20longer%20any%20guard%20that%20prevents%20the%20old%20key%20from%20leaking%20into%20rendered%20output.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=generaltranslation%2Fgt&pr=1687&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodexDark.svg?v=3"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=3"><img alt="Fix in Codex" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=3" height="20"></picture></a> </details> <!-- /greptile_failed_comments --> <a href="https://app.greptile.com/ide/claude-code?prompt=Fix%20the%20following%202%20code%20review%20issues.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%202%0Apackages%2Fi18n%2Fsrc%2Fi18n-cache%2Ftranslations-manager%2Futils%2Fdictionary-helpers.ts%3A116-124%0A**Old%20%60context%60%20key%20now%20leaks%20into%20lookup%20options**%0A%0APreviously%2C%20%60context%60%20was%20explicitly%20destructured%20out%20of%20%60options%60%20before%20the%20spread%2C%20so%20it%20was%20always%20stripped%20from%20the%20returned%20object.%20After%20this%20change%2C%20any%20object%20that%20still%20carries%20a%20%60context%60%20property%20%28e.g.%20a%20JS%20dictionary%20written%20before%20the%20migration%29%20will%20have%20%60context%60%20included%20in%20%60rest%60%20and%20therefore%20spread%20verbatim%20into%20the%20%60DictionaryLookupOptions%60%20result.%20Downstream%20consumers%20that%20treat%20unknown%20keys%20as%20template%20variables%20will%20then%20expose%20%60context%60%20as%20an%20interpolation%20variable%20%E2%80%94%20if%20the%20message%20contains%20%60%7Bcontext%7D%60%2C%20it%20would%20be%20silently%20filled%20with%20the%20old%20metadata%20string%20rather%20than%20surfacing%20an%20error.%20A%20one-liner%20%60const%20%7B%20%24format%2C%20context%3A%20_context%2C%20...rest%20%7D%20%3D%20options%3B%60%20would%20preserve%20the%20old%20strip-and-discard%20behavior%20without%20resurrecting%20the%20compatibility%20mapping.%0A%0A%23%23%23%20Issue%202%20of%202%0Apackages%2Fi18n%2Fsrc%2Futils%2FextractVariables.ts%3A14-24%0A**%60%24_locales%60%20no%20longer%20filtered%20%E2%80%94%20becomes%20a%20live%20template%20variable**%0A%0A%60%24_locales%60%20was%20previously%20excluded%20from%20%60extractVariables%60%20so%20it%20could%20never%20accidentally%20appear%20as%20an%20interpolation%20variable.%20After%20this%20removal%2C%20any%20un-migrated%20JS%20caller%20that%20still%20passes%20%60%24_locales%60%20will%20have%20it%20treated%20as%20a%20user-defined%20placeholder.%20If%20the%20message%20string%20contains%20%60%7B%24_locales%7D%60%20%28unlikely%20but%20possible%29%2C%20it%20would%20be%20interpolated%20with%20the%20locale%20value%20instead%20of%20raising%20a%20missing-variable%20error.%20This%20is%20consistent%20with%20the%20broader%20deprecation%20removal%2C%20but%20unlike%20the%20%60%24locale%60%20key%20%28which%20remains%20excluded%29%2C%20there%20is%20no%20longer%20any%20guard%20that%20prevents%20the%20old%20key%20from%20leaking%20into%20rendered%20output.%0A%0A&repo=generaltranslation%2Fgt&pr=1687&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaudeDark.svg?v=3"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=3"><img alt="Fix All in Claude Code" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=3" height="20"></picture></a> <a href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22generaltranslation%2Fgt%22%20on%20the%20existing%20branch%20%22refactor%2Fremove-deprecated-i18n-options%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22refactor%2Fremove-deprecated-i18n-options%22.%0A%0AFix%20the%20following%202%20code%20review%20issues.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%202%0Apackages%2Fi18n%2Fsrc%2Fi18n-cache%2Ftranslations-manager%2Futils%2Fdictionary-helpers.ts%3A116-124%0A**Old%20%60context%60%20key%20now%20leaks%20into%20lookup%20options**%0A%0APreviously%2C%20%60context%60%20was%20explicitly%20destructured%20out%20of%20%60options%60%20before%20the%20spread%2C%20so%20it%20was%20always%20stripped%20from%20the%20returned%20object.%20After%20this%20change%2C%20any%20object%20that%20still%20carries%20a%20%60context%60%20property%20%28e.g.%20a%20JS%20dictionary%20written%20before%20the%20migration%29%20will%20have%20%60context%60%20included%20in%20%60rest%60%20and%20therefore%20spread%20verbatim%20into%20the%20%60DictionaryLookupOptions%60%20result.%20Downstream%20consumers%20that%20treat%20unknown%20keys%20as%20template%20variables%20will%20then%20expose%20%60context%60%20as%20an%20interpolation%20variable%20%E2%80%94%20if%20the%20message%20contains%20%60%7Bcontext%7D%60%2C%20it%20would%20be%20silently%20filled%20with%20the%20old%20metadata%20string%20rather%20than%20surfacing%20an%20error.%20A%20one-liner%20%60const%20%7B%20%24format%2C%20context%3A%20_context%2C%20...rest%20%7D%20%3D%20options%3B%60%20would%20preserve%20the%20old%20strip-and-discard%20behavior%20without%20resurrecting%20the%20compatibility%20mapping.%0A%0A%23%23%23%20Issue%202%20of%202%0Apackages%2Fi18n%2Fsrc%2Futils%2FextractVariables.ts%3A14-24%0A**%60%24_locales%60%20no%20longer%20filtered%20%E2%80%94%20becomes%20a%20live%20template%20variable**%0A%0A%60%24_locales%60%20was%20previously%20excluded%20from%20%60extractVariables%60%20so%20it%20could%20never%20accidentally%20appear%20as%20an%20interpolation%20variable.%20After%20this%20removal%2C%20any%20un-migrated%20JS%20caller%20that%20still%20passes%20%60%24_locales%60%20will%20have%20it%20treated%20as%20a%20user-defined%20placeholder.%20If%20the%20message%20string%20contains%20%60%7B%24_locales%7D%60%20%28unlikely%20but%20possible%29%2C%20it%20would%20be%20interpolated%20with%20the%20locale%20value%20instead%20of%20raising%20a%20missing-variable%20error.%20This%20is%20consistent%20with%20the%20broader%20deprecation%20removal%2C%20but%20unlike%20the%20%60%24locale%60%20key%20%28which%20remains%20excluded%29%2C%20there%20is%20no%20longer%20any%20guard%20that%20prevents%20the%20old%20key%20from%20leaking%20into%20rendered%20output.%0A%0A&repo=generaltranslation%2Fgt&pr=1687&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=3"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=3"><img alt="Fix All in Codex" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=3" height="20"></picture></a> <details><summary>Prompt To Fix All With AI</summary> `````markdown Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes. --- ### Issue 1 of 2 packages/i18n/src/i18n-cache/translations-manager/utils/dictionary-helpers.ts:116-124 **Old `context` key now leaks into lookup options** Previously, `context` was explicitly destructured out of `options` before the spread, so it was always stripped from the returned object. After this change, any object that still carries a `context` property (e.g. a JS dictionary written before the migration) will have `context` included in `rest` and therefore spread verbatim into the `DictionaryLookupOptions` result. Downstream consumers that treat unknown keys as template variables will then expose `context` as an interpolation variable — if the message contains `{context}`, it would be silently filled with the old metadata string rather than surfacing an error. A one-liner `const { $format, context: _context, ...rest } = options;` would preserve the old strip-and-discard behavior without resurrecting the compatibility mapping. ### Issue 2 of 2 packages/i18n/src/utils/extractVariables.ts:14-24 **`$_locales` no longer filtered — becomes a live template variable** `$_locales` was previously excluded from `extractVariables` so it could never accidentally appear as an interpolation variable. After this removal, any un-migrated JS caller that still passes `$_locales` will have it treated as a user-defined placeholder. If the message string contains `{$_locales}` (unlikely but possible), it would be interpolated with the locale value instead of raising a missing-variable error. This is consistent with the broader deprecation removal, but unlike the `$locale` key (which remains excluded), there is no longer any guard that prevents the old key from leaking into rendered output. ````` </details> <sub>Reviews (1): Last reviewed commit: ["fix: format issue"](ffc7be8) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=40596073)</sub> > Greptile also left **1 inline comment** on this PR. <!-- /greptile_comment -->
## Summary
`gt-next` was published **CJS-only** (no `import` export condition).
Because the app entry imports `gt-next`, bundlers resolved the whole gt
dependency graph — `gt-react`, `@generaltranslation/react-core`,
`generaltranslation`, `gt-i18n`, `@generaltranslation/format` — through
the `require` condition, pulling CJS variants onto the client. CJS can't
be tree-shaken, so the browser received `gt-next`'s own server/error
code (e.g. ~11 kB of `createErrors` diagnostic strings) plus unused
exports from every dependency.
This PR gives `gt-next` a **dual ESM/CJS build**: it now emits unbundled
`.mjs` alongside `.js`, and every `exports` subpath gains an `import`
condition (preserving `react-server`/`browser`/`default` ordering).
Bundlers now resolve the gt graph as ESM, enabling tree-shaking across
all gt packages.
No public API changes — purely packaging.
## Measured impact
Built a real Next.js app (Turbopack) against these packages and
attributed bundle bytes per module via `next experimental-analyze`. gt's
**client** footprint (deduped across routes):
| | gt total raw | gt total gz |
|---|---|---|
| before (CJS) | 304.9 kB | 96.0 kB |
| after (ESM) | 236.0 kB | **73.9 kB (−23%)** |
`gt-next`'s own client code drops to **0** (including the leaked error
strings); `generaltranslation`, `gt-i18n`, and `gt-react` each shed
their dead exports.
## Notes
- This is the first of two related changes. A follow-up PR will unbundle
`@generaltranslation/react-core` so its `pure`/`components` entries can
also tree-shake — that change reverses an existing "independent
entrypoints" guard and is being reviewed separately. Layered on this PR
it takes the combined reduction to ~40% gz.
- Mirrors the dual-format setup already used by `gt-react`
(`createUseClientBoundaryPlugin` with `.js`/`.mjs` output extensions).
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR gives `gt-next` a dual ESM/CJS build by adding a second tsdown
pass that emits `.mjs` files and wiring every `exports` subpath with an
`import` condition, enabling tree-shaking across the entire gt
dependency graph for downstream bundlers. No public API changes are
made.
- **tsdown config**: A second `createTsdownUnbundleConfig` block is
added with `format: 'esm'`, `clean: false` (to preserve the CJS output),
`outExtensions` mapping to `.mjs`, and `polyfillRequire: false` to
suppress the `createRequire`-from-`node:module` shim that would break
client bundlers (Turbopack/webpack) reachable from ESM init paths.
- **package.json exports**: All subpath exports gain a flat `import`
condition; the root `.` entry nests `import`/`default` inside
`react-server` and `browser` conditions, preserving correct environment
routing.
- **sideEffects**: `index.rsc.*`, `index.client.*`, and
`utils/client-boundary.*` are added to the `sideEffects` list so their
top-level initialization is not eliminated by tree-shaking.
<details open><summary><h3>Confidence Score: 5/5</h3></summary>
Pure packaging change — no runtime logic altered, no API surface
changed, and the dual-build pattern mirrors what gt-react already uses.
All three changed files touch only build configuration and the exports
map. The ESM build is additive (clean: false preserves the CJS
artifacts), polyfillRequire: false is a well-motivated guard against a
concrete Turbopack/webpack breakage, and the sideEffects expansion
correctly covers the newly ESM-exposed init files. TypeScript type
resolution falls back correctly to the CJS .d.ts files when .d.mts
counterparts are absent.
No files require special attention.
</details>
<details><summary><h3>Important Files Changed</h3></summary>
| Filename | Overview |
|----------|----------|
| .changeset/gt-next-esm-build.md | Changeset documenting the ESM/CJS
dual build for gt-next; numbers in changeset (~78 kB) differ slightly
from the PR description table (73.9 kB) but this is not a code concern.
|
| packages/next/package.json | Adds `import` conditions to all subpath
exports pointing to .mjs files; correctly expands sideEffects to cover
index.rsc.* and index.client.* (needed for top-level init); top-level
types ordering looks correct; missing legacy "module" field compared to
gt-react (P2, already noted in a prior review). |
| packages/next/tsdown.config.mts | Adds a second ESM build pass (clean:
false to preserve CJS output, polyfillRequire: false to avoid injecting
a node:module shim, .mjs output extension); mirrors the dual-build
pattern used by gt-react. |
</details>
<details><summary><h3>Flowchart</h3></summary>
<a href="#gh-light-mode-only">
```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["Bundler imports gt-next"] --> B{Condition check}
B -->|react-server| C{import condition?}
C -->|ESM / import| D["index.rsc.mjs ✅ tree-shakeable"]
C -->|CJS / default| E["index.rsc.js"]
B -->|browser| F{import condition?}
F -->|ESM / import| G["index.client.mjs ✅ tree-shakeable"]
F -->|CJS / default| H["index.client.js"]
B -->|server/default| I{import condition?}
I -->|ESM / import| J["index.server.mjs ✅ tree-shakeable"]
I -->|CJS / default| K["index.server.js"]
B -->|TypeScript| L["index.types.d.ts"]
```
</a>
<a href="#gh-dark-mode-only">
```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A["Bundler imports gt-next"] --> B{Condition check}
B -->|react-server| C{import condition?}
C -->|ESM / import| D["index.rsc.mjs ✅ tree-shakeable"]
C -->|CJS / default| E["index.rsc.js"]
B -->|browser| F{import condition?}
F -->|ESM / import| G["index.client.mjs ✅ tree-shakeable"]
F -->|CJS / default| H["index.client.js"]
B -->|server/default| I{import condition?}
I -->|ESM / import| J["index.server.mjs ✅ tree-shakeable"]
I -->|CJS / default| K["index.server.js"]
B -->|TypeScript| L["index.types.d.ts"]
```
</a>
</details>
<!-- greptile_failed_comments -->
<details open><summary><h3>Comments Outside Diff (1)</h3></summary>
1. `packages/next/package.json`, line 5
([link](https://github.com/generaltranslation/gt/blob/b0b44e681408927a7cc45f1ca0a5a1434c1f603a/packages/next/package.json#L5))
<a href="#"><img alt="P2"
src="https://greptile-static-assets.s3.amazonaws.com/badges/p2.svg?v=9"
align="top"></a> The `"module"` legacy field is present in `gt-react`
(`"module": "./dist/index.server.mjs"`) but absent from `gt-next`.
Webpack 4 and other bundlers that predate the `"exports"` field use
`"module"` as their ESM signal; without it they fall back to `"main"`
(the CJS variant) and the tree-shaking gains won't materialise in those
environments. Since `gt-next` is Next.js-specific and Next.js itself
uses Webpack 5/Turbopack (both `"exports"`-aware), the practical impact
is low — but adding the field would keep the two packages consistent.
<details><summary>Prompt To Fix With AI</summary>
`````markdown
This is a comment left during a code review.
Path: packages/next/package.json
Line: 5
Comment:
The `"module"` legacy field is present in `gt-react` (`"module":
"./dist/index.server.mjs"`) but absent from `gt-next`. Webpack 4 and
other bundlers that predate the `"exports"` field use `"module"` as
their ESM signal; without it they fall back to `"main"` (the CJS
variant) and the tree-shaking gains won't materialise in those
environments. Since `gt-next` is Next.js-specific and Next.js itself
uses Webpack 5/Turbopack (both `"exports"`-aware), the practical impact
is low — but adding the field would keep the two packages consistent.
How can I resolve this? If you propose a fix, please make it concise.
`````
</details>
Note: If this suggestion doesn't match your team's coding style, reply
to this and let me know. I'll remember it for next time!
<a
href="https://app.greptile.com/ide/claude-code?prompt=This%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20packages%2Fnext%2Fpackage.json%0ALine%3A%205%0A%0AComment%3A%0AThe%20%60%22module%22%60%20legacy%20field%20is%20present%20in%20%60gt-react%60%20%28%60%22module%22%3A%20%22.%2Fdist%2Findex.server.mjs%22%60%29%20but%20absent%20from%20%60gt-next%60.%20Webpack%204%20and%20other%20bundlers%20that%20predate%20the%20%60%22exports%22%60%20field%20use%20%60%22module%22%60%20as%20their%20ESM%20signal%3B%20without%20it%20they%20fall%20back%20to%20%60%22main%22%60%20%28the%20CJS%20variant%29%20and%20the%20tree-shaking%20gains%20won't%20materialise%20in%20those%20environments.%20Since%20%60gt-next%60%20is%20Next.js-specific%20and%20Next.js%20itself%20uses%20Webpack%205%2FTurbopack%20%28both%20%60%22exports%22%60-aware%29%2C%20the%20practical%20impact%20is%20low%20%E2%80%94%20but%20adding%20the%20field%20would%20keep%20the%20two%20packages%20consistent.%0A%0A%60%60%60suggestion%0A%20%20%22main%22%3A%20%22dist%2Findex.server.js%22%2C%0A%20%20%22module%22%3A%20%22dist%2Findex.server.mjs%22%2C%0A%60%60%60%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=generaltranslation%2Fgt&pr=1688&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaudeDark.svg?v=3"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=3"><img
alt="Fix in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=3"
height="20"></picture></a> <a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22generaltranslation%2Fgt%22%20on%20the%20existing%20branch%20%22bg%2Fodysseus-gt-next-esm%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22bg%2Fodysseus-gt-next-esm%22.%0A%0AThis%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20packages%2Fnext%2Fpackage.json%0ALine%3A%205%0A%0AComment%3A%0AThe%20%60%22module%22%60%20legacy%20field%20is%20present%20in%20%60gt-react%60%20%28%60%22module%22%3A%20%22.%2Fdist%2Findex.server.mjs%22%60%29%20but%20absent%20from%20%60gt-next%60.%20Webpack%204%20and%20other%20bundlers%20that%20predate%20the%20%60%22exports%22%60%20field%20use%20%60%22module%22%60%20as%20their%20ESM%20signal%3B%20without%20it%20they%20fall%20back%20to%20%60%22main%22%60%20%28the%20CJS%20variant%29%20and%20the%20tree-shaking%20gains%20won't%20materialise%20in%20those%20environments.%20Since%20%60gt-next%60%20is%20Next.js-specific%20and%20Next.js%20itself%20uses%20Webpack%205%2FTurbopack%20%28both%20%60%22exports%22%60-aware%29%2C%20the%20practical%20impact%20is%20low%20%E2%80%94%20but%20adding%20the%20field%20would%20keep%20the%20two%20packages%20consistent.%0A%0A%60%60%60suggestion%0A%20%20%22main%22%3A%20%22dist%2Findex.server.js%22%2C%0A%20%20%22module%22%3A%20%22dist%2Findex.server.mjs%22%2C%0A%60%60%60%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=generaltranslation%2Fgt&pr=1688&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodexDark.svg?v=3"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=3"><img
alt="Fix in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=3"
height="20"></picture></a>
</details>
<!-- /greptile_failed_comments -->
<sub>Reviews (3): Last reviewed commit: ["fix(gt-next): mark
client-boundary as
ha..."](006591d)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40606533)</sub>
<!-- /greptile_comment -->
## Summary
- replace deprecated inline/dictionary option aliases with focused
translation option types
- type dictionary t() options as interpolation variables and dictionary
leaf metadata separately
- trim higher-level public type barrels to expose only
GTTranslationOptions and RuntimeTranslationOptions
## Tests
- pnpm --filter gt-i18n typecheck
- pnpm --filter @generaltranslation/react-core typecheck
- pnpm --filter gt-next typecheck
- pnpm --filter gt-react-native typecheck
- pnpm --filter gt-node typecheck
- pnpm --filter gt-i18n test
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR refactors the translation option type system in the `gt-i18n`
monorepo, replacing a set of deprecated alias types
(`InlineTranslationOptions`, `InlineResolveOptions`,
`DictionaryTranslationOptions`, `BaseTranslationOptions`,
`ResolutionOptions`, `DictionaryOptions`) with a cleaner, focused
hierarchy (`GTTranslationOptions`, `TranslationVariables`,
`TranslationMetadata`, `TranslationOptions`, `LookupOptionsFor`). It
also trims the public-facing type barrels to expose only
`GTTranslationOptions` and `RuntimeTranslationOptions`, hiding internal
plumbing types.
- **Type hierarchy flattened and renamed**:
`InlineTranslationOptionsFields` → `TranslationMetadata`;
`InlineTranslationOptions` → internal `TranslationOptions`; user-facing
`GTTranslationOptions` now deliberately excludes `$_fallback` and
`$_source` while keeping `$_hash`.
- **`t()` options narrowed**: Dictionary `t()` and `useTranslations()`
now accept `TranslationVariables` (plain `Record<string, unknown>`)
instead of `DictionaryTranslationOptions`, reflecting that metadata
lives on the dictionary leaf, not the call site.
- **`MFunctionType` tightened**: The previous `Record<string, any>`
escape-hatch on `m()`'s `options` parameter is replaced with the proper
`GTTranslationOptions`.
<details open><summary><h3>Confidence Score: 5/5</h3></summary>
Safe to merge — this is a pure type-level refactoring with no runtime
logic changes, and the new type hierarchy is structurally equivalent to
what it replaces.
All renamed types resolve to the same structural shapes as their
predecessors at the TypeScript level. The narrowing of
DictionaryLookupOptions (dropping $id, $locale, $_hash fields never
actually used in the dictionary path) is intentional and correct. The
MFunctionType fix (replacing Record<string, any> with
GTTranslationOptions) is a strict improvement. The major-version
changeset is correct since public-facing type names changed.
No files require special attention. The options.ts rewrite is the most
impactful file and it reads cleanly.
</details>
<details><summary><h3>Important Files Changed</h3></summary>
| Filename | Overview |
|----------|----------|
| packages/i18n/src/translation-functions/types/options.ts | Core type
definitions refactored cleanly; new hierarchy is structurally equivalent
to old one; DictionaryLookupOptions intentionally narrowed to remove
fields unused in the dictionary path. |
| packages/i18n/src/translation-functions/types/functions.ts |
MFunctionType now uses GTTranslationOptions instead of Record<string,
any>; all function types updated consistently with the new type names. |
| packages/i18n/src/types.ts | Public barrel trimmed correctly; internal
types like DictionaryLookupOptions removed from public exports; new
types like LookupOptionsFor and DictionaryEntryOptions added. |
|
packages/i18n/src/i18n-cache/translations-manager/utils/dictionary-helpers.ts
| isDictionaryOptions renamed to isDictionaryLeafOptions; now imports
DictionaryEntryOptions/DictionaryLookupOptions from central options.ts
rather than defining them locally. |
| packages/i18n/src/translation-functions/internal/helpers.ts |
ResolutionOptions replaced by LookupOptionsFor across all six resolve
functions; behaviorally equivalent. |
| packages/react-core/src/hooks/useTranslations.ts |
DictionaryTranslationOptions replaced by TranslationVariables in
useTranslations and UseTranslationsFunction; structurally identical
types. |
| packages/i18n/src/translation-functions/msg/decodeOptions.ts | Return
type widened from InlineTranslationOptions to TranslationOptions (the
full internal shape), which is correct since decoded options can carry
any metadata field. |
| .changeset/simplify-translation-option-types.md | All six affected
packages correctly marked as major version bumps in the changeset. |
</details>
<details><summary><h3>Class Diagram</h3></summary>
<a href="#gh-light-mode-only">
```mermaid
%%{init: {'theme': 'neutral'}}%%
classDiagram
class TranslationVariables {
<<Record~string,unknown~>>
}
class TranslationMetadata {
+$context?: string
+$id?: string
+$format?: StringFormat
+$locale?: string
+$_hash?: string
+$_fallback?: string
+$_source?: string
+$maxChars?: number
}
class TranslationOptions {
<<internal full shape>>
}
class GTTranslationOptions {
<<user-facing gt() m()>>
+$context?: string
+$id?: string
+$format?: StringFormat
+$locale?: string
+$_hash?: string
+$maxChars?: number
}
class DictionaryEntryOptions {
<<dictionary leaf metadata>>
+$context?: string
+$format?: StringFormat
+$maxChars?: number
}
class DictionaryLookupOptions {
<<internal>>
+$format: StringFormat
}
class RuntimeTranslationOptions {
<<user-facing tx()>>
+$format?: DataFormat
}
class EncodedTranslationOptions {
<<msg() output>>
+$_hash: string
+$_source: string
}
class LookupOptionsFor~T~ {
<<generic resolution>>
}
TranslationVariables <|-- TranslationOptions : intersects
TranslationMetadata <|-- TranslationOptions : intersects
TranslationVariables <|-- GTTranslationOptions : intersects
TranslationMetadata <|-- GTTranslationOptions : Pick subset
GTTranslationOptions <|-- EncodedTranslationOptions : extends
TranslationVariables <|-- DictionaryEntryOptions : intersects
TranslationMetadata <|-- DictionaryEntryOptions : Pick subset
DictionaryEntryOptions <|-- DictionaryLookupOptions : extends
TranslationVariables <|-- RuntimeTranslationOptions : intersects
TranslationMetadata <|-- RuntimeTranslationOptions : Omit~$id,$format~
TranslationOptions <|-- LookupOptionsFor~T~ : when T is StringFormat
```
</a>
<a href="#gh-dark-mode-only">
```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
classDiagram
class TranslationVariables {
<<Record~string,unknown~>>
}
class TranslationMetadata {
+$context?: string
+$id?: string
+$format?: StringFormat
+$locale?: string
+$_hash?: string
+$_fallback?: string
+$_source?: string
+$maxChars?: number
}
class TranslationOptions {
<<internal full shape>>
}
class GTTranslationOptions {
<<user-facing gt() m()>>
+$context?: string
+$id?: string
+$format?: StringFormat
+$locale?: string
+$_hash?: string
+$maxChars?: number
}
class DictionaryEntryOptions {
<<dictionary leaf metadata>>
+$context?: string
+$format?: StringFormat
+$maxChars?: number
}
class DictionaryLookupOptions {
<<internal>>
+$format: StringFormat
}
class RuntimeTranslationOptions {
<<user-facing tx()>>
+$format?: DataFormat
}
class EncodedTranslationOptions {
<<msg() output>>
+$_hash: string
+$_source: string
}
class LookupOptionsFor~T~ {
<<generic resolution>>
}
TranslationVariables <|-- TranslationOptions : intersects
TranslationMetadata <|-- TranslationOptions : intersects
TranslationVariables <|-- GTTranslationOptions : intersects
TranslationMetadata <|-- GTTranslationOptions : Pick subset
GTTranslationOptions <|-- EncodedTranslationOptions : extends
TranslationVariables <|-- DictionaryEntryOptions : intersects
TranslationMetadata <|-- DictionaryEntryOptions : Pick subset
DictionaryEntryOptions <|-- DictionaryLookupOptions : extends
TranslationVariables <|-- RuntimeTranslationOptions : intersects
TranslationMetadata <|-- RuntimeTranslationOptions : Omit~$id,$format~
TranslationOptions <|-- LookupOptionsFor~T~ : when T is StringFormat
```
</a>
</details>
<sub>Reviews (3): Last reviewed commit: ["refactor: simplify translation
option
ty..."](4417d04)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40623023)</sub>
<!-- /greptile_comment -->
## Summary Each `@generaltranslation/react-core` entrypoint (`pure`, `hooks`, `components`, `components-rsc`, `cookies`) was built as a **single pre-bundled, minified file**, so importing one component pulled the whole entry and a downstream bundler couldn't drop unused code. This PR switches react-core to an **unbundled** build (per-module output, ESM + CJS): entrypoints become thin re-export barrels over granular sibling modules. Output filenames change from `*.cjs.min.cjs`/`*.esm.min.mjs` to `*.cjs`/`*.mjs`, resolved through the `exports` map — no consumer-facing API change. ## Measured impact When react-core is consumed via ESM, this lets the bundler tree-shake the unused half of `pure`/`components`. react-core's **client** footprint (real Next.js app, `next experimental-analyze`): | | react-core client raw | react-core client gz | |---|---|---| | bundled (before) | 158.2 kB | 49.1 kB | | unbundled (after) | **82.0 kB** | **33.0 kB** | >⚠️ This reduction only materializes when react-core is resolved as **ESM**. CJS can't be tree-shaken, so on its own this PR barely moves gzip (it just de-duplicates raw text). It pays off layered on #1688 (`gt-next` ESM build); together the two cut gt's total client bundle ~40% gzip. ## Reviewer note — intentional architecture reversal This reverses the previous "independent entrypoints **without shared chunks**" design. The `react-core-package.test.ts` guard that enforced per-entry bundling is rewritten to assert the new unbundled layout (entrypoints present in both formats; many granular runtime modules emitted). The two behavioral export-loading tests are unchanged. All 267 react-core tests pass. ## Validation - `pnpm --filter @generaltranslation/react-core test` → 267 passing - Full app build (this + #1688) compiles and runs; gt-react/gt-next consume the unbundled subpaths via the `exports` map with no changes. <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR switches `@generaltranslation/react-core` from a per-entrypoint pre-bundled build to an unbundled (per-module) ESM + CJS output, enabling downstream bundlers to tree-shake unused components and hooks. The measured client footprint drops from 158 kB → 82 kB raw (49 kB → 33 kB gzip) when consumed as ESM. - **Build config** (`tsdown.config.mts`): replaces `createTsdownMinifiedDualFormatConfig` with two `createTsdownUnbundleConfig` calls (CJS with `dts:true`, ESM with `clean:false`); `@generaltranslation/format` and `generaltranslation` subpath imports are intentionally externalized instead of inlined. - **Package exports** (`package.json`): filename extensions updated from `*.cjs.min.cjs`/`*.esm.min.mjs` to `*.cjs`/`*.mjs`; `sideEffects: false` is already set, which is required for tree-shaking to work. - **Tests**: TypeScript AST-based bundling assertion removed and replaced with a file-count heuristic asserting the unbundled layout; the two behavioral load tests (CJS and ESM named-export checks) are kept unchanged. <details open><summary><h3>Confidence Score: 5/5</h3></summary> Safe to merge — the change is a pure build-output restructuring with no runtime logic changes and no public API surface modifications. The only changes are to the build configuration, the exports map filename extensions, the size-limit path, and the test assertions. The two behavioral load tests that verify named exports from both CJS and ESM entrypoints are unchanged and confirmed passing (267 tests). The `sideEffects: false` flag that makes tree-shaking effective was already present. The dependency externalization (`@generaltranslation/format`, `generaltranslation` subpaths) is intentional and documented in the changeset, and both packages remain listed as `dependencies` in `package.json` so they are guaranteed to be installed. No files require special attention. </details> <details><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | packages/react-core/tsdown.config.mts | Switches from createTsdownMinifiedDualFormatConfig to createTsdownUnbundleConfig; CJS gets dts:true, ESM gets clean:false; both get minify:true spread in. No alwaysBundle overrides needed since generaltranslation/format subpaths are now intentionally externalized. | | packages/react-core/package.json | Exports map updated from *.cjs.min.cjs/esm.min.mjs to *.cjs/*.mjs; all five entrypoints updated consistently; no other consumer-facing changes. | | packages/react-core/src/__tests__/react-core-package.test.ts | Test rewritten to assert unbundled layout: barrel presence in both formats plus a file-count check; TypeScript AST-based bundling check removed; two behavioral load tests are unchanged. | | .size-limit.cjs | Path updated from *.esm.min.mjs to *.mjs to match new output extensions; 48 kB limit preserved. | | .changeset/react-core-unbundle.md | New patch-level changeset describing the unbundled build, removed format sub-dependency inlining, and filename extension changes. | </details> <sub>Reviews (2): Last reviewed commit: ["perf(react-core): unbundle build output ..."](c6441df) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=40606757)</sub> <!-- /greptile_comment -->
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to odysseus, this PR will be updated.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ `odysseus` is currently in **pre mode** so this branch has prereleases rather than normal releases. If you want to exit prereleases, run `changeset pre exit` on `odysseus`.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ # Releases ## gt-i18n@1.0.0-odysseus.2 ### Major Changes - [#1687](#1687) [`41c938c`](41c938c) Thanks [@bgub](https://github.com/bgub)! - Remove deprecated translation options. The `context` dictionary option has been removed in favor of `$context`, and the `$_locales` inline option has been removed in favor of `$locale`. - [#1690](#1690) [`b3c3b9a`](b3c3b9a) Thanks [@bgub](https://github.com/bgub)! - Simplify translation option types. Replace deprecated inline and dictionary option aliases with `GTTranslationOptions`, use interpolation variables for dictionary `t()` options, and trim higher-level type exports to avoid exposing internal translation option fields. ### Patch Changes - Updated dependencies [[`4b97bc3`](4b97bc3), [`020c6bd`](020c6bd)]: - @generaltranslation/format@0.1.2-odysseus.1 - generaltranslation@9.0.0-odysseus.2 - @generaltranslation/supported-locales@2.1.2-odysseus.2 ## gt-next@11.0.0-odysseus.5 ### Major Changes - [#1690](#1690) [`b3c3b9a`](b3c3b9a) Thanks [@bgub](https://github.com/bgub)! - Simplify translation option types. Replace deprecated inline and dictionary option aliases with `GTTranslationOptions`, use interpolation variables for dictionary `t()` options, and trim higher-level type exports to avoid exposing internal translation option fields. ### Patch Changes - [#1685](#1685) [`795147f`](795147f) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Allow client i18n cache expiry to default to no expiry while preserving explicit cache expiry configuration. - [#1688](#1688) [`2836b96`](2836b96) Thanks [@bgub](https://github.com/bgub)! - Ship a dual ESM/CJS build for `gt-next` and add `import` export conditions. Previously `gt-next` was published as CJS only (no `import` condition), so bundlers resolved the entire gt dependency graph (`gt-react`, `@generaltranslation/react-core`, `generaltranslation`, `gt-i18n`, `@generaltranslation/format`) through the `require` condition. That forced CJS variants onto the client, which cannot be tree-shaken — shipping `gt-next`'s own server/error code and unused dependency exports to the browser. `gt-next` now emits unbundled `.mjs` output alongside the existing `.js` output, and every `exports` subpath exposes an `import` condition. Bundlers now resolve the gt graph as ESM, enabling tree-shaking across all gt packages. Measured on a real Next.js app, this cuts gt's total client bundle by ~19% gzip (≈96 kB → ≈78 kB) with no API changes. The ESM build sets `polyfillRequire: false` so rolldown does not inject a `createRequire`-from-`node:module` shim (server-only `require()` calls are provided `require` by the bundler), and marks the `index.rsc`/`index.client` entrypoints as having side effects so their top-level initialization is not tree-shaken away. - [#1678](#1678) [`4b97bc3`](4b97bc3) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Organize package entrypoint exports and replace re-export-only imports with direct export declarations. - [#1676](#1676) [`020c6bd`](020c6bd) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove default exports from package entrypoints and internal source modules. Use named imports for affected public entrypoints, including `import { plugin } from 'gt-react-native/plugin'`. The `gt-next/link` entrypoint keeps its default export to match `next/link`. - Updated dependencies [[`795147f`](795147f), [`4b97bc3`](4b97bc3), [`020c6bd`](020c6bd), [`41c938c`](41c938c), [`b3c3b9a`](b3c3b9a)]: - gt-react@11.0.0-odysseus.5 - @generaltranslation/format@0.1.2-odysseus.1 - generaltranslation@9.0.0-odysseus.2 - @generaltranslation/react-core@11.0.0-odysseus.5 - gt-i18n@1.0.0-odysseus.2 - @generaltranslation/compiler@1.3.25-odysseus.2 - @generaltranslation/supported-locales@2.1.2-odysseus.2 ## gt-node@1.0.0-odysseus.2 ### Major Changes - [#1690](#1690) [`b3c3b9a`](b3c3b9a) Thanks [@bgub](https://github.com/bgub)! - Simplify translation option types. Replace deprecated inline and dictionary option aliases with `GTTranslationOptions`, use interpolation variables for dictionary `t()` options, and trim higher-level type exports to avoid exposing internal translation option fields. ### Patch Changes - Updated dependencies [[`4b97bc3`](4b97bc3), [`020c6bd`](020c6bd), [`41c938c`](41c938c), [`b3c3b9a`](b3c3b9a)]: - generaltranslation@9.0.0-odysseus.2 - gt-i18n@1.0.0-odysseus.2 ## gt-react@11.0.0-odysseus.5 ### Major Changes - [#1690](#1690) [`b3c3b9a`](b3c3b9a) Thanks [@bgub](https://github.com/bgub)! - Simplify translation option types. Replace deprecated inline and dictionary option aliases with `GTTranslationOptions`, use interpolation variables for dictionary `t()` options, and trim higher-level type exports to avoid exposing internal translation option fields. ### Patch Changes - [#1685](#1685) [`795147f`](795147f) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Allow client i18n cache expiry to default to no expiry while preserving explicit cache expiry configuration. - [#1676](#1676) [`020c6bd`](020c6bd) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove default exports from package entrypoints and internal source modules. Use named imports for affected public entrypoints, including `import { plugin } from 'gt-react-native/plugin'`. The `gt-next/link` entrypoint keeps its default export to match `next/link`. - Updated dependencies [[`4b97bc3`](4b97bc3), [`020c6bd`](020c6bd), [`41c938c`](41c938c), [`b3c3b9a`](b3c3b9a)]: - @generaltranslation/format@0.1.2-odysseus.1 - generaltranslation@9.0.0-odysseus.2 - @generaltranslation/react-core@11.0.0-odysseus.5 - gt-i18n@1.0.0-odysseus.2 - @generaltranslation/supported-locales@2.1.2-odysseus.2 ## @generaltranslation/react-core@11.0.0-odysseus.5 ### Major Changes - [#1690](#1690) [`b3c3b9a`](b3c3b9a) Thanks [@bgub](https://github.com/bgub)! - Simplify translation option types. Replace deprecated inline and dictionary option aliases with `GTTranslationOptions`, use interpolation variables for dictionary `t()` options, and trim higher-level type exports to avoid exposing internal translation option fields. ### Patch Changes - [#1676](#1676) [`020c6bd`](020c6bd) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove default exports from package entrypoints and internal source modules. Use named imports for affected public entrypoints, including `import { plugin } from 'gt-react-native/plugin'`. The `gt-next/link` entrypoint keeps its default export to match `next/link`. - Updated dependencies [[`4b97bc3`](4b97bc3), [`020c6bd`](020c6bd), [`41c938c`](41c938c), [`b3c3b9a`](b3c3b9a)]: - @generaltranslation/format@0.1.2-odysseus.1 - generaltranslation@9.0.0-odysseus.2 - gt-i18n@1.0.0-odysseus.2 - @generaltranslation/supported-locales@2.1.2-odysseus.2 ## gt-react-native@11.0.0-odysseus.5 ### Major Changes - [#1690](#1690) [`b3c3b9a`](b3c3b9a) Thanks [@bgub](https://github.com/bgub)! - Simplify translation option types. Replace deprecated inline and dictionary option aliases with `GTTranslationOptions`, use interpolation variables for dictionary `t()` options, and trim higher-level type exports to avoid exposing internal translation option fields. ### Patch Changes - [#1678](#1678) [`4b97bc3`](4b97bc3) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Organize package entrypoint exports and replace re-export-only imports with direct export declarations. - [#1676](#1676) [`020c6bd`](020c6bd) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove default exports from package entrypoints and internal source modules. Use named imports for affected public entrypoints, including `import { plugin } from 'gt-react-native/plugin'`. The `gt-next/link` entrypoint keeps its default export to match `next/link`. - Updated dependencies [[`4b97bc3`](4b97bc3), [`020c6bd`](020c6bd), [`41c938c`](41c938c), [`b3c3b9a`](b3c3b9a)]: - @generaltranslation/format@0.1.2-odysseus.1 - generaltranslation@9.0.0-odysseus.2 - @generaltranslation/react-core@11.0.0-odysseus.5 - gt-i18n@1.0.0-odysseus.2 - @generaltranslation/supported-locales@2.1.2-odysseus.2 ## gt@2.14.51-odysseus.2 ### Patch Changes - Updated dependencies [[`4b97bc3`](4b97bc3), [`020c6bd`](020c6bd)]: - @generaltranslation/format@0.1.2-odysseus.1 - generaltranslation@9.0.0-odysseus.2 - @generaltranslation/python-extractor@0.2.23-odysseus.2 - @generaltranslation/supported-locales@2.1.2-odysseus.2 ## @generaltranslation/compiler@1.3.25-odysseus.2 ### Patch Changes - Updated dependencies [[`4b97bc3`](4b97bc3), [`020c6bd`](020c6bd)]: - @generaltranslation/format@0.1.2-odysseus.1 - generaltranslation@9.0.0-odysseus.2 ## generaltranslation@9.0.0-odysseus.2 ### Patch Changes - [#1678](#1678) [`4b97bc3`](4b97bc3) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Organize package entrypoint exports and replace re-export-only imports with direct export declarations. - [#1676](#1676) [`020c6bd`](020c6bd) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Remove default exports from package entrypoints and internal source modules. Use named imports for affected public entrypoints, including `import { plugin } from 'gt-react-native/plugin'`. The `gt-next/link` entrypoint keeps its default export to match `next/link`. - Updated dependencies [[`4b97bc3`](4b97bc3)]: - @generaltranslation/format@0.1.2-odysseus.1 ## @generaltranslation/format@0.1.2-odysseus.1 ### Patch Changes - [#1678](#1678) [`4b97bc3`](4b97bc3) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Organize package entrypoint exports and replace re-export-only imports with direct export declarations. ## gtx-cli@2.14.51-odysseus.2 ### Patch Changes - Updated dependencies []: - gt@2.14.51-odysseus.2 ## locadex@1.0.186-odysseus.2 ### Patch Changes - Updated dependencies []: - gt@2.14.51-odysseus.2 ## @generaltranslation/gt-next-lint@15.0.0-odysseus.5 ### Patch Changes - Updated dependencies [[`795147f`](795147f), [`2836b96`](2836b96), [`4b97bc3`](4b97bc3), [`020c6bd`](020c6bd), [`b3c3b9a`](b3c3b9a)]: - gt-next@11.0.0-odysseus.5 ## @generaltranslation/python-extractor@0.2.23-odysseus.2 ### Patch Changes - Updated dependencies [[`4b97bc3`](4b97bc3), [`020c6bd`](020c6bd)]: - generaltranslation@9.0.0-odysseus.2 ## gt-sanity@2.0.18-odysseus.4 ### Patch Changes - [#1678](#1678) [`4b97bc3`](4b97bc3) Thanks [@ErnestM1234](https://github.com/ErnestM1234)! - Organize package entrypoint exports and replace re-export-only imports with direct export declarations. - Updated dependencies [[`4b97bc3`](4b97bc3), [`020c6bd`](020c6bd)]: - generaltranslation@9.0.0-odysseus.2 ## @generaltranslation/supported-locales@2.1.2-odysseus.2 ### Patch Changes - Updated dependencies [[`4b97bc3`](4b97bc3), [`020c6bd`](020c6bd)]: - generaltranslation@9.0.0-odysseus.2 ## gt-tanstack-start@11.0.0-odysseus.5 ### Patch Changes - Updated dependencies [[`795147f`](795147f), [`4b97bc3`](4b97bc3), [`020c6bd`](020c6bd), [`41c938c`](41c938c), [`b3c3b9a`](b3c3b9a)]: - gt-react@11.0.0-odysseus.5 - generaltranslation@9.0.0-odysseus.2 - @generaltranslation/react-core@11.0.0-odysseus.5 - gt-i18n@1.0.0-odysseus.2 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## Summary - Add `scripts/version-packages-odysseus.sh` for the Odysseus release action. - The script rewrites `.changeset/config.json` to use `baseBranch: odysseus` and `@changesets/cli/changelog`, marks the config file assume-unchanged, then runs `pnpm run version-packages`. - Configure `changesets/action` to call the script via `version: bash scripts/version-packages-odysseus.sh`, so the rewrite happens after the action resets the release branch. ## Testing - `bash -n scripts/version-packages-odysseus.sh` - `pnpm exec oxfmt --check .github/workflows/release.yml scripts/version-packages-odysseus.sh` - In a temp worktree at this PR head, ran `bash scripts/version-packages-odysseus.sh`; it completed successfully, generated the expected release files, and `.changeset/config.json` had no diff. ## Notes The previous workflow step did run, but `changesets/action` then performed `git reset --hard <headSha>` before invoking `version`, which discarded the config rewrite. The script is called from `version`, after that reset.
## Summary - Add a patch changeset for `@generaltranslation/react-core` to trigger a new Odysseus prerelease path. - Rely on the Odysseus fixed package group to include the related React/Next packages during versioning. ## Testing - `pnpm changeset status --since=origin/odysseus`
## Summary
Removes a dead, self-referential dictionary-injection cluster from
`@generaltranslation/react-core`. These 8 modules were exported from the
client-shipped `/pure` entry but have **zero consumers** anywhere in the
monorepo (verified by grep across all `packages/*/src`): they only
imported each other.
Deleted:
- `collectUntranslatedEntries`, `injectAndMerge`, `injectEntry`,
`injectFallbacks`, `injectHashes`, `injectTranslations`,
`getSubtree`/`getSubtreeWithCreation`, `stripMetadataFromEntries` (+
their `__tests__`)
- the 9 corresponding exports in `src/pure.ts`
~415 LOC of dead code removed from `/pure`. The still-used dictionary
helpers (`getDictionaryEntry`, `getEntryAndMetadata`,
`mergeDictionaries`, `flattenDictionary`, `indexDict`,
`isDictionaryEntry`) are untouched.
## Verification
- `src/pure.ts` was the only importer of all 8 modules; the kept
dictionary files don't depend on any of them.
- react-core builds; 139 tests pass (the removed tests only covered the
deleted modules).
- `gt-react` and `gt-next` (the `/pure` consumers) build clean.
Part of an odysseus (next-major) dead-code/trim sweep.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR removes 8 dead dictionary-injection helper modules from
`@generaltranslation/react-core/pure`, along with their corresponding
test files. No consumer anywhere in the monorepo referenced any of the
deleted exports; they only imported each other.
- Removes `collectUntranslatedEntries`, `injectAndMerge`, `injectEntry`,
`injectFallbacks`, `injectHashes`, `injectTranslations`,
`getSubtree`/`getSubtreeWithCreation`, and `stripMetadataFromEntries`
(source + tests) — ~415 LOC total.
- Strips the 9 corresponding exports from `src/pure.ts`; all still-used
dictionary helpers (`getDictionaryEntry`, `getEntryAndMetadata`,
`mergeDictionaries`, `flattenDictionary`, `indexDict`,
`isDictionaryEntry`) are untouched.
- The changeset is marked `patch` within the active `odysseus`
pre-release, which already carries a major-version bump via a separate
changeset, so no semver concern.
<details open><summary><h3>Confidence Score: 5/5</h3></summary>
Safe to merge — this is a pure deletion of exports and source files that
have zero consumers in the monorepo.
All 8 deleted modules were verified unused across every package in the
monorepo. The surviving exports in pure.ts are untouched, and the
downstream consumers (gt-react, gt-next) import none of the removed
symbols. Test coverage for the deleted code is removed alongside the
source, leaving no orphaned references.
No files require special attention.
</details>
<details><summary><h3>Important Files Changed</h3></summary>
| Filename | Overview |
|----------|----------|
| packages/react-core/src/pure.ts | Removes 9 export lines pointing to
the deleted modules; all remaining exports are untouched and verified
still-used. |
| .changeset/trim-react-core-dead-dictionaries.md | Changeset correctly
scoped to @generaltranslation/react-core as patch; acceptable within the
active odysseus pre-release that already carries a major bump. |
|
packages/react-core/src/utils/dictionaries/collectUntranslatedEntries.ts
| Deleted source file — confirmed no consumers in the monorepo. |
| packages/react-core/src/utils/dictionaries/injectAndMerge.ts | Deleted
source file — confirmed no consumers in the monorepo. |
| packages/react-core/src/utils/dictionaries/getSubtree.ts | Deleted
source file — confirmed no consumers in the monorepo. |
</details>
<details><summary><h3>Flowchart</h3></summary>
<a href="#gh-light-mode-only">
```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["@generaltranslation/react-core/pure"] --> B["Kept: getDictionaryEntry"]
A --> C["Kept: getEntryAndMetadata"]
A --> D["Kept: mergeDictionaries"]
A --> E["Kept: flattenDictionary"]
A --> F["Kept: isDictionaryEntry"]
A --> G["Kept: isValidDictionaryEntry"]
H["REMOVED: collectUntranslatedEntries"] -.->|"no consumers"| X["❌ Dead cluster"]
I["REMOVED: injectAndMerge"] -.-> X
J["REMOVED: injectEntry"] -.-> X
K["REMOVED: injectFallbacks"] -.-> X
L["REMOVED: injectHashes"] -.-> X
M["REMOVED: injectTranslations"] -.-> X
N["REMOVED: getSubtree / getSubtreeWithCreation"] -.-> X
O["REMOVED: stripMetadataFromEntries"] -.-> X
A --> P["gt-react (consumer)"]
A --> Q["gt-next (consumer)"]
```
</a>
<a href="#gh-dark-mode-only">
```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A["@generaltranslation/react-core/pure"] --> B["Kept: getDictionaryEntry"]
A --> C["Kept: getEntryAndMetadata"]
A --> D["Kept: mergeDictionaries"]
A --> E["Kept: flattenDictionary"]
A --> F["Kept: isDictionaryEntry"]
A --> G["Kept: isValidDictionaryEntry"]
H["REMOVED: collectUntranslatedEntries"] -.->|"no consumers"| X["❌ Dead cluster"]
I["REMOVED: injectAndMerge"] -.-> X
J["REMOVED: injectEntry"] -.-> X
K["REMOVED: injectFallbacks"] -.-> X
L["REMOVED: injectHashes"] -.-> X
M["REMOVED: injectTranslations"] -.-> X
N["REMOVED: getSubtree / getSubtreeWithCreation"] -.-> X
O["REMOVED: stripMetadataFromEntries"] -.-> X
A --> P["gt-react (consumer)"]
A --> Q["gt-next (consumer)"]
```
</a>
</details>
<sub>Reviews (1): Last reviewed commit: ["refactor(react-core): remove
dead
dictio..."](21e5e12)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40685657)</sub>
<!-- /greptile_comment -->
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to odysseus, this PR will be updated.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ `odysseus` is currently in **pre mode** so this branch has prereleases rather than normal releases. If you want to exit prereleases, run `changeset pre exit` on `odysseus`.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ # Releases ## gt-next@11.0.0-odysseus.6 ### Patch Changes - Updated dependencies [c1aa794] - Updated dependencies [e0ace5b] - @generaltranslation/react-core@11.0.0-odysseus.6 - gt-react@11.0.0-odysseus.6 ## @generaltranslation/gt-next-lint@15.0.0-odysseus.6 ### Patch Changes - gt-next@11.0.0-odysseus.6 ## gt-react@11.0.0-odysseus.6 ### Patch Changes - Updated dependencies [c1aa794] - Updated dependencies [e0ace5b] - @generaltranslation/react-core@11.0.0-odysseus.6 ## @generaltranslation/react-core@11.0.0-odysseus.6 ### Patch Changes - c1aa794: Trigger a new Odysseus prerelease after updating the release workflow. - e0ace5b: Build `@generaltranslation/react-core` as unbundled, tree-shakeable modules. Each entrypoint (`pure`, `hooks`, `components`, `components-rsc`, `cookies`) was previously emitted as a single pre-bundled, minified file, so a consumer importing one component pulled the entire entry. The package now builds unbundled (per-module) output in both ESM and CJS: entrypoints are thin re-export barrels over granular sibling modules, allowing a downstream bundler to drop unused components and hooks. The build also stops inlining `generaltranslation`/`@generaltranslation/format` into react-core's output, so they resolve to their single shared copy instead of being duplicated in react-core (they are already loaded standalone). This removes the duplication and keeps the per-module declarations referencing the dependency packages directly, so inferred types stay portable for downstream packages. When consumed via ESM (see the companion `gt-next` ESM change), tree-shaking plus de-duplication cuts react-core's client footprint substantially. Output filenames change from `*.cjs.min.cjs`/`*.esm.min.mjs` to `*.cjs`/`*.mjs` (resolved through the `exports` map, so no consumer-facing API change). The package-shape test is updated to assert the new unbundled layout. ## gt-react-native@11.0.0-odysseus.6 ### Patch Changes - Updated dependencies [c1aa794] - Updated dependencies [e0ace5b] - @generaltranslation/react-core@11.0.0-odysseus.6 ## gt-tanstack-start@11.0.0-odysseus.6 ### Patch Changes - Updated dependencies [c1aa794] - Updated dependencies [e0ace5b] - @generaltranslation/react-core@11.0.0-odysseus.6 - gt-react@11.0.0-odysseus.6 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## Summary
Removes the v8-era backwards-compatibility shim from
`generaltranslation`. Deletes `src/backwards-compatability/` and its 26
re-exports from `generaltranslation/internal`:
- `dataConversion.ts` — `getNew*`/`getOld*` JSX/variable/branch/GTProp
format converters
- `oldTypes.ts` — `Old*` type definitions
- `typeChecking.ts` — `isOld*`/`isNew*` guards
- `oldHashJsxChildren.ts` — `oldHashJsxChildren`/`oldHashString` (legacy
hashers)
These bridged the pre-v8 JSX/variable format, which is no longer
produced. **Verified zero consumers** across all `packages/*/src` — the
only references were `internal.ts` (the barrel) itself. ~477 LOC removed
from the `/internal` entry.
`@noble/hashes` stays a dependency (the live `id/hashSource.ts` still
uses it).
## Verification
- grep across the monorepo: none of the 26 symbols (or the module paths)
are imported anywhere outside `backwards-compatability/` +
`internal.ts`.
- `generaltranslation` builds; **432 tests pass** (3 skipped).
- Dependents build clean: `gt-i18n`, `@generaltranslation/react-core`,
`gt-react`, `gt-next`.
Part of an odysseus (next-major) dead-code/legacy-removal sweep.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR removes the v8-era backwards-compatibility shim from
`generaltranslation` — 4 source files and 26 re-exports are deleted from
the `generaltranslation/internal` entry point. The PR description
confirms zero consumers in the monorepo and all dependent packages build
clean after the removal.
- Deletes `packages/core/src/backwards-compatability/` (dataConversion,
oldTypes, typeChecking, oldHashJsxChildren) and scrubs their 26
re-exports from `src/internal.ts`.
- The `patch` changeset bump is safe here because a separate
`odysseus-major-version-bumps.md` changeset already carries a `major`
bump for `generaltranslation`, and changesets tooling always uses the
highest bump across all pending changesets.
<details open><summary><h3>Confidence Score: 5/5</h3></summary>
Safe to merge — this is a pure deletion of dead code with no active
consumers anywhere in the monorepo.
All four deleted files were confirmed to have zero imports outside their
own directory and the internal barrel. The remaining exports in
internal.ts are untouched. The @noble/hashes dependency is retained for
the live hash implementation. The patch changeset bump is harmless
because a separate odysseus-major-version-bumps.md already locks in a
major bump for generaltranslation.
No files require special attention.
</details>
<details><summary><h3>Important Files Changed</h3></summary>
| Filename | Overview |
|----------|----------|
| .changeset/trim-core-backwards-compat.md | Adds a patch changeset;
safe because odysseus-major-version-bumps.md already ensures a major
bump for this package. |
| packages/core/src/backwards-compatability/dataConversion.ts | Deleted
— 14 old↔new JSX/variable format converter functions with zero remaining
consumers. |
| packages/core/src/backwards-compatability/oldHashJsxChildren.ts |
Deleted — legacy oldHashJsxChildren and oldHashString functions;
@noble/hashes stays as a live dependency via id/hashSource.ts. |
| packages/core/src/backwards-compatability/oldTypes.ts | Deleted — Old*
type definitions (OldBranchType, OldGTProp, OldJsxElement,
OldVariableObject, etc.) no longer needed. |
| packages/core/src/backwards-compatability/typeChecking.ts | Deleted —
isOld*/isNew* type guards for the old JSX format, no longer referenced
anywhere. |
| packages/core/src/internal.ts | Removed 26 backwards-compat
re-exports; remaining exports are unaffected. |
</details>
<details><summary><h3>Flowchart</h3></summary>
<a href="#gh-light-mode-only">
```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["generaltranslation/internal"] --> B["Active Exports (kept)"]
A --> C["backwards-compatability/ (deleted)"]
B --> B1["settings, logging, locales"]
B --> B2["utils: isVariable, minify, base64, etc."]
B --> B3["derive: decodeVars, declareVar, derive, indexVars, extractVars, condenseVars"]
C --> C1["dataConversion.ts\n14 getNew*/getOld* converters"]
C --> C2["oldTypes.ts\n7 Old* type definitions"]
C --> C3["typeChecking.ts\n3 isOld*/isNew* guards"]
C --> C4["oldHashJsxChildren.ts\noldHashJsxChildren + oldHashString"]
style C fill:#ffcccc,stroke:#cc0000
style C1 fill:#ffdddd
style C2 fill:#ffdddd
style C3 fill:#ffdddd
style C4 fill:#ffdddd
style B fill:#ccffcc,stroke:#006600
```
</a>
<a href="#gh-dark-mode-only">
```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A["generaltranslation/internal"] --> B["Active Exports (kept)"]
A --> C["backwards-compatability/ (deleted)"]
B --> B1["settings, logging, locales"]
B --> B2["utils: isVariable, minify, base64, etc."]
B --> B3["derive: decodeVars, declareVar, derive, indexVars, extractVars, condenseVars"]
C --> C1["dataConversion.ts\n14 getNew*/getOld* converters"]
C --> C2["oldTypes.ts\n7 Old* type definitions"]
C --> C3["typeChecking.ts\n3 isOld*/isNew* guards"]
C --> C4["oldHashJsxChildren.ts\noldHashJsxChildren + oldHashString"]
style C fill:#ffcccc,stroke:#cc0000
style C1 fill:#ffdddd
style C2 fill:#ffdddd
style C3 fill:#ffdddd
style C4 fill:#ffdddd
style B fill:#ccffcc,stroke:#006600
```
</a>
</details>
<sub>Reviews (1): Last reviewed commit: ["refactor(core): remove v8
backwards-comp..."](bacce40)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40685817)</sub>
<!-- /greptile_comment -->
Three files with **zero importers** anywhere (grep-verified):
gt-tanstack-start `condition-store/WritableConditionStore.ts` (orphaned
local copy — the package uses gt-i18n's writable store), gt-react-native
`utils/utils.ts` (`readAuthFromEnv`), and gt-i18n
`translations-manager/utils/types/translations-manager.ts`
(`TranslationsManagerConfig` type). All three packages build clean. Part
of the odysseus dead-code sweep.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR removes three orphaned source files that had zero importers
anywhere in their respective packages, as part of the odysseus dead-code
sweep. All three packages continue to build cleanly after the deletions.
-
**`packages/tanstack-start/src/condition-store/WritableConditionStore.ts`**:
A local duplicate of the writable condition store singleton already
provided by `gt-i18n/internal`; the package never wired this copy up.
- **`packages/react-native/src/utils/utils.ts`**: Contained a
`readAuthFromEnv` helper with no callers anywhere in the package.
-
**`packages/i18n/src/i18n-cache/translations-manager/utils/types/translations-manager.ts`**:
An unreferenced `TranslationsManagerConfig` type definition that was
never imported.
<details open><summary><h3>Confidence Score: 5/5</h3></summary>
All three deletions are verified dead code with zero importers in their
packages — this change carries no functional risk.
Each deleted file was grep-confirmed to have no consumers anywhere in
its package or in the wider monorepo. The tanstack-start file was a
duplicate of functionality already provided by gt-i18n/internal, the
react-native helper had no callers, and the i18n type was never
imported. A changeset is included for all three packages.
No files require special attention.
</details>
<details><summary><h3>Important Files Changed</h3></summary>
| Filename | Overview |
|----------|----------|
| .changeset/trim-orphan-files.md | New changeset documenting the
patch-level deletion of three dead files across gt-tanstack-start,
gt-react-native, and gt-i18n. |
|
packages/i18n/src/i18n-cache/translations-manager/utils/types/translations-manager.ts
| Deleted unreferenced TranslationsManagerConfig type — grep-confirmed
zero importers in the entire i18n package. |
| packages/react-native/src/utils/utils.ts | Deleted orphaned
readAuthFromEnv function — grep-confirmed zero consumers in the entire
react-native package. |
| packages/tanstack-start/src/condition-store/WritableConditionStore.ts
| Deleted orphaned local WritableConditionStore singleton — the package
already uses the equivalent export from gt-i18n/internal, so this
duplicate was dead code. |
</details>
<details><summary><h3>Flowchart</h3></summary>
<a href="#gh-light-mode-only">
```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["Dead-code sweep"] --> B["gt-tanstack-start"]
A --> C["gt-react-native"]
A --> D["gt-i18n"]
B --> B1["condition-store/WritableConditionStore.ts\n(duplicate of gt-i18n/internal export)"]
B1 --> B2["🗑 Deleted — 0 importers"]
C --> C1["utils/utils.ts\n(readAuthFromEnv)"]
C1 --> C2["🗑 Deleted — 0 importers"]
D --> D1["translations-manager/utils/types/translations-manager.ts\n(TranslationsManagerConfig type)"]
D1 --> D2["🗑 Deleted — 0 importers"]
```
</a>
<a href="#gh-dark-mode-only">
```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A["Dead-code sweep"] --> B["gt-tanstack-start"]
A --> C["gt-react-native"]
A --> D["gt-i18n"]
B --> B1["condition-store/WritableConditionStore.ts\n(duplicate of gt-i18n/internal export)"]
B1 --> B2["🗑 Deleted — 0 importers"]
C --> C1["utils/utils.ts\n(readAuthFromEnv)"]
C1 --> C2["🗑 Deleted — 0 importers"]
D --> D1["translations-manager/utils/types/translations-manager.ts\n(TranslationsManagerConfig type)"]
D1 --> D2["🗑 Deleted — 0 importers"]
```
</a>
</details>
<sub>Reviews (1): Last reviewed commit: ["refactor: remove three
orphaned dead
fil..."](824bfda)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40687047)</sub>
<!-- /greptile_comment -->
`hashTemplate` (`generaltranslation/id`) has **zero consumers** anywhere (grep-verified). Deletes the file + its barrel export; `hashSource`/`hashString` untouched. core builds + tests pass; dependents build. Part of the odysseus dead-code sweep. <!-- greptile_comment --> <h3>Greptile Summary</h3> Removes the `hashTemplate` function and its barrel export from `generaltranslation/id`. A codebase-wide grep confirms zero consumers of this export remain after the deletion. - Deletes `packages/core/src/id/hashTemplate.ts` (a thin wrapper around `stableStringify` + `hashString`) and removes its re-export from `packages/core/src/id.ts`. - Adds a patch-level changeset entry; `hashSource` and `hashString` are unaffected. <details open><summary><h3>Confidence Score: 5/5</h3></summary> Safe to merge — removes a dead export with no remaining consumers in the repository. The deleted function was a thin, self-contained wrapper with zero callers anywhere in the codebase. The remaining exports in the barrel file are untouched, the changeset is correctly scoped as a patch, and no dependents reference the removed symbol. No files require special attention. </details> <details><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | .changeset/trim-core-hashtemplate.md | New changeset documenting the patch-level removal of hashTemplate from the generaltranslation package. | | packages/core/src/id.ts | Barrel export for the id subpath — removes the hashTemplate re-export; hashSource and hashString remain untouched. | | packages/core/src/id/hashTemplate.ts | Deleted file — contained the hashTemplate implementation (a thin wrapper around stableStringify + hashString). Confirmed zero consumers remain in the repo. | </details> <sub>Reviews (1): Last reviewed commit: ["refactor(core): remove unused hashTempla..."](520b242) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=40686968)</sub> <!-- /greptile_comment -->
Removes `isVariableObject`, `renderSkeleton`, and `reactHasUse` (+ their modules) from `@generaltranslation/react-core/pure` — **zero consumers** anywhere (grep-verified). More dead code off the client-shipped `/pure` entry. react-core + gt-react + gt-next build; react-core tests pass. (Companion to #1699.) Part of the odysseus dead-code sweep. <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR removes three unused exports — `isVariableObject`, `renderSkeleton`, and `reactHasUse` — along with their source files from the `@generaltranslation/react-core/pure` client-shipped entry point. Grep-verification confirms no consumers exist anywhere in the monorepo. - `pure.ts`: three `export { … }` lines removed; the remaining exports are unaffected. - Three source files deleted: `isVariableObject.ts`, `renderSkeleton.tsx`, and `reactHasUse.ts`, each confirmed orphaned. - A patch-level changeset entry documents the removal for downstream consumers. <details open><summary><h3>Confidence Score: 5/5</h3></summary> Safe to merge — strictly removes dead code with no remaining consumers in the monorepo. All three deleted symbols (`isVariableObject`, `renderSkeleton`, `reactHasUse`) have zero import sites anywhere in the repository, confirmed by grep. The pure.ts entry point drops only the three export lines and is otherwise unchanged. The changeset is correctly marked as a patch. There are no logic changes and no risk of breakage for existing consumers. No files require special attention. </details> <details><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | packages/react-core/src/pure.ts | Three dead export lines removed; remaining exports intact and unaffected. | | packages/react-core/src/utils/promises/reactHasUse.ts | File deleted; boolean utility had zero consumers in the monorepo. | | packages/react-core/src/utils/rendering/isVariableObject.ts | File deleted; type-guard had zero consumers in the monorepo. | | packages/react-core/src/utils/rendering/renderSkeleton.tsx | File deleted; skeleton renderer returned a single empty string and had zero consumers. | | .changeset/trim-react-core-pure-exports.md | Patch-level changeset entry accurately describes the three removed exports. | </details> <details><summary><h3>Flowchart</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% flowchart TD A["@generaltranslation/react-core/pure"] --> B["pure.ts (entry point)"] B --> C["Remaining exports\n(dictionaries, rendering utils, types…)"] B -. "removed" .-> D["isVariableObject\n❌ deleted"] B -. "removed" .-> E["renderSkeleton\n❌ deleted"] B -. "removed" .-> F["reactHasUse\n❌ deleted"] style D stroke:#f66,stroke-dasharray:5 5 style E stroke:#f66,stroke-dasharray:5 5 style F stroke:#f66,stroke-dasharray:5 5 ``` </a> <a href="#gh-dark-mode-only"> ```mermaid %%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% flowchart TD A["@generaltranslation/react-core/pure"] --> B["pure.ts (entry point)"] B --> C["Remaining exports\n(dictionaries, rendering utils, types…)"] B -. "removed" .-> D["isVariableObject\n❌ deleted"] B -. "removed" .-> E["renderSkeleton\n❌ deleted"] B -. "removed" .-> F["reactHasUse\n❌ deleted"] style D stroke:#f66,stroke-dasharray:5 5 style E stroke:#f66,stroke-dasharray:5 5 style F stroke:#f66,stroke-dasharray:5 5 ``` </a> </details> <sub>Reviews (1): Last reviewed commit: ["refactor(react-core): remove unused /pur..."](b8c1840) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=40686898)</sub> <!-- /greptile_comment -->
Removes `condition-store/localeResolver.ts` and its `gt-i18n/internal`
exports (`determineSupportedLocale`, `resolveSupportedLocale`,
`createLocaleResolver`). These were thin wrappers over
`getI18nConfig().<method>()` with **zero consumers** — callers use the
`I18nConfig` methods directly. Verified via grep across all packages;
the `LocaleCandidates` type re-export is preserved (sourced from
`I18nConfig`). gt-i18n + react-core + gt-next + gt-react-native build;
238 gt-i18n tests pass. Part of the odysseus dead-code sweep.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR removes the `condition-store/localeResolver.ts` module and its
three `/internal` exports (`determineSupportedLocale`,
`resolveSupportedLocale`, `createLocaleResolver`) from `gt-i18n`, along
with their test file and changeset entry. The functions were thin
wrappers over `getI18nConfig().<method>()` with no consumers across the
monorepo — verified here as well.
- `packages/i18n/src/condition-store/localeResolver.ts` and its tests
are deleted; the `LocaleCandidates` type re-export in `internal.ts` is
redirected to its real source (`i18n-config/I18nConfig`), preserving the
public API.
- The only existing caller
(`tanstack-start/src/functions/parseLocale.ts`) already calls
`getI18nConfig().resolveSupportedLocale()` directly, confirming no
breakage.
<details open><summary><h3>Confidence Score: 5/5</h3></summary>
Safe to merge — removes dead code only, with no callers anywhere in the
monorepo.
All three deleted functions were pure pass-throughs to getI18nConfig()
methods. The one external caller (tanstack-start/parseLocale.ts) already
calls the underlying I18nConfig methods directly and is unaffected. The
LocaleCandidates type re-export is correctly preserved from its real
source. No logic changes, no API breakage.
No files require special attention.
</details>
<details><summary><h3>Important Files Changed</h3></summary>
| Filename | Overview |
|----------|----------|
| packages/i18n/src/condition-store/localeResolver.ts | Deleted — three
thin wrapper functions with no consumers; safe removal. |
| packages/i18n/src/condition-store/__tests__/localeResolver.test.ts |
Deleted — test file for the removed module; no residual coverage gaps
since the underlying I18nConfig methods retain their own tests. |
| packages/i18n/src/internal.ts | Removed three named exports from the
deleted module; `LocaleCandidates` type re-export is correctly
redirected to its canonical source. |
| .changeset/trim-i18n-localeresolver.md | Patch-level changeset entry;
description is accurate and complete. |
</details>
<details><summary><h3>Flowchart</h3></summary>
<a href="#gh-light-mode-only">
```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["gt-i18n/internal (public entry)"] --> B["LocaleCandidates type\n(re-exported from I18nConfig)"]
A -. "REMOVED" .-> C["determineSupportedLocale\nresolveSupportedLocale\ncreateLocaleResolver"]
C -. "were wrappers over" .-> D["getI18nConfig()"]
D --> E["I18nConfig instance\n.determineSupportedLocale()\n.resolveSupportedLocale()"]
F["tanstack-start/parseLocale.ts"] --> D
F -- "calls directly" --> E
```
</a>
<a href="#gh-dark-mode-only">
```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A["gt-i18n/internal (public entry)"] --> B["LocaleCandidates type\n(re-exported from I18nConfig)"]
A -. "REMOVED" .-> C["determineSupportedLocale\nresolveSupportedLocale\ncreateLocaleResolver"]
C -. "were wrappers over" .-> D["getI18nConfig()"]
D --> E["I18nConfig instance\n.determineSupportedLocale()\n.resolveSupportedLocale()"]
F["tanstack-start/parseLocale.ts"] --> D
F -- "calls directly" --> E
```
</a>
</details>
<sub>Reviews (1): Last reviewed commit: ["refactor(gt-i18n): remove
unused
localeR..."](04e6541)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40686757)</sub>
<!-- /greptile_comment -->
Removes 8 long-`@deprecated` `I18nCache` methods that duplicated
`I18nConfig`/loader APIs and had **no callers**: `getDefaultLocale`,
`getLocales`, `getCustomMapping`, `getGTClass`, `getTranslationLoader`,
`resolveTranslationSync`, `getTranslations`, `getTranslationResolver`.
The TS build across gt-i18n + all consumers confirms nothing called
them. Removes now-unused imports and the tests that covered the removed
methods; 236 gt-i18n tests pass. Part of the odysseus dead-code sweep
(major version — deprecated API removal).
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR removes 8 long-deprecated `I18nCache` methods that were thin
pass-throughs to `I18nConfig` or existing cache methods
(`lookupTranslation`, `loadTranslations`, `getLookupTranslation`), along
with their unused imports (`GT`, `TranslationsLoader`) and the tests
that covered them.
- **`I18nCache.ts`**: Deletes `getDefaultLocale`, `getLocales`,
`getCustomMapping`, `getGTClass`, `getTranslationLoader`,
`resolveTranslationSync`, `getTranslations`, and
`getTranslationResolver`. No other logic is touched.
- **Tests**: Removes the dedicated `resolveTranslationSync.test.ts` file
entirely and strips the corresponding assertions from
`I18nCache.test.ts`; the 236 remaining tests continue to cover all
active behavior.
- **Changeset**: Typed as `patch`, which is safe because
`odysseus-major-version-bumps.md` already carries a `major` bump for
`gt-i18n` that takes precedence at release time.
<details open><summary><h3>Confidence Score: 5/5</h3></summary>
Safe to merge — removes only dead, deprecated pass-through methods with
no callers in the codebase.
Every removed method was a one-liner delegating to either
getI18nConfig() or an existing I18nCache method; no business logic was
changed. The corresponding tests are correctly removed. The patch
changeset is absorbed by the existing major odysseus bump, so semver is
unaffected. No imports, types, or runtime paths outside the deleted code
are touched.
No files require special attention.
</details>
<details><summary><h3>Important Files Changed</h3></summary>
| Filename | Overview |
|----------|----------|
| packages/i18n/src/i18n-cache/I18nCache.ts | Removes 8 deprecated
pass-through methods and their now-unused GT/TranslationsLoader imports;
remaining code is untouched. |
| packages/i18n/src/i18n-cache/__tests__/I18nCache.test.ts | Removes
tests for the 8 deleted methods; the remaining test suite continues to
cover active I18nCache behavior. |
| packages/i18n/src/i18n-cache/__tests__/resolveTranslationSync.test.ts
| Entire file deleted — it tested only resolveTranslationSync and
getTranslations, both of which are removed in this PR. |
| .changeset/trim-i18ncache-deprecated.md | Changeset typed as patch;
safe because odysseus-major-version-bumps.md already carries a major
bump for gt-i18n that will take precedence. |
</details>
<details><summary><h3>Flowchart</h3></summary>
<a href="#gh-light-mode-only">
```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
subgraph BEFORE["Before (deprecated methods present)"]
A1[Caller] -->|getDefaultLocale / getLocales / getCustomMapping| B1[I18nCache]
A2[Caller] -->|getGTClass| B1
A3[Caller] -->|getTranslationLoader| B1
A4[Caller] -->|resolveTranslationSync| B1
A5[Caller] -->|getTranslations / getTranslationResolver| B1
B1 -->|delegates| C1[getI18nConfig]
B1 -->|delegates| C2[lookupTranslation / loadTranslations / getLookupTranslation]
end
subgraph AFTER["After (deprecated methods removed)"]
D1[Caller] -->|getI18nConfig directly| E1[I18nConfig]
D2[Caller] -->|lookupTranslation / loadTranslations / getLookupTranslation| E2[I18nCache active API]
end
```
</a>
<a href="#gh-dark-mode-only">
```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
subgraph BEFORE["Before (deprecated methods present)"]
A1[Caller] -->|getDefaultLocale / getLocales / getCustomMapping| B1[I18nCache]
A2[Caller] -->|getGTClass| B1
A3[Caller] -->|getTranslationLoader| B1
A4[Caller] -->|resolveTranslationSync| B1
A5[Caller] -->|getTranslations / getTranslationResolver| B1
B1 -->|delegates| C1[getI18nConfig]
B1 -->|delegates| C2[lookupTranslation / loadTranslations / getLookupTranslation]
end
subgraph AFTER["After (deprecated methods removed)"]
D1[Caller] -->|getI18nConfig directly| E1[I18nConfig]
D2[Caller] -->|lookupTranslation / loadTranslations / getLookupTranslation| E2[I18nCache active API]
end
```
</a>
</details>
<sub>Reviews (1): Last reviewed commit: ["refactor(gt-i18n): remove
deprecated
I18..."](35ba67c)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40687579)</sub>
<!-- /greptile_comment -->
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to odysseus, this PR will be updated.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ `odysseus` is currently in **pre mode** so this branch has prereleases rather than normal releases. If you want to exit prereleases, run `changeset pre exit` on `odysseus`.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ # Releases ## gt@2.14.51-odysseus.3 ### Patch Changes - Updated dependencies [b1eef00] - generaltranslation@9.0.0-odysseus.3 - @generaltranslation/python-extractor@0.2.23-odysseus.3 - @generaltranslation/supported-locales@2.1.2-odysseus.3 ## @generaltranslation/compiler@1.3.25-odysseus.3 ### Patch Changes - Updated dependencies [b1eef00] - generaltranslation@9.0.0-odysseus.3 ## generaltranslation@9.0.0-odysseus.3 ### Patch Changes - b1eef00: Remove the v8-era backwards-compatibility shim from `generaltranslation`. Deletes `src/backwards-compatability/` (`dataConversion`, `oldTypes`, `typeChecking`, `oldHashJsxChildren`) and its 26 re-exports from `generaltranslation/internal` — the old↔new JSX/variable-format converters, legacy type guards, and the legacy hashers. These had no consumers anywhere in the libraries; the old format they bridged is no longer produced. Safe to drop in the next major. ~477 LOC removed from the `/internal` entry. ## gtx-cli@2.14.51-odysseus.3 ### Patch Changes - gt@2.14.51-odysseus.3 ## gt-i18n@1.0.0-odysseus.3 ### Patch Changes - b765174: Remove three orphaned, never-imported files: - `gt-tanstack-start`: `condition-store/WritableConditionStore.ts` (an orphaned local copy; the package uses gt-i18n's writable condition store). - `gt-react-native`: `utils/utils.ts` (`readAuthFromEnv`, no consumers). - `gt-i18n`: `i18n-cache/translations-manager/utils/types/translations-manager.ts` (unreferenced `TranslationsManagerConfig` type). - Updated dependencies [b1eef00] - generaltranslation@9.0.0-odysseus.3 - @generaltranslation/supported-locales@2.1.2-odysseus.3 ## locadex@1.0.186-odysseus.3 ### Patch Changes - gt@2.14.51-odysseus.3 ## gt-next@11.0.0-odysseus.7 ### Patch Changes - Updated dependencies [b1eef00] - Updated dependencies [b765174] - Updated dependencies [07bfb00] - generaltranslation@9.0.0-odysseus.3 - gt-i18n@1.0.0-odysseus.3 - @generaltranslation/react-core@11.0.0-odysseus.7 - @generaltranslation/compiler@1.3.25-odysseus.3 - gt-react@11.0.0-odysseus.7 - @generaltranslation/supported-locales@2.1.2-odysseus.3 ## @generaltranslation/gt-next-lint@15.0.0-odysseus.7 ### Patch Changes - gt-next@11.0.0-odysseus.7 ## gt-node@1.0.0-odysseus.3 ### Patch Changes - Updated dependencies [b1eef00] - Updated dependencies [b765174] - generaltranslation@9.0.0-odysseus.3 - gt-i18n@1.0.0-odysseus.3 ## @generaltranslation/python-extractor@0.2.23-odysseus.3 ### Patch Changes - Updated dependencies [b1eef00] - generaltranslation@9.0.0-odysseus.3 ## gt-react@11.0.0-odysseus.7 ### Patch Changes - Updated dependencies [b1eef00] - Updated dependencies [b765174] - Updated dependencies [07bfb00] - generaltranslation@9.0.0-odysseus.3 - gt-i18n@1.0.0-odysseus.3 - @generaltranslation/react-core@11.0.0-odysseus.7 - @generaltranslation/supported-locales@2.1.2-odysseus.3 ## @generaltranslation/react-core@11.0.0-odysseus.7 ### Patch Changes - 07bfb00: Remove the unused dictionary-injection helpers from `@generaltranslation/react-core/pure`. `collectUntranslatedEntries`, `injectAndMerge`, `injectEntry`, `injectFallbacks`, `injectHashes`, `injectTranslations`, `getSubtree`, `getSubtreeWithCreation`, and `stripMetadataFromEntries` were a self-referential cluster with no consumers anywhere in the library or its packages. Removing them (and their modules/tests) trims ~415 LOC of dead code from the client-shipped `/pure` entry. The still-used dictionary helpers (`getDictionaryEntry`, `getEntryAndMetadata`, `mergeDictionaries`, `flattenDictionary`, `indexDict`, `isDictionaryEntry`) are unchanged. - Updated dependencies [b1eef00] - Updated dependencies [b765174] - generaltranslation@9.0.0-odysseus.3 - gt-i18n@1.0.0-odysseus.3 - @generaltranslation/supported-locales@2.1.2-odysseus.3 ## gt-react-native@11.0.0-odysseus.7 ### Patch Changes - b765174: Remove three orphaned, never-imported files: - `gt-tanstack-start`: `condition-store/WritableConditionStore.ts` (an orphaned local copy; the package uses gt-i18n's writable condition store). - `gt-react-native`: `utils/utils.ts` (`readAuthFromEnv`, no consumers). - `gt-i18n`: `i18n-cache/translations-manager/utils/types/translations-manager.ts` (unreferenced `TranslationsManagerConfig` type). - Updated dependencies [b1eef00] - Updated dependencies [b765174] - Updated dependencies [07bfb00] - generaltranslation@9.0.0-odysseus.3 - gt-i18n@1.0.0-odysseus.3 - @generaltranslation/react-core@11.0.0-odysseus.7 - @generaltranslation/supported-locales@2.1.2-odysseus.3 ## gt-sanity@2.0.18-odysseus.5 ### Patch Changes - Updated dependencies [b1eef00] - generaltranslation@9.0.0-odysseus.3 ## @generaltranslation/supported-locales@2.1.2-odysseus.3 ### Patch Changes - Updated dependencies [b1eef00] - generaltranslation@9.0.0-odysseus.3 ## gt-tanstack-start@11.0.0-odysseus.7 ### Patch Changes - b765174: Remove three orphaned, never-imported files: - `gt-tanstack-start`: `condition-store/WritableConditionStore.ts` (an orphaned local copy; the package uses gt-i18n's writable condition store). - `gt-react-native`: `utils/utils.ts` (`readAuthFromEnv`, no consumers). - `gt-i18n`: `i18n-cache/translations-manager/utils/types/translations-manager.ts` (unreferenced `TranslationsManagerConfig` type). - Updated dependencies [b1eef00] - Updated dependencies [b765174] - Updated dependencies [07bfb00] - generaltranslation@9.0.0-odysseus.3 - gt-i18n@1.0.0-odysseus.3 - @generaltranslation/react-core@11.0.0-odysseus.7 - gt-react@11.0.0-odysseus.7 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
`validateLocales` was defined but never wired into config validation
(which runs
`validateLoadTranslations`/`validateTranslationApi`/`validateDictionary`)
and has **zero consumers** anywhere (grep-verified). Deletes the file +
its test. gt-i18n builds and tests pass. Part of the odysseus dead-code
sweep.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR removes the `validateLocales` function and its test from
`gt-i18n` as part of a dead-code sweep. The function validated BCP 47
locale codes but was never wired into `validateConfig`, which only calls
`validateLoadTranslations`, `validateTranslationApi`, and
`validateDictionary`.
- Deletes `validateLocales.ts` and its accompanying Vitest test file —
confirmed zero consumers in the repo.
- Adds a patch-level changeset entry documenting the removal.
<details open><summary><h3>Confidence Score: 5/5</h3></summary>
Straightforward dead-code removal with no runtime impact — the deleted
function was never invoked by any code path.
The deleted file was never imported by validateConfig or any other
module; the grep confirms zero consumers remain. Removing it and its
test leaves the validation pipeline unchanged.
No files require special attention.
</details>
<details><summary><h3>Important Files Changed</h3></summary>
| Filename | Overview |
|----------|----------|
|
packages/i18n/src/i18n-cache/validation/config-validation/validateLocales.ts
| Dead-code validator deleted; confirmed it was never imported by
validateConfig or any other consumer. |
|
packages/i18n/src/i18n-cache/validation/config-validation/__tests__/validateLocales.test.ts
| Test file for the deleted validator removed; no orphaned references
remain. |
| .changeset/trim-i18n-validatelocales.md | Patch-level changeset entry
accurately describes the removal. |
</details>
<details><summary><h3>Flowchart</h3></summary>
<a href="#gh-light-mode-only">
```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[validateConfig] --> B[validateLoadTranslations]
A --> C[validateTranslationApi]
A --> D[validateDictionary]
E["validateLocales (deleted)"] -.->|"was never called"| A
style E stroke-dasharray: 5 5,color:#999,fill:#f9f9f9
```
</a>
<a href="#gh-dark-mode-only">
```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[validateConfig] --> B[validateLoadTranslations]
A --> C[validateTranslationApi]
A --> D[validateDictionary]
E["validateLocales (deleted)"] -.->|"was never called"| A
style E stroke-dasharray: 5 5,color:#999,fill:#f9f9f9
```
</a>
</details>
<sub>Reviews (1): Last reviewed commit: ["refactor(gt-i18n): remove
unused
validat..."](43fb20e)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40686819)</sub>
<!-- /greptile_comment -->
Removes 21 error/warning builders from `errors/createErrors.ts` that
have **zero consumers** anywhere (grep-verified each). ~155 LOC of dead
error-string code, some of which shipped to bundles. The 29 still-used
builders are unchanged. gt-next builds; 191 tests pass. Part of the
odysseus dead-code sweep.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR removes 21 dead error/warning builder functions from
`packages/next/src/errors/createErrors.ts` (~155 LOC), along with the
now-unused `formatDiagnosticErrorDetails` import. The 29 remaining
builders are untouched and the changeset is correctly scoped as a patch.
- **Dead code removed**: 21 exported functions
(`createDictionaryTranslationError`, `gtProviderUseClientError`,
`noInitGTWarn`, `runtimeTranslationTimeoutWarning`, and 17 others) that
had zero consumers in the repo were deleted.
- **Import cleaned up**: `formatDiagnosticErrorDetails` was the only
import whose sole callers (`createStringRenderError` /
`createStringRenderWarning`) were among the deleted functions; it was
correctly removed in the same commit.
<details open><summary><h3>Confidence Score: 5/5</h3></summary>
Pure dead-code removal with no changes to active error paths; safe to
merge.
Every deleted symbol was confirmed to have zero consumers, the unused
import was correctly cleaned up in the same commit, and the 29
still-used builders are untouched.
No files require special attention.
</details>
<details><summary><h3>Important Files Changed</h3></summary>
| Filename | Overview |
|----------|----------|
| packages/next/src/errors/createErrors.ts | Removes 21 unused exported
error/warning builders and the now-orphaned
`formatDiagnosticErrorDetails` import; all 29 remaining builders and
their consumers are unchanged. |
| .changeset/trim-next-createerrors.md | Correct patch-level changeset
enumerating all 21 removed symbols; no issues. |
</details>
<details><summary><h3>Flowchart</h3></summary>
<a href="#gh-light-mode-only">
```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[createErrors.ts\n29 remaining builders] --> B[createGtNextDiagnostic]
A --> C[createGtNextPluginDiagnostic]
B --> D[diagnostics.ts]
C --> D
DEL["❌ Removed — 21 unused builders\n(createStringRenderError, gtProviderUseClientError,\nnoInitGTWarn, runtimeTranslationTimeoutWarning,\ncreateStringRenderWarning, dictionaryDisabledError,\ncreateTranslationLoadingWarning, … +14 more)"]
DEL -. was calling .-> FMT["❌ formatDiagnosticErrorDetails\n(import also removed)"]
FMT -. was imported from .-> D
```
</a>
<a href="#gh-dark-mode-only">
```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[createErrors.ts\n29 remaining builders] --> B[createGtNextDiagnostic]
A --> C[createGtNextPluginDiagnostic]
B --> D[diagnostics.ts]
C --> D
DEL["❌ Removed — 21 unused builders\n(createStringRenderError, gtProviderUseClientError,\nnoInitGTWarn, runtimeTranslationTimeoutWarning,\ncreateStringRenderWarning, dictionaryDisabledError,\ncreateTranslationLoadingWarning, … +14 more)"]
DEL -. was calling .-> FMT["❌ formatDiagnosticErrorDetails\n(import also removed)"]
FMT -. was imported from .-> D
```
</a>
</details>
<!-- greptile_failed_comments -->
<details open><summary><h3>Comments Outside Diff (1)</h3></summary>
1. `packages/next/src/errors/createErrors.ts`, line 4-8
([link](https://github.com/generaltranslation/gt/blob/3d7fd6cda7f5364f90381634aa4975fa717c1616/packages/next/src/errors/createErrors.ts#L4-L8))
<a href="#"><img alt="P2"
src="https://greptile-static-assets.s3.amazonaws.com/badges/p2.svg?v=9"
align="top"></a> The `formatDiagnosticErrorDetails` import is now
unused. The only two callers — `createStringRenderError` and
`createStringRenderWarning` — were both removed in this PR, leaving the
import as dead code. TypeScript (and any lint rule for `no-unused-vars`)
will flag this.
<details><summary>Prompt To Fix With AI</summary>
`````markdown
This is a comment left during a code review.
Path: packages/next/src/errors/createErrors.ts
Line: 4-8
Comment:
The `formatDiagnosticErrorDetails` import is now unused. The only two
callers — `createStringRenderError` and `createStringRenderWarning` —
were both removed in this PR, leaving the import as dead code.
TypeScript (and any lint rule for `no-unused-vars`) will flag this.
How can I resolve this? If you propose a fix, please make it concise.
`````
</details>
<a
href="https://app.greptile.com/ide/claude-code?prompt=This%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20packages%2Fnext%2Fsrc%2Ferrors%2FcreateErrors.ts%0ALine%3A%204-8%0A%0AComment%3A%0AThe%20%60formatDiagnosticErrorDetails%60%20import%20is%20now%20unused.%20The%20only%20two%20callers%20%E2%80%94%20%60createStringRenderError%60%20and%20%60createStringRenderWarning%60%20%E2%80%94%20were%20both%20removed%20in%20this%20PR%2C%20leaving%20the%20import%20as%20dead%20code.%20TypeScript%20%28and%20any%20lint%20rule%20for%20%60no-unused-vars%60%29%20will%20flag%20this.%0A%0A%60%60%60suggestion%0Aimport%20%7B%0A%20%20createGtNextDiagnostic%2C%0A%20%20createGtNextPluginDiagnostic%2C%0A%7D%20from%20'.%2Fdiagnostics'%3B%0A%60%60%60%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=generaltranslation%2Fgt&pr=1707&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaudeDark.svg?v=3"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=3"><img
alt="Fix in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=3"
height="20"></picture></a> <a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22generaltranslation%2Fgt%22%20on%20the%20existing%20branch%20%22bg%2Fodysseus-trim-next-createerrors%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22bg%2Fodysseus-trim-next-createerrors%22.%0A%0AThis%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20packages%2Fnext%2Fsrc%2Ferrors%2FcreateErrors.ts%0ALine%3A%204-8%0A%0AComment%3A%0AThe%20%60formatDiagnosticErrorDetails%60%20import%20is%20now%20unused.%20The%20only%20two%20callers%20%E2%80%94%20%60createStringRenderError%60%20and%20%60createStringRenderWarning%60%20%E2%80%94%20were%20both%20removed%20in%20this%20PR%2C%20leaving%20the%20import%20as%20dead%20code.%20TypeScript%20%28and%20any%20lint%20rule%20for%20%60no-unused-vars%60%29%20will%20flag%20this.%0A%0A%60%60%60suggestion%0Aimport%20%7B%0A%20%20createGtNextDiagnostic%2C%0A%20%20createGtNextPluginDiagnostic%2C%0A%7D%20from%20'.%2Fdiagnostics'%3B%0A%60%60%60%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=generaltranslation%2Fgt&pr=1707&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodexDark.svg?v=3"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=3"><img
alt="Fix in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=3"
height="20"></picture></a>
</details>
<!-- /greptile_failed_comments -->
<sub>Reviews (2): Last reviewed commit: ["refactor(gt-next): drop
now-unused
forma..."](646c8b8)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40687204)</sub>
<!-- /greptile_comment -->
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to odysseus, this PR will be updated.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ `odysseus` is currently in **pre mode** so this branch has prereleases rather than normal releases. If you want to exit prereleases, run `changeset pre exit` on `odysseus`.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ # Releases ## gt@2.14.51-odysseus.4 ### Patch Changes - Updated dependencies [26faa87] - generaltranslation@9.0.0-odysseus.4 - @generaltranslation/python-extractor@0.2.23-odysseus.4 - @generaltranslation/supported-locales@2.1.2-odysseus.4 ## @generaltranslation/compiler@1.3.25-odysseus.4 ### Patch Changes - Updated dependencies [26faa87] - generaltranslation@9.0.0-odysseus.4 ## generaltranslation@9.0.0-odysseus.4 ### Patch Changes - 26faa87: Remove the unused `hashTemplate` export from `generaltranslation/id`. It had no consumers anywhere in the libraries. `hashSource`/`hashString` are unchanged. ## gtx-cli@2.14.51-odysseus.4 ### Patch Changes - gt@2.14.51-odysseus.4 ## gt-i18n@1.0.0-odysseus.4 ### Patch Changes - 270b821: Remove the unused `condition-store/localeResolver` module from `gt-i18n/internal`. `determineSupportedLocale`, `resolveSupportedLocale`, and `createLocaleResolver` were thin wrappers over `getI18nConfig().<method>()`. They had no consumers — callers (e.g. tanstack-start) use the `I18nConfig` methods directly via `getI18nConfig()`. Removing the module trims dead indirection from the `/internal` entry; the `LocaleCandidates` type re-export is unaffected (re-exported from its real source). - bffaa67: Remove the unused `validateLocales` config validator from `gt-i18n`. `validateLocales` was defined but never called (config validation runs `validateLoadTranslations`, `validateTranslationApi`, and `validateDictionary`) and had no consumers anywhere. Dead code removed. - d602065: Remove deprecated methods from `gt-i18n`'s `I18nCache`. Dropped the long-`@deprecated` cache methods that duplicated `I18nConfig`/loader APIs: `getDefaultLocale`, `getLocales`, `getCustomMapping`, `getGTClass`, `getTranslationLoader`, `resolveTranslationSync`, `getTranslations`, and `getTranslationResolver`. None were called anywhere (consumers use `getI18nConfig()` / `lookupTranslation` / `loadTranslations`). Removes the methods, their now-unused imports, and the tests that covered them. - Updated dependencies [26faa87] - generaltranslation@9.0.0-odysseus.4 - @generaltranslation/supported-locales@2.1.2-odysseus.4 ## locadex@1.0.186-odysseus.4 ### Patch Changes - gt@2.14.51-odysseus.4 ## gt-next@11.0.0-odysseus.8 ### Patch Changes - Updated dependencies [26faa87] - Updated dependencies [270b821] - Updated dependencies [bffaa67] - Updated dependencies [d602065] - Updated dependencies [6da26e8] - generaltranslation@9.0.0-odysseus.4 - gt-i18n@1.0.0-odysseus.4 - @generaltranslation/react-core@11.0.0-odysseus.8 - @generaltranslation/compiler@1.3.25-odysseus.4 - gt-react@11.0.0-odysseus.8 - @generaltranslation/supported-locales@2.1.2-odysseus.4 ## @generaltranslation/gt-next-lint@15.0.0-odysseus.8 ### Patch Changes - gt-next@11.0.0-odysseus.8 ## gt-node@1.0.0-odysseus.4 ### Patch Changes - Updated dependencies [26faa87] - Updated dependencies [270b821] - Updated dependencies [bffaa67] - Updated dependencies [d602065] - generaltranslation@9.0.0-odysseus.4 - gt-i18n@1.0.0-odysseus.4 ## @generaltranslation/python-extractor@0.2.23-odysseus.4 ### Patch Changes - Updated dependencies [26faa87] - generaltranslation@9.0.0-odysseus.4 ## gt-react@11.0.0-odysseus.8 ### Patch Changes - Updated dependencies [26faa87] - Updated dependencies [270b821] - Updated dependencies [bffaa67] - Updated dependencies [d602065] - Updated dependencies [6da26e8] - generaltranslation@9.0.0-odysseus.4 - gt-i18n@1.0.0-odysseus.4 - @generaltranslation/react-core@11.0.0-odysseus.8 - @generaltranslation/supported-locales@2.1.2-odysseus.4 ## @generaltranslation/react-core@11.0.0-odysseus.8 ### Patch Changes - 6da26e8: Remove three unused exports from `@generaltranslation/react-core/pure`: `isVariableObject`, `renderSkeleton`, and `reactHasUse`. None had consumers anywhere in the libraries. Trims dead code from the client-shipped `/pure` entry. - Updated dependencies [26faa87] - Updated dependencies [270b821] - Updated dependencies [bffaa67] - Updated dependencies [d602065] - generaltranslation@9.0.0-odysseus.4 - gt-i18n@1.0.0-odysseus.4 - @generaltranslation/supported-locales@2.1.2-odysseus.4 ## gt-react-native@11.0.0-odysseus.8 ### Patch Changes - Updated dependencies [26faa87] - Updated dependencies [270b821] - Updated dependencies [bffaa67] - Updated dependencies [d602065] - Updated dependencies [6da26e8] - generaltranslation@9.0.0-odysseus.4 - gt-i18n@1.0.0-odysseus.4 - @generaltranslation/react-core@11.0.0-odysseus.8 - @generaltranslation/supported-locales@2.1.2-odysseus.4 ## gt-sanity@2.0.18-odysseus.6 ### Patch Changes - Updated dependencies [26faa87] - generaltranslation@9.0.0-odysseus.4 ## @generaltranslation/supported-locales@2.1.2-odysseus.4 ### Patch Changes - Updated dependencies [26faa87] - generaltranslation@9.0.0-odysseus.4 ## gt-tanstack-start@11.0.0-odysseus.8 ### Patch Changes - Updated dependencies [26faa87] - Updated dependencies [270b821] - Updated dependencies [bffaa67] - Updated dependencies [d602065] - Updated dependencies [6da26e8] - generaltranslation@9.0.0-odysseus.4 - gt-i18n@1.0.0-odysseus.4 - @generaltranslation/react-core@11.0.0-odysseus.8 - gt-react@11.0.0-odysseus.8 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to odysseus, this PR will be updated.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ `odysseus` is currently in **pre mode** so this branch has prereleases rather than normal releases. If you want to exit prereleases, run `changeset pre exit` on `odysseus`.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ # Releases ## gt-next@11.0.0-odysseus.9 ### Patch Changes - cf3e961: Remove 21 unused error/warning builders from `gt-next`'s `errors/createErrors.ts`. The following had no consumers anywhere: `createDictionaryTranslationError`, `createInvalidDictionaryEntryWarning`, `createInvalidDictionaryTranslationEntryWarning`, `createInvalidIcuDictionaryEntryError`, `createInvalidIcuDictionaryEntryWarning`, `createMismatchingHashWarning`, `createNoEntryFoundWarning`, `createRequiredPrefixError`, `createStringRenderError`, `createStringRenderWarning`, `createStringTranslationError`, `createTranslationLoadingWarning`, `dictionaryDisabledError`, `dictionaryNotFoundWarning`, `gtProviderUseClientError`, `missingVariablesError`, `noInitGTWarn`, `runtimeTranslationTimeoutWarning`, `txUseClientError`, `unresolvedGetLocaleBuildError`, `usingDefaultsWarning`. ~155 LOC of dead error-string code removed. - @generaltranslation/react-core@11.0.0-odysseus.9 - gt-react@11.0.0-odysseus.9 ## @generaltranslation/gt-next-lint@15.0.0-odysseus.9 ### Patch Changes - Updated dependencies [cf3e961] - gt-next@11.0.0-odysseus.9 ## gt-react@11.0.0-odysseus.9 ### Patch Changes - @generaltranslation/react-core@11.0.0-odysseus.9 ## gt-react-native@11.0.0-odysseus.9 ### Patch Changes - @generaltranslation/react-core@11.0.0-odysseus.9 ## gt-tanstack-start@11.0.0-odysseus.9 ### Patch Changes - @generaltranslation/react-core@11.0.0-odysseus.9 - gt-react@11.0.0-odysseus.9 ## @generaltranslation/react-core@11.0.0-odysseus.9 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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
gt-i18ninternalsgt-i18n/internalexceptcreateLookupOptionsgt-i18n/fallbackspackage entrypoint while keeping fallback functions on the main entrypointTesting
pnpm --filter gt-i18n testpnpm buildpnpm lintNo changeset added per request.
Greptile Summary
This PR cleans up the
gt-i18npackage by removing two redundant public API surfaces: thegt-i18n/fallbackssub-entrypoint (whose exports already live on the main index) and the six resolve-helper function exports fromgt-i18n/internal. The change is internally consistent across all affected layers — build config,package.jsonexports, source files, and tests all align.src/fallbacks.tsand all references to the./fallbacksentrypoint;gtFallbackandmFallbackremain accessible via the maingt-i18nimport.gt-i18n/internalto export onlycreateLookupOptionsfromhelpers.ts;resolveJsxandresolveJsxWithFallbackare fully removed from source, while the remaining resolve helpers are kept as package-internal utilities.fallbacks.Confidence Score: 5/5
Safe to merge — all changes are removals of redundant or unused exports, and every layer (build config, package.json, source, tests) is updated consistently.
The diff is a pure subtraction: no new logic is introduced, the deleted functions were unused externally, and the fallback functions remain accessible on the main entrypoint. The build config, exports map, size-limit config, and test file all agree with the source changes.
No files require special attention.
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD subgraph Before A[gt-i18n] -->|main index| B[gtFallback / mFallback / t / msg / ...] A -->|gt-i18n/fallbacks| C[gtFallback / mFallback] A -->|gt-i18n/internal| D[createLookupOptions\nresolveJsx\nresolveJsxWithFallback\nresolveJsxWithRuntimeFallback\nresolveStringContent\nresolveStringContentWithFallback\nresolveStringContentWithRuntimeFallback\n...] end subgraph After E[gt-i18n] -->|main index| F[gtFallback / mFallback / t / msg / ...] E -->|gt-i18n/internal| G[createLookupOptions\n...] end%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% flowchart TD subgraph Before A[gt-i18n] -->|main index| B[gtFallback / mFallback / t / msg / ...] A -->|gt-i18n/fallbacks| C[gtFallback / mFallback] A -->|gt-i18n/internal| D[createLookupOptions\nresolveJsx\nresolveJsxWithFallback\nresolveJsxWithRuntimeFallback\nresolveStringContent\nresolveStringContentWithFallback\nresolveStringContentWithRuntimeFallback\n...] end subgraph After E[gt-i18n] -->|main index| F[gtFallback / mFallback / t / msg / ...] E -->|gt-i18n/internal| G[createLookupOptions\n...] endReviews (1): Last reviewed commit: "fix: remove unused gt-i18n internal entr..." | Re-trigger Greptile