2010-02-09 4 views
50

Можно создать дубликат:
Schema for a multilanguage databaseКакая лучшая структура базы данных для хранения многоязычных данных?

Вот пример:

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

Проблема: каждый новый язык необходимо изменить структуру таблицы.

Вот еще один пример:

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

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

Проблема: каждый новый язык будет нуждаться в создании новых таблиц и поле «цена» дублируются в каждой таблице.

Вот еще один пример:

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

Проблема: Fuc * ING трудно?

+4

Третий способ более-менее правильный - что в этом трудно сделать? –

+2

Проблема заключается в том, что при каждом найденном вами решении вы всегда найдете случай, когда вам нужно изменить таблицу - то есть больше языков, разных языков, другое поле ... –

+0

Вы можете проверить эту ссылку: http://www.gsdesign.ro/blog/multilanguage-database-design-approach/ , хотя чтение комментариев очень полезно –

ответ

25

Ваш третий пример на самом деле является способом решения проблемы. Трудный, но выполнимый.

Удалить ссылку на продукт из таблицы переводов и поместить ссылку на перевод там, где вам это нужно (наоборот).

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

В качестве альтернативы (не особенно хороший), вы можете иметь один одно поле и сохранить все переводы там слились воедино (как XML, например).

<translation> 
    <en>Supplier</en> 
    <de>Lieferant</de> 
    <fr>Fournisseur</fr> 
</translation> 
+10

Что делать, если таблица продуктов содержит несколько переведенных полей? При извлечении продуктов вам нужно будет сделать одно дополнительное соединение для каждого переведенного поля, что приведет к серьезным проблемам с производительностью. Существует также (IMO) дополнительная сложность для вставки/обновления/удаления. Единственным преимуществом этого является меньшее количество таблиц. Я бы пошел на метод, предложенный Цыганом Кингом или Клементом: я думаю, что это хороший баланс между проблемами производительности, сложности и обслуживания. –

-1

У многих есть много отношений.

У вас есть таблица данных, таблица языков и таблица data_language.

В таблице data_language у вас есть

идентификатор, data_id, LANGUAGE_ID

Я думаю, что лучше всего подходит для вашего.

+0

@AntonioCS - таблица «данные» не является «продуктовой» таблицей, верно? –

+0

@TiuTalk это. Таким образом, таблица продуктов не должна знать, какие языки существуют, и таблица языков. Это все в таблице data_language (или в этом случае «table_language table») – AntonioCS

10

Для того, чтобы уменьшить количество JOIN, вы могли бы отмежеваться переведенный и не переведены в 2 отдельных таблицах:

[ products ] 
id (INT) 
price (DECIMAL) 

[ products_i18n ] 
id (INT) 
name (VARCHAR) 
description (VARCHAR) 
lang_code (CHAR(5)) 
+0

@ Clément - Проблема в том, что таблица продуктов получает новое поле ... Мне также нужно будет изменить таблицу products_i18n. :/ –

+6

@TiuTalk - только одна из таблиц получит новое поле, если это переведенное поле, оно переходит в 'products_i18n', иначе оно переходит в' products'. Таким образом, вы не дублируете какую-либо информацию. –

+0

@ Clément: product.id является пользователем как FK в products_i18n.id или вы используете третью таблицу соединений? – CoR

-2

Мы используем эту концепцию для нашего Webiste (600k просмотров в день) и (возможно удивительно) это работает. Разумеется, наряду с кешированием и оптимизацией запросов.

[attribute_names] 
id (INT) 
name (VARCHAR) 

[languages_names] 
id (INT) 
name (VARCHAR) 

[products] 
id (INT) 
attr_id (INT) 
value (MEDIUMTEXT) 
lang_id (INT) 
+0

А как насчет дублированных полей, таких как цена? –

+0

уверен, что сработает. – Rolf

3

В моем $ DAYJOB мы используем gettext для I18N. Я написал плагин для xgettext.pl, который извлекает весь текст на английском языке из таблиц базы данных и добавляет их в master messages.pot.

Работает очень хорошо - переводчики обрабатывают только один файл при выполнении перевода - файл po. При выполнении переводов не возится с записями базы данных.

29

Подобный метод 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 

Таким образом, для каждой таблицы, сделать еще одну таблицу (в моем случае с суффиксом «_t»), который держит переведенные поля. Когда вы SELECT * FROM products, просто ... LEFT JOIN products_t ON products_t.id = products.id AND products_t.language = CURRENT_LANGUAGE.

Не так сложно и держит вас свободными от головных болей.

2

[язык] идентификатора (интермедиат PK) кода (VARCHAR)

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

Я использую этот метод, но в моем случае, это не в точке продукта зрения, для различных страниц моя CMS, эта работа неплоха.

Если у вас есть много продуктов, это может быть головная боль, чтобы обновить один на 5 или 6 языках ... но это вопрос работы с макетом.

0

А как насчет четвертого решения?

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

* Translation_of * является FK из его самоуправления. Когда вы добавляете язык по умолчанию * translation_of * имеет значение Null. Но когда вы добавляете второй язык * translation_of * принимает первичный идентификатор языка продукта.

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

В этом случае мы получаем все переводы для продукта с идентификатором 1.

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

Мы получаем только продукт в польском переводе. Без второй таблицы и JOINS.

+0

Это интересный подход. Мне нравится легкость запросов, но это нарушает предположение, что когда-либо вход в таблицу продуктов является одним продуктом, поэтому нужно помнить об этом. Он также позволяет вам использовать правильные типы (varchar и т. Д.) Для полей. – Rolf

+0

Я думал о том, чтобы реализовать то же самое прямо сейчас, но не нашел это решение нигде. Я вижу, что ваш пост с 2011 года. У вас были проблемы с этим? Вы все еще думаете, что это хорошее решение? Благодарю. – tabacitu

+0

@tabacitu Пробовали ли вы это? Как выглядит вся схема db? Как это делается при вставке, обновлении, удалении ...? – CoR

Смежные вопросы