Next.js is an open-source framework created by Vercel (formerly ZEIT). It is built on top of React and provides an out-of-the-box solution for server-side rendering (SSR) of React components. Furthermore, it supports static site generation (SSG), which can help us to build superfast and user-friendly websites in no time. Although a relatively young framework, it has a good foundation for internationalization which complements well with existing i18n libraries. In the following chapters, we will explain how to set up internationalization in your Next.js app.
Create a new Next.js project
First, let's create a new Next.js project with the create-next-app CLI tool.
npx create-next-app nextjs-i18n-example
Add React Intl dependency
As we mentioned earlier, the Next.js works well with existing i18n libraries (react-intl, lingui, next-intl, and similar). In this tutorial, we will use the react-intl
.
cd nextjs-i18n-example
npm i react-intl
Add config for internationalized routing
Translations and routing are two main pillars of internationalization. The previously added react-intl
library is going to handle translations and formatting. When it comes to routing, Next.js has built-in support for that. This built-in support offers two options, sub-path routing, and domain routing. In this tutorial, we will use sub-path routing as it is less complex and more common for average websites. For that, let's update the next.config.js
file with the i18n
config.
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
i18n: {
// The locales you want to support in your app
locales: ["en", "fr"],
// The default locale you want to be used when visiting a non-locale prefixed path e.g. `/hello`
defaultLocale: "en",
},
};
module.exports = nextConfig;
Note: The internationalized routing is available since Next.js 10.
Create localization files
The next important thing is to add localization files. For that purpose, let's create a lang
directory. Within it, add two JSON files: en.json
and fr.json
. These files are going to hold translations for English and French, respectively. Below, you can see the project structure after adding the mentioned files.
nextjs-i18n-example
|-- lang
| |-- en.json
| |-- fr.json
|-- pages
| |-- api
| |-- _app.js
| |-- index.js
| |-- ...
|-- public
|-- ...
|-- package.json
|-- package-lock.json
Afterward, fill in localization files with messages that we will use later.
The en.json
file:
{
"page.home.head.title": "Next.js i18n example",
"page.home.head.meta.description": "Next.js i18n example - English",
"page.home.title": "Welcome to <b>Next.js i18n tutorial</b>",
"page.home.description": "You are currently viewing the homepage in English 🚀"
}
The fr.json
file:
{
"page.home.head.title": "Next.js i18n exemple",
"page.home.head.meta.description": "Next.js i18n exemple - Français",
"page.home.title": "Bienvenue à <b>Next.js i18n didacticiel</b>",
"page.home.description": "Vous consultez actuellement la page d'accueil en Français 🚀"
}
Configure react-intl in Next.js project
Internationalized routing and localization files are just the first part of the task. The second part is setting up the react-intl
library. Below, you can see what changes have been made in the _app.js
file.
import { useRouter } from "next/router";
import { IntlProvider } from "react-intl";
import en from "../lang/en.json";
import fr from "../lang/fr.json";
import "../styles/globals.css";
const messages = {
en,
fr,
};
function MyApp({ Component, pageProps }) {
const { locale } = useRouter();
return (
<IntlProvider locale={locale} messages={messages[locale]}>
<Component {...pageProps} />
</IntlProvider>
);
}
export default MyApp;
Adapt pages for i18n
We did most of the work. The last step is to put all this together. Therefore, we are going to update the index.js
file under the pages directory. Below, you can find two approaches for accessing the localization messages, imperative and declarative. We've already covered these two ways of usage, formatting options, and similar in another post.
The index.js
file:
import Head from "next/head";
import Link from "next/link";
import { useRouter } from "next/router";
import { FormattedMessage, useIntl } from "react-intl";
import styles from "../styles/Home.module.css";
export default function Home(props) {
const { locales } = useRouter();
const intl = useIntl();
const title = intl.formatMessage({ id: "page.home.head.title" });
const description = intl.formatMessage({ id: "page.home.head.meta.description" });
return (
<div className={styles.container}>
<Head>
<title>{title}</title>
<meta name="description" content={description} />
<link rel="icon" href="/favicon.ico" />
{/* Add hreflang links */}
<link rel="alternate" href="http://example.com" hrefLang="x-default" />
<link rel="alternate" href="http://example.com" hrefLang="en" />
<link rel="alternate" href="http://example.com/fr" hrefLang="fr" />
</Head>
<header>
<div className={styles.languages}>
{[...locales].sort().map((locale) => (
<Link key={locale} href="/" locale={locale}>
{locale}
</Link>
))}
</div>
</header>
<main className={styles.main}>
<h1 className={styles.title}>
<FormattedMessage id="page.home.title" values={{ b: (chunks) => <b>{chunks}</b> }} />
</h1>
<p className={styles.description}>
<FormattedMessage id="page.home.description" />
</p>
</main>
</div>
);
}
Congratulations! 🎉
You have successfully set up internationalization in your Next.js project.
More details and examples you can find in the original post.
All code samples used in this article are available on the GitHub repo.
Top comments (0)