Skip to content

Consume Translations

Once you’ve published translations, any app can consume them. Comvi is deliberately unopinionated about how you load them — pick the shape that fits your runtime and deployment model.

This page covers the two production-grade approaches and when to choose each.

ApproachHow it worksBest for
Runtime fetch (CDN)Your app downloads a bundle from the CDN at startup or on demandWeb apps, apps that want translation updates without a redeploy
Build-time bundle (CLI / export)You pull translations into your repo and ship them with your appMobile apps, embedded/offline apps, anywhere you want zero runtime dependency on Comvi

You can also mix: bundle a fallback set at build time and fetch updates at runtime.

Every published bundle is plain JSON — a flat map of keys to values for one (language, namespace) pair:

{
"greeting": "Hello, {name}!",
"welcome_message": "Welcome to our application",
"nav.home": "Home",
"nav.settings": "Settings"
}

URLs follow a predictable shape:

https://cdn.comvi.io/<distribution-token>/<namespace>/<language>.json
# the default namespace is served at the project root:
https://cdn.comvi.io/<distribution-token>/<language>.json

The distribution token is project-scoped and lives under Settings → Content Deploy. See CDN Deployment for the full URL format.

Because the format is plain JSON, any i18n library that accepts a JSON resource can consume it. You can also load it by hand with fetch if you don’t want a library at all.

Our i18n library is the path of least resistance for web apps. Install the core package plus a framework binding, add the fetch loader plugin, and point it at your distribution URL.

The library handles:

  • Loading bundles on demand (per namespace, per language)
  • ICU MessageFormat rendering (plurals, selects, placeholders)
  • Language switching at runtime
  • Optional TypeScript types for autocompleted keys
  • Server-side rendering for Next.js, Nuxt, and similar frameworks

See the i18n library quick start for framework-specific setup.

Bundles are standard JSON, so any existing i18n stack can consume them. Point the library’s resource loader at your Comvi CDN URL — no adapter needed.

Typical shape:

  1. Configure your i18n library to load resources from a URL pattern (the library will have its own way to specify this)
  2. Plug in https://cdn.comvi.io/<distribution-token>/<namespace>/<lang>.json (or https://cdn.comvi.io/<distribution-token>/<lang>.json for the default namespace) as the URL
  3. Keep your existing rendering / plural / interpolation behaviour

If you are migrating from another i18n library, start with the closest framework guide in the i18n library docs.

For a small app, plain fetch is enough:

const bundle = await fetch(
'https://cdn.comvi.io/YOUR_DISTRIBUTION_TOKEN/en.json',
).then((r) => r.json());
document.querySelector('h1')!.textContent = bundle.welcome_message;

Caching, language switching, and interpolation become your responsibility — pick this only if your needs are genuinely that simple.

When you want zero runtime dependency on Comvi — mobile apps, offline-first apps, static sites without client-side JS — pull translations into your repo at build time and ship them with the binary / bundle.

The Comvi CLI has a pull command that fetches translations from the platform and writes them to your filesystem.

Terminal window
npx @comvi/cli pull

Typical setup:

  1. Create a project-scoped API key
  2. Add a .comvirc.json in your repo pointing at the project and output directory
  3. Run comvi pull in your build step (local dev, CI, release pipeline)
  4. Commit the output or let CI fetch it on every build

See CLI pull for configuration options, output format choices, and typed output for TypeScript projects.

If the CLI is overkill — for example, if your build pipeline isn’t Node.js — use the Import & Export UI to download a ZIP of all translations. Exports are served as JSON (default) or an i18next-v4 compatible shape. Any language can read JSON, so this works for backend services, desktop apps, static site generators, or any pipeline where Node.js tooling isn’t available.

Translations change more often than code. How each approach handles updates:

  • Runtime CDN fetch — updates appear on the next fetch after the editor clicks Publish. Typical propagation is a few seconds at the edge; your app sees them on next page load / i18n library refresh interval / user action.
  • Build-time bundle — updates require a new build and deploy of your app. Subscribe to webhooks to trigger CI automatically. For content changes the relevant events are translation.created, translation.updated, and translation.batch_updated (bulk operations like MT or TM apply). Add key.* if you want rebuilds on source-key changes too. Debounce on the CI side — individual edits fan out one event per value, while a bulk operation emits a single translation.batch_updated.

For contributors who need to preview edits before publishing, see the In-Context Editor plugin — authorized editors see their drafts instantly in your live app without going through the publish cycle.