Skip to content

refactor(next): use built-in Pages Router i18n - #2004

Merged
eoinest merged 6 commits into
mainfrom
e/next/refactor-nextjs-pages
Jul 29, 2026
Merged

refactor(next): use built-in Pages Router i18n#2004
eoinest merged 6 commits into
mainfrom
e/next/refactor-nextjs-pages

Conversation

@eoinest

@eoinest eoinest commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • delegate Pages Router locale-prefixed routing and active-locale resolution to Next.js while retaining the deprecated request detector as a compatibility fallback until the next major version
  • preserve the user-owned i18n object and configure GT to use NEXT_LOCALE only when Next.js locale detection is enabled
  • keep GTProvider unchanged and document the application-owned _reload callback for locale-aware Pages Router navigation
  • preserve explicit locale and translation props, with App Router middleware and provider behavior unchanged

Testing

  • pnpm --filter gt-next test:js — passed, 265 tests
  • pnpm --filter gt-next typecheck
  • pnpm --filter next-pages-router typecheck
  • pnpm --filter gt-test-next-pages-router typecheck
  • pnpm --filter gt-test-apps-e2e typecheck
  • pnpm exec oxlint packages/next/src/config.ts packages/next/src/__tests__/config.test.ts examples/next-pages-router/src/pages/_app.tsx tests/apps/next-pages-router/pages/_app.tsx tests/apps/test-apps-e2e/e2e/app.spec.ts
  • pnpm --filter gt-next build:no-swc-plugin
  • pnpm --filter next-pages-router exec next build — Next.js 15 SSG passed
  • pnpm --filter gt-test-next-pages-router build — Next.js 16 Pages Router passed
  • GT_TEST_APPS=next-pages-router pnpm --filter gt-test-apps-e2e test:e2e — locale routes, html lang, translations, and NEXT_LOCALE passed
  • pnpm --filter gt-test-next-app-router build — App Router passed
  • pnpm check:library-defaults

Notes

  • Next.js treats omitted localeDetection as enabled; localeDetection: false preserves the existing GT cookie configuration.
  • Changeset: patch release for gt-next.

Greptile Summary

This PR delegates Pages Router locale resolution and URL routing to Next.js built-in i18n, replacing gt-next's own request-based locale detection as the primary mechanism while keeping the old detector as a compatibility fallback. The App Router, GTProvider, and middleware paths are untouched.

  • withGTConfig now overrides localeCookieName to NEXT_LOCALE when i18n.localeDetection is enabled (the Next.js default), aligning GT's client-side persistence with the router's own cookie.
  • parseLocale and withGTStaticProps prefer context.locale injected by Next.js; resolvePagesRouterLocale provides a graceful fallback to context.defaultLocale with a warning when context.locale is absent.
  • The example and test apps are migrated from gt-react to gt-next, adding i18n config to next.config.ts and an application-owned _reload callback to _app.tsx for locale navigation.

Confidence Score: 5/5

Safe to merge; all locale-resolution paths are covered by unit and E2E tests and the core library logic is correct.

The locale-priority change (context.locale → legacy fallback) is well-tested across getStaticProps and getServerSideProps paths, and the cookie-name override to NEXT_LOCALE is intentional and verified. No logic errors, data-loss scenarios, or auth-boundary issues were found in the changed code.

Files Needing Attention: packages/next/src/config.ts — the NEXT_LOCALE cookie-name override silently discards user-supplied custom cookie names when locale detection is enabled; may warrant a build-time notice for clarity.

Important Files Changed

