IntlPull
Guide
11 min read

Translation Workflow Automation: Webhooks, CI/CD & API Integration

Automate translation workflows with webhooks, CI/CD pipelines, and API integration. Learn event-driven automation, notification patterns, and continuous localization.

IntlPull Team
IntlPull Team
Feb 12, 2026
On this page
Summary

Automate translation workflows with webhooks, CI/CD pipelines, and API integration. Learn event-driven automation, notification patterns, and continuous localization.

Why Automate Translation Workflows

Manual translation workflows don't scale. As products grow from supporting 3 languages to 15+, from 500 translation keys to 10,000+, and from quarterly releases to continuous deployment, human coordination bottlenecks emerge at every step. Developers forget to notify translators about new keys, translators wait for manual assignment, completed translations sit undeployed, missing translations escape detection until production, and status tracking requires constant manual updates across spreadsheets and emails.

Workflow automation eliminates these bottlenecks through event-driven architecture where systems communicate automatically. When developers push code with new translation keys, automated pipelines detect changes and trigger translation workflows. When translators complete work, webhooks notify downstream systems to deploy updates. When quality issues arise, automated checks flag problems immediately rather than during manual review cycles. This continuous, automated approach transforms localization from a periodic batch process into a seamless extension of software delivery.

Automation Opportunities in Translation Workflow

Development Phase

Automated Key Extraction: Scan code for new translation keys during development. Extract keys from source code, generate translation files, and create TMS entries automatically.

Missing Translation Detection: CI pipeline checks for hardcoded strings and validates all user-facing text uses i18n keys before allowing merge.

Format Validation: Automatically validate translation file syntax (JSON, YAML, PO) to prevent malformed files from reaching production.

Translation Phase

Automatic Assignment: When new keys appear, auto-assign to translators based on language expertise, workload, or round-robin distribution.

Notification Triggers: Send Slack/email notifications when new translation tasks become available, urgent translations are needed, or deadlines approach.

Machine Translation Pre-fill: Automatically generate MT suggestions for new keys to accelerate translator productivity.

Review Phase

Quality Check Automation: Run automated QA checks (placeholder matching, length limits, glossary compliance) before human review.

Auto-Approval: Configure rules to auto-approve translations that pass all quality checks from trusted translators.

Review Assignment: Route completed translations to appropriate reviewers based on language, domain expertise, or project ownership.

Deployment Phase

Auto-Export: When translations are approved, automatically export to target format and commit to repository.

CI/CD Integration: Translation updates trigger builds and deployments just like code changes.

OTA Updates: Push translation updates to mobile/web apps without full redeployment using over-the-air update mechanisms.

Cache Invalidation: Automatically invalidate CDN caches for translation files when updates publish.

Webhook Events and Handlers

What are Webhooks?

Webhooks are HTTP callbacks that TMS platforms send to your servers when specific events occur. Instead of polling the TMS API repeatedly to check for changes, your system receives real-time notifications pushed by the platform.

Webhook Flow:

  1. Event occurs in TMS (e.g., translation completed)
  2. TMS sends HTTP POST request to your configured endpoint
  3. Your server receives payload and processes event
  4. Your server responds with 200 OK to confirm receipt

Common Webhook Events

Translation Events:

  • translation.created: New translation added
  • translation.updated: Existing translation modified
  • translation.approved: Translation passed review
  • translation.rejected: Translation failed review

Key Events:

  • key.created: New translation key added
  • key.updated: Key metadata modified
  • key.deleted: Translation key removed

Project Events:

  • project.created: New project initialized
  • project.updated: Project settings changed
  • language.added: New language added to project
  • language.removed: Language removed from project

Export Events:

  • export.completed: Translation export finished
  • import.completed: Translation import finished

Setting Up Webhook Endpoints

Express.js Example:

