Si vous avez déjà livré une application Django dans plus d'une langue, vous connaissez la routine. Vous encapsulez vos chaînes dans gettext(), vous exécutez makemessages, vous ouvrez un fichier .po avec des centaines d'entrées, et vous commencez à traduire ligne par ligne. Pour deux langues et cinquante chaînes, c'est tolérable. Pour six langues et cinq cents chaînes, c'est une journée entière de travail que vous ne récupérerez jamais.
Ce guide couvre le pipeline d'internationalisation (i18n) de Django du début à la fin, explique où il échoue, et montre comment automatiser la partie pénible avec la traduction assistée par IA.
Le workflow standard de Django i18n
Le système i18n intégré de Django est bien conçu. La boucle principale ressemble à ceci :
Étape 1 : Marquer les chaînes pour la traduction dans votre code Python et vos templates :
from django.utils.translation import gettext as _
def dashboard(request):
welcome = _("Welcome back, %(name)s!") % {"name": request.user.first_name}
return render(request, "dashboard.html", {"welcome": welcome})
{% load i18n %}
<h1>{% trans "Account Settings" %}</h1>
<p>{% blocktrans %}You have {{ count }} unread messages.{% endblocktrans %}</p>
Étape 2 : Extraire les chaînes dans des fichiers .po :
python manage.py makemessages -l de -l fr -l nl
Cela analyse l'ensemble de votre base de code et génère un fichier .po par langue, contenant chaque chaîne traduisible :
#: myapp/views.py:4
msgid "Welcome back, %(name)s!"
msgstr ""
#: templates/dashboard.html:2
msgid "Account Settings"
msgstr ""
Étape 3 : Traduire chaque msgstr vide à la main.
Étape 4 : Compiler les fichiers .po terminés en fichiers binaires .mo :
python manage.py compilemessages
Les étapes 1, 2 et 4 sont rapides. L'étape 3 est celle où le processus s'effondre.
Pourquoi la traduction manuelle ne passe pas à l'échelle
Une application Django typique contient entre 200 et 2 000 chaînes traduisibles. Multipliez cela par le nombre de langues cibles, et vous faites face à un engagement de temps considérable.
Ce n'est pas une plainte théorique. Dans un fil de discussion bien connu du Django Forum, un développeur a rapporté avoir passé plus de 8 heures par fichier .po pour des traductions manuelles. Un contributeur principal de Django a décrit avoir passé plus de 10 heures à intégrer les traductions soumises par la communauté dans une seule release, principalement pour la revue, les corrections de formatage et la réparation des marqueurs de substitution cassés.
Les problèmes s'accumulent avec le temps :
- Les marqueurs de substitution se cassent. Copiez une chaîne comme
Welcome, %(name)s!dans Google Translate, et vous obtiendrez souventWillkommen, %(Name)s!ouBienvenue, %(nom)s!. Cette corruption subtile provoque des plantages à l'exécution. - La cohérence dérive. Sans glossaire, "dashboard" est traduit par "Instrumententafel" dans un fichier et "Dashboard" dans un autre. Trois mois plus tard, personne ne se souvient lequel était intentionnel.
- Les sprints ajoutent des chaînes. Chaque branche de fonctionnalité ajoute de nouvelles chaînes traduisibles. Même si vous avez payé pour une passe de traduction complète le trimestre dernier, vous avez maintenant 40 entrées non traduites dispersées dans vos fichiers
.po. - Les assistants IA aident une fois. Vous pouvez coller un fichier
.podans ChatGPT ou Claude et obtenir des résultats corrects. Mais au sprint suivant, quand 15 nouvelles chaînes apparaissent, vous repartez de zéro avec les prompts, retraduisez tout le fichier, et espérez que cela reste cohérent avec ce qui existait déjà.
La cause racine est que la traduction est traitée comme un événement ponctuel plutôt que comme un processus incrémental et reproductible.
Automatiser la traduction avec l'IA
L'idée est simple : au lieu qu'un humain ouvre chaque fichier .po et remplisse les valeurs msgstr, un outil lit le fichier, envoie les chaînes non traduites à un modèle d'IA ou une API de traduction, écrit les résultats en retour, et préserve tout le reste (commentaires, structure du fichier, marqueurs de substitution, formes plurielles).
TranslateBot Django est un package open source qui fait exactement cela. Il s'intègre au système de commandes de gestion de Django, et s'inscrit donc dans le workflow que vous avez déjà.
Configuration étape par étape
1. Installer le package
pip install translatebot-django
Ou, si vous utilisez uv (recommandé) :
uv add --dev translatebot-django
L'installer comme dépendance de développement est intentionnel. Vous n'avez besoin de TranslateBot que lors de la génération des traductions, pas à l'exécution en production.
2. Ajouter à INSTALLED_APPS
# settings.py
INSTALLED_APPS = [
# ...
"translatebot_django",
]
3. Configurer votre fournisseur d'IA
# settings.py
import os
TRANSLATEBOT_API_KEY = os.getenv("OPENAI_API_KEY")
TRANSLATEBOT_MODEL = "gpt-4o-mini"
TranslateBot utilise LiteLLM en interne, ce qui signifie que vous pouvez passer à n'importe lequel des 100+ modèles en changeant une seule chaîne :
| Fournisseur | Valeur de TRANSLATEBOT_MODEL |
|---|---|
| OpenAI | gpt-4o-mini, gpt-4o |
| Anthropic | claude-sonnet-4-5-20250929 |
gemini/gemini-2.5-flash |
|
| Azure OpenAI | azure/gpt-4o-mini |
| DeepL | Utilisez TRANSLATEBOT_PROVIDER = "deepl" à la place |
Pour DeepL, installez l'extra : pip install translatebot-django[deepl]. Le niveau gratuit de DeepL vous donne 500 000 caractères par mois sans frais, ce qui est suffisant pour la plupart des projets de petite à moyenne taille.
4. Définir vos langues
# settings.py
LANGUAGES = [
("en", "English"),
("de", "German"),
("fr", "French"),
("nl", "Dutch"),
("ja", "Japanese"),
]
5. Lancer la traduction
python manage.py translate
C'est tout. TranslateBot analyse votre projet à la recherche de fichiers .po, identifie les entrées non traduites, les envoie au modèle d'IA configuré par lots optimisés, et écrit les résultats en retour. Les traductions existantes restent intactes.
Pour traduire une seule langue :
python manage.py translate --target-lang nl
La sortie ressemble à ceci :
Translating to Dutch (nl)...
Found 42 strings to translate
Translating batch 1/2...
Translating batch 2/2...
Successfully translated 42 strings
6. Compiler comme d'habitude
python manage.py compilemessages
Votre workflow complet est maintenant :
python manage.py makemessages -l de -l fr -l nl -l ja
python manage.py translate
python manage.py compilemessages
Trois commandes. Toutes les langues. Chaque sprint.
Incrémental par conception
La fonctionnalité la plus importante pour un workflow reproductible est la traduction incrémentale. TranslateBot ne traduit que les entrées où msgstr est vide. Si vous avez 500 chaînes et que 15 sont nouvelles ce sprint, seules ces 15 sont envoyées à l'API.
Cela compte pour des raisons pratiques :
- Coût. Vous ne payez que pour les nouvelles chaînes, pas pour le fichier entier.
- Vitesse. Traduire 15 chaînes prend des secondes, pas des minutes.
- Stabilité. Les traductions que vous avez déjà revues et approuvées ne sont jamais écrasées (sauf si vous passez explicitement
--overwrite).
Sécurité des marqueurs de substitution
Django utilise plusieurs formats de marqueurs de substitution : %(name)s, %s, %d, {0}, {name}, et des balises HTML en ligne comme <strong> ou <a href="...">. Si l'un d'entre eux est altéré lors de la traduction, vous obtenez des erreurs à l'exécution ou du balisage cassé.
TranslateBot demande au modèle d'IA de préserver tous les formats de marqueurs de substitution et valide la sortie. Une chaîne comme :
Welcome to %(site_name)s! You have <strong>%(count)d</strong> new messages.
Est traduite en néerlandais comme :
Welkom bij %(site_name)s! Je hebt <strong>%(count)d</strong> nieuwe berichten.
Chaque marqueur de substitution survit intact.
Contrôler la qualité avec TRANSLATING.md
Les modèles d'IA traduisent mieux quand ils comprennent le contexte. TranslateBot cherche un fichier TRANSLATING.md à la racine de votre projet et inclut son contenu dans chaque requête de traduction.
# Translation Context
## About This Project
A B2B project management tool for construction companies.
## Terminology
- "project" means a construction project, not a software project
- "plan" means a building plan/blueprint, not a subscription plan
- Keep "Gantt chart" as-is in all languages
## Tone
- German: use formal "Sie" form (business context)
- French: use formal "vous" form
- Dutch: use informal "je" form
## Do Not Translate
- Brand name: "BuildFlow"
- Feature names: "SmartSchedule", "CostTracker"
Ce fichier est versionné avec votre code, de sorte que toute votre équipe partage le même contexte de traduction. Vous pouvez également placer des fichiers TRANSLATING.md par application pour les apps avec une terminologie spécialisée. Un module de dossiers médicaux et un module de facturation peuvent chacun avoir leur propre glossaire.
Prévisualiser avant de committer
Le drapeau --dry-run montre exactement ce qui serait traduit sans effectuer d'appels API ni modifier de fichiers :
python manage.py translate --target-lang fr --dry-run
Found 15 untranslated entries
Dry run mode: skipping LLM translation
Would translate 'Welcome to our site'
Would translate 'Hello, %(name)s!'
...
Dry run complete: 15 entries would be translated
C'est utile avant une grande session de traduction ou quand un nouveau membre de l'équipe veut comprendre ce que fait la commande avant de s'engager sur les coûts d'API.
Intégration CI/CD
L'obsolescence des traductions est inévitable sans enforcement. TranslateBot inclut une commande de gestion check_translations conçue pour les pipelines CI :
# .github/workflows/ci.yml
jobs:
translations:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- run: uv python install
- run: uv sync --frozen
- name: Install gettext
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends gettext
- name: Check translations
run: uv run python manage.py check_translations --makemessages
Le drapeau --makemessages exécute d'abord makemessages -a --no-obsolete, garantissant que les fichiers .po reflètent le code source actuel avant vérification. Si des entrées sont non traduites ou floues, la commande se termine avec le code 1 et fait échouer le build :
locale/de/LC_MESSAGES/django.po: 2 untranslated, 0 fuzzy
locale/nl/LC_MESSAGES/django.po: 0 untranslated, 1 fuzzy
CommandError: Translation check failed
Le workflow typique du développeur devient :
- Ajouter de nouvelles chaînes traduisibles dans une branche de fonctionnalité.
- Le CI échoue parce que ces chaînes ne sont pas traduites.
- Exécuter
python manage.py translatelocalement. - Committer les fichiers
.pomis à jour. - Le CI passe.
Les traductions ne se désynchronisent jamais silencieusement.
Traduire le contenu de la base de données
Si votre application stocke du contenu traduisible dans la base de données (noms de produits, titres d'articles de blog, libellés de catégories), TranslateBot s'intègre également avec django-modeltranslation :
pip install translatebot-django[modeltranslation]
# Translate all registered model fields
python manage.py translate --target-lang de --models
# Translate specific models only
python manage.py translate --target-lang de --models Product Category
La même logique incrémentale s'applique : seuls les champs où la valeur de la langue cible est vide sont traduits.
Comparaison des coûts
L'une des questions les plus courantes est de savoir si la traduction par IA est rentable par rapport aux alternatives. Voici une comparaison approximative pour un projet avec 500 chaînes traduisibles en 5 langues :
| Approche | Coût estimé | Investissement en temps |
|---|---|---|
| Manuel (temps développeur) | 0 $ de poche, 20-40+ heures | Très élevé |
| Service de traduction professionnel | 500-2 000 $+ | Faible (mais délai long) |
| Plateforme de localisation SaaS | 50-200 $/mois | Moyen |
| TranslateBot + GPT-4o-mini | ~0,05 $ (ponctuel) | Minutes |
| TranslateBot + DeepL Free | 0 $ (jusqu'à 500k caractères/mois) | Minutes |
| TranslateBot + Claude/GPT-4o | ~0,30 $ (ponctuel) | Minutes |
Les chiffres varient selon le nombre de chaînes et de langues cibles, mais la différence d'ordre de grandeur est constante. Pour la maintenance continue (traduire les 20-50 nouvelles chaînes ajoutées chaque sprint), le coût de l'IA est essentiellement nul.
Bonnes pratiques
Commencez par --dry-run. Avant votre première vraie session de traduction, prévisualisez ce qui va se passer. Cela renforce la confiance et détecte les problèmes de configuration tôt.
Committez les fichiers .po avant de traduire. Si quelque chose tourne mal, git checkout vous ramène instantanément à un état propre.
Rédigez un TRANSLATING.md dès le premier jour. Même un fichier succinct avec la description de votre projet et quelques règles de terminologie améliore de manière mesurable la qualité de traduction.
Ajoutez check_translations au CI. Cette seule étape prévient le mode de défaillance i18n le plus courant : des chaînes marquées pour traduction mais jamais réellement traduites.
Utilisez gpt-4o-mini ou DeepL pour l'efficacité des coûts. Réservez les modèles premium comme GPT-4o ou Claude pour les projets où la précision compte, comme les textes marketing, les textes juridiques ou la terminologie spécifique à un domaine.
Relisez les chaînes critiques. Les traductions par IA sont suffisamment bonnes pour la plupart des textes d'interface, mais faites relire par un locuteur natif tout ce qui est juridiquement contraignant, critique pour la sécurité ou destiné au client dans un contexte à fort enjeu.
De heures à secondes
Le framework i18n de Django est excellent pour extraire et compiler les traductions. Le manque a toujours été l'étape de traduction elle-même, le travail fastidieux et sujet aux erreurs de remplir des centaines de valeurs msgstr dans plusieurs langues.
TranslateBot comble ce manque. Installez-le, pointez-le vers un fournisseur d'IA, et exécutez une commande. Les nouvelles chaînes sont traduites. Les chaînes existantes restent intactes. Les marqueurs de substitution restent intacts. Le CI attrape tout ce qui passe entre les mailles.
Vos fichiers .po cessent d'être une corvée et deviennent simplement une partie du build.
pip install translatebot-django
Commencez sur translatebot.dev.