i18n with Next.js + React.js + Typescript

i18n with Next.js + React.js + Typescript

By Gabriel Messias da Rosa

Requirements to understand the content

HTML CSS Typescript React.js Next.js

ATTENTION! Requires intermediate/advanced knowledge of the Next.js framework and the technologies involved in this article.


Internationalization (also known as i18n) and translation are the means of adapting the software to different languages, regional peculiarities and technical requirements of a target language.

Let's understand how i18n works on a website that uses Next.js + React as frameworks. We will carry out a simple but very efficient configuration to internationalize your website.

Starting with version 10 of Next.js, it is possible to perform this configuration in a simple, clear and native way.

The advantage of using the native i18n of Next.js, without external libraries, is the speed and fluidity with which the texts are changed on the site. Thus avoiding page reloading, preventing layout shift, which greatly improves user experience.

Let's suppose we have the following website:

Example website

We need it to have a “select” component that changes all the text on the page from English to Portuguese (Brazilian). We will also have to make, based on the default language of the user's browser, the language dynamically change, providing more comfort for the user when accessing our site.

Configuring the next.config.js file

The first step of configuring the i18n with Next.js is to correctly configure the next.config.js file.

For that add the default configuration provided by the official Next.js documentation.

Create or edit the next.config.js file and add the i18n module. As in the example below:

module.exports = {
  i18n: {
    locales: ["en", "pt-BR"],
    defaultLocale: "en",
  },
};
Next.js module i18n default configuration

The “locales” attribute must be an array of languages supported by the website. The other attribute, “defaultLocale”, must be one of the languages configured in “locales”. It will be the default language of the website if the language the user is using in their browser is not supported.

This configuration will use “subpath base routing“, that is, when we change the language to pt-BR the site will present itself as “www.example.com/pt-BR” and for the defaultLocale it will only be www.example.com/

As for the “lang” property of the <html/> tag, don't worry about that. Next.js “under the hood” identifies the browser's default language and changes this property to the user's preferred language.

Organizing files with text translations

From here, the developer's creativity comes into play, you can create a React context, a JSON file, an API with the translations, or whatever you prefer as long as you can access this data. In this case we will make it as vanilla as possible.

We organize the files inside a folder called “i18n” and inside this folder the files named with the locales that we configured in the next.config.js file. In this case we will only have 2 files, the file “en.ts” and “pt-br.ts”, as in the example below.

File organization example

According to your needs, assemble objects inside each file to represent each component and page that deserves a translation of its texts.

For example, my “en.ts” file looks like the example below.

export const en = {
  defaultLayoutComponents: {
    header: {
      navOption1: "Home",
      navOption2: "About",
      navOption3: "Users List",
    },
    footer: {
      p1: "I'm here to stay (Footer)",
    },
  },
  pages: {
    homePage: {
      h1: "Hello Next.js 👋",
    },
    aboutPage: {
      h1: "About",
      p1: "This is the about page",
    },
    usersListPage: {
      h1: "Users List",
      p1: "Example fetching data from inside getStaticProps().",
      p2: "You are currently on: /users",
    },
  },
};
Content of the en.ts file

For the file in another language, do the same, just changing the texts for your translation.

The pt-br translation file would look like this.

export const ptBr = {
  defaultLayoutComponents: {
    header: {
      navOption1: "Página inicial",
      navOption2: "Sobre",
      navOption3: "Lista de usuários",
    },
    footer: {
      p1: "Estou aqui para ficar (Rodapé)",
    },
  },
  pages: {
    homePage: {
      h1: "Olá Next.js 👋",
    },
    aboutPage: {
      h1: "Sobre",
      p1: "Esta é a página 'Sobre'",
    },
    usersListPage: {
      h1: "Lista de usuários",
      p1: "Exemplo de busca de dados de dentro de getStaticProps().",
      p2: "Atualmente você está em: /users",
    },
  },
};
Content of the pt-br.ts file

Applying the translation to the website

We will use one more feature of Next.js, the useRouter hook of Next.js. Deconstruct the variable “locale” from useRouter, then declare a constant called “translation” and make it return a condition: if locale is equal to “en” return the values from the en.ts file, otherwise return the values from the pt-br.ts file.

Adapt the translation return according to the amount of translations your site must support.

To do the translation, just replace the text of h1, which is hard coded, to the corresponding value in the translation file (en.ts and pt-br.ts)

As in the example below:

import { useRouter } from "next/router";
import Layout from "../src/components/Layout";
import { en } from "../src/i18n/en";
import { ptBr } from "../src/i18n/pt-br";
const IndexPage = () => {
  const { locale } = useRouter();
  const translation = locale === "en" ? en : ptBr;
  
  return (
    <Layout title="Home | Next.js + TypeScript Example">
      <h1>{translation.pages.homePage.h1}</h1>
    </Layout>
  );
};

export default IndexPage;
Example of a page with content being translated

Now the H1 tag on our home page is being translated to pt-br in case any user from Brazil is accessing our site.

Repeat the process for each text that needs to be translated.

The result is something like the example below.

Final result of configuring the entire site with translation.

Select of available translations

This is the simplest way to “switch” from one language to another.

Create a Select component to translate the page into another language.

Remembering that we are making it as vanilla as possible, so we will create a simple SelectLanguage component, with only the necessary options and a function to change the site's language, pushing the user to the selected translation route.

As in the example:

import { useRouter } from "next/router";

const SelectLanguage = () => {
  const { locale, push } = useRouter();

  const changeLanguage = (event) => {
    const locale = event.target.value;
    push("/", "/", { locale });
  };

  return (
    <select onChange={changeLanguage} defaultValue={locale}>
      <option value={"en"}>EN</option>
      <option value={"pt-BR"}>PT-BR</option>
    </select>
  );
};

export default SelectLanguage;
Example of a language select component

Add this select to a place where it appears on every page of the site, for a better user experience. In this case I added SelectLanguages to the header component.

Finally, we have a page being translated immediately. No page reloads or redirects.

Final result

This is the simplest way to internationalize a site that uses Next.js. With this knowledge, you are now able to adapt the presented techniques to your reality. Check the official Next.js documentation for what the next i18n has to offer.

You can also check out the sample project code cited in this article:

https://github.com/GabrielMessiasdaRosa/i18n-next-js

Happy hacking!

References

Advanced Features: Internationalized Routing | Next.js