|
Documentation
Book a DemoPlatform
PlatformMCPCLIAPIWorkflows
Guides
Changelog

Localization

  • Overview
  • Translation API
  • Web App Localization
  • Mobile App Localization
  • iOS with String Catalogs
  • Android with strings.xml
  • Emails Localization
  • Static Content (e.g. .md, .json)
  • Next.js with Markdoc
  • Rails with i18n

Workflows

  • Engine Setup with MCP
  • Jira Triage
  • CI/CD

CI/CD Localization Workflows

Lingo.dev runs your localization automatically in CI/CD. There are two ways to do it: the GitHub App, which reacts to your pushes and pull requests server-side, or the CLI run inside your own pipeline. Both keep translations in sync on every change, and both process only the strings that actually changed - so localization stays fast and cost-efficient as your project grows.

On GitHub? Start with the App

The GitHub App is the recommended path on GitHub. Install it once, and it localizes on every push and pull request with no runner, no CI secret, and no lockfile to manage. If you're not on GitHub, or you want translation to run alongside your other CI steps, run the CLI in your own pipeline instead.

Option 1: GitHub App (recommended)#

The GitHub App is the simplest way to run continuous localization. It watches your repository and translates server-side, so there's nothing to install in your pipeline and no API key to store as a CI secret.

Setup is a one-time thing:

  1. Install the Lingo.dev GitHub App on your repository.
  2. Commit a .lingo/config.json with your orgId, engineId, source locale, target locales, and the files to translate. Run lingo init and lingo link locally to generate it, then commit the result.
  3. Push.

From then on the App handles both workflow styles for you:

  • On a push to your default branch, it commits translations back to the branch.
  • On a pull request, it adds the translations to that PR so you can review them before merging.

Because the App tracks translation state server-side, there's no lockfile in your repo to conflict on, and no verification step to wire up - it simply keeps your target locales in sync with your source.

Option 2: CLI in your own pipeline#

When you're not on GitHub, or you want localization to run as an explicit step next to your build and test jobs, run the CLI yourself. It works in any CI environment with Node.js 22 or newer - GitHub Actions, GitLab CI, Bitbucket Pipelines, or anything else.

The flow is always the same:

  1. Install @lingo.dev/cli.
  2. Authenticate with your API key via the LINGO_API_KEY environment variable.
  3. Run lingo push to translate changed strings.
  4. Commit the results, or open a pull request from your job.

Store your Lingo.dev API key as a CI secret and expose it as LINGO_API_KEY. The committed .lingo/config.json tells the CLI what to translate, and the committed .lingo/lock.json (regenerated by lingo push) tracks state so only changed strings are processed.

Minimal GitHub Actions example#

This workflow installs the CLI, translates on every push to main, and commits the results back:

yaml
name: Localize
on:
  push:
    branches: [main]
permissions:
  contents: write
jobs:
  localize:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npm install -g @lingo.dev/cli
      - run: lingo push
        env:
          LINGO_API_KEY: ${{ secrets.LINGO_API_KEY }}
      - name: Commit translations
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add .
          git commit -m "chore: update translations" || echo "No changes"
          git push

The same two lines - npm install -g @lingo.dev/cli then lingo push - drop into a GitLab CI script: block or a Bitbucket Pipelines step. Set LINGO_API_KEY as a masked/protected CI variable in those platforms.

First run and new locales

The first time you run in CI, or whenever you add a target locale, use lingo push --backfill-missing so every existing string gets translated into the new locale. After that, a plain lingo push translates only the delta.

Commit or pull request?#

Whichever path you pick, you still choose how translations land:

ApproachHow it worksBest forTrade-off
Commit directlyTranslations are committed to the branch that changedSmall teams, zero frictionNo review step for translations
Pull requestTranslations land in a PR for review before mergeTeams that review translationsRequires PR approval

The GitHub App gives you both automatically - it commits on pushes to your default branch and adds translations to open PRs. In your own pipeline, the choice is yours: commit the results as shown above, or have the job open a pull request instead of pushing to the branch.

Verifying translations before deploy#

To make sure no untranslated content ships, add lingo check as a gate before your deploy step. It exits with a non-zero status when any strings still need translation:

yaml
- name: Verify translations
  run: lingo check

The GitHub App keeps locales in sync continuously, so a dedicated verification step is mainly useful when you run the CLI yourself.

Monorepos#

For monorepos where each package has its own .lingo/config.json, scope the run to a package by passing a glob, or run the CLI from that package's directory:

bash
lingo push "apps/web/**"

Next Steps#

GitHub App
Managed continuous localization on GitHub - no runner, secret, or lockfile
CLI overview
Install, authenticate, and run the Lingo.dev CLI
Quickstart
Go from zero to your first push in a few minutes
Configuration
Everything that goes in .lingo/config.json
Run state
How the lockfile tracks what's been translated

Was this page helpful?

Max PrilutskiyMax Prilutskiy·Updated 4 days ago·4 min read