Integraciones
Astro
La integración oficial de Astro. Una línea en astro.config conecta la extracción en vivo, las claves tipadas y el reporte del build; si usas el flujo de espejo pre-traducido, verbaly render corre solo después de cada build.
Qué puedes lograr:
- Escribe tu texto directamente en archivos
.astro, frontmatter y markup: claves, tipos y catálogos se mantienen en sincronía mientras programas - Publica cada idioma como páginas estáticas, con dos flujos para elegir
- En el flujo de espejo,
verbaly rendercorre solo después de cada build: páginas pre-traducidas, hreflang y un sitemap por idioma sin pasos extra - Un build que lista las traducciones que faltan, el mismo informe que en cualquier otro setup de Verbaly
Instalación
Instala el paquete con tu gestor de paquetes preferido.
pnpm add verbaly @verbaly/astroConéctalo
import { defineConfig } from 'astro/config';
import verbaly from '@verbaly/astro';
export default defineConfig({
integrations: [verbaly()],
});Esa única línea inyecta el plugin de Vite con la raíz de tu proyecto fijada: extracción en vivo mientras programas, el módulo tipado virtual:verbaly y el reporte del build. Los tipos generados viven dentro de la carpeta .astro propia de Astro, y npx verbaly extract escribe ese mismo fichero, así que no se añade ninguno a tu proyecto. Las opciones son las mismas del plugin de Vite (locales, sourceLocale, dir, failOnMissing…), inline o en tu verbaly.config.
Escribe el texto en su lugar
---
import { createRequestInstance } from 'virtual:verbaly';
const { t } = await createRequestInstance('en');
const title = t`Search and find`;
---
<h1>{title}</h1>
<p>{t`Hello ${name}, you have ${count} messages`}</p>
<img alt={t`Company logo`} src="/logo.png" />El compilador lee tus archivos .astro como cualquier otro fuente. El frontmatter y las expresiones del markup se extraen los dos, cada mensaje se vuelve una clave estable con params tipados, y una entrada sin traducir la lista cada build y hace fallar verbaly check antes de que salga.
Dos formas de publicar los idiomas
Los sitios Astro son estáticos por defecto, así que el idioma se decide al momento del build. Elige el flujo que calce con tu routing:
Páginas por ruta
Si el routing i18n de Astro es dueño de tus URLs (/es/…, /pt/…), construye una instancia por request y usa t como siempre. Astro es dueño de las rutas, Verbaly de los catálogos y de la seguridad de tipos. createRequestInstance espera al catálogo antes de devolver, que es lo que hace que la página llegue traducida en vez de parpadear, y Astro.currentLocale viene vacío fuera de una ruta con idioma, así que el fallback no es decoración.
---
import { createRequestInstance, sourceLocale } from 'virtual:verbaly';
const { t } = await createRequestInstance(Astro.currentLocale ?? sourceLocale);
---Modo espejo
Un solo árbol de páginas, pre-traducido en todos los idiomas. Bindea tu markup con atributos data-verbaly y añade una sección render a tu config. Después de astro build, la integración espeja el sitio en dist/es/, dist/pt/… con cada mensaje ya relleno, más los alternates de hreflang y un sitemap por idioma cuando pones baseUrl. Sin parpadeo de texto sin traducir y sin trabajo en el cliente.
export default {
locales: ['en', 'es', 'pt'],
render: { baseUrl: 'https://example.com', sitemap: true },
};El sitemap lleva las páginas que un buscador debería indexar. Tus redirecciones y tu 404 se quedan fuera, porque lo dicen ellas mismas, y se siguen mirroreando a todos los idiomas para que quien llegue a una la reciba ahí. Deja fuera más con render.exclude.
Un sitio con mirror puede ir más lejos: el texto que solo enseña una página no necesita llegar al navegador, porque el mirror ya lo escribió en el HTML. Nombra esos grupos bajo bundle y el resto de páginas dejan de descargarlos.
export default {
locales: ['en', 'es', 'pt'],
bundle: { exclude: ['changelog'] },
render: { baseUrl: 'https://example.com', sitemap: true },
};Cada página trae solo sus palabras
Una página del mirror llega ya traducida y, aun así, el visitante se descarga todos los mensajes de ese idioma, la mayoría de los cuales esa página no muestra nunca. Enciende inlineCatalog y el mirror escribe en cada página exactamente los mensajes que renderiza, así que una página traducida no necesita catálogo propio.
export default {
locales: ['en', 'es', 'pt'],
render: { baseUrl: 'https://example.com', inlineCatalog: true },
};En este sitio los mensajes en español pesan unos 59 KB comprimidos. La home usa 3 KB de ellos, así que una primera visita deja de bajarse unos 56 KB, nueve veces lo que pesa aquí el runtime entero de Verbaly. La página más pesada es la de novedades, y hasta esa se ahorra 26 KB.
Si tu página pide después un mensaje que no mostró, Verbaly se trae el resto una vez y actualiza, en vez de enseñar tu idioma de origen sin decir nada. Tus páginas en el idioma de origen no reciben nada extra: sus mensajes ya viajan con la app.
Con <ClientRouter /> esto sigue funcionando mientras el visitante navega, y tú no escribes nada: la integración le pasa al runtime los mensajes de cada página en el momento en que esa página entra.