Question

Disons que j'ai le modèle Django suivant:

class StandardLabel(models.Model):
    id = models.AutoField(primary_key=True)
    label = models.CharField(max_length=255)
    abbreviation = models.CharField(max_length=255)

Chaque étiquette a un numéro d'identification, son texte et une abréviation. Maintenant, je veux avoir ces étiquettes traduisibles dans d'autres langues. Quelle est la meilleure façon de faire cela?

Comme je le vois, j'ai quelques options:

1: ajoutez les traductions sous forme de champs dans le modèle:

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)

Ce n'est évidemment pas idéal - l'ajout de langues nécessite la modification du modèle, le nom de champ correct dépend de la langue.

2: ajoutez la langue en tant que clé étrangère:

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')

C’est beaucoup mieux, je peux maintenant demander toutes les étiquettes avec un certain langage et les jeter dans un dict:

labels = StandardLabel.objects.filter(language=1)
labels = dict((x.pk, x) for x in labels)

Mais le problème ici est que le libellé dict est censé être une table de recherche, comme suit:

x = OtherObjectWithAReferenceToTheseLabels.object.get(pk=3)
thelabel = labels[x.labelIdNumber].label

Ce qui ne fonctionne pas s’il ya une ligne par étiquette, éventuellement avec plusieurs langues pour une seule étiquette. Pour résoudre ce problème, il me faut un autre champ:

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: jetez le texte de l'étiquette dans un nouveau modèle:

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)

Mais cela ne fonctionne pas et provoque une frappe de base de données chaque fois que je référence le texte du libellé:

x = OtherObjectWithAReferenceToTheseLabels.object.get(pk=3)
thelabel = labels[x.labelIdNumber].text.get(language=1)

J'ai implémenté l'option 2, mais je la trouve très moche - je n'aime pas le champ group_id, et je ne peux penser à rien de mieux pour le nommer. En outre, StandardLabel, tel que je l’utilise, est un modèle abstrait que je sous-classe pour obtenir différents jeux d’étiquettes pour différents champs.

Je suppose que si l’option 3 / n’avait pas accès à la base de données, c’était ce que je choisirais. Je crois que le vrai problème est que le filtre text__language = 1 ne met pas en cache les instances LabelText , et que la base de données est touchée lorsque je text.get (langue = 1)

Quelles sont vos pensées à ce sujet? Quelqu'un peut-il recommander une solution plus propre?

Modifier : je tiens à préciser que ce ne sont pas des étiquettes de formulaire. Le système d'internationalisation de Django ne vous aide pas.

Était-ce utile?

La solution

Je préférerais de loin ajouter un champ par langue plutôt qu'une nouvelle instance de modèle par langue. Cela nécessite une modification du schéma lorsque vous ajoutez une nouvelle langue, mais ce n'est pas difficile et combien de fois comptez-vous ajouter des langues? En attendant, cela vous donnera de meilleures performances de base de données (pas de jointures ajoutées ni d’index) et vous n’aurez pas à perdre votre logique de requête avec des éléments de traduction; conservez le tout dans les modèles auxquels il appartient.

Encore mieux, utilisez une application réutilisable telle que django-transmeta ou django-modeltranslation qui rend cette stupide simple et presque complètement transparente.

Autres conseils

Une autre option que vous pourriez envisager, selon la conception de votre application, consiste à utiliser les fonctionnalités d'internationalisation de Django. L'approche qu'ils utilisent est assez commune à celle utilisée dans les logiciels de bureau.

Je vois que la question a été modifiée pour ajouter une référence à l’internationalisation de Django. Vous en avez donc connaissance, mais les fonctionnalités intl de Django s’appliquent à beaucoup plus que des formulaires; cela touche beaucoup et ne nécessite que quelques ajustements dans la conception de votre application.

Leurs documents sont ici: http: //docs.djangoproject .com / fr / dev / topics / i18n / # topics-i18n

L’idée est que vous définissiez votre modèle comme s’il n’y avait qu’une seule langue. En d’autres termes, ne faites aucune référence à la langue et ne mettez que, disons, l’anglais dans le modèle.

Donc:

class StandardLabel(models.Model):
    abbreviation = models.CharField(max_length=255)
    label = models.CharField(max_length=255)

Je sais que vous semblez avoir totalement rejeté le problème de la langue, mais que vous venez de le déplacer. Au lieu que la langue soit dans votre modèle de données, vous l'avez poussée dans la vue.

Les fonctionnalités d'internationalisation de Django vous permettent de générer des fichiers de traduction de texte et fournissent un certain nombre de fonctionnalités permettant d'extraire du texte du système dans des fichiers. C'est en fait très utile car cela vous permet d'envoyer des fichiers en clair à votre traducteur, ce qui facilite son travail. Ajouter une nouvelle langue est aussi simple que de faire traduire le fichier dans une nouvelle langue.

Les fichiers de traduction définissent l'étiquette de la base de données et une traduction pour cette langue. Il existe des fonctions permettant de gérer la traduction de la langue de manière dynamique au moment de l’exécution pour les modèles, les vues administrateur, javascript et les modèles.

Par exemple, dans un modèle, vous pouvez faire quelque chose comme:

<b>Hello {% trans "Here's the string in english" %}</b>

Ou, dans l'affichage du code, vous pouvez faire:

# See docs on setting language, or getting Django to auto-set language
s = StandardLabel.objects.get(id=1)
lang_specific_label = ugettext(s.label)

Bien sûr, si votre application consiste uniquement à saisir de nouvelles langues à la volée , cette approche risque de ne pas fonctionner pour vous. Néanmoins, jetez un coup d’œil au projet d’internationalisation car vous pourrez soit l’utiliser "en l’état", soit vous inspirer d’une solution appropriée à Django qui fonctionne pour votre domaine.

Je voudrais garder les choses aussi simples que possible. La recherche sera plus rapide et le code plus propre avec quelque chose comme ceci:

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')

Ensuite, interrogez sur la base d'une abréviation et de la langue:

l = StandardLabel.objects.get(language='en', abbreviation='suite')

Bien que j'aie choisi la solution de Daniel , ici est une alternative à ce que j'ai compris de vos commentaires:

Vous pouvez utiliser un XMLField ou JSONField pour stockez vos paires de langues / traduction. Cela permettrait à vos objets référençant vos étiquettes d'utiliser un seul id pour toutes les traductions. Et vous pouvez alors avoir une méthode de gestionnaire personnalisée pour appeler une traduction spécifique:

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

Ou une solution légèrement plus propre et légèrement plus compliquée qui fonctionne bien avec admin consisterait à dénormaliser le XMLField en un autre modèle avec une relation plusieurs à un avec le Label . modèle. Même API, mais au lieu d’analyser XML, elle pourrait interroger les modèles associés.

Pour les deux suggestions, il existe un seul objet vers lequel les utilisateurs d'une étiquette doivent pointer.

Je ne m'inquiéterais pas trop des requêtes, Django met en cache les requêtes et votre SGBD aurait probablement également une mise en cache supérieure.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top