未验证 提交 fd33c9f7 编写于 作者: J JJ Kasper 提交者: GitHub

Ensure href is updated for locale domain (#20631)

This ensures we render the locale domain on the `href` when using `next/link` previously the provided `href` was stilling being rendered which differed from the resulting `href` that was navigated to. 

Fixes: https://github.com/vercel/next.js/issues/20612
上级 9fc9a6e1
......@@ -3,6 +3,7 @@ import { UrlObject } from 'url'
import {
addBasePath,
addLocale,
getDomainLocale,
isLocalURL,
NextRouter,
PrefetchOptions,
......@@ -297,13 +298,19 @@ function Link(props: React.PropsWithChildren<LinkProps>) {
// If child is an <a> tag and doesn't have a href attribute, or if the 'passHref' property is
// defined, we specify the current 'href', so that repetition is not needed by the user
if (props.passHref || (child.type === 'a' && !('href' in child.props))) {
childProps.href = addBasePath(
addLocale(
as,
typeof locale !== 'undefined' ? locale : router && router.locale,
router && router.defaultLocale
)
const curLocale =
typeof locale !== 'undefined' ? locale : router && router.locale
const localeDomain = getDomainLocale(
as,
curLocale,
router && router.locales,
router && router.domainLocales
)
childProps.href =
localeDomain ||
addBasePath(addLocale(as, curLocale, router && router.defaultLocale))
}
return React.cloneElement(child, childProps)
......
......@@ -74,6 +74,28 @@ function addPathPrefix(path: string, prefix?: string) {
: path
}
export function getDomainLocale(
path: string,
locale?: string | false,
locales?: string[],
domainLocales?: DomainLocales
) {
if (process.env.__NEXT_I18N_SUPPORT) {
locale = locale || normalizeLocalePath(path, locales).detectedLocale
const detectedDomain = detectDomainLocale(domainLocales, undefined, locale)
if (detectedDomain) {
return `http${detectedDomain.http ? '' : 's'}://${detectedDomain.domain}${
basePath || ''
}${locale === detectedDomain.defaultLocale ? '' : `/${locale}`}${path}`
}
return false
}
return false
}
export function addLocale(
path: string,
locale?: string | false,
......@@ -290,6 +312,7 @@ export type BaseRouter = {
locale?: string
locales?: string[]
defaultLocale?: string
domainLocales?: DomainLocales
}
export type NextRouter = BaseRouter &
......
......@@ -74,6 +74,7 @@ class ServerRouter implements NextRouter {
locale?: string
locales?: string[]
defaultLocale?: string
domainLocales?: DomainLocales
// TODO: Remove in the next major version, as this would mean the user is adding event listeners in server-side `render` method
static events: MittEmitter = mitt()
......@@ -85,7 +86,8 @@ class ServerRouter implements NextRouter {
basePath: string,
locale?: string,
locales?: string[],
defaultLocale?: string
defaultLocale?: string,
domainLocales?: DomainLocales
) {
this.route = pathname.replace(/\/$/, '') || '/'
this.pathname = pathname
......@@ -96,6 +98,7 @@ class ServerRouter implements NextRouter {
this.locale = locale
this.locales = locales
this.defaultLocale = defaultLocale
this.domainLocales = domainLocales
}
push(): any {
noRouter()
......@@ -533,7 +536,8 @@ export async function renderToHTML(
basePath,
renderOpts.locale,
renderOpts.locales,
renderOpts.defaultLocale
renderOpts.defaultLocale,
renderOpts.domainLocales
)
const ctx = {
err,
......
......@@ -74,6 +74,44 @@ export function runTests(ctx) {
)
})
it('should render the correct href for locale domain', async () => {
let browser = await webdriver(
ctx.appPort,
`${ctx.basePath || ''}/links?nextLocale=go`
)
for (const [element, pathname] of [
['#to-another', '/another'],
['#to-gsp', '/gsp'],
['#to-fallback-first', '/gsp/fallback/first'],
['#to-fallback-hello', '/gsp/fallback/hello'],
['#to-gssp', '/gssp'],
['#to-gssp-slug', '/gssp/first'],
]) {
const href = await browser.elementByCss(element).getAttribute('href')
expect(href).toBe(`https://example.com${ctx.basePath || ''}${pathname}`)
}
browser = await webdriver(
ctx.appPort,
`${ctx.basePath || ''}/links?nextLocale=go-BE`
)
for (const [element, pathname] of [
['#to-another', '/another'],
['#to-gsp', '/gsp'],
['#to-fallback-first', '/gsp/fallback/first'],
['#to-fallback-hello', '/gsp/fallback/hello'],
['#to-gssp', '/gssp'],
['#to-gssp-slug', '/gssp/first'],
]) {
const href = await browser.elementByCss(element).getAttribute('href')
expect(href).toBe(
`https://example.com${ctx.basePath || ''}/go-BE${pathname}`
)
}
})
it('should navigate through history with query correctly', async () => {
const browser = await webdriver(ctx.appPort, `${ctx.basePath || '/'}`)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册