Keys are never split — each one is stored and looked up literally. Choose this when your keys contain dots or are natural text: versions, prices, filenames, scripture or legal references. App Version 6.3.8 stays exactly that.
Guide · Key nesting
Flat vs nested keys
By default Verbumia splits your keys on . into a nested JSON tree in the CDN bundle — the classic i18next shape. That is perfect for organised keys like checkout.review.confirm, but it silently mangles keys whose text contains a dot. This guide covers the project setting and the matching SDK option so your lookups always resolve.
The dotted-key trap
A key is just a string. When that string contains a literal dot — a version like App Version 6.3.8, a price, a filename, a scripture reference like Jean 3.16 — splitting on . turns one key into an accidental nested object. The translation is still stored, but t("App Version 6.3.8") no longer finds it.
bundle.json 1// your source key — a literal label with dots in it2{ "App Version 6.3.8": "App Version 6.3.8" } 4// nested bundle (default) — split on "." → broken tree5{ "App Version 6": { "3": { "8": "App Version 6.3.8" } } } 7// flat bundle — the key stays literal, lookups just work8{ "App Version 6.3.8": "App Version 6.3.8" } The project setting
Two project-level settings control how the CDN bundle is shaped. The defaults reproduce the current i18next behaviour, so existing projects are unaffected until you opt in.
| Setting | Values | Default |
|---|---|---|
| bundle_key_style | nested | flat | nested |
| bundle_key_separator | string | "." |
Set them on the project — in your dashboard's project settings, or via the projects API. The chosen style is baked into every release, and every published version reports it back, so any client can self-configure.
versions/main 1# the version object reports the active key style2GET /v1/projects/<project_uuid>/versions/main 4{ "slug": "main", "key_style": "flat", "key_separator": "." } Choosing flat or nested
Keys are split on the separator into a JSON tree — the classic i18next layout. Choose this for deliberately namespaced keys like checkout.review.confirm. This is the default.
Match it in the SDK
@verbumia/react-i18next (>= 0.11.0) takes a keySeparator option: false for literal / flat lookups, a string for nested, default ".". There is also nsSeparator (default ":"). The SDK is literal-first — it tries an exact bundle[key] match before any splitting, so dotted keys resolve even in nested mode. On start() it also auto-detects key_style / key_separator from the published version (best-effort).
main.tsx 1// src/main.tsx — match the bundle in @verbumia/react-i18next >= 0.11.02import { VerbumiaProvider } from "@verbumia/react-i18next"; 4<VerbumiaProvider5 projectId="<project_uuid>"6 apiKey={import.meta.env.VITE_VERBUMIA_KEY}7 keySeparator={false} // literal lookup — for dotted / natural-text keys8 nsSeparator=":" // default; set false to disable ns parsing too9>10 <App />11</VerbumiaProvider> 13// then t() treats the whole string as one key — no splitting14t("App Version 6.3.8"); // ✓ exact match Auto-detection reads the version metadata and needs a key with project:read. If that read is denied (403) the SDK falls back gracefully to its defaults — so when in doubt, set keySeparator explicitly to match your bundle rather than relying on detection.
Recommendation
- Keys contain dots? Set
bundle_key_style: flaton the project andkeySeparator={false}in the SDK. Both ends literal — no surprises. - Cleanly namespaced keys (
checkout.review.confirm)? Keep the nested default; nothing to change. - Migrating an existing app? The defaults preserve your current behaviour. Flip to flat only when you hit a dotted key, then re-publish and update the SDK option together.