JavaScript
1const express = require('express');
2const crypto = require('crypto');
3
4const app = express();
5app.use(express.json());
6
7// Webhook signature validation
8function validateSignature(payload, signature, secret) {
9  const hash = crypto
10    .createHmac('sha256', secret)
11    .update(JSON.stringify(payload))
12    .digest('hex');
13
14  return `sha256=${hash}` === signature;
15}
16
17app.post('/webhooks/intlpull', (req, res) => {
18  const signature = req.headers['x-intlpull-signature'];
19  const webhookSecret = process.env.INTLPULL_WEBHOOK_SECRET;
20
21  // Validate webhook authenticity
22  if (!validateSignature(req.body, signature, webhookSecret)) {
23    return res.status(401).json({ error: 'Invalid signature' });
24  }
25
26  const { event, data } = req.body;
27
28  // Route to appropriate handler
29  switch (event) {
30    case 'translation.approved':
31      handleTranslationApproved(data);
32      break;
33    case 'key.created':
34      handleKeyCreated(data);
35      break;
36    case 'export.completed':
37      handleExportCompleted(data);
38      break;
39    default:
40      console.log(`Unhandled event: ${event}`);
41  }
42
43  // Acknowledge receipt
44  res.status(200).json({ received: true });
45});
46
47function handleTranslationApproved(data) {
48  const { projectId, keyId, language, value } = data;
49
50  console.log(`Translation approved: ${keyId} (${language})`);
51
52  // Trigger deployment pipeline
53  triggerDeploy(projectId, language);
54
55  // Notify team via Slack
56  notifySlack(`New translation approved for ${language}: ${keyId}`);
57
58  // Invalidate cache
59  invalidateCache(`translations/${language}`);
60}
61
62app.listen(3000, () => {
63  console.log('Webhook server listening on port 3000');
64});

Security Best Practices:

  • Signature Validation: Always verify webhook signatures to prevent spoofed requests
  • HTTPS Only: Configure webhook URLs with HTTPS endpoints
  • Secret Rotation: Rotate webhook secrets periodically
  • IP Allowlisting: Restrict webhook requests to TMS platform IP ranges (if provided)

Webhook Retry and Reliability

Failed Delivery Handling: TMS platforms typically retry failed webhook deliveries with exponential backoff.

Retry Schedule Example:

  • First failure: Retry after 1 minute
  • Second failure: Retry after 5 minutes
  • Third failure: Retry after 15 minutes
  • Fourth failure: Retry after 1 hour
  • Fifth+ failure: Retry every 6 hours for 48 hours, then give up

Best Practices:

  • Respond with 200 OK quickly (< 5 seconds)
  • Perform heavy processing asynchronously
  • Implement idempotency (handle duplicate events gracefully)
  • Log all webhook receipts for debugging

Idempotent Handler Example:

JavaScript
1const processedWebhooks = new Set();
2
3app.post('/webhooks/intlpull', async (req, res) => {
4  const webhookId = req.body.id;
5
6  // Check if already processed
7  if (processedWebhooks.has(webhookId)) {
8    console.log(`Duplicate webhook ignored: ${webhookId}`);
9    return res.status(200).json({ received: true });
10  }
11
12  // Process webhook
13  await processWebhook(req.body);
14
15  // Mark as processed
16  processedWebhooks.add(webhookId);
17
18  res.status(200).json({ received: true });
19});

CI/CD Pipeline Patterns

Pattern 1: Sync on Translation Approval

Workflow:

  1. Translator completes and approves translation
  2. Webhook fires: translation.approved
  3. Webhook handler triggers GitHub Actions workflow
  4. Workflow pulls latest translations from TMS API
  5. Commits translation files to repository
  6. Creates pull request for review
  7. After PR approval, merges and deploys

GitHub Actions Workflow:

YAML
1name: Sync Translations
2
3on:
4  repository_dispatch:
5    types: [translation_approved]
6
7jobs:
8  sync:
9    runs-on: ubuntu-latest
10    steps:
11      - uses: actions/checkout@v3
12
13      - name: Download translations from IntlPull
14        run: |
15          curl -X GET "https://api.intlpull.com/v1/projects/$PROJECT_ID/export" \
16            -H "X-API-Key: ${{ secrets.INTLPULL_API_KEY }}" \
17            -o translations.zip
18
19      - name: Extract translations
20        run: |
21          unzip translations.zip -d locales/
22
23      - name: Create Pull Request
24        uses: peter-evans/create-pull-request@v5
25        with:
26          commit-message: 'i18n: sync translations from IntlPull'
27          title: 'Update translations'
28          body: 'Automated translation sync triggered by approval'
29          branch: translations/sync-${{ github.run_number }}

