Atrás

Estás haciendo mal el i18n en Next.js

General Translation avatarGeneral Translation
Ernest McCarter avatarErnest McCarter
guideinternationalizationnextjsi18ngt-nextapp-routertutorial

La internacionalización en JavaScript ha adoptado una convención defectuosa: extraer cada cadena que ve el 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 UI vive en un sitio, tu contenido vive en otro.

Esto funciona. Miles de aplicaciones se lanzan así. Pero no es una gran experiencia para desarrolladores.

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 tienen que inventarse, organizarse en espacios de nombres y mantenerse sincronizadas. Las traducciones obsoletas se acumulan porque nadie sabe qué claves siguen en uso. El problema está tan extendido que existen categorías completas de herramientas solo para gestionarlo: extensiones del IDE que sugieren claves automáticamente, generadores de tipos que las validan, 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 debería estar separado del lugar donde se usa. Un componente que renderiza un encabezado, un párrafo y un botón debería ser la única fuente de verdad de lo que dicen esos elementos, no un proxy que apunte a cadenas de texto almacenadas en otra parte. Cuando tu código y tus traducciones son dos sistemas paralelos, se desincronizan. Inevitablemente.

¿Qué pasaría 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 i18n.

import { T } from 'gt-next';

function Hero() {
  return (
    <T>
      <h1>Lleva tu producto a todo el mundo</h1>
      <p>Alcanza cualquier mercado sin reescribir tu aplicación.</p>
    </T>
  );
}

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

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

Configuración

La sintaxis anterior proviene de gt-next, una biblioteca i18n de código abierto para Next.js App Router. Ponerlo en marcha requiere solo un comando:

npx gtx-cli@latest init

El asistente de configuración instala las dependencias, envuelve tu configuración de Next.js con withGTConfig, agrega GTProvider a tu layout raíz, crea un gt.config.json con tus locales, configura claves de API de desarrollo para la recarga en caliente de traducciones y configura el almacenamiento de traducciones en la red de distribución de contenido (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 bajo demanda en tiempo de desarrollo, para que puedas ver tu aplicación en cualquier idioma al instante.

Despliegue

En producción, las traducciones se generan previamente.

  1. Obtén una clave de API de producción desde dash.generaltranslation.com. Las claves de producción comienzan con gtx-api- (distintas de las claves gtx-dev- usadas localmente).

  2. Agrega el paso de traducción a tu proceso de build:

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

El comando translate analiza tu código en busca de todas las apariciones de <T>, genera traducciones y las publica en una red de distribución de contenido (CDN, Content Delivery Network). Cuando se compila tu aplicación, todas las configuraciones regionales están listas.

Próximos pasos