Filename Overview
packages/next/src/config.ts Adds nextLocaleDetectionEnabled check that silently overrides localeCookieName to NEXT_LOCALE whenever Next.js locale detection is enabled, taking priority over any user-supplied cookie name.
packages/next/src/pages-dir/parseLocale.ts Refactored to prefer context.locale from Next.js i18n routing over legacy request detection; adds resolvePagesRouterLocale for static-props use; retains legacy detector as deprecated fallback. Logic and warnings look correct.
packages/next/src/pages-dir/withGTStaticProps.ts Error guard relaxed from !context.locale to !context.locale && !context.defaultLocale, allowing graceful fallback via resolvePagesRouterLocale when only defaultLocale is available; correct and well-tested.
packages/next/src/utils/cookies.ts Adds nextLocaleCookieName = 'NEXT_LOCALE' constant with correct documentation link; minimal and correct.
packages/next/src/errors/ssg.ts Adds createMissingPagesRouterLocaleWarning that correctly reports the resolved (post-fallback) locale, addressing the previously noted warning-accuracy concern.
packages/next/src/pages-dir/tests/parseLocale.test.ts Comprehensive test coverage for new context.locale priority, legacy fallback paths, unsupported locales, and alias handling; also validates the fixed warning-message accuracy for the unsupported defaultLocale case.
tests/apps/next-pages-router/pages/_app.tsx Adds _reload callback for locale-aware navigation; Component {...pageProps} now forwards locale, translations, and enableI18n to every page component rather than stripping them.
packages/next/src/tests/config.test.ts New tests cover NEXT_LOCALE cookie override when locale detection is enabled, cookie preservation when detection is disabled, and i18n config passthrough — all correctly aligned with the implementation.
tests/apps/test-apps-e2e/e2e/app.spec.ts E2E tests extended to verify locale URL prefix, html lang attribute, NEXT_LOCALE cookie presence, and translation rendering after locale switch; coverage looks solid.

Sequence Diagram

sequenceDiagram
    participant NextJs as Next.js Router
    participant getStaticProps as withGTStaticProps / withGTServerSideProps
    participant parseLocale as parseLocale / resolvePagesRouterLocale
    participant GTProvider as GTProvider (_app.tsx)
    participant Cookie as NEXT_LOCALE cookie

    NextJs->>getStaticProps: "context { locale, defaultLocale }"
    alt context.locale is set (i18n enabled)
        getStaticProps->>parseLocale: resolvePagesRouterLocale(context)
        parseLocale-->>getStaticProps: returns context.locale (validated)
    else context.locale undefined, defaultLocale set (legacy fallback)
        getStaticProps->>parseLocale: resolvePagesRouterLocale(context)
        parseLocale-->>getStaticProps: returns resolved defaultLocale + emits warning
    else both undefined
        getStaticProps-->>NextJs: throws withGTStaticPropsLocaleRoutingError
    end

    getStaticProps-->>GTProvider: "pageProps { locale, translations }"
    GTProvider->>Cookie: writes NEXT_LOCALE (when localeDetection enabled)
    GTProvider-->>NextJs: "_reload({ locale }) → Router.push(pathname, asPath, { locale })"
    NextJs->>NextJs: "navigates to /<locale>/path, updates NEXT_LOCALE cookie"
Loading

Reviews (4): Last reviewed commit: "docs(next): remove Pages Router migratio..." | Re-trigger Greptile

