Skip to content

Commit d1bbc84

Browse files
Magnum5234TheAlexLichter
authored andcommitted
feat: rework browser detection and save lang to cookie (#148)
1 parent 9b1b5d5 commit d1bbc84

File tree

4 files changed

+103
-70
lines changed

4 files changed

+103
-70
lines changed

docs/browser-language-detection.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,14 @@ To completely disable the browser's language detection feature, set `detectBrows
4848
detectBrowserLanguage: false
4949
}]
5050
```
51+
52+
To redirect the user every time they visit the app and keep their selected choice, enable alwaysRedirect:
53+
54+
```js
55+
// nuxt.config.js
56+
57+
['nuxt-i18n', {
58+
useCookie: true,
59+
alwaysRedirect: true
60+
}]
61+
```

docs/options-reference.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,11 @@ Here are all the options available when configuring the module and their default
5555
// Set to false to redirect every time
5656
useCookie: true,
5757
// Cookie name
58-
cookieKey: 'i18n_redirected'
58+
cookieKey: 'i18n_redirected',
59+
// Set to always redirect to value stored in the cookie, not just once
60+
alwaysRedirect: false,
61+
// If no locale for the browsers locale is a match, use this one as a fallback
62+
fallbackLocale: null
5963
},
6064

6165
// Set this to true if you're using different domains for each language

src/helpers/constants.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ exports.DEFAULT_OPTIONS = {
3333
rootRedirect: null,
3434
detectBrowserLanguage: {
3535
useCookie: true,
36-
cookieKey: 'i18n_redirected'
36+
cookieKey: 'i18n_redirected',
37+
alwaysRedirect: '',
38+
fallbackLocale: null
3739
},
3840
differentDomains: false,
3941
forwardedHost: false,

src/templates/middleware.js

Lines changed: 84 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -33,91 +33,107 @@ middleware['i18n'] = async ({ app, req, res, route, store, redirect, isHMR }) =>
3333

3434
// Handle browser language detection
3535
const detectBrowserLanguage = <%= JSON.stringify(options.detectBrowserLanguage) %>
36+
const routeLocale = getLocaleFromRoute(route, routesNameSeparator, locales)
37+
38+
const getCookie = () => {
39+
if (isSpa) {
40+
return Cookies.get(cookieKey);
41+
} else if (req && typeof req.headers.cookie !== 'undefined') {
42+
const cookies = req.headers && req.headers.cookie ? cookie.parse(req.headers.cookie) : {}
43+
return cookies[cookieKey]
44+
}
45+
return null
46+
}
47+
48+
const setCookie = (locale) => {
49+
const date = new Date()
50+
if (isSpa) {
51+
Cookies.set(cookieKey, locale, {
52+
expires: new Date(date.setDate(date.getDate() + 365))
53+
})
54+
} else if (res) {
55+
const redirectCookie = cookie.serialize(cookieKey, locale, {
56+
expires: new Date(date.setDate(date.getDate() + 365))
57+
})
58+
res.setHeader('Set-Cookie', redirectCookie)
59+
}
60+
}
61+
62+
const { useCookie, cookieKey, alwaysRedirect, fallbackLocale } = detectBrowserLanguage
63+
64+
const switchLocale = async (newLocale) => {
65+
// Abort if different domains option enabled
66+
if (app.i18n.differentDomains) {
67+
return
68+
}
69+
70+
// Abort if newLocale did not change
71+
if (newLocale === app.i18n.locale) {
72+
return
73+
}
74+
75+
const oldLocale = app.i18n.locale
76+
app.i18n.beforeLanguageSwitch(oldLocale, newLocale)
77+
if(useCookie) {
78+
setCookie(newLocale)
79+
}
80+
// Lazy-loading enabled
81+
if (lazy) {
82+
const { loadLanguageAsync } = require('./utils')
83+
const messages = await loadLanguageAsync(app.i18n, newLocale)
84+
app.i18n.locale = newLocale
85+
app.i18n.onLanguageSwitched(oldLocale, newLocale)
86+
syncVuex(locale, messages)
87+
} else {
88+
// Lazy-loading disabled
89+
app.i18n.locale = newLocale
90+
app.i18n.onLanguageSwitched(oldLocale, newLocale)
91+
syncVuex(newLocale, app.i18n.getLocaleMessage(newLocale))
92+
}
93+
}
3694

3795
if (detectBrowserLanguage) {
38-
// Get browser language either from navigator if running in mode SPA, or from the headers
39-
let browserLocale = null
40-
if (isSpa && typeof navigator !== 'undefined' && navigator.language) {
96+
let browserLocale
97+
98+
if (useCookie && (browserLocale = getCookie()) && browserLocale !== 1 && browserLocale !== '1') {
99+
// Get preferred language from cookie if present and enabled
100+
// Exclude 1 for backwards compatibility and fallback when fallbackLocale is empty
101+
} else if (isSpa && typeof navigator !== 'undefined' && navigator.language) {
102+
// Get browser language either from navigator if running in mode SPA, or from the headers
41103
browserLocale = navigator.language.toLocaleLowerCase().substring(0, 2)
42104
} else if (req && typeof req.headers['accept-language'] !== 'undefined') {
43105
browserLocale = req.headers['accept-language'].split(',')[0].toLocaleLowerCase().substring(0, 2)
44106
}
45107

46108
if (browserLocale) {
47-
const { useCookie, cookieKey } = detectBrowserLanguage
48-
49-
const redirectToBrowserLocale = () => {
109+
// Handle cookie option to prevent multiple redirections
110+
if(!useCookie || alwaysRedirect || !getCookie()) {
50111
const routeName = route && route.name ? app.getRouteBaseName(route) : 'index'
51-
if (browserLocale && browserLocale !== app.i18n.locale && locales.indexOf(browserLocale) !== -1) {
52-
redirect(app.localePath(Object.assign({}, route , {
53-
name: routeName
54-
}), browserLocale))
55-
}
56-
}
112+
let redirectToLocale = fallbackLocale
57113

58-
const getCookie = () => {
59-
if (isSpa) {
60-
return Cookies.get(cookieKey);
61-
} else if (req && typeof req.headers.cookie !== 'undefined') {
62-
const cookies = req.headers && req.headers.cookie ? cookie.parse(req.headers.cookie) : {}
63-
return cookies[cookieKey]
114+
// Use browserLocale if we support it, otherwise use fallbackLocale
115+
if(locales.indexOf(browserLocale) !== -1) {
116+
redirectToLocale = browserLocale
64117
}
65-
return null
66-
}
67118

68-
const setCookie = () => {
69-
const date = new Date()
70-
if (isSpa) {
71-
Cookies.set(cookieKey, 1, {
72-
expires: new Date(date.setDate(date.getDate() + 365))
73-
})
74-
} else if (res) {
75-
const redirectCookie = cookie.serialize(cookieKey, 1, {
76-
expires: new Date(date.setDate(date.getDate() + 365))
77-
})
78-
res.setHeader('Set-Cookie', redirectCookie)
119+
if(useCookie){
120+
setCookie(redirectToLocale || 1)
79121
}
80-
}
81122

82-
// Handle cookie option to prevent multiple redirections
83-
if (useCookie) {
84-
if (!getCookie()) {
85-
// Set cookie
86-
setCookie()
87-
redirectToBrowserLocale()
88-
}
89-
} else {
90-
redirectToBrowserLocale()
91-
}
92-
}
93-
}
123+
if (redirectToLocale && redirectToLocale !== app.i18n.locale && locales.indexOf(redirectToLocale) !== -1) {
94124

95-
// Abort if different domains option enabled
96-
if (app.i18n.differentDomains) {
97-
return
98-
}
125+
// We switch the locale before redirect to prevent loops
126+
await switchLocale(redirectToLocale)
99127

100-
const routeLocale = getLocaleFromRoute(route, routesNameSeparator, locales)
101-
locale = routeLocale ? routeLocale : locale
128+
redirect(app.localePath(Object.assign({}, route , {
129+
name: routeName
130+
}), redirectToLocale))
102131

103-
// Abort if locale did not change
104-
if (locale === app.i18n.locale) {
105-
return
132+
return
133+
}
134+
}
135+
}
106136
}
107137

108-
const oldLocale = app.i18n.locale
109-
app.i18n.beforeLanguageSwitch(oldLocale, locale)
110-
// Lazy-loading enabled
111-
if (lazy) {
112-
const { loadLanguageAsync } = require('./utils')
113-
const messages = await loadLanguageAsync(app.i18n, locale)
114-
app.i18n.locale = locale
115-
app.i18n.onLanguageSwitched(oldLocale, locale)
116-
syncVuex(locale, messages)
117-
} else {
118-
// Lazy-loading disabled
119-
app.i18n.locale = locale
120-
app.i18n.onLanguageSwitched(oldLocale, locale)
121-
syncVuex(locale, app.i18n.getLocaleMessage(locale))
122-
}
138+
await switchLocale(locale = routeLocale ? routeLocale : locale)
123139
}

0 commit comments

Comments
 (0)