Skip to content

fix(next/routing): compare i18n domains by hostname when redirecting - #97005

Draft
yogesh968 wants to merge 1 commit into
vercel:canaryfrom
yogesh968:fix/routing-locale-domain-compare
Draft

fix(next/routing): compare i18n domains by hostname when redirecting#97005
yogesh968 wants to merge 1 commit into
vercel:canaryfrom
yogesh968:fix/routing-locale-domain-compare

Conversation

@yogesh968

Copy link
Copy Markdown

What?

A locale redirect for an i18n domain configured with a port sent the user to the wrong scheme. A request to http://example.de:3000/ with domains: [{ domain: 'example.de:3000', defaultLocale: 'de', locales: ['de', 'fr'] }] and Accept-Language: fr redirected to https://example.de:3000/fr/ instead of staying on http.

Why?

Two places compared the configured domain against the request hostname, but only one of them normalized:

  • detectDomainLocale strips the port and lowercases before matching, so it correctly resolved example.de:3000 for the example.de host we were already serving.
  • resolveRoutes compared the raw targetDomain.domain against hostname'example.de:3000' !== 'example.de' — so it concluded we were on a different domain.

That took the cross-domain branch, which rebuilds the URL from the config, and the rebuilt URL derives its scheme from targetDomain.http rather than the incoming request. Hence the silent httphttps switch on a same-origin redirect.

How?

Extract the normalization detectDomainLocale was already doing inline into an exported getDomainHostname(domain) in i18n.ts (strip port, lowercase), and use it in resolveRoutes for the comparison. Both call sites now agree on what "same domain" means, so the port-carrying config takes the same-origin branch and keeps the request's scheme, host and port.

The comparison result is hoisted into isTargetDomainCurrent and reused by both branches, which also removes the redundant targetDomain && re-check in the second condition.

Test added in packages/next-routing/src/__tests__/i18n-resolve-routes.test.ts asserting the redirect keeps origin === 'http://example.de:3000' and gains the /fr/ prefix.

The locale redirect compared the raw `domains[].domain` against the request
hostname. `detectDomainLocale` strips the port and lowercases before matching,
so a domain configured as `example.de:3000` never compared equal to the
`example.de` we are already serving.

That took the cross-domain branch and rebuilt the URL from the config, which
replaced the request scheme: a request to http://example.de:3000/ was redirected
to https://example.de:3000/fr/ instead of staying on http.

Reuse the same normalization for the comparison.
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