Build Modes

@lingo.dev/compiler supports two build modes that control when and how translations are generated.

Modes Overview

ModeWhen to UseAPI CallsBehavior
translateDevelopment, CIYesGenerates missing translations using configured LLM
cache-onlyProduction buildsNoUses only cached translations from .lingo/metadata.json

Translate Mode

Purpose: Generate translations on-demand during builds.

{
  buildMode: "translate"
}

Behavior:

  • Scans code for translatable text
  • Checks .lingo/metadata.json for existing translations
  • Generates missing translations via configured LLM provider
  • Updates .lingo/metadata.json with new translations
  • Fails build if translation generation fails

When to use:

  • Local development (with usePseudotranslator: true)
  • CI/CD pipelines (with real LLM providers)
  • Initial setup and translation generation

Requires:

  • Valid API key for configured provider (or pseudotranslator enabled)
  • Network connection to LLM provider

Cache-Only Mode

Purpose: Build using pre-generated translations only.

{
  buildMode: "cache-only"
}

Behavior:

  • Reads translations from .lingo/metadata.json
  • No API calls made
  • Fails build if translations are missing for any locale
  • Fast, deterministic builds

When to use:

  • Production builds
  • Deployments without API keys
  • Environments with restricted network access

Requires:

  • .lingo/metadata.json with translations for all locales
  • Translations pre-generated in CI or development

1. Local Development

Use pseudotranslator for instant feedback:

{
  buildMode: "translate",
  dev: {
    usePseudotranslator: true,
  }
}

Benefits:

  • Instant fake translations
  • No API costs
  • See exactly what gets translated
  • Test UI with varying text lengths

2. CI/CD Pipeline

Generate real translations in CI:

{
  buildMode: "translate",
  dev: {
    usePseudotranslator: false,
  }
}

Setup in CI:

# GitHub Actions example
- name: Install dependencies
  run: pnpm install

- name: Generate translations
  env:
    LINGODOTDEV_API_KEY: ${{ secrets.LINGODOTDEV_API_KEY }}
  run: pnpm run build

- name: Commit translations
  run: |
    git config user.name "github-actions[bot]"
    git config user.email "github-actions[bot]@users.noreply.github.com"
    git add .lingo/
    git commit -m "chore: update translations" || exit 0
    git push

Benefits:

  • Real translations generated once per deployment
  • Committed to version control
  • Production builds don't need API keys

3. Production Build

Use cached translations only:

{
  buildMode: "cache-only",
}

Benefits:

  • No API keys needed
  • Fast builds
  • Deterministic—same input always produces same output
  • No external network dependencies

Environment Variable Override

Override build mode via environment variable:

# Force cache-only mode
LINGO_BUILD_MODE=cache-only npm run build

# Force translate mode
LINGO_BUILD_MODE=translate npm run build

This is useful for deployment environments where you want to enforce cache-only without modifying config.

Handling Missing Translations

In Translate Mode

If translation fails:

Error: Failed to generate translation for locale "es":
  - Hash: abc123def
  - Source text: "Welcome to our app"
  - Provider: lingo.dev
  - Reason: API key invalid

Solution: Fix API key, re-run build.

In Cache-Only Mode

If translations are missing:

Error: Missing translations for locale "es":
  - Hash: abc123def
  - Source text: "Welcome to our app"
  - File: app/page.tsx:12

Run with buildMode: "translate" to generate missing translations.

Solution: Run a build with translate mode to generate missing translations, then commit .lingo/.

Incremental Translation

The compiler uses content hashing to determine what needs translation:

  1. Each translatable string gets a stable hash
  2. Hash is based on source text + context
  3. If hash exists in .lingo/metadata.json, translation is reused
  4. Only new or changed text triggers re-translation

Result: You only pay for translations once. Subsequent builds reuse cached translations.

CI Configuration Examples

GitHub Actions

name: Generate Translations

on:
  push:
    branches: [main]
  pull_request:

jobs:
  translate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: pnpm/action-setup@v2
        with:
          version: 8

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: "pnpm"

      - name: Install dependencies
        run: pnpm install

      - name: Generate translations
        env:
          LINGODOTDEV_API_KEY: ${{ secrets.LINGODOTDEV_API_KEY }}
        run: pnpm run build

      - name: Commit translations
        if: github.event_name == 'push'
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
          git add .lingo/
          git diff --quiet && git diff --staged --quiet || git commit -m "chore: update translations"
          git push

GitLab CI

stages:
  - translate

generate-translations:
  stage: translate
  script:
    - pnpm install
    - pnpm run build
    - git config user.name "GitLab CI"
    - git config user.email "[email protected]"
    - git add .lingo/
    - git diff --quiet && git diff --staged --quiet || git commit -m "chore: update translations"
    - git push origin HEAD:$CI_COMMIT_REF_NAME
  only:
    - main

Common Questions

Do I need API keys in production? No. Use buildMode: "cache-only" in production. Translations are pre-generated in CI.

What if I forget to generate translations in CI? Production build will fail with a clear error listing missing translations. Generate them in CI, commit, and redeploy.

Can I use translate mode in production? Yes, but not recommended. It makes builds non-deterministic and requires API keys in production. Better to generate translations in CI.

How do I test cache-only mode locally?

  1. Generate translations with translate mode
  2. Switch to cache-only mode
  3. Run build—should succeed using cached translations

What if my source text changes? The hash changes, so a new translation is generated (in translate mode). Old translation is kept in .lingo/metadata.json for history.

Do I commit .lingo/ to git? Yes. The .lingo/ directory should be version-controlled. It contains your translation cache.

Next Steps