Skip to main content

Guía completa de internacionalización en React

Del inicio a una aplicación multilingüe: configure i18n en su aplicación React y automatice después las traducciones con IA.

1

Instalar paquetes

Necesita tres paquetes: react-i18next —los enlaces para React—, i18next —la biblioteca principal— y, opcionalmente, i18next-browser-languagedetector para detectar automáticamente la configuración regional.

react-i18next proporciona hooks y componentes de React. i18next es el motor principal que gestiona la carga de traducciones, la interpolación y la pluralización. El plugin detector de idioma lee automáticamente la preferencia lingüística del navegador.
Terminal
npm install react-i18next i18next i18next-browser-languagedetector i18next-http-backend
2

Configurar la instancia de i18n

Cree un archivo de configuración de i18n que inicialice i18next con el idioma predeterminado, los recursos de traducción y la cadena de plugins. Debe importar este archivo en el punto de entrada de la aplicación antes de renderizar cualquier componente.

src/i18n.ts
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import Backend from 'i18next-http-backend';

i18n
  .use(Backend)
  .use(LanguageDetector)
  .use(initReactI18next)  // Must come before .init()
  .init({
    fallbackLng: 'en',
    debug: process.env.NODE_ENV === 'development',
    interpolation: {
      escapeValue: false,  // React already escapes
    },
    backend: {
      loadPath: '/locales/{{lng}}/{{ns}}.json',
    },
  });

export default i18n;
«You will need to pass in an i18next instance by using initReactI18next»: este error indica que ha olvidado llamar a i18n.use(initReactI18next) antes de i18n.init(). La llamada .use() debe ir antes que .init().
3

Envolver la aplicación con I18nextProvider

Importe el archivo de configuración de i18n en la raíz de la aplicación y envuelva el árbol de componentes con I18nextProvider. Sin él, useTranslation() devuelve las claves sin traducir en lugar del texto traducido.

src/main.tsx
import React, { Suspense } from 'react';
import ReactDOM from 'react-dom/client';
import { I18nextProvider } from 'react-i18next';
import i18n from './i18n';  // Import your config
import App from './App';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <Suspense fallback={<div>Loading...</div>}>
      <I18nextProvider i18n={i18n}>
        <App />
      </I18nextProvider>
    </Suspense>
  </React.StrictMode>
);
Si las traducciones muestran claves sin procesar como «welcome» en vez de «Welcome to our app», la causa más habitual es que falte I18nextProvider o que no se haya importado el archivo de configuración de i18n.
4

Crear archivos de traducción

Cree un archivo JSON por idioma. Utilice claves anidadas para organizar las cadenas por funcionalidad o página. Mantenga el idioma de origen —normalmente el inglés— como única fuente de referencia.

public/locales/en/translation.json
// public/locales/en/translation.json
{
  "nav": {
    "home": "Home",
    "about": "About",
    "settings": "Settings"
  },
  "greeting": "Hello, {{name}}!",
  "cart": {
    "itemCount_one": "{{count}} item",
    "itemCount_other": "{{count}} items"
  }
}

// public/locales/de/translation.json
{
  "nav": {
    "home": "Startseite",
    "about": "Über uns",
    "settings": "Einstellungen"
  },
  "greeting": "Hallo, {{name}}!",
  "cart": {
    "itemCount_one": "{{count}} Artikel",
    "itemCount_other": "{{count}} Artikel"
  }
}
Nombre las claves por lo que describen, no por el lugar donde aparecen: «cart.itemCount» es mejor que «homepageCartLabel». Las claves deben sobrevivir a los rediseños de la interfaz.
5

Utilizar traducciones en los componentes

Llame a useTranslation() en cualquier componente para obtener la función t(). Utilícela con cadenas sencillas, variables interpoladas y traducciones que incluyan JSX mediante el componente Trans.

Greeting.tsx
import { useTranslation } from 'react-i18next';

function Greeting({ userName }: { userName: string }) {
  const { t } = useTranslation();

  return (
    <div>
      <h1>{t('greeting', { name: userName })}</h1>
      <nav>
        <a href="/">{t('nav.home')}</a>
        <a href="/about">{t('nav.about')}</a>
      </nav>
    </div>
  );
}
Trans component for JSX
import { Trans, useTranslation } from 'react-i18next';

// For JSX inside translations:
// "terms": "By signing up, you agree to our <link>Terms</link>."

function SignUp() {
  const { t } = useTranslation();
  return (
    <Trans i18nKey="terms" components={{
      link: <a href="/terms" className="underline" />
    }} />
  );
}
Las claves dinámicas como t(`error.$'{code}'`) funcionan durante la ejecución, pero herramientas como i18next-scanner no pueden extraerlas estáticamente. Si utiliza herramientas de extracción, enumere explícitamente las claves dinámicas o añada una indicación en un comentario.
6

Gestionar plurales y variables

i18next gestiona los plurales con reglas CLDR, no solo singular y plural. El árabe tiene 6 formas (zero, one, two, few, many y other) y el japonés 1 (other). Defina en los archivos de traducción todas las formas necesarias e i18next seleccionará automáticamente la correcta.

