'Redirect based on header OR cookie in Next.js next.config.js
We're using Next.js and want to route all paths (not just root) to locale-based paths based on the browser Accept-Language
header. However, if the user SETS their region, we will set a cookie that would need to be checked first to respect user preferences.
So we need to check for the cookie, and if it's not there, try redirect based on browser language header instead. We're using ISG so limited to next.config.js redirects serverside.
According to the docs, this should work, but since we're using ISG, we need to do this in next.config.js
redirects function.
We've tried this solution and it does not work (we get infinite redirects as both cookie AND header match):
const { i18n } = require('./next-i18next.config');
const withTM = require('next-transpile-modules')(['fitty', 'react-svg']); // pass the modules you would like to see transpiled
const handleLocaleRedirects = (path) => {
const result = [];
i18n.locales.forEach((locale) => {
i18n.locales.forEach((loc) => {
if (loc !== locale) {
result.push({
source: `/${locale}${path}`,
has: [
{
type: 'header',
key: 'accept-language',
value: `^${loc}(.*)`,
},
],
permanent: false,
locale: false,
destination: `/${loc}${path}`,
});
result.push({
source: `/${locale}${path}`,
has: [
{
type: 'cookie',
key: 'NEXT_LOCALE',
value: loc,
},
],
permanent: true,
locale: false,
destination: `/${loc}${path}`,
});
}
});
});
return result;
};
module.exports = withTM({
i18n,
reactStrictMode: true,
images: {
domains: [
'dxjnh2froe2ec.cloudfront.net',
'starsona-stb-usea1.s3.amazonaws.com',
],
},
eslint: {
// Warning: Dangerously allow production builds to successfully complete even if
// your project has ESLint errors.
ignoreDuringBuilds: true,
},
async redirects() {
return [...handleLocaleRedirects('/:celebrityId')];
},
});
Solution 1:[1]
I've managed to achieve this using _app.js
Add getInitialProps
inside _app.js
It checks cookie
inside request, gets current locale using ctx.locale
,
My default locale is en-IN
so if targetLocale
matches default locale it sets an empty string to targetLocale
, then redirects using header.
Other than that we don't have to use localeDetection
because we are handling on our own.
MyApp.getInitialProps = async ({ ctx }) => {
if (ctx.req) {
const rawCookies = ctx.req.headers.cookie
let locale = ctx.locale
const path = ctx.asPath
if (rawCookies != undefined) {
const cookies = cookie.parse(rawCookies)
let targetLocale = cookies['NEXT_LOCALE']
if (targetLocale != locale) {
if (targetLocale == 'en-IN') {
targetLocale = ''
} else {
targetLocale = '/' + targetLocale
}
ctx.res.writeHead(302, {
Location: `${targetLocale}${path}`
})
ctx.res.end()
}
}
}
return {}
}
Other than this, I'm showing modal when there is no cookie named NEXT_LOCALE
to handle first time users.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Sølve Tornøe |