# Django: gettext vs gettext_lazy – Klarheit durch das Timing der Auswertung Wenn man Django i18n nutzt, schwankt man ständig, ob man `gettext()` oder `gettext_lazy()` einsetzen soll. Der wahre Grund für die Verwirrung liegt darin, dass man die *Unterschiede* als reine Terminologie auswendig lernen will. Das Wesentliche ist ein einziges Prinzip. * **`gettext` übersetzt sofort (eager)** * **`gettext_lazy` übersetzt erst später (lazy)** Dieses Timing‑Prinzip fasst fast alle Anwendungsfälle zusammen. --- ## Warum ist das Timing der Übersetzung wichtig? {#sec-cd5e4068943f} In Django ändert sich die Sprache üblicherweise bei jeder Anfrage. ![Django: Vergleich der Übersetzungstermine](/media/editor_temp/6/29f9dbe8-44b7-47ed-bef6-4cc0cc62bb79.png) * Middleware erkennt die Anfrage und ruft `activate("ko")` / `activate("en")` auf, um die aktuelle Sprache für den Thread/Context zu aktivieren. * Beim Rendern von Templates, Forms oder im Admin muss die Übersetzung bereits in dieser Sprache erfolgen. Kurz gesagt: **Wann** man einen String übersetzt, bestimmt das Ergebnis. --- ## `gettext()` : „Jetzt“ übersetzen und den String zurückgeben {#sec-9ff53b7dc3ad} ```python from django.utils.translation import gettext as _ def view(request): message = _("Welcome") # wird zur Laufzeit in der aktiven Sprache übersetzt return HttpResponse(message) ``` * Wird innerhalb einer View oder eines Funktionsaufrufs (runtime) aufgerufen, funktioniert es wie erwartet. * Wird jedoch beim Importieren eines Moduls ausgeführt, kann es zu Problemen kommen. ### Häufiges Problem: `gettext()` in Modulkonstanten {#sec-7c331db329fb} ```python # app/constants.py from django.utils.translation import gettext as _ WELCOME = _("Welcome") # ❌ wird beim Serverstart/Import in der aktuellen Sprache festgelegt ``` In diesem Fall bleibt `WELCOME` ein fester, bereits übersetzter String, selbst wenn die Sprache später wechselt (besonders in Umgebungen, in denen das Modul nur einmal importiert wird). --- ## `gettext_lazy()` : „Später“ übersetzbare Proxy‑Objekte zurückgeben {#sec-a90df9111315} ```python from django.utils.translation import gettext_lazy as _ WELCOME = _("Welcome") # ✅ kein echter String, sondern ein Objekt, das bei Bedarf übersetzt wird ``` `gettext_lazy()` liefert in der Regel ein *lazy object*. * Beim Rendern von Forms, Templates oder Admin wird es in den aktiven String übersetzt. > Kurz gesagt: **In Bereichen, in denen die Sprache erst beim Rendern feststeht, ist lazy die richtige Wahl.** --- ## Praktische Regeln für die Verwendung {#sec-4a8a3cbed930} ### 1) „Jetzt“ eine Antwort oder Log erzeugen → `gettext` {#sec-197c23c83765} ```python from django.utils.translation import gettext as _ def signup_done(request): return JsonResponse({"message": _("Signup completed.")}) ``` ### 2) „Definition vor Rendern“ (z. B. Klassenattribute, Meta‑Daten, Form‑Labels) → `gettext_lazy` {#sec-b545464ef5b7} * `verbose_name`, `help_text` in Modellen * `label`, `help_text` in Forms * `label` in DRF‑Serializers * `list_display`‑Beschreibungen im 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) Wiederverwendbare Konstanten/Choices → meist `gettext_lazy` {#sec-9ea28af08fa3} ```python from django.utils.translation import gettext_lazy as _ STATUS_CHOICES = [ ("draft", _("Draft")), ("published", _("Published")), ] ``` ### 4) Strings an externe Systeme senden (Logs, APIs, Header) → `gettext` oder explizite Auswertung {#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)) # ✅ wird in einen echten String umgewandelt ``` ### 5) String‑Konkatenation/Formatierung → `format_lazy` oder Platzhalter in der Übersetzung {#sec-67d42a88924b} ```python from django.utils.translation import gettext_lazy as _ from django.utils.text import format_lazy title = format_lazy("{}: {}", _("Error"), _("Invalid token")) ``` oder mit `%`‑Formatierung: ```python from django.utils.translation import gettext as _ message = _("Hello, %(name)s!") % {"name": user.username} ``` --- ## Häufigste Fehler (3) {#sec-273d53d27224} ### Fehler 1: `gettext()` beim Import festlegt {#sec-7f4b5a25d9d0} * Bei Konstanten/Choices sollte lazy in Betracht gezogen werden. ### Fehler 2: Lazy‑Objekte direkt in JSON oder Logs verwenden {#sec-7a741de5c1d8} * Verwenden Sie `force_str()`. ### Fehler 3: f‑Strings mit Übersetzungen mischen {#sec-76316b53a754} ```python # ❌ nicht empfohlen _("Hello") + f" {user.username}" ``` * Die Reihenfolge der Wörter kann je nach Sprache variieren. * Stattdessen: ```python # ✅ empfohlen _("Hello, %(name)s!") % {"name": user.username} ``` --- ## Tipps zur Vermeidung von Verwirrung {#sec-79205bb8a9a7} Eine klare Trennung nach Dateityp hilft enorm: * In `models.py`, `forms.py`, `admin.py` (Definition zuerst): `from django.utils.translation import gettext_lazy as _` * In `views.py`, `services.py` (Ausführung zuerst): `from django.utils.translation import gettext as _` So entsteht ein konsistentes Muster, das Fehler reduziert. --- ## Kurzfassung {#sec-3aa43e207283} * **Runtime‑Logik** → `gettext` * **Definition/Meta/Choices/Labels** → `gettext_lazy` * **Ausgehende Strings** → ggf. `force_str` * **Lazy + Formatierung** → `format_lazy` oder Platzhalter in der Übersetzung Mit diesen Regeln wird die Wahl fast automatisch. --- **Verwandte Artikel** - [Probleme bei der Verwendung von gettext_lazy als JSON‑Schlüssel und deren Lösung](/ko/whitedec/2025/4/26/gettext-lazy-json-key-problem-solution/)