Виджет мультиязычности в YII2 без использования базы данных
Я использую шаблон advanced поэтому расположение файлов могут отличаться.
Цель
- переключение сайта между двумя языками: ru и en;
- отображение языка в адресной строке в виде site.com/en/;
- автоматическое перенаправление пользователя на наиболее подходящий для него язык, если он перешел на сайт без указания языка;
- хранение переводов должно осуществляться в PHP файлах в виде массивов;
Конфигурация
Правим файл конфигурации, в моем случаи это \frontend\config\main.php
return [
'language'=>'en',
// язык по умолчанию, на который будет перенаправлен пользователь в случае невозможности определения для него наиболее подходящего языка на основе данных предоставляемых его браузером.
'components' => [
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'class' => 'frontend\widgets\MultiLang\components\UrlManager',
// заменяем стандартный урл.менеджер на наш.
'languages' => ['ru', 'en'],
//список языков на который переводим сайт
'enableDefaultLanguageUrlCode' => true,
// показываем идентификатор языка по умолчанию, если false, то при в корне сайта не будет виден идентификатор языка www.site.com/ , с true – www.site.com/ru
'rules'=>[
'/' => 'site/index',
'//'=>'/',
],
],
'i18n' => [
'translations' => [
'app*' => [
// app название нашего php файла переводов который нужно создать app.php (может быть любым)
'class' => 'yii\i18n\PhpMessageSource',
'basePath' => '@frontend/messages',
// путь для нашего файла переводов frontend/messages/ru/app.php
'sourceLanguage' => 'en',
// язык с какого переводим, то есть, в проекте все надписи пишем на английском
],
],
],
],
'class' => 'frontend\widgets\MultiLang\components\UrlManager', содержание файла взято отсюда, можно следовать инструкции разработчика и использовать composer, но мы то делаем виджет, по этому просто скопируем UrlManager.php в наш виджет.
Файл со списком переводов frontend/messages/ru/app.php, должен содержать массив
return [
...
'Example text...' => 'Пример текста...',
...
];
Используем встроенный метод t
= Yii::t('app', 'Example text...') ?>
В первом аргументе указываем категорию, у нас она одна — app, вы можете создать много файлов переводов. Во втором аргументе пишем английский текст в том виде как он должен отображаться на сайте.
Переключение языков.
Создаем папку MultiLang в папке с виджетами, у меня это выглядит так:
Frontend\
Widgets\
MultiLang\
Components\
UrlManager.php
Views\
View.php
MultiLang.php
Для показа переключателя языка в любом месте вызываем
= MultiLang::widget(['cssClass'=>'pull-right language']); ?>
Не забудьте прописать путь к виджету
use frontend\widgets\MultiLang\MultiLang;
Содержание класса frontend\widgets\MultiLang\MultiLang.php
render('view', [
'cssClass' => $this->cssClass,
]);
}
}
Содержание представление frontend\widgets\MultiLang\views\view.php
Заключение
В целом реализация интернационализации в Yii2 не представляет ничего сложного, получился простой виджет, с тремя файлами.
UrlManager.php взят отсюда. MultiLang.php просто рендерит представление. View.php само представление.
Комментарии (3)
17 декабря 2016 в 17:36 (комментарий был изменён)
+2↑
↓
Спасибо за ваши старания, позвольте высказать свою критику по поводу архитектурных решений.
'frontend\widgets\MultiLang\components\UrlManager'
Предложенная иерархия директорий (и неймспейсов) не укладывается в хорошие практики. Виджеты — это виджеты, а компоненты — это компоненты. Если у вас есть компонент, а рядом с ним — виджет для работы с этим компонентом, при этом существует общая предметная область, с которой ведется работа — это больше похоже на расширение.
Я бы предложил выделить это в отдельный репозиторий, или (если не планируется переиспользование) — разместить код в вашем проекте таким образом:
frontend\ extensions\ MultiLang\ Components\ UrlManager.php Views\ View.php Widgets\ MultiLang.php
содержание файла взято отсюда, можно следовать инструкции разработчика и использовать composer, но мы то делаем виджет, по этому просто скопируем UrlManager.php в наш виджет
Копируя UrlManager.php в свой проект, вы лишаете себя чудесной возможности получать обновления с улучшениями и исправленными ошибками из оригинального репозитория. Отказ от использования composer в пользу копи-пасты — один из самых вредных советов для PHP разработчика в 2016 году.
Что касается кода виджета:
use yii\helpers\Html; class MultiLang extends \yii\bootstrap\Widget { public $cssClass; public function init(){} // ... }
Класс
\yii\bootstrap\Widget
находится в отдельном репозитории yii2-bootstrap и наследуется отyii\base\Widget
, добавляя некоторые методы для работы с Frontend-фреймворком Bootstarp. Вы не используете никаких возможностей этого класса, достаточно будет наследования отyii\base\Widget
.
Кроме того, вы указали лишнийuse
и без какого-либо смысла предопределили методinit()
.В коде представления вы указали
use Yii;
, но каждый раз при обращении к Yii явно указываете namespace:\Yii::$app->request->get()
Да и если следовать правилам распределения ответственности в MVC, представление не должно «добывать» данные самостоятельно — данные должен собрать тот, кто вызывает рендер представления. Было бы уместно избавится от обращения к компонентам
request
,controller
и свойствуlanguage
из представления, а перенести это в виджет.17 декабря 2016 в 17:48 (комментарий был изменён)
+2↑
↓
Кроме того, название
MultiLang
мне не кажется само-описывающим. Пока не откроешь код, сложно однозначно сказать, что делает этот класс. Что-то про мультиязычность, но что именно?
Я бы его назвалLanguageSwitcher
. Согласитесь, сразу понятно, что это переключатель языков, не так ли?Если всё таки использовать composer и подключить оригинальное расширение, можно еще больше упростить себе жизнь. Структуру директорий можно свести до такой:
frontend\ widgets\ LanguageSwitcher.php views\ languageSwitcher.php
И я бы еще упомянул, что вызов этого виджета нужно добавить куда-то в layout, чтобы переключатель где-то отобразился.
17 декабря 2016 в 19:37
–3↑
↓
Унылые подходы, унылые фреймворки, унылые фреймворщики.
Описывать детально желания нет, ибо для адекватных людей это очевидно.
А зомбостадо никаких аргументов не услышит.
:)