Skip to content

fix: skip locale prefix for absolute and protocol-relative Link hrefs#455

Merged
james-elicx merged 2 commits intocloudflare:mainfrom
NathanDrake2406:fix/link-locale-absolute-urls
Mar 11, 2026
Merged

fix: skip locale prefix for absolute and protocol-relative Link hrefs#455
james-elicx merged 2 commits intocloudflare:mainfrom
NathanDrake2406:fix/link-locale-absolute-urls

Conversation

@NathanDrake2406
Copy link
Contributor

@NathanDrake2406 NathanDrake2406 commented Mar 11, 2026

Summary

  • applyLocaleToHref() blindly prepended /${locale} to any href, producing malformed URLs like /fr/https://example.com/about or /fr///example.com/about for absolute and protocol-relative hrefs
  • Guard against http://, https://, and // URLs before applying the locale prefix — these should pass through unchanged

Test plan

  • 3 new tests (RED → GREEN): absolute https, protocol-relative, absolute http — all confirmed failing before fix
  • All 41 link tests pass
  • All 652 shims tests pass
  • Typecheck and format clean
  • CI (Format, Lint, Typecheck, Vitest, Playwright E2E)

applyLocaleToHref() blindly prepended /${locale} to any href string,
producing malformed URLs like /fr/https://example.com/about or
/fr///example.com/about for absolute and protocol-relative hrefs.

Guard against http://, https://, and // URLs before applying the
locale prefix — these are external or same-origin absolute URLs that
should not be rewritten.
@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 11, 2026

Open in StackBlitz

npm i https://pkg.pr.new/vinext@455

commit: 2b49d08

@james-elicx
Copy link
Collaborator

/bigbonk review

Copy link
Contributor

@ask-bonk ask-bonk bot left a comment

Choose a reason for hiding this comment

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

Clean, correct fix. The guard is in the right place and the tests cover all three URL patterns.

One thing to flag: applyNavigationLocale() in router.ts:125 is the sibling function used by Router.push() / Router.replace() and has the exact same bug — it will prepend /${locale} to absolute URLs. Should be fixed in this PR or a follow-up. See inline comment.

// Absolute and protocol-relative URLs must not be prefixed — locale
// only applies to local paths.
if (href.startsWith("http://") || href.startsWith("https://") || href.startsWith("//")) {
return href;
Copy link
Contributor

Choose a reason for hiding this comment

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

The fix looks correct and is well-placed — right after the undefined/false early returns and before the locale-prefixing logic.

Note: the sibling function applyNavigationLocale() in router.ts:125-132 has the same bug. It's used by Router.push() and Router.replace() when a locale option is passed. Consider adding the same guard there (and a corresponding test) — either in this PR or as an immediate follow-up:

Suggested change
return href;
// Absolute and protocol-relative URLs must not be prefixed — locale
// only applies to local paths.
if (/^https?:\/\//.test(href) || href.startsWith("//")) {
return href;
}

(The startsWith version you have is perfectly fine too — just showing the regex alternative for brevity. No change needed here.)

React.createElement(Link, { href: "http://example.com/path", locale: "de" } as any, "x"),
);
expect(html).toContain('href="http://example.com/path"');
});
Copy link
Contributor

Choose a reason for hiding this comment

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

Good coverage — three distinct URL patterns (https, protocol-relative, http) with clear comments explaining the expected behavior.

Minor: might be worth adding a test for mailto: or other non-http schemes to document whether those are handled (they'd currently get locale-prefixed, but that's a separate issue).

@ask-bonk
Copy link
Contributor

ask-bonk bot commented Mar 11, 2026

Review submitted. Here's the summary:

Approved the PR. The fix is correct and well-placed — it adds an early return in applyLocaleToHref() for absolute (http://, https://) and protocol-relative (//) URLs, preventing malformed hrefs like /fr/https://example.com/about. Tests cover all three patterns.

One follow-up flagged: The sibling function applyNavigationLocale() in router.ts:125-132 (used by Router.push() / Router.replace()) has the exact same bug and should get the same guard, either in this PR or as an immediate follow-up.

github run

…plyNavigationLocale

applyNavigationLocale() in router.ts (used by Router.push() / Router.replace())
had the same bug as applyLocaleToHref() in link.tsx — it would prepend /{locale}
to absolute and protocol-relative URLs, producing malformed hrefs like
/fr/https://example.com/about or /fr///cdn.example.com/img.png.

Add the same guard that was applied to applyLocaleToHref(), and add
corresponding tests covering https://, http://, and // URL patterns.
@james-elicx james-elicx force-pushed the fix/link-locale-absolute-urls branch from 0de685d to ba458ab Compare March 11, 2026 08:34
@james-elicx james-elicx enabled auto-merge (squash) March 11, 2026 08:34
@james-elicx james-elicx merged commit 15cd5d2 into cloudflare:main Mar 11, 2026
17 checks passed
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