Возможный дубликат:
Схема для многоязычной базы данныхВот пример:
[ 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)
Проблема: трудно?
Твой третий пример - это обычный способ решения проблемы. Трудно, но выполнимо.
Удалите ссылку на продукт из таблицы переводов и поместите ссылку на перевод там, где он вам нужен (наоборот).
[ 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>
Аналогично методу 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
, просто ... ЛЕВОЕ СОЕДИНЕНИЕ products_t НА products_t.id = products.id И products_t.language = CURRENT_LANGUAGE
.
Не так уж и сложно, и избавляет от головной боли.
Для того, чтобы уменьшить количество JOIN, можно разделить переведенные и непереведенные в 2 отдельных таблицах :
[ products ]
id (INT)
price (DECIMAL)
[ products_i18n ]
id (INT)
name (VARCHAR)
description (VARCHAR)
lang_code (CHAR(5))
В моем $ DAYJOB мы используем gettext для I18N. Я написал плагин для xgettext.pl , который извлекает весь английский текст из таблиц базы данных и добавляет их в главный messages.pot.
Это работает очень хорошо - переводчики работают только с одним файлом при переводе - файлом po. При переводе не нужно возиться с записями в базе данных.
Когда браузер обнаруживает элементы SCRIPT
, он прекращает синтаксический анализ и визуализацию HTML и начинает синтаксический анализ и интерпретацию его содержимого. Это связано с тем, что элементы кода SCRIPT
могут изменить уже проанализированное дерево DOM.
Поэтому рекомендуется поместить SCRIPT
в нижнюю часть документа , чтобы все тело документа уже было проанализировано.
Поэтому я бы предпочел запросить географические местоположения вообще (возможно, вы можете собрать их на стороне сервера и напечатать в конце). Если вы не можете или не хотите этого сделать, добавьте атрибут defer
к элементам SCRIPT
, чтобы сообщить синтаксическому анализатору не ждать сценария.
Декларативная безопасность в Java EE действительно не подходит для таких требований. Проблема безопасности может быть разделена на две группы:
. Мы использовали встроенную аутентификацию, чтобы иметь основной набор, и полагались на механизмы входа Java EE по умолчанию. Но в итоге мы управляем частью полномочий вручную на уровне приложения.
Даже роли, которые будут загружены и связаны с участником ( isUserInRole
для веб-сайта и isCallerInRole
для EJB), должны быть указаны в web.xml
или ejb.xml
, что не обеспечивает достаточной гибкости. Затем нам пришлось загрузить роли вручную (согласно участнику) из LDAP или ActiveDirectory. Затем мы использовали EJB3 перехватчики и сервлетный фильтр для выполнения проверок безопасности.
Однако я бы настоятельно предложил придерживаться ролевого контроля доступа (RBAC) и не внедрять что-то более вычурное. Существует несколько рамочных основ, которые могут помочь справиться с собственными RBAC.
Мы также рассмотрели JSecurity и Acegi Security , и они казались интересными.
-121--3505016-[языки] id (int PK) код (варчар)
[products]
id (int PK)
name
price
all other fields of product
id_language ( int FK )
Я на самом деле использую этот метод, но в моем случае, это не с точки зрения продукта, для различных страниц в моей CMS, эта работа вполне хорошо.
Если у вас много продуктов, может быть головной болью обновить один на 5 или 6 языках... но это вопрос работы макета.
По крайней мере, необходимо проверить, поддерживает ли ваш веб-сервер пулы приложений ASP.NET 4.0.
-121--4817639- Если имеется только инструкция INSERT, можно использовать метод ExeciveNonQuery ()
, который возвращает количество затронутых строк.
Вот так:
cmd = New OleDbCommand("INSERT INTO blah blah...", cn)
rowCount = cmd.ExecuteNonQuery()
If rowCount < 1 Then
' Blah
Вы должны меня извинить, если VB не верен, я не тестировал его, но я надеюсь, что вы получите идею.
-121--4349415-Мы используем эту концепцию для нашего веб-сайта (600 000 просмотров в день) и (может быть, удивительно) это работает. Обязательно наряду с кэшированием и оптимизацией запросов.
[attribute_names]
id (INT)
name (VARCHAR)
[languages_names]
id (INT)
name (VARCHAR)
[products]
id (INT)
attr_id (INT)
value (MEDIUMTEXT)
lang_id (INT)
Имейте отношения "многие ко многим".
У вас есть таблица данных, таблица языков и таблица data_language.
В таблице data_language у вас есть
id, data_id, language_id
Я думаю, это лучше всего подойдет вам.