假设我有以下Django模型:
class StandardLabel(models.Model):
id = models.AutoField(primary_key=True)
label = models.CharField(max_length=255)
abbreviation = models.CharField(max_length=255)
每个标签都有一个ID号,标签文本和缩写。现在,我希望将这些标签翻译成其他语言。这样做的最佳方式是什么?
在我看来,我有几个选择:
1:将翻译添加为模型上的字段:
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)
这显然不太理想 - 添加语言需要编辑模型,正确的字段名称取决于语言。
2:将语言添加为外键:
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')
这要好得多,现在我可以要求所有使用某种语言的标签,然后把它们扔进dict:
labels = StandardLabel.objects.filter(language=1)
labels = dict((x.pk, x) for x in labels)
但问题是标签dict意味着是一个查找表,如下所示:
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)
3:将标签文本丢弃到新模型中:
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国际化系统没有帮助。
答案 0 :(得分:3)
根据您的应用程序设计,您可能会考虑的另一个选择是利用Django的国际化功能。他们使用的方法与桌面软件中的方法相当普遍。
我看到编辑的问题是为了添加对Django国际化的引用,所以你知道它,但是Django中的intl特性不仅仅适用于Forms;它触动了很多,只需要对你的应用程序设计进行一些调整。
他们的文档在这里: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)
当然,如果您的应用只是输入新语言on the fly
,那么这种方法可能对您不起作用。不过,请看看国际化项目,因为您可以“按原样”使用它,或者受到适合您的域的适合django的解决方案的启发。
答案 1 :(得分:2)
我会尽可能地保持简单。查找会更快,代码更清晰,如下所示:
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')
答案 2 :(得分:1)
我更倾向于为每种语言添加一个字段而不是每种语言的新模型实例。当您添加新语言时,它确实需要更改架构,但这并不难,您希望多久添加一次语言?与此同时,它将为您提供更好的数据库性能(没有添加的连接或索引),您不必使用翻译内容来破坏查询逻辑;将它全部保存在它所属的模板中。
更好的是,使用可重复使用的应用,例如django-transmeta或django-modeltranslation,这使得这个愚蠢的简单且几乎完全透明。
答案 3 :(得分:0)
虽然我会选择Daniel's solution,但这是我从你的评论中理解的另一种选择:
您可以使用XMLField或JSONField来存储您的语言/翻译对。这将允许引用标签的对象对所有翻译使用单个id
。然后,您可以使用自定义管理器方法来调用特定的翻译:
Label.objects.get_by_language('ru', **kwargs)
或者稍微更清晰且稍微复杂的解决方案与admin
一起使用就是将XMLField非规范化为另一个与Label
模型具有多对一关系的模型。相同的API,但不是解析XML,它可以查询相关的模型。
对于这两个建议,标签的用户都会指向一个对象。
我不会太担心查询,Django会缓存查询,而你的DBMS也可能会有更好的缓存。