Trigger from Webhook:

JavaScript
1// Webhook handler triggers GitHub Actions via repository_dispatch
2function handleTranslationApproved(data) {
3  const { Octokit } = require('@octokit/rest');
4  const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
5
6  octokit.repos.createDispatchEvent({
7    owner: 'your-org',
8    repo: 'your-repo',
9    event_type: 'translation_approved',
10    client_payload: data
11  });
12}

Pattern 2: Continuous Translation Sync

Workflow:

  1. Scheduled job runs every hour
  2. Checks for new/updated translations via TMS API
  3. If changes detected, pulls translations and commits to repo
  4. Triggers automated tests and deployment

GitHub Actions Scheduled Workflow:

YAML
1name: Sync Translations (Scheduled)
2
3on:
4  schedule:
5    - cron: '0 * * * *'  # Run every hour
6  workflow_dispatch:       # Allow manual trigger
7
8jobs:
9  sync:
10    runs-on: ubuntu-latest
11    steps:
12      - uses: actions/checkout@v3
13
14      - name: Fetch translation status
15        id: status
16        run: |
17          LAST_UPDATE=$(curl -s -H "X-API-Key: ${{ secrets.INTLPULL_API_KEY }}" \
18            "https://api.intlpull.com/v1/projects/$PROJECT_ID/status" \
19            | jq -r '.lastUpdated')
20
21          echo "last_update=$LAST_UPDATE" >> $GITHUB_OUTPUT
22
23      - name: Download if updated
24        if: steps.status.outputs.last_update > env.LAST_SYNC_TIME
25        run: |
26          # Download and extract translations
27          curl -X GET "https://api.intlpull.com/v1/projects/$PROJECT_ID/export" \
28            -H "X-API-Key: ${{ secrets.INTLPULL_API_KEY }}" \
29            -o translations.zip
30          unzip translations.zip -d locales/
31
32      - name: Commit changes
33        run: |
34          git config user.name "Translation Bot"
35          git config user.email "bot@intlpull.com"
36          git add locales/
37          git diff --staged --quiet || git commit -m "i18n: sync translations"
38          git push

Pattern 3: Bidirectional Sync

Workflow:

  1. Developers push code with new translation keys
  2. CI pipeline extracts new keys and uploads to TMS
  3. Translators work in TMS
  4. Completed translations sync back to repository

Extract and Upload New Keys:

YAML
1name: Extract Translation Keys
2
3on:
4  push:
5    branches:
6      - main
7    paths:
8      - 'src/**'
9
10jobs:
11  extract:
12    runs-on: ubuntu-latest
13    steps:
14      - uses: actions/checkout@v3
15
16      - name: Extract translation keys
17        run: npm run i18n:extract
18
19      - name: Upload new keys to IntlPull
20        run: |
21          curl -X POST "https://api.intlpull.com/v1/projects/$PROJECT_ID/keys/bulk" \
22            -H "X-API-Key: ${{ secrets.INTLPULL_API_KEY }}" \
23            -H "Content-Type: application/json" \
24            -d @extracted-keys.json

Key Extraction Script Example (React):

JavaScript
1// scripts/extract-keys.js
2const fs = require('fs');
3const parser = require('@babel/parser');
4const traverse = require('@babel/traverse').default;
5
6const extractedKeys = new Set();
7
8function extractFromFile(filePath) {
9  const code = fs.readFileSync(filePath, 'utf8');
10  const ast = parser.parse(code, {
11    sourceType: 'module',
12    plugins: ['jsx', 'typescript']
13  });
14
15  traverse(ast, {
16    CallExpression(path) {
17      // Find t('key') calls
18      if (path.node.callee.name === 't') {
19        const keyArg = path.node.arguments[0];
20        if (keyArg.type === 'StringLiteral') {
21          extractedKeys.add(keyArg.value);
22        }
23      }
24    }
25  });
26}
27
28// Recursively extract from all source files
29// ... (walk directory and call extractFromFile)
30
31// Output to JSON
32const output = Array.from(extractedKeys).map(key => ({
33  key,
34  language: 'en',
35  value: key // Placeholder, developer should provide real value
36}));
37
38fs.writeFileSync('extracted-keys.json', JSON.stringify(output, null, 2));

