Get Started
i18n ci-cd automation devops

Automating i18n in CI/CD Pipelines

LangCTL Team 6 min read

Manual translation workflows don’t scale. As projects grow, manually checking for missing keys, syncing with translation platforms, and validating file formats becomes error-prone and time-consuming.

Automation solves this. Translation validation and sync should be part of your CI/CD pipeline, just like tests and linting.

This guide covers practical approaches to automating i18n in common CI/CD environments.

What to Automate

Translation automation typically includes:

  1. Validation: Check translation file format and structure
  2. Completeness checks: Ensure all languages have all keys
  3. Sync: Pull/push translations from/to external platforms
  4. Build-time processing: Generate optimized translation bundles

Let’s cover each.

Validation

Catch formatting errors and structural issues before they reach production.

JSON/YAML validation

At minimum, ensure files parse correctly:

# GitHub Actions example
- name: Validate translation files
  run: |
    for file in locales/*.json; do
      jq empty "$file" || exit 1
    done

Schema validation

For more structured checks, validate against a schema:

- name: Validate translation schema
  run: |
    npx ajv validate -s translation-schema.json -d "locales/*.json"

CLI tool validation

Most i18n CLI tools include validation:

- name: Validate translations
  run: langctl validate --strict

This catches:

  • Duplicate keys
  • Invalid placeholder syntax
  • Malformed files
  • Encoding issues

Completeness Checks

Missing translations should fail the build (or at least warn).

Basic check

Compare key counts across language files:

- name: Check translation completeness
  run: |
    base_count=$(jq 'keys | length' locales/en.json)
    for file in locales/*.json; do
      count=$(jq 'keys | length' "$file")
      if [ "$count" -lt "$base_count" ]; then
        echo "Warning: $file has fewer keys than base language"
        # Optionally: exit 1
      fi
    done

CLI tool check

More sophisticated tools compare actual keys:

- name: Check for missing translations
  run: langctl status --fail-on-missing

This identifies specific missing keys, not just counts.

Configurable strictness

You might want different behavior for different branches:

- name: Check translations
  run: |
    if [ "${{ github.ref }}" = "refs/heads/main" ]; then
      langctl status --fail-on-missing
    else
      langctl status --warn-on-missing
    fi

Strict on main, permissive on feature branches.

Syncing with Translation Platforms

If you use an external translation management system, sync in CI/CD.

Pull before build

Ensure builds use latest translations:

- name: Sync translations
  env:
    LANGCTL_API_KEY: ${{ secrets.LANGCTL_API_KEY }}
  run: |
    langctl pull
    git diff --exit-code locales/ || echo "Translations updated"

Push after merge

When new keys are merged, push to the platform:

# On push to main
- name: Push new keys to translation platform
  if: github.ref == 'refs/heads/main'
  env:
    LANGCTL_API_KEY: ${{ secrets.LANGCTL_API_KEY }}
  run: langctl push

Handling credentials

Translation platform credentials should be stored as secrets:

# GitHub Actions
env:
  LANGCTL_API_KEY: ${{ secrets.LANGCTL_API_KEY }}

# GitLab CI
variables:
  LANGCTL_API_KEY: $LANGCTL_API_KEY  # Set in GitLab CI/CD settings

Never commit API keys to your repository.

Complete Pipeline Examples

GitHub Actions

name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

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

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

      - name: Install dependencies
        run: npm ci

      - name: Install langctl
        run: npm install -g langctl

      - name: Validate translation files
        run: langctl validate

      - name: Check for missing translations
        run: langctl status --fail-on-missing

  build:
    needs: validate-translations
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

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

      - name: Install dependencies
        run: npm ci

      - name: Pull latest translations
        env:
          LANGCTL_API_KEY: ${{ secrets.LANGCTL_API_KEY }}
        run: langctl pull

      - name: Build
        run: npm run build

  sync-keys:
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install langctl
        run: npm install -g langctl

      - name: Push new keys
        env:
          LANGCTL_API_KEY: ${{ secrets.LANGCTL_API_KEY }}
        run: langctl push

GitLab CI

stages:
  - validate
  - build
  - sync

validate-translations:
  stage: validate
  image: node:20
  script:
    - npm install -g langctl
    - langctl validate
    - langctl status --fail-on-missing
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"

build:
  stage: build
  image: node:20
  script:
    - npm ci
    - npm install -g langctl
    - langctl pull
    - npm run build
  artifacts:
    paths:
      - dist/

sync-keys:
  stage: sync
  image: node:20
  script:
    - npm install -g langctl
    - langctl push
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
  when: on_success

Generic Pipeline (Bash)

For other CI systems:

#!/bin/bash
set -e

# Validate
echo "Validating translations..."
langctl validate --strict

# Check completeness
echo "Checking for missing translations..."
langctl status --fail-on-missing

# Sync (if on main branch)
if [ "$BRANCH" = "main" ]; then
  echo "Syncing translations..."
  langctl pull
fi

# Build
echo "Building..."
npm run build

# Push new keys (if on main branch after successful build)
if [ "$BRANCH" = "main" ]; then
  echo "Pushing new keys..."
  langctl push
fi

Advanced Patterns

Scheduled translation sync

Run translation sync on a schedule, not just on commits:

# GitHub Actions
on:
  schedule:
    - cron: '0 6 * * *'  # Daily at 6 AM

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

      - name: Pull translations
        env:
          LANGCTL_API_KEY: ${{ secrets.LANGCTL_API_KEY }}
        run: |
          langctl pull

      - name: Commit if changed
        run: |
          git config user.name "Translation Bot"
          git config user.email "[email protected]"
          git add locales/
          git diff --staged --quiet || git commit -m "chore: sync translations"
          git push

Translation preview in PRs

Add translation status to pull request comments:

- name: Translation status
  run: |
    status=$(langctl status --format markdown)
    echo "## Translation Status" > comment.md
    echo "$status" >> comment.md

- name: Post comment
  uses: actions/github-script@v7
  with:
    script: |
      const fs = require('fs');
      const body = fs.readFileSync('comment.md', 'utf8');
      github.rest.issues.createComment({
        issue_number: context.issue.number,
        owner: context.repo.owner,
        repo: context.repo.repo,
        body
      });

Branch-specific languages

Only require certain languages in feature branches:

- name: Check translations
  run: |
    if [ "${{ github.ref }}" = "refs/heads/main" ]; then
      langctl status --languages en,es,fr,de --fail-on-missing
    else
      langctl status --languages en --fail-on-missing
    fi

Troubleshooting

Build failures from translation issues

If translations block builds unexpectedly:

  1. Check if new keys were added without translations
  2. Verify file format is valid (try parsing locally)
  3. Review CI logs for specific error messages
  4. Consider relaxing strictness for feature branches

Sync conflicts

If CI sync creates conflicts:

  1. Pull translations locally first
  2. Resolve conflicts
  3. Push resolved state
  4. Re-run CI

Credential issues

If authentication fails in CI:

  1. Verify secrets are configured correctly
  2. Check API key hasn’t expired
  3. Ensure key has appropriate permissions
  4. Test locally with same credentials

Summary

Automating i18n in CI/CD catches issues early and keeps translations in sync. The key steps:

  1. Validate file format and structure
  2. Check completeness to catch missing translations
  3. Sync with translation platforms automatically
  4. Adjust strictness based on branch and context

Start simple—add validation first, then completeness checks, then sync. Iterate as your needs evolve.


See also: How to Manage i18n in Git Workflows for Git-specific practices that complement CI/CD automation.

Ready to simplify your i18n workflow?

LangCTL is a CLI-first translation management tool built for developers. Start for free.