# Démystifier gettext vs gettext_lazy dans Django (Comprendre le moment d’évaluation) Lorsque vous utilisez l’internationalisation de Django, vous vous demandez souvent quel est le bon choix entre `gettext()` et `gettext_lazy()`. La plupart des confusions proviennent de la tentative de mémoriser les différences terminologiques. Le principe est simple : * **`gettext` traduit immédiatement (évaluation immédiate, eager)** * **`gettext_lazy` attend pour traduire (évaluation paresseuse, lazy)** Un seul concept d’évaluation suffit pour clarifier la plupart des cas. --- ## Pourquoi le moment de la traduction est-il important ? {#sec-cd5e4068943f} Dans Django, la langue change généralement à chaque requête. ![Comparaison des moments de traduction dans Django](/media/editor_temp/6/29f9dbe8-44b7-47ed-bef6-4cc0cc62bb79.png) * Le middleware active la langue du thread/corps de la requête via `activate("ko")` ou `activate("en")`. * La traduction doit se produire au moment du rendu du template, du formulaire ou de l’interface d’administration. En d’autres termes, **le moment où vous traduisez une chaîne détermine le résultat**. --- ## `gettext()` : traduire immédiatement et retourner la chaîne {#sec-9ff53b7dc3ad} ```python from django.utils.translation import gettext as _ def view(request): message = _("Welcome") # traduit selon la langue active au moment de l’exécution return HttpResponse(message) ``` * Appelé dans une vue ou une fonction de service (runtime) → fonctionne comme prévu. * Appelé au moment de l’importation du module → problème. ### Piège courant : utiliser `gettext()` dans les constantes de module {#sec-7c331db329fb} ```python # app/constants.py from django.utils.translation import gettext as _ WELCOME = _("Welcome") # ❌ peut être « figé » dans la langue du démarrage du serveur ``` Dans ce cas, `WELCOME` reste la traduction effectuée lors de l’importation, même si la langue change par la suite. --- ## `gettext_lazy()` : retourner un proxy qui se traduit plus tard {#sec-a90df9111315} ```python from django.utils.translation import gettext_lazy as _ WELCOME = _("Welcome") # ✅ un objet proxy, pas encore traduit ``` `gettext_lazy()` renvoie généralement un **objet proxy paresseux**. * Lors du rendu du formulaire/template/admin, l’objet est traduit avec la langue active. > Résumé en une phrase : **Dans les endroits où la langue est déterminée au moment du rendu, le lazy est la solution.** --- ## Où utiliser quoi : règles pratiques {#sec-4a8a3cbed930} ### 1) Vous créez immédiatement une réponse ou un message → `gettext` {#sec-197c23c83765} ```python from django.utils.translation import gettext as _ def signup_done(request): return JsonResponse({"message": _("Signup completed.")}) ``` ### 2) Vous définissez des attributs de classe, des métadonnées ou des champs de formulaire qui seront évalués lors de l’importation → `gettext_lazy` {#sec-b545464ef5b7} * `verbose_name`, `help_text` de modèles * `label`, `help_text` de champs de formulaire * `label` de sérialiseur DRF * `list_display` d’admin ```python from django.db import models from django.utils.translation import gettext_lazy as _ class Article(models.Model): title = models.CharField(_("title"), max_length=100) status = models.CharField( _("status"), max_length=20, choices=[ ("draft", _("Draft")), ("published", _("Published")), ], help_text=_("Visibility of the article."), ) ``` ### 3) Vous avez des constantes ou des choix réutilisables au niveau du module → généralement `gettext_lazy` {#sec-9ea28af08fa3} ```python from django.utils.translation import gettext_lazy as _ STATUS_CHOICES = [ ("draft", _("Draft")), ("published", _("Published")), ] ``` ### 4) Vous envoyez une chaîne vers un système externe (logs, API tierce, en-têtes) → `gettext` ou forcez l’évaluation du lazy {#sec-f04525bb1d99} ```python from django.utils.translation import gettext_lazy as _ from django.utils.encoding import force_str msg = _("Welcome") logger.info(force_str(msg)) # ✅ convertit en chaîne réelle ``` ### 5) Vous combinez ou formatez des chaînes → utilisez `format_lazy` ou la substitution interne {#sec-67d42a88924b} ```python from django.utils.translation import gettext_lazy as _ from django.utils.text import format_lazy title = format_lazy("{}: {}", _("Error"), _("Invalid token")) ``` ou ```python from django.utils.translation import gettext as _ message = _("Hello, %(name)s!") % {"name": user.username} ``` --- ## Trois erreurs fréquentes {#sec-273d53d27224} ### Erreur 1 : créer une traduction figée au moment de l’importation avec `gettext()` {#sec-7f4b5a25d9d0} * Si vous avez des constantes ou des choix, privilégiez le lazy. ### Erreur 2 : insérer un objet lazy directement dans JSON ou les logs {#sec-7a741de5c1d8} * Utilisez `force_str()` pour obtenir une chaîne. ### Erreur 3 : assembler des chaînes traduites avec f‑string {#sec-76316b53a754} ```python # ❌ non recommandé _("Hello") + f" {user.username}" ``` * La traduction se fait en morceaux et l’ordre peut changer selon la langue. * Utilisez la substitution interne : ```python # ✅ recommandé _("Hello, %(name)s!") % {"name": user.username} ``` --- ## Astuces pour réduire la confusion {#sec-79205bb8a9a7} Uniformisez l’usage de `_` selon le type de fichier : * `models.py`, `forms.py`, `admin.py` : `from django.utils.translation import gettext_lazy as _` * `views.py`, `services.py` : `from django.utils.translation import gettext as _` Cette convention crée un **point de référence** qui diminue les erreurs. --- ## Résumé rapide {#sec-3aa43e207283} * **Évaluation immédiate (runtime)** : `gettext` * **Évaluation paresseuse (définition/metadata/constantes)** : `gettext_lazy` * **Chaînes sortantes** : utilisez `force_str` si nécessaire * **Lazy + formatage** : `format_lazy` ou substitution interne Avec ces règles, vous choisissez automatiquement la bonne fonction sans confusion. --- **Liens connexes** - [Problème et solution de l’utilisation de gettext_lazy comme clé JSON](/ko/whitedec/2025/4/26/gettext-lazy-json-key-problem-solution/)