Slack and Email Notifications

Slack Notification Patterns

Pattern 1: New Translation Tasks Notify translators in Slack channel when new keys need translation.

JavaScript
1const { WebClient } = require('@slack/web-api');
2const slack = new WebClient(process.env.SLACK_BOT_TOKEN);
3
4async function notifyNewTranslations(language, keyCount) {
5  await slack.chat.postMessage({
6    channel: '#translations',
7    text: `🌐 New translation task available`,
8    blocks: [
9      {
10        type: 'section',
11        text: {
12          type: 'mrkdwn',
13          text: `*New translations needed*\n${keyCount} keys require translation to *${language}*`
14        }
15      },
16      {
17        type: 'actions',
18        elements: [
19          {
20            type: 'button',
21            text: { type: 'plain_text', text: 'Start Translating' },
22            url: `https://app.intlpull.com/translate/${language}`,
23            style: 'primary'
24          }
25        ]
26      }
27    ]
28  });
29}

Pattern 2: Translation Completion Alerts Notify product team when language reaches 100% completion.

JavaScript
1async function notifyCompletionMilestone(language, projectName) {
2  await slack.chat.postMessage({
3    channel: '#product',
4    text: `${language} translations complete for ${projectName}!`,
5    blocks: [
6      {
7        type: 'section',
8        text: {
9          type: 'mrkdwn',
10          text: `:tada: *Translation milestone reached*\n${language} translations are now 100% complete for *${projectName}*. Ready for deployment!`
11        }
12      }
13    ]
14  });
15}

Pattern 3: Quality Issue Alerts Escalate quality check failures to translation leads.

JavaScript
1async function notifyQualityIssues(issues) {
2  const issueList = issues.map(i => `${i.key}: ${i.message}`).join('\n');
3
4  await slack.chat.postMessage({
5    channel: '#translation-quality',
6    text: `⚠️ Translation quality issues detected`,
7    blocks: [
8      {
9        type: 'section',
10        text: {
11          type: 'mrkdwn',
12          text: `*Quality check failures*\n${issueList}`
13        }
14      }
15    ]
16  });
17}

Email Notification System

Automated Email on Assignment:

JavaScript
1const nodemailer = require('nodemailer');
2
3const transporter = nodemailer.createTransport({
4  host: process.env.SMTP_HOST,
5  port: 587,
6  auth: {
7    user: process.env.SMTP_USER,
8    pass: process.env.SMTP_PASS
9  }
10});
11
12async function emailTranslationAssignment(translator, language, keyCount) {
13  await transporter.sendMail({
14    from: '"IntlPull" <noreply@intlpull.com>',
15    to: translator.email,
16    subject: `New translation task: ${keyCount} keys in ${language}`,
17    html: `
18      <h2>New Translation Assignment</h2>
19      <p>Hello ${translator.name},</p>
20      <p>You have been assigned ${keyCount} new translation keys for <strong>${language}</strong>.</p>
21      <p><a href="https://app.intlpull.com/translate/${language}">Start Translating →</a></p>
22      <p>Deadline: ${translator.deadline}</p>
23    `
24  });
25}

Auto-Publishing Translations

Automatic Deployment on Approval

Workflow:

  1. Translation approved in TMS
  2. Webhook triggers deployment pipeline
  3. Translations exported and committed to repository
  4. Automated build and deployment initiated
  5. New translations live in production

Deployment Script:

