Skip to content

Next.js: Adding Localization with Next-Intl

Next.js: Adding Localization with next-intl

Adding locales to a project in NextJs is as easy as creating a few files, and installing the handy npm package next-intl. Using next-intl works right away with minimal setup and configuration, and makes adding different locales to a new or existing project a breeze.

We'll step trough the basic setup of the project and necessary dependendies, the project structure, and a few cool things we can do with next-intl that make langauge integrations seemless.


To start thigns off, we'll create a nextjs app using the following:

$ npx create-next-app nextjs-locaels --use-npm --example ""

Once you've created the app:

$ cd nextjs-locales
$ npm run dev

You should see a generic starter page from cloning the NextJs learn-starter project.

Next we need to add the translations dependency:

$ npm i -S next-intl


At this point, we would have already considered which langauges we want to support, and which language is our default. For this example, we're going to use English as the default, and Japanese as the next supported langauge.

Configure NextJs

Create the file next.config.js and add the following line:

module.exports = {
  i18n: {
    locales: ['en', 'ja'],
    defaultLocale: 'en',

We add this to next.config.js because we want the framework to be aware of context changes within the app when we provide static props to our app.

Register Locales

In our project, we want to consider the best place for loading different translation files. Typically these extra files don't need to compiled with our source code so we can create a locales folder outside the main source files:

| ...
| locales/
| pages/
| ...

In the locales folder, we can create en.json and ja.json respectively, making sure to match the name of the file to what we used in the config.

Using next-intl

The next few steps are a basic usage of next-intl.

Add Languages

First we need to add to our language files, so we know where to pull information from. Using the existing text generated from our initial script, we can add to out en.json file:

// en.json
    "Home": {
        "hello": "Welcome to Next.js!"

And to the ja.json file:

// ja.json
    "Home": {
        "hello": "Next.jsγΈγ‚ˆγ†γ“γοΌ"

NOTE: be sure to research what the correct translation are for he languages you use and test accordingly!

Provide Locales

Our pages need context to pull locale information from. We provide that to a page via NextJs built-in function getStaticProps. This gives default prop values to a react component. Place it at the bottom of index.js.

export function getStaticProps({ locale }) {
  return {
    props: {
      messages: require(`../locales/${locale}.json`),

NOTE: the previous step is crucial to making this work correctly since the name provided in the config need to match the file name.

Then in the pages/ folder again, create a file _app.js which we'll use to register providers for our app. Then add the following:

import {NextIntlProvider} from 'next-intl';

export default function App({Component, pageProps}) {
  return (
    <NextIntlProvider messages={pageProps.messages}>
      <Component {...pageProps} />

What this did was take the default pageProps object and give it another default property messages.

Component Use

Now that our setup is complete, we can use our translation package like:

import { useTranslations } from 'next-intl';
export default function Home() {
  const t = useTranslations('Home');

Think of the sctructure of the JSON as the copy text you'd include directly in HTML. We need to access the section of copy for the page we're on, and we identify the piece with the Home key. Then, we access the inner copy like:


Start up the app, and if it was setup correctly, you should see the "Welcome to Next.js!"

Advanced Use

Now that we've covered the basic use. Let's take a look at a cool pattern we can use.

next-intl gives us the option of specifying how we want to style and break apart pieces of copy. The way they accomplish this is with custom tags, declared within the copy itself.

To accomplish this, first we adjust the language files by wrapping the word "NextJs" in link tags.

// en.json
    "Home": {
        "hello": "Welcome to <link>Next.js!</link>"
// ja.json
    "Home": {
        "hello": "<link>Next.js</link>γΈγ‚ˆγ†γ“γοΌ"

Then in the component, we express how we want the link tag to function when rendering. We access the specific tag by the custom name given in the JSON, and give it a function where children, like in React, takes the contents between the custom tags, and interpolates that, whoever we choose. In our case, we want to maintain the original link that was generated from the project starter.

<h1>{t('hello', {
  link: (children) => <a href="">{children}</a>,

Locale Strategies

NextJs' routing feature is powerful in the way it works with the basic setup we have thus far. Because we defined our locales in the config, we can run the app and navigate to the locale code to see it render in view.

For example: navigating to localhost:3000/ja will dynamically render the right context via the provider we set up in _app.js.

Read more about NextJs Locale Strategies to learn more about routing and locales for your app's needs.


Adding i18n to a project is simple. As we've seen, with just a few steps, we were able to add some basic copy translations to our app with minimal effort.

Try the complete code example.