Skip to content

Consume translations

View .md

Every deployed bundle is a flat JSON map for one (language, namespace) pair, so any runtime can read it. Fetch it from the CDN at runtime, or pull it into your repository at build time.

https://cdn.comvi.io/<project-token>/<language>.json # default namespace
https://cdn.comvi.io/<project-token>/<namespace>/<language>.json # any other namespace
https://cdn.comvi.io/<project-token>/en.json
{
"greeting": "Hello, {name}!",
"welcome_message": "Welcome to our application",
"nav.home": "Home",
"nav.settings": "Settings"
}

The full endpoint URL, token included, is under Settings → Content Deploy with a copy button. Bundles hold only the values that match the Filter by Status setting on that page; the filter is empty by default, and empty deploys every status, drafts included. See CDN settings.

Approach How it works Best for
Runtime fetch (CDN) The app downloads a bundle at startup or on demand Web apps, anything that wants wording changes without a redeploy
Build-time bundle (CLI or export) You pull translations into the repo and ship them with the app Mobile, embedded and offline apps, anywhere with no runtime dependency on Comvi

Mixing works too: bundle a fallback set at build time and fetch updates at runtime.

src/i18n.ts
import { createI18n } from '@comvi/core';
import { cdnLoader } from '@comvi/plugin-fetch-loader';
export const i18n = createI18n({
locale: 'en',
fallbackLocale: 'en',
}).use(cdnLoader({ cdnUrl: 'https://cdn.comvi.io/<project-token>' }));

The Comvi i18n library loads one bundle per namespace and language and switches locale at runtime. cdnUrl is required and has no default or environment override; omitting it throws before init() runs. See the fetch loader options and Connect your app for the framework bindings.

Point your library’s resource loader at the bundle URL and keep its rendering, plural and interpolation behaviour. No adapter is needed: the bundle is plain JSON. For a small app, fetch alone is enough, with caching, language switching and interpolation left to you:

src/main.ts
const bundle = await fetch('https://cdn.comvi.io/<project-token>/en.json').then((r) =>
r.json(),
);
document.querySelector('h1')!.textContent = bundle.welcome_message;
Terminal
npx --package @comvi/cli comvi pull

comvi pull writes the project’s translations to your filesystem. It needs a project-scoped API key in COMVI_API_KEY and a .comvirc.json in the repo with the output directory and file layout; the project comes from the key, so there is no project field. Run it in local dev, CI or the release pipeline, and commit the output or let CI fetch it on every build. CLI pull covers the file layout, the locale and namespace filters, and --empty-dir; comvi typegen generates the TypeScript types.

When the pipeline is not Node.js, download a ZIP of all translations from the Export page. Exports are JSON or an i18next v4 compatible shape, readable from any language. Native mobile formats (iOS .strings, Android XML) are not supported, and XLIFF 1.2, XLIFF 2.0, CSV and PO (Gettext) are listed as coming soon, so consume the JSON directly or convert it in your build step. For another format, email hello@comvi.io.

  • Runtime CDN fetch. A deploy propagates at the edge in a few seconds, and files carry a 30-second cache lifetime, so the app picks up changes on the next page load, refresh interval or user action.
  • Build-time bundle. A change needs a new build. Subscribe to webhooks on translation.created, translation.updated and translation.batch_updated (the bulk event for MT and TM apply) to trigger CI, and add key.* for source-key changes. Debounce on the CI side: single edits fan out one event per value, a bulk operation emits one translation.batch_updated.

Contributors who need to preview edits before a deploy can use the In-Context Editor plugin, which shows authorized editors their drafts in the live app.