Next.js multi idioma
Tags: nextj, react, i18n, polyglot
Published: 2020-11-24 21:12:17

> Con la versión 10 de Next.js han introducido el soporte a internacionalización. Se puede configurar un listado de idiomas, el idioma por defecto y, en caso de requerirlo, un dominio específico para cada uno. Next.js hará la detección del idioma del usuario y gestionará las rutas automáticamente.

La gestión de idioma por Next.js debe ser complementada con la gestión de las traducciones, utilizando alguna biblioteca Open Source existente o llevando a cabo el desarrollo nosotros mismos. En la documentación de Next.js recomiendan soluciones como `react-intl`, `react-i18next`, `lingui` o `rosetta`.

En este artículo, os voy a explicar cómo he llevado a cabo la implementación de [Polyglot.js](https://github.com/airbnb/polyglot.js), una herramienta desarrollada y mantenida por Airbnb.

Lo primero que deberemos hacer es instalar la dependencia:

```
$ npm install node-polyglot --S
```

## Internacionalización de rutas con Next.js 10 o superior

La configuración de internacionalización en Next.js debe hacerse en el archivo `next.config.js`, en este ejemplo vamos a utilizar la opción de _Sub-path Routing_ con locales sin región, es decir, las url's de las páginas de cada idioma tendrán `/es` o `/en` al inicio del _path_.

A continuación la configuración de `next.config.js`:

```javascript 
// next.config.js
module.exports = {
  i18n: {
    /* Listado de locales que vamos a soportar */
    locales: ['en', 'es'],
    /* Locale seleccionado por defecto */
    defaultLocale: 'es'
  }
}
```

## Traducción de textos con Polyglot.js en Next.js

Para integrar Polyglot.js con Next.js he creado un contexto, el cual recibirá el `locale` actual en el que está corriendo la aplicación. Este contexto contendrá la instancia de Polyglot con la configuración seleccionada.

```javascript
// src/I18n.js
import {createContext, useContext, useMemo} from 'react'
import Polyglot from 'node-polyglot'

// Creamos las traducciones para cada idioma.
// Es recomendable mover esto a otros archivos.
const literals = {
  en: {hello: 'hello'},
  es: {hello: 'hola'}
}

// Definimos los idiomas a los que damos soporte
const locales = {
  en: 'en',
  es: 'es'
}

// Creamos el contexto
const I18nContext = createContext()

/**
 * Componente que encapsula la aplicación dentro del Provider.
 * Este componente será el responsable de actualizar el idioma activado en la aplicación
 */
function I18n({children, locale}) {
  // Cada vez que el locale cambie, obtendremos una instancia de i18n actualizada.
  const i18n = useMemo(
    () =>
      new Polyglot({
        locale,
        phrases: literals[locale]
      }),
    [locale]
  )

  return <I18nContext.Provider value={i18n}>{children}</I18nContext.Provider>
}

// Creamos un Hook para utilizar el contexto en los componentes que necesitemos
const useTranslate = () => useContext(I18nContext)

export {locales, useTranslate}
export default I18n
```

Lo siguiente que debemos hacer consiste en utilizar este contexto en la aplicación. Yo he optado por utilizar el componente I18n directamente en el componente `_app.js`, enviándole la _prop_ `locale` que se puede obtener directamente del _Hook_ `useRouter`.

```javascript
// src/pages/_app.js
import {useRouter} from 'next/router'
import I18n from '../i18n'

function MyApp({Component, pageProps}) {
  const {locale} = useRouter()

  return (
    <I18n locale={locale}>
      <Component {...pageProps} />
    </I18n>
  )
}

export default MyApp

```

## Localización de textos en componentes y páginas

Para utilizar las traducciones que hemos ido añadiendo en el objeto `literals` utilizaremos el valor del contexto, que corresponde con la instancia de Polyglot. Para ello, utilizaremos el _Hook_ `useTranslate`.

```javascript
// src/pages/index.js
import {useTranslate} from '../i18n'

const Home = () => {
  const i18n = useTranslate()
  return <p>{i18n.t('hello')}</p>
}

export default Home
```