diff --git a/packages/next/next-server/lib/router/router.ts b/packages/next/next-server/lib/router/router.ts index 785cbf0bbaf8b..45379d17937d0 100644 --- a/packages/next/next-server/lib/router/router.ts +++ b/packages/next/next-server/lib/router/router.ts @@ -113,7 +113,8 @@ export function addLocale( defaultLocale?: string ) { if (process.env.__NEXT_I18N_SUPPORT) { - const pathLower = path.toLowerCase() + const pathname = pathNoQueryHash(path) + const pathLower = pathname.toLowerCase() const localeLower = locale && locale.toLowerCase() return locale && diff --git a/packages/next/package.json b/packages/next/package.json index 23e3436d1c1b2..366c470a826e9 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -28,6 +28,8 @@ "dynamic.d.ts", "error.js", "error.d.ts", + "experimental-script.js", + "experimental-script.d.ts", "head.js", "head.d.ts", "image.js", diff --git a/test/integration/i18n-support/test/shared.js b/test/integration/i18n-support/test/shared.js index f183ee1b9dc0b..f0dac7dafbad3 100644 --- a/test/integration/i18n-support/test/shared.js +++ b/test/integration/i18n-support/test/shared.js @@ -53,6 +53,84 @@ export function runTests(ctx) { expect(await res.text()).toContain('index page') }) + it('should not add duplicate locale key when navigating back to root path with query params', async () => { + const basePath = ctx.basePath || '' + const queryKey = 'query' + const queryValue = '1' + const browser = await webdriver( + ctx.appPort, + `${basePath}/fr?${queryKey}=${queryValue}` + ) + + expect(await browser.eval(() => document.location.pathname)).toBe( + `${basePath}/fr` + ) + expect(await browser.elementByCss('#router-pathname').text()).toBe('/') + expect( + JSON.parse(await browser.elementByCss('#router-query').text()) + ).toEqual({ [queryKey]: queryValue }) + expect(await browser.elementByCss('#router-locale').text()).toBe('fr') + + await browser + .elementByCss('#to-another') + .click() + .waitForElementByCss('#another') + + expect(await browser.eval(() => document.location.pathname)).toBe( + `${basePath}/fr/another` + ) + expect(await browser.elementByCss('#router-pathname').text()).toBe( + '/another' + ) + expect(await browser.elementByCss('#router-locale').text()).toBe('fr') + + await browser.back().waitForElementByCss('#index') + + expect(await browser.eval(() => document.location.pathname)).toBe( + `${basePath}/fr` + ) + expect(await browser.elementByCss('#router-pathname').text()).toBe('/') + expect( + JSON.parse(await browser.elementByCss('#router-query').text()) + ).toEqual({ [queryKey]: queryValue }) + expect(await browser.elementByCss('#router-locale').text()).toBe('fr') + }) + + it('should not add duplicate locale key when navigating back to root path with hash', async () => { + const basePath = ctx.basePath || '' + const hashValue = '#anchor-1' + const browser = await webdriver(ctx.appPort, `${basePath}/fr${hashValue}`) + + expect(await browser.eval(() => document.location.pathname)).toBe( + `${basePath}/fr` + ) + expect(await browser.eval(() => document.location.hash)).toBe(hashValue) + expect(await browser.elementByCss('#router-pathname').text()).toBe('/') + expect(await browser.elementByCss('#router-locale').text()).toBe('fr') + + await browser + .elementByCss('#to-another') + .click() + .waitForElementByCss('#another') + + expect(await browser.eval(() => document.location.pathname)).toBe( + `${basePath}/fr/another` + ) + expect(await browser.elementByCss('#router-pathname').text()).toBe( + '/another' + ) + expect(await browser.elementByCss('#router-locale').text()).toBe('fr') + + await browser.back().waitForElementByCss('#index') + + expect(await browser.eval(() => document.location.pathname)).toBe( + `${basePath}/fr` + ) + expect(await browser.eval(() => document.location.hash)).toBe(hashValue) + expect(await browser.elementByCss('#router-pathname').text()).toBe('/') + expect(await browser.elementByCss('#router-locale').text()).toBe('fr') + }) + it('should handle navigating back to different casing of locale', async () => { const browser = await webdriver( ctx.appPort,