Skip to content

CI/CD Integration

Comvi’s CDN serves translations at runtime, so CI rarely needs to bundle them. But CI is still where you want to run pre-flight checks: key coverage, ICU validation, and — if you use a build-time bundle or a staging-to-prod promotion — the actual sync step.

StepWhyFrequency
Pull translationsSeed or refresh a local copy (only if you bundle at build time — not needed for runtime CDN reads)Every build
Push new keysDeveloper added checkout.new_banner; ensure it exists in ComviOn PR merge
Run type generationKeep Translations TS type in sync with keysEvery build
Promote staging → productionPublish approved drafts to the prod CDNOn release tag

Most apps need only push new keys + type generation. The rest depend on your setup.

  1. Create a CI-specific API key

    In API Keys, create a key named github-actions-ci (or equivalent) with the minimum permissions your pipeline needs:

    • Read-only CI: project:read, translations:read, schema:read
    • Push-new-keys CI: add translations:write

    Set an expiration (6–12 months). Rotate on schedule.

  2. Store the key as a CI secret

    • GitHub: Settings → Secrets and variables → ActionsCOMVI_API_KEY
    • GitLab: Settings → CI/CD → VariablesCOMVI_API_KEY (mark as masked)
  3. Add a .comvirc.json to your repo (committable; the key is in the env)

    {
    "apiBaseUrl": "https://api.comvi.io",
    "translationsPath": "./src/locales",
    "fileTemplate": "{languageTag}/{namespace}.json",
    "format": "json"
    }
  4. Wire the CLI into your workflow

    See the examples below.

name: Sync translation keys
on:
push:
branches: [main]
jobs:
push-keys:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 24 }
- run: npm ci
- name: Extract and push keys
run: npx @comvi/cli push --dry-run
env:
COMVI_API_KEY: ${{ secrets.COMVI_API_KEY }}
- run: npx @comvi/cli push
env:
COMVI_API_KEY: ${{ secrets.COMVI_API_KEY }}

The CLI scans your source code for t('...') calls, diffs against Comvi, and creates missing keys. Deletions are not automatic — run the CLI locally with --prune to clean up unused keys after a refactor.

- name: Generate translation types
run: npx @comvi/cli typegen
env:
COMVI_API_KEY: ${{ secrets.COMVI_API_KEY }}
- run: npm run build

This pulls the current key set and writes Translations types into your source tree. Check the result into git or regenerate on every build — see CLI typegen.

For the two-project pattern from Staging → Production:

name: Promote translations to production
on:
release:
types: [published]
jobs:
promote:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 24 }
- name: Pull from staging
run: npx comvi pull --path ./promote
env:
COMVI_API_KEY: ${{ secrets.COMVI_STAGING_KEY }}
- name: Push to production
run: npx comvi push --path ./promote --force-mode keep
env:
COMVI_API_KEY: ${{ secrets.COMVI_PROD_KEY }}

The API key determines the source or destination project. --force-mode keep avoids overwriting existing production translations during promotion.

Fail the build if any language drops below a threshold — e.g., “production languages must be ≥95% translated”. Query via the REST API:

Terminal window
curl -H "X-API-Key: $COMVI_API_KEY" \
"https://api.comvi.io/api/v1/projects/$PROJECT_ID/stats" \
| jq '.languages[] | select(.code == "de") | .translated_ratio'

If the value is below your threshold, exit 1 in the CI script. This catches “we forgot to translate the new feature” before release.

The editor already rejects broken ICU, but if you import translations from files, run comvi pull --validate in CI. A placeholder mismatch fails the build.

Two ways to react to translation changes:

  • Pull on build — simple, deterministic, works in offline CI. Downside: your CI doesn’t know when translations changed, so fresh copy only lands on the next scheduled build.
  • Webhook-triggered build — set up a webhook on translation.updated (see Webhooks) that triggers your CI via repository_dispatch (GitHub) or a pipeline trigger. Fresh translations within minutes.

For runtime-CDN apps, neither is needed — the CDN is the source of truth.

  • API keys as secrets, never in committed config. The ${COMVI_API_KEY} substitution in config files resolves from env.
  • Separate keys per environment and per purpose. Don’t share the prod push key with the staging CI.
  • last used in the dashboard should match your expected cadence. An unused CI key is a leak risk.
  • Rotate on contributor offboarding — a departing engineer may have pulled the CI secret into a local shell.

See API Keys for the full security guide.

comvi push says “no new keys” but my new key isn’t in Comvi

Section titled “comvi push says “no new keys” but my new key isn’t in Comvi”

The extractor didn’t find the call in your code. Check your CLI config’s extract.patterns — if you use a custom t wrapper, you may need to register it.

Probably a 401/403 with no output. Run with --verbose and check the key’s scopes. The pull endpoint needs project:read and translations:read; type generation also needs schema:read.

Translations in CI differ from what translators see

Section titled “Translations in CI differ from what translators see”

CI may be caching an old CDN response. The CDN cache is short (minutes), but aggressive CI caches can hold for longer. Clear the cache or add a cache-busting param.

A new namespace got pulled by accident. Check namespaces in your config — it should list only the ones this app loads.