@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size
generaltranslation 18.03 KB (0%)
generaltranslation/runtime 14.93 KB (0%)
generaltranslation/id 2.55 KB (0%)
generaltranslation/internal 7.38 KB (0%)
generaltranslation/types 89 B (0%)
generaltranslation/errors 81 B (0%)
@generaltranslation/format 9.5 KB (0%)
@generaltranslation/format/types 89 B (0%)
@generaltranslation/format/internal 880 B (0%)
gt-i18n 11.91 KB (0%)
gt-i18n/types 13 B (0%)
gt-i18n/internal 22.46 KB (0%)
gt-i18n/internal/types 13 B (0%)
@generaltranslation/react-core/pure 25.59 KB (0%)
@generaltranslation/react-core/hooks 20.61 KB (0%)
@generaltranslation/react-core/components 22.81 KB (0%)
@generaltranslation/react-core/components-rsc 26.16 KB (0%)
gt-react (client) 32.02 KB (0%)
gt-react (rsc) 28.67 KB (0%)
gt-react (server) 31.65 KB (0%)
gt-react/macros 8.86 KB (0%)
gt-next (client) 43.74 KB (0%)
gt-next (rsc) 47.62 KB (+0.22% 🔺)
gt-next (server) 43.91 KB (+0.52% 🔺)
gt-next/config 269.68 KB (-0.03% 🔽)
gt-next/server 46.15 KB (+0.2% 🔺)
gt-next/middleware 36.38 KB (-0.03% 🔽)
gt-next/link 42.59 KB (0%)
gt-next/internal/_dictionary 144 B (0%)
gt-next/internal/_load-translations 144 B (0%)
gt-next/internal/_load-dictionary 144 B (0%)
gt-next/internal/_getLocale 125 B (0%)
gt-next/internal/_getRegion 122 B (0%)
gt-node 23.54 KB (0%)
gt-node/types 219 B (0%)
gt-node/internal 13.47 KB (0%)
gt-tanstack-start (client) 31.58 KB (0%)
gt-tanstack-start (server) 32.06 KB (0%)
gt-tanstack-start/server 10.27 KB (0%)
gt-react-native 30.05 KB (0%)
gt-react-native/plugin 4.62 KB (0%)
gt-react-native/internal 746 B (0%)

@eoinest

eoinest commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

@greptileai

Comment thread packages/next/src/pages-dir/parseLocale.ts
Comment thread packages/next/src/pages-dir/GTProvider.tsx Outdated
@linear-code

linear-code Bot commented Jul 29, 2026

Copy link
Copy Markdown

GEN-743

@eoinest

eoinest commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

@greptileai

@eoinest

eoinest commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

@greptileai

@eoinest

eoinest commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

@greptileai

@eoinest
eoinest enabled auto-merge (squash) July 29, 2026 23:05

@fernando-aviles fernando-aviles left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lgtm

@eoinest
eoinest merged commit e54d376 into main Jul 29, 2026
28 checks passed
@eoinest
eoinest deleted the e/next/refactor-nextjs-pages branch July 29, 2026 23:13
@github-actions github-actions Bot mentioned this pull request Jul 29, 2026
eoinest pushed a commit that referenced this pull request Jul 29, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## gt-next@11.1.3

### Patch Changes

