# Consume translations

Load deployed translations into any app: fetch the JSON bundles from the CDN at runtime, or bundle them at build time with the CLI or an export.

Canonical: https://comvi.io/docs/platform/consume-translations

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.

```text
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`

```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](/docs/platform/cdn#cdn-settings).

> **Production reads go to the CDN, not the REST API**
>
> The [REST API](/docs/api) is rate-limited and exists for authoring, automation and dev
> tooling. Read translations in production from the CDN or from a build-time bundle.

## Choose an approach

| 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.

## Fetch at runtime with Comvi i18n

`src/i18n.ts`

```ts

export const i18n = createI18n({
locale: 'en',
fallbackLocale: 'en',
}).use(cdnLoader({ cdnUrl: 'https://cdn.comvi.io/<project-token>' }));
```

The [Comvi i18n library](/docs/i18n/quick-start) 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](/docs/i18n/plugins/fetch-loader#options) and
[Connect your app](/docs/i18n/connect-comvi) for the framework bindings.

## Fetch at runtime with another library

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`

```ts
const bundle = await fetch('https://cdn.comvi.io/<project-token>/en.json').then((r) =>
r.json(),
);

document.querySelector('h1')!.textContent = bundle.welcome_message;
```

## Bundle at build time with the CLI

`Terminal`

```bash
npx --package @comvi/cli comvi pull
```

`comvi pull` writes the project's translations to your filesystem. It needs a project-scoped
[API key](/docs/platform/api-keys) 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](/docs/cli/pull) covers the file layout, the locale and
namespace filters, and `--empty-dir`; [comvi typegen](/docs/cli/typegen) generates the
TypeScript types.

## Bundle at build time with an export

When the pipeline is not Node.js, download a ZIP of all translations from the
[Export](/docs/platform/import-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](mailto:hello@comvi.io).

## Keep translations fresh

- **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](/docs/platform/integrations/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](/docs/i18n/plugins/in-context-editor), which shows authorized
editors their drafts in the live app.

## Next steps

- [Quick start](/docs/i18n/quick-start): Set up the Comvi i18n library in a web app.
- [CLI pull](/docs/cli/pull): Bundle translations into your repo at build time.
- [Content Deploy / CDN](/docs/platform/cdn): How deploys, bundles and cache invalidation work.
- [Webhooks](/docs/platform/integrations/webhooks): Trigger CI when translations change.
