NextJS Internationalization: Embrace a Global Audience with App Router and next-intl

In an increasingly connected world, where your website's audience might come from any corner of the globe, internationalization (i18n) is not just a courtesy—it's a must. For those building with NextJS, incorporating i18n strategies can seem daunting at first. However, with the help of App Router and the next-intl library, this task becomes not only manageable but also seamless.

In this in-depth guide, we'll walk you through the steps of implementing internationalization in your NextJS project by leveraging these robust tools. By the end, you'll be able to cater to a diverse audience in their language preferences, thus ensuring a global reach for your application.

Understanding NextJS Internationalization

Internationalization is the process of designing a software application so that it can be adapted to various languages and regions without requiring engineering changes. For web apps, this means enabling the display of your NextJS application in multiple languages based on user preferences or locale data.

NextJS has built-in support for internationalized routing since version 10, allowing the framework to handle different locales by defining them in the next.config.js file. However, managing the text translations can be where the complexity arises. To solve this, next-intl comes to the rescue.

What is next-intl?

next-intl is a powerful i18n library for NextJS that simplifies the management of translations and locale data. It offers a React provider and hooks to handle language switching and text display based on the active locale, making your app localization-ready with minimal fuss.

Step 1: Configuring NextJS Internationalization

The initial step is to set up your NextJS project for internationalization. In your next.config.js, you will need to add the i18n block, which includes the locales you intend to support and the default locale:

// next.config.js

module.exports = {
  i18n: {
    locales: ['en', 'de', 'fr'],
    defaultLocale: 'en',
  },
  // ... other configurations
};

Step 2: Integrating next-intl

Once the basic i18n configuration is complete, the next step is to integrate next-intl. Begin by installing the package in your project:

npm install next-intl
# or
yarn add next-intl

After adding it to your project, the core part of the next-intl integration is setting up the provider. In your _app.js or _app.tsx file, import and wrap your application in the NextIntlProvider:

import { NextIntlProvider } from 'next-intl';

function MyApp({ Component, pageProps }) {
  return (
    <NextIntlProvider messages={pageProps.messages}>
      <Component {...pageProps} />
    </NextIntlProvider>
  );
}

export default MyApp;

Step 3: Define Translation Messages

With next-intl, you'll house your translations in JSON files, ideally in a structured directory such as translations/en.json for English, translations/de.json for German, and so on:

// translations/en.json
{
  "greeting": "Hello, world!"
}

// translations/de.json
{
  "greeting": "Hallo, Welt!"
}

Step 4: Fetching Translations Using Middleware

One of the benefits of the new NextJS App Router is that you can handle loading translations server-side using middleware. This way, you preload the required translations for each route and pass them as props:

// middleware.js

import { NextResponse } from 'next/server';
import { applyServerHMR } from 'next-intl/server';

export function middleware(request) {
  const { nextUrl: { locale } } = request;
  const messages = require(`./translations/${locale}.json`); // pseudocode, sync loading for illustration
  const response = NextResponse.next();
  response.headers.set('X-Messages', JSON.stringify(messages));
  return response;
}

applyServerHMR(middleware);

Remember to adapt this to your actual project structure and asynchronous data fetching needs.

Step 5: Loading Translations on the Client

With the middleware configured to pass the translations, let’s load them on the client side:

// pages/_app.js

import { NextIntlProvider } from 'next-intl';

function MyApp({ Component, pageProps, router }) {
  const messages = router.query.messages || pageProps.messages;

  return (
    <NextIntlProvider messages={JSON.parse(messages)}>
      <Component {...pageProps} />
    </NextIntlProvider>
  );
}

export default MyApp;

Step 6: Using the Translations in Components

Inside your components, translating text is straightforward with next-intl:

import { useTranslations } from 'next-intl';

export default function Greeting() {
  const t = useTranslations('greeting');

  return <p>{t('greeting')}</p>;
}

This functional component fetches the appropriate translation based on the active locale. If you navigate to /en, it will display "Hello, world!" and for /de, it will show "Hallo, Welt!"


By following these steps, you will have a solid foundation for internationalizing your NextJS application. next-intlpaired with the App Router offers a development-friendly and user-centric approach to serving a global audience.

Remember, internationalization goes beyond just translations. Always consider the cultural nuances and regional differences — such as date formatting, currency conversion, and more — to ensure a truly localized experience for your users. With the flexibility of NextJS and next-intl, your application is well-equipped to welcome users from all over the world.

0
Subscribe to my newsletter

Read articles from Sebastian Goscinski directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sebastian Goscinski
Sebastian Goscinski

Hi there 👋, I´m Sebastian 👨‍💻 Passionate Full-Stack Developer with a knack for creating efficient and scalable applications. Enthusiastically exploring the world of web development with Next.js, React, Angular, and .NET. Join me as I share insights, tips, and best practices on building modern web applications. Let’s code something amazing together!