Понимание разницы между gettext и gettext_lazy в Django (по моменту оценки)
При работе с i18n в Django часто возникает сомнение: какой из методов использовать – gettext() или gettext_lazy()? Большая часть путаницы возникает из‑за попытки запомнить «разницу» как термин.
Ключевой момент прост: один и тот же.
gettextпереводит сейчас (непосредственная оценка, eager)gettext_lazyпереводит позже (ленивая оценка, lazy)
Эта разница по моменту оценки позволяет решить почти все случаи.
Почему важно, когда определяется перевод?
В Django язык меняется с каждым запросом.

- Middleware смотрит на запрос и вызывает
activate("ko")/activate("en"), активируя язык для текущего потока/контекста. - При рендеринге шаблонов, форм и админки перевод должен быть выполнен именно в этот момент.
То есть когда вы переводите строку, определяет результат.
gettext() : «переводим сейчас» и возвращаем строку
from django.utils.translation import gettext as _
def view(request):
message = _("Welcome") # переводится в момент выполнения этой строки
return HttpResponse(message)
- При вызове внутри функции/вью, во время обработки запроса (runtime), обычно всё работает как ожидается.
- Но при вызове во время импорта модуля возникают проблемы.
Типичная ловушка: использование gettext() в константах модуля
# app/constants.py
from django.utils.translation import gettext as _
WELCOME = _("Welcome") # ❌ может быть «запечатан» на языке, который был активен при старте сервера
В таком случае WELCOME фиксируется как строка, переведённая в момент импорта, и не меняется при смене языка.
gettext_lazy() : возвращает «ленивый» объект, который переводится позже
from django.utils.translation import gettext_lazy as _
WELCOME = _("Welcome") # ✅ это не строка, а объект, который будет переведен при необходимости
gettext_lazy() обычно возвращает «ленивый объект».
- При рендеринге шаблонов/форм/админки, когда объект преобразуется в строку,
- перевод выполняется в активный язык в тот момент.
Кратко: в местах, где язык определяется во время рендеринга, lazy – правильный выбор.
Практические правила использования
1) «Сейчас создаём ответ/экран» → gettext
- В логике вью/сервиса, когда сразу формируется строка для ответа или логирования.
from django.utils.translation import gettext as _
def signup_done(request):
return JsonResponse({"message": _("Signup completed.")})
2) «Определения, которые могут быть оценены при импорте» → gettext_lazy
verbose_name,help_textв моделяхlabel,help_textв формахlabelв DRF сериализаторах- Описание в
list_displayадминки
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) «Константы/choices, которые переиспользуются» → обычно gettext_lazy
from django.utils.translation import gettext_lazy as _
STATUS_CHOICES = [
("draft", _("Draft")),
("published", _("Published")),
]
4) «Строки, отправляемые наружу (логи, сторонние API, заголовки)» → gettext или принудительная оценка lazy
from django.utils.translation import gettext_lazy as _
from django.utils.encoding import force_str
msg = _("Welcome")
logger.info(force_str(msg)) # ✅ преобразуем в реальную строку
5) «Строки с форматированием» → используйте format_lazy или форматирование внутри строки
from django.utils.translation import gettext_lazy as _
from django.utils.text import format_lazy
title = format_lazy("{}: {}", _("Error"), _("Invalid token"))
Или используйте %‑форматирование, которое удобно для перевода:
from django.utils.translation import gettext as _
message = _("Hello, %(name)s!") % {"name": user.username}
Три самые частые ошибки
Ошибка 1) Создание «запечатанного» перевода при импорте модуля
- Если есть константы/choices, сначала подумайте о
gettext_lazy.
Ошибка 2) Передача lazy‑объекта в JSON/логи без преобразования
- Преобразуйте через
force_str().
Ошибка 3) Сборка строки через f‑строку
# ❌ Не рекомендуется
_("Hello") + f" {user.username}"
- Перевод разбивается, порядок слов меняется, момент оценки усложняется.
- Вместо этого используйте переменные внутри строки:
# ✅ Рекомендовано
_("Hello, %(name)s!") % {"name": user.username}
Советы, чтобы уменьшить путаницу
Самый эффективный способ – унифицировать смысл _ в зависимости от типа файла.
- В
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 _
Такой подход создаёт правило «здесь по умолчанию lazy», что снижает вероятность ошибок.
Быстрый обзор
- Непосредственная оценка (runtime):
gettext - Ленивая оценка (при рендеринге):
gettext_lazy - Выходящие строки: при необходимости
force_str - Ленивая + форматирование:
format_lazyили переменные внутри строки
С этими правилами вы быстро выберете правильный инструмент и избежите типичных ошибок.
Ссылки на связанные статьи
- Проблемы и решения при использовании gettext_lazy с ключами JSON
Комментариев нет.