Haz tu pregunta y obtén un resumen del documento referenciando esta página y el proveedor AI de tu elección
Historial de versiones
- "Versión inicial"v9.5.1026/9/2026
El contenido de esta página ha sido traducido con una IA.
Ver la última versión del contenido original en inglésSi tienes una idea para mejorar esta documentación, no dudes en contribuir enviando una pull request en GitHub.
Enlace de GitHub a la documentaciónCopiar el Markdown del documento a la portapapeles
Cómo internacionalizar tu aplicación TanStack Start usando Lingui en 2026
Tabla de contenidos
¿Qué es Lingui?
Lingui es una biblioteca de i18n diseñada alrededor de macros y extracción de mensajes. Escribes el texto fuente directamente en tus componentes ( t`Hello` , <Trans>Hello</Trans>), lingui extract recopila cada mensaje en catálogos (archivos PO por defecto), los traductores los completan y el plugin de Vite los compila en JavaScript compacto. Los mensajes utilizan ICU MessageFormat, por lo que las formas plurales y selects están soportados.
TanStack Start no incluye una capa de i18n integrada, por lo que esta guía conecta Lingui desde cero:
- Macros compiladas por Babel a través de
@rolldown/plugin-babel(requerido con@vitejs/plugin-reactv6 y Vite 8). - Enrutamiento por locale con un segmento opcional
{-$locale}(/about,/fr/about). - Un catálogo por locale, cargado bajo demanda, y una instancia de
I18npor renderizado para que las solicitudes SSR concurrentes nunca compartan un locale. - SEO multilingüe completo:
<title>y descripción traducidos, URL canónica,hreflangconx-default, locales Open Graph, JSON-LD, sitemap,robots.txt, pre-renderizado y páginas 404 localizadas.
¿Buscas otro stack? Consulta la guía de TanStack Start + use-intl, la guía de TanStack Start + Paraglide o la guía de TanStack Start + Intlayer.
¿Usas Next.js? Consulta la guía de Next.js + Lingui. ¿Comparando bibliotecas? Lee Lingui vs Intlayer.
Qué dice el benchmark sobre Lingui en TanStack Start
El benchmark de i18n ejecuta la misma aplicación TanStack Start de 10 páginas y 10 locales con cada biblioteca principal y mide lo que el navegador realmente descarga.
Carga JSON dinámica
Carga traducciones en tiempo de ejecución
JSON con alcance (namespacing)
Espacios de nombres de traduction por página
Benchmark de Rendimiento I18n
¿Qué es esta métrica?
El tamaño total comprimido en gzip del paquete de la biblioteca de internacionalización. Solo incluye el proveedor y la lógica de recuperación de contenido después del tree-shaking y la minificación.
¿Por qué es importante?
Un tamaño de biblioteca más pequeño reduce la carga útil inicial de JavaScript, lo que acelera el tiempo de descarga y ejecución en el cliente.
Ver como
Cifras clave para @lingui/core@6.6.0, medidas el 2026-09-26 (gzip):
Abrir la tabla en una ventana flotante para ver todo el contenido claramente
| Configuración | Tamaño de biblioteca | JS por página | Fuga de otro locale | Fuga de otra página |
|---|---|---|---|---|
| Sin i18n (app base) | - | 111.0 KB | 0% | 0% |
| Lingui (configuración de la guía) | 56.7 KB | 115.2 KB | 9.3% | 0% |
@intlayer/lingui (compat) | 9.8 KB | 136.7 KB | 9.9% | 0% |
react-intlayer (Intlayer nativo) | 4.5 KB | 126.8 KB | 0% | 0% |
Conclusiones principales:
- Carga un catálogo por locale, bajo demanda. Mantiene las páginas cerca del tamaño de la aplicación base.
- El runtime sigue siendo pesado (~57 KB gzip). El adaptador de compatibilidad
@intlayer/lingui(paso 16) conserva tus macros y lo reduce a ~10 KB.
Consulta los datos completos: Informe de benchmark de TanStack Start y el repositorio del benchmark.
Comparación de características en TanStack Start
Cómo se compara Lingui con otras bibliotecas comúnmente usadas en TanStack Start:
Abrir la tabla en una ventana flotante para ver todo el contenido claramente
| Característica | react-intlayer (Intlayer) | use-intl | Paraglide JS | Lingui |
|---|---|---|---|---|
| Traducciones junto a componentes | ✅ Co-ubicadas | ❌ JSON centralizado | ❌ Un archivo JSON por locale | ⚠️ Texto fuente en componentes |
| Integración con TypeScript | ✅ Tipos autogenerados | ✅ Vía AppConfig | ✅ Funciones de mensaje tipadas | ⚠️ Solo macros |
| Detección de traducción faltante | ✅ Errores de tipo y avisos de build | ⚠️ Fallback en runtime | ⚠️ Recurre al locale base | ⚠️ Recurre al texto fuente |
| Contenido enriquecido (JSX, MD) | ✅ Soporte directo | ⚠️ Tags vía t.rich | ⚠️ Strings | ✅ JSX dentro de <Trans> |
| Enrutamiento localizado | ✅ Integrado | ❌ {-$locale} manual | ✅ urlPatterns + rewrite router | ❌ {-$locale} manual |
| Cambio de locale sin recarga | ✅ Sí | ✅ Sí | ❌ Recarga completa de página | ✅ Sí |
| Pluralización | ✅ Basada en enumeración | ✅ ICU | ✅ Variantes | ✅ ICU |
| ICU MessageFormat | ✅ Vía format: "icu" | ✅ Nativo | ⚠️ Vía un plugin inlang | ✅ Nativo |
| Formatos de contenido | ✅ .ts, .json, .md, .yaml... | ⚠️ .json | ⚠️ JSON de inlang | ✅ PO, JSON, CSV |
| Traducción con IA | ✅ Tu propio proveedor y clave | ❌ No | ❌ No | ❌ No |
| Editor visual / CMS | ✅ Editor local + CMS opcional | ❌ Plataformas externas | ⚠️ Apps del ecosistema inlang | ❌ Plataformas externas |
| Ayudantes SEO (hreflang, sitemap) | ✅ Integrados | ❌ Manual | ⚠️ URLs localizadas, resto manual | ❌ Manual |
| Tamaño de runtime (gzip, bench) | 4.5 KB | 75.9 KB | 1.8 KB | 56.7 KB |
| Fuga, mejor setup (locale / pág) | 0% / 0% | 0% / 0% | 49.7% / 0% | 8.6% / 0% |
| Traducciones faltantes en CI | ✅ npx intlayer test | ⚠️ No integrado | ⚠️ No integrado | ✅ lingui compile --strict |
Las cifras de tamaño de runtime y fuga provienen del benchmark de TanStack Start. La fuga se mide en la mejor configuración de cada biblioteca.
Otras guías de TanStack Start: use-intl, Paraglide JS e Intlayer.
Prácticas recomendadas que debes seguir
- Establece
langydiren<html>a partir del locale de la ruta, para que sean correctos en el HTML del servidor. - Mantén una URL por locale con un prefijo, para que cada versión de idioma sea indexable.
- Crea una instancia de
I18npor locale, nunca mutes una global durante el SSR: dos solicitudes concurrentes sobreescribirían el locale de la otra. - Carga solo el catálogo activo, nunca importes todos ellos en el código del cliente.
- Elige un estilo de macro (
useLingui+ten componentes,msgpara descriptores perezosos) y mantén la consistencia. Mezclart,i18n._,i18n.ty<Trans>hace que el código sea más difícil de leer para humanos y asistentes de IA. - Ejecuta
lingui extracten CI para que un mensaje nuevo nunca se publique sin traducir. - Traduce tus metadatos y declara
canonical,hreflangyx-defaulten cada página. - Genera un sitemap multilingüe y robots.txt, y pre-renderiza cada locale.
- Usa enlaces reales para el selector de idioma, para que los rastreadores descubran cada idioma.
Consulta nuestra guía sobre internacionalización y SEO y la guía de hreflang.
Guía paso a paso para configurar Lingui en una aplicación TanStack Start
Esta es la estructura del proyecto que crearemos:
Copiar el código al portapapeles
Instalar dependencias
bashCopiar códigoCopiar el código al portapapeles
- @lingui/core / @lingui/react: runtime,
I18nProvidery las macros (@lingui/core/macro,@lingui/react/macro). - @lingui/cli:
lingui extractpara recolectar mensajes en catálogos. - @lingui/vite-plugin: compila catálogos
.poal importar, por lo quelingui compileno es necesario. - @lingui/babel-plugin-lingui-macro + @rolldown/plugin-babel: transforman las macros en tiempo de compilación.
- @lingui/core / @lingui/react: runtime,
Centralizar la configuración de locales
El locale predeterminado se mantiene sin prefijo (
/about), otros locales llevan prefijo (/fr/about).src/i18n/config.tsCopiar códigoCopiar el código al portapapeles
Configurar Lingui
La configuración de Lingui reutiliza la misma lista de locales, de modo que los catálogos, el enrutador y el sitemap nunca discrepen.
lingui.config.tsCopiar códigoCopiar el código al portapapeles
Añade los scripts de extracción:
package.jsonCopiar códigoCopiar el código al portapapeles
i18n:checkfalla en CI cuando un componente contiene un mensaje que no fue extraído y confirmado en git.Configurar Vite
Con
@vitejs/plugin-reactv6, Babel ya no viene integrado.@rolldown/plugin-babelejecuta el plugin de macro de Lingui, ylinguiTransformerBabelPresetsolo procesa archivos que importan una macro, lo que mantiene compilaciones rápidas.vite.config.tsCopiar códigoCopiar el código al portapapeles
Cargar catálogos por locale
La plantilla literal en
import()permite que Vite emita un chunk por catálogo, y el plugin de Lingui compila el archivo.podentro de él. Un visitante en francés descarga únicamente el catálogo en francés.Los mensajes compilados son datos planos, por lo que pueden ser devueltos por un loader de ruta, serializados en el HTML y reutilizados durante la hidratación.
src/i18n/lingui.tsCopiar códigoCopiar el código al portapapeles
Para que TypeScript acepte la importación
.po, declara el módulo una vez:src/i18n/po.d.tsCopiar códigoCopiar el código al portapapeles
Crear el documento raíz
La ruta raíz lee el parámetro opcional de locale para configurar
langydiren el<html>renderizado en el servidor.src/routes/__root.tsxCopiar códigoCopiar el código al portapapeles
Crear la ruta de layout del locale
La carpeta
{-$locale}crea un segmento de ruta opcional:/abouty/fr/aboutcoinciden con/{-$locale}/about. El layout rechaza prefijos desconocidos, carga el catálogo del locale actual y proporciona una instancia dedicada deI18n.src/routes/{-$locale}/route.tsxCopiar códigoCopiar el código al portapapeles
Utilizar traducciones en tus páginas
Escribe el texto fuente en el componente. Las macros lo convierten en IDs de mensajes en tiempo de compilación, y
lingui extractlo recolecta.<Trans>para contenido JSX, incluyendo elementos anidados;useLingui().tpara cadenas (atributos, props);<Plural>para plurales ICU.
src/routes/{-$locale}/about.tsxCopiar códigoCopiar el código al portapapeles
La importación dinámica
import()de un catálogo se almacena en caché por el sistema de módulos, por lo que llamar aloadI18nen varios loaders no descarga el catálogo dos veces.Extraer y traducir tus mensajes
Ejecuta la extracción. Lingui escribe cada mensaje en el catálogo de cada locale:
bashCopiar códigoCopiar el código al portapapeles
Luego traduce el
msgstrde cada entrada:src/locales/fr/messages.poCopiar códigoCopiar el código al portapapeles
src/locales/es/messages.poCopiar códigoCopiar el código al portapapeles
Por defecto, los IDs de mensajes son hashes del texto fuente: cambiar el texto en inglés crea un mensaje nuevo. Usa IDs explícitos (
<Trans id="about.title">About us</Trans>) para textos que cambien a menudo.Construir un componente de enlace localizado
OpcionalCada ruta se encuentra bajo
{-$locale}, por lo que los enlaces deben portar el parámetro del locale actual.src/components/LocalizedLink.tsxCopiar códigoCopiar el código al portapapeles
Cambiar el idioma de tu contenido
OpcionalRenderiza el selector como enlaces, de modo que los rastreadores encuentren cada versión de idioma.
to="."mantiene la página actual y reemplaza el parámetro de locale. El loader del layout del locale obtiene entonces el nuevo catálogo.src/components/LocaleSwitcher.tsxCopiar códigoCopiar el código al portapapeles
Internacionalizar tus metadatos
OpcionalCada versión de idioma puede posicionarse por sí misma, siempre que cada página exponga un
<title>y descripción traducidos, un canonical autorreferenciado, unhreflangpor locale másx-default, locales de Open Graph y JSON-LD coninLanguage. Los metadatos se traducen en el loader (paso 8), y este asistente construye el resto:src/i18n/seo.tsCopiar códigoCopiar el código al portapapeles
Internacionalizar tu Sitemap y robots.txt
OpcionalEl sitemap enumera cada URL de cada locale, declarando cada entrada todas sus alternativas con
xhtml:link.robots.txtbloquea rutas privadas en todos los idiomas y apunta al sitemap. Eliminapublic/robots.txtsi el proyecto inicial creó uno.src/routes/sitemap[.]xml.tsCopiar códigoCopiar el código al portapapeles
src/routes/robots[.]txt.tsCopiar códigoCopiar el código al portapapeles
Pre-renderizar cada locale
OpcionalEnumera cada ruta localizada para que TanStack Start pre-renderice todas las versiones de idioma en tiempo de compilación:
vite.config.tsCopiar códigoCopiar el código al portapapeles
Redirigir a visitantes primerizos y manejar páginas 404
OpcionalUn middleware de solicitud envía a los visitantes que aterrizan en
/a su idioma preferido (primero por cookie, luego porAccept-Language). Los enlaces profundos nunca se redirigen, por lo que los rastreadores y las URLs compartidas siempre obtienen la página que solicitaron.src/i18n/negotiateLocale.tsCopiar códigoCopiar el código al portapapeles
src/start.tsCopiar códigoCopiar el código al portapapeles
Para las páginas 404, una ruta comodín (catch-all) renderiza el
notFoundComponentlocalizado del layout. Márcala comonoindex: React 19 eleva el<meta>hacia<head>.src/components/NotFound.tsxCopiar códigoCopiar el código al portapapeles
src/routes/{-$locale}/$.tsxCopiar códigoCopiar el código al portapapeles
Mantén tus macros, reduce el runtime con Intlayer
OpcionalEl adaptador de compatibilidad
@intlayer/linguimantiene tu código fuente intacto: las macros se compilan exactamente como antes, y las llamadas resultantes ai18n._(),useLingui()y<Trans>son servidas por diccionarios compilados de Intlayer. En el benchmark, el runtime baja de ~56.7 KB a ~9.8 KB gzip.bashCopiar códigoCopiar el código al portapapeles
Añade el plugin después de la transformación de macros, de modo que cree alias de
@lingui/corey@lingui/reacthacia el adaptador:vite.config.tsCopiar códigoCopiar el código al portapapeles
Los catálogos se sincronizan con el plugin de sincronización JSON (catálogos JSON) o el plugin de sincronización PO (catálogos PO). Consulta la configuración completa en la guía de compatibilidad con Lingui y una comparación detallada en Lingui vs @intlayer/lingui.
Automatiza tus traducciones usando Intlayer
OpcionalLingui extrae mensajes, pero completar docenas de catálogos a mano es donde se va la mayor parte del tiempo. Intlayer es gratuito y de código abierto, y sus herramientas funcionan junto a Lingui:
- Traduce con IA utilizando tu propia clave de API y proveedor. Consulta auto fill y la CLI.
- Conserva tus archivos PO como la fuente de la verdad con el plugin de sincronización PO.
- Comprueba traducciones faltantes en CI. Consulta probar tus traducciones.
- Audita tu sitio desplegado en busca de
hreflangfaltantes, canonicals erróneos y fugas de locale con el comando scan.
Preguntas frecuentes
Sí. Lingui no tiene una integración dedicada para TanStack Start, pero su plugin de Vite y el plugin de macros de Babel funcionan tal cual. Los dos puntos clave a configurar correctamente son ejecutar las macros a través de @rolldown/plugin-babel (Vite 8 y @vitejs/plugin-react v6 ya no incluyen Babel) y crear una instancia de I18n por locale en lugar de activar una global durante el SSR.
En el servidor, un proceso renderiza muchas solicitudes al mismo tiempo. Llamar a i18n.activate("fr") en un objeto compartido cambiaría el idioma de una solicitud que se esté renderizando en inglés en paralelo. setupI18n crea una instancia aislada por locale, lo cual es seguro.
No. @lingui/vite-plugin compila los catálogos .po cuando son importados. Solo necesitas ejecutar lingui extract para recolectar nuevos mensajes.
Decláralos con la macro msg y tradúcelos en el loader de la ruta con i18n._(msg`...`). El loader devuelve cadenas de texto simples, por lo que head() se mantiene síncrono y los valores se serializan para la hidratación. El paso 8 y el paso 12 muestran la configuración completa.
El benchmark mide ~56.7 KB gzip para el runtime. Con un catálogo por locale cargado bajo demanda, las páginas pesan ~115 KB frente a 111 KB sin i18n. Importar todos los catálogos estáticamente eleva el tamaño a ~152 KB.
Sí. El adaptador @intlayer/lingui mantiene las macros y reemplaza el runtime. Luego puedes migrar los componentes a useIntlayer uno por uno. Consulta los adaptadores de compatibilidad.
Comentarios
Aún no hay comentarios. Sé el primero en compartir tus pensamientos.
