Как использовать Yii с моделью многоязычной базы данных?
У меня возникла проблема с получением данных из моей базы данных, которые я создал, чтобы быть полностью многоязычными, и я надеюсь, что кто-то здесь может мне помочь.
Ive разделил все мои таблицы на 2 части; "универсальная" таблица (не содержит текст, который необходимо перевести), и таблицу, содержащую все поля, которые необходимо перевести с их переводами.
Примеры таблиц:
base_material
id
picture
base_material_i18n
base_material_id
localization_id
name
description
review_status
review_notes
localization
id
language_name
Запрос для получения переводов (используя английский (en) в качестве языка возврата, если перевод отсутствует):
SELECT o.id
, o.type
, o.code
, o.position
, ifnull(t.name,d.name) name
, ifnull(t.description,d.description) description
FROM base_material o
INNER JOIN base_material_i18n d
ON ( o.id=d.base_material_id)
LEFT OUTER JOIN base_material_i18n t
ON ( d.base_material_id=t.base_material_id AND t.localization_id='nl' )
WHERE d.localization_id='en'
Мой вопрос заключается в том, как я могу автоматически получить эти переводы (с исходным языком, как в этом запросе), прикрепленным к моей модели в Yii, когда Im ищет объекты base_material? (Это только 1 таблица примеров, но почти все мои таблицы (20+) построены таким образом, поэтому, если возможно, мне будет нужно что-то гибкое)
Примером существующей системы, использующей то, что мне нужно, является Propel: http://propel.posterous.com/propel-gets-i18n-behavior-and-why-it-matters
Любые идеи, как это сделать? Ive проверил существующие расширения Yii в отношении многоязычных сайтов (например, Многоязычная активная запись), но все они используют другой дизайн базы данных (общая информация + откат язык в главной таблице, переводы в таблице i18n), и я не уверен, как изменить эти расширения для использования моей модели БД.
Если кто-то знает способ изменить существующее расширение, чтобы он мог использовать мою схему БД, тогда это было бы абсолютно блестящим и, вероятно, лучшим способом сделать это.
Изменить: я добавил щедрость, потому что я все еще не могу найти что-либо о том, как заставить Propel работать с Yii (существует расширение для Doctrine, но Doctrine не поддерживает такую модель DB с переводами либо), а также больше информации о том, как справиться с этим, используя существующее расширение Yii или с областями.
Изменить: просмотрено 98 раз, но только 3 upvotes и 1 комментарий. Я не могу не чувствовать, что я делаю что-то не так, будь то в моем вопросе или проекте приложения/базы данных; либо это, либо моя проблема просто уникальна (что меня удивило бы, так как я не думаю, что мой многоязычный дизайн базы данных абсурден;-). Итак, если кто-нибудь знает о более широком решении для многоязычных сайтов с Yii и/или Propel (помимо текущих расширений, которые мне действительно не нравятся из-за дублирования текстовых полей) или что-то подобное, сообщите мне также.
Спасибо заранее!
Ответы
Ответ 1
Я также ищу универсальное решение для внедрения i18n в модели Yii.
Недавно я выбрал очень похожую схему базы данных для такого проекта, как вы.
Единственное различие заключается в том, что я не использую отдельную таблицу языков, я храню информацию о языке в таблице i18n.
Следующее решение без пользовательской инструкции SQL, но я думаю, что это может быть реализовано с параметрами отношения, в любом случае, если вы работаете с внешним ключом в своей базе данных (например, MySQL InnoDB), gii создаст отношения между вашим базовым_материалом и base_material_i18n, например
class BaseMaterial extends CActiveRecord
public function relations()
{
return array(
'baseMaterialI18ns' => array(self::HAS_MANY, 'base_material_i18n', 'id'),
);
}
class BaseMaterialI18n extends CActiveRecord
public function relations()
{
return array(
'baseMaterial' => array(self::BELONGS_TO, 'base_material', 'id'),
);
}
Теперь вы сможете получить доступ к своим переводам, используя объектную нотацию для отношений.
$model = BaseMaterial::model()->with('baseMaterialI18ns')->findByPk(1);
foreach($model->baseMaterialI18ns AS $translation) {
if ($translation->language != "the language I need") continue:
// do something with translation data ...
}
Я думал о создании поведения или базового класса для тех моделей, которые будут действовать как помощник для управления переводами - псевдокод:
I18nActiveRecord extends CActiveRecord
protected $_attributesI18n;
// populate _attributesI18n on query ...
public function __get($name) {
if(isset($this->_attributesI18n['language_I_need'][$name]))
return $this->_attributesI18n[$name];
else if(isset($this->_attributesI18n['fallback_language'][$name]))
return $this->_attributesI18n[$name];
else
parent::__get();
}
CActiveRecord __get() source
Для поиска нужной записи i18n необходимо выполнить еще одну работу, также вы можете ограничить параметр with(), чтобы повысить производительность и уменьшить парсинг на стороне PHP.
Но могут быть разные варианты использования, как определить значение, например. все переводы, перевод или возврат, отсутствие возврата (пустое значение).
Сценарии могут быть полезны здесь.
PS: Я бы выбрал проект github!
Ответ 2
Вы пробовали http://www.yiiframework.com/extension/i18n-columns/ (на основе http://www.yiiframework.com/extension/stranslateablebehavior/)?
Это альтернативный, более простой подход, добавляя новые поля таблицы в стиле {поле} _ {код языка}, а затем устанавливая переведенное поле в исходной модели на текущий перевод языка на afterFind.
По сути, он заставит вас работать с переводимыми полями, при этом переведенный контент будет автоматически загружен, для хорошего и плохого:). Добавление и удаление языков (= столбцы) выполняется с помощью миграции.
Ответ 3
Вы можете попытаться использовать простое многоязычное расширение CRUD.
он очень прост в использовании и модификации. вам просто нужно добавить языковое поле в таблицу.
просто смотрите описание здесь: http://all-of.me/yii-multilingual-crud/
он находится в альфа-состоянии, но пробовал по нескольким проектам. вы можете легко модифицировать его или связаться с автором, чтобы исправить или добавить функции.