Tips for maintaining i18n locale slugs and ensuring i18n consistency when reloading in Next.js

I'm currently utilizing next-translate. The default recognition of my routes is as follows:

/about         <---
/de/about
/es/about

However, I would like to set a specific locale for all paths:

/en/about      <---
/de/about
/es/about

Below is the configuration I am using:

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),
}

It's important to note that I have a language change component that stores the NEXT_LOCALE cookie. Despite this, when I visit /about with a previously set cookie value of de, the router does not redirect me to /de/about. Instead, it remains at /about and changes the cookie value to en...

The current structure of my pages folder is as follows:

...
pages/
  _app.tsx
  _document.tsx
  about.tsx
  ...

Should I reorganize it to look like this?

pages/
  _app.tsx
  _document.tsx
  [lang]/         <---
    about.tsx
    ...

If yes, what steps should I take next?

  • Extract the preferred locale using useRouter()
  • Retrieve the NEXT_LOCALE cookie value
  • Analyze the lang slug

and then decide on the priority? Where should these processes be implemented? In _app.tsx or in a Higher Order Component?

Are there any necessary rewrites or redirects in my next.config.js, or should I handle these dynamically through Router.push?

Answer №1

When the persisted NEXT_LOCALE cookie doesn't automatically redirect based on its value, it's because you have specifically disabled it by setting localeDetection: false. This disables both header-based and cookie-based redirection.

To resolve this issue, simply remove the setting from your next.config.js.


There isn't a built-in method to enforce the default locale on all paths. However, there are some workarounds that can help in prefixing the default locale on the URL.

Workaround #1: Set default locale to default, and perform a redirect in middleware

As described in the i18n Routing documentation, create a dummy locale named default and set it as the default. This doesn't actually use the locale but allows us to always have the en locale prefixed on paths.

// next.config.js
module.exports = {
    i18n: {
        locales: ['default', 'en', 'de', 'es'],
        defaultLocale: 'default'
    }
}

Next, implement a middleware file to redirect to the /en prefix when 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: Implement shallow routing with a prefixed path on the client-side

Alternatively, you can check for the default locale and explicitly set it in the URL on initial mount using router.push.

For example, consider using a custom hook like useDefaultLocale to streamline this logic for reuse.

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 // Include this if data fetching methods shouldn't be rerun
            });
        }
    }, [router.asPath]);
};

This hook could then be applied in your pages or _app.js.

import { useDefaultLocale } from '<path-to>/use-default-locale';

const AboutPage = () => {
    useDefaultLocale()

    return <>About Page</>;
};

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

merge two structures to create a unified entity

I have been searching in vain, can you please advise me on how to combine these two simple forms into one? I want it to be like a box with a select option and a button. The challenge for me is merging the two different actions, ".asp", into one script fo ...

Is there a way to order the execution of two functions that each produce promises?

With my code, I first check the status of word.statusId to see if it's dirty. If it is, I update the word and then proceed to update wordForms. If it's clean, I simply update wordForms. I'm looking for advice on whether this is the correct a ...

Bringing in a script and invoking a function on a specific variable

As a newcomer to Typescript, I've been experimenting with some code I came across online to enhance the appearance of links on my website. <script src="https://wow.zamimg.com/widgets/power.js"></script> <script>var wowhead_tooltips ...

What is the standard error function used for jQuery promises?

Is there a way to establish a default error handling function for a jQuery promise? I am running a series of functions asynchronously, and if any of them encounter an error, I want the error to be reported. Currently, this is how I have to handle it: fun ...

The JSX component. 'ReactSVG' is not allowed for use

For my first React/Next.js project, I encountered the task of importing an SVG file and making modifications before rendering it. After some research, I decided to use react-svg from https://github.com/tanem/react-svg/, which worked perfectly during develo ...

Simple solution for storing key-value pairs temporarily in a form using JQuery

Is there an elegant method to temporarily store an array of string values in a form? In my article editing form, users can add tags as string values. I don't want these tags to be persisted until the user saves the entire article, so I require a way ...

Receive a response in fragments from express on the browser

As I work on creating a progress bar to track long-running server-side tasks that may take up to a few minutes, I am exploring different methods to display the progress of each task. While WebSockets and interval polling are options, I prefer using long-po ...

Discover the most affordable price from an array in Vue Js

One of the challenges I'm facing involves working with an array that loops through all the trips for a listing. <span v-for="price in listing.trips"> <div class="price">{{ price.cost }} </div> </span> I'm wonderin ...

Leverage ESlint for optimal code quality in your expressjs

Is there a way to use ESlint with Express while maintaining the no-unused-vars rule? After enabling ESlint, I am encountering the following issue: https://i.stack.imgur.com/7841z.png I am interested in disabling the no-unused-vars rule exclusively for e ...

Upgrade the jQuery code from version 1.4.2 min to version 1.10.2 min

Hey there, I'm looking for assistance with updating the code below to use jQuery 1.10.2. The backslashes are present because I am using it with PHP and need to escape special characters. I'm not very familiar with JavaScript and unsure of the ch ...

Tips for testing an API that relies on an external library such as "<script src="http://stripe[...]"

Currently, I am working on unit testing an API call to verify it has been executed with the correct properties. The API call is reliant on Stripe's external library that is connected to the window through index.html src="http://stripe[...]". However, ...

Is it possible to send the value of "this" as an argument to a different function in JavaScript?

I currently have the following code: $('#slider li').click(function () { var stepClicked = $(this).index(); alert(stepClicked); if (stepClicked != 0) { $('#cs_previous').removeClass('cs_hideMe'); } els ...

Executing Basic Calculations Instantly with Live Data in Qualtrics

I am encountering an issue with displaying the values on a slider in Qualtrics. I need to show the value where the respondent has placed the handle, as well as the complementary value from the other end of the scale. For example, if the user has chosen 55, ...

Upon Login, No API Requests are Initiated in Next.js Application

I'm currently working on a Next.js project and encountering an issue where my API is not receiving any requests when attempting to log in. I'm struggling to pinpoint the root cause of this problem. Below, you'll find the project structure an ...

Devices such as CAC cards and smart cards are not being recognized by Chrome's WebUSB feature

I recently developed a script to identify all USB devices connected to Chrome using chrome.usb.getDevices. Surprisingly, the script successfully detected a second-generation iPod touch, a mouse, keyboard, and two unidentified items from Intel. However, it ...

How come outerHTML retrieves <!-- --> comments?

I came across a jsfiddle link that showcases the collection of outerHTML for elements with a class='active'. Surprisingly, even when certain parts of the HTML are commented out like this: <!-- <div>'Some inner text'</d ...

What is the best way to test the Express router catch branch in this specific scenario with Jest?

My current task involves working with a file containing two routes. The first route is located in routes/index.js const express = require('express') const router = express.Router() router.get('', (req, res, next) => { try { r ...

Is it possible to dynamically add and remove items using React state?

I am currently working on implementing a dynamic queue of game players in my React state. The goal is to avoid hardcoding the number of players who can participate and achieve this state update using a JS FIFO queue. My objective is to create a player que ...

What is the best way to interact with all the rendered DOM elements in React that were created using the map method

return <div> <div >{'Audios'}</div> {urls.map(url => <div > <audio controls src={url} ref={(element) => this.audioRefs.push(element)} /> </div>)} </div>; I a ...

How come the method $.when().pipe().then() is functioning properly while $.when().then().then() is not working as expected

I'm still grappling with the concept of using JQuery's Deferred objects, and am faced with a puzzling issue. In this code snippet, my attempt to chain deferred.then() was unsuccessful as all three functions executed simultaneously. It wasn't ...