4

Currently, Next.js makes a redirect to the user's language only from the root, so "/" becomes "/fr-FR". But if a user accesses for example "/profile" route, it won't redirect him to the "/fr-FR/profile".

Is there a way to force Next to do these kinds of redirects?

Gucal
  • 842
  • 1
  • 11
  • 19
Bohdan Kontsedal
  • 111
  • 3
  • 12
  • 1
    This is a highly rated feature request, https://github.com/vercel/next.js/discussions/18419 – AviKKi Aug 09 '21 at 23:59
  • Does this answer your question: [How to enforce i18n locale slugs and achieve i18n consistency upon reload in Next.js?](https://stackoverflow.com/questions/67149545/how-to-enforce-i18n-locale-slugs-and-achieve-i18n-consistency-upon-reload-in-nex)? – juliomalves Jul 24 '22 at 06:03

5 Answers5

1

For me the key was to set up my _middleware.ts the following way:

const PUBLIC_FILE = /\.(.*)$/ // anything having a file extension.
const getIsInternalRoute = (url: string) => {
    if (url.startsWith('/_next')) return true // next internal routes
    if (url.includes('/api/')) return true // nextjs api routes
    return PUBLIC_FILE.test(url) // static files
}

const handleLocaleRedirects = (req: NextRequest) => {
    const { pathname } = req.nextUrl
    const isPreloadRequest = req.method === 'HEAD'
    /*
    Due to several bugs with prefetching/middleware/i18n combination
    https://github.com/vercel/next.js/issues/35648
    https://github.com/vercel/next.js/issues/36100
    https://github.com/vercel/next.js/issues/40678

    we cannot redirect any prefetch requests. They get cached with the current locale which then causes
    infinite loop redirect when we click a link to change the locale.
    Possibly might be fixed in later NextJs versions (>=13), but I'd be really careful & skeptical here.
     */
    if (isPreloadRequest || getIsInternalRoute(pathname)) return

    const locale = req.cookies.NEXT_LOCALE || req.nextUrl.defaultLocale // locale you're supposed to have
    if (locale && req.nextUrl.locale !== locale) {
        req.nextUrl.locale = locale
        return NextResponse.redirect(req.nextUrl)
    }
}

export function middleware(req: NextRequest) {
    const maybeRedirectResponse = handleLocaleRedirects(req)
    if (maybeRedirectResponse) return maybeRedirectResponse

    const response = NextResponse.next()

    // perhaps other middleware logic here...

    return response
}

and set up the switcher link to set the cookie before redirecting to the new route, so the middleware already has the new NEXT_LOCALE value.

function LocaleSwitcher({ locale, children, ...props }) {
    const router = useRouter()
    const { pathname, asPath, query } = router

    const handleClick = e => {
        e.preventDefault()

        /*
        The locale cookie needs to be set before the page redirect, so the nextjs middleware already knows which locale is correct.
         */
        setCookie({}, 'NEXT_LOCALE', locale, {
            maxAge: 100 * 365 * 24 * 60 * 60, // 100 yrs
        })
        // change just the locale and maintain all other route information including href's query
        router.push({ pathname, query }, asPath, { locale })
    }

    return (
        <Link {...props} locale={locale} to={asPath} onClick={handleClick}>
            {children}
        </Link>
    )
}

This setup checks the user's locale from the cookie on every route and redirects them to the correct locale version of the site.

0

Check out this Page from the official NextJS Documentation:

Prefixing the Default Locale

It solves your problem by redirecting domain.com/example to domain.com/en/example

sakramento
  • 369
  • 5
  • 16
0

You can do it with middleware and NEXT_LOCALE cookie, when you change language you should set this cookie

document.cookie = `NEXT_LOCALE=${langugage};path=/`;

middleware.js

import { NextResponse } from "next/server";

export function middleware(request) {
  const localeCookie = request.cookies.get("NEXT_LOCALE");
  if (localeCookie !== undefined && request.nextUrl.locale !== localeCookie) {
    return NextResponse.redirect(new URL(`/${localeCookie}${request.nextUrl.pathname}`, request.url));
  }
}
export const config = { 
  matcher: ["/", "/about"], // paths on which middleware will work
};

https://nextjs.org/docs/advanced-features/i18n-routing#leveraging-the-next_locale-cookie

https://nextjs.org/docs/advanced-features/i18n-routing#prefixing-the-default-locale

https://nextjs.org/docs/advanced-features/middleware

https://nextjs.org/docs/messages/middleware-upgrade-guide

https://nextjs.org/docs/api-reference/next/server

0

This reference https://nextjs.org/docs/advanced-features/i18n-routing#transition-between-locales:

router.push(router.asPath, router.asPath, { locale: language });
kolserdav
  • 260
  • 4
  • 14
-1
Sub-path Routing
Sub-path Routing puts the locale in the url path.

With the above configuration en-US, fr, and nl-NL will be available to be routed to, and en-US is the default locale. If you have a pages/blog.js the following urls would be available:

//next.config.js
module.exports = {
  i18n: {
    locales: ['en-US', 'fr', 'nl-NL'],
    defaultLocale: 'en-US',
  },
}

/blog
/fr/blog
/nl-nl/blog
The default locale does not have a prefix.

from Nextjs docs