
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.
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.
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.
npm install --save-dev @anthropic/i18n-validateGitHub 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
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.xmlGitLab 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
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/**/*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
#!/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
fiConfiguration 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
{
"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