I’m using next-translate. By default, my routes are recognized as follows:
/about <--- /de/about /es/about
but I’d like to enforce a locale for all paths:
/en/about <--- /de/about /es/about
Here’s my config:
next.config.js
const nextTranslate = require('next-translate');
module.exports = nextTranslate({
...
i18n: {
localeDetection: false,
locales: ['en', 'de', 'es'],
defaultLocale: 'en',
}
});
i18n.js
module.exports = {
locales: ['en', 'de', 'es'],
defaultLocale: 'en',
pages: {
'*': ['common']
},
interpolation: {
prefix: '${',
suffix: '}',
},
loadLocaleFrom: (locale, namespace) =>
import(`./translations/${locale}/${namespace}`).then((m) => m.default),
}
Note that I also have a lang change component that persists the NEXT_LOCALE cookie. As such, I would expect that when I access /about and my NEXT_LOCALE cookie had previously been set to de, the router would redirect me to /de/about. But it does not. It stays at /about and rewrites the cookie to en…
Here’s current pages folder structure:
... pages/ _app.tsx _document.tsx about.tsx ...
Do I need to restructure it to this?
pages/
_app.tsx
_document.tsx
[lang]/ <---
about.tsx
...
If so, what would be the next step?
- Parse the preferred locale through
useRouter() - Parse the
NEXT_LOCALEcookie - Parse the
langslug
and then decide which has higher precedence? Where should I do that? In _app.tsx / some HOC?
Do I need any rewrites or redirects in my next.config.js or should I handle these dynamically through Router.push?
Advertisement
Answer
The fact that the persisted NEXT_LOCALE cookie doesn’t automatically redirect based on its value is because you have explicitly disabled it by setting localeDetection: false. This affects the header-based redirection as well as the cookie-based one.
Simply removing it from your next.config.js should solve that issue.
There’s no built-in way to force the default locale on all paths. However, there are a couple of workarounds that could help with prefixing the default locale on the URL.
Workaround #1: Set default locale to default, and redirect in middleware
As documented in the i18n Routing documentation, add a new “dummy” locale named default and set it as the default locale. Note that this locale won’t actually be used, it will simply allow us to have the en locale always prefixed on its paths.
// next.config.js
module.exports = {
i18n: {
locales: ['default', 'en', 'de', 'es'],
defaultLocale: 'default'
}
}
Next, create a middleware file to redirect to the /en prefix if a request is made to the default locale.
// middleware.js
import { NextResponse } from 'next/server'
const PUBLIC_FILE = /.(.*)$/
export function middleware(request) {
const shouldHandleLocale = !PUBLIC_FILE.test(request.nextUrl.pathname)
&& !request.nextUrl.pathname.includes('/api/')
&& request.nextUrl.locale === 'default'
if (shouldHandleLocale) {
const url = request.nextUrl.clone()
url.pathname = `/en${request.nextUrl.pathname}`
return NextResponse.redirect(url)
}
return undefined
}
Workaround #2: Shallow routing to prefixed path on the client-side
Alternatively, you could check for the default locale and set it explicitly in the URL on first mount through router.push.
Let’s assume the following custom useDefaultLocale hook that abstracts the logic to be re-used.
import { useState, useEffect } from 'react';
import { useRouter } from 'next/router';
export const useDefaultLocale = () => {
const router = useRouter();
useEffect(() => {
if (router.locale === router.defaultLocale) {
router.push(`/${router.locale}${router.asPath}`, undefined, {
locale: false,
shallow: true // Optionally add this if you don't want to rerun data fetching methods
});
}
}, [router.asPath]);
};
Which could then be used in your pages or _app.js.
import { useDefaultLocale } from '<path-to>/use-default-locale';
const AboutPage = () => {
useDefaultLocale()
return <>About Page</>;
};