2

假设我有以下 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(language=1)

您对此有何看法?谁能推荐一个更清洁的解决方案?

编辑:为了清楚起见,这些不是表单标签,所以 Django 国际化系统没有帮助。

4

4 回答 4

3

当然,根据您的应用程序设计,您可能会考虑的另一个选择是利用 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)

当然,如果您的应用程序都是关于输入新语言on the fly的,那么这种方法可能不适合您。不过,请查看 Internationalization 项目,因为您可能可以“按原样”使用它,或者受到启发,找到适合您的域的 django 解决方案。

于 2009-03-05T19:51:20.523 回答
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')
于 2009-03-05T19:38:25.873 回答
1

我更喜欢为每种语言添加一个字段,而不是为每种语言添加一个新模型实例。添加新语言时确实需要更改架构,但这并不难,您希望多久添加一次语言?同时,它会为您提供更好的数据库性能(不添加连接或索引),并且您不必用翻译的东西弄乱您的查询逻辑;将其全部保存在它所属的模板中。

更好的是,使用像django-transmetadjango-modeltranslation这样的可重复使用的应用程序,这使得这个愚蠢的简单并且几乎完全透明。

于 2009-03-06T19:26:19.903 回答
0

虽然我会选择Daniel 的解决方案,但这是我从您的评论中了解到的另一种选择:

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

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

或者一个稍微干净和稍微复杂一点的解决方案可以很好地使用,admin将 XMLField 非规范化为另一个与模型具有多对一关系的Label模型。相同的 API,但它可以查询相关模型,而不是解析 XML。

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

我不会过多地担心查询,Django 缓存查询,您的 DBMS 可能也有更好的缓存。

于 2009-03-05T21:30:00.567 回答