Reference
Configuration
One file at the root of your project, and the plugin takes the same object, so a setting means the same thing to your build and to the command line. Flags win over the file.
export default {
sourceLocale: 'es',
locales: ['es', 'en', 'pt'],
};Accepted names are verbaly.config.js, .mjs, .ts, .mts and .json, read in that order. A TypeScript config needs esbuild installed, and the tool says so if it is missing.
Every option
| Option | Default | What it does |
|---|---|---|
sourceLocale | 'en' | The language you write in |
locales | The catalog files it finds | Your languages. List them and the list is complete; leave it out and every JSON file in dir counts as one |
dir | 'locales' | Where the catalogs live |
root | Where you ran the command | The project root every other path is resolved against |
include | src/**, app/** | Which files are scanned for messages and compiled. A file outside it that writes t`…` is named, with the pattern to add, when your build or dev server starts. [] turns scanning off, for a project whose catalogs are written by hand |
exclude | node_modules, dist | Which files are skipped inside that |
routing | Follows your setup | Where the language lives in your addresses. See URL strategy |
dts | Where your framework reads them | Where the generated types are written, or false to write none. Left out, they go to src/verbaly.d.ts (the root without a src/), to .verbaly/types.d.ts in Next.js, which Verbaly adds to your tsconfig.json, and to the types folder Astro and Nuxt keep for this |
bundle | Nothing excluded | exclude: groups of messages that stay in the build and never reach the browser |
render | Off | The pre-translated mirror for static sites. Its own options are below |
translate | Claude | Everything machine translation needs beyond the provider: model, batch size, glossary, instructions |
icu | Your catalogs decide | Forces the ICU parser to ship. Only for messages that reach your app after the build |
relative | Your catalogs decide | The same, for relative time formatting |
Inside render
Only for static sites that publish one address tree per language. Adding this section is what switches the mirror on.
| Option | What it does |
|---|---|
baseUrl | Your public address. Alternates and the sitemap need it |
site | The built directory to mirror. Defaults to dist |
sitemap | Writes a per-language sitemap. A string names the file |
exclude | Pages to leave out of that sitemap, by path inside the build directory |
hreflang | Reciprocal alternates on every page. On by default |
redirect | Sends a first-time visitor to their language before the page paints |
links | The real addresses behind named links inside your messages |
base | The path prefix, if your site is not served from the root |
attribute | The attribute to look for, if you renamed data-verbaly |
inlineCatalog | Writes into each page the messages it renders, so a translated page downloads no catalog of its own |
clean | Drops language pages left over from an earlier build |
Inside translate
Everything machine translation needs beyond the provider, so a run behaves the same for everyone on the project instead of depending on who typed the command.
| Option | What it does |
|---|---|
provider | Who does the translating. 'claude' is the one that ships; give it a function instead and it is yours, with no lock-in |
model | Which model the built-in provider uses. --model overrides it for one run |
batchSize | How many messages go in one request, 20 by default. Lower it if long messages get cut off, raise it for short ones |
concurrency | How many requests are in flight at once, 4 by default. Lower it if your provider rate limits you |
retries | How many times a request that fails for a passing reason is tried again, 2 by default |
instructions | Anything you would tell a human translator about your product: how formal to be, how short a button label has to stay, what your app is |
glossary | How a term has to come out. Give one wording for every language, which is how you say leave this alone, or one per language. Only the terms a batch actually contains are sent |
A run survives a bad connection. Requests that fail for a passing reason are tried again, and if one still does not come back, everything else is written and the report names the messages it could not fill. Running translate again asks only for those, so a dropped connection never costs you the whole run twice. The command exits 1 when that happens, so a script notices.
Only in the plugin
failOnMissing: true stops a build on whatever fails verbaly check, for a project that deploys without CI. Without it, a build lists missing, broken and unknown keys and finishes: a missing translation falls back to your source language, and check in CI is the gate.