How I translated my Next.js Blog
Tags: nextjs, tutorial, react
Published: 2021-01-21 00:19:40

This post is also available in Spanish here: https://www.infoxicator.com/es/traduciendo-mi-blog-con-next-js

![translate-gif](https://user-images.githubusercontent.com/17012976/105107793-c02f4780-5ab0-11eb-86d9-586b8781df42.gif)

English is my second language and before I was proficient, I always found it really difficult to find tech resources in my own language. That's why I decided to translate my blog and make all my content available in Spanish.


## Internationalization with `Next.js`

`Next.js` has made Internationalization [(i18n)](https://en.wikipedia.org/wiki/Internationalization_and_localization#Naming) a breeze with one of the most recent advanced features available in version 10: [Internationalized Routing](https://nextjs.org/docs/advanced-features/i18n-routing).

From the [two options](https://nextjs.org/docs/advanced-features/i18n-routing#locale-strategies) provided by Next.js, I have decided to use Sub-path Routing instead of Domain Routing since I don't want to create a subdomain for the Spanish version of my blog.

## Basic Configuration


`next.config.js`

```js
module.exports = {
    i18n: {
      locales: ['en', 'es'],
      defaultLocale: 'en',
    },
  }
```

This is the only setup required to enable "[Automatic Language Detection](https://nextjs.org/docs/advanced-features/i18n-routing#automatic-locale-detection)".

The [automatic language detection system](https://nextjs.org/docs/advanced-features/i18n-routing#automatic-locale-detection) provided by `Next.js` will redirect users to the `/es` path prefix if their browsers are set to Spanish (or any of its regional variations) as their default language. `Next.js` will look at the [`Accept-Language`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language) HTTP Header and try to set the correct language, however, if the language doesn't match, it will use the default language. For example, if users have German (DE-de) as their browser language, it will set the current language to English (en).

## Managing Locale Files

`Next.js` doesn't prescribe a way of managing your locale data or what `i18n` library you should use (or if you need a library at all). 

For small projects (like in my case) a simple key-value pair JSON file does the job, however, for a large application, a more robust solution is recommended to avoid things like a bloated bundle size.

I have created a folder called `locale` and created a single JSON file per language. i.e. `locale/en.json` and `locale/es.json`

```json
{
  "greeting": "Hola amigos!"
}
```

We could use the `key` to render the value of the translated language without any library, however, I want to use [`react-intl`](https://formatjs.io/docs/getting-started/installation/) since it is one of the most popular `i18n` libraries out there.

Add the following configuration to your `_app.js`

```js

import '../styles/index.css'
import { IntlProvider } from 'react-intl';
import { useRouter } from "next/router"

const languages = {
  en: require('../locale/en.json'),
  es: require('../locale/es.json')
};

function MyApp({ Component, pageProps }) {
  const router = useRouter()
  const { locale, defaultLocale } = router;
  const messages = languages[locale];
  return <IntlProvider messages={messages} locale={locale} defaultLocale={defaultLocale}>
      <Component {...pageProps} />
      </IntlProvider>
}

export default MyApp
```

In the snippet above, we are wrapping our entire application with the `IntlProvider` and passing the `messages` and the `locale` that we obtained from the `useRouter()` hook. Now we can use `react-intl` components like `FormatedMessage` throughout our application.

```js
import { FormattedMessage } from 'react-intl'

export default function Greeting() {
return (
  <h1><FormattedMessage id="greeting" /></h1>
)}
```

## Changing The Language

When switching languages, I want to persist the user's selection so if they visit my blog again it will set the language to their preferred language rather than the locale detected automatically by `Next.js`.

To achieve this, we can use the [`Next.js Locale Cookie`](https://nextjs.org/docs/advanced-features/i18n-routing#leveraging-the-next_locale-cookie):

```js
import { useRouter } from "next/router"
import { useCookies } from 'react-cookie';

export default function LanguageSwitcher() {
  const [ cookie, setCookie ] = useCookies(['NEXT_LOCALE']);
  const router = useRouter();
  const { locale } = router;

  const switchLanguage = (e) => {
    const locale = e.target.value;
    router.push('/','/', { locale });
    if(cookie.NEXT_LOCALE !== locale){
      setCookie("NEXT_LOCALE", locale, { path: "/" });
    }
  }

  return (
    <select
      onChange={switchLanguage}
      defaultValue={locale}
    >
      <option value="en">EN</option>
      <option value="es">ES</option>
    </select>
  );
}
```

## `getStaticProps` For Each Locale

To render the list of blog posts in the selected language, the `locale` parameter will be available in `getStaticProps` so I can pass it to my data fetching function.

**For Example:**

```js
export async function getStaticProps({ locale }) {
  const allPosts = await getAllPostsForHome(locale)
  return {
    props: { allPosts },
  }
}
```

## Search Engine Optimization

`Next.js` will add a global `lang` HTML attribute to your site with the current locale, however, if you have a custom  `_document.js` file make sure that you remove any hardcoded `lang` values you might have set there.

To tell search engines about alternative versions of your posts in different languages, we must set a `hreflang` meta tag for each language (including the original language) to the `head` section of our blog posts page.

**For Example:**

```js
import Head from 'next/head'

export default function Post({ post }) {
return (
...
  <article>
    <Head>
        <link rel="alternate" hreflang={locale} href={`${SITE_URL}${locale}/${post?.slug}`} />
        <link rel="alternate" hreflang={altLocale} href={`${SITE_URL}${altLocale}/${altPost?.slug}`} />
    </Head>
  </article>
...
)}
```
## Conclusion

Internationalization `(i(18 letters)n)` used to be a complex task, however, with the aid of Meta-Frameworks like `Next.js` and tools like `react-intl`, providing localised text and translated data to our users has never been easier!.

I hope you enjoy my (translated) content and to my Spanish speaking friends out there, nos vemos pronto!.