How to localize your Next.js application with next-translate
Tags: nextjs, tutorial, javascript
Published: 2021-02-09 15:54:42

To add internationalization to a web app, you need to handle two main tasks: managing translations and maintaining separate URLs.

Questions related to your URLs often include:
* How are locales split up? Will you use a sub-path (/fr vs /en) or domain locale strategy (domain.com vs domain.fr)?
* If your user change locale, how do you redirect them to the correct URL?
* Can you detect the user's preferred locale and redirect them accordingly?

In October 2020, Next.js released a new version of its framework. Among  all the new and shiny features, the one which interested me the most was [Internationalized Routing](https://nextjs.org/blog/next-10#internationalized-routing). This feature added built-in support for routing in multilingual applications along with language detection. This however leaves you with the last component: managing translations.

Enter [next-translate](https://github.com/vinissimus/next-translate). I have chosen this particular translation library for many reasons. On top of being very easy to use and configure, I love next-translate because it works very well with Next.s automatic page optimization. Meaning, my prerendered static pages can stay this way and next-translate will handle the translation. Woo!!

Now that the introductions are done, let's move on to the nitty gritty.

## Step 1: Setting up locale strategy in next.config.js
As mentioned before, there are two ways you can go about locale strategy: sub-path (/fr, /en, /en-US, ...) or domain routing (.com, .fr, .ca).

_Note: If you are not sure which to choose, consult [Google's documentation on using locale-specific URLs](https://developers.google.com/search/docs/advanced/crawling/managing-multi-regional-sites#using-locale-specific-urls) detailing the pros and cons for each._

For this tutorial, you will be going down the sub-path route (pun intended). To do so, you need to update your next.config.js and add your locales.

In this example, the resulting URLs will be / for anglophones and /fr for francophones.

```jsx
module.exports = {
  i18n: {
    locales: ['en', 'fr'],
    defaultLocale: 'en',
  },
}
```
## Step 2: Set up Internationalized Routing in your Next.js pages

Now that your locale strategy is defined, let's move on to your pages. How does Next.js handle internationalization with its static and dynamic pages?

### Static pages
Luckily for us, Next.js generates separate versions for each locale. At build time, Next.js will therefore spit out two index.js pages, one in english and one in french.

### Dynamic pages
However, your dynamic pages need a little bit of love. Say, for example, I have a Next.js application for my blog. I have two pages: index.js listing all the posts and [slug].js for individual post.

Because I want my pages to load quickly, I want them statically generated. This means that, at built time, separate HTML files (post-1.html, post-2.html, ...) are generated for all my blog posts. 

In multilingual applications, not only would I want all these pages generated, but I would also want a version for each locale. The end result will look something like this:
```
.next/ <- contains all the files generated at build time
│
└───en/
|       post-1.html
|       post-2.html
└───fr/
	post-1.html
        post-2.html
```

Therefore, in your application, not only do you need to specify all the different paths (meaning /post-1, /post-2, ...), but also the locales.

What it would look like with my blog example:
```jsx
export async function getStaticPaths({ locales }) {
  const paths = []

  locales.forEach((locale, i) => {
    posts.forEach((post, i) => {
      paths.push({ params: { slug: post.id }, locale })
    });
  });

  return { paths, fallback: false }
}
```
## (Optional) Retrieve the current locale in your Next.js app

You can see what the current locale is at any point thanks to the router.
```jsx
import { useRouter } from 'next/router';

export default function Home() {
  const router = useRouter()
  const { locale } = router

  return (
    <div className="center-container">
      <main className="main">
        // ...

        <section>
          <div>Current locale: {locale}</div>
        </section>
       
       // ...
      </main>
    </div>
  )
}
```

## Step 3: Changing locale and redirecting in your Next.js app

I love that Next.js made it really simple to redirect when changing locale. All you have to do is specify the locale in your Link component. It's pretty straightforward which I love! <3
```jsx
import Link from 'next/link';

export default function Home() {
  return (
    <div className="center-container">
       // ...
          <div>
            <Link href="/" locale="en">
              <a>Change to english</a>
            </Link>
          </div>
          <div>
            <Link href="/" locale="fr">
              <a>Change to french</a>
            </Link>
          </div>
      // ..
    </div>
  )
}
```

## Step 4: Install next-translate
Now that internationalized routing is implemented, we can move on to the last part of this tutorial: translations.

To start with, let's add the library.
```
npm install next-translate

# or

yarn add next-translate
```

## Step 5: Update next.config.js

Then, update your next.config.js to use next-translate.
```jsx
const nextTranslate = require('next-translate')

module.exports = nextTranslate()
```

## Step 6: Set up your locales and namespaces
 
The last part of your configuration is to create an i18n.json and add your locales. One feature I really is being able to split your translations into separate files. This allows you to have page-specific translations.

For the sake of this tutorial however, I will only have one namespace called `common` which will be applied to my entire app ("*").

```json
{
  "locales": ["en", "fr"],
  "defaultLocale": "en",
  "pages": {
    "*": ["common"]
  }
}
```
## Step 7: Creating translations files
For your next step, you then create a locales folder where you will add separate folders for all your locales. In each folder, you need to create a json file for all your namespaces. 

Since I only have one namespace (common), I will go ahead and create one json file called `common.json` for each locale folder.

This is what I have in the end:
```
locales/ 
│
└───en/
│       common.json
└───fr/
        common.json
```

Inside your json files, add all your translations.
```json
{
  "homepage_title": "Blog in Next.js",
  "homepage_description": "This example shows a multilingual blog built in Next.js with next-translate"
}
```
## Step 8: Displaying translated content

Finally, you can display your translated text by getting the t function from useTranslation. By passing the translation key, you can then retrieve the translated value and display it.

```jsx
import useTranslation from 'next-translate/useTranslation'

export default function Home() {
  const { t } = useTranslation('common')

  return (
    <div className="center-container">
      <main className="main">
        <h1 className="title">
          {t('homepage_title')}
        </h1>

        <p className="description">
          {t('homepage_description')}
        </p>
      </main>
    </div>
  )
}
```

Et voilà!

Your application is now officially multilingual. Along with displaying translated content, your app also handles internationalized routing thanks to Next.js built-in support.

If you liked the article, you can [follow me on Twitter](https://twitter.com/MStarckJS).