Respuesta rápida
react-intl es el binding de React para FormatJS, proporcionando soporte para el formato de mensajes ICU para internacionalización. Instálalo con npm install react-intl, envuelve tu app con <IntlProvider locale="es" messages={messages}>, y luego usa <FormattedMessage id="saludo" /> o el hook useIntl() para mostrar traducciones. Elige react-intl cuando necesites cumplimiento estricto de ICU o formateo integrado de fechas/números. Para necesidades más simples, react-i18next puede ser más fácil.
¿Qué es react-intl?
react-intl es parte del ecosistema FormatJS, una implementación oficial del Formato de Mensajes ICU para JavaScript. Proporciona:
- Formato de Mensajes ICU: Sintaxis estándar de la industria para plurales, género y mensajes complejos
- Formateadores integrados: Fechas, números, monedas, tiempo relativo
- Soporte TypeScript: Extracción de mensajes y formateo con seguridad de tipos
- Probado en producción: Usado por Yahoo, Microsoft, Airbnb
react-intl vs react-i18next
| Característica | react-intl | react-i18next |
|---|---|---|
| Formato de Mensaje | ICU (estricto) | JSON (flexible) |
| Tamaño del Bundle | ~25KB | ~15KB |
| Plurales | Sintaxis ICU | Claves con sufijo |
| Formateadores | Integrados | Plugin/manual |
| Curva de Aprendizaje | Más alta | Más baja |
| TypeScript | Excelente | Excelente |
Elige react-intl cuando:
- Necesitas cumplimiento estricto de ICU
- Tu equipo conoce la sintaxis ICU
- Quieres formateo de fechas/números integrado
- Estás integrando con herramientas de traducción que usan ICU
Elige react-i18next cuando:
- Quieres una sintaxis más simple
- Necesitas un tamaño de bundle menor
- Tu equipo prefiere claves basadas en JSON
Instalación
Terminal1npm install react-intl 2# o 3yarn add react-intl 4# o 5pnpm add react-intl
Herramientas CLI Opcionales
Terminal1# Extraer mensajes del código 2npm install -D @formatjs/cli 3 4# Compilar mensajes para producción 5npm install -D @formatjs/cli
Configuración Básica
Paso 1: Crear Archivos de Traducción
src/
├── lang/
│ ├── en.json
│ ├── es.json
│ └── fr.json
└── App.tsx
en.json:
JSON1{ 2 "app.greeting": "Welcome to our application!", 3 "app.nav.home": "Home", 4 "app.nav.about": "About", 5 "app.buttons.submit": "Submit", 6 "app.buttons.cancel": "Cancel" 7}
es.json:
JSON1{ 2 "app.greeting": "¡Bienvenido a nuestra aplicación!", 3 "app.nav.home": "Inicio", 4 "app.nav.about": "Acerca de", 5 "app.buttons.submit": "Enviar", 6 "app.buttons.cancel": "Cancelar" 7}
Paso 2: Configurar IntlProvider
TSX1// src/App.tsx 2import { IntlProvider } from 'react-intl'; 3import { useState } from 'react'; 4 5import enMessages from './lang/en.json'; 6import esMessages from './lang/es.json'; 7 8const messages: Record<string, Record<string, string>> = { 9 en: enMessages, 10 es: esMessages, 11}; 12 13function App() { 14 const [locale, setLocale] = useState('en'); 15 16 return ( 17 <IntlProvider 18 locale={locale} 19 messages={messages[locale]} 20 defaultLocale="en" 21 onError={(err) => { 22 if (err.code !== 'MISSING_TRANSLATION') { 23 console.error(err); 24 } 25 }} 26 > 27 <MainApp onLocaleChange={setLocale} /> 28 </IntlProvider> 29 ); 30}
Paso 3: Usar FormattedMessage
TSX1import { FormattedMessage } from 'react-intl'; 2 3function Header() { 4 return ( 5 <header> 6 <h1> 7 <FormattedMessage id="app.greeting" /> 8 </h1> 9 <nav> 10 <a href="/"><FormattedMessage id="app.nav.home" /></a> 11 <a href="/about"><FormattedMessage id="app.nav.about" /></a> 12 </nav> 13 </header> 14 ); 15}
El Hook useIntl
Para acceso programático al formateo:
TSX1import { useIntl } from 'react-intl'; 2 3function Form() { 4 const intl = useIntl(); 5 6 const handleSubmit = () => { 7 const confirmMessage = intl.formatMessage({ id: 'app.confirm' }); 8 if (confirm(confirmMessage)) { 9 // Enviar formulario 10 } 11 }; 12 13 return ( 14 <form onSubmit={handleSubmit}> 15 <button type="submit"> 16 {intl.formatMessage({ id: 'app.buttons.submit' })} 17 </button> 18 </form> 19 ); 20}
Métodos del Hook
| Método | Propósito | Ejemplo |
|---|---|---|
formatMessage | Traducir mensaje | intl.formatMessage({ id: 'key' }) |
formatDate | Formatear fecha | intl.formatDate(new Date()) |
formatTime | Formatear hora | intl.formatTime(new Date()) |
formatNumber | Formatear número | intl.formatNumber(1234.56) |
formatRelativeTime | Tiempo relativo | intl.formatRelativeTime(-1, 'day') |
Formato de Mensajes ICU
ICU (Componentes Internacionales para Unicode) es el estándar de la industria para mensajes complejos.
Variables (Argumentos)
JSON1{ 2 "greeting": "Hola, {name}!", 3 "cartInfo": "Tienes {count} artículos por valor de {total}" 4}
TSX1<FormattedMessage 2 id="greeting" 3 values={{ name: user.name }} 4/> 5 6<FormattedMessage 7 id="cartInfo" 8 values={{ count: 5, total: '$99.99' }} 9/>
Pluralización
ICU maneja reglas complejas de plurales para todos los idiomas:
JSON{ "items": "{count, plural, =0 {Sin artículos} one {# artículo} other {# artículos}}" }
TSX1<FormattedMessage id="items" values={{ count: 0 }} /> 2// "Sin artículos" 3 4<FormattedMessage id="items" values={{ count: 1 }} /> 5// "1 artículo" 6 7<FormattedMessage id="items" values={{ count: 5 }} /> 8// "5 artículos"
Select (Género, Elección)
JSON{ "pronoun": "A {gender, select, male {él} female {ella} other {ellos}} le gustó tu publicación" }
TSX1<FormattedMessage 2 id="pronoun" 3 values={{ gender: 'female' }} 4/> 5// "A ella le gustó tu publicación"
Plural + Select Anidado
JSON{ "invites": "{gender, select, male {{count, plural, one {Él invitó a # persona} other {Él invitó a # personas}}} female {{count, plural, one {Ella invitó a # persona} other {Ella invitó a # personas}}} other {{count, plural, one {Ellos invitaron a # persona} other {Ellos invitaron a # personas}}}}" }
Texto Rico (Componentes HTML)
JSON1{ 2 "terms": "Al registrarte, aceptas nuestros <link>Términos de Servicio</link>", 3 "welcome": "Bienvenido <bold>{name}</bold> a nuestra plataforma!" 4}
TSX1<FormattedMessage 2 id="terms" 3 values={{ 4 link: (chunks) => <a href="/terms">{chunks}</a> 5 }} 6/> 7 8<FormattedMessage 9 id="welcome" 10 values={{ 11 name: user.name, 12 bold: (chunks) => <strong>{chunks}</strong> 13 }} 14/>
Formateadores Integrados
Formateo de Fecha
TSX1import { FormattedDate } from 'react-intl'; 2 3<FormattedDate 4 value={new Date()} 5 year="numeric" 6 month="long" 7 day="2-digit" 8/> 9// "17 de enero de 2026" (es)
Formateo de Hora
TSX1import { FormattedTime } from 'react-intl'; 2 3<FormattedTime 4 value={new Date()} 5 hour="numeric" 6 minute="numeric" 7 timeZoneName="short" 8/> 9// "14:30 EST" (es)
Formateo de Números
TSX1import { FormattedNumber } from 'react-intl'; 2 3// Número simple 4<FormattedNumber value={1234567.89} /> 5// "1.234.567,89" (es) 6 7// Moneda 8<FormattedNumber 9 value={99.99} 10 style="currency" 11 currency="EUR" 12/> 13// "99,99 €" (es) 14 15// Porcentaje 16<FormattedNumber value={0.25} style="percent" /> 17// "25 %"
Tiempo Relativo
TSX1import { FormattedRelativeTime } from 'react-intl'; 2 3<FormattedRelativeTime value={-1} unit="day" /> 4// "ayer" 5 6<FormattedRelativeTime value={3} unit="hour" /> 7// "en 3 horas"
Integración con TypeScript
Definir Tipos de Mensajes
TypeScript1// src/types/intl.d.ts 2import en from '../lang/en.json'; 3 4type Messages = typeof en; 5 6declare global { 7 namespace FormatjsIntl { 8 interface Message { 9 ids: keyof Messages; 10 } 11 } 12}
Ahora TypeScript autocompleta y valida los IDs de mensajes:
TSX<FormattedMessage id="app.greeting" /> // ✅ Válido <FormattedMessage id="invalid.key" /> // ❌ Error TypeScript
defineMessages para Extracción
TSX1import { defineMessages, useIntl } from 'react-intl'; 2 3const messages = defineMessages({ 4 title: { 5 id: 'app.title', 6 defaultMessage: 'My Application', 7 description: 'Main application title', 8 }, 9 greeting: { 10 id: 'app.greeting', 11 defaultMessage: 'Hello, {name}!', 12 description: 'User greeting message', 13 }, 14});
Extracción de Mensajes
Extraer con FormatJS CLI
Terminal# Extraer mensajes de archivos fuente npx formatjs extract 'src/**/*.ts*' --out-file lang/en.json --id-interpolation-pattern '[sha512:contenthash:base64:6]'
Compilar para Producción
Terminal# Compilar a AST para mejor rendimiento npx formatjs compile lang/en.json --out-file lang/compiled/en.json npx formatjs compile lang/es.json --out-file lang/compiled/es.json
Usando mensajes compilados:
TSX1import compiledMessages from './lang/compiled/en.json'; 2 3<IntlProvider 4 locale="en" 5 messages={compiledMessages} 6/>
Los mensajes compilados están pre-analizados, mejorando el rendimiento en tiempo de ejecución en un 30-50%.
Cambio de Idioma
TSX1import { useState, useCallback } from 'react'; 2import { IntlProvider } from 'react-intl'; 3 4const SUPPORTED_LOCALES = ['en', 'es', 'fr', 'de'] as const; 5type Locale = typeof SUPPORTED_LOCALES[number]; 6 7function App() { 8 const [locale, setLocale] = useState<Locale>('en'); 9 const [messages, setMessages] = useState(enMessages); 10 11 const handleLocaleChange = useCallback(async (newLocale: Locale) => { 12 // Importar traducciones dinámicamente 13 const newMessages = await import(`./lang/${newLocale}.json`); 14 setMessages(newMessages.default); 15 setLocale(newLocale); 16 17 // Persistir preferencia 18 localStorage.setItem('locale', newLocale); 19 document.documentElement.lang = newLocale; 20 }, []); 21 22 return ( 23 <IntlProvider locale={locale} messages={messages}> 24 <LocaleSwitcher 25 current={locale} 26 available={SUPPORTED_LOCALES} 27 onChange={handleLocaleChange} 28 /> 29 <MainContent /> 30 </IntlProvider> 31 ); 32}
Preguntas Frecuentes
¿Qué es react-intl?
react-intl es el binding de React para FormatJS, proporcionando internacionalización con soporte para el Formato de Mensajes ICU. Ofrece componentes como FormattedMessage, FormattedDate, y FormattedNumber, además del hook useIntl. Es usado por grandes compañías y es la elección principal para proyectos que requieren cumplimiento estricto de ICU.
¿Cuál es la diferencia entre react-intl y react-i18next?
react-intl usa el Formato de Mensajes ICU con sintaxis estricta para plurales y selecciones. react-i18next usa claves JSON más simples con plurales basados en sufijos. react-intl tiene formateadores integrados; react-i18next requiere plugins.
¿Cómo uso FormattedMessage con variables?
Usa sintaxis de llaves en mensajes ICU: "greeting": "Hola, {name}!". Luego pasa valores: <FormattedMessage id="greeting" values={{ name: 'Juan' }} />.
¿Cómo funciona la pluralización en react-intl?
Usa sintaxis plural ICU: "{count, plural, one {# artículo} other {# artículos}}". ICU soporta categorías zero, one, two, few, many, other y coincidencias exactas.
Resumen
react-intl proporciona internacionalización robusta con Formato de Mensajes ICU:
| Aspecto | Detalles |
|---|---|
| Instalación | npm install react-intl |
| Provider | <IntlProvider locale messages> |
| Componente | <FormattedMessage id values /> |
| Hook | useIntl().formatMessage() |
| Formato de Mensaje | ICU (estándar) |
| Formateadores | Integrados fecha, número, moneda |
Lo mejor para: Equipos que necesitan cumplimiento de ICU, formateadores integrados o integración con herramientas CAT.
¿Listo para gestionar traducciones de react-intl? Empieza gratis con IntlPull — soporte completo de ICU con traducción por IA.
