From 3f84a55ba38649ee81fbc703ccb1173de896d4de Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Mon, 2 Nov 2020 17:32:56 -0600 Subject: [PATCH] Ensure locale is added/stripped correctly (#18712) This makes sure we don't incorrectly strip locale characters from the path if it is not a locale prefix e.g. `/fr` should not be removed from `/frank`. Additional tests have been added to ensure this isn't stripped for this case. Fixes: https://github.com/vercel/next.js/issues/18332 --- .../next/next-server/lib/router/router.ts | 8 ++- test/integration/i18n-support/pages/frank.js | 56 +++++++++++++++++++ .../i18n-support/test/index.test.js | 29 ++++++++++ 3 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 test/integration/i18n-support/pages/frank.js diff --git a/packages/next/next-server/lib/router/router.ts b/packages/next/next-server/lib/router/router.ts index 0d7ceb2d42..a626c36dcd 100644 --- a/packages/next/next-server/lib/router/router.ts +++ b/packages/next/next-server/lib/router/router.ts @@ -62,7 +62,10 @@ export function addLocale( defaultLocale?: string ) { if (process.env.__NEXT_I18N_SUPPORT) { - return locale && locale !== defaultLocale && !path.startsWith('/' + locale) + return locale && + locale !== defaultLocale && + !path.startsWith('/' + locale + '/') && + path !== '/' + locale ? addPathPrefix(path, '/' + locale) : path } @@ -71,7 +74,8 @@ export function addLocale( export function delLocale(path: string, locale?: string) { if (process.env.__NEXT_I18N_SUPPORT) { - return locale && path.startsWith('/' + locale) + return locale && + (path.startsWith('/' + locale + '/') || path === '/' + locale) ? path.substr(locale.length + 1) || '/' : path } diff --git a/test/integration/i18n-support/pages/frank.js b/test/integration/i18n-support/pages/frank.js new file mode 100644 index 0000000000..56d0ebaea4 --- /dev/null +++ b/test/integration/i18n-support/pages/frank.js @@ -0,0 +1,56 @@ +import Link from 'next/link' +import { useRouter } from 'next/router' + +export default function Page(props) { + const router = useRouter() + + return ( + <> +

frank page

+

{JSON.stringify(props)}

+

{router.locale}

+

{JSON.stringify(router.locales)}

+

{JSON.stringify(router.query)}

+

{router.pathname}

+

{router.asPath}

+ + to /another + +
+ + to /gsp + +
+ + to /gsp/fallback/first + +
+ + to /gsp/fallback/hello + +
+ + to /gsp/no-fallback/first + +
+ + to /gssp + +
+ + to /gssp/first + +
+ + ) +} + +export const getStaticProps = ({ locale, locales, defaultLocale }) => { + return { + props: { + locale, + locales, + defaultLocale, + }, + } +} diff --git a/test/integration/i18n-support/test/index.test.js b/test/integration/i18n-support/test/index.test.js index 281d506dc1..8ece675dca 100644 --- a/test/integration/i18n-support/test/index.test.js +++ b/test/integration/i18n-support/test/index.test.js @@ -172,6 +172,11 @@ function runTests(isDev) { initialRevalidateSeconds: false, srcRoute: '/not-found/fallback/[slug]', }, + '/frank': { + dataRoute: `/_next/data/${buildId}/frank.json`, + initialRevalidateSeconds: false, + srcRoute: null, + }, '/gsp': { dataRoute: `/_next/data/${buildId}/gsp.json`, srcRoute: null, @@ -1092,6 +1097,30 @@ function runTests(isDev) { } }) + it('should transition on client properly for page that starts with locale', async () => { + const browser = await webdriver(appPort, '/fr') + await browser.eval(`(function() { + window.beforeNav = 1 + window.next.router.push('/frank') + })()`) + + await browser.waitForElementByCss('#frank') + + expect(await browser.elementByCss('#router-locale').text()).toBe('fr') + expect( + JSON.parse(await browser.elementByCss('#router-locales').text()) + ).toEqual(locales) + expect( + JSON.parse(await browser.elementByCss('#router-query').text()) + ).toEqual({}) + expect(await browser.elementByCss('#router-pathname').text()).toBe('/frank') + expect(await browser.elementByCss('#router-as-path').text()).toBe('/frank') + expect( + url.parse(await browser.eval(() => window.location.href)).pathname + ).toBe('/fr/frank') + expect(await browser.eval('window.beforeNav')).toBe(1) + }) + it('should 404 for GSP that returned notFound on client-transition', async () => { const browser = await webdriver(appPort, '/en') await browser.eval(`(function() {