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?



In Django ändert sich die Sprache üblicherweise bei jeder Anfrage.

Django: Vergleich der Übersetzungstermine

  • 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

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

# 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



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

1) „Jetzt“ eine Antwort oder Log erzeugen → gettext

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

  • verbose_name, help_text in Modellen
  • label, help_text in Forms
  • label in DRF‑Serializers
  • list_display‑Beschreibungen im Admin
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

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

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

from django.utils.translation import gettext_lazy as _
from django.utils.text import format_lazy

title = format_lazy("{}: {}", _("Error"), _("Invalid token"))

oder mit %‑Formatierung:

from django.utils.translation import gettext as _

message = _("Hello, %(name)s!") % {"name": user.username}

Häufigste Fehler (3)

Fehler 1: gettext() beim Import festlegt

  • Bei Konstanten/Choices sollte lazy in Betracht gezogen werden.

Fehler 2: Lazy‑Objekte direkt in JSON oder Logs verwenden

  • Verwenden Sie force_str().

Fehler 3: f‑Strings mit Übersetzungen mischen

# ❌ nicht empfohlen
_("Hello") + f" {user.username}"
  • Die Reihenfolge der Wörter kann je nach Sprache variieren.
  • Stattdessen:
# ✅ empfohlen
_("Hello, %(name)s!") % {"name": user.username}

Tipps zur Vermeidung von Verwirrung

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

  • Runtime‑Logikgettext
  • Definition/Meta/Choices/Labelsgettext_lazy
  • Ausgehende Strings → ggf. force_str
  • Lazy + Formatierungformat_lazy oder Platzhalter in der Übersetzung

Mit diesen Regeln wird die Wahl fast automatisch.


Verwandte Artikel - Probleme und Lösungen bei der Verwendung von gettext_lazy mit JSON-Schlüsseln