Warum Lokalisierung automatisieren?#
Manuelle Lokalisierungs-Workflows sind der Flaschenhals in den Release-Zyklen der meisten Teams:
Entwickler: "Ich habe das Update gepusht."
PM: "Hast du die neuen Strings an den Übersetzer geschickt?"
Entwickler: "...mache ich jetzt."
PM: "Wann kommen die Übersetzungen zurück?"
Entwickler: "Vielleicht nächste Woche?"
Indem du Lokalisierung in deine CI/CD Pipeline integrierst, werden neue Strings automatisch übersetzt und deine lokalisierte App ist immer versandbereit.
Das Ziel: Kontinuierliche Lokalisierung#
Vor der Automatisierung:
Code → Manueller Export → E-Mail an Übersetzer → Tage warten → Manueller Import → Test → Deploy
Nach der Automatisierung:
Code → Push → CI erkennt neue Strings → Auto-Übersetzen → PR mit Übersetzungen → Merge → Deploy
Der Unterschied: Tage vs. Minuten.
Architektur-Überblick#
Eine typische automatisierte Lokalisierungs-Pipeline hat drei Komponenten:
- String-Erkennung: Neue oder geänderte Strings in deinem Commit identifizieren
- Übersetzung: Strings an deinen Übersetzungsservice senden (shipglobal.dev)
- Integration: Übersetzte Dateien zurück in dein Repository committen
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Git Push │ → │ CI Pipeline │ → │ Übersetzen │
│ (neue │ │ (Änderungen │ │ (API-Aufruf)│
│ Strings) │ │ erkennen) │ └──────┬──────┘
└─────────────┘ └──────────────┘ │
▼
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Merge │ ← │ PR mit │ ← │ Übersetzungen│
│ │ │ Übersetzungen│ │ committen │
└─────────────┘ └──────────────┘ └─────────────┘
Implementierung: GitHub Actions#
Hier ist ein praktischer GitHub Actions Workflow, der neue Strings bei jedem Push übersetzt:
Basis-Workflow#
# .github/workflows/localize.yml
name: Localize
on:
push:
branches: [main, develop]
paths:
- 'src/locales/en/**' # Englische Quelldateien beobachten
- 'src/strings/en.json' # Oder deine spezifische Datei
jobs:
translate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Auf String-Änderungen prüfen
id: changes
run: |
# Erkennen ob Quellsprach-Dateien geändert wurden
CHANGED=$(git diff --name-only HEAD~1 HEAD -- src/locales/en/)
echo "changed_files=$CHANGED" >> $GITHUB_OUTPUT
if [ -z "$CHANGED" ]; then
echo "has_changes=false" >> $GITHUB_OUTPUT
else
echo "has_changes=true" >> $GITHUB_OUTPUT
fi
- name: Über shipglobal.dev API übersetzen
if: steps.changes.outputs.has_changes == 'true'
env:
SHIPGLOBAL_API_KEY: ${{ secrets.SHIPGLOBAL_API_KEY }}
run: |
# Quelldatei hochladen und Übersetzungen abrufen
for lang in de es fr ja pt; do
curl -X POST https://api.shipglobal.dev/v1/translate \
-H "Authorization: Bearer $SHIPGLOBAL_API_KEY" \
-F "file=@src/locales/en/strings.json" \
-F "target_language=$lang" \
-o "src/locales/$lang/strings.json"
done
- name: Pull Request erstellen
if: steps.changes.outputs.has_changes == 'true'
uses: peter-evans/create-pull-request@v5
with:
title: 'chore: Übersetzungen aktualisieren'
body: 'Automatisiertes Übersetzungs-Update ausgelöst durch Änderungen an englischen Quellstrings.'
branch: translations/auto-update
commit-message: 'chore: Übersetzungen für neueste String-Änderungen aktualisieren'
Erweiterter Workflow mit Validierung#
# .github/workflows/localize-advanced.yml
name: Localize (Advanced)
on:
push:
branches: [main]
paths:
- 'src/locales/en/**'
jobs:
translate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Node.js einrichten
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Neue Strings erkennen
id: detect
run: |
# Aktuelle und vorherige englische Strings vergleichen
git show HEAD~1:src/locales/en/strings.json > /tmp/old_strings.json 2>/dev/null || echo '{}' > /tmp/old_strings.json
NEW_KEYS=$(node -e "
const old = require('/tmp/old_strings.json');
const curr = require('./src/locales/en/strings.json');
const newKeys = Object.keys(curr).filter(k => !old[k] || old[k] !== curr[k]);
console.log(newKeys.length);
")
echo "new_key_count=$NEW_KEYS" >> $GITHUB_OUTPUT
- name: Neue Strings übersetzen
if: steps.detect.outputs.new_key_count > 0
env:
SHIPGLOBAL_API_KEY: ${{ secrets.SHIPGLOBAL_API_KEY }}
run: |
TARGET_LANGUAGES="de es fr ja pt ko it"
for lang in $TARGET_LANGUAGES; do
curl -X POST https://api.shipglobal.dev/v1/translate \
-H "Authorization: Bearer $SHIPGLOBAL_API_KEY" \
-F "file=@src/locales/en/strings.json" \
-F "target_language=$lang" \
-o "src/locales/$lang/strings.json"
done
- name: Übersetzungen validieren
run: |
# Alle Übersetzungsdateien auf gültiges JSON prüfen
for file in src/locales/*/strings.json; do
python3 -m json.tool "$file" > /dev/null || {
echo "Ungültiges JSON: $file"
exit 1
}
done
# Prüfen ob alle Dateien die gleichen Keys haben
node -e "
const fs = require('fs');
const en = Object.keys(require('./src/locales/en/strings.json')).sort();
const dirs = fs.readdirSync('./src/locales').filter(d => d !== 'en');
for (const dir of dirs) {
const keys = Object.keys(require('./src/locales/' + dir + '/strings.json')).sort();
const missing = en.filter(k => !keys.includes(k));
if (missing.length) {
console.error(dir + ' fehlende Keys:', missing);
process.exit(1);
}
}
console.log('Alle Übersetzungen haben übereinstimmende Keys');
"
- name: Pull Request erstellen
uses: peter-evans/create-pull-request@v5
with:
title: 'chore: Übersetzungen aktualisieren (${{ steps.detect.outputs.new_key_count }} neue Strings)'
body: |
Automatisiertes Übersetzungs-Update.
- **Neue/geänderte Strings**: ${{ steps.detect.outputs.new_key_count }}
- **Aktualisierte Sprachen**: de, es, fr, ja, pt, ko, it
- **Validierung**: Bestanden
branch: translations/auto-update
Implementierung: GitLab CI#
# .gitlab-ci.yml
localize:
stage: post-build
rules:
- changes:
- src/locales/en/**
script:
- |
for lang in de es fr ja pt; do
curl -X POST https://api.shipglobal.dev/v1/translate \
-H "Authorization: Bearer $SHIPGLOBAL_API_KEY" \
-F "file=@src/locales/en/strings.json" \
-F "target_language=$lang" \
-o "src/locales/$lang/strings.json"
done
- git config user.email "ci@yourapp.com"
- git config user.name "CI Bot"
- git add src/locales/
- git commit -m "chore: Übersetzungen aktualisieren" || true
- git push origin HEAD:translations/auto-update
Best Practices#
1. Nur übersetzen was sich geändert hat#
Übersetze nicht deine gesamte Datei bei jedem Push neu. Nutze Translation Memory um unveränderte Strings nicht erneut zu übersetzen und Kosten zu senken.
2. PRs erstellen, nicht auto-mergen#
Erstelle immer einen Pull Request für Übersetzungsänderungen. Das gibt deinem Team Sichtbarkeit und die Möglichkeit zum Review.
3. Übersetzungen validieren#
Füge Validierungsschritte hinzu:
- JSON/XML Syntax-Validierung
- Key-Vollständigkeitsprüfung (alle Keys in allen Sprachen vorhanden)
- Platzhalter-Konsistenz (z.B.
{{name}}existiert in Übersetzungen) - String-Längen-Warnungen (Übersetzungen deutlich länger als Quelle)
4. Branch Protection nutzen#
Lass Übersetzungs-PRs nicht deinen normalen Review-Prozess umgehen. Behandle sie wie Code-Änderungen.
5. Translation Memory cachen#
Wenn du shipglobal.dev nutzt, handhabt Translation Memory das automatisch — du zahlst nur für neue oder geänderte Strings.
6. Merge-Konflikte handhaben#
Übersetzungsdateien sind JSON/XML, und Merge-Konflikte sind häufig. Nutze eine Strategie:
- Immer aus der englischen Quelldatei neu generieren
- Oder ein Merge-Tool verwenden, das dein Dateiformat versteht
Plattform-spezifische Tipps#
iOS (Localizable.strings)#
# .strings direkt zu shipglobal.dev hochladen
curl -X POST https://api.shipglobal.dev/v1/translate \
-F "file=@en.lproj/Localizable.strings" \
-F "target_language=de" \
-o "de.lproj/Localizable.strings"
Android (strings.xml)#
# strings.xml direkt hochladen
curl -X POST https://api.shipglobal.dev/v1/translate \
-F "file=@app/src/main/res/values/strings.xml" \
-F "target_language=de" \
-o "app/src/main/res/values-de/strings.xml"
React / Next.js (JSON)#
# i18n JSON-Datei hochladen
curl -X POST https://api.shipglobal.dev/v1/translate \
-F "file=@public/locales/en/common.json" \
-F "target_language=de" \
-o "public/locales/de/common.json"
Monitoring und Alerts#
Richte Alerts für deine Lokalisierungs-Pipeline ein:
- Übersetzungsfehler: Team benachrichtigen wenn die API nicht erreichbar ist
- Key-Abweichungen: Alarm wenn Übersetzungen Keys fehlen
- Budget-Alerts: Übersetzungskosten pro Monat tracken
- PR-Alter: Alarm wenn Übersetzungs-PRs länger als 24 Stunden nicht gemerged sind
Fazit#
Die Automatisierung der Lokalisierung in deiner CI/CD Pipeline entfernt die größte Reibung beim Global-Gehen. Statt dass Lokalisierung ein manueller, fehleranfälliger Prozess ist, der Releases verzögert, wird sie ein automatisierter Schritt, der im Hintergrund passiert.
Starte einfach — ein Basis-Workflow der bei Push übersetzt und einen PR erstellt. Dann iteriere: füge Validierung, Monitoring und Optimierung hinzu, wenn deine Anforderungen wachsen.
Das Ergebnis: Deine App ist immer bereit zum Versand in jeder Sprache, mit null manuellem Übersetzungsmanagement.