Back to blog

Python for Localization: Automating Away Manual Work

Python is one of the most powerful tools for localization engineers. Here's how to leverage it to eliminate manual work and scale your workflows.

January 5, 2024
5 min read
#localization#python#automation#engineering#tools

Localization engineering often feels like a series of manual, repetitive tasks: extracting strings from code, checking for consistency, validating formats, updating translation files, comparing versions. Each task is mechanical. Each task takes hours. Most teams do them by hand.

That's where Python comes in.

Why Python for Localization?

Python prioritizes readability and practicality over complexity. For localization engineers, this means:

  • Low barrier to entry — You don't need a computer science degree to write useful scripts
  • Vast ecosystem — Libraries for almost any localization task
  • Cross-platform — Run the same script on Windows, Mac, Linux
  • Automation — Schedule scripts via cron or task scheduler
  • Integration — Connect with CI/CD pipelines, APIs, and existing tools

Most importantly: Python lets non-developers automate their work.

Common Automation Tasks

String Extraction and Management

Most development frameworks don't automatically handle string extraction. You're left doing it manually:

import os, re, json

def extract_strings_from_code(directory):
    strings = {}
    pattern = r't\(["\']([^"\']+)["\']\)'
    
    for root, dirs, files in os.walk(directory):
        for file in files:
            if file.endswith(('.js', '.jsx', '.tsx')):
                filepath = os.path.join(root, file)
                with open(filepath, 'r') as f:
                    content = f.read()
                    matches = re.findall(pattern, content)
                    for match in matches:
                        strings[match] = match
    
    with open('strings.json', 'w') as f:
        json.dump(strings, f, indent=2, ensure_ascii=False)
    
    return len(strings)

count = extract_strings_from_code('./src')
print(f"Extracted {count} strings")

What took hours manually now takes seconds. Run it as part of CI/CD? Automatic.

Terminology Consistency Checking

You have a terminology database. A translator uses "Login" in one screen and "Sign in" in another. Finding inconsistencies manually is tedious:

import json, os
from collections import defaultdict

def check_terminology(translations_dir, terminology_file):
    with open(terminology_file) as f:
        terms = json.load(f)
    
    mismatches = defaultdict(list)
    
    for locale in os.listdir(translations_dir):
        locale_file = os.path.join(translations_dir, locale, 'strings.json')
        if not os.path.exists(locale_file):
            continue
            
        with open(locale_file) as f:
            translations = json.load(f)
        
        for english_term, approved_translation in terms.items():
            for string_id, translated_text in translations.items():
                if english_term in translated_text and approved_translation not in translated_text:
                    mismatches[locale].append({
                        'string': string_id,
                        'found': english_term,
                        'should_be': approved_translation
                    })
    
    for locale, issues in mismatches.items():
        print(f"\n{locale}: {len(issues)} mismatches")
        for issue in issues[:5]:
            print(f"  - {issue['string']}: '{issue['found']}' should be '{issue['should_be']}'")

check_terminology('./translations', 'terminology.json')

Consistency checking that took a full day of manual review now happens in seconds.

Translation Completeness Monitoring

How many strings are translated? Which languages are complete?

import os, json

def translation_status(translations_dir, source_file='en.json'):
    with open(source_file) as f:
        source_count = len(json.load(f))
    
    status = {}
    
    for locale in os.listdir(translations_dir):
        locale_file = os.path.join(translations_dir, locale, 'strings.json')
        if not locale_file.endswith('.json'):
            continue
            
        with open(locale_file) as f:
            translated = sum(1 for v in json.load(f).values() if v)
        
        percentage = (translated / source_count) * 100
        status[locale] = {
            'translated': translated,
            'total': source_count,
            'percentage': round(percentage, 1),
            'missing': source_count - translated
        }
    
    for locale, data in sorted(status.items(), key=lambda x: x[1]['percentage'], reverse=True):
        bar = '█' * int(data['percentage'] / 5) + '░' * (20 - int(data['percentage'] / 5))
        print(f"{locale:10} {bar} {data['percentage']:5.1f}% ({data['missing']} missing)")

translation_status('./translations')

Output:

de         ████████████████████ 100.0% (0 missing)
fr         ████████████████████ 100.0% (0 missing)
es         ██████████████████░░  92.3% (15 missing)
ja         ██████████████░░░░░░  75.0% (50 missing)

Now you have real-time status visibility.

Format Validation

Ensure translations maintain source format (variables, HTML tags, punctuation):

import re

def validate_format(source, translation):
    errors = []
    
    source_vars = re.findall(r'\{[^}]+\}', source)
    trans_vars = re.findall(r'\{[^}]+\}', translation)
    
    if source_vars != trans_vars:
        errors.append(f"Variable mismatch: {source_vars} vs {trans_vars}")
    
    source_tags = re.findall(r'<[^>]+>', source)
    trans_tags = re.findall(r'<[^>]+>', translation)
    
    if source_tags != trans_tags:
        errors.append(f"HTML tag mismatch: {source_tags} vs {trans_tags}")
    
    if source.endswith('.') and not translation.endswith('.'):
        errors.append("Period missing in translation")
    
    return errors

source = "Welcome, {name}! Click <a href='#'>here</a>."
trans_bad = "¡Bienvenido, {nombre} Haz clic aquí"

for error in validate_format(source, trans_bad):
    print(f"❌ {error}")

Catches format issues before they reach production.

Real-World Impact

Here's what I typically see when teams move from manual to automated localization:

TaskManualAutomated
String extraction2-4 hrs/week0 (runs in CI/CD)
Consistency checking4-6 hrs/week0 (automated)
Completeness reports1-2 hrs/weekautomated
Format validation2-3 hrs/week0 (catches on commit)
Translation sync1-2 hrs/week0 (automatic)
Total saved10-17 hrs/weekNear zero

That's 40-68 hours per month freed up for strategy and quality work.

Getting Started

You don't need to be a developer:

  1. Start small — Write a script to extract strings from your specific file format
  2. Solve one pain point — Maybe it's consistency checking or completeness reporting
  3. Iterate — Add more automation as you get comfortable
  4. Integrate — Hook into your CI/CD pipeline for automatic execution

Python has fantastic libraries for localization: babel for Unicode and localization utilities, polib for .po/.pot files, ruamel.yaml for YAML handling, openpyxl for Excel, requests for API integrations.

The Localization Engineer's Superpower

Python is how you multiply your impact. You can't manually manage 50 languages while maintaining quality. But you can write scripts that work across 50 languages while you focus on strategy, quality, and ensuring cultural appropriateness.

When I design localization solutions, automation is always part of the architecture. Not "nice to have"—essential.

The teams that scale globally aren't doing more manual work. They've systematically automated the mechanical parts so they can focus on what matters: quality, consistency, and cultural fit.