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?
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>
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.
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))
À 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.
[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.
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.