Skip to content

Commit

Permalink
refactor!: set redirectOn to root by default (nuxt-modules#1244)
Browse files Browse the repository at this point in the history
  • Loading branch information
divine authored and rchl committed Aug 3, 2021
1 parent 399f1a3 commit 956df98
Show file tree
Hide file tree
Showing 5 changed files with 332 additions and 9 deletions.
2 changes: 2 additions & 0 deletions docs/content/en/migrating.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Follow this guide to upgrade from one major version to the other.

### Vuex `syncLocale` and `syncMessages` properties has been removed. Use `this.$i18n` context instead.

### `redirectOn` default value has been changed from `all` to `root`. Use `redirectOn: 'all'` to set it `all`.

## Upgrading from 5.x to 6.x

### Global SEO features are now disabled by default
Expand Down
4 changes: 2 additions & 2 deletions docs/content/en/options-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ Directory that contains translation files to load. Can be used with or without l
## `detectBrowserLanguage`

- type: `object`
- default: `{ alwaysRedirect: false, fallbackLocale: '', redirectOn: 'all', useCookie: true, cookieCrossOrigin: false, cookieDomain: null, cookieKey: 'i18n_redirected', cookieSecure: false }`
- default: `{ alwaysRedirect: false, fallbackLocale: '', redirectOn: 'root', useCookie: true, cookieCrossOrigin: false, cookieDomain: null, cookieKey: 'i18n_redirected', cookieSecure: false }`

Enables browser language detection to automatically redirect visitors to their preferred locale as they visit your site for the first time.

Expand All @@ -175,7 +175,7 @@ Note that for better SEO it's recommended to set `redirectOn` to `root`.
Supported properties:
- `alwaysRedirect` (default: `false`) - Set to always redirect to the value stored in the cookie, not just on first visit.
- `fallbackLocale` (default: `null`) - If none of the locales match the browser's locale, use this one as a fallback.
- `redirectOn` (default: `all`) - Supported options:
- `redirectOn` (default: `root`) - Supported options:
- `all` - detect browser locale on all paths.
- `root` (recommended for improved SEO) - only detect the browser locale on the root path (`/`) of the site. Only effective when using strategy other than `'no_prefix'`.
- `no prefix` - a more permissive variant of `root` that will detect the browser locale on the root path (`/`) and also on paths that have no locale prefix (like `/foo`). Only effective when using strategy other than `'no_prefix'`.
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const DEFAULT_OPTIONS = {
cookieKey: 'i18n_redirected',
cookieSecure: false,
fallbackLocale: '',
redirectOn: 'all',
redirectOn: 'root',
useCookie: true
},
differentDomains: false,
Expand Down
173 changes: 171 additions & 2 deletions test/browser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ for (const target of ['server', 'static']) {
})
}

