
Для того, чтобы контент из базы данных выводился на разных языках, необходимо создать две таблицы. В одной, назовем "post", будут храниться значения которые не нужно переводить, например id поста, url , author (допустим должен быть всегда латинскими буквами), дата создания и тд.

В другой, назовем "lang_post", будет храниться контент поста - заголовок, основной текст и несколько служебных полей, среди которых указатель языка – ru, uk, en... и поле post_id, значения которого будут соответствовать id поста из первой таблицы.

Это самый рациональный способ, когда мы не дублируем значения из первой таблицы для каждой языковой версии.
Кроме этого, данные таблицы нужно связать между собой, по полю post_id. Это позволяет избежать ошибок и путаницы. В данном случае, связь, при удалении поста, запишет значение Null в таблицу lang_post, а при изменении id поста автоматически перезапишет post_id в таблице lang_post. Кроме того не даст записать несуществующий id поста в таблицу lang_post.
Для быстрого создания данных таблиц и связей предлагаю выполнить следующую миграцию:
Создание миграции:
yii migrate/create Multilingual_KSLв появившийся файл в папке console\migrations вставить:
<?php use yii\db\Migration; class m170220_203728_ForeignKey extends Migration { public function safeUp() { $tableOptions = null; //Опции для mysql if ($this->db->driverName === 'mysql') { $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB'; } //Создание таблицы для категорий $this->createTable('{{%lang_post}}', [ 'id' => $this->primaryKey(), 'title' => $this->string(), 'text' => $this->text()->notNull(), 'lang' => $this->string()->notNull(), 'post_id' => $this->integer(10), ], $tableOptions); //Создание таблиц постов $this->createTable('{{%post}}', [ 'id' => $this->primaryKey(), 'url' => $this->string()->notNull()->unique(), 'author' => $this->string()->notNull(), ], $tableOptions); //Создание индекса в таблице lang_post для ячейки 'post_id' $this->createIndex('FK_lang_post', '{{%lang_post}}', 'post_id'); /* Связывание таблицы lang_post с таблицей post по первичным ключам. * При удалении записи в таблице post, записи из графы post_id таблицы lang_post будут обновлены на NULL, * а при обновлении записи в таблице post, записи из графы post_id таблицы lang_post будут обновлены соответственно. */ $this->addForeignKey( 'FK_lang_post', '{{%lang_post}}', 'post_id', '{{%post}}', 'id', 'SET NULL', 'CASCADE' ); } public function safeDown() { $this->dropTable('{{%lang_post}}'); $this->dropTable('{{%post}}'); } }Конечно данные таблицы вы можете дополнять своими полями по описанному выше принципу.
Для тестирования можете добавить такие данные (выполнить в закладке SQL приложения PhpMyAdmin):
-- Дамп данных таблицы `lang_post`
INSERT INTO `lang_post` (`id`, `title`, `text`, `lang`, `post_id`) VALUES (1, 'Русский заголовок1', 'Русский текст1', 'ru', 1), (2, 'Український заголовок1', 'Український текст1', 'uk', 1), (3, 'English title1', 'English text1', 'en', 1), (4, 'Русский заголовок2', 'Русский текст2', 'ru', 2), (5, 'Український заголовок2', 'Український текст2', 'uk', 2), (6, 'English title2', 'English text2', 'en', 2);
-- Дамп данных таблицы `post`
INSERT INTO `post` (`id`, `url`, `author`) VALUES (1, 'test1', 'test1_author'), (2, 'test2', 'test2_author');
Пример вывода постов из БД в зависимости от текущего языка.
Прежде всего приложение Yii2 у вас уже должно быть настроено на мультиязычность как я писал в этой статье.
После создания данных таблиц, необходимо сделать для них модели. Проще всего это сделать с помощью генератора Yii2 – Gii. Там все как обычно, только нужно поставить птичку в пункте Enable I18N, чтобы названия полей таблиц были заключены в метод Yii:t() для автоматического перевода.
В созданную модель Post добавляем следующие методы:
/* * Возвращает массив объектов модели Post */ public function getPosts(){ return $this->find()->all(); } /* * Возвращает данные для указанного языка */ public function getDataPosts(){ $language = Yii::$app->language; $data_lang = $this->getLangPosts()->where(['lang'=>$language])->one(); return $data_lang; } /* * Возвращает объект поста по его url */ public function getPost($url){ return $this->find()->where(['url' => $url])->one(); }Метод getDataPosts() получает объект модели lang_post с помощью метода getLangPosts() сгенерированного автоматически Gii.
В frontend\controllers\PostController.php
Создаем действие контроллера для вывода списка постов:public function actionIndex(){ $post = new Post(); return $this->render('index', [ 'posts' => $post->getPosts(), ]); }
Действие контроллера для вывода текущего поста:
public function actionView($url) { $model = new Post(); //пост соответствующий переданному url $post = $model->getPost($url); //данные поста из связанной таблицы lang_post $lang_data = $post->getDataPosts(); return $this->render('view', [ 'post' => $post, 'lang_data' => $lang_data, ]); }действие принимает GET параметр – url поста, по нему и будет осуществляться поиск. Этот параметр я использую для создания URL страницы содержащей не номер поста, а его название такого вида: http://site.com/en/test.html. Подробнее тут. Если вы используете id, принципиально ничего не меняется, просто слегка подправить несколько строк в этом действии и методе getPost() модели.
Создадим упрощенный Вид для действия контроллера выводящего список постов actionIndex().
Файл frontend\views\post\index.php:
<?php use yii\helpers\Html; ?> <div class="post-index"> <h1><?= Yii::t('app','Список постов')?></h1> <?php foreach ($posts as $post) { ?> <div class="content"> <?php $lang_data = $post->getDataPosts(); ?> <h3><?= $lang_data->title ?></h3> <h4><?= $lang_data->text ?></h4> <p><?= $post->author ?></p> </div> <?= Html::a(Yii::t('app','Читать далее'), ['post/view', 'url' => $post->url]) ?> <?php } ?> </div>Посты выводятся в цикле. Данные которые подлежат переводу и берутся из таблицы lang_post получаем с помощью связывающего метода getDataPosts().
Упрощенный Вид для действия контроллера выводящего каждый отдельный пост - actionView().
Файл frontend\views\post\view.php:
<?php use yii\helpers\Html; ?> <h1><?= $lang_data->title ?></h1> <div class="meta"> <p>Автор: <?= $post->author ?> </p> </div> <div> <h4><?= $lang_data->text ?></h4> </div>Для вывода заголовка и текста применяется объект $lang_data, который получает данные в модели Post с помощью связанной таблицы lang_post, а для вывода автора поста (допустим имя автора всегда хранится английскими буквами) получаем данные в модели Post напрямую из таблицы post.
Порядок вывода страницы с переводом - списка постов (в файле frontend\views\post\index.php).
Перед тем, как вывести переведенный контент определенной страницы из базы данных, получаем массив объектов Post (все строки таблицы) - метод getPosts() модели. Далее в файле представления index.php, в цикле, этот массив объектов перебирается и для каждого объекта вызывается метод getDataPosts(), который с помощью связывающего метода getLangPosts() (создается при генерации модели автоматически) по полученному значению текущего языка $language = Yii::$app->language; ищет для данного поста соответствующее значение в поле lang и таким образом отбирает нужную строку.
В итоге при выводе контента используется два объекта - один содержит данные таблицы "post", другой данные таблицы "lang_post". Таким образом, для вывода заголовка используется объект $lang_data:
$lang_data->titleа для вывода автора (допустим его имя не подлежит переводу и пишется всегда английскими буквами) используется объект $post:
$post->authorАналогично выводится и страница для каждой отдельной записи - файл frontend\views\post\view.php.
Спасибо!
ответ на комментарий Александр от 09.11.2017
ответ на комментарий Сергей от 09.11.2017
Да, я все сделал по первой статье, а вот со второй не получилось =(
Я правильно понял что надо прислать исходники или каким образом показать в чем проблема?
ответ на комментарий Сергей от 09.11.2017
ответ на комментарий Александр от 09.11.2017