Haz tu pregunta y obtén un resumen del documento referenciando esta página y el proveedor AI de tu elección
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
Vite i18n: los aspectos propios de Vite, no de tu framework
La mayoría de los tutoriales de "Vite i18n" son en realidad tutoriales de React o Vue que casualmente usan Vite. Este artículo aborda la capa inferior: cómo se importan los catálogos, qué hace Rollup con ellos y por qué la carga diferida (lazy loading) que escribiste probablemente no sea tan diferida como crees.
Tabla de contenidos
La importación estática es la opción predeterminada, y es síncrona
La configuración más elemental importa cada catálogo en la parte superior de un módulo.
Copiar el código al portapapeles
Eso introduce tres catálogos en el chunk de entrada principal, en cada página, para cada visitante. Es admisible para dos idiomas y un centenar de cadenas. Con diez idiomas se convierte en el mayor costo innecesario de todo el bundle.
import.meta.glob y el parámetro que casi todos configuran mal
La importación por patrones (glob import) de Vite es la solución estándar.
Copiar el código al portapapeles
La carga diferida viene activada por defecto: cada entrada es una función que retorna una importación dinámica, y Rollup emite un chunk por archivo. Añadir { eager: true } incrusta todos los catálogos directamente en el módulo que importa, exactamente lo contrario de lo que buscabas evitar.
Copiar el código al portapapeles
La trampa radica en que ambas variantes funcionan en desarrollo, ya que Vite sirve módulos individuales sin empaquetar. La diferencia solo se hace visible en la carpeta dist. Compruébalo con npx vite build && npx vite preview y analiza qué contiene realmente el chunk de entrada.
La división por ruta rara vez divide los catálogos
Este es el comportamiento que suele sorprender a los desarrolladores. Divides los catálogos por vista:
Copiar el código al portapapeles
Luego dos rutas distintas importan checkout.json, y Rollup eleva ese archivo a un chunk compartido que se descarga en ambas páginas. La partición de Rollup se guía por el grafo de módulos y no por el nombre de tus carpetas: cualquier módulo alcanzable desde más de un punto de entrada pasa a ser común. Agregar una tercera ruta no cambia nada, y una cuarta puede provocar una reorganización imprevista.
Por lo tanto, la división de idiomas por ruta solo se sostiene si el grafo de importaciones es estrictamente disjunto. Si el tamaño de tu bundle importa, verifícalo con datos y no con suposiciones:
Copiar el código al portapapeles
Si necesitas forzar los límites de empaquetado, build.rollupOptions.output.manualChunks es el mecanismo de escape, con el costo de requerir mantenimiento manual.
Los catálogos no recargan en caliente (HMR)
Modificas un componente y Vite lo actualiza al instante. Modificas locales/fr.json y, según cómo haya sido importado, no ocurre nada. El JSON importado dinámicamente carece de un límite HMR nativo, por lo que el grafo de dependencias no sabe cómo invalidar los módulos consumidores.
Muchos equipos sortean esto reiniciando el servidor de desarrollo ante cada cambio de texto, sin percatarse de que es evitable. La solución corresponde al plugin de i18n: debe aceptar la actualización de HMR e inyectar los nuevos mensajes en la aplicación en ejecución. Al evaluar una librería, verifica si su plugin de Vite implementa esto, pues representa una fricción diaria de desarrollo.
define incrusta el idioma de forma irreversible
Es tentador resolver el idioma por defecto durante la compilación:
Copiar el código al portapapeles
define ejecuta un reemplazo textual puro al compilar. El valor presente en el build es el que se distribuye, obligándote a realizar un build por cada idioma. Esa es una estrategia válida, adoptada por ejemplo por el sistema i18n nativo de Angular, pero no es lo adecuado si una única implementación debe atender todos los idiomas.
Para variables que deban variar por petición del usuario, evita define y resuélvelas en tiempo de ejecución.
Mover el análisis de mensajes a tiempo de compilación
Cualquier opción madura en este ecosistema termina adoptando la misma estrategia: dejar de procesar mensajes en el navegador.
Abrir la tabla en una ventana flotante para ver todo el contenido claramente
| Plugin | Lo que traslada a tiempo de compilación |
|---|---|
@intlify/unplugin-vue-i18n | Compila mensajes de vue-i18n a funciones de render (bundle de solo runtime) |
| Lingui (macro + plugin) | Extrae y compila catálogos, sustituye macros por IDs de mensajes |
| Paraglide (inlang) | Compila cada mensaje en su propia función tree-shakable |
vite-intlayer | Construye diccionarios por componente, purga y minifica claves inactivas |
La ventaja compartida es doble: el compilador de mensajes en runtime desaparece del bundle final y las entradas no utilizadas pueden eliminarse de forma estática. El costo asociado es que tanto tu servidor de desarrollo como tu CI requieren el plugin, y un comando tsc aislado o un ejecutor de pruebas ajeno a Vite requerirá configuración adicional.
vue-i18n es el caso más claro. Sin @intlify/unplugin-vue-i18n distribuyes un compilador que invoca new Function, lo que suma bytes superfluos y genera conflictos con la directiva Content Security Policy (CSP).
SSR: nunca almacenes el idioma en variables de módulo
Si implementas SSR, sea mediante un framework o con vite-plugin-ssr, la regla inquebrantable es esta: una variable a nivel de módulo que guarde el idioma actual se comparte entre todas las solicitudes concurrentes que atienda ese proceso del servidor.
Copiar el código al portapapeles
Dos usuarios que consulten el servidor al mismo tiempo competirán en una condición de carrera, y uno recibirá la respuesta en el idioma del otro. Esto no se reproduce en desarrollo porque eres el único visitante. Resuelve el idioma por cada petición y transmítelo explícitamente mediante contexto o mediante el almacenamiento de petición de tu framework.
El plugin de Vite de Intlayer
Intlayer registra un único plugin que gestiona la compilación de diccionarios, la observación de cambios en desarrollo y la canalización de optimización.
Copiar el código al portapapeles
La reescritura de importaciones, purga y minificación vienen activadas por defecto. Los dos parámetros clave se configuran en intlayer.config.ts:
Copiar el código al portapapeles
Dado que el contenido se declara por componente y no en gigantescos archivos por idioma, el proceso de purga dispone de un grafo de dependencias real sobre el que operar, haciendo segura la poda de código. El compromiso es el mencionado: el plugin es obligatorio en cualquier entorno donde se compile el código, incluidos CI y runners de tests. Más detalles en optimización de bundles.
Errores habituales
{ eager: true }en un glob pensado para carga diferida. Funciona en desarrollo, incluye todos los idiomas en producción.- Creer que la estructura de directorios genera chunks independientes. Rollup sigue imports, no carpetas. Mide el build.
- Reiniciar el servidor de desarrollo para ver cambios de texto. Es indicio de un handler de HMR ausente, no algo normal.
- Incrustar el idioma en
define. Te obliga a compilar un bundle distinto por cada idioma. - Guardar el estado de idioma a nivel de módulo en SSR. Fuga entre peticiones indetectable en desarrollo local.
- Evaluar rendimiento sobre el servidor de desarrollo. Los módulos sin empaquetar no guardan relación con el bundle empaquetado.
Para profundizar
- Optimización del bundle: purga, minificación y lo que llega al navegador
- Informes de benchmark entre frameworks
- Referencia de configuración
- Configurar Intlayer con Vite y React
- Adaptador de compatibilidad i18next
- React i18n: cómo funciona el modelo de providers
- Vue i18n: cómo funciona y dónde tropieza
- i18n por componente vs centralizada
Comentarios
Aún no hay comentarios. Sé el primero en compartir tus pensamientos.
