diff --git a/src/templates/plugin.routing.js b/src/templates/plugin.routing.js index 03525d5e7..f7bbdecf7 100644 --- a/src/templates/plugin.routing.js +++ b/src/templates/plugin.routing.js @@ -49,7 +49,7 @@ function localeRoute (route, locale) { } } - const localizedRoute = Object.assign({}, route) + let localizedRoute = Object.assign({}, route) if (route.path && !route.name) { const isDefaultLocale = locale === defaultLocale @@ -61,10 +61,21 @@ function localeRoute (route, locale) { !(strategy === STRATEGIES.NO_PREFIX) && // no prefix for different domains !i18n.differentDomains - - let path = (isPrefixed ? `/${locale}${route.path}` : route.path) - path = path.replace(/\/+$/, '') + (trailingSlash ? '/' : '') || '/' - localizedRoute.path = path + const resolvedRoute = this.router.resolve(route.path).route + const resolvedRouteName = this.getRouteBaseName(resolvedRoute) + if (resolvedRouteName) { + localizedRoute = { + name: getLocaleRouteName(resolvedRouteName, locale), + params: resolvedRoute.params, + query: resolvedRoute.query, + hash: resolvedRoute.hash + } + } else { + if (isPrefixed) { + localizedRoute.path = `/${locale}${route.path}` + } + localizedRoute.path = localizedRoute.path.replace(/\/+$/, '') + (trailingSlash ? '/' : '') || '/' + } } else { if (!route.name && !route.path) { localizedRoute.name = this.getRouteBaseName() diff --git a/test/browser.test.js b/test/browser.test.js index 3b2cf9499..cfaa0c1ab 100644 --- a/test/browser.test.js +++ b/test/browser.test.js @@ -637,6 +637,14 @@ describe(`${browserString} (SPA)`, () => { expect(await (await page.$('body'))?.textContent()).toContain('page could not be found') expect(await getRouteFullPath(page)).toBe(path) }) + + test('preserves the URL on 404 page with non-default locale', async () => { + const path = '/nopage?a#h' + page = await browser.newPage({ locale: 'fr' }) + await page.goto(url(path)) + expect(await (await page.$('body'))?.textContent()).toContain('page could not be found') + expect(await getRouteFullPath(page)).toBe(`/fr${path}`) + }) }) describe(`${browserString} (SPA with router in hash mode)`, () => { diff --git a/test/module.test.js b/test/module.test.js index 5bb1c4608..6b663b7b8 100644 --- a/test/module.test.js +++ b/test/module.test.js @@ -1035,6 +1035,20 @@ describe('prefix_and_default strategy', () => { expect(window.$nuxt.localeRoute('/simple', 'fr')).toMatchObject({ name: 'simple___fr', fullPath: '/fr/simple' }) }) + test('localeRoute returns customized localized route (by route path)', async () => { + const window = await nuxt.renderAndGetWindow(url('/')) + // Prefer unprefixed path for default locale: + expect(window.$nuxt.localeRoute('/about-us', 'en')).toMatchObject({ name: 'about___en___default', fullPath: '/about-us' }) + expect(window.$nuxt.localeRoute('/en/about-us', 'en')).toMatchObject({ name: 'about___en___default', fullPath: '/about-us' }) + expect(window.$nuxt.localeRoute('/about-us', 'fr')).toMatchObject({ name: 'about___fr', fullPath: '/fr/a-propos' }) + expect(window.$nuxt.localeRoute('/about-us?q=1#hash', 'en')).toMatchObject({ + name: 'about___en___default', + fullPath: '/about-us?q=1#hash', + query: { q: '1' }, + hash: '#hash' + }) + }) + test('canonical SEO link is added to prefixed default locale', async () => { const html = await get('/en') const dom = getDom(html)