Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add option to only detect browser locale on root path #799

Merged
merged 1 commit into from
Sep 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions docs/content/en/browser-language-detection.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,20 @@ By default, **nuxt-i18n** attempts to redirect users to their preferred language
// ...
detectBrowserLanguage: {
useCookie: true,
cookieKey: 'i18n_redirected'
cookieKey: 'i18n_redirected',
// onlyOnRoot: true,
}
}]
```

<alert type="info">

Browser language is detected either from `navigator` when running on client side, or from the `accept-language` HTTP header. Configured `locales` (or locales `code`s when locales are specified in object form) are matched against locales reported by the browser (for example `en-US,en;q=0.9,no;q=0.8`). If there is no exact match, the language code (letters before `-`) are matched against configured locales (for backwards compatibility).
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.

</alert>

Browser language is detected either from `navigator` when running on client-side, or from the `accept-language` HTTP header. Configured `locales` (or locales `code`s when locales are specified in object form) are matched against locales reported by the browser (for example `en-US,en;q=0.9,no;q=0.8`). If there is no exact match for the full locale, the language code (letters before `-`) are matched against configured locales (for backward-compatibility).

To prevent redirecting users every time they visit the app, **nuxt-i18n** sets a cookie after the first redirection. You can change the cookie's name by setting `detectBrowserLanguage.cookieKey` option to whatever you'd like, the default is _i18n_redirected_.

```js{}[nuxt.config.js]
Expand Down
14 changes: 9 additions & 5 deletions docs/content/en/options-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Here are all the options available when configuring the module and their default
// - 'prefix_and_default': add locale prefix for every locale and default
strategy: 'prefix_except_default',

// Wether or not the translations should be lazy-loaded, if this is enabled,
// Whether or not the translations should be lazy-loaded, if this is enabled,
// you MUST configure langDir option, and locales must be an array of objects,
// each containing a file key
lazy: false,
Expand All @@ -79,9 +79,10 @@ Here are all the options available when configuring the module and their default
// }
rootRedirect: null,

// Enable browser language detection to automatically redirect user
// to their preferred language as they visit your app for the first time
// Set to false to disable
// Enable browser language detection to automatically redirect visitors to their
// preferred language as they visit your site for the first time.
// Note that for better SEO it's recommended to set 'onlyOnRoot' to true.
// Set to false to disable.
detectBrowserLanguage: {
// If enabled, a cookie is set once a user has been redirected to his
// preferred language to prevent subsequent redirections
Expand All @@ -99,7 +100,10 @@ Here are all the options available when configuring the module and their default
// Set to always redirect to value stored in the cookie, not just once
alwaysRedirect: false,
// If no locale for the browsers locale is a match, use this one as a fallback
fallbackLocale: null
fallbackLocale: null,
// Set to true (recommended for improved SEO) to only attempt to detect browser locale
// on the root path ("/") of the site. Only effective when using strategy other than 'no_prefix'.
onlyOnRoot: false,
},

// Set this to true if you're using different domains for each language
Expand Down
12 changes: 11 additions & 1 deletion docs/content/es/browser-language-detection.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,23 @@ Por defecto, **nuxt-i18n** intenta redirigir a los usuarios a su idioma preferid
```js{}[nuxt.config.js]

['nuxt-i18n', {
// ...
detectBrowserLanguage: {
useCookie: true,
cookieKey: 'i18n_redirected'
cookieKey: 'i18n_redirected',
// onlyOnRoot: true,
}
}]
```

<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.

</alert>

Browser language is detected either from `navigator` when running on client-side, or from the `accept-language` HTTP header. Configured `locales` (or locales `code`s when locales are specified in object form) are matched against locales reported by the browser (for example `en-US,en;q=0.9,no;q=0.8`). If there is no exact match for the full locale, the language code (letters before `-`) are matched against configured locales (for backward-compatibility).

Para evitar redirigir a los usuarios cada vez que visitan la aplicación, **nuxt-i18n** establece una cookie después de la primera redirección. Puede cambiar el nombre de la cookie configurando la opción `detectBrowserLanguage.cookieKey` a lo que desee, el valor predeterminado es _i18n_redirected_.

```js{}[nuxt.config.js]
Expand Down
27 changes: 22 additions & 5 deletions docs/content/es/options-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,19 @@ Aquí están todas las opciones disponibles al configurar el módulo y sus valor
```js
{
// vue-i18n configuration
// See documentation: http://kazupon.github.io/vue-i18n/api/#constructor-options
// To be able to pass more complex configuration options that can't be stringified, it's also
// supported to set this property to a path to a local configuration file. File needs to export
// a function (that will be passed a Nuxt context as a parameter) or plain object.
// Example path: '~/plugins/vue-i18n.js'
// Example file content:
// export default context => {
// return {
// modifiers: {
// snakeCase: (str) => str.split(' ').join('-')
// }
// }
// }
vueI18n: {},

// If true, vue-i18n-loader is added to Nuxt's Webpack config
Expand Down Expand Up @@ -49,7 +62,7 @@ Aquí están todas las opciones disponibles al configurar el módulo y sus valor
// - 'prefix_and_default': add locale prefix for every locale and default
strategy: 'prefix_except_default',

// Wether or not the translations should be lazy-loaded, if this is enabled,
// Whether or not the translations should be lazy-loaded, if this is enabled,
// you MUST configure langDir option, and locales must be an array of objects,
// each containing a file key
lazy: false,
Expand All @@ -66,9 +79,10 @@ Aquí están todas las opciones disponibles al configurar el módulo y sus valor
// }
rootRedirect: null,

// Enable browser language detection to automatically redirect user
// to their preferred language as they visit your app for the first time
// Set to false to disable
// Enable browser language detection to automatically redirect visitors to their
// preferred language as they visit your site for the first time.
// Note that for better SEO it's recommended to set 'onlyOnRoot' to true.
// Set to false to disable.
detectBrowserLanguage: {
// If enabled, a cookie is set once a user has been redirected to his
// preferred language to prevent subsequent redirections
Expand All @@ -86,7 +100,10 @@ Aquí están todas las opciones disponibles al configurar el módulo y sus valor
// Set to always redirect to value stored in the cookie, not just once
alwaysRedirect: false,
// If no locale for the browsers locale is a match, use this one as a fallback
fallbackLocale: null
fallbackLocale: null,
// Set to true (recommended for improved SEO) to only attempt to detect browser locale
// on the root path ("/") of the site. Only effective when using strategy other than 'no_prefix'.
onlyOnRoot: false,
},

// Set this to true if you're using different domains for each language
Expand Down
3 changes: 2 additions & 1 deletion src/helpers/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ exports.DEFAULT_OPTIONS = {
cookieKey: 'i18n_redirected',
cookieSecure: false,
alwaysRedirect: false,
fallbackLocale: ''
fallbackLocale: '',
onlyOnRoot: false
},
differentDomains: false,
seo: false,
Expand Down
25 changes: 15 additions & 10 deletions src/templates/plugin.main.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {

Vue.use(VueI18n)

const { alwaysRedirect, onlyOnRoot, fallbackLocale } = detectBrowserLanguage
const getLocaleFromRoute = createLocaleFromRouteGetter(localeCodes, { routesNameSeparator, defaultLocaleRouteNameSuffix })

/** @type {import('@nuxt/types').Plugin} */
Expand Down Expand Up @@ -79,10 +80,10 @@ export default async (context) => {

if (!initialSetup) {
app.i18n.beforeLanguageSwitch(oldLocale, newLocale)
}

if (useCookie) {
app.i18n.setLocaleCookie(newLocale)
}
if (useCookie) {
app.i18n.setLocaleCookie(newLocale)
}

// Lazy-loading enabled
Expand Down Expand Up @@ -124,7 +125,11 @@ export default async (context) => {
}

if (getLocaleFromRoute(route) === locale) {
return ''
// If "onlyOnRoot" is set and strategy is "prefix_and_default", prefer unprefixed route for
// default locale.
if (!onlyOnRoot || locale !== defaultLocale || strategy !== STRATEGIES.PREFIX_AND_DEFAULT) {
return ''
}
}

// At this point we are left with route that either has no or different locale.
Expand Down Expand Up @@ -166,21 +171,23 @@ export default async (context) => {
app.i18n.__baseUrl = resolveBaseUrl(baseUrl, context)

const finalLocale =
(detectBrowserLanguage && doDetectBrowserLanguage()) ||
(detectBrowserLanguage && doDetectBrowserLanguage(route)) ||
getLocaleFromRoute(route) || app.i18n.locale || app.i18n.defaultLocale || ''

await app.i18n.setLocale(finalLocale)

return [null, null]
}

const doDetectBrowserLanguage = () => {
const doDetectBrowserLanguage = route => {
// Browser detection is ignored if it is a nuxt generate.
if (process.static && process.server) {
return false
}

const { alwaysRedirect, fallbackLocale } = detectBrowserLanguage
if (onlyOnRoot && strategy !== STRATEGIES.NO_PREFIX && route.path !== '/') {
return false
}

let matchedLocale

Expand All @@ -199,8 +206,6 @@ export default async (context) => {
if (finalLocale && (!useCookie || alwaysRedirect || !app.i18n.getLocaleCookie())) {
if (finalLocale !== app.i18n.locale) {
return finalLocale
} else if (useCookie && !app.i18n.getLocaleCookie()) {
app.i18n.setLocaleCookie(finalLocale)
}
}

Expand Down Expand Up @@ -244,7 +249,7 @@ export default async (context) => {
}
}

let finalLocale = detectBrowserLanguage && doDetectBrowserLanguage()
let finalLocale = detectBrowserLanguage && doDetectBrowserLanguage(route)

if (!finalLocale) {
if (vuex && vuex.syncLocale && store && store.state[vuex.moduleName].locale !== '') {
Expand Down
5 changes: 2 additions & 3 deletions src/templates/plugin.routing.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,10 @@ function getRouteBaseName (givenRoute) {
}

function getLocaleRouteName (routeName, locale) {
const name = routeName + (strategy === STRATEGIES.NO_PREFIX ? '' : routesNameSeparator + locale)
let name = routeName + (strategy === STRATEGIES.NO_PREFIX ? '' : routesNameSeparator + locale)

// Match route without prefix for default locale
if (locale === defaultLocale && strategy === STRATEGIES.PREFIX_AND_DEFAULT) {
return name + routesNameSeparator + defaultLocaleRouteNameSuffix
name += routesNameSeparator + defaultLocaleRouteNameSuffix
}

return name
Expand Down
Loading