diff --git a/packages/next/build/webpack/loaders/next-serverless-loader/utils.ts b/packages/next/build/webpack/loaders/next-serverless-loader/utils.ts index 2ab3106b90c706d..cf01d3ac3a37ee1 100644 --- a/packages/next/build/webpack/loaders/next-serverless-loader/utils.ts +++ b/packages/next/build/webpack/loaders/next-serverless-loader/utils.ts @@ -179,10 +179,11 @@ export function getUtils({ // Simulate a RegExp match from the \`req.url\` input exec: (str: string) => { const obj = parseQs(str) + const matchesHasLocale = + i18n && detectedLocale && obj['1'] === detectedLocale // favor named matches if available const routeKeyNames = Object.keys(routeKeys || {}) - const filterLocaleItem = (val: string | string[]) => { if (i18n) { // locale items can be included in route-matches @@ -228,8 +229,13 @@ export function getUtils({ return Object.keys(obj).reduce((prev, key) => { if (!filterLocaleItem(obj[key])) { + let normalizedKey = key + + if (matchesHasLocale) { + normalizedKey = parseInt(key, 10) - 1 + '' + } return Object.assign(prev, { - [key]: obj[key], + [normalizedKey]: obj[key], }) } return prev diff --git a/test/production/required-server-files-i18n.test.ts b/test/production/required-server-files-i18n.test.ts index 2c77d97c61ac10b..832442d2e4f5224 100644 --- a/test/production/required-server-files-i18n.test.ts +++ b/test/production/required-server-files-i18n.test.ts @@ -601,11 +601,12 @@ describe('should set-up next', () => { it('should normalize optional values correctly for SSG page', async () => { const res = await fetchViaHTTP( appPort, - '/optional-ssg', - { rest: '', another: 'value' }, + '/en/optional-ssg/[[...rest]]', + undefined, { headers: { - 'x-matched-path': '/optional-ssg/[[...rest]]', + 'x-matched-path': '/en/optional-ssg/[[...rest]]', + 'x-now-route-matches': 'nextLocale=en&1=en', }, } ) @@ -616,6 +617,28 @@ describe('should set-up next', () => { expect(props.params).toEqual({}) }) + it('should normalize optional values correctly for nested optional SSG page', async () => { + const res = await fetchViaHTTP( + appPort, + '/en/[slug]/social/[[...rest]]', + undefined, + { + headers: { + 'x-matched-path': '/en/[slug]/social/[[...rest]]', + 'x-now-route-matches': 'nextLocale=en&1=en&2=user-123&slug=user-123', + }, + } + ) + + const html = await res.text() + const $ = cheerio.load(html) + const props = JSON.parse($('#props').text()) + expect(props.params).toEqual({ + slug: 'user-123', + }) + expect($('#page').text()).toBe('/[slug]/social/[[...rest]]') + }) + it('should normalize optional values correctly for SSG page with encoded slash', async () => { const res = await fetchViaHTTP( appPort, diff --git a/test/production/required-server-files/pages/[slug].js b/test/production/required-server-files/pages/[slug]/index.js similarity index 100% rename from test/production/required-server-files/pages/[slug].js rename to test/production/required-server-files/pages/[slug]/index.js diff --git a/test/production/required-server-files/pages/[slug]/social/[[...rest]].js b/test/production/required-server-files/pages/[slug]/social/[[...rest]].js new file mode 100644 index 000000000000000..b77f6378f9e29f4 --- /dev/null +++ b/test/production/required-server-files/pages/[slug]/social/[[...rest]].js @@ -0,0 +1,25 @@ +export const getStaticProps = ({ params }) => { + return { + props: { + random: Math.random(), + params: params || null, + }, + revalidate: 1, + } +} + +export const getStaticPaths = () => { + return { + paths: [], + fallback: true, + } +} + +export default function Page(props) { + return ( + <> +

/[slug]/social/[[...rest]]

+

{JSON.stringify(props)}

+ + ) +}