web-dev-qa-db-fra.com

Quelle est la meilleure structure de base de données pour conserver des données multilingues?

Dupliquer possible:
Schéma pour une base de données multilingue

Voici un exemple:

[ products ]
id (INT)
name-en_us (VARCHAR)
name-es_es (VARCHAR)
name-pt_br (VARCHAR)
description-en_us (VARCHAR)
description-es_es (VARCHAR)
description-pt_br (VARCHAR)
price (DECIMAL)

Le problème: chaque nouvelle langue devra modifier la structure de la table.

Voici un autre exemple:

[ products-en_us ]
id (INT)
name (VARCHAR)
description (VARCHAR)
price (DECIMAL)

[ products-es_es ]
id (INT)
name (VARCHAR)
description (VARCHAR)
price (DECIMAL)

Le problème: chaque nouvelle langue nécessitera la création de nouvelles tables et le champ "price" sera dupliqué dans chaque table.

Voici un autre exemple:

[ languages ]
id (INT)
name (VARCHAR)

[ products ]
id (INT)
price (DECIMAL)

[ translation ]
id (INT, PK)
model (VARCHAR) // product
field (VARCHAR) // name
language_id (INT, FK) 
text (VARCHAR)

Le problème: vous avez du mal?

54
Thiago Belem

Votre troisième exemple est en fait la manière dont le problème est généralement résolu. Dur, mais faisable.

Supprimez la référence au produit de la table de traduction et placez une référence à la traduction là où vous en avez besoin (dans l’inverse).

[ products ]
id (INT)
price (DECIMAL)
title_translation_id (INT, FK)

[ translation ]
id (INT, PK)
neutral_text (VARCHAR)
-- other properties that may be useful (date, creator etc.)

[ translation_text ]
translation_id (INT, FK)
language_id (INT, FK) 
text (VARCHAR)

En guise d'alternative (pas spécialement bonne), vous pouvez avoir un seul champ et y conserver toutes les traductions fusionnées (comme XML, par exemple).

<translation>
  <en>Supplier</en>
  <de>Lieferant</de>
  <fr>Fournisseur</fr>
</translation>
28
user151323

Similaire à la méthode 3:

[languages]
id (int PK)
code (varchar)

[products]
id (int PK)
neutral_fields (mixed)

[products_t]
id (int FK)
language (int FK)
translated_fields (mixed)
PRIMARY KEY: id,language

Donc, pour chaque table, créez une autre table (dans mon cas, avec le suffixe "_t") qui contient les champs traduits . Lorsque vous SELECT * FROM products, simplement ... LEFT JOIN products_t ON products_t.id = products.id AND products_t.language = CURRENT_LANGUAGE.

Pas si difficile, et vous évite les maux de tête.

35
Gipsy King

Afin de réduire le nombre de JOIN, vous pouvez séparer les fichiers traduits et non traduits dans 2 tableaux distincts:

[ products ]
id (INT)
price (DECIMAL)

[ products_i18n ]
id (INT)
name (VARCHAR)
description (VARCHAR)
lang_code (CHAR(5))
13
Clément

À mon $ DAYJOB, nous utilisons gettext pour I18N. J'ai écrit un plugin sur xgettext.pl qui extrait tout le texte anglais des tables de la base de données et les ajoute au message principal.

Cela fonctionne très bien - les traducteurs ne traitent qu’un seul fichier lors de la traduction - le fichier po. Il n'y a pas de bidouillage avec les entrées de base de données lors de la traduction.

3
holygeek

[langues] id (int PK) code (varchar)

[products]
id (int PK)
name
price
all other fields of product
id_language ( int FK )

J'utilise effectivement cette méthode, mais dans mon cas, ce n'est pas du point de vue du produit, pour les différentes pages de mon système de gestion de contenu, ce travail est plutôt bien.

Si vous avez beaucoup de produits, vous pourriez avoir mal à la tête d'en mettre à jour un seul en 5 ou 6 langues ... mais c'est une question de travail de mise en page.

2
Tio

Qu'en est-il de la quatrième solution?

[ products ]
id (INT)
language (VARCHAR 2)
name (VARCHAR)
description (VARCHAR)
price (DECIMAL)
*translation_of (INT FK)*

* Translation_of * estFKde lui-même. Lorsque vous ajoutez la langue par défaut * translation_of * est défini sur Null. Mais lorsque vous ajoutez une deuxième langue * translation_of * prend l'identifiant principal de la langue du produit.

SELECT * FROM products WHERE id = 1 AND translation_of = 1

Dans ce cas, nous obtenons toutes les traductions du produit dont l'identifiant est 1.

SELECT * FROM products WHERE id = 1 AND translation_of = 1 AND language = 'pl'

Nous n'obtenons que des produits en traduction polonaise. Sans deuxième table et JOINS.

0
chf