假设我们有一个 Django 模型:
class StandardLabel(models.Model):
id = models.AutoField(primary_key=True)
label = models.CharField(max_length=255)
abbreviation = models.CharField(max_length=255)
每个标签都有一个 ID 号、标签文本和缩写。现在,我们希望将这些标签翻译成其他语言。
以下是我们考虑的几种解决方案:
① 在模型上添加翻译字段:
class StandardLabel(models.Model):
id = models.AutoField(primary_key=True)
label_english = models.CharField(max_length=255)
abbreviation_english = models.CharField(max_length=255)
label_spanish = models.CharField(max_length=255)
abbreviation_spanish = models.CharField(max_length=255)
显然这不是理想的解决方案,添加语言需要编辑模型,正确的字段名称取决于语言。
② 将语言作为外键添加:
class StandardLabel(models.Model):
id = models.AutoField(primary_key=True)
label = models.CharField(max_length=255)
abbreviation = models.CharField(max_length=255)
language = models.ForeignKey('languages.Language')
这种方法好得多,现在我们可以查询具有某种语言的所有标签,并将它们放到字典中:
labels = StandardLabel.objects.filter(language=1)
labels = dict((x.pk, x) for x in labels)
但问题是标签字典被用作查找表,如下所示:
x = OtherObjectWithAReferenceToTheseLabels.object.get(pk=3)
thelabel = labels[x.labelIdNumber].label
如果每条标签都有一个行,并且一个标签可能有多个语言,那么这种方法就不起作用了。为了解决这个问题,我们需要另一个字段:
class StandardLabel(models.Model):
id = models.AutoField(primary_key=True)
group_id = models.IntegerField(db_index=True)
label = models.CharField(max_length=255)
abbreviation = models.CharField(max_length=255)
language = models.ForeignKey('languages.Language')
class Meta:
unique_together=(("group_id", "language"),)
#and I need to group them differently:
labels = StandardLabel.objects.filter(language=1)
labels = dict((x.group_id, x) for x in labels)
③ 将标签文本扔到一个新模型中:
class StandardLabel(models.Model):
id = models.AutoField(primary_key=True)
text = models.ManyToManyField('LabelText')
class LabelText(models.Model):
id = models.AutoField(primary_key=True)
label = models.CharField(max_length=255)
abbreviation = models.CharField(max_length=255)
language = models.ForeignKey('languages.Language')
labels = StandardLabel.objects.filter(text__language=1)
labels = dict((x.pk, x) for x in labels)
但是这种方法不起作用,每次引用标签的文本时都会导致数据库命中:
x = OtherObjectWithAReferenceToTheseLabels.object.get(pk=3)
thelabel = labels[x.labelIdNumber].text.get(language=1)
我们已经实现了选项 2,但我们觉得它很丑陋——我们不喜欢 group_id 字段,而且我们想不出更好的名称。此外,我们正在使用 StandardLabel 作为抽象模型,我们对它进行子类化以获取不同字段的不同标签集。
我们认为如果选项 3 不命中数据库,那么就是我们想要的。我们认为真正的问题是过滤器 text__language=1 没有缓存 LabelText 实例,因此在我们 text.get(language=1) 时命中了数据库。
您对此有何看法?谁能推荐一个更简洁的解决方案?
解决方案
① 使用 Django 国际化特性
根据你的应用程序设计,你可以考虑使用 Django 的国际化特性。他们使用的方法与桌面软件中发现的方法非常相似。
我们看到问题已经被编辑以添加对 Django 国际化的引用,因此你确实知道它,但 Django 中的 intl 特性不仅仅适用于表单;它涉及很多,并且只需要对你的应用程序设计进行一些调整。
他们的文档在这里:
http://docs.djangoproject.com/en/dev/topics/i18n/#topics-i18n
这个想法是将你的模型定义为只有一种语言。换句话说,不要在你的模型中引用任何语言,而只在你的模型中填写英语。
因此:
class StandardLabel(models.Model):
abbreviation = models.CharField(max_length=255)
label = models.CharField(max_length=255)
我知道这看起来像是你已经完全抛弃了语言的问题,但你实际上只是把它重新安置了。语言不再存在于你的数据模型中,你已经将它推到了视图中。
Django 的国际化特性允许你生成文本翻译文件,并提供了一些将文本从系统提取到文件中的特性。这实际上非常有用,因为它允许你将纯文件发送给你的翻译,从而使他们的工作更容易。添加新语言就像将文件翻译成一种新语言一样简单。
翻译文件定义了来自数据库的标签以及该语言的翻译。有函数可以在运行时动态处理模型、管理视图、javascript 和模板的语言翻译。
例如,在模板中,你可以做类似这样的事情:
<b>Hello {% trans "Here's the string in english" %}</b>
或者在视图代码中,你可以这样做:
# See docs on setting language, or getting Django to auto-set language
s = StandardLabel.objects.get(id=1)
lang_specific_label = ugettext(s.label)
当然,如果你的应用程序完全是关于即时输入新语言,那么这种方法可能不适合你。不过,请查看 Internationalization 项目,因为你可能能够“按原样”使用它,或者从一个确实适用于你的域的 Django 适当的解决方案中获得启发。
② 保持简单
我们希望尽可能地保持简单。使用类似这样的东西,查找速度会更快,代码也更简洁:
class StandardLabel(models.Model):
abbreviation = models.CharField(max_length=255)
label = models.CharField(max_length=255)
language = models.CharField(max_length=2)
# or, alternately, specify language as a foreign key:
#language = models.ForeignKey(Language)
class Meta:
unique_together = ('language', 'abbreviation')
然后根据缩写和语言查询:
l = StandardLabel.objects.get(language='en', abbreviation='suite')
③ 使用可重用的应用程序
我更愿意为每种语言添加一个字段,而不是为每种语言添加一个新模型实例。当你添加新语言时,确实需要修改架构,但这并不难,而且你希望添加语言的频率是多少?与此同时,它将为你提供更好的数据库性能(无需添加联接或索引),并且你不需要用翻译内容来弄乱查询逻辑;保持它们全部都在属于它们的模板中。
更好的是,使用一个可重用的应用程序,如 django-transmeta 或 django-modeltranslation,它使这一切变得非常简单且几乎完全透明。















暂无评论内容