Skip to content

Commit 6372ba0

Browse files
authored
[backport] Fix i18n fallback: false collision (#82158)
This backports #82136 to our next-15-4 release branch
1 parent 1e2c379 commit 6372ba0

File tree

11 files changed

+201
-5
lines changed

11 files changed

+201
-5
lines changed

packages/next/src/server/lib/i18n-provider.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,8 @@ export class I18NProvider {
118118
// query and strip it from the pathname.
119119
if (analysis.detectedLocale) {
120120
if (analysis.detectedLocale !== detectedLocale) {
121-
throw new Error(
122-
`Invariant: The detected locale does not match the locale in the query. Expected to find '${detectedLocale}' in '${pathname}' but found '${analysis.detectedLocale}'}`
121+
console.warn(
122+
`The detected locale does not match the locale in the query. Expected to find '${detectedLocale}' in '${pathname}' but found '${analysis.detectedLocale}'}`
123123
)
124124
}
125125

packages/next/src/server/next-server.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,9 +1096,9 @@ export default class NextNodeServer extends BaseServer<
10961096
throw new Error('Invariant: pathname is undefined')
10971097
}
10981098

1099-
// This is a catch-all route, there should be no fallbacks so mark it as
1100-
// such.
1101-
addRequestMeta(req, 'bubbleNoFallback', true)
1099+
// When in minimal mode we do not bubble the fallback as the
1100+
// router-server is not present to handle the error
1101+
addRequestMeta(req, 'bubbleNoFallback', this.minimalMode ? undefined : true)
11021102

11031103
// TODO: this is only needed until route-module can handle
11041104
// rendering/serving the 404 directly with next-server
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { nextTestSetup } from 'e2e-utils'
2+
3+
describe('i18n-disallow-multiple-locales', () => {
4+
const { next } = nextTestSetup({
5+
files: __dirname,
6+
})
7+
8+
it.each([
9+
['/non-existent'],
10+
['/es/non-existent'],
11+
['/first/non-existent'],
12+
['/es/first/non-existent'],
13+
['/first/second/non-existent'],
14+
['/es/first/second/non-existent'],
15+
])(
16+
'should 404 properly for fallback: false non-prerendered %s',
17+
async (pathname) => {
18+
const res = await next.fetch(pathname)
19+
expect(res.status).toBe(404)
20+
}
21+
)
22+
23+
it.each([
24+
{ urlPath: '/first', page: '/[first]' },
25+
{ urlPath: '/first/second', page: '/[first]/[second]' },
26+
{ urlPath: '/first/second/third', page: '/[first]/[second]/[third]' },
27+
{
28+
urlPath: '/first/second/third/fourth',
29+
page: '/[first]/[second]/[third]/[fourth]',
30+
},
31+
])(
32+
'should render properly for fallback: false prerendered $urlPath',
33+
async ({ urlPath, page }) => {
34+
const res = await next.fetch(urlPath)
35+
expect(res.status).toBe(200)
36+
expect(await res.text()).toContain(page)
37+
}
38+
)
39+
40+
it('should render properly for fallback: blocking', async () => {
41+
const res = await next.fetch('/first/second/third/another')
42+
expect(res.status).toBe(200)
43+
expect(await res.text()).toContain('/[first]/[second]/[third]/[fourth]')
44+
})
45+
})
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type { NextConfig } from 'next'
2+
3+
const nextConfig: NextConfig = {
4+
/* config options here */
5+
reactStrictMode: true,
6+
7+
i18n: {
8+
defaultLocale: 'en',
9+
locales: ['en', 'es'],
10+
},
11+
}
12+
13+
export default nextConfig
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
export default function Page() {
2+
return (
3+
<>
4+
<p>page: /[first]/[second]/[third]/[fourth]</p>
5+
</>
6+
)
7+
}
8+
9+
export function getStaticProps({ params }) {
10+
return {
11+
props: {
12+
params,
13+
now: Date.now(),
14+
},
15+
}
16+
}
17+
18+
export function getStaticPaths() {
19+
return {
20+
paths: [
21+
{
22+
params: {
23+
first: 'first',
24+
second: 'second',
25+
third: 'third',
26+
fourth: 'fourth',
27+
},
28+
},
29+
],
30+
fallback: 'blocking',
31+
}
32+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
export default function Page() {
2+
return (
3+
<>
4+
<p>page: /[first]/[second]/[third]</p>
5+
</>
6+
)
7+
}
8+
9+
export function getStaticProps({ params }) {
10+
return {
11+
props: {
12+
params,
13+
now: Date.now(),
14+
},
15+
}
16+
}
17+
18+
export function getStaticPaths() {
19+
return {
20+
paths: [
21+
{
22+
params: { first: 'first', second: 'second', third: 'third' },
23+
},
24+
],
25+
fallback: false,
26+
}
27+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
export default function Page() {
2+
return (
3+
<>
4+
<p>page: /[first]/[second]</p>
5+
</>
6+
)
7+
}
8+
9+
export function getStaticProps({ params }) {
10+
return {
11+
props: {
12+
params,
13+
now: Date.now(),
14+
},
15+
}
16+
}
17+
18+
export function getStaticPaths() {
19+
return {
20+
paths: [
21+
{
22+
params: { first: 'first', second: 'second' },
23+
},
24+
],
25+
fallback: false,
26+
}
27+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
export default function Page() {
2+
return (
3+
<>
4+
<p>page: /[first]</p>
5+
</>
6+
)
7+
}
8+
9+
export function getStaticProps({ params }) {
10+
return {
11+
props: {
12+
params,
13+
now: Date.now(),
14+
},
15+
}
16+
}
17+
18+
export function getStaticPaths() {
19+
return {
20+
paths: [
21+
{
22+
params: { first: 'first' },
23+
},
24+
],
25+
fallback: false,
26+
}
27+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import type { AppProps } from 'next/app'
2+
3+
export default function App({ Component, pageProps }: AppProps) {
4+
return <Component {...pageProps} />
5+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Html, Head, Main, NextScript } from 'next/document'
2+
3+
export default function Document() {
4+
return (
5+
<Html lang="en">
6+
<Head />
7+
<body className="antialiased">
8+
<Main />
9+
<NextScript />
10+
</body>
11+
</Html>
12+
)
13+
}

0 commit comments

Comments
 (0)