describe(`${browserString} (generate, with router base)`, () => {
describe(`${browserString} (generate, with router base) + redirectOn is root`, () => {
/** @type {import('playwright-chromium').ChromiumBrowser} */
let browser
/** @type {import('playwright-chromium').Page} */
Expand Down Expand Up @@ -280,6 +280,98 @@ describe(`${browserString} (generate, with router base)`, () => {
expect(await page.title()).toBe('Homepage')
})

test('reactivity works after redirecting to locale (sub-path)', async () => {
page = await browser.newPage({ locale: 'fr' })
await page.goto(server.getUrl('/posts/'))
expect(page.url()).toBe(server.getUrl('/posts/'))
// Need to delay a bit due to vue-meta batching with 10ms timeout.
await page.waitForTimeout(20)
expect(await page.title()).toBe('Posts')

await navigate(page, '/fr/articles/')
await page.waitForTimeout(20)
expect(await page.title()).toBe('Articles')
})

test('localePath returns correct path', async () => {
page = await browser.newPage()
await page.goto(server.getUrl('/'))
/**
* @param {string} route
* @param {string | undefined} [locale]
*/
const localePath = async (route, locale) => {
// @ts-ignore
return await page.evaluate(args => window.$nuxt.localePath(...args), [route, locale])
}
expect(await localePath('about')).toBe('/about-us')
expect(await localePath('about', 'fr')).toBe('/fr/a-propos')
expect(await localePath('/about-us')).toBe('/about-us')
})
})

describe(`${browserString} (generate, with router base) + redirectOn is all`, () => {
/** @type {import('playwright-chromium').ChromiumBrowser} */
let browser
/** @type {import('playwright-chromium').Page} */
let page
/** @type {import('./utils').StaticServer} */
let server

beforeAll(async () => {
const base = '/nuxt/'
const distDir = resolve(__dirname, 'fixture', 'basic', '.nuxt-generate')
const overrides = {
generate: { dir: distDir },
router: { base },
i18n: {
detectBrowserLanguage: {
redirectOn: 'all'
}
}
}
await generate(loadConfig(__dirname, 'basic', overrides, { merge: true }))
server = await startHttpServer({ path: distDir, base, verbose: true })
browser = await createBrowser()
})

afterAll(async () => {
if (server) {
await server.destroy()
}
if (browser) {
await browser.close()
}
})

// Issue https://github.com/nuxt-community/i18n-module/issues/378
test('navigate to non-default locale', async () => {
page = await browser.newPage()
await page.goto(server.getUrl('/'))
expect(await (await page.$('body'))?.textContent()).toContain('locale: en')

await navigate(page, '/fr')
expect(await (await page.$('body'))?.textContent()).toContain('locale: fr')

await navigate(page, '/')
expect(await (await page.$('body'))?.textContent()).toContain('locale: en')
})

// Issue https://github.com/nuxt-community/i18n-module/issues/737
test('reactivity works after redirecting to detected browser locale (root path)', async () => {
page = await browser.newPage({ locale: 'fr' })
await page.goto(server.getUrl('/'))
// Trailing slash added by the server.
expect(page.url()).toBe(server.getUrl('/fr'))
// Need to delay a bit due to vue-meta batching with 10ms timeout.
await page.waitForTimeout(20)
expect(await page.title()).toBe('Accueil')

await navigate(page, '/')
await page.waitForTimeout(20)
expect(await page.title()).toBe('Homepage')
})

test('reactivity works after redirecting to detected browser locale (sub-path)', async () => {
page = await browser.newPage({ locale: 'fr' })
await page.goto(server.getUrl('/posts/'))
Expand Down Expand Up @@ -310,7 +402,7 @@ describe(`${browserString} (generate, with router base)`, () => {
})
})

describe(`${browserString} (generate, no subFolders, trailingSlash === false)`, () => {
describe(`${browserString} (generate, no subFolders, trailingSlash === false) + redirectOn is root`, () => {
/** @type {import('playwright-chromium').ChromiumBrowser} */
let browser
/** @type {import('playwright-chromium').Page} */
Expand Down Expand Up @@ -368,6 +460,83 @@ describe(`${browserString} (generate, no subFolders, trailingSlash === false)`,
expect(await page.title()).toBe('Homepage')
})

test('reactivity works after redirecting to locale (sub-path)', async () => {
page = await browser.newPage({ locale: 'fr' })
await page.goto(server.getUrl('/dynamicNested'))
expect(page.url()).toBe(server.getUrl('/dynamicNested'))
// Need to delay a bit due to vue-meta batching with 10ms timeout.
await page.waitForTimeout(20)
expect(await page.title()).toBe('Dynamic')

await navigate(page, '/fr/imbrication-dynamique')
await page.waitForTimeout(20)
expect(await page.title()).toBe('Dynamique')
})
})

describe(`${browserString} (generate, no subFolders, trailingSlash === false) + redirectOn is all`, () => {
/** @type {import('playwright-chromium').ChromiumBrowser} */
let browser
/** @type {import('playwright-chromium').Page} */
let page
/** @type {import('./utils').StaticServer} */
let server

beforeAll(async () => {
const distDir = resolve(__dirname, 'fixture', 'basic', '.nuxt-generate')
const overrides = {
generate: {
dir: distDir,
subFolders: false
},
router: {
trailingSlash: false
},
i18n: {
detectBrowserLanguage: {
redirectOn: 'all'
}
}
}
await generate(loadConfig(__dirname, 'basic', overrides, { merge: true }))
server = await startHttpServer({ path: distDir, noTrailingSlashRedirect: true, verbose: true })
browser = await createBrowser()
})

afterAll(async () => {
if (server) {
await server.destroy()
}
if (browser) {
await browser.close()
}
})

test('navigate to non-default locale', async () => {
page = await browser.newPage()
await page.goto(server.getUrl('/'))
expect(await (await page.$('body'))?.textContent()).toContain('locale: en')

await navigate(page, '/fr')
expect(await (await page.$('body'))?.textContent()).toContain('locale: fr')

await navigate(page, '/')
expect(await (await page.$('body'))?.textContent()).toContain('locale: en')
})

test('reactivity works after redirecting to detected browser locale (root path)', async () => {
page = await browser.newPage({ locale: 'fr' })
await page.goto(server.getUrl('/'))
expect(page.url()).toBe(server.getUrl('/fr'))
// Need to delay a bit due to vue-meta batching with 10ms timeout.
await page.waitForTimeout(20)
expect(await page.title()).toBe('Accueil')

await navigate(page, '/')
await page.waitForTimeout(20)
expect(await page.title()).toBe('Homepage')
})

test('reactivity works after redirecting to detected browser locale (sub-path)', async () => {
page = await browser.newPage({ locale: 'fr' })
await page.goto(server.getUrl('/dynamicNested'))
Expand Down
Loading

0 comments on commit 956df98

Please sign in to comment.