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 Paraglide JS en 2026
Tabla de contenidos
¿Qué es Paraglide JS?
Paraglide JS (creado por inlang) es una biblioteca de i18n basada en compilador. En lugar de incluir un runtime que busca claves en un objeto JSON, compila cada mensaje en una función JavaScript tipada (m.about_title()). Los mensajes no utilizados pueden ser eliminados por el empaquetador (bundler), y un error tipográfico en una clave genera un error de compilación.
Paraglide es el enfoque de i18n utilizado en los ejemplos oficiales de TanStack Router, y se integra con TanStack Start a través de tres elementos:
- un plugin de Vite que compila los mensajes y el runtime en
src/paraglide; - un middleware del servidor que resuelve el locale de cada solicitud;
- una reescritura del router (router rewrite) que asigna URLs localizadas (
/fr/about) a tu árbol de rutas (/about), de modo que no necesitas un segmento$locale.
Esta guía configura estos tres componentes y luego cubre todo lo que Paraglide deja en tus manos: lang y dir, selector de idioma, metadatos traducidos, canonical, hreflang con x-default, Open Graph, JSON-LD, sitemap, robots.txt, prerenderizado y páginas 404 localizadas.
¿Buscas otro stack? Consulta la guía de TanStack Start + use-intl, la guía de TanStack Start + Lingui o la guía de TanStack Start + Intlayer.
¿Comparando los dos enfoques basados en compilador? Lee ¿es Intlayer más ligero que Paraglide?.
Lo que dice el benchmark sobre Paraglide en TanStack Start
El benchmark de i18n ejecuta la misma aplicación TanStack Start de 10 páginas y 10 locales con cada una de las principales bibliotecas 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 @inlang/paraglide-js@2.15.1, medidas el 2026-09-26 (gzip):
Abrir la tabla en una ventana flotante para ver todo el contenido claramente
| Configuración | Tamaño de la biblioteca | JS por página | Fuga de otros locales | Fuga de otras páginas | Carga de página |
|---|---|---|---|---|---|
| Sin i18n (app base) | - | 111.0 KB | 0% | 0% | 15.7 ms |
| Paraglide JS | 1.8 KB | 125.1 KB | 49.7% | 0% | 22.1 ms |
react-intlayer | 4.5 KB | 126.8 KB | 0% | 0% | 14.8 ms |
use-intl | 75.9 KB | 128.7 KB | 0% | 0% | 17.4 ms |
| Lingui | 56.7 KB | 120.2 KB | 8.6% | 0% | 21.9 ms |
Puntos clave a considerar:
- El runtime es diminuto y no hay fuga entre páginas. El runtime se genera para tu configuración específica y los mensajes se importan donde se utilizan.
- Fuga de locales. Cada función de mensaje contiene todos los locales, por lo que aproximadamente la mitad de las cadenas traducidas enviadas a una página corresponden a idiomas que el visitante no utiliza. Cuantos más locales agregues, mayor será esta proporción.
- La carga de página es la más lenta del grupo, en parte porque el locale se resuelve mediante estrategias en cada llamada en lugar de leerse desde un contexto de React.
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 Paraglide JS con las otras bibliotecas comúnmente utilizadas 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 | ✅ Colocalizadas | ❌ JSON centralizado | ❌ Un archivo JSON por locale | ⚠️ Texto fuente en componentes |
| Integración con TypeScript | ✅ Tipos autogenerados | ✅ Vía AppConfig | ✅ Funciones de mensajes tipadas | ⚠️ Solo macros |
| Detección de traducciones faltantes | ✅ Errores de tipo y advertencias de build | ⚠️ Fallback en runtime | ⚠️ Recurre al locale base | ⚠️ Recurre al texto fuente |
| Contenido enriquecido (JSX, Markdown) | ✅ Soporte directo | ⚠️ Etiquetas vía t.rich | ⚠️ Cadenas de texto | ✅ JSX dentro de <Trans> |
| Enrutamiento localizado | ✅ Integrado | ❌ Manual {-$locale} | ✅ urlPatterns + reescritura de router | ❌ Manual {-$locale} |
| 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 plugin de 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, benchmark) | 4.5 KB | 75.9 KB | 1.8 KB | 56.7 KB |
| Fuga, mejor configuración (locale / página) | 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: Lingui, use-intl e Intlayer.
Prácticas recomendadas
- Establece
langydiren<html>a partir del locale resuelto, en el servidor. - Mantén una URL por locale con una estrategia de prefijo (
/fr/about), para que cada versión de idioma sea indexable. - Coloca
urlprimero en tu estrategia de locales, de modo que la URL sea la fuente de verdad y los rastreadores obtengan la página solicitada. - Usa claves de mensaje planas y descriptivas (
about_title) que se asignen de forma limpia a nombres de funciones. - Haz commit de tus archivos
messages/*.json, no de la carpeta generadasrc/paraglide, para evitar conflictos de fusión en archivos autogenerados. - Traduce tus metadatos y declara
canonical,hreflangyx-defaulten cada página. - Genera un sitemap multilingüe y robots.txt, y prerenderiza cada locale.
- Usa enlaces reales para el selector de idioma, para que los rastreadores descubran todos los idiomas.
Consulta nuestra guía sobre internacionalización y SEO y la guía de hreflang.
Guía paso a paso para configurar Paraglide JS en una aplicación TanStack Start
Esta es la estructura de proyecto que crearemos:
Copiar el código al portapapeles
Observa que no hay carpeta $locale: la reescritura del router elimina el prefijo antes de la coincidencia de rutas.
Instalar dependencias
Comienza desde un proyecto TanStack Start y luego inicializa Paraglide. El comando init crea
project.inlang/settings.json, un primermessages/en.jsone instala el paquete.bashCopiar códigoCopiar el código al portapapeles
- @inlang/paraglide-js: el compilador y su plugin de Vite. No hay ningún paquete de runtime que instalar: el runtime se genera dentro de tu proyecto.
Configurar tus locales
project.inlang/settings.jsones la fuente única de verdad para los locales. El plugin de formato de mensajes lee un archivo JSON por locale.project.inlang/settings.jsonCopiar códigoCopiar el código al portapapeles
Configurar el plugin de Vite y la estrategia de URL
El plugin compila los mensajes en cada cambio. Tres opciones son fundamentales para TanStack Start:
strategy: la lista ordenada de lugares donde leer el locale.urlen primer lugar hace que la URL sea la fuente de verdad.cookieypreferredLanguageson utilizados por el middleware cuando la URL no determina el locale.urlPatterns: cómo se asigna un locale a una URL. Los locales no predeterminados se listan primero, ya que el primer patrón coincidente gana. Aquí el locale predeterminado se mantiene sin prefijo (/about), y los otros locales llevan prefijo (/fr/about).outputStructure: "message-modules": un módulo por mensaje, lo que permite al empaquetador descartar los mensajes que una página no importa.
vite.config.tsCopiar códigoCopiar el código al portapapeles
Añade la carpeta generada a
.gitignore. Se reconstruye endevybuild:.gitignoreCopiar códigoCopiar el código al portapapeles
Crear tus archivos de traducción
Cada clave se convierte en una función exportada desde
src/paraglide/messages. Las claves planas en snake_case generan los nombres de función más limpios. Las variables utilizan marcadores de posición{name}.messages/en.jsonCopiar códigoCopiar el código al portapapeles
messages/fr.jsonCopiar códigoCopiar el código al portapapeles
Los plurales utilizan la sintaxis de variantes del formato de mensajes de inlang:
messages/en.jsonCopiar códigoCopiar el código al portapapeles
Añadir el middleware del servidor
El middleware resuelve el locale de cada solicitud con tu estrategia y lo pone a disposición de
getLocale()para todo el renderizado del servidor, a través de un ámbitoAsyncLocalStorage. Esto es lo que garantiza la seguridad en solicitudes concurrentes en diferentes idiomas.En TanStack Start, envuelve la entrada de servidor predeterminada:
src/server.tsCopiar códigoCopiar el código al portapapeles
Reescribir URLs localizadas en el router
La opción
rewritede TanStack Router traduce las URLs en los límites del router:- input:
/fr/aboutse deslocaliza a/aboutantes de la coincidencia, por lo que una única rutaabout.tsxsirve a todos los idiomas; - output: cada
hrefgenerado (enlaces, redirecciones, navegación) se localiza para el locale activo, por lo que<Link to="/about">renderiza/fr/abouten una página en francés.
src/router.tsxCopiar códigoCopiar el código al portapapeles
Dado que los enlaces se localizan mediante la reescritura, no necesitas un componente
LocalizedLinkpersonalizado: usa elLinkde TanStack Router como de costumbre.- input:
Crear el documento raíz
getLocale()devuelve el locale resuelto por el middleware en el servidor y el locale de la URL en el navegador, por lo quelangydirson idénticos en el HTML del servidor y tras la hidratación.src/i18n/config.tsCopiar códigoCopiar el código al portapapeles
src/routes/__root.tsxCopiar códigoCopiar el código al portapapeles
Utilizar traducciones en tus páginas
Los mensajes son funciones estándar: importa
m, llama a la función y pasa las variables como un objeto. Todo está tipado, incluidas las variables.src/routes/index.tsxCopiar códigoCopiar el código al portapapeles
src/routes/about.tsxCopiar códigoCopiar el código al portapapeles
Una función de mensaje también acepta un locale explícito:
m.about_title({}, { locale: "fr" }). Esto es útil en código del servidor que renderiza un idioma diferente al de la solicitud, como los correos electrónicos.Cambiar el idioma de tu contenido
OpcionalRenderiza el selector como enlaces con
localizeHref, para que los rastreadores descubran todos los idiomas.setLocaleguarda la elección en la cookie y recarga la página en el nuevo idioma: una recarga completa es el comportamiento esperado de Paraglide, ya que las funciones de mensajes leen el locale en cada llamada en lugar de suscribirse a un estado de React.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>ydescriptiontraducidos; - una URL canónica que apunte a sí misma;
- un
hreflangalternativo por cada locale, másx-default; - etiquetas Open Graph
og:locale,og:locale:alternateyog:url; - JSON-LD con
inLanguage.
La función
localizeUrlde Paraglide construye las URLs alternativas a partir de tusurlPatterns, evitando desfases con el enrutamiento real:src/i18n/seo.tsCopiar códigoCopiar el código al portapapeles
- un
Internacionalizar tu Sitemap
OpcionalUn sitemap multilingüe lista cada URL de cada locale, y cada entrada declara todas sus alternativas con
xhtml:link:src/routes/sitemap[.]xml.tsCopiar códigoCopiar el código al portapapeles
Internacionalizar tu robots.txt
OpcionalLas rutas privadas existen en todos los idiomas, por lo que las reglas
Disallowdeben cubrir cada ruta localizada. Eliminapublic/robots.txtsi la plantilla de inicio creó uno y luego sírvelo desde una ruta:src/routes/robots[.]txt.tsCopiar códigoCopiar el código al portapapeles
Prerenderizar cada locale
OpcionalEnumera la ruta localizada de cada página para que TanStack Start prerenderice todas las versiones de idioma.
localizeHrefes código generado sin dependencias del navegador, por lo que puede ejecutarse envite.config.ts, pero el archivo solo existe tras una primera compilación. Listar las rutas manualmente, como se muestra a continuación, evita este problema de orden:vite.config.tsCopiar códigoCopiar el código al portapapeles
Debido a que el selector renderiza enlaces reales,
crawlLinks: truetambién descubrirá las páginas que hayas olvidado listar.Manejar páginas 404 localizadas
OpcionalCon la reescritura,
/fr/does-not-existcoincide como/does-not-exist, ygetLocale()sigue devolviendofr, por lo que elnotFoundComponentraíz del paso 7 se renderiza en francés. Una ruta comodín (catch-all) garantiza que las rutas profundas también lleguen a él. Marca la página comonoindex: React 19 eleva la etiqueta<meta>al<head>.src/components/NotFound.tsxCopiar códigoCopiar el código al portapapeles
src/routes/$.tsxCopiar códigoCopiar el código al portapapeles
Acceder al locale en funciones del servidor
OpcionalLas funciones del servidor se ejecutan dentro del ámbito del middleware de Paraglide, por lo que
getLocale()también funciona allí:src/server/sendWelcomeEmail.tsCopiar códigoCopiar el código al portapapeles
Comparación con Intlayer
OpcionalNo existe un adaptador directo de Paraglide a Intlayer, porque ambos siguen el mismo concepto: compilar el contenido en tiempo de compilación e incluir la menor cantidad posible de runtime. Las diferencias radican en lo que llega al navegador y cómo se organiza el contenido:
- Locales: Intlayer carga diccionarios dinámicos por locale (0% de fuga de locales en el benchmark), mientras que cada función de mensaje de Paraglide incluye todos los locales (49.7%).
- Organización del contenido: el contenido puede residir en archivos
.content.tsjunto a cada componente, o en archivos centralizados. Consulta i18n por componente vs centralizado. - Cambio de locale: el contenido se lee desde un contexto de React, por lo que cambiar de locale vuelve a renderizar sin necesidad de recargar la página.
- Código generado: no se genera nada dentro de
src, por lo que no hay nada que regenerar antes de hacer commit.
Si vienes de otra biblioteca en lugar de Paraglide, los adaptadores de compatibilidad mantienen la API de
use-intl,next-intl,react-i18next,react-intlo Lingui e intercambian el runtime.Consulta ¿es Intlayer más ligero que Paraglide? y la guía de Intlayer con TanStack Start.
Automatizar tus traducciones usando Intlayer
OpcionalParaglide renderiza traducciones, pero no te ayuda a producirlas. Intlayer es gratuito y de código abierto, y sus herramientas son útiles incluso en un proyecto con Paraglide:
- Traduce con IA utilizando tu propia clave y proveedor de API. Consulta auto fill y la CLI.
- Mantén tus archivos JSON como la fuente de verdad con el plugin sync JSON.
- Prueba traducciones faltantes en CI. Consulta probar tus traducciones.
- Analiza tu sitio desplegado en busca de
hreflangfaltantes, etiquetas canonical erróneas y fugas de locales con el comando scan.
Preguntas frecuentes
Es una opción sólida: se utiliza en los ejemplos oficiales de TanStack Router, tiene el runtime más pequeño del benchmark (~1.8 KB gzip) y los mensajes están completamente tipados. Las contrapartidas son que cada función de mensaje contiene todos los locales, lo que genera una fuga de aproximadamente la mitad de las cadenas traducidas a visitantes de otros idiomas, y que cambiar de locale recarga la página.
No. La reescritura (rewrite) del router elimina el prefijo de locale antes de la coincidencia de rutas y lo vuelve a añadir a los enlaces generados, por lo que un único about.tsx sirve a /about, /fr/about y /es/about.
Las funciones de mensajes leen el locale en el momento en que se llaman; no están suscritas a un estado de React. Por lo tanto, setLocale recarga la página por defecto para que cada mensaje se vuelva a renderizar en el nuevo idioma. Puedes pasar { reload: false }, pero en ese caso deberás volver a renderizar el árbol tú mismo.
Es preferible no hacerlo. La carpeta se regenera en cada dev y build, y versionarla provoca conflictos de fusión en archivos autogenerados. Haz commit de messages/*.json y project.inlang/settings.json en su lugar.
Usa localizeUrl para construir una URL absoluta por locale en el head() de la ruta, y añade un x-default que apunte al locale base. El paso 10 proporciona una función auxiliar reutilizable, y el paso 11 añade los mismos enlaces alternativos al sitemap.
Los mensajes no utilizados se eliminan cuando usas outputStructure: "message-modules", por lo que el contenido de otras páginas no se filtra. Los locales no utilizados no se eliminan: cada función de mensaje contiene todas las traducciones, razón por la cual el benchmark mide un 49.7% de fuga de locales.
Comentarios
Aún no hay comentarios. Sé el primero en compartir tus pensamientos.