JavaScript
1async function deployTranslations(projectId, language) {
2  // 1. Export translations from IntlPull
3  const response = await fetch(
4    `https://api.intlpull.com/v1/projects/${projectId}/export?language=${language}`,
5    { headers: { 'X-API-Key': process.env.INTLPULL_API_KEY } }
6  );
7
8  const translations = await response.json();
9
10  // 2. Write to file system
11  fs.writeFileSync(
12    `./public/locales/${language}.json`,
13    JSON.stringify(translations, null, 2)
14  );
15
16  // 3. Build application
17  execSync('npm run build');
18
19  // 4. Deploy to hosting (example: Vercel)
20  execSync('vercel --prod');
21
22  // 5. Invalidate CDN cache
23  await invalidateCDN(`/locales/${language}.json`);
24}

Staged Deployments

Workflow:

  1. Translations approved → Deploy to staging automatically
  2. QA team validates on staging
  3. Manual approval triggers production deployment

GitHub Actions Multi-Environment:

YAML
1name: Deploy Translations
2
3on:
4  repository_dispatch:
5    types: [translation_approved]
6
7jobs:
8  deploy-staging:
9    runs-on: ubuntu-latest
10    environment: staging
11    steps:
12      - name: Deploy to staging
13        run: ./deploy.sh staging
14
15  deploy-production:
16    runs-on: ubuntu-latest
17    needs: deploy-staging
18    environment: production
19    steps:
20      - name: Deploy to production
21        run: ./deploy.sh production

GitHub Actions for i18n

Action 1: Validate Translation Files

YAML
1name: Validate Translations
2
3on:
4  pull_request:
5    paths:
6      - 'locales/**'
7
8jobs:
9  validate:
10    runs-on: ubuntu-latest
11    steps:
12      - uses: actions/checkout@v3
13
14      - name: Validate JSON syntax
15        run: |
16          for file in locales/**/*.json; do
17            echo "Validating $file"
18            jq empty "$file" || exit 1
19          done
20
21      - name: Check for missing keys
22        run: npm run i18n:check-missing
23
24      - name: Validate placeholders
25        run: npm run i18n:check-placeholders

Action 2: Auto-Generate Missing Translations with MT

YAML
1name: Generate Missing Translations
2
3on:
4  schedule:
5    - cron: '0 2 * * *'  # Daily at 2 AM
6
7jobs:
8  auto-translate:
9    runs-on: ubuntu-latest
10    steps:
11      - uses: actions/checkout@v3
12
13      - name: Find missing translations
14        id: missing
15        run: |
16          npm run i18n:find-missing > missing.json
17
18      - name: Generate translations via IntlPull API
19        if: steps.missing.outputs.count > 0
20        run: |
21          curl -X POST "https://api.intlpull.com/v1/projects/$PROJECT_ID/auto-translate" \
22            -H "X-API-Key: ${{ secrets.INTLPULL_API_KEY }}" \
23            -d @missing.json
24
25      - name: Download generated translations
26        run: |
27          curl -X GET "https://api.intlpull.com/v1/projects/$PROJECT_ID/export" \
28            -H "X-API-Key: ${{ secrets.INTLPULL_API_KEY }}" \
29            -o translations.zip
30
31      - name: Create PR
32        uses: peter-evans/create-pull-request@v5
33        with:
34          title: 'i18n: auto-generated translations'
35          body: 'Machine-generated translations for missing keys. Review required.'

Action 3: Translation Coverage Report

YAML
1name: Translation Coverage
2
3on:
4  push:
5    branches: [main]
6  pull_request:
7
8jobs:
9  coverage:
10    runs-on: ubuntu-latest
11    steps:
12      - uses: actions/checkout@v3
13
14      - name: Calculate coverage
15        id: coverage
16        run: |
17          npm run i18n:coverage > coverage.json
18
19      - name: Comment PR with coverage
20        if: github.event_name == 'pull_request'
21        uses: actions/github-script@v6
22        with:
23          script: |
24            const coverage = require('./coverage.json');
25            const body = `## Translation Coverage\n\n${Object.entries(coverage).map(([lang, pct]) => `- ${lang}: ${pct}%`).join('\n')}`;
26
27            github.rest.issues.createComment({
28              issue_number: context.issue.number,
29              owner: context.repo.owner,
30              repo: context.repo.repo,
31              body
32            });

