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
- "Usar el middleware y los hooks de remix-intlayer"v9.5.519/9/2026
- "Documentación inicial para Remix 3"v9.5.09/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
Traduce tu sitio web Remix 3 usando Intlayer
Esta guía demuestra cómo integrar Intlayer para una internacionalización fluida en aplicaciones Remix 3 con enrutamiento según el idioma, declaraciones de contenido con seguridad de tipos, componentes JSX renderizados en el servidor y soporte multi-entorno en Node.js, Bun, Deno y Cloudflare Workers.
¿Qué es Remix 3?
Remix 3 representa un cambio arquitectónico fundamental hacia un framework web componible, independiente del entorno de ejecución y construido íntegramente sobre estándares web. En lugar de acoplarse a empaquetadores específicos o a APIs de servidor propietarias, Remix 3 se distribuye como paquetes componibles de un solo propósito:
remix/fetch-router(oremix/router): Enrutamiento ligero y conforme a los estándares basado en la API Fetch (RequestyResponse).remix/ui: Un modelo de componentes JSX (jsxImportSource: "remix/ui"). Un componente es una función de setup que devuelve una función de render, por lo que parece React pero mantiene el estado en closures simples de JavaScript.remix/middleware/render: Instalacontext.render(<Page />)en cada petición, transmitiendo el árbol JSX como unaResponseHTML.remix/node-fetch-server: Adaptadores de servidor para Node.js, con soporte nativo para Bun, Deno y entornos edge.remix/cookie: Análisis y serialización de cookies criptográficamente seguras.
Combinado con Intlayer y el paquete remix-intlayer, un middleware de idioma más los mismos hooks useIntlayer / useDictionary / useLocale que react-intlayer, vinculados al contexto de petición de Remix, obtienes un sistema completo de internacionalización que ofrece seguridad en tiempo de compilación, traducciones automatizadas por IA, renderizado en servidor sin sobrecarga y enrutamiento fluido por idioma.
Tabla de contenidos
¿Por qué elegir Intlayer frente a otras alternativas?
En comparación con soluciones tradicionales como i18next o cargadores de traducción a medida, Intlayer ofrece una experiencia de desarrollador integrada y optimizada para la arquitectura web moderna:
Intlayer está diseñado para funcionar de forma nativa con los estándares web (Request, Response, Headers y URL). remix-intlayer se integra en el router Fetch de Remix 3 como un middleware ligero, extrayendo el idioma de las rutas URL, cookies o encabezados Accept-Language y exponiéndolo al resto de la petición, handlers, vistas y componentes remix/ui, sin pasarlo manualmente ni atarte a un entorno de ejecución específico.
Dile adiós a las claves JSON sueltas y a los errores en tiempo de ejecución por claves faltantes. Intlayer aplica validaciones de TypeScript en todos los idiomas declarados, advirtiéndote en tiempo de compilación si falta una traducción o si es inválida.
Remix 3 renderiza componentes JSX en el servidor y transmite el HTML al cliente. Solo el texto resuelto para el idioma solicitado se incluye en la respuesta. No se requieren paquetes de hidratación en el cliente ni catálogos pesados a menos que un componente esté explícitamente marcado como clientEntry.
Intlayer ubica las declaraciones de contenido (.content.ts) junto a la lógica de tus rutas, reduciendo el contexto de tokens necesario para los Modelos de Lenguaje (LLM). Los comandos CLI integrados como intlayer fill e intlayer test te permiten automatizar traducciones en pipelines de CI/CD al costo directo de tu proveedor de IA.
Más allá de los flujos de trabajo basados en código, Intlayer ofrece un Editor Visual autohospedado y un CMS Remoto, permitiendo a editores y traductores actualizar el contenido sin tener que volver a desplegar la aplicación.
Guía paso a paso
Consulta la Plantilla de Aplicación en GitHub.
Instalar dependencias
Instala
intlayer,remix-intlayeryremix(versión 3) usando tu gestor de paquetes preferido:bashCopiar códigoCopiar el código al portapapeles
intlayer: Motor central de internacionalización que proporciona gestión de configuración, declaración de diccionarios (t(),Dictionary), herramientas CLI e intérprete en tiempo de ejecución.remix-intlayer: La integración con Remix 3: el middleware de routerintlayer()que resuelve el idioma de cada petición, y los hooksuseIntlayer,useDictionaryyuseLocaleque lo leen en cualquier punto posterior.remix: El paquete unificado del framework Remix 3 que exportaremix/router,remix/routes,remix/ui,remix/middleware/renderyremix/node-fetch-server.
Configurar Intlayer
Arquitectura
En esta arquitectura, el middleware
intlayer()deremix-intlayerse registra encreateRouter()antes del middlewarerender(). Elimina el prefijo de locale antes de que el router coincida, por lo que las rutas se declaran una sola vez ensrc/routes.tssin segmento:locale, y ejecuta el resto de la solicitud dentro de un alcanceAsyncLocalStorage, lo que permite queuseIntlayer/useLocalelean la locale sin argumentos en los manejadores de rutas y vistas deremix/ui. Las declaraciones de contenido se ubican junto a tus vistas ensrc/:bashCopiar códigoCopiar el código al portapapeles
Configuración
Crea un archivo
intlayer.config.tsen la raíz de tu proyecto para declarar los idiomas soportados y los ajustes de internacionalización:intlayer.config.tsCopiar códigoCopiar el código al portapapeles
import { Locales, type IntlayerConfig } from "intlayer"; const config: IntlayerConfig = { internationalization: { locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH], defaultLocale: Locales.ENGLISH, }, }; export default config;Para ajustes de configuración adicionales (como modo estricto o preferencias de almacenamiento de rutas), consulta la documentación de configuración.
Declarar tu contenido multilingüe
Declara tu contenido localizado en un archivo
.content.ts:src/home.content.tsCopiar códigoCopiar el código al portapapeles
import { t, type Dictionary } from "intlayer"; const homeContent = { key: "home", content: { title: t({ es: "Bienvenido a Remix 3", en: "Welcome to Remix 3", fr: "Bienvenue sur Remix 3", }), description: t({ es: "Una aplicación componible basada en estándares web con i18n nativa.", en: "A composable, web-standard application with native i18n.", fr: "Une application composable basée sur les standards web avec i18n native.", }), switchLanguage: t({ es: "Cambiar idioma:", en: "Switch language:", fr: "Changer de langue :", }), }, } satisfies Dictionary; export default homeContent;Intlayer también admite formatos JSON, YAML y CommonJS. Consulta la Documentación de Declaración de Contenido.
Compilar diccionarios Intlayer
Compila las definiciones de diccionarios para generar los tipos de TypeScript y los registros en tiempo de ejecución:
bashCopiar códigoCopiar el código al portapapeles
Esto compila tu contenido en el directorio de artefactos
.intlayer, permitiendo autocompletado completo en TypeScript y acceso rápido a los diccionarios.Añadir el middleware de Intlayer
Remix 3 proporciona un pipeline de middleware componible mediante
createRouter({ middleware: [...] }).remix-intlayerincluye el middlewareintlayer(). Para cada petición entrante, resuelve el idioma utilizando:- La URL, en todos los modos de enrutamiento excepto
no-prefix: el prefijo de ruta (ej./fro/es) o el parámetro de búsqueda?locale=. - El idioma persistido por el cliente: la cookie de almacenamiento (
INTLAYER_LOCALE) o el encabezado personalizado (x-intlayer-locale). - La negociación estándar de
Accept-Language, recurriendo a tudefaultLocaleconfigurado.
El resultado se almacena en el contexto de petición de Remix como
context.intlayer(ocontext.get(Intlayer)), conlocale,defaultLocaleyavailableLocales. A continuación, el middleware ejecuta el resto de la petición dentro de un ámbito deAsyncLocalStoragevinculado a ese contexto, lo que permite que los hooks del paquete lean el idioma sin argumentos, tanto en manejadores de rutas como en vistas y componentes deremix/ui:typescriptCopiar códigoCopiar el código al portapapeles
useIntlayer("home", "fr")ouseIntlayer("faq", { item: 2 })anulan el idioma de la petición para una llamada, yuseDictionary(homeContent)lee un diccionario importado en lugar de una clave. Fuera de una petición, los hooks recurren al idioma predeterminado.El middleware también prepara los diccionarios de Intlayer cuando se inicia el servidor, por lo que la falta de un
intlayer buildno deja el registro vacío.Establece
routing.enableProxy: falseenintlayer.config.tspara conservar solo la resolución de la locale y gestionar el enrutamiento tú mismo.intlayer({ ignore })deja intactas las solicitudes coincidentes (un prefijo de API, por ejemplo), eintlayer({ isDevServer })controla si la locale almacenada determina las redirecciones en el modo automático predeterminado deenableProxy.- La URL, en todos los modos de enrutamiento excepto
Definir rutas con seguridad de tipos
Define las rutas de tu aplicación usando
route()deremix/routes:src/routes.tsCopiar códigoCopiar el código al portapapeles
import { route } from "remix/routes"; export const routes = route({ // Ruta para el idioma por defecto home: "/", // Ruta localizada con segmento dinámico :locale localizedHome: "/:locale", });El uso de
route()te ofrece generación de URL con seguridad de tipos en toda la aplicación:typescriptCopiar códigoCopiar el código al portapapeles
Renderizar páginas localizadas con JSX
Remix 3 renderiza la interfaz de usuario con componentes JSX de
remix/ui. Un componente es una función de setup que recibe unHandley devuelve una función de render. El setup se ejecuta una sola vez por instancia, el render se ejecuta en cada actualización, y las props se leen a través dehandle.props.Comienza con un shell compartido
Documentque establece los atributos<html lang="..." dir="...">a partir del idioma resuelto por el middleware:src/views/document.tsxCopiar códigoCopiar el código al portapapeles
import { getHTMLTextDir } from "intlayer"; import { useLocale } from "remix-intlayer"; import type { Handle, RemixNode } from "remix/ui"; type DocumentProps = { title: string; children?: RemixNode; }; export const Document = (handle: Handle<DocumentProps>) => () => { const { title, children } = handle.props; const { locale } = useLocale(); return ( <html lang={locale} dir={getHTMLTextDir(locale)}> <head> <meta charSet="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>{title}</title> </head> <body>{children}</body> </html> ); };Luego crea la página de inicio. Lee el diccionario localizado con
useIntlayery renderiza un selector de idioma:src/views/home.tsxCopiar códigoCopiar el código al portapapeles
import { getLocaleName, getLocalizedUrl, getPathWithoutLocale } from "intlayer"; import { useIntlayer, useLocale } from "remix-intlayer"; import { Document } from "./document"; export const HomePage = () => () => { const { locale, availableLocales } = useLocale(); const home = useIntlayer("home"); const pathWithoutLocale = getPathWithoutLocale(); return ( <Document title={home.title}> <header> <nav aria-label="Languages"> <span>{home.switchLanguage}</span> <ul> {availableLocales.map((localeItem) => { const isActive = localeItem === locale; return ( <li key={localeItem} class="p-1"> <a href={getLocalizedUrl(pathWithoutLocale, localeItem)} class={isActive ? "active" : undefined} aria-current={isActive ? "page" : undefined} > {getLocaleName(localeItem, locale)} </a> </li> ); })} </ul> </nav> </header> <main> <h1>{home.title}</h1> <p>{home.description}</p> </main> </Document> ); };Remix JSX no es React:
classse escribe tal cual (classNametambién se acepta) y los re-renderizados se activan explícitamente conhandle.update(). Los valores interpolados se escapan automáticamente. Los hooks de Intlayer son funciones simples que leen el ámbito de la petición, por lo que se pueden llamar tanto desde la función de setup como desde la de renderizado.Conectar el router y el servidor
Añade el middleware
render()deremix/middleware/renderjunto al middleware de Intlayer. Este instalacontext.render(node, init)en cada petición, lo cual transmite el árbol JSX en unaResponseHTML (anteponiendo<!DOCTYPE html>y configurando el encabezadoContent-Type):src/router.tsxCopiar códigoCopiar el código al portapapeles
import { isDeclaredLocale } from "intlayer"; import { intlayer } from "remix-intlayer"; import { render } from "remix/middleware/render"; import { createRouter } from "remix/router"; import { routes } from "./routes"; import { HomePage } from "./views/home"; // 1. Initialize router with Intlayer + render middleware export const router = createRouter({ middleware: [intlayer(), render()], }); // 2. Map route handlers router.map(routes, { actions: { // Default locale route home(context) { return context.render(<HomePage />); }, // Localized route localizedHome(context) { if (!isDeclaredLocale(context.params.locale)) { return new Response("Not Found", { status: 404 }); } return context.render(<HomePage />); }, }, });context.renderacepta unResponseInitopcional como segundo argumento, ej.context.render(<NotFoundPage />, { status: 404 }). El idioma resuelto permanece accesible desde el manejador comocontext.intlayer.locale, por ejemplo para construir una respuestaResponse.json.Por último, expón el router a través de un manejador
fetchestándar. El mismo router funciona en Node.js, Bun, Deno y Cloudflare Workers:src/server.tsCopiar códigoCopiar el código al portapapeles
import * as http from "node:http"; import { createRequestListener } from "remix/node-fetch-server"; import { router } from "./router"; const PORT = Number(process.env.PORT || 3000); // Node.js const server = http.createServer( createRequestListener((request) => router.fetch(request)) ); server.listen(PORT, () => { console.log(`Servidor ejecutándose en http://localhost:${PORT}`); }); // Bun / Deno / Cloudflare Workers export default { port: PORT, fetch(request: Request) { return router.fetch(request); }, };Auditar y autocompletar traducciones
Intlayer proporciona una CLI para auditar traducciones faltantes y completarlas automáticamente mediante IA:
bashCopiar códigoCopiar el código al portapapeles
Configuración de TypeScript
Apunta JSX al runtime remix/ui y asegúrate de que tu tsconfig.json incluya los tipos generados por .intlayer:
Copiar el código al portapapeles
jsxImportSource: "remix/ui"es lo que hace que<HomePage />se resuelva mediante elcreateElementde Remix en lugar del de React.
Conclusión
Con Remix 3 e Intlayer, dispones de una pila tecnológica ligera, tipada y portable que cumple con los estándares web abiertos. Tu aplicación puede escalar sin problemas desde simples páginas de marketing localizadas hasta servicios distribuidos globalmente y renderizados en el edge.
