Framework

Vue

The official Vue 3 package for Verbaly. Composables with automatic cleanup, a <Trans> component for rich text, and keys + params fully typed.

What you can accomplish:

Installation

Install the package with your preferred package manager.

 pnpm add @verbaly/vue

Setup & composables

main.ts
import { verbalyPlugin } from '@verbaly/vue';
import { verbaly } from 'virtual:verbaly';

app.use(verbalyPlugin(verbaly));
Inbox.vue
<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>

Write the text in place

Since 0.20.0 the compiler reads your .vue files too: write the source text in the template, in a binding or in script setup, and it is extracted, keyed and typed on save. No key to invent, no catalog to touch.

Inbox.vue
<template>
  <p>{{ t`Hola ${user.name}` }}</p>
  <a :title="t`Abrir ajustes`">…</a>
</template>

<!-- extracted on save; the build rewrites both to t('key', …) -->

Prefer readable keys? t.id('inbox.title') before the template extracts under your id instead of a content hash.

Rich text with <Trans>

Same idea; in Vue each named tag is a render function that wraps its children:

Agree.vue
<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>

For plain links skip the render function: the links prop (0.11.0) maps tag names to hrefs (a string or an href/target/rel object). components wins on the same name; javascript: hrefs are blocked.

Since 0.23.0 whitelisted tags (<em>, <code>…) render as real elements with no render function needed, the same safe whitelist as the DOM interpreter; richTags overrides it, and the instance prop renders without the plugin.

Nuxt

Server-rendered pages arrive already translated in the visitor's language, and the client hydrates with the same locale and catalog: no flash of untranslated text, no hydration mismatch.

Nuxt needs the module (@verbaly/nuxt) alongside the Vue bindings:

 pnpm add verbaly @verbaly/nuxt @verbaly/vue

Wire it up

One line in nuxt.config. The module wires the Vite plugin (live extraction and virtual:verbaly), negotiates the locale per request and keeps the lang attribute in sync:

nuxt.config.ts
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'] }]],
});

From here it's plain @verbaly/vue: useT() / useLocale() and <Trans> work unchanged in every component.

Switching languages

switchLocale (a core export since 0.18.0) loads the catalog first, switches live, then writes the cookie the server reads, so the next SSR request already matches:

LangPicker.vue
<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>
Copied to clipboard