IntlPull's Webhook and API Capabilities

IntlPull provides comprehensive automation infrastructure to enable fully automated translation workflows without custom development overhead.

Webhook Events

IntlPull fires webhooks for all critical events:

  • Translation CRUD operations (created, updated, approved, rejected)
  • Key lifecycle (created, updated, deleted)
  • Language additions/removals
  • Import/export completions
  • Project changes

Configure webhook endpoints in IntlPull dashboard, and receive real-time notifications for all translation activity.

Comprehensive REST API

Translation Management:

  • Create/update/delete translation keys
  • Fetch translations by key, language, or project
  • Bulk operations for efficiency
  • Search and filter with advanced queries

Workflow Automation:

  • Trigger auto-translation for specific languages
  • Export translations in multiple formats
  • Import translations from external systems
  • Manage translation assignments and approvals

Analytics and Reporting:

  • Translation progress by language
  • Translator productivity metrics
  • Quality check results
  • Missing translation reports

GitHub Integration

IntlPull's native GitHub integration automates bidirectional sync:

  • Detects new translation keys from commits
  • Automatically creates translation tasks
  • Commits completed translations via pull requests
  • Syncs on configurable schedules or event triggers

No custom webhook handlers or API code required—IntlPull handles sync automatically.

Slack Integration

Connect IntlPull to Slack for automated notifications:

  • New translation assignments posted to channels
  • Completion milestones celebrated
  • Quality issues escalated
  • Daily/weekly progress summaries

Configure notification preferences and channel routing in IntlPull dashboard.

By providing these automation primitives out-of-box, IntlPull enables sophisticated workflows without requiring teams to build and maintain custom integration code.

Frequently Asked Questions

How do I prevent webhook duplicates from causing issues?

Implement idempotency in webhook handlers using unique webhook IDs. Store processed webhook IDs in database or cache, and skip processing if ID already seen. Most TMS platforms include unique ID in webhook payload. Also ensure handlers are safe to run multiple times (idempotent operations).

Should I use webhooks or polling for translation updates?

Use webhooks for real-time automation (notification, immediate deployment). Use polling for less time-sensitive operations (nightly sync, reporting). Webhooks reduce latency and server load compared to frequent polling. However, polling provides simpler implementation for teams without webhook infrastructure.

How can I test webhook handlers locally during development?

Use tools like ngrok or localtunnel to expose local development server to internet with temporary public URL. Configure TMS to send webhooks to ngrok URL. Test webhook handling locally before deploying to production. Many TMS platforms also provide webhook testing/replay features in their dashboard.

What happens if my webhook endpoint is down?

Most TMS platforms retry failed webhooks with exponential backoff for 24-48 hours. Monitor webhook delivery logs in TMS dashboard to detect failures. Implement health checks and alerting for webhook endpoints. For critical workflows, consider message queue backup (TMS publishes to queue, your workers process asynchronously).

Can I automate translator assignments based on workload?

Yes, use APIs to query current translator workloads (pending task counts) and assign new tasks to translators with capacity. Implement round-robin, least-busy-first, or language expertise-based assignment algorithms. IntlPull's API provides translator status and task metrics for building intelligent assignment logic.

How do I handle merge conflicts when automatically committing translations?

Use git strategies like rebase or merge, and configure automated conflict resolution for simple cases (e.g., accept incoming changes for translation files). For complex conflicts, create pull request instead of direct commit, allowing human review. Organize translations by namespace/feature to minimize conflicts.

Should automated translations be auto-approved or require review?

Machine-translated content should require human review before deployment. Auto-approve only trusted translator submissions that pass all quality checks. Configure approval rules based on translator seniority, key importance (critical UI vs. help docs), and QA check results. Balance speed with quality based on content type.

Tags
automation
webhooks
ci-cd
api
workflow
integration
devops
localization
IntlPull Team
IntlPull Team
Engineering

Building tools to help teams ship products globally. Follow us for more insights on localization and i18n.