The Agile Localization Problem
Your team ships features every sprint. But translations lag behind by weeks:
Sprint 1:
- ✅ Feature coded
- ✅ Deployed to production
- ❌ Only in English
Sprint 3:
- ❌ Translations finally arrive
- ❌ Original code has changed
- ❌ Context is lost
- ❌ Developers frustrated
Sound familiar? You're doing waterfall localization in an agile environment.
The solution: Continuous Localization. Treat translation as part of your deployment pipeline, not a separate process.
What is Continuous Localization?
Continuous Localization means:
- Developers code features and extract translatable strings
- Strings automatically sync to translators
- Translations flow back into the codebase automatically
- Features deploy in all languages simultaneously
Old way (Waterfall):
Code → QA → Deploy → Extract strings → Wait 2 weeks → Translate → Re-deploy
New way (Continuous):
Code → Auto-extract → Auto-translate → QA → Deploy (all languages)
Result: Features launch globally from day one, not weeks later.
Why Continuous Localization Matters
Business Impact
| Metric | Traditional | Continuous | Improvement |
|---|---|---|---|
| Time to market (multilingual) | 4-8 weeks | 0-3 days | 90% faster |
| Translation costs | $0.15/word | $0.08/word | 47% cheaper |
| Developer time on i18n | 8 hrs/sprint | 1 hr/sprint | 87% reduction |
| Translation errors | 15-20% | 3-5% | 75% fewer errors |
Source: Compilation of studies from Nimdzi, CSA Research, and internal data
Developer Benefits
- ✅ No more manual string extraction
- ✅ No chasing translators for updates
- ✅ No merge conflicts from translation PRs
- ✅ No "we'll translate it later" tech debt
Product/Business Benefits
- ✅ Launch in all markets simultaneously
- ✅ Faster feedback loops from international users
- ✅ Consistent brand voice across languages
- ✅ Reduced context-switching for translators
The Continuous Localization Pipeline
Here's the complete workflow:
┌─────────────────────────────────────────────────────────────┐
│ 1. DEVELOPER │
│ - Codes feature │
│ - Uses t('key') for strings │
│ - Commits to Git │
└─────────────────┬───────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 2. CI PIPELINE (GitHub Actions, etc.) │
│ - Auto-extracts new keys │
│ - Pushes to TMS (IntlPull, etc.) │
│ - Triggers translation workflow │
└─────────────────┬───────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 3. TRANSLATION MANAGEMENT SYSTEM │
│ - AI pre-translates (80% done instantly) │
│ - Translation memory fills gaps │
│ - Alerts translators to review │
└─────────────────┬───────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 4. TRANSLATORS │
│ - See context (screenshots, usage) │
│ - Review AI translations │
│ - Approve or edit │
└─────────────────┬───────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 5. WEBHOOK → CI/CD │
│ - TMS pings webhook on translation complete │
│ - Auto-downloads updated translations │
│ - Creates PR or deploys directly │
└─────────────────┬───────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 6. PRODUCTION │
│ - Feature live in all languages │
│ - Zero developer intervention │
└─────────────────────────────────────────────────────────────┘
Key insight: Developers never touch translation files. The pipeline handles it.
Step 1: Set Up String Extraction
First, configure automatic string extraction in your CI/CD.
For React/Next.js Projects
Install IntlPull CLI:
Terminalnpm install -D @intlpullhq/cli
Configure (.intlpull.json):
JSON1{ 2 "projectId": "proj_abc123", 3 "sourceLanguage": "en", 4 "targetLanguages": ["es", "fr", "de", "ja"], 5 "format": "json", 6 "outputDir": "locales", 7 "extractPatterns": [ 8 "src/**/*.{ts,tsx,js,jsx}", 9 "!src/**/*.test.{ts,tsx}" 10 ], 11 "scanConfig": { 12 "functions": ["t", "i18n.t", "useTranslation"], 13 "extractComments": true 14 } 15}
Test upload:
Terminalnpx @intlpullhq/cli status
This shows translation coverage and missing keys.
Step 2: Automate CI/CD Integration
GitHub Actions Example
Create .github/workflows/i18n-sync.yml:
YAML1name: Continuous Localization 2 3on: 4 push: 5 branches: [main, develop] 6 pull_request: 7 branches: [main] 8 9jobs: 10 # Job 1: Extract and upload new strings 11 extract-upload: 12 runs-on: ubuntu-latest 13 steps: 14 - uses: actions/checkout@v3 15 16 - name: Setup Node 17 uses: actions/setup-node@v3 18 with: 19 node-version: '18' 20 cache: 'npm' 21 22 - name: Install dependencies 23 run: npm ci 24 25 - name: Upload to IntlPull 26 run: npx @intlpullhq/cli upload 27 env: 28 INTLPULL_API_KEY: ${{ secrets.INTLPULL_API_KEY }} 29 30 - name: Check translation coverage 31 run: | 32 COVERAGE=$(npx @intlpullhq/cli status --json | jq -r '.coverage') 33 echo "Translation coverage: ${COVERAGE}%" 34 35 if [ $COVERAGE -lt 90 ]; then 36 echo "⚠️ Warning: Translation coverage below 90%" 37 fi 38 39 # Job 2: Download latest translations 40 download-translations: 41 runs-on: ubuntu-latest 42 if: github.event_name == 'push' 43 steps: 44 - uses: actions/checkout@v3 45 46 - name: Setup Node 47 uses: actions/setup-node@v3 48 with: 49 node-version: '18' 50 51 - name: Download translations 52 run: npx @intlpullhq/cli download 53 env: 54 INTLPULL_API_KEY: ${{ secrets.INTLPULL_API_KEY }} 55 56 - name: Create PR if changes 57 uses: peter-evans/create-pull-request@v5 58 with: 59 commit-message: 'chore: update translations' 60 title: '🌍 Translation Update' 61 body: | 62 Automated translation sync from IntlPull. 63 64 **Changes:** 65 - Downloaded latest translations 66 - Translation coverage: See workflow logs 67 68 **Next steps:** 69 - Review and merge 70 - Translations will deploy on next release 71 branch: i18n-auto-update 72 labels: i18n, automated
What this does:
- On every commit: extracts new strings → uploads to IntlPull
- Every 6 hours: downloads latest translations → creates PR
- Developers review PR → merge → deploy
Step 3: Set Up Webhook for Real-Time Updates
Instead of polling every 6 hours, use webhooks for instant updates.
Configure IntlPull Webhook
In IntlPull dashboard:
- Go to Settings → Webhooks
- Add webhook URL:
https://api.github.com/repos/your-org/your-repo/dispatches - Select events:
translation.approved,language.completed - Add GitHub token with
reposcope
GitHub Workflow for Webhook
.github/workflows/translation-webhook.yml:
YAML1name: Translation Webhook Handler 2 3on: 4 repository_dispatch: 5 types: [translation-update] 6 7jobs: 8 sync: 9 runs-on: ubuntu-latest 10 steps: 11 - uses: actions/checkout@v3 12 13 - name: Download translations 14 run: npx @intlpullhq/cli download 15 env: 16 INTLPULL_API_KEY: ${{ secrets.INTLPULL_API_KEY }} 17 18 - name: Commit and push 19 run: | 20 git config user.name "i18n-bot" 21 git config user.email "bot@intlpull.com" 22 git add locales/ 23 git commit -m "chore: sync translations [skip ci]" || exit 0 24 git push
Now: As soon as a translator approves a translation, it auto-deploys to your repo.
Step 4: Integrate with Development Workflow
Pre-commit Hooks
Prevent commits with missing translations:
Terminalnpm install -D husky lint-staged
JSON1// package.json 2{ 3 "lint-staged": { 4 "src/**/*.{ts,tsx}": [ 5 "eslint --fix" 6 ] 7 } 8}
What it does: If you add t('new.key') but forget to extract it, commit fails.
PR Checks
Add translation coverage checks to PRs:
YAML1# .github/workflows/pr-checks.yml 2name: PR Checks 3 4on: pull_request 5 6jobs: 7 translation-coverage: 8 runs-on: ubuntu-latest 9 steps: 10 - uses: actions/checkout@v3 11 12 - name: Check translation coverage 13 run: | 14 npx @intlpullhq/cli status --format json > coverage.json 15 16 MISSING=$(jq -r '.missing | length' coverage.json) 17 18 if [ $MISSING -gt 0 ]; then 19 echo "❌ $MISSING untranslated keys found" 20 exit 1 21 fi 22 23 echo "✅ All keys translated"
Result: PRs can't merge until translations are complete.
Step 5: AI Pre-Translation
AI translates 80-90% of your strings instantly. Humans review the rest.
Enable AI Translation in IntlPull
Terminal1# .intlpull.json 2{ 3 "ai": { 4 "enabled": true, 5 "provider": "claude-3.5-sonnet", 6 "fallback": "gpt-4o", 7 "autoApprove": { 8 "threshold": 0.95, // Auto-approve if confidence > 95% 9 "languages": ["es", "fr", "de"] // Only for similar languages 10 } 11 } 12}
Workflow:
- New key added:
t('product.new_feature') - IntlPull detects it
- AI translates to Spanish/French/German instantly
- High confidence? Auto-approve
- Low confidence? Flag for human review
Cost: ~$0.01 per 1,000 words (vs $0.15 for human translation)
Speed: Instant vs 2-3 days
Step 6: Set Up Translation Memory
Avoid re-translating the same phrases.
How Translation Memory Works
First time:
- Translate "Add to cart" → "Añadir al carrito" (costs $0.05)
Second time:
- Detect "Add to cart" in new component
- Reuse existing translation (costs $0)
Partial match:
- "Add to wishlist" detected
- TM suggests: "Añadir a..." (70% match)
- Translator completes: "Añadir a la lista de deseos"
Configure TM in IntlPull
JSON1{ 2 "translationMemory": { 3 "enabled": true, 4 "minMatchScore": 0.75, 5 "autoApplyPerfectMatches": true, 6 "sources": [ 7 "current-project", 8 "organization-wide", 9 "public-domain" // Free TM from open source 10 ] 11 } 12}
Savings: 30-50% cost reduction after 6 months
Step 7: Monitor Translation Status
Dashboard Metrics
Track these KPIs:
| Metric | Target | Why It Matters |
|---|---|---|
| Translation Coverage | >95% | Features can't ship incomplete |
| Time to Translate | <24 hrs | Faster releases |
| Cost per Word | <$0.10 | Budget efficiency |
| Translator SLA | <48 hrs | Predictable timelines |
| Missing Key Rate | <1% | Quality control |
Slack Notifications
Get alerted when translations are ready:
YAML1# GitHub Action 2- name: Notify Slack 3 if: steps.download.outcome == 'success' 4 uses: slackapi/slack-github-action@v1 5 with: 6 payload: | 7 { 8 "text": "🌍 Translations updated", 9 "blocks": [ 10 { 11 "type": "section", 12 "text": { 13 "type": "mrkdwn", 14 "text": "*Translation Update* 15 16Languages: ES, FR, DE 17Coverage: 98% 18 19<https://github.com/${{ github.repository }}/pull/123|Review PR>" 20 } 21 } 22 ] 23 } 24 env: 25 SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
Real-World Examples
Example 1: SaaS Company (React + Next.js)
Before Continuous Localization:
- 2-week delay for translations
- 4 hours/week managing translation spreadsheets
- 10% of keys untranslated at launch
After:
- Features ship in all languages simultaneously
- 20 minutes/week on i18n (automated checks)
- 99% translation coverage
Setup:
- GitHub Actions for CI/CD
- IntlPull for TMS
- Claude AI for pre-translation (Spanish, French)
- Human review for German, Japanese
ROI: Saved 15 hours/week × $100/hr = $6,000/month
Example 2: Mobile App (React Native)
Challenge: App updates every 2 weeks. Translations lag by 4 weeks.
Solution: OTA (Over-The-Air) translation updates
JavaScript1// app.tsx 2import { IntlPullOTA } from '@intlpullhq/react-native'; 3 4useEffect(() => { 5 // Check for translation updates on app start 6 IntlPullOTA.sync({ 7 projectId: 'proj_abc123', 8 currentVersion: '1.2.0', 9 }).then((updated) => { 10 if (updated) { 11 console.log('Translations updated!'); 12 // Optionally reload UI 13 } 14 }); 15}, []);
Result:
- Translations update without app store approval
- Users get new languages within hours
- 50% faster localization cycle
Common Pitfalls
1. Not Involving Translators Early
Mistake: Translators only see strings after code is done.
Fix: Share Figma designs and context early. Use IntlPull's screenshot feature:
```bash
Upload screenshots via the IntlPull Dashboard
Or use the API to upload screenshots from your CI pipeline
```
Translators see where the text appears → better translations.
2. Over-Automating Quality Checks
Mistake: Auto-approving all AI translations.
Fix: Set confidence thresholds:
JSON1{ 2 "autoApprove": { 3 "threshold": 0.95, 4 "languages": ["es", "fr", "pt"], // Similar to English 5 "exclude": ["ja", "ar", "zh"] // Always human-review these 6 } 7}
3. Ignoring Context
Mistake: Translator sees "Save". Is it "save a file" or "save money"?
Fix: Add comments in code:
TypeScript1// Context appears in TMS automatically 2t('actions.save', { 3 // Translators will see this 4 _comment: 'Button to save document, not save money', 5});
Or use namespaces:
JSON1{ 2 "file.save": "Save", 3 "checkout.save": "Save 20%" 4}
4. No Rollback Plan
Mistake: Bad translation goes to production, no way to revert.
Fix: Use versioned releases:
Terminal1# Tag translations with release version 2npx @intlpullhq/cli release create v1.2.0 3 4# Rollback if needed 5npx @intlpullhq/cli release rollback v1.1.0
Advanced: Multi-Branch Translation Strategy
Challenge
You have:
mainbranch (production)developbranch (staging)- Feature branches
How do you manage translations across branches?
Solution: Branch-Based Translation Syncing
JSON1// .intlpull.json 2{ 3 "branches": { 4 "main": { 5 "requireApproval": true, // Human review required 6 "autoMerge": false 7 }, 8 "develop": { 9 "requireApproval": false, // AI auto-approve 10 "autoMerge": true 11 }, 12 "feature/*": { 13 "inheritFrom": "develop" 14 } 15 } 16}
Workflow:
- Feature branch: AI translates, auto-merges
- Develop: AI + quick human review
- Main: Full human review before production
Measuring Success
Track these metrics 3 months after implementing continuous localization:
| Metric | Baseline | Target | How to Measure |
|---|---|---|---|
| Time to translate | 2 weeks | 48 hours | IntlPull analytics |
| Developer time on i18n | 8 hrs/sprint | 1 hr/sprint | Time tracking |
| Translation cost | $0.15/word | $0.08/word | Invoice analysis |
| Bug reports (i18n) | 15/month | 3/month | Issue tracker |
| Translation coverage | 85% | 98% | npx @intlpullhq/cli status |
Expected ROI: 300-500% in first year
Continuous Localization Checklist
Infrastructure:
- ✅ CI/CD extracts strings automatically
- ✅ TMS integrated (IntlPull, Crowdin, etc.)
- ✅ Webhooks configured for instant sync
- ✅ OTA updates enabled (mobile apps)
Workflow:
- ✅ Pre-commit hooks prevent untranslated keys
- ✅ PR checks enforce translation coverage
- ✅ AI pre-translation enabled
- ✅ Translation memory configured
- ✅ Context (screenshots, comments) provided
Monitoring:
- ✅ Dashboard tracks coverage, cost, SLA
- ✅ Slack/email notifications on updates
- ✅ Weekly reports to stakeholders
- ✅ Rollback plan for bad translations
Team:
- ✅ Developers trained on
t()usage - ✅ Translators have access to TMS
- ✅ Product team reviews key copy
- ✅ Stakeholders understand ROI
Next Steps
- Audit current state: How long does localization take now?
- Pick a pilot project: Start with one repo, one language
- Set up IntlPull: Get started here
- Configure CI/CD: Use the GitHub Actions example above
- Enable AI translation: Cut costs by 50%+
- Measure results: Track time, cost, coverage
- Scale: Add more languages and repos
Want help? Contact us for a consultation. We'll review your setup and show you exactly how to implement continuous localization.
Further Reading
- Best AI Translation Tools Comparison
- GitHub Actions for i18n
- Best Practices Managing Translation Keys
- Machine Translation Accuracy Benchmark
Continuous localization isn't just faster. it's how modern agile teams ship global products. Start today.
