Сервис на Yii2: Доработка шаблона приложения и i18n
В прошлый раз мы к нашему приложению на basic-шаблоне добавили функционал хранения пользователей в базе данных и добавили формы подтверждения электронного адреса и восстановления пароля. Сегодня мы сделаем последние подготовительные штрихи: доработаем интерфейс и переведём всё с английского языка.
Репозиторий проекта на GitHub
Часть 1: Установка и настройка приложения
Часть 2: Настройка IDE и модульная структура
Часть 3: Перенос пользователей в БД
На данный момент мы получили приложение стандартного вида:
Сейчас у нас имя приложения (и имя компании) вписано в шаблоны вручную. Заголовок окна главной страницы формируется в файле представления index.php
модуля main
:
<?php /* @var $this yii\web\View */ $this->title = 'My Yii Application';
А имя компании вписано в главный шаблон views/layouts/main.php
:
NavBar::begin([ 'brandLabel' => 'My Company', ... ]); ... <footer class="footer"> <div class="container"> <p class="pull-left">© My Company <?= date('Y') </p> <p class="pull-right"> Yii::powered() </p> </div> </footer>
Для удобства подставим вместо этих имён значение Yii::$app->name
:
<?php /* @var $this yii\web\View */ $this->title = Yii::$app->name;
И в views/layouts/main.php
:
NavBar::begin([ 'brandLabel' => Yii::$app->name, ... ]); ... <footer class="footer"> <div class="container"> <p class="pull-left">© <?= Yii::$app->name </p> <p class="pull-right"> date('Y') </p> </div> </footer>
Также это значение уже используется нами как имя отправителя при отправке писем в модели ContactForm
и других:
Yii::$app->mailer->compose() ->setTo($email) ->setFrom([Yii::$app->params['supportEmail'] => Yii::$app->name]) ...
Теперь по умолчанию нам будет выводиться значение My Application
из соответствующего поля объекта нашего приложения. Действительно, в базовом классе приложения фреймворка имеется поле name
с именем приложения по умолчанию:
namespace yii\base; abstract class Application extends Module { ... public $name = 'My Application'; ... }
Теперь мы спокойно можем изменить это имя в конфигурационном файле config/common.php
:
return [ 'name' => 'SeoKeys', 'basePath' => dirname(__DIR__), 'bootstrap' => ['log'], ... ];
Теперь имя приложения в логотипе, подвале и заголовке окна главной страницы будет одинаковым:
Но никто не мешает нам в качестве логотипа использовать изображение. Мы это делать не будем. Перейдём к руссификации интерфейса.
Язык интерфейса приложения
Если сейчас перейти на любую внутреннюю страницу, то можно заметить, что хлебные крошки и остальные элементы интерфейса выполнены на английском языке. Если попробовать неправильно заполнить любую форму, то сообщения об ошибках тоже выводятся на английском:
Для исправления ситуации можно сразу указать язык приложения 'languageв
config/web.php`:
$config = [ 'id' => 'app', 'language'=>'ru-RU', ... ];
Теперь все системные сообщения фреймворка и ссылка на главную страницу в хлебных крошках будут выводиться на русском:
Остались непереведёнными пункты меню, имена полей форм и фрагменты хлебных крошек. Это всё вписано в представления вручную, поэтому мы могли бы заменить их сами:
echo Nav::widget([ 'options' => ['class' => 'navbar-nav navbar-right'], 'items' => array_filter([ ['label' => 'Главная', 'url' => ['/main/default/index']], ['label' => 'Связь', 'url' => ['/main/contact/index']], Yii::$app->user->isGuest ? ['label' => 'Регистрация', 'url' => ['/user/default/signup']] : false, Yii::$app->user->isGuest ? ['label' => 'Вход', 'url' => ['/user/default/login']] : ['label' => 'Выход', 'url' => ['/user/default/logout'], 'linkOptions' => ['data-method' => 'post']], ]), ]);
Но тогда всё станет на другом языке, но будет так же жёстко вписано в код. Если же мы собираемся обеспечить свободную поддержку нескольких языков, то можно воспользоваться имеющемся во фреймворке решением по интернационализации.
Первым делом добавим папки messages/en
и messages/ru
в корень приложения и создадим в них по файлу app.php
. После этого в конфигурационном файле config/common.php
укажем компоненту Yii::$app->i18n
эти файлы переводов:
return [ ... 'language'=>'ru', ... 'components' => [ ... 'i18n' => [ 'translations' => [ 'app' => [ 'class' => 'yii\i18n\PhpMessageSource', 'forceTranslation' => true, ], ], ], ], ];
Теперь заменим надписи пунктов меню. А именно, все тексты заменим на конструкцию Yii::t('app', *)
, где в качестве ключей подставим некие идентификаторы:
echo Nav::widget([ 'options' => ['class' => 'navbar-nav navbar-right'], 'items' => array_filter([ ['label' => Yii::t('app', 'NAV_HOME'), 'url' => ['/main/default/index']], ['label' => Yii::t('app', 'NAV_CONTACT'), 'url' => ['/main/contact/index']], Yii::$app->user->isGuest ? ['label' => Yii::t('app', 'NAV_SIGNUP'), 'url' => ['/user/default/signup']] : false, Yii::$app->user->isGuest ? ['label' => Yii::t('app', 'NAV_LOGIN'), 'url' => ['/user/default/login']] : ['label' => Yii::t('app', 'NAV_LOGOUT'), 'url' => ['/user/default/logout'], 'linkOptions' => ['data-method' => 'post']], ]), ]);
И пройдёмся по всем имеющимся у нас представлениям и поменяем заголовки, тексты, надписи и кнопки:
$this->title = Yii::t('app', 'TITLE_RESET_PASSWORD'); $this->params['breadcrumbs'][] = $this->title; <div class="user-default-password-reset-request"> <h1> Html::encode($this->title) </h1> <p> Yii::t('app', 'PLEASE_FILL_FOR_RESET_REQUEST') </p> <div class="row"> <div class="col-lg-5"> $form = ActiveForm::begin(['id' => 'password-reset-request-form']); $form->field($model, 'email') <div class="form-group"> Html::submitButton(Yii::t('app', 'BUTTON_SEND'), ['class' => 'btn btn-primary']) </div> ActiveForm::end(); </div> </div> </div>
Обратите внимание, что по умолчанию если исходный язык
sourceLanguage
совпадает с текущимtargetLanguage
, то перевод не производится и строка возвращается как есть. Но мы вместо строк используем их идентификаторы, и нам нужно принудительно «переводить» их даже с английского на английский. Именно для принудительной обработки переводов в конфигурации нашего источника у транслятора мы установили параметрforceTranslation
вtrue
.
Или на странице обратной связи:
$this->title = Yii::t('app', 'TITLE_CONTACT'); $this->params['breadcrumbs'][] = $this->title; <div class="main-contact-index"> <h1> Html::encode($this->title) </h1> if (Yii::$app->session->hasFlash('contactFormSubmitted')): <div class="alert alert-success"> Yii::t('app', 'CONTACT_THANKS'); </div> else: <div class="row"> <div class="col-lg-5"> $form = ActiveForm::begin(['id' => 'contact-form']); $form->field($model, 'name') $form->field($model, 'email') $form->field($model, 'subject') $form->field($model, 'body')->textArea(['rows' => 6]) $form->field($model, 'verifyCode')->widget(Captcha::className(), [ 'captchaAction' => '/main/contact/captcha', 'template' => '<div class="row"><div class="col-lg-3">{image}</div><div class="col-lg-6">{input}</div></div>', ]) <div class="form-group"> Html::submitButton(Yii::t('app', 'BUTTON_SEND'), ['class' => 'btn btn-primary', 'name' => 'contact-button']) </div> ActiveForm::end(); </div> </div> endif; </div>
Аналогично доработаем все остальные представления и шаблоны писем в папке mail
:
<?php /* @var $this yii\web\View */ /* @var $user app\modules\user\models\User */ $confirmLink = Yii::$app->urlManager->createAbsoluteUrl(['user/default/email-confirm', 'token' => $user->email_confirm_token]); Yii::t('app', 'HELLO {username}', ['username' => $user->username]); Yii::t('app', 'FOLLOW_TO_CONFIRM_EMAIL') $confirmLink Yii::t('app', 'IGNORE_IF_DO_NOT_REGISTER')
Все нуждающиеся в переводе тексты мы будем выводить не напрямую, а через метод Yii::t()
, принимающий категорию и идентификатор сообщения для перевода. Этот метод попробует найти отображение этой строки на нужном нам языке.
Этот компонент не настолько умный, чтобы самостоятельно переводить тексты. Никакой магии здесь нет. Для его работы нам нужно самим подготовить все переводы и поместить в наши файлы.
В messages/en/app.php
переместим из наших приедставлений и моделей все исходные надписи на английском языке:
return [ 'NAV_HOME' => 'Home', 'NAV_CONTACT' => 'Contact', 'NAV_SIGNUP' => 'Signup', 'NAV_LOGIN' => 'Login', 'NAV_LOGOUT' => 'Logout', 'BUTTON_SEND' => 'Send', 'BUTTON_SAVE' => 'Save', 'BUTTON_UPDATE' => 'Update', 'BUTTON_DELETE' => 'Delete', ... 'HELLO {username}' => 'Hello, {username}!', 'FOLLOW_TO_RESET_PASSWORD' => 'Follow the link below to reset your password:', 'FOLLOW_TO_CONFIRM_EMAIL' => 'Follow the link below to confirm your email:', 'IGNORE_IF_DO_NOT_REGISTER' => 'If you do not register on our site just remove this mail.' ];
Скопируем всё это в файл messages/ru/app.php
и заменим сообщения на нужные для языка ru
:
return [ 'NAV_HOME' => 'Главная', 'NAV_CONTACT' => 'Связь', 'NAV_SIGNUP' => 'Регистрация', 'NAV_LOGIN' => 'Вход', 'NAV_PROFILE' => 'Профиль', 'NAV_LOGOUT' => 'Выход', 'BUTTON_SEND' => 'Отправить', 'BUTTON_SAVE' => 'Сохранить', 'BUTTON_UPDATE' => 'Редактировать', 'BUTTON_DELETE' => 'Удалить', ... 'HELLO {username}' => 'Здравствуйте, {username}!', 'FOLLOW_TO_RESET_PASSWORD' => 'Для смены пароля пройдите по ссылке:', 'FOLLOW_TO_CONFIRM_EMAIL' => 'Для подтверждения адреса пройдите по ссылке:', 'IGNORE_IF_DO_NOT_REGISTER' => 'Если Вы не регистрировались на нашем сайте, то просто удалите это письмо.' ];
В итоге изменились тексты, элементы хлебных крошек и кнопки:
Осталось только изменить названия полей форм. На странице входа они до сих пор остались подписанными как Username
, Password
, Remember Me
.
Имена полей любой модели (и ActiveRecord
в частности) формируются методом yii\base\Model::getAttributeLabel
:
class Model extends Component implements IteratorAggregate, ArrayAccess, Arrayable { ... public function getAttributeLabel($attribute) { $labels = $this->attributeLabels(); return isset($labels[$attribute]) ? $labels[$attribute] : $this->generateAttributeLabel($attribute); } public function generateAttributeLabel($name) { return Inflector::camel2words($name, true); } }
Он пытается найти имя в методе attributeLabels
текущей модели, а если не находит, то генерирует надпись автоматически. В нашем классе LoginForm
, например, этого метода нет (нами он непереопределён), поэтому к нашим полям:
class LoginForm extends Model { public $username; public $password; public $rememberMe = true; ... }
с помощью Inflector::camel2words
автоматически генерируются имена Username
, Password
и Remember Me
. Чтобы заменить имена полей на свои нужно добавить к моделям метод attributeLabels
по аналогии с тем, который мы генерировали в модели User
:
class LoginForm extends Model { public $username; public $password; public $rememberMe = true; ... public function attributeLabels() { return [ 'username' => Yii::t('app', 'USER_USERNAME'), 'password' => Yii::t('app', 'USER_PASSWORD'), 'rememberMe' => Yii::t('app', 'USER_REMEMBER_ME'), ]; } }
Аналогично обходим остальные модели, добавляем имена полей и дописываем их переводы в файлы messages/en/app.php
и messages/ru/app.php
.
Теперь все надписи в формах генерируются верно:
Помимо этого, у нас есть вбитые вручную сообщения для ошибок валидации. Переведём и эти сообщения в моделях User
, SignupForm`:
public function rules() { return [ ... ['username', 'unique', 'targetClass' => User::className(), 'message' => Yii::t('app', 'ERROR_USERNAME_EXISTS')], ... ['email', 'unique', 'targetClass' => User::className(), 'message' => Yii::t('app', 'ERROR_EMAIL_EXISTS')], ... ]; }
и в прочих моделях:
class LoginForm extends Model { ... public function validatePassword() { if (!$this->hasErrors()) { $user = $this->getUser(); if (!$user || !$user->validatePassword($this->password)) { $this->addError('password', Yii::t('app', 'ERROR_WRONG_USERNAME_OR_PASSWORD')); } elseif ($user && $user->status == User::STATUS_BLOCKED) { $this->addError('username', Yii::t('app', 'ERROR_PROFILE_BLOCKED')); } elseif ($user && $user->status == User::STATUS_WAIT) { $this->addError('username', Yii::t('app', 'ERROR_PROFILE_NOT_CONFIRMED')); } } } ... }
Теперь если все переводы вбиты верно, то интерфейс полностью стал отображаться на другом языке.
Удаление лишнего
При разработке интерфейсов важно сделать так, чтобы ничего не мешало. Окинув взглядом приведённые выше скриншоты попробуем оценить, мешает ли нам что-то из элементов, занимает ли много лишнего места?
Да, есть такой большой элемент. Это заголовок <h1></h1>
:
$this->title = Yii::t('app', 'TITLE_CONTACT'); $this->params['breadcrumbs'][] = $this->title; <div class="main-contact-index"> <h1> Html::encode($this->title) </h1> ... </div>
Во-первых, он выводится крупным шрифтом, а во-вторых, он повторяет «хвост» хлебных крошек, то есть никакой дополнительной информации не несёт. Значит его можно спокойно удалить. Но мы вместо удаления из всех представлений можем его просто спрятать. Для этого в файл стилей web/css/site.css
добавим пару правил:
h1 { display: none; } .jumbotron h1 { display: block; }
Теперь без лишнего заголовка интерфейс стал проще и контент поднялся выше:
И пользоваться сервисом на маленьких мониторах стало удобнее.
Поддержка IE8 (опционально)
Браузер Internet Explorer поддерживает HTML5-теги и медиа-запросы в CSS для адаптивной вёрстки только со своей девятой версии. Но уже давно известен вариант эмуляции этого в старых версиях с помощью сторонних скриптов html5shiv
и respond
. Обычно разработчики это делают подключением этих скриптов в секцию <head></head>
страницы:
<!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]-->
Мы можем это сделать также, вписав в шаблон этот код. Но если мы хотим использовать возможности Yii2, для этого можно создать отдельный бандл с указанием ему условия [if lt IE 9]
:
namespace app\assets; use yii\web\AssetBundle; use yii\web\View; class IESupportAsset extends AssetBundle { public $js = [ 'https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js', 'https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js' ]; public $jsOptions = [ 'condition'=>'lt IE 9', 'position' => View::POS_HEAD, ]; }
И вписать его в список зависимостей главного бандла приложения AppAsset
:
namespace app\assets; use yii\web\AssetBundle; class AppAsset extends AssetBundle { public $basePath = '@webroot'; public $baseUrl = '@web'; public $css = [ 'css/site.css', ]; public $js = [ ]; public $depends = [ 'app\assets\IESupportAsset', 'yii\web\YiiAsset', 'yii\bootstrap\BootstrapAsset', ]; }
Но в последнее время с ростом скорости интернета наметилась тенденция отхода от загрузки ресурсов со сторонних хранилищ (CDN), чтобы не тратить время на обращение к DNS-серверам для каждого домена. Да и использование скриптов из своих папок позволяет нормально работать с локальной копией приложения на компьютере без доступа к сети.
Плюс к тому, почти все популярные ресурсы (вроде шрифтов, стилей и JS-скриптов) давно доступны в пакетном менеджере Bower, поэтому мы можем спокойно загружать их и обновлять через Composer с плагином для работы с Bower (это тот самый загадочный fxp/composer-asset-plugin
, который нужно подключать глобально при установке Yii2-app-*).
Так что установим эти скрипты html5shiv
и respond
к себе:
composer require bower-asset/html5shiv:* bower-asset/respond:*
и создадим для них бандлы для подключения к шаблону Yii2. Так как скрипты установились в две разные папки внутрь vendor/bower-asset
, то нам нужно будет создать отдельный бандл для каждого скрипта.
Первый:
namespace app\assets; use yii\web\AssetBundle; use yii\web\View; class Html5ShivAsset extends AssetBundle { public $sourcePath = '@bower/html5shiv/dist'; public $js = [ 'html5shiv.min.js', ]; public $jsOptions = [ 'condition'=>'lt IE 9', 'position' => View::POS_HEAD, ]; }
Второй:
namespace app\assets; use yii\web\AssetBundle; use yii\web\View; class RespondAsset extends AssetBundle { public $sourcePath = '@bower/respond/dest'; public $js = [ 'respond.min.js', ]; public $jsOptions = [ 'condition'=>'lt IE 9', 'position' => View::POS_HEAD, ]; }
Не знаю, почему у пакета Respond поддиректория называется dest
вместо dist
, но напишем как есть.
Теперь, чтобы подключить их глобально для всех страниц шаблона, в AppAsset
объявим от них зависимости:
namespace app\assets; use yii\web\AssetBundle; class AppAsset extends AssetBundle { public $basePath = '@webroot'; public $baseUrl = '@web'; public $css = [ 'css/site.css', ]; public $js = [ ]; public $depends = [ 'app\assets\Html5ShivAsset', 'app\assets\RespondAsset', 'yii\web\YiiAsset', 'yii\bootstrap\BootstrapAsset', ]; }
И, обновив вкладку в браузере, в исходном коде страницы увидим автоматически подключенные скрипты:
<!--[if lt IE 9]> <script src="/assets/db84ef52/html5shiv.min.js"></script> <![endif]--> <!--[if lt IE 9]> <script src="/assets/ff150184/respond.min.js"></script> <![endif]-->
Теперь эти скрипты будут у нас всегда и мы сможем их автоматически обновлять через Composer.
Таким же образом можно подключать любые свои или сторонние JS и CSS пакеты. Так что при необходимости прикрутить любой набор шрифтов или jQuery-плагин сначала поищите его здесь и, если найдёте, установите командой
composer require bower-asset/<имя>
, потом создайте для него бандл и подключайте по требованию в нужном месте или глобально.
Чтобы папки в web/assets
автоматически обновлялись (чтобы не вычищать их вручную после каждого обновления) можно в config/web-local.php
включить использование символических ссылок:
'components' => [ ... 'assetManager' => [ 'linkAssets' => true, ], ... ]
На данный момент основа полностью готова. Интерфейс успешно доработан, переведён и добавлена дополнительная кроссбраузерность.
Теперь начнём делать проект. В следующей части сделаем страницу профиля пользователя:
Просмотр и редактирование профиля
Подписывайтесь на рассылку (форма в сайдбаре), чтобы не пропустить продолжение и получать полезные фишки, и оставляйте свои предложения или замечания в комментариях. Спасибо!
Дмитрий, спасибо за качественные интересные уроки. Не думали делать практикум по Yii2 ?
Может быть. Если надумаю, то сообщу. Подпишитесь на обновления, если ещё не подписаны. Спасибо! :)
Спасибо за статью, у вас очень хорошо получается писать. В yii1 был простой и доступный для всех механизм минимификации js и сss, а также объединения этого всего в один файл для заливки на сервер, но во 2-й версии его к сожалению нет. Не могли бы вы посвятить одну из статей именно этому вопросу или хотя бы дать ссылку на адекватные материалы по данной проблеме.
Вот отличное расширение для вашей задачи: https://github.com/rmrevin/yii2-minify-view
Сам пользуюсь, доволен.
Всегда делаю как в этом мануале - http://scriptidy.com/obedinenie-css-i-js-fajlov-i-ix-minifikaciya-v-yii2.html
То же самое, что в официальном, практически.
https://github.com/kriswallsmith/assetic
Дмитрий, благадарствую за проделанную работу))
Следующий урок будет по созданию профиля пользователя и привязке к юзеру?
Спасибо, ждем rbac !!!
Так про RBAC отлично расписано в официальном HOW-TO, надо только взять и попробовать :)
Ну да скорей всего нужно попробовать, но все равно ждем rbac )
Добавил пункт про замену версии JQuery.
Дмитрий создайте репозиторий этого проекта в гитхабе
Создал.
UPD: Убрал жёстко вписанные переводы и добавил мультиязычность с Yii::t().
This username exists / This username is present in our database / Dear sir, the username you kindly entered appears to be already present in our records
А вообще по хорошему нужно не сами имена по-английски писать, а т.н. токены (button.save - хорошо, forms.registration.button.save - еще лучше, forms.registration.submitButton - практически идеально). Любой Home, Add может оказаться используемым в двух разных местах даже в пределах одной секции, а при замене слова придется менять его не только в оригинальном месте, но и во всех переводах (чего не сделаешь через ctrl-r, потому что можно задеть соседние переводы).
Спасибо! Поменял на идентификаторы.
По поводу i18n стоит добавить что справочники с переводами можно создавать автоматически. Для этого используется консольная команда:
Она парсит исходный код проекта, и извлекает найденные переводы в справочники. Если появились новые - добавляет, старые и неиспользуемые в коде - помечает. Переводы разносятся в файлы по категориям.
@app/config/message.php - настройки парсера. Может выглядеть следующим образом:
Здравствуйте, спасибо за ваш труд. А подскажите, как все это дело запилить в модальных окнах?
Вот те на. Уii 2 не рботает в ие ниже 9. пичаль, пичаль. Сильно функционал от даунгрейда страдает? И еще: добавьте как можно поправить шаблон чтобы при создании нового круда текст был русским.
Дмитрий, спасибо за интересную статью!
На сайте фреймворка в документации по Yii2 в разделе Internationalization говорится - "For consistency, all locale IDs used in Yii applications should be canonicalized to the format of ll-CC ..." и в примерах для указания русского языка в качестве "target language" используется соответственно "ru-RU". В статье вы используете краткий формат 'ru' ('language'=>'ru'). Поясните - почему был выбран такой формат и в чем его преимущества.
Для ru помимо ru-RU имеются и сублокали ru-BY, ru-KG, ru-KZ, ru-MD, ru-UA. Интернационализация в Yii2 методе PhpMessageSource::loadMessages устроена так, что фреймворк ищет переводы и для конкретной локали вроде ru-UA, и для общей ru и склеивает их вместе. Так что вместо глобального ru можете указать конкретный язык ru-RU. При этом переводы из папки ru продолжат работать.
Добавил примечание про forceTranslation.
Здравствуйте.
Скажите, а есть где-нибудь что-нибудь попроще? Т.е. написано у вас хорошо, но много сленга типа "бандлы". Понятно, что это все через некоторое время любой будет знать, но пока читать трудновато.
В принципе, я бы подрядился перевести бы это на литературный русский, если на то будет интерес. Плюс чуток опечаток у вас - если поправлю, без обид?
Еще два момента:
1. Сюда бы очень вписалось бы еще добавление логотипа.
2. Если уж есть переключение на русский - то можно было бы написать, как подобные переключения делать налету. Что-то типа: "вот иконка флага английского, вот русского - и вот интерфейсы переключаются сразу".
Попроще не искал, но есть ещё и интерактивное руководство.
В Yii2 ресурсы оформляются через AssetBundle, вот и называю их пока бандлами. Если переведёте, то будет хорошо.
По моментам:
1. Просто надпись меняем на логотип:
2. Можно сделать хранение текущего языка в сессии и переключать по GET-параметру lang. А ссылки переключения выводить в цикле с адресами Url::current(['lang' => $lang]).
При работе с композером появляются следующие ошибки:
- большое количество Deprecation Notice: Composer\Package\Version\Versionparser::parseLinks is deprecated. Use....
- дальше идет стадия обновления зависимостей, но все завершается следующей ошибкой
[UnexpectedValueException]
Could not parse version constraint <=2.*:Invalid version string "2.*"
composer self-update делал, не помогает
Проблему починили. Обновите плагин:
modules/user/models/PasswordResetForm.php на GitHub
остался без перевода
Спасибо огромное за статью. Очень доходчиво объяснил, как работать с мультиязычностью. Облазил кучу сайтов, но так и ничего не понял. А у тебя всё доходчиво описано.
а как сделать возможность юзеру переключать язык?
Дмитрий, хотелось бы услышать ваше мнение по двум вопросам:
1. Какие вы видите преимущества у хранения сообщений в PHP-файлах против использования Gettext?
2. Не считаете ли вы, что использование идентификаторов вместо строк немного накладно для разработчика (в разрезе трудозатрат)? Да и то, что весь перевод хранится в одном файле не делает проект суше (особенно, при его росте). Так понимаю, идентификаторы используются для того, чтобы избежать перекрывания одинаковых английских слов при различном переводе. Может быть целесообразнее использовать для каждой предметной области свой файл, а в качестве идентификаторов использовать сообщения?
1. В Yii2 нет нативной работы с Gettext, так что пока никакой разницы.
2. Да, про перекрытие верно. Например, "Update" - это и текст кнопки, и заголовок окна и ещё много чего. Много путаницы. А для роста можно не только по нескольким файлам, но и переводы разных модулей по папкам самих модулей разносить.
Дмитрий, подскажите, а как сделать чтобы язык переключался в зависимости от ЧПУ?
Ну например:
site.ru/ru/index - Сайт на русском
site.ru/en/index - Сайт на английском
Заранее спасибо!
Добрый день, Дмитрий!
В моем composer.json в секции require я не нашел:
И, кстати, в вашем гитхаб-проекте данная строчка добавляется только на коммите b424414.
При этом у меня в директории ./vendor/bower/ есть пакет jquery и на страницах в секции head jquery.js скрипт тоже загружается (в футере). В документации я не нашел описания момента загрузки jquery по-умолчанию (возможно, плохо искал), но я полагаю он загружается как зависимость какого другого скрипта (например, bootstrap js). Могли бы вы чуть прояснить данный момент?
Этой строкой он вписан в composer.json самого фреймворка. В моём коммите я именно форсирую подключение версии 1.* для поддержки IE8.
>>"... Но тогда всё станет на другом языке, но будет так же жёстко вписано в код. ..."
Возможно, первое "но" там случайно?
И спасибо за статьи, очень хороший блог, подписался.
Дмитрий вопрос с сообщением на advanced где должна быть папка messages. Своя во frontend своя в backend?
Если что-то общее, то можно в common, если разное, то отдельно. Как Вам удобнее.
Добрый день, Дмитрий!
Возник такой вопрос, по поводу ресурсов. Может у вас будет такая тема, про использование ресурсов и их подключение!
А вопрос такой, посоветуйте как разделять ресурсы backend и frontend, как их подключать и где лучше хранить?
Т.к. нигде не могу найти "cookbook", могу только лишь предположить, на примере Symfony, хранить ресурсы в модулях в папке Resources либо же Assets, а подключать если что-то глобальное в layout, а локальное во вьюхах. Т.к. не могу понять, как разделять ресурсы с помощью AppAsset.
Для виджетов в модуле делаете папку assets и рядом делаете MyWidgetAsset вроде как здесь. А для глобальных layouts делаем два AppAsset для frontend и backend.
Спасибо! Радует ваша уверенность, это помогает. Легко пишете, легко читается.
Не могу понять, есть ли необходимость в поддержке старых браузеров?
С одной стороны очевидно, что затраты ресурсов на поддержку минимальны, с другой стороны ощущается некий балласт прошлого ))
Здравствуйте, Дмитрий!
Проблема с кодировкой файлов. У всех файлов фреймворка кодировка windows-1251.
и PhpStorm создает новые файлы в этой кодировке. Проблема с отображением кириллических символов. Проблема известная, и есть способы решения, в которых предполагается перенастройка на utf-8. Однако как бы я не перенастраивал кодировку, кириллические символы не отображаются, если сам файл остается в 1251.
Скажите, как Вы решаете эту проблему?
Заранее спасибо!
> У всех файлов фреймворка кодировка windows-1251.
У меня абсолютно всё в utf-8. И файлы, и PhpStorm. Проблемы нет.
Вопрос по поводу файлов messages/en, messages/ru: они хранятся в корне проекта, и в них прописаны данные для всех модулей. А можно ли сделать так, чтобы переводы, относящиеся к конкретному модулю хранились в самом модуле. И для каждого модуля иметь свои файлы переводов.
Я подумал что такое решение было бы лучше для обеспечения модульности. Или я ошибаюсь, и все переводы лучше хранить в одном файле независимо от модулей?
В одной из сделующих частей это есть.
Я так и не разобрался, как менять язык "на лету". То есть как сделать чтобы на основной странице (или в профиле пользователя - не суть важно) было меню с выбором языка и можно было быстро поменять язык во всем приложении?
Просто присвоить где-нибудь:
А так хоть в профиле пользователя Yii::$app->identity->language храните, хоть в cookies.
вопрос возник, когда пользователь авторизован - то в отображение меню хотелось бы добавить отображение не Выход, а Выход (username). Что-то не могу понять как это сделать?
Как в стандартном приложении.
Спасибо
Подскажите, есть ли какая-то универсальная админка для редактирования файлов переводов?
либо некий генератор такой админки, по аналогии с gii
Переводы можно хранить и в бд через DbMessageSource. И уже для таблицы переводов сгенерировать ActiveRecord и CRUD.