---
title: "Automate translations in CI"
description: "Keep pull requests fast, update development languages, and keep production releases deliberate."
canonical_url: "https://docs.linguana.dev/docs/automate/ci-cd"
markdown_url: "https://docs.linguana.dev/docs/automate/ci-cd.md"
x_farming_labs_generated_preamble: true
agent:
  task: "Add safe Linguana stages to a continuous delivery pipeline."
  outcome: "Pull requests perform free deterministic checks; only an authorized development job can request paid work."
  prerequisites:
    - "The application has a deterministic extraction-only configuration."
    - "A development environment token is stored in CI secrets."
  files:
    - ".github/workflows/linguana.yml"
    - "vite.config.ts"
  commands:
    - "bun install --frozen-lockfile"
    - "bun run build"
  verification:
    - "Pull requests make no remote request and production remains a dashboard release."
  rollback:
    - "Disable the development translation job without changing application deployment."
  failureModes:
    - symptom: "A pull request attempts manifest upload."
      resolution: "Remove remote secrets and force LINGUANA_UPLOAD=false in the validation job."
---

# Automate translations in CI
URL: /docs/automate/ci-cd
LLM index: /llms.txt
Description: Keep pull requests fast, update development languages, and keep production releases deliberate.
Related: /docs/advanced/testing/extraction, /docs/automate/production-checklist

<!-- farming-labs:agent-contract:start -->
## Agent Contract

Task: Add safe Linguana stages to a continuous delivery pipeline.
Outcome: Pull requests perform free deterministic checks; only an authorized development job can request paid work.

### Prerequisites

- The application has a deterministic extraction-only configuration.
- A development environment token is stored in CI secrets.

### Files

- `.github/workflows/linguana.yml`
- `vite.config.ts`

### Commands

- `bun install --frozen-lockfile`
- `bun run build`

### Verification

- Pull requests make no remote request and production remains a dashboard release.

### Rollback

- Disable the development translation job without changing application deployment.

### Failure Modes

- A pull request attempts manifest upload. — Recovery: Remove remote secrets and force LINGUANA_UPLOAD=false in the validation job.
<!-- farming-labs:agent-contract:end -->

# Automate translations in CI

Keep pull requests fast, let development builds update translations, and keep production releases deliberate.

```text
Pull request
  Check the app and find new text

Development build
  Send new text for translation

Production release
  Review and publish the selected language
```

## GitHub Actions example

Pull requests do not need a project token. The development job runs only on `main` and receives its token from a protected CI environment.

```yaml title=".github/workflows/linguana.yml"
name: Linguana

on:
  pull_request:
  push:
    branches: [main]

jobs:
  validate:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    env:
      LINGUANA_UPLOAD: "false"
      LINGUANA_TRANSLATE: "false"
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: oven-sh/setup-bun@v2
        with:
          bun-version: 1.3.14
      - run: bun install --frozen-lockfile
      - run: bun run check-types
      - run: bun run docs:verify
      - name: Snapshot source
        run: bun run source:before
      - name: Extraction-only build
        run: bun run build
      - name: Verify source integrity
        run: bun run source:after
      - uses: actions/upload-artifact@v4
        with:
          name: linguana-manifest
          path: .linguana/manifest.json
          if-no-files-found: error
          retention-days: 14

  translate-development:
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    needs: validate
    runs-on: ubuntu-latest
    timeout-minutes: 15
    environment: linguana-development
    env:
      LINGUANA_API_URL: ${{ vars.LINGUANA_API_URL }}
      LINGUANA_PROJECT_TOKEN: ${{ secrets.LINGUANA_PROJECT_TOKEN }}
      LINGUANA_UPLOAD: "true"
      LINGUANA_TRANSLATE: "true"
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: oven-sh/setup-bun@v2
        with:
          bun-version: 1.3.14
      - run: bun install --frozen-lockfile
      - name: Upload and translate development catalog
        run: bun run build
```

Configure the plugin with an explicit charge and wait ceiling:

```ts title="vite.config.ts"
translation: process.env.LINGUANA_PROJECT_TOKEN &&
  process.env.LINGUANA_TRANSLATE !== "false"
  ? {
      enabled: true,
      maxChargeMicros: 100_000,
      waitTimeoutMs: 300_000,
      publish: "development",
    }
  : undefined,
```

## Other CI providers

Use the same stage boundaries:

```bash title="pull request validation"
export LINGUANA_UPLOAD=false
export LINGUANA_TRANSLATE=false
bun install --frozen-lockfile
bun run check-types
bun run docs:verify
bun run source:before
bun run build
bun run source:after
```

```bash title="authorized development build"
test -n "$LINGUANA_PROJECT_TOKEN"
export LINGUANA_UPLOAD=true
export LINGUANA_TRANSLATE=true
bun run build
```

## Keep credentials private

| Value | Store | Browser-safe? |
| --- | --- | --- |
| `LINGUANA_PROJECT_TOKEN` | Protected CI environment secret | No |
| Provider API key | Translation service secret store | No |
| `VITE_LINGUANA_API_URL` | Build/public variable | Yes |
| Publishable catalog key | Public runtime configuration | Yes |

Do not print environment values, authorization headers, source bodies, or translated bodies. Retain the manifest artifact, manifest hash, job IDs, request IDs, and redacted logs.

## If something fails

Keep the error code, translation-run ID, and request ID from the build logs. Check an existing run before retrying so you do not start the same translation twice.

The build integration updates development languages only. Production remains an explicit dashboard action after review.

<ExpectedResult>
Pull requests perform no authenticated translation work. Merged development builds may update development languages, while production requires review and an explicit release.
</ExpectedResult>

## Next

Test the setup with [Test your integration](/docs/automate/test-integration), then complete the [production checklist](/docs/automate/production-checklist).

## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
Docs-scoped sitemap: [/docs/sitemap.md](/docs/sitemap.md).
Well-known sitemap: [/.well-known/sitemap.md](/.well-known/sitemap.md).
