Connecting Crowdin API to GitHub Pull Requests
The Core Synchronization Bottleneck
Engineering teams frequently experience localization drift when translation assets are manually exported from Crowdin and committed to GitHub. Without automated API orchestration, stale string files cause UI rendering failures, merge conflicts, and delayed release cycles. Implementing a robust pipeline for Crowdin Integration for Dev Teams resolves these friction points by replacing manual handoffs with deterministic, event-driven syncs.
Key Failure Modes to Eliminate:
- Manual export/commit cycles introducing race conditions
- Unvalidated JSON/YAML payloads breaking frontend parsers
- Branch divergence between feature work and l10n updates
- Lack of automated reviewer routing for translation PRs
Event-Driven API & PR Orchestration
The architecture relies on Crowdin’s REST API v2, GitHub Actions, and webhook listeners to create a closed-loop localization pipeline. A scheduled or webhook-triggered workflow authenticates via OAuth2, queries project translation status, and conditionally exports only approved language bundles. The CI runner commits these assets to an isolated l10n-sync branch, opens or updates a pull request, and attaches automated validation reports. This pattern ensures Translation Workflows & CI/CD Pipeline Sync remains deterministic and auditable across all environments.
Core Workflow Components:
- Crowdin API v2 client with scoped project tokens
- GitHub Actions runner utilizing
actions/checkoutandpeter-evans/create-pull-request - Conditional export logic filtering by
translationProgress >= 100 - Pre-merge JSON schema validation and placeholder integrity checks
Production-Ready GitHub Actions Workflow
name: Crowdin l10n Sync & PR
on:
schedule:
- cron: '0 2 * * 1-5' # Run weekdays at 02:00 UTC
workflow_dispatch:
jobs:
sync-translations:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GH_PAT }}
- name: Export Approved Translations via Crowdin API
run: |
curl -s -X POST "https://api.crowdin.com/api/v2/projects/${{ secrets.CROWDIN_PROJECT_ID }}/translations/exports" \
-H "Authorization: Bearer ${{ secrets.CROWDIN_API_TOKEN }}" \
-H "Content-Type: application/json" \
-d '{"targetLanguageIds": ["es", "fr", "de"], "skipUntranslatedStrings": true}'
- name: Download & Stage Assets
run: |
mkdir -p tmp_export
# Use Crowdin CLI or direct API download here based on export ID
# cp -r tmp_export/* ./locales/
- name: Validate Payloads
run: |
for f in locales/**/*.json; do
jq empty "$f" || { echo "Invalid JSON: $f"; exit 1; }
done
- name: Create/Update l10n PR
uses: peter-evans/create-pull-request@v5
with:
token: ${{ secrets.GH_PAT }}
branch: l10n-sync
commit-message: "chore(l10n): sync approved translations"
title: "Automated Localization Sync"
body: "Generated by CI pipeline. Review translations before merge."
labels: "l10n, automated"
Framework-Specific Path Mapping & Export Rules
Successful API integration requires precise alignment between Crowdin’s export paths and your framework’s i18n routing conventions. Configure your CI environment variables and Crowdin file mappings to match the exact directory structures below.
Next.js (next-i18next)
LOCALE_DIRECTORY: "/locales/{lang}/"
CROWDIN_FILE_MAPPING: "locales/{lang}/common.json"
EXPORT_FLAGS: "--skip-untranslated-strings --dest locales/{lang}"
React (i18next)
LOCALE_DIRECTORY: "/public/locales/{lang}/"
CROWDIN_FILE_MAPPING: "public/locales/{lang}/translation.json"
EXPORT_FLAGS: "--dest public/locales/{lang} --branch main"
Vue (vue-i18n)
LOCALE_DIRECTORY: "/src/locales/"
CROWDIN_FILE_MAPPING: "src/locales/{lang}.json"
EXPORT_FLAGS: "--dest src/locales --export-only-approved"
Edge Case Audit & Resolution Matrix
Production deployments encounter predictable failure states during API-to-PR synchronization. Use the following diagnostic steps to isolate and remediate pipeline errors.
| Error State | Diagnostic Trigger | Production Resolution |
|---|---|---|
HTTP 429 Too Many Requests on Crowdin API |
Concurrent language exports exceed rate limits. | Implement exponential backoff in the workflow and stagger exports using --parallel 2 with a 30-second delay between language batches. |
| GitHub Action fails on JSON parse validation | Translator injected unescaped characters or broken placeholders. | Add a jq or ajv validation step in the workflow to reject malformed payloads before commit, and enable Crowdin’s ‘Tag validation’ in project settings. |
| Webhook HMAC signature mismatch | Secret encoding mismatch or payload tampering. | Ensure the webhook secret in Crowdin matches GitHub exactly, strip trailing whitespace, and verify UTF-8 encoding without BOM during signature generation. |
| Automated PR blocked by merge conflicts | Developer modified i18n files concurrently with sync workflow. | Configure the workflow to fetch origin/main, perform an automated rebase on the l10n-sync branch, and force-push only if the conflict resolution script exits cleanly. |