- [#2004](#2004)
[`e54d376`](e54d376)
Thanks [@eoinest](https://github.com/eoinest)! - Delegate Pages Router
locale routing and active-locale resolution to Next.js internationalized
routing. Pages data wrappers prefer `context.locale` while retaining the
previous request detector as a compatibility fallback, `withGTConfig`
selects `NEXT_LOCALE` when Next.js locale detection is enabled, and
applications can navigate with the Pages Router locale option through
the existing provider reload callback. App Router middleware and
`GTProvider` behavior are unchanged.

- Updated dependencies []:
  - @generaltranslation/react-core@11.1.3
  - gt-react@11.1.3
## gt-react@11.1.3

### Patch Changes

- Updated dependencies []:
  - @generaltranslation/react-core@11.1.3
## gt-react-native@11.1.3

### Patch Changes

- Updated dependencies []:
  - @generaltranslation/react-core@11.1.3
## gt-tanstack-start@11.1.3

### Patch Changes

- Updated dependencies []:
  - @generaltranslation/react-core@11.1.3
  - gt-react@11.1.3
## @generaltranslation/react-core@11.1.3

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
eoinest added a commit that referenced this pull request Jul 30, 2026
## Summary

- Warn when explicitly configured `defaultLocale` or `locales` values in
the GT config file differ from Next.js internationalized routing.
- Compare locale lists without treating order as a mismatch, and leave
the user-owned Next.js `i18n` configuration unchanged.

## Testing

- `pnpm --filter gt-next test:js` — passed (25 files, 268 tests)
- `pnpm --filter gt-next typecheck` — passed
- `pnpm --filter gt-next build:no-swc-plugin` — passed
- `pnpm exec oxlint packages/next/src/config.ts
packages/next/src/errors/createErrors.ts
packages/next/src/__tests__/config.test.ts` — passed
- `pnpm exec oxfmt --check packages/next/src/config.ts
packages/next/src/errors/createErrors.ts
packages/next/src/__tests__/config.test.ts
.changeset/next-i18n-config-mismatch-warning.md` — passed

## Notes

- Stacked on `e/next/refactor-nextjs-pages` / #2004.
- Changeset: added a patch changeset for `gt-next`.

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR adds a build-time advisory warning when locale settings in the
GT config file (`gt.config.json`) diverge from Next.js's built-in
internationalized routing config (`i18n.defaultLocale` /
`i18n.locales`). The comparison is order-independent,
deduplication-safe, and accounts for GT's own normalization that
prepends `defaultLocale` into the effective locale set.

- Adds `getNextI18nConfigMismatches` (private) and `haveSameLocales`
helpers in `config.ts`, with the check deliberately scoped to
file-loaded config only (inline `props` continue through existing
conflict/merge paths).
- Adds `createNextI18nConfigMismatchWarning` to the diagnostic helpers
in `createErrors.ts` and wires it in just after the GT config file is
loaded, before environment variables are resolved.
- Covers the new paths with five focused tests (mismatch fires,
order-safe, defaultLocale-omitted-from-locales, deduplication, no-i18n
guard).

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

Safe to merge — the change is purely additive, emitting an advisory
console warning at build time without modifying any runtime behavior or
Next.js config output.

The new mismatch-detection logic is well-scoped (file-loaded config
only), order-independent, and correctly normalizes the GT locale set
before comparison. Previous review thread concerns (false-positive when
defaultLocale is omitted from locales, duplicate deduplication,
inline-props scope) are all addressed with tests. No runtime paths are
affected.

**Files Needing Attention:** No files require special attention.
</details>

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

| Filename | Overview |
|----------|----------|
| packages/next/src/config.ts | Adds getNextI18nConfigMismatches and
haveSameLocales helpers; wires warning after GT config file load. Logic
correctly handles order-independence, defaultLocale prepend, and
deduplication edge cases. |
| packages/next/src/errors/createErrors.ts | Adds
createNextI18nConfigMismatchWarning using the existing plugin diagnostic
format; consistent with other warnings in the file. |
| packages/next/src/__tests__/config.test.ts | Adds five targeted tests
covering: mismatch detection, order-independence, defaultLocale prepend
normalization, duplicate deduplication, and no-i18n guard. All
regression cases from previous review threads are covered. |
| .changeset/next-i18n-config-mismatch-warning.md | Patch changeset for
gt-next, correctly categorized as non-breaking user-visible change. |

</details>

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

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[withGTConfig called] --> B[Load GT config file]
    B --> C{internalNextConfig.i18n present?}
    C -- No --> E[Skip mismatch check]
    C -- Yes --> D[getNextI18nConfigMismatches]
    D --> F{gtConfig.defaultLocale !== undefined AND !== nextI18n.defaultLocale?}
    F -- Yes --> G[Push defaultLocale mismatch string]
    F -- No --> H
    G --> H{gtConfig.locales !== undefined AND haveSameLocales returns false?}
    H -- Yes --> I[Push locales mismatch string]
    H -- No --> J
    I --> J{mismatches.length > 0?}
    G --> J
    J -- Yes --> K[console.warn with createNextI18nConfigMismatchWarning]
    J -- No --> L[Continue build normally]
    E --> L
    K --> L
```
</details>

<sub>Reviews (3): Last reviewed commit: ["chore: merge latest main into
i18n
confi..."](33c5718)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=48518447)</sub>

<!-- /greptile_comment -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants