Internationalization
Locale catalogs are JSON files compiled into the binary; lookup, plurals, and locale negotiation are framework calls.
Catalogs
Put <locale>.json files in i18n/ (or point -Di18n-dir elsewhere):
{ "greeting": "Hello", "items.one": "{n} item", "items.other": "{n} items" }zig build run -Di18n-dir=i18n -Di18n-default=enLookup
// Static catalog
const text = catalog.lookup("de", "greeting");
// missing key → default locale → key literal (never crashes a render)
// Lazy catalog: JSON parsed on first lookup per locale, cached after
var lazy = verve.LazyCatalog.init(&.{
.{ .tag = "en", .json = @embedFile("../i18n/en.json") },
.{ .tag = "de", .json = @embedFile("../i18n/de.json") },
}, "en", gpa);Locale negotiation
const locale = verve.resolveLocale(catalog, ctx.request_meta, ctx.location, ctx.alloc());Resolution order: lang cookie → ?lang= query → Accept-Language header → catalog default. Stick the result in a layout and pass it to every lookup.
Plurals
CLDR plural categories (zero/one/two/few/many/other) with {n} substitution:
const label = try verve.tPlural(catalog, locale, "items", count, ctx.alloc());
// keys: items.one, items.other (plus zero/two/few/many where the language needs them)verve.pluralCategory(locale, n) exposes the raw category when you need custom logic.
Right-to-left
verve.isRtl(locale) // true for ar, he, fa, ur, …
verve.dir(locale) // "rtl" | "ltr" — stamp on <html dir=…>Next: State.