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_LOCALE
cookie - Parse the
lang
slug
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</>; };