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

Ensure index rewrite is matched with i18n correctly (#20509)

This makes sure we don't generate the wrong locale source variant for the rewrite requiring a `/` on the end which won't ever be added causing the rewrite to never match. Additional tests have been added to ensure this specific rewrite is working correctly. 


Fixes: https://github.com/vercel/next.js/issues/20508
上级 6189fe96
......@@ -407,7 +407,9 @@ function processRoutes<T>(
r.source = `/:nextInternalLocale(${config.i18n.locales
.map((locale: string) => escapeStringRegexp(locale))
.join('|')})${r.source}`
.join('|')})${
r.source === '/' && !config.trailingSlash ? '' : r.source
}`
if (r.destination && r.destination?.startsWith('/')) {
r.destination = `/:nextInternalLocale${
......
......@@ -1366,8 +1366,11 @@ export default class Server {
? (req as any)._nextRewroteUrl
: urlPathname
resolvedUrlPathname = removePathTrailingSlash(resolvedUrlPathname)
urlPathname = removePathTrailingSlash(urlPathname)
resolvedUrlPathname = normalizeLocalePath(
removePathTrailingSlash(resolvedUrlPathname),
this.nextConfig.i18n?.locales
).pathname
const stripNextDataPath = (path: string) => {
if (path.includes(this.buildId)) {
......
module.exports = {
i18n: {
// localeDetection: false,
locales: ['nl-NL', 'nl-BE', 'nl', 'fr-BE', 'fr', 'en'],
defaultLocale: 'en',
domains: [
{
// used for testing, this should not be needed in most cases
// as production domains should always use https
http: true,
domain: 'example.be',
defaultLocale: 'nl-BE',
locales: ['nl', 'nl-NL', 'nl-BE'],
},
{
http: true,
domain: 'example.fr',
defaultLocale: 'fr',
locales: ['fr-BE'],
},
],
},
async rewrites() {
return [
{
source: '/',
destination: '/company/about-us',
},
]
},
}
import React from 'react'
const DynamicPage = (props) => (
<>
<div>DynamicPage</div>
<div id="props">{JSON.stringify(props)}</div>
</>
)
export const getStaticPaths = async ({ locales }) => {
const paths = []
for (const locale of locales) {
paths.push({
params: {
slug: ['hello'],
},
locale,
})
paths.push({
params: {
slug: ['company', 'about-us'],
},
locale,
})
}
return {
fallback: false,
paths,
}
}
export const getStaticProps = async ({ params, locale }) => ({
props: {
locale,
params,
hello: 'world',
},
})
export default DynamicPage
/* eslint-env jest */
import { join } from 'path'
import assert from 'assert'
import cheerio from 'cheerio'
import webdriver from 'next-webdriver'
import {
launchApp,
killApp,
findPort,
nextBuild,
nextStart,
renderViaHTTP,
check,
} from 'next-test-utils'
jest.setTimeout(1000 * 60 * 2)
const appDir = join(__dirname, '..')
const locales = ['nl-NL', 'nl-BE', 'nl', 'fr-BE', 'fr', 'en']
let appPort
let app
const runTests = () => {
it('should rewrite index route correctly', async () => {
for (const locale of locales) {
const html = await renderViaHTTP(
appPort,
`/${locale === 'en' ? '' : locale}`
)
const $ = cheerio.load(html)
expect(JSON.parse($('#props').text())).toEqual({
params: {
slug: ['company', 'about-us'],
},
locale,
hello: 'world',
})
}
})
it('should handle index rewrite on client correctly', async () => {
for (const locale of locales) {
const browser = await webdriver(
appPort,
`${locale === 'en' ? '' : `/${locale}`}/hello`
)
expect(JSON.parse(await browser.elementByCss('#props').text())).toEqual({
params: {
slug: ['hello'],
},
locale,
hello: 'world',
})
await browser.eval(`(function() {
window.beforeNav = 1
window.next.router.push('/')
})()`)
await check(async () => {
const html = await browser.eval('document.documentElement.innerHTML')
const props = JSON.parse(cheerio.load(html)('#props').text())
assert.deepEqual(props, {
params: {
slug: ['company', 'about-us'],
},
locale,
hello: 'world',
})
return 'success'
}, 'success')
}
})
}
describe('Custom routes i18n', () => {
describe('dev mode', () => {
beforeAll(async () => {
appPort = await findPort()
app = await launchApp(appDir, appPort)
})
afterAll(() => killApp(app))
runTests(true)
})
describe('production mode', () => {
beforeAll(async () => {
await nextBuild(appDir)
appPort = await findPort()
app = await nextStart(appDir, appPort)
})
afterAll(() => killApp(app))
runTests()
})
})
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册