Skip to main content

CI Translation Validation: Automate i18n Checks in Your Pipeline

Translation bugs are invisible in code review. A missing key, a broken placeholder, a malformed plural — none of these show up in a diff. CI-level validation catches them before they reach production.

1

Why Translation Bugs Slip Through Code Review

A developer adds 10 new keys to en.json and updates the feature code. The PR reviewer checks the code, verifies the English strings, and approves. Nobody diffs the 14 other locale files. Three bugs ship to production: de.json is missing 2 keys (German users see raw key paths), fr.json has a broken {count} placeholder (French users see literal {count}), and ja.json has a malformed ICU plural (Japanese users see a crash). These are preventable with a 30-second CI check.

Translation bugs have a unique property: they are invisible to the developer, invisible to the reviewer, and only visible to users in a specific locale. CI validation is the only reliable way to catch them before production.
2

Install i18n-validate

Add i18n-validate to your project as a dev dependency. It supports JSON, YAML, PO, XLIFF, and ARB formats out of the box — no configuration needed for basic usage.

Terminal
npm install --save-dev @anthropic/i18n-validate
3

GitHub Actions Integration

Add i18n-validate as a step in your pull request workflow. The tool exits with code 1 when errors are found, failing the PR check. Use JUnit XML output with a test reporter action to get inline annotations directly on the PR diff.

.github/workflows/i18n-validate.yml
# .github/workflows/i18n-validate.yml
name: Validate Translations

on:
  pull_request:
    paths:
      - 'src/locales/**'
      - 'public/locales/**'

jobs:
  validate:
    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: Validate translation files
        run: npx i18n-validate \
          --source src/locales/en.json \
          --targets 'src/locales/*.json' \
          --check-missing \
          --check-unused \
          --check-placeholders \
          --check-plurals \
          --min-coverage 95 \
          --junit-output reports/i18n.xml

      - name: Upload report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: i18n-validation-report
          path: reports/i18n.xml
Pin the i18n-validate version in your workflow to avoid unexpected breaks from new validation rules. Use @latest only in development.
4

GitLab CI Integration

Add a translation validation job to your .gitlab-ci.yml pipeline. GitLab natively supports JUnit XML artifacts — upload the validation report and errors appear in the merge request's Test tab.

.gitlab-ci.yml
# .gitlab-ci.yml
i18n-validate:
  stage: test
  image: node:20
  script:
    - npm ci
    - npx i18n-validate \
        --source src/locales/en.json \
        --targets 'src/locales/*.json' \
        --check-missing \
        --check-unused \
        --check-placeholders \
        --min-coverage 95 \
        --junit-output reports/i18n.xml
  artifacts:
    reports:
      junit: reports/i18n.xml
  only:
    changes:
      - src/locales/**/*
5

Pre-Commit Hook

For faster feedback, run validation as a pre-commit hook. This catches issues before they even reach CI, saving pipeline time and reducing feedback loops. Use Husky (JS) or pre-commit (Python) to manage hooks.

.husky/pre-commit
# .husky/pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

# Only validate if translation files changed
CHANGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '(locales|i18n|translations)/')

if [ -n "$CHANGED_FILES" ]; then
  echo "Translation files changed, validating..."
  npx i18n-validate \
    --source src/locales/en.json \
    --targets 'src/locales/*.json' \
    --check-missing \
    --check-placeholders
fi
Pre-commit hooks run on every commit, so keep them fast. Use the --locales flag to validate only the locales that changed in the current commit, rather than all locales. This keeps hook execution under 2 seconds for most projects.
6

Configuration and Severity Levels

Customize validation behavior with a .i18n-validate.toml configuration file. Set check severity (error, warning, off) per rule, define expected languages, exclude WIP locales, and configure output format. In CI, only errors fail the pipeline — warnings appear in the report but don't block.

i18n-validate.config.json
// i18n-validate.config.json
{
  "source": "src/locales/en.json",
  "targets": "src/locales/*.json",
  "checks": {
    "missing": true,         // Keys in source missing from target
    "unused": true,          // Keys in target not in source
    "placeholders": true,    // Mismatched {variables}
    "plurals": true,         // Missing CLDR plural forms
    "icu": true,             // ICU syntax validation
    "emptyValues": true,     // Empty string values
    "duplicateValues": false // Same value as source (untranslated)
  },
  "minCoverage": 95,
  "exclude": [
    "src/locales/pseudo.json"
  ],
  "junitOutput": "reports/i18n.xml",
  "format": "json"          // json | yaml | po | xliff
}

Try i18n Agent Now

Drop your translation file here

JSON, YAML, PO, XML, CSV, Markdown, Properties

or click to browse

Target languages

No signup requiredInstant estimate

CI Translation Validation FAQ