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-intl
paired 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.
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!