Guides
Server-side
The core runs anywhere JavaScript does, including Node. Create an instance, pass the locale, call t(). No DOM required.
One instance per request
Build a fresh instance per request and hand it the visitor's locale. negotiateLocale reads the Accept-Language header and picks the best match among your locales (it understands quality values, and es-PE matches es). resolveRequestLocale makes the whole decision in one call: the address first when it carries the language, then the saved choice, then the browser, then your fallback. Instances don't share state, so two requests never mix their languages.
import { createVerbaly, negotiateLocale } from 'verbaly';
import es from './locales/es.json';
import en from './locales/en.json';
function handle(req) {
const locale = negotiateLocale(req.headers['accept-language'], ['en', 'es']);
const v = createVerbaly({ locale, fallback: 'en', messages: { en, es } });
return v.t('home.title');
}When your addresses carry the language
If your pages live at /es/dashboard, that address is the answer. Anyone who opens the link gets Spanish, whether or not they ever picked a language here, because an address is public and shared while a saved choice belongs to one person. A page without a prefix then means your source language, so a visitor who once chose Spanish never sees your English pages translated by accident.
You switch this on by telling your integration the routing you already set. Here is the whole of it, per stack:
| Stack | What you write |
|---|---|
| SvelteKit | Pass routing to verbalyHandle, and add verbalyReroute in hooks.ts so one route tree serves every language |
| Nuxt | Nothing: the module reads the address for you |
| Next.js | routing: 'prefix-all' in your config, and setRequestLocale(locale) in your [locale] layout, before anything asks for text |
| Astro | createRequestInstance(Astro.currentLocale ?? sourceLocale) in the page |
Your pages can also point search engines at each other. alternateLinks gives you the list of addresses for one page in every language, the same list a statically rendered site gets, so a server-rendered page is not a second-class citizen. See URL strategy.
Render HTML ahead of time
For static sites, verbaly render pre-fills your built HTML per locale so pages ship already translated. See CLI → Static rendering.
Meta-frameworks
On SvelteKit, Nuxt and Next.js you do not wire any of this by hand. The SvelteKit integration, the Nuxt module and the Next.js integration pick the language per request and hydrate without a flash, all on these same primitives.