Integraciones
Vue
El paquete oficial de Vue 3 para Verbaly. Composables con limpieza automática, un componente <Trans> para rich text, y claves + params totalmente tipados.
Qué puedes lograr:
- Traduce con composables (useT, useLocale) que reaccionan a cada cambio de idioma
- Enlaza el idioma directo a un select:
useLocale()devuelve un computed escribible - Mantén claves y params totalmente tipados, con autocompletado desde tus propios mensajes
- Cero fugas: las suscripciones son por componente y se limpian vía
onScopeDispose
Instalación
Instala el paquete con tu gestor de paquetes preferido.
pnpm add @verbaly/vueSetup y composables
import { verbalyPlugin } from '@verbaly/vue';
import { verbaly } from 'virtual:verbaly';
app.use(verbalyPlugin(verbaly));<script setup>
import { useT, useLocale } from '@verbaly/vue';
const t = useT();
const locale = useLocale(); // writable: locale.value = 'en'
</script>
<template>
<p>{{ t('inbox', { count: 3 }) }}</p>
</template>- Las suscripciones son por componente y se limpian al desmontar vía
onScopeDispose. useLocale()devuelve un computed escribible, así que conéctalo directo a un select.- ¿Sin el plugin instalado, en el navegador?
useT()yuseLocale()leen la instancia que creavirtual:verbaly, así que un test de componente no necesita preparación. En el servidor el plugin es obligatorio, porque cada petición tiene su propia instancia.
Escribe el texto en su lugar
El compilador también lee tus archivos .vue: escribe el texto fuente en una interpolación, en un binding de directiva o en script setup, y se extrae, recibe su clave y sus tipos al guardar. El texto que solo se muestra nunca se extrae, así que una página puede enseñar t`…` como ejemplo sin riesgo. Sin inventar claves, sin tocar catálogos.
<template>
<p>{{ t`Hola ${user.name}` }}</p>
<a :title="t`Abrir ajustes`">…</a>
</template>
<!-- extracted on save; the build rewrites both to t('key', …) -->¿Prefieres claves legibles? t.id('inbox.title') antes del template extrae bajo tu id en vez de un hash del contenido.
Rich text con <Trans>
La misma idea; en Vue cada tag nombrado es una render function que envuelve a sus hijos:
<script setup>
import { Trans } from '@verbaly/vue';
import { h } from 'vue';
const components = { terms: (c) => h('a', { href: '/terms' }, c) };
</script>
<template>
<Trans id='agree' :components='components' />
</template>Para links simples olvídate de la render function: el prop links mapea nombres de tag a hrefs (un string o un objeto href/target/rel). components gana con el mismo nombre; los hrefs javascript: se bloquean.
Las etiquetas de la whitelist (<em>, <code>…) se renderizan como elementos de verdad, sin necesidad de una render function: la misma whitelist segura que usa el intérprete del DOM. richTags la sobrescribe, y la prop instance renderiza sin el plugin.
Nuxt
Las páginas renderizadas en el servidor llegan ya traducidas al idioma del visitante, y el cliente hidrata con el mismo locale y el mismo catálogo, sin flash de texto sin traducir ni mismatch de hidratación.
- Cada página se renderiza en el idioma del visitante, tomado de la dirección cuando la lleva, y si no de su elección guardada o del header
Accept-Language - Sin flash de texto sin traducir: el HTML que envía el servidor y la página ya hidratada son idénticos, catálogo incluido
- Cada request tiene su propia instancia, así que dos visitantes simultáneos nunca ven el idioma del otro
- Cero cableado: una sola entrada de módulo reemplaza el setup del plugin de Vite, la negociación y la sincronización de los atributos
langydir
Nuxt necesita el módulo (@verbaly/nuxt) junto a los bindings de Vue:
pnpm add verbaly @verbaly/nuxt @verbaly/vueConéctalo
Una línea en nuxt.config. El módulo conecta el plugin de Vite (extracción viva y virtual:verbaly), elige el locale por request y mantiene los atributos lang y dir en sincronía. Si tus direcciones llevan el idioma, las lee él solo y no hay nada más que escribir:
export default defineNuxtConfig({
modules: ['@verbaly/nuxt'],
});
// locales live in your verbaly.config (npx verbaly init), or inline:
export default defineNuxtConfig({
modules: [['@verbaly/nuxt', { locales: ['en', 'es', 'pt'] }]],
});De aquí en adelante es @verbaly/vue normal: useT() / useLocale() y <Trans> funcionan sin cambios en cada componente.
useT() está tipado por tu catálogo: los tipos van a .nuxt/verbaly.d.ts, donde Nuxt los enlaza, y npx verbaly extract escribe ese mismo fichero. Una clave que ningún catálogo tiene hace fallar nuxi typecheck.
Cambiar de idioma
switchLocale (export del core) carga el catálogo primero, cambia en vivo y escribe la cookie que el servidor lee, así el próximo request SSR ya coincide:
<script setup>
import { switchLocale } from 'verbaly';
import { useVerbaly } from '@verbaly/vue';
const verbaly = useVerbaly();
</script>
<template>
<button @click="switchLocale(verbaly, 'es')">Español</button>
</template>- La cookie por defecto es
verbaly-locale(la misma identidad que la key de storage del core);cookie: falseen las opciones del módulo la desactiva, paraAccept-Languagepuro. fallbackpor defecto es tu locale fuente; la negociación entiende q-values y estrecha regiones (es-PEmatcheaes).ssr: falsetambién está cubierto: el módulo resuelve el locale en el navegador, leyendo primero la dirección cuando lleva el idioma, luego la cookie, luegonavigator.languages, luego tu fallback.- Sin dependencia de Nuxt en sí: el módulo está tipado estructuralmente, sin
@nuxt/kit. La claveverbalyennuxt.config.tsqueda totalmente tipada (autocompletado y detección de errores de tipeo), y se mantiene compatible con Nuxt 4. - ¿Sitio totalmente estático (
nuxi generate)? Prefiere salida pre-traducida por locale con verbaly render.