Plural forms by language
// English: 2 forms (one, other)
{
  "itemCount_one": "{{count}} item",
  "itemCount_other": "{{count}} items"
}

// Arabic: 6 forms (zero, one, two, few, many, other)
{
  "itemCount_zero": "لا عناصر",
  "itemCount_one": "عنصر واحد",
  "itemCount_two": "عنصران",
  "itemCount_few": "{{count}} عناصر",
  "itemCount_many": "{{count}} عنصرًا",
  "itemCount_other": "{{count}} عنصر"
}

// Japanese: 1 form (other)
{
  "itemCount_other": "{{count}}個のアイテム"
}
Nunca codifique count === 1 para detectar el singular. Idiomas como el francés consideran singular el 0. El ruso, el árabe y el polaco tienen formas que no existen en inglés. Deje que i18next gestione las reglas de plural.
7

Añadir el cambio y la detección de idioma

Cree un selector de idioma que llame a i18n.changeLanguage(). Combínelo con el detector del navegador para identificar automáticamente el idioma preferido del usuario en la primera visita y conservar después su elección explícita.

LanguageSwitcher.tsx
import { useTranslation } from 'react-i18next';

const LANGUAGES = [
  { code: 'en', label: 'English' },
  { code: 'de', label: 'Deutsch' },
  { code: 'ja', label: '日本語' },
  { code: 'es', label: 'Español' },
];

function LanguageSwitcher() {
  const { i18n } = useTranslation();

  return (
    <select
      value={i18n.language}
      onChange={(e) => i18n.changeLanguage(e.target.value)}
    >
      {LANGUAGES.map(({ code, label }) => (
        <option key={code} value={code}>{label}</option>
      ))}
    </select>
  );
}
Si utiliza SSR (Next.js o Remix), el servidor puede detectar un idioma distinto del cliente, ya que no dispone de las preferencias del navegador. Esto provoca una discrepancia de hidratación. Solución: pase la configuración regional detectada del servidor al cliente como prop o cookie para que ambos rendericen el mismo idioma.
8

Automatizar traducciones

Cuando termine de configurar i18n, traduzca sus archivos de configuración regional con IA. Pida a su asistente de IA desde el IDE que traduzca el archivo de origen o utilice la CLI de i18n Agent en su proceso de CI/CD.

Terminal
# In your IDE, ask your AI assistant:
> Translate public/locales/en/translation.json to German, Japanese, and Spanish

✓ de/translation.json created (1.2s)
✓ ja/translation.json created (1.5s)
✓ es/translation.json created (1.1s)

# Or use the CLI in CI/CD:
npx i18n-agent translate public/locales/en/translation.json --lang de,ja,es
Traduzca de forma incremental: cuando añada claves nuevas al archivo de origen, traduzca solo las diferencias en vez de volver a generar todos los archivos. Así conserva las traducciones que ya haya revisado una persona.

Automatizar la calidad de la traducción

Detecte las claves ausentes y los marcadores de posición rotos antes de publicar con i18n-validate. Pruebe la interfaz con traducciones simuladas mediante i18n-pseudo antes de recibir las reales.

Errores habituales

Las traducciones muestran las claves sin procesar

Causas: falta I18nextProvider, no se importó la configuración de i18n en la raíz de la aplicación, no se cargó el espacio de nombres o las traducciones siguen cargándose de forma asíncrona. Busque pistas en la consola del navegador con debug: true.

Error de Suspense sin alternativa

«A component suspended while responding to synchronous input»: añada un límite '&lt;Suspense&gt;' alrededor de la aplicación o configure useSuspense: false en la configuración inicial de i18next.

Discrepancia de hidratación con SSR

El servidor renderiza en una configuración regional y el cliente hidrata en otra. Asegúrese de que ambos utilicen el mismo origen: páselo como prop desde el servidor y no dependa solo de la detección del navegador.

Sin autocompletado para las claves de traducción

Amplíe el módulo i18next con su tipo de recurso: declare module 'i18next' '{ interface CustomTypeOptions { resources: typeof resources } }'. Así obtendrá llamadas a t() con seguridad de tipos y autocompletado.

Estructura de archivos recomendada

Project Structure
my-react-app/
├── public/
│   └── locales/
│       ├── en/
│       │   ├── translation.json    # Default namespace
│       │   ├── common.json         # Shared strings
│       │   └── dashboard.json      # Feature namespace
│       ├── de/
│       │   ├── translation.json
│       │   ├── common.json
│       │   └── dashboard.json
│       └── ja/
│           └── ...
├── src/
│   ├── i18n.ts                     # i18n configuration
│   ├── main.tsx                    # App entry with Provider
│   ├── App.tsx
│   └── components/
│       └── LanguageSwitcher.tsx
└── package.json

Pruebe i18n Agent ahora

Arrastre y suelte aquí su archivo de traducción

JSON, YAML, PO, XML, CSV, Markdown, Properties

o haga clic para seleccionar

Idiomas de destino

No es necesario registrarsePresupuesto al instante

Preguntas frecuentes