假设我有以下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')

这要好得多,现在我可以要求所有使用某种语言的标签,并把它们扔进一个字典:

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(语言)时,数据库会被命中= 1)

您对此有何看法?任何人都可以推荐更清洁的解决方案吗?

编辑:为了说清楚,这些不是表单标签,因此Django国际化系统没有帮助。

有帮助吗?

解决方案

我更倾向于为每种语言添加一个字段而不是每种语言的新模型实例。当您添加新语言时,它确实需要更改架构,但这并不难,您希望多久添加一次语言?与此同时,它将为您提供更好的数据库性能(没有添加的连接或索引),您不必使用翻译内容来破坏查询逻辑;将它全部保存在它所属的模板中。

更好的是,使用可重复使用的应用,例如 django-transmeta django-modeltranslation ,使这个愚蠢简单,几乎完全透明。

其他提示

根据您的应用程序设计,您可能会考虑的另一个选择是利用Django的国际化功能。他们使用的方法与桌面软件中的方法相当普遍。

我看到编辑的问题是为了添加对Django国际化的引用,所以你知道它,但是Django中的intl特性不仅仅适用于Forms;它触动了很多,只需要对你的应用程序设计进行一些调整。

他们的文档在这里: http://docs.djangoproject的.com / EN的/ dev /主题/ I18N /#主题-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)

当然,如果您的应用程序是关于即时输入新语言 ,那么这种方法可能对您无效。不过,请查看国际化项目,因为您可以“按原样”使用它,或者启发适用于您的域的适合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')

虽然我会使用 Daniel的解决方案,但这里是我从你的评论中理解的另一种选择:

您可以使用 XMLField 或JSONField存储您的语言/翻译对。这将允许引用标签的对象对所有翻译使用单个 id 。然后,您可以使用自定义管理器方法来调用特定的翻译:

Label.objects.get_by_language('ru', **kwargs)

或者稍微更清晰,稍微复杂的解决方案,与 admin 配合使用,可以将XMLField非规范化为另一个与 Label 具有多对一关系的模型模型。相同的API,但不是解析XML,它可以查询相关的模型。

对于这两个建议,标签的用户都会指向一个对象。

我不会过多担心查询,Django会缓存查询,并且您的DBMS也可能在那里拥有更好的缓存。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top