"gettext()" vs "gettext_lazy()" 在 Django 中的区别

172
我有一个关于使用ugettext和gettext_lazy()进行翻译的问题。 我了解到在模型中应该使用gettext_lazy(),而在视图中使用ugettext。 但是还有其他地方需要使用gettext_lazy()吗?表单定义呢? 它们之间是否有性能差异?
编辑: 还有一件事。有时候,除了gettext_lazy()之外,还会使用gettext_noop()。根据文档所说,gettext_noop()字符串只是标记为需要翻译,并在显示给用户之前尽可能晚地进行翻译,但是我对此有些困惑,这不是和gettext_lazy()的作用类似吗?我仍然很难决定在我的模型和表单中应该使用哪个。
4个回答

246

gettext()gettext_lazy()

在表单或模型等定义中,应使用gettext_lazy,因为这些定义的代码只执行一次(大多数情况下在Django启动时);gettext_lazy以延迟的方式翻译字符串,这意味着每当您访问模型上属性的名称时,该字符串将会重新翻译-这是有意义的,因为自Django启动以来,您可能会以不同的语言查看此模型!

在视图和类似的函数调用中,可以毫无问题地使用gettext,因为每次调用视图时gettext都会被重新执行,所以你总是会得到符合请求的正确翻译!

关于gettext_noop()

正如Bryce在他的回答中指出的那样,该函数将一个字符串标记为可提取的用于翻译,但不返回已翻译的字符串。这对于在两个位置使用字符串 - 翻译和未翻译 - 非常有用。请参见以下示例:

import logging
from django.http import HttpResponse
from django.utils.translation import gettext as _, gettext_noop as _noop

def view(request):
    msg = _noop("An error has occurred")
    logging.error(msg)
    return HttpResponse(_(msg))

22
在我看来,这比 Django 文档中的解释更易理解。感谢 @Bernhard。 - Utku
15
谢谢!解释一下何时不应该使用ugettext_lazy,例如当将其传递给期望字符串的内容(如"".replace、字符串拼接等)时,懒加载代理对象在这些情况下无法正常工作。否则,这个答案暗示着你可以安全地始终使用ugettext_lazy。 - mrooney
4
@mrooney提到,这些情况并不重要,因为如果你这样做,它们会给出一个错误,而不是默默地返回错误的语言翻译。此外,您可以使用"".replace和ugettext_lazy一起使用,只需要在结果上调用str(),例如:lazytext=ugettext_lazy('hello'),然后稍后使用 str(lazytext).replace。 - fabspro
2
如果没有_noop,Django将无法找到需要翻译的字符串吗?为什么需要msg =“An error has occurred”;logging.error(msg); return HttpResponse(_(msg))中的 _noop? 注:此处的 _noop 指 Django 中的占位符函数 _noop() - WeizhongTu
2
我发现如果你将标记函数之一(例如ugettext)导入为“_”,然后使用“import as”(例如import ugettext_noop as _noop)导入第二个函数(例如ugettext_noop),那么xgettext将无法识别和提取后者。换句话说,除了你用“import as _”导入的那个之外,所有其他导入都必须通过它们的全名导入和引用。 - Eric P
显示剩余6条评论

23

4
链接已损坏。 - nalzok

9

懒惰版本返回的是代理对象而不是字符串,在某些情况下,它可能无法按预期工作。例如:

def get(self, request, format=None):
   search_str = request.GET.get('search', '')
   data = self.search(search_str)
   lst = []
   lst.append({'name': ugettext_lazy('Client'), 'result': data})
   return HttpResponse(json.dumps(lst), content_type='application/json')

如果这样做,会失败,因为最后一行会尝试将lst对象序列化为JSON,而不是"client"的字符串,它将具有代理对象。代理对象无法序列化为json。


2
在这些情况下,您应该使用ugettext。 - sudip

0

gettext()可以在函数内部工作,但在函数外部无法工作。

gettext_lazy()可以在函数内部和外部工作。

*根据翻译的示例,最好在函数外部使用gettext_lazy()

<gettext()>

下面是gettext()可以工作的地方:

# "my_app1/views.py"

from django.http import HttpResponse
from django.utils.translation import gettext as _

def hello(request):
    HttpResponse(_("Hello")) # Here

<gettext_lazy()>

以下是gettext_lazy()可以使用的地方:

# "core/settings.py"

from django.utils.translation import gettext_lazy as _

LANGUAGES = (
    ('en', _('English')),
    ('fr', _('French'))
)

# "my_app1/views.py"

from django.http import HttpResponse
from django.utils.translation import gettext_lazy as _

def hello(request): # Here
    HttpResponse(_("Hello"))

# "my_app1/urls.py"

from django.urls import path
from . import views
from django.utils.translation import gettext_lazy as _

app_name = "my_app1"

urlpatterns = [
    path(_('hello'), views.hello, name="hello"),
]        # Here

# "my_app1/models.py"

from django.db import models
from django.utils.translation import gettext_lazy as _

class Person(models.Model):                             # Here
    name = models.CharField(max_length=20, verbose_name=_("name"))

    class Meta:
        verbose_name = _('person') # Here
        verbose_name_plural = _('persons') # Here

# "my_app1/admin.py"

from django.contrib import admin
from django import forms
from .models import Person
from django.utils.translation import gettext_lazy as _

admin.site.site_title = _('My site title') # Here
admin.site.site_header = _('My site header') # Here
admin.site.index_title = _('My index title') # Here

class PersonForm(forms.ModelForm): # Here
    name = forms.CharField(label=_('name')) 

    class Meta:
        model = Person
        fields = "__all__"

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):    
    form = PersonForm

# "my_app1/apps.py"

from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _

class App1Config(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'my_app1'
    verbose_name = _('my app1') # Here

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接