@verbaly/vue

Vue 3 bindings for Verbaly: composables over the reactive core.
12,551 4
Install
npm install @verbaly/vue
Latest Version:0.75.0
Vue:3
License:MIT
Last Updated:Oct 20, 2026
Links: GitHub  ·  npm
Maintainer: aronchino

Vue 3 composables for Verbaly: a thin layer over the reactive core with per-component cleanup (onScopeDispose).

🚀 Install

pnpm add verbaly @verbaly/vue
// main.ts
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>

The plugin is optional in the browser. With none above it, a hook reads the instance virtual:verbaly creates, so a single-page app can skip it and a component test renders with no wrapper. On a server it is required, since every request has its own instance.

Keys are typed. useT() checks every key and its params against your source catalog, through the types Verbaly generates (src/verbaly.d.ts in a Vite app, .nuxt/verbaly.d.ts in Nuxt): a key no catalog has does not compile. A key that comes from data, like t(item.key) or a variable typed as a union of keys, passes as it is, and its params are left open; declare it with defineKeys from virtual:verbaly when you want check to verify it exists.

Or skip the keys entirely: write the source text in place and the compiler extracts it, right in your .vue files (script and template):

<template>
  <p>{{ t`Hello ${name}, you have ${count} messages` }}</p>
</template>

✨ Rich text: <Trans>

<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>

Whitelisted phrasing tags in a message (<em>, <code>…) render as real elements, same whitelist as data-verbaly-rich (richTags overrides it); unknown tags unwrap to inert text. Named links need no render functions; hrefs come from your code, never from messages (javascript: blocked):

<!-- message: 'Read the <docs>guide</docs>' -->
<Trans id="cta" :links="{ docs: { href: '/docs', target: '_blank', rel: 'noopener' } }" />

📖 Docs: https://verbaly-web.vercel.app/docs/frameworks/vue

⚠️ Early development (0.x): API not stable yet.

License

MIT © Aron Soto

Related Packages

@verbaly/nuxt

Nuxt integration for Verbaly: zero-config module with per-request locale negotia...

8,706 4
@vintl/vintl

Integrate @formatjs/intl into your Vue apps for easier internationalisation

10,663 5
@makemepulse/tool-i18n

Handle locales with Google Spreadsheet and vue-i18n plugin

5,419 0
vite-plugin-vue-viai18n

i18n transform plugin for vite/vue which can generate message key automatically

2,940 0

Version History

Version Released License
0.75.0 MIT
0.74.0 MIT
0.73.0 MIT
0.72.0 MIT
0.71.0 MIT