Volver

Estás haciendo mal el i18n en Next.js

Team avatarTeam
Ernest McCarter avatarErnest McCarter
guideinternationalizationnextjsi18ngt-nextapp-routertutorial

La internacionalización en JavaScript se ha asentado en una convención defectuosa: extraer cada cadena de cara al usuario a un archivo JSON, asignarle una clave y hacer referencia a esa clave en tus componentes. t('home.hero.title') en lugar del texto en sí. Tu interfaz vive en un sitio; tu contenido, en otro.

Esto funciona. Miles de aplicaciones se lanzan así. Pero no ofrece una buena experiencia de desarrollo.

Leer t('checkout.summary.total') en una revisión de código no te dice nada: tienes que abrir un archivo JSON para ver qué cambió. Las claves hay que inventarlas, organizarlas en espacios de nombres y mantenerlas sincronizadas. Las traducciones obsoletas se acumulan porque nadie sabe qué claves siguen en uso. El problema está tan extendido que existen categorías enteras de herramientas solo para gestionarlo: extensiones de IDE que sugieren claves automáticamente, generadores de tipos que las validan y linters que marcan las que no se usan. Estas herramientas están resolviendo un problema creado por un paradigma mal diseñado.

El componente <T>

El contenido no debe separarse de donde se usa. Un componente que renderiza un encabezado, un párrafo y un botón debe ser la única fuente de verdad sobre lo que muestran esos elementos, no un intermediario que apunta a cadenas almacenadas en otro lugar. Cuando tu código y tus traducciones son dos sistemas paralelos, acaban desincronizándose. Inevitablemente.

¿Y si la biblioteca funcionara al revés: adaptándose a tu código en lugar de pedirte que lo reestructures? Así es como debería ser la i18n.

import { T } from 'gt-next';

function Hero() {
  return (
    <T>
      <h1>Ship your product worldwide</h1>
      <p>Reach every market without rewriting your app.</p>
    </T>
  );
}

Envuelve tu JSX en <T>. El texto en inglés se queda justo donde lo escribiste. Cuando un usuario accede en español o japonés, el contenido dentro de <T> se traduce: estructura, formato y todo.

Sin claves. Sin archivos JSON. Sin referencias cruzadas. Tu código es la fuente de verdad.

Configuración

La sintaxis anterior proviene de gt-next, una biblioteca de i18n de código abierto para el App Router de Next.js. Para empezar, solo necesitas ejecutar un comando:

npx gt@latest init

El asistente de configuración instala dependencias, envuelve tu configuración de Next.js con withGTConfig, agrega GTProvider a tu layout raíz, crea un gt.config.json con tus configuraciones regionales, configura las claves de API de desarrollo para la recarga en caliente de las traducciones y configura el almacenamiento de traducciones en la CDN, todo de forma interactiva.

Una vez hecho esto, envuelve el contenido en <T>, ejecuta tu servidor de desarrollo y usa el componente <LocaleSelector> para cambiar entre idiomas:

import { LocaleSelector } from 'gt-next';

function Header() {
  return (
    <header>
      <nav>{/* ... */}</nav>
      <LocaleSelector />
    </header>
  );
}

Las traducciones se realizan on-demand durante el desarrollo para que puedas ver tu aplicación en cualquier idioma de inmediato.

Despliegue

En producción, las traducciones se generan con antelación.

  1. Obtén una clave de API de producción en dash.generaltranslation.com. Las claves de producción empiezan por gtx-api- (a diferencia de las claves gtx-dev- que se usan localmente).

  2. Añade el paso translate a tu proceso de compilación:

{
  "scripts": {
    "build": "npx gt translate --publish && next build"
  }
}

El comando translate analiza tu base de código para detectar todos los usos de <T>, genera las traducciones y las publica en una CDN. Cuando se compila tu aplicación, todas las configuraciones regionales están listas.

Próximos pasos