Skip to content

Commit

Permalink
feat: rework browser detection and save lang to cookie (#148)
Browse files Browse the repository at this point in the history
  • Loading branch information
Magnum5234 authored and manniL committed Nov 15, 2018
1 parent 9b1b5d5 commit d1bbc84
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 70 deletions.
11 changes: 11 additions & 0 deletions docs/browser-language-detection.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,14 @@ To completely disable the browser's language detection feature, set `detectBrows
detectBrowserLanguage: false
}]
```

To redirect the user every time they visit the app and keep their selected choice, enable alwaysRedirect:

```js
// nuxt.config.js

['nuxt-i18n', {
useCookie: true,
alwaysRedirect: true
}]
```
6 changes: 5 additions & 1 deletion docs/options-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,11 @@ Here are all the options available when configuring the module and their default
// Set to false to redirect every time
useCookie: true,
// Cookie name
cookieKey: 'i18n_redirected'
cookieKey: 'i18n_redirected',
// 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
},

// Set this to true if you're using different domains for each language
Expand Down
4 changes: 3 additions & 1 deletion src/helpers/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ exports.DEFAULT_OPTIONS = {
rootRedirect: null,
detectBrowserLanguage: {
useCookie: true,
cookieKey: 'i18n_redirected'
cookieKey: 'i18n_redirected',
alwaysRedirect: '',
fallbackLocale: null
},
differentDomains: false,
forwardedHost: false,
Expand Down
152 changes: 84 additions & 68 deletions src/templates/middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,91 +33,107 @@ middleware['i18n'] = async ({ app, req, res, route, store, redirect, isHMR }) =>

// Handle browser language detection
const detectBrowserLanguage = <%= JSON.stringify(options.detectBrowserLanguage) %>
const routeLocale = getLocaleFromRoute(route, routesNameSeparator, locales)

const getCookie = () => {
if (isSpa) {
return Cookies.get(cookieKey);
} else if (req && typeof req.headers.cookie !== 'undefined') {
const cookies = req.headers && req.headers.cookie ? cookie.parse(req.headers.cookie) : {}
return cookies[cookieKey]
}
return null
}

const setCookie = (locale) => {
const date = new Date()
if (isSpa) {
Cookies.set(cookieKey, locale, {
expires: new Date(date.setDate(date.getDate() + 365))
})
} else if (res) {
const redirectCookie = cookie.serialize(cookieKey, locale, {
expires: new Date(date.setDate(date.getDate() + 365))
})
res.setHeader('Set-Cookie', redirectCookie)
}
}

const { useCookie, cookieKey, alwaysRedirect, fallbackLocale } = detectBrowserLanguage

const switchLocale = async (newLocale) => {
// Abort if different domains option enabled
if (app.i18n.differentDomains) {
return
}

// Abort if newLocale did not change
if (newLocale === app.i18n.locale) {
return
}

const oldLocale = app.i18n.locale
app.i18n.beforeLanguageSwitch(oldLocale, newLocale)
if(useCookie) {
setCookie(newLocale)
}
// Lazy-loading enabled
if (lazy) {
const { loadLanguageAsync } = require('./utils')
const messages = await loadLanguageAsync(app.i18n, newLocale)
app.i18n.locale = newLocale
app.i18n.onLanguageSwitched(oldLocale, newLocale)
syncVuex(locale, messages)
} else {
// Lazy-loading disabled
app.i18n.locale = newLocale
app.i18n.onLanguageSwitched(oldLocale, newLocale)
syncVuex(newLocale, app.i18n.getLocaleMessage(newLocale))
}
}

if (detectBrowserLanguage) {
// Get browser language either from navigator if running in mode SPA, or from the headers
let browserLocale = null
if (isSpa && typeof navigator !== 'undefined' && navigator.language) {
let browserLocale

if (useCookie && (browserLocale = getCookie()) && browserLocale !== 1 && browserLocale !== '1') {
// Get preferred language from cookie if present and enabled
// Exclude 1 for backwards compatibility and fallback when fallbackLocale is empty
} else if (isSpa && typeof navigator !== 'undefined' && navigator.language) {
// Get browser language either from navigator if running in mode SPA, or from the headers
browserLocale = navigator.language.toLocaleLowerCase().substring(0, 2)
} else if (req && typeof req.headers['accept-language'] !== 'undefined') {
browserLocale = req.headers['accept-language'].split(',')[0].toLocaleLowerCase().substring(0, 2)
}

if (browserLocale) {
const { useCookie, cookieKey } = detectBrowserLanguage

const redirectToBrowserLocale = () => {
// Handle cookie option to prevent multiple redirections
if(!useCookie || alwaysRedirect || !getCookie()) {
const routeName = route && route.name ? app.getRouteBaseName(route) : 'index'
if (browserLocale && browserLocale !== app.i18n.locale && locales.indexOf(browserLocale) !== -1) {
redirect(app.localePath(Object.assign({}, route , {
name: routeName
}), browserLocale))
}
}
let redirectToLocale = fallbackLocale

const getCookie = () => {
if (isSpa) {
return Cookies.get(cookieKey);
} else if (req && typeof req.headers.cookie !== 'undefined') {
const cookies = req.headers && req.headers.cookie ? cookie.parse(req.headers.cookie) : {}
return cookies[cookieKey]
// Use browserLocale if we support it, otherwise use fallbackLocale
if(locales.indexOf(browserLocale) !== -1) {
redirectToLocale = browserLocale
}
return null
}

const setCookie = () => {
const date = new Date()
if (isSpa) {
Cookies.set(cookieKey, 1, {
expires: new Date(date.setDate(date.getDate() + 365))
})
} else if (res) {
const redirectCookie = cookie.serialize(cookieKey, 1, {
expires: new Date(date.setDate(date.getDate() + 365))
})
res.setHeader('Set-Cookie', redirectCookie)
if(useCookie){
setCookie(redirectToLocale || 1)
}
}

// Handle cookie option to prevent multiple redirections
if (useCookie) {
if (!getCookie()) {
// Set cookie
setCookie()
redirectToBrowserLocale()
}
} else {
redirectToBrowserLocale()
}
}
}
if (redirectToLocale && redirectToLocale !== app.i18n.locale && locales.indexOf(redirectToLocale) !== -1) {

// Abort if different domains option enabled
if (app.i18n.differentDomains) {
return
}
// We switch the locale before redirect to prevent loops
await switchLocale(redirectToLocale)

const routeLocale = getLocaleFromRoute(route, routesNameSeparator, locales)
locale = routeLocale ? routeLocale : locale
redirect(app.localePath(Object.assign({}, route , {
name: routeName
}), redirectToLocale))

// Abort if locale did not change
if (locale === app.i18n.locale) {
return
return
}
}
}
}

const oldLocale = app.i18n.locale
app.i18n.beforeLanguageSwitch(oldLocale, locale)
// Lazy-loading enabled
if (lazy) {
const { loadLanguageAsync } = require('./utils')
const messages = await loadLanguageAsync(app.i18n, locale)
app.i18n.locale = locale
app.i18n.onLanguageSwitched(oldLocale, locale)
syncVuex(locale, messages)
} else {
// Lazy-loading disabled
app.i18n.locale = locale
app.i18n.onLanguageSwitched(oldLocale, locale)
syncVuex(locale, app.i18n.getLocaleMessage(locale))
}
await switchLocale(locale = routeLocale ? routeLocale : locale)
}

0 comments on commit d1bbc84

Please sign in to comment.