Actually it is necessary to implement multilingualism both for the interface and for the database. So, when a user visits the site, it is necessary to determine the language of his browser and, depending on this, show the necessary translations.

I implemented this whole thing as follows:

I created a component and added it to the general application configuration:

'dbTranslator' => [ 'class' => 'common\components\DbTranslator', 'table' => 'lang' ], 

Further, in the settings of the application I need, I called the component and redefined the language:

 'on beforeRequest' => function ($event) { Yii::$app->dbTranslator->init(); Yii::$app->language = Yii::$app->dbTranslator->getLanguage('code'); }, 

The whole component looks like this:

 <?php namespace common\components; use yii\base\InvalidConfigException; use yii\base\InvalidParamException; use yii\db\Query; use yii\helpers\ArrayHelper; use Yii; class DbTranslator { /** * Таблица где хранятся все доступные языки * @param string */ public $table = 'lang'; /** * Все поддерживаемые языки * @param array */ private $_supportLanguages; /** * Язык по умолчанию * @param array */ private $_defaultLanguage; /** * Инициализация компонента */ public function init() { $languages = (new Query) ->from($this->table) ->orderBy(['default' => SORT_DESC]) ->all(); if (!$languages) { throw new InvalidParamException('Languages NOT FOUND'); } if (!isset($languages[0]['default']) || $languages[0]['default'] != 1) { throw new InvalidParamException('Default language NOT FOUND'); } $this->_supportLanguages = ArrayHelper::index($languages, 'code'); $this->_defaultLanguage = $languages[0]; } /** * Определение языка на котором будет показан сайт * @return array|string */ public function getLanguage($item = false) { if (Yii::$app->session->get('user.language')) { $userLanguage = Yii::$app->session->get('user.language')['code']; } else if (isset(Yii::$app->request->cookies['language'])) { $userLanguage = Yii::$app->request->cookies->getValue('language'); } else { $userLanguage = $this->getUserLanguage(); } if (isset($this->_supportLanguages[$userLanguage])) { $language = $this->_supportLanguages[$userLanguage]; } else { $language = $this->_defaultLanguage; } if (!$item || !isset($language[$item])) { return $language; } return $language[$item]; } /** * Определение языка браузера пользователя * @return string */ public function getUserLanguage() { return substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2); } /** * Язык системы по умолчанию * @return array */ public function getDefaultLanguage($item = false) { if (!$item || !isset($this->_defaultLanguage[$item])) { return $this->_defaultLanguage; } return $this->_defaultLanguage[$item]; } /** * Все поддерживаемые языки * @return array */ public function getLanguages() { return $this->_supportLanguages; } /** * Устанавливает выбранный язык */ public function setLanguage($lang) { if (isset($this->_supportLanguages[$lang])) { $language = $this->_supportLanguages[$lang]; } else { $language = $this->_defaultLanguage; } if (isset(Yii::$app->request->cookies['language'])) { Yii::$app->response->cookies->remove('language'); } Yii::$app->response->cookies->add(new \yii\web\Cookie([ 'name' => 'language', 'value' => $language['code'], 'expire' => time() + 86400 * 365, // Запись на 365 дней ])); Yii::$app->session->set('user.language', $language); } } 

Actually everything works, no complaints. But there was some kind of back feeling that I could have done something wrong.

Please share tips and comments on this approach.

Update

And I just stay here: https://github.com/yiisoft/yii2/blob/master/docs/guide-ru/tutorial-i18n.md

You probably did not understand me. The whole essence of the component is to determine the browser language, check whether it is supported by the site, if not, issue the default one and actually overwrite Yii::$app->language .

    2 answers 2

    aa then this:

     ['default' => SORT_DESC] 

    If default is the name of the field, then get ready to catch the database failures, since this is a reserved word and sooner or later it will be sent to the query without escaping

     substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2); 

    And what if this key is not there? Is it necessary to get it through yii \ Request?

     throw new InvalidParamException('Default language NOT FOUND'); 

    The method has no parameters, why throw a message about the wrong parameter? Why write caps? Exception text should allow the end user to quickly unleash the problem in the opposite direction.

     public function getDefaultLanguage($item = false) { if (!$item || !isset($this->defaultLanguage[$item])) { return $this->defaultLanguage; } return $this->defaultLanguage[$item]; } 

    We want to get data on $ item, but if it is not there, we get the entire $ defaultLanguage. This is extremely unintuitive and will lead to difficult unwinding errors on the first missed item.

    In general, the class has a huge connectivity, it defines both requests and pulls data from the database, and translates the messages themselves. But if so, then

     $language = Yii::$app->session->get('user.language'); 

    if this parameter is not found in the session, it should be put down; anyway, the class is already wildly connected.

     /** * Все поддерживаемые языки * @param array */ private $supportLanguages; 

    @param is the argument description, @type needed @type . Almost all @return array should be replaced with @return string[] , methods should use @param

    Update

    @NEPSTER 4234223 ,> this is more for the developer

    I had it in the form under the end user. Eksepshen and should say that the base is not deployed, and not that something is not found, in the current version you need to climb into the code to figure it out. This is the common pain of all developers, because at this moment you need to exit the local scopa and look at the application.

    Regarding connectivity, all that the class does is determine the client’s language and compare it with the list of supported languages.

    This does not affect the above, unfortunately. DI is hardly needed there, and still it is not in Yii.

    • Many thanks, I will consider councils, I will correct. Concerning actions, this is more likely for a developer if the database does not have a list of languages. The default is always used 1 time and only in this component, + with the active record all such things are shielded. Regarding connectivity, all that the class does is determine the client’s language and compare it with the list of supported languages. Actually there is no sense to divide it into a bunch of small classes, the implementation of the DI series and so on. - Nepster
    • Thank you very much for all the moments. DI in Yii2 is. Here you are: github.com/yiisoft/yii2/blob/master/docs/guide-ru/… - Nepster
    • @NEPSTER 4234223, go nuts. Right now my brain really went. If they have a normal container, then what are they still pulling the app? - etki

    As for the definition of the language that best suits the user, you can use this: https://github.com/codemix/yii2-localeurls

    In addition, this component substitutes the language in the URL, which is good for the CEO.

    In order to store translations in the database, it is enough to use the built-in yii \ i18n \ DbMessageSource

    Details on how to make multilingual can be found here: http://atoumus.imtqy.com/yii2-i18n.html (although the messages here are stored in PHP files and not in the database).