Autor:
    Creación:2024-03-07Última actualización:2026-09-27

    Traducir tu sitio Astro con Intlayer

    ide.intlayer.org
    intlayer-astro-template.vercel.app

    Tabla de Contenidos

    ¿Por qué Intlayer en lugar de alternativas?

    En comparación con soluciones principales como astro-i18n o i18next, Intlayer es una solución que viene con optimizaciones integradas como:

    Intlayer está optimizado para funcionar perfectamente con Astro al ofrecer enrutamiento multilingüe, mapa del sitio y todas las funciones necesarias para escalar la internacionalización (i18n).

    En lugar de cargar archivos JSON masivos en sus páginas, cargue solo el contenido necesario. Intlayer ayuda a reducir el tamaño de su bundle y de sus páginas hasta en un 50%.

    Determinar el alcance del contenido de su aplicación facilita el mantenimiento para aplicaciones a gran escala. Puede duplicar o eliminar una sola carpeta de funciones sin la carga mental de revisar todo el código base de contenido. Además, Intlayer está completamente escrito para garantizar la precisión de su contenido.

    La ubicación conjunta de contenido reduce el contexto necesario para los modelos de lenguajes grandes (LLM). Intlayer también viene con un conjunto de herramientas, como una CLI para comprobar si faltan traducciones,LSP, MCP y agent skills, para que la experiencia del desarrollador (DX) sea aún más fluida para los agentes de IA.

    Utilice la automatización para traducir su canal de CI/CD utilizando el LLM de su elección al costo de su proveedor de IA. Intlayer también ofrece un compilador para automatizar la extracción de contenido, así como una plataforma web para ayudar a traducir en segundo plano.

    La conexión de archivos JSON masivos a componentes puede provocar problemas de rendimiento y reactividad. Intlayer optimiza la carga de su contenido en el momento de la compilación.

    Más que una simple solución i18n, Intlayer proporciona un [editor visual] autohospedado(/es/doc/concept/editor)* y un *CMS completo para ayudarle a administrar su contenido multilingüe en tiempo real, lo que facilita la colaboración con traductores, redactores y otros miembros del equipo. El contenido se puede almacenar de forma local y/o remota.

    Guía paso a paso para configurar Intlayer en Astro

    Consulta la plantilla de aplicación en GitHub.

    1. Instalar dependencias

      Instala los paquetes necesarios utilizando tu gestor de paquetes preferido:

      bash
      npx intlayer init --interactive
      
      la bandera --interactive es opcional. Usa intlayer-cli init si eres un agente de IA.
      Este comando detectará tu entorno e instalará los paquetes requeridos. Por ejemplo:
      bash
      npm install intlayer astro-intlayer
      
      • intlayer El paquete core que proporciona herramientas de i18n para la gestión de la configuración, traducciones, declaración de contenidos, transpilación y comandos CLI.

      • astro-intlayer Incluye el plugin de integración de Astro para integrar Intlayer con el empaquetador Vite, un middleware que resuelve el idioma de cada solicitud en Astro.locals.intlayer, y los hooks useIntlayer / useDictionary / useLocale. La misma ruta de importación resuelve a la implementación de servidor en tu frontmatter .astro y a la de cliente (respaldada por vanilla-intlayer) en bloques <script>.

    2. Configurar tu proyecto

      Arquitectura

      En esta arquitectura, la integración intlayer() registrada en astro.config.ts compila tus diccionarios y agrega un middleware que resuelve la locale de cada solicitud y la expone en Astro.locals.intlayer. Las páginas residen bajo un segmento rest src/pages/[...locale]/, de modo que la locale predeterminada se sirve sin prefijo y cada otra locale obtiene su propia URL dedicada. Los archivos .astro leen el contenido con los hooks useIntlayer / useLocale de astro-intlayer, y las declaraciones de contenido se ubican junto a tus componentes en src/.

      bash
      .
      ├── src
      │   ├── app.content.tsx               # App content declaration
      │   ├── components
      │   │   └── LocaleSwitcher.astro      # Locale switcher component
      │   └── pages
      │       ├── [...locale]
      │       │   └── index.astro           # Localized page (rest param also serves the default locale)
      │       ├── robots.txt.ts             # robots.txt endpoint
      │       └── sitemap.xml.ts            # Localized sitemap endpoint
      ├── astro.config.ts                   # Astro config with the intlayer() integration
      ├── intlayer.config.ts
      ├── package.json
      └── tsconfig.json
      

      Configuración

      Crea un archivo de configuración para definir los idiomas de tu aplicación:

      intlayer.config.ts
      import { Locales, type IntlayerConfig } from "intlayer";
      
      const config: IntlayerConfig = {
        internationalization: {
          locales: [
            Locales.ENGLISH,
            Locales.FRENCH,
            Locales.SPANISH,
            // Tus otros idiomas
          ],
          defaultLocale: Locales.ENGLISH,
        },
      };
      
      export default config;
      
      A través de este archivo de configuración, puedes configurar URLs localizadas, redirecciones de middleware, nombres de cookies, ubicación y extensiones de las declaraciones de contenido, desactivar los logs de Intlayer en la consola, y más. Para una lista completa de los parámetros disponibles, consulta la documentación de configuración.
    3. Integrar Intlayer en tu configuración de Astro

      Añade el plugin intlayer a tu configuración de Astro.

      astro.config.ts
      // @ts-check
      
      import { intlayer } from "astro-intlayer";
      import { defineConfig } from "astro/config";
      
      // https://astro.build/config
      export default defineConfig({
        integrations: [intlayer()],
      });
      
      El plugin de integración intlayer() se utiliza para integrar Intlayer con Astro. Asegura la generación de los archivos de declaración de contenido y los vigila en modo desarrollo. Define las variables de entorno de Intlayer dentro de la aplicación Astro y proporciona alias para optimizar el rendimiento.
    4. Declarar tu contenido

      Crea y gestiona tus declaraciones de contenido para almacenar traducciones:

      src/app.content.tsx
      import { t, type Dictionary } from "intlayer";
      import type { ReactNode } from "react";
      
      const appContent = {
        key: "app",
        content: {
          title: t({
            en: "Hello World",
            fr: "Bonjour le monde",
            es: "Hola mundo",
          }),
        },
      } satisfies Dictionary;
      
      export default appContent;
      
      Las declaraciones de contenido pueden definirse en cualquier lugar de tu aplicación, siempre que estén incluidas en el contentDir (por defecto ./src) y coincidan con la extensión de los archivos de declaración de contenido (por defecto .content.{json,ts,tsx,js,jsx,mjs,cjs,md,mdx,yaml,yml}).
      Para más información, consulta la documentación de declaración de contenido.
    5. Usar el contenido en Astro

      Consume tus diccionarios en archivos .astro con los hooks exportados por astro-intlayer. Comparten las firmas de react-intlayer: useIntlayer("key") devuelve el contenido de un diccionario y useLocale() el idioma actual, sin necesidad de pasar argumentos.

      El idioma proviene del middleware astro-intlayer, que la integración registra automáticamente antes de tu propio src/middleware.ts. Lo resuelve para cada solicitud, a partir del prefijo de URL, luego del idioma guardado por el cliente (cookie o encabezado), luego de Accept-Language, y lo almacena en Astro.locals.intlayer. Las páginas pre-renderizadas solo usan la URL, ya que se renderizan una vez para cada visitante.

      También debes agregar metadatos de SEO como hreflang y enlaces canónicos a cada página e incluir un selector de idioma para permitir a los usuarios cambiar de idioma.

      src/pages/index.astro
      ---
      import { useIntlayer, useLocale } from "astro-intlayer";
      import {
        getLocalizedUrl,
        defaultLocale,
        localeMap,
        getHTMLTextDir,
      } from "intlayer";
      import LocaleSwitcher from "../components/LocaleSwitcher.astro";
      
      // Idioma resuelto por el middleware (ej. /es/about -> 'es')
      const { locale } = useLocale();
      
      // Contenido del diccionario 'app' para ese idioma
      const { title } = useIntlayer("app");
      ---
      
      <!doctype html>
      <html lang={locale} dir={getHTMLTextDir(locale)}>
        <head>
          <meta charset="utf-8" />
          <meta name="viewport" content="width=device-width" />
          <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
          <title>{title}</title>
      
          <!-- Canonical link: Tells search engines which is the primary version of this page -->
          <link
            rel="canonical"
            href={new URL(getLocalizedUrl(Astro.url.pathname, locale), Astro.site)}
          />
      
          <!-- Hreflang: Tell Google about all localized versions -->
          {
            localeMap(({ locale: mapLocale }) => (
              <link
                rel="alternate"
                hreflang={mapLocale}
                href={new URL(
                  getLocalizedUrl(Astro.url.pathname, mapLocale),
                  Astro.site
                )}
              />
            ))
          }
      
          <!-- x-default: Fallback for users in unmatched languages -->
          <link
            rel="alternate"
            hreflang="x-default"
            href={new URL(
              getLocalizedUrl(Astro.url.pathname, defaultLocale),
              Astro.site
            )}
          />
        </head>
        <body>
          <header>
            <LocaleSwitcher />
          </header>
          <main>
            <h1>{title}</h1>
          </main>
        </body>
      </html>
      
      Astro.locals.intlayer también expone locale, defaultLocale y availableLocales a tus propios middlewares y endpoints. Pasa un idioma o un selector como segundo argumento (useIntlayer("app", "fr"), useIntlayer("faq", { item: 2 })) para anular el idioma de la solicitud en una llamada.
    6. Enrutamiento localizado

      Crea segmentos de ruta dinámicos para servir páginas localizadas (ej: src/pages/[locale]/index.astro):

      src/pages/[locale]/index.astro
      <!-- astro -->
      ---
      import { getIntlayer } from "intlayer";
      
      const { title } = getIntlayer('app');
      ---
      
      <h1>{title}</h1>
      

      La integración de Astro añade un middleware de Vite que ayuda con el enrutamiento sensible al idioma y las definiciones de entorno durante el desarrollo. También puedes crear enlaces entre idiomas utilizando tu propia lógica o herramientas de intlayer como getLocalizedUrl.

    7. Agregar un selector de idioma

      Para permitir a los usuarios cambiar de idioma, puedes crear un componente LocaleSwitcher. Este componente debe mostrar una lista de todos los idiomas admitidos y enlazar a la misma página en cada idioma.

      src/components/LocaleSwitcher.astro
      ---
      import { useLocale } from "astro-intlayer";
      import { getLocaleName, getLocalizedUrl, getPathWithoutLocale } from "intlayer";
      
      const { locale, availableLocales } = useLocale();
      const pathWithoutLocale = getPathWithoutLocale(Astro.url.pathname);
      ---
      
      <nav aria-label="Languages">
        <ul>
          {
            availableLocales.map((localeItem) => (
              <li key={localeItem} class="p-1">
                <a
                  href={getLocalizedUrl(pathWithoutLocale, localeItem)}
                  data-locale={localeItem}
                  aria-current={localeItem === locale ? "page" : undefined}
                >
                  {getLocaleName(localeItem)}
                </a>
              </li>
            ))
          }
        </ul>
      </nav>
      
      <script>
        // En el navegador, la misma importación resuelve a la implementación del cliente
        import { useLocale } from "astro-intlayer";
        import { getLocalizedUrl, type LocalesValues } from "intlayer";
      
        // Guarda la elección en la cookie de idioma y luego navega a la URL localizada
        const { setLocale } = useLocale({
          onLocaleChange: (newLocale) => {
            window.location.href = getLocalizedUrl(window.location.pathname, newLocale);
          },
        });
      
        const localeLinks = document.querySelectorAll("[data-locale]");
      
        localeLinks.forEach((link) => {
          link.addEventListener("click", (event) => {
            const locale = link.getAttribute("data-locale") as LocalesValues;
      
            event.preventDefault();
            setLocale(locale);
          });
        });
      </script>
      
      <style>
        nav {
          display: flex;
          gap: 1rem;
        }
        ul {
          display: flex;
          list-style: none;
          padding: 0;
          margin: 0;
          gap: 0.5rem;
        }
        a[aria-current="page"] {
          font-weight: bold;
          text-decoration: underline;
        }
      </style>
      

      Nota sobre la persistencia: setLocale desde el useLocale del lado del cliente guarda la preferencia de idioma del usuario en una cookie. Esto permite que Intlayer recuerde la elección y redirija automáticamente al usuario a su idioma preferido en futuras visitas: las páginas renderizadas bajo demanda (un adaptador con output: 'server' o prerender = false) son redirigidas por el middleware de Intlayer antes de que se envíe cualquier HTML, mientras que las páginas prerenderizadas, servidas como archivos estáticos, son redirigidas por un pequeño script que la integración inyecta en cada página. Establece routing.enableProxy en false para desactivar ambos. En astro dev, la cookie se ignora como fuente de redirección a menos que routing.enableProxy esté establecido en true, por lo que una cookie obsoleta no puede secuestrar las páginas en las que estás trabajando.

      Intercompatibilidad servidor / cliente: astro-intlayer resuelve a sus hooks de servidor en el frontmatter (leyendo Astro.locals) y a los hooks de cliente de vanilla-intlayer en bloques <script> e islas, con los mismos nombres y formato de contenido. setLocale y onChange solo actúan en el cliente, llama a installIntlayer() allí una vez para inicializar el almacén del cliente. astro-intlayer/client expone la entrada del cliente explícitamente.

    8. Sitemap y Robots.txt

      Intlayer ofrece utilidades para crear dinámicamente tu sitemap localizado y tus archivos robots.txt.

      Sitemap

      Intlayer viene con un generador de sitemap integrado para ayudarte a crear fácilmente un sitemap para tu aplicación. Maneja las rutas localizadas y agrega los metadatos necesarios para los motores de búsqueda.

      El sitemap generado por Intlayer admite el espacio de nombres xhtml:link (Hreflang XML Extensions). A diferencia de los generadores de sitemap predeterminados que solo enumeran URL sin procesar, Intlayer crea automáticamente los enlaces bidireccionales necesarios entre todas las versiones de idioma de una página (por ejemplo, /about, /about?lang=fr y /about?lang=es). Esto garantiza que los motores de búsqueda indexen y sirvan correctamente la versión de idioma adecuada a la audiencia adecuada.

      Crea src/pages/sitemap.xml.ts para generar un sitemap que incluya todas tus rutas localizadas.

      src/pages/sitemap.xml.ts
      import type { APIRoute } from "astro";
      import { generateSitemap, type SitemapUrlEntry } from "intlayer";
      
      const pathList: SitemapUrlEntry[] = [
        { path: "/", changefreq: "daily", priority: 1.0 },
        { path: "/about", changefreq: "monthly", priority: 0.7 },
      ];
      
      export const GET: APIRoute = async ({ site }) => {
        const xmlOutput = generateSitemap(pathList, {
          siteUrl: "https://example.com",
        });
      
        return new Response(xmlOutput, {
          headers: { "Content-Type": "application/xml" },
        });
      };
      

      Robots.txt

      Crea src/pages/robots.txt.ts para controlar el rastreo de los motores de búsqueda.

      src/pages/robots.txt.ts
      import type { APIRoute } from "astro";
      import { getMultilingualUrls } from "intlayer";
      
      const getAllMultilingualUrls = (urls: string[]) =>
        urls.flatMap((url) => Object.values(getMultilingualUrls(url)) as string[]);
      
      const disallowedPaths = getAllMultilingualUrls(["/admin", "/private"]);
      
      export const GET: APIRoute = ({ site }) => {
        const robotsTxt = [
          "User-agent: *",
          "Allow: /",
          ...disallowedPaths.map((path) => `Disallow: ${path}`),
          "",
          `Sitemap: ${new URL("/sitemap.xml", site).href}`,
        ].join("\n");
      
        return new Response(robotsTxt, {
          headers: { "Content-Type": "text/plain" },
        });
      };
      
    9. Continúa usando tus frameworks favoritos

      Sigue construyendo tu aplicación con el framework que prefieras.

    10. Extraer el contenido de tus componentes

      Opcional

      Si tienes una base de código existente, transformar miles de archivos puede llevar mucho tiempo.

      Para facilitar este proceso, Intlayer propone un compilador / extractor para transformar tus componentes y extraer el contenido.

      Para configurarlo, puedes agregar una sección compiler en tu archivo intlayer.config.ts :

      intlayer.config.ts
      import { type IntlayerConfig } from "intlayer";
      
      const config: IntlayerConfig = {
        // ... Resto de tu configuración
        compiler: {
          /**
           * Indica si el compilador debe estar habilitado.
           */
          enabled: true,
      
          /**
           * Define la ruta de los archivos de salida
           */
          output: ({ fileName, extension }) => `./${fileName}${extension}`,
      
          /**
           * Indica si los componentes deben guardarse después de ser transformados. De esa manera, el compilador se puede ejecutar solo una vez para transformar la aplicación y luego se puede eliminar.
           */
          saveComponents: false,
      
          /**
           * Prefijo de clave de diccionario
           */
          dictionaryKeyPrefix: "",
        },
      };
      
      export default config;
      

      Ejecuta el extractor para transformar tus componentes y extraer el contenido

      bash
      npx intlayer extract
      

      Compila tu aplicación para transformar tus componentes y extraer el contenido

      bash
      npm run build # O npm run dev
      

    Configuración de TypeScript

    Intlayer utiliza el aumento de módulos (module augmentation) para aprovechar TypeScript, haciendo que tu código sea más robusto.

    Autocompletado

    Error de traducción

    Asegúrate de que tu configuración de TypeScript incluya los tipos autogenerados.

    tsconfig.json
    {
      // ... tu configuración de TypeScript existente
      "include": [
        // ... tu configuración de TypeScript existente
        ".intlayer/**/*.ts", // Incluir tipos autogenerados
      ],
    }
    

    Configuración de Git

    Se recomienda ignorar los archivos generados por Intlayer. Esto evita incluirlos en tu repositorio de Git.

    Para hacerlo, añade las siguientes instrucciones a tu archivo .gitignore:

    bash
    # Ignorar archivos generados por Intlayer
    .intlayer
    

    Extensión de VS Code

    Para mejorar tu experiencia de desarrollo con Intlayer, puedes instalar la extensión oficial de Intlayer para VS Code.

    Esta extensión proporciona:

    • Autocompletado para las claves de traducción.
    • Detección de errores en tiempo real para traducciones faltantes.
    • Previsualización en línea del contenido traducido.
    • Acciones rápidas para crear y actualizar traducciones fácilmente.

    Para más información sobre el uso de la extensión, consulta la documentación de la extensión para VS Code.

    Profundiza más

    Si quieres saber más, también puedes implementar el Editor Visual o usar el CMS para externalizar tus contenidos.

    Preguntas frecuentes

    Astro incluye una opción i18n a nivel de enrutamiento que gestiona los prefijos de idioma y las redirecciones, pero no gestiona el contenido en sí, así que todavía necesitas una capa de mensajes:

    • La i18n integrada de Astro más diccionarios JSON o TypeScript escritos a mano: sin dependencias, pero sin tipado, sin reglas de plural y sin herramientas.
    • i18next o vue-i18n / svelte-i18n dentro de las islas: una biblioteca completa por cada framework de isla, cada una con su propio catálogo.
    • Intlayer: una única capa de contenido compartida por las páginas de Astro y todos los frameworks de isla, compilada en tiempo de compilación, totalmente tipada, con traducción con IA, un editor visual y un CMS.

    La ventaja específica de Astro es que el mismo diccionario sirve a una página .astro y a una isla de React, Vue, Svelte, Solid, Preact o Lit, en lugar de una biblioteca de i18n por cada runtime de isla. Consulta por qué Intlayer.

    Mucho menos que una configuración basada en espacios de nombres, porque una página nunca descarga un catálogo que no renderiza. Las páginas de Astro se renderizan en tiempo de compilación, así que entregan HTML traducido y ningún diccionario; solo las islas reciben uno. El compilador de tiempo de compilación resuelve las llamadas de contenido a las entradas exactas que usa un componente, y los diccionarios dinámicos reparten el resto por idioma. Frente a las alternativas habituales, Intlayer reduce el tamaño del bundle y de la página hasta en un 50%. Consulta la optimización del bundle y el benchmark.

    En gran medida. Sigue la guía de migración de i18next para trasladar el contenido. También puedes migrar de forma gradual: el plugin de sincronización JSON mantiene tus catálogos JSON existentes como fuente de verdad y genera diccionarios de Intlayer a partir de ellos, de modo que ambas capas se mantienen sincronizadas mientras trasladas los componentes uno a uno.

    Sí. El plugin de sincronización JSON mantiene tus archivos /messages/{locale}/{namespace}.json como fuente de verdad y genera diccionarios de Intlayer a partir de ellos, en ambas direcciones. Un plugin de sincronización PO hace lo mismo para los catálogos gettext, y los archivos por idioma te permiten dividir el contenido por idioma en lugar de agrupar los idiomas en un solo archivo.

    No. Ejecuta npx intlayer extract e Intlayer lee tus componentes, extrae las cadenas visibles para el usuario y escribe un archivo .content junto a cada uno, así que revisas un diff en lugar de copiar cadenas a un catálogo una por una. El paso 15 de esta guía lo explica paso a paso.

    Para una canalización totalmente automatizada, el compilador de Intlayer hace lo mismo en tiempo de compilación: escanea tu código JSX, TSX, Vue y Svelte en cada cambio, genera los diccionarios y los mantiene sincronizados mediante el reemplazo de módulos en caliente, así que no hay ninguna clave que mantener a mano.

    Conviene conocer dos límites antes de activar el compilador. Funciona por análisis estático, así que las cadenas que solo existen en tiempo de ejecución, como los códigos de error de la API o los campos del CMS, quedan fuera de su alcance. Y tiene que distinguir el texto visible para el usuario de la lógica de la aplicación, como className="active" o un código de estado, lo que requiere unas pocas anotaciones en una base de código grande. El comando extract evita ambos manteniéndote en el proceso.

    Cinco piezas, todas opcionales:

    • Extensión de VS Code: salta de una clave useIntlayer al archivo de contenido que la declara, extrae contenido de un componente y ejecuta build, fill, test, push y pull desde la paleta de comandos o desde una pestaña de Intlayer dedicada.
    • Servidor LSP: el mismo conocimiento en cualquier editor que hable LSP, con ir a la definición, buscar todas las referencias, vistas previas al pasar el cursor de un valor traducido, autocompletado de claves y campos, y un aviso cuando una clave no está declarada en ninguna parte. También resuelve las llamadas a i18next, react-i18next, next-intl y use-intl, lo que ayuda durante la migración.
    • Servidor MCP: expone la documentación y la CLI de Intlayer a Cursor, VS Code, Claude Desktop, Claude Code y ChatGPT, para que un asistente responda a partir de la documentación actual en lugar de adivinar, y pueda ejecutar comandos como intlayer fill por sí mismo.
    • Habilidades para agentes: habilidades específicas como intlayer-config, intlayer-cli e intlayer-content, además de una por framework, que enseñan a un agente tu configuración de enrutamiento y los tipos de nodo de contenido.
    • Plugin de ESLint: no-raw-text marca las cadenas codificadas de forma fija, con reglas adicionales para claves de diccionario estáticas y contenido sin usar.