## Summary
- Resolve the `NEXT_LOCALE` cookie case-insensitively and return the
canonical configured locale (e.g. `NEXT_LOCALE=EN-US` -> `en-US`).
- Add unit tests covering uppercase/mixed-case cookies, exact-case, and
non-configured values.
## Root Cause
`parseCookieLocaleFromHeader` matched the cookie value against
`i18nConfig.locales` with a case-sensitive `Array.includes`. A cookie like
`NEXT_LOCALE=EN-US` therefore failed to match a configured `en-US`, so the
sticky locale was silently dropped and locale detection fell through to the
default. Next.js's `getLocaleFromCookie` lowercases the cookie value and
finds the configured locale case-insensitively, returning the canonical
form; vinext now mirrors that.
## References
- Next.js: packages/next/src/shared/lib/i18n/get-locale-redirect.ts
(`getLocaleFromCookie`).
- Next.js test: test/e2e/i18n-support/shared.ts (`addDefaultLocaleCookie`
sets `NEXT_LOCALE=EN-US` "to ensure it's case-insensitive").
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(i18n): strip locale prefix for API routes
Mirror Next.js's behaviour where a locale-prefixed request path like
`/fr/api/ok` is matched against `pages/api/ok` after stripping the
locale segment. Previously the locale prefix was kept through the
`/api/` startsWith check, so any locale-prefixed API URL 404'd.
Add a small helper `stripI18nLocaleForApiRoute(url, i18nConfig)` in
`server/pages-i18n.ts` that mirrors Next.js's
`normalizeLocalePath().pathname` (see
packages/next/src/shared/lib/i18n/normalize-locale-path.ts) and wire it
into all three Pages Router request pipelines so dev/prod parity holds:
- dev plugin: `packages/vinext/src/index.ts`
- prod (Node): `packages/vinext/src/server/prod-server.ts`
- prod (Cloudflare worker entry): `packages/vinext/src/deploy.ts`
App Router is intentionally unchanged: Next.js does not support the
`i18n` config field with App Router, so App Router route handlers
under `app/*/route.ts` never see a locale prefix to strip.
Refs #1336 (item 3). Items 2 (sticky locale on client navigations) and
4 (default-locale path normalisation) are being handled in parallel
PRs.
Tests:
- Unit tests for `stripI18nLocaleForApiRoute` covering basic, regional
(`nl-NL`), query-preserving, unconfigured-prefix, and null-config
cases (`tests/pages-i18n.test.ts`).
- Dev integration tests (`tests/features.test.ts`) and prod integration
tests (`tests/pages-i18n-prod.test.ts`) that GET `/fr/api/ok` and
assert a 200 "ok" response against the existing
`pages-i18n-domains` fixture, ported from Next.js's
`test/e2e/middleware-redirects/test/index.test.ts` ("should redirect
to api route with locale").
- Updates to `tests/deploy.test.ts` assertions for the generated
worker-entry template strings.
* test(after-deploy): update worker-entry assertion after locale strip
The Pages Router worker entry now calls handleApiRoute(request,
apiLookupUrl, ctx) instead of using resolvedUrl directly, so this
generated-code assertion needs the new variable name.
Refs #1336 (item 3).
* chore: migrate to vite plus
* Disable typeAware and typeCheck
* Update CI
* Fix CI
* Fix test
* Clean
* Run test with vp
* Try revert
* react: false In test
* Fix test
* Revert "Try revert"
This reverts commit 009da10473.
* Update
* Update
* Try revert ci changes
* revert
* Run vp migrate
* Disable typeAware and typeCheck for now
* Better resolve for test
* Use vp dev instead of vite
* Update expect
* Fix NormalizeManifestModuleId
* Try increase timeout
* Update to use vp
* Try new check
* Bring back npx vp
* Migrate CI
* Make next-intl resolvable
* Update
* Update
* Update