Skip to content

Commit

Permalink
refactor!: combine onlyOnNoPrefix and onlyOnRoot
Browse files Browse the repository at this point in the history
  • Loading branch information
divine committed Jul 19, 2021
1 parent 635a18f commit 2cda4be
Show file tree
Hide file tree
Showing 10 changed files with 48 additions and 35 deletions.
4 changes: 2 additions & 2 deletions docs/content/en/browser-language-detection.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ By default, **nuxt-i18n** attempts to redirect users to their preferred language
detectBrowserLanguage: {
useCookie: true,
cookieKey: 'i18n_redirected',
onlyOnRoot: true, // recommended
redirectOn: 'root', // recommended
}
}]
```

<alert type="info">

For better SEO, it's recommended to set `onlyOnRoot` to `true`. With it set, the language detection is only attempted when the user visits the root path (`/`) of the site. This allows crawlers to access the requested page rather than being redirected away based on detected locale. It also allows linking to pages in specific locales.
For better SEO, it's recommended to set `redirectOn` to `root`. With it set, the language detection is only attempted when the user visits the root path (`/`) of the site. This allows crawlers to access the requested page rather than being redirected away based on detected locale. It also allows linking to pages in specific locales.

</alert>

Expand Down
2 changes: 2 additions & 0 deletions docs/content/en/migrating.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ Follow this guide to upgrade from one major version to the other.

### `seo` option has been removed. Use `$nuxtI18nHead({ addDirAttribute: true, addSeoAttributes: true })` instead.

### `onlyOnRoot` and `onlyOnNoPrefix` has been removed. It's features are combined into `redirectOn` instead. Use `redirectOn: 'all|root|no prefix'` instead.

## Upgrading from 5.x to 6.x

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

- type: `object`
- default: `{ alwaysRedirect: false, fallbackLocale: '', onlyOnRoot: false, useCookie: true, cookieCrossOrigin: false, cookieDomain: null, cookieKey: 'i18n_redirected', cookieSecure: false }`
- default: `{ alwaysRedirect: false, fallbackLocale: '', redirectOn: 'all', 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.

See also [Browser language detection](/browser-language-detection) for a guide.

<alert type="info">

Note that for better SEO it's recommended to set `onlyOnRoot` to true.
Note that for better SEO it's recommended to set `redirectOn` to `root`.

</alert>

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.
- `onlyOnRoot` (default: `false`) - Set to `true` (recommended for improved SEO) to only attempt to detect the browser locale on the root path (`/`) of the site. Only effective when using strategy other than `'no_prefix'`.
- `onlyOnNoPrefix` (default: `false`) - This is a more permissive variant of `onlyOnRoot` that will allow attempt to detect the browser locale on the root path (`/`) and also on paths that have no locale prefix (like `/foo`). Only effective when `onlyOnRoot` is not enabled and using strategy other than `'no_prefix'`.
- `redirectOn` (default: `all`) - 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'`.
- `useCookie` (default: `true`) - If enabled, a cookie is set once the user has been redirected to browser's preferred locale, to prevent subsequent redirections. Set to `false` to redirect every time.
- `cookieKey` (default: `'i18n_redirected'`) - Cookie name.
- `cookieDomain` (default: `null`) - Set to override the default domain of the cookie. Defaults to the **host** of the site.
Expand Down
12 changes: 10 additions & 2 deletions src/helpers/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ export const STRATEGIES = {
NO_PREFIX: STRATEGY_NO_PREFIX
}

const REDIRECT_ON_ALL = 'all'
const REDIRECT_ON_ROOT = 'root'
const REDIRECT_ON_NO_PREFIX = 'no prefix'
export const REDIRECT_ON_OPTIONS = {
ALL: REDIRECT_ON_ALL,
ROOT: REDIRECT_ON_ROOT,
NO_PREFIX: REDIRECT_ON_NO_PREFIX
}

export const COMPONENT_OPTIONS_KEY = 'nuxtI18n'

/** @type {Options} */
Expand All @@ -39,8 +48,7 @@ export const DEFAULT_OPTIONS = {
cookieKey: 'i18n_redirected',
cookieSecure: false,
fallbackLocale: '',
onlyOnNoPrefix: false,
onlyOnRoot: false,
redirectOn: 'all',
useCookie: true
},
differentDomains: false,
Expand Down
5 changes: 3 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { readdirSync } from 'fs'
import merge from 'lodash.merge'
// @ts-ignore
import { directive as i18nExtensionsDirective } from '@intlify/vue-i18n-extensions'
import { COMPONENT_OPTIONS_KEY, DEFAULT_OPTIONS, ROOT_DIR, STRATEGIES } from './helpers/constants'
import { COMPONENT_OPTIONS_KEY, DEFAULT_OPTIONS, ROOT_DIR, STRATEGIES, REDIRECT_ON_OPTIONS } from './helpers/constants'
import { buildHook, createExtendRoutesHook } from './core/hooks'
import { formatMessage } from './templates/utils-common'

Expand Down Expand Up @@ -53,7 +53,8 @@ export default function (moduleOptions) {
const templatesOptions = {
Constants: {
COMPONENT_OPTIONS_KEY,
STRATEGIES
STRATEGIES,
REDIRECT_ON_OPTIONS
},
nuxtOptions: {
isUniversalMode: nuxtOptions.mode === 'universal',
Expand Down
3 changes: 2 additions & 1 deletion src/templates/options.d.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import Vue from 'vue'
import { ComponentOptions } from 'vue/types/options'
import { STRATEGIES } from '../helpers/constants'
import { STRATEGIES, REDIRECT_ON_OPTIONS } from '../helpers/constants'
import { LocaleFileExport, ResolvedOptions } from '../../types/internal'

interface ModuleConstants {
COMPONENT_OPTIONS_KEY: keyof Pick<ComponentOptions<Vue>, 'nuxtI18n'>
STRATEGIES: typeof STRATEGIES
REDIRECT_ON_OPTIONS: typeof REDIRECT_ON_OPTIONS
}

interface ModuleNuxtOptions {
Expand Down
11 changes: 5 additions & 6 deletions src/templates/plugin.main.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ export default async (context) => {
const {
alwaysRedirect,
fallbackLocale,
onlyOnNoPrefix,
onlyOnRoot,
redirectOn,
useCookie,
cookieKey,
cookieDomain,
Expand Down Expand Up @@ -181,9 +180,9 @@ export default async (context) => {
}

if (getLocaleFromRoute(route) === locale) {
// If "onlyOnRoot" or "onlyOnNoPrefix" is set and strategy is "prefix_and_default", prefer unprefixed route for
// If "redirectOn" is "all" and strategy is "prefix_and_default", prefer unprefixed route for
// default locale.
if (!(onlyOnRoot || onlyOnNoPrefix) || locale !== options.defaultLocale || options.strategy !== Constants.STRATEGIES.PREFIX_AND_DEFAULT) {
if (redirectOn === Constants.REDIRECT_ON_OPTIONS.ALL || locale !== options.defaultLocale || options.strategy !== Constants.STRATEGIES.PREFIX_AND_DEFAULT) {
return ''
}
}
Expand Down Expand Up @@ -287,11 +286,11 @@ export default async (context) => {
}

if (options.strategy !== Constants.STRATEGIES.NO_PREFIX) {
if (onlyOnRoot) {
if (redirectOn === Constants.REDIRECT_ON_OPTIONS.ROOT) {
if (route.path !== '/') {
return ''
}
} else if (onlyOnNoPrefix) {
} else if (redirectOn === Constants.REDIRECT_ON_OPTIONS.NO_PREFIX) {
if (!alwaysRedirect && route.path.match(getLocalesRegex(options.localeCodes))) {
return ''
}
Expand Down
28 changes: 14 additions & 14 deletions test/browser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ describe(`${browserString} (generate, no subFolders, trailingSlash === false)`,
})

for (const target of ['server', 'static']) {
describe(`${browserString} (target ${target}, generate, prefix strategy, alwaysRedirect, onlyOnRoot)`, () => {
describe(`${browserString} (target ${target}, generate, prefix strategy, alwaysRedirect, redirectOn is root)`, () => {
/** @type {import('playwright-chromium').ChromiumBrowser} */
let browser
/** @type {import('playwright-chromium').Page} */
Expand All @@ -403,7 +403,7 @@ for (const target of ['server', 'static']) {
detectBrowserLanguage: {
alwaysRedirect: true,
fallbackLocale: 'en',
onlyOnRoot: true
redirectOn: 'root'
}
}
}
Expand Down Expand Up @@ -968,7 +968,7 @@ describe(`${browserString} (SPA with router in hash mode)`, () => {
})
})

describe(`${browserString} (onlyOnRoot + alwaysRedirect + no_prefix)`, () => {
describe(`${browserString} (redirectOn is root + alwaysRedirect + no_prefix)`, () => {
/** @type {Nuxt} */
let nuxt
/** @type {import('playwright-chromium').ChromiumBrowser} */
Expand All @@ -982,7 +982,7 @@ describe(`${browserString} (onlyOnRoot + alwaysRedirect + no_prefix)`, () => {
detectBrowserLanguage: {
useCookie: false,
alwaysRedirect: true,
onlyOnRoot: true
redirectOn: 'root'
}
}
}
Expand All @@ -998,13 +998,13 @@ describe(`${browserString} (onlyOnRoot + alwaysRedirect + no_prefix)`, () => {
await nuxt.close()
})

test('onlyOnRoot does not affect locale detection on root path', async () => {
test('redirectOn is root does not affect locale detection on root path', async () => {
const page = await browser.newPage({ locale: 'fr' })
await page.goto(url('/'))
expect(await (await page.$('body'))?.textContent()).toContain('locale: fr')
})

test('onlyOnRoot does not affect locale detection on sub-path', async () => {
test('redirectOn is root does not affect locale detection on sub-path', async () => {
const page = await browser.newPage({ locale: 'fr' })
await page.goto(url('/about'))
expect(await (await page.$('#current-page'))?.textContent()).toContain('page: À propos')
Expand Down Expand Up @@ -1059,7 +1059,7 @@ describe(`${browserString} (alwaysRedirect, prefix)`, () => {
})
})

describe(`${browserString} (onlyOnRoot + prefix_except_default)`, () => {
describe(`${browserString} (redirectOn is root + prefix_except_default)`, () => {
/** @type {Nuxt} */
let nuxt
/** @type {import('playwright-chromium').ChromiumBrowser} */
Expand All @@ -1071,7 +1071,7 @@ describe(`${browserString} (onlyOnRoot + prefix_except_default)`, () => {
defaultLocale: 'en',
strategy: 'prefix_except_default',
detectBrowserLanguage: {
onlyOnRoot: true
redirectOn: 'root'
}
}
}
Expand Down Expand Up @@ -1131,7 +1131,7 @@ describe(`${browserString} (onlyOnRoot + prefix_except_default)`, () => {
})
})

describe(`${browserString} (onlyOnRoot + alwaysRedirect + prefix_except_default)`, () => {
describe(`${browserString} (redirectOn is root + alwaysRedirect + prefix_except_default)`, () => {
/** @type {Nuxt} */
let nuxt
/** @type {import('playwright-chromium').ChromiumBrowser} */
Expand All @@ -1144,7 +1144,7 @@ describe(`${browserString} (onlyOnRoot + alwaysRedirect + prefix_except_default)
strategy: 'prefix_except_default',
detectBrowserLanguage: {
alwaysRedirect: true,
onlyOnRoot: true
redirectOn: 'root'
}
}
}
Expand Down Expand Up @@ -1176,7 +1176,7 @@ describe(`${browserString} (onlyOnRoot + alwaysRedirect + prefix_except_default)
})
})

describe(`${browserString} (onlyOnRoot + prefix_and_default)`, () => {
describe(`${browserString} (redirectOn is root + prefix_and_default)`, () => {
/** @type {Nuxt} */
let nuxt
/** @type {import('playwright-chromium').ChromiumBrowser} */
Expand All @@ -1188,7 +1188,7 @@ describe(`${browserString} (onlyOnRoot + prefix_and_default)`, () => {
defaultLocale: 'en',
strategy: 'prefix_and_default',
detectBrowserLanguage: {
onlyOnRoot: true
redirectOn: 'root'
}
}
}
Expand Down Expand Up @@ -1219,7 +1219,7 @@ describe(`${browserString} (onlyOnRoot + prefix_and_default)`, () => {
})
})

describe(`${browserString} (onlyOnRoot + prefix)`, () => {
describe(`${browserString} (redirectOn is root + prefix)`, () => {
/** @type {Nuxt} */
let nuxt
/** @type {import('playwright-chromium').ChromiumBrowser} */
Expand All @@ -1231,7 +1231,7 @@ describe(`${browserString} (onlyOnRoot + prefix)`, () => {
defaultLocale: 'en',
strategy: 'prefix',
detectBrowserLanguage: {
onlyOnRoot: true
redirectOn: 'root'
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions test/module.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1786,7 +1786,7 @@ describe('prefix + detectBrowserLanguage', () => {
})
})

describe('prefix + detectBrowserLanguage + onlyOnNoPrefix', () => {
describe('prefix + detectBrowserLanguage + redirectOn is no_prefix', () => {
/** @type {Nuxt} */
let nuxt

Expand All @@ -1797,7 +1797,7 @@ describe('prefix + detectBrowserLanguage + onlyOnNoPrefix', () => {
strategy: 'prefix',
detectBrowserLanguage: {
useCookie: true,
onlyOnNoPrefix: true
redirectOn: 'no prefix'
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import './vue'
export { Locale }
export type Strategies = 'no_prefix' | 'prefix_except_default' | 'prefix' | 'prefix_and_default'
export type Directions = 'ltr' | 'rtl' | 'auto'
export type RedirectOnOptions = 'all' | 'root' | 'no prefix'

export interface LocaleObject extends Record<string, any> {
code: Locale
Expand All @@ -21,8 +22,7 @@ export interface DetectBrowserLanguageOptions {
cookieKey?: string
cookieSecure?: boolean
fallbackLocale?: Locale | null
onlyOnNoPrefix?: boolean
onlyOnRoot?: boolean
redirectOn?: RedirectOnOptions
useCookie?: boolean
}

Expand Down

0 comments on commit 2cda4be

Please sign in to comment.