Пример интернационализации сайта на Yii2 на двух языках: ru и en. В Yii2 уже встроен компонент отвечающий за интернационализацию, называется он i18n. Для того что бы можно было начать им пользоваться, достаточно добавить его в конфигурацию приложения в раздел components.

Я использую шаблон advanced поэтому расположение файлов могут отличаться.

Цель

  1. переключение сайта между двумя языками: ru и en;
  2. отображение языка в адресной строке в виде site.com/en/;
  3. автоматическое перенаправление пользователя на наиболее подходящий для него язык, если он перешел на сайт без указания языка;
  4. хранение переводов должно осуществляться в 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',
                '<controller:\w+>/<action:\w+>/'=>'<controller>/<action>',

            ],
        ],
        '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

<?php
namespace frontend\widgets\MultiLang;

use yii\helpers\Html;

class MultiLang extends \yii\bootstrap\Widget
{
    public $cssClass;
    public function init(){}

    public function run() {

        return $this->render('view', [
            'cssClass' => $this->cssClass,
        ]);

    }
}

Содержание представление frontend\widgets\MultiLang\views\view.php

<?php
namespace frontend\widgets\MultiLang;
use yii\helpers\Html;
use Yii;
?>

<div class="btn-group <?= $cssClass; ?>">
    <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
        <span class="uppercase"><?= Yii::$app->language; ?></span>
        <span class="caret"></span>
    </a>
    <ul class="dropdown-menu">
        <li class="item-lang">
            <?= Html::a('Go to English', array_merge(
                \Yii::$app->request->get(),
                [\Yii::$app->controller->route, 'language' => 'en']
            )); ?>
        </li>
        <li class="item-lang">
            <?= Html::a('Перейти на русский', array_merge(
                \Yii::$app->request->get(),
                [\Yii::$app->controller->route, 'language' => 'ru']
            )); ?>
        </li>
    </ul>
</div>

Заключение

В целом реализация интернационализации в Yii2 не представляет ничего сложного, получился простой виджет, с тремя файлами.

UrlManager.php взят отсюда. MultiLang.php просто рендерит представление. View.php само представление.
Поделиться с друзьями
-->

Комментарии (8)


  1. SilverFire
    17.12.2016 17:36
    +4

    Спасибо за ваши старания, позвольте высказать свою критику по поводу архитектурных решений.


    '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 из представления, а перенести это в виджет.


    1. SilverFire
      17.12.2016 17:48
      +2

      Кроме того, название MultiLang мне не кажется само-описывающим. Пока не откроешь код, сложно однозначно сказать, что делает этот класс. Что-то про мультиязычность, но что именно?
      Я бы его назвал LanguageSwitcher. Согласитесь, сразу понятно, что это переключатель языков, не так ли?


      Если всё таки использовать composer и подключить оригинальное расширение, можно еще больше упростить себе жизнь. Структуру директорий можно свести до такой:


      frontend    widgets        LanguageSwitcher.php
              views            languageSwitcher.php

      И я бы еще упомянул, что вызов этого виджета нужно добавить куда-то в layout, чтобы переключатель где-то отобразился.


    1. xelaxela
      18.12.2016 18:43
      +1

      Спасибо за комментарий, изучаю Yii2 чуть меньше месяца, пока еще не понимаю разнице между расширениями и виджетами, будет повод почитать об этом. Просто возникла задача, я поискал решение, нашел с использованием базы данных попробовал, вроде получилось, потом нашел это решение, попробовал через композер, то же получилось )), потом решил сделать виджет )) не судите строго, а лучше научите как правильно… Спасибо!


  1. http2
    17.12.2016 19:37
    -14

    Унылые подходы, унылые фреймворки, унылые фреймворщики.
    Описывать детально желания нет, ибо для адекватных людей это очевидно.
    А зомбостадо никаких аргументов не услышит.
    :)


  1. TOLK
    18.12.2016 11:46

    Посмотрел ваши комменты, чтобы изучить что Вам нравится — неунылое. Кажется, что пишутся они специально, чтобы обратить внимание на поле «откуда».
    Зомбоящик рулит?
    PS. если что, я вообще в «другой стороне света» живу ), просто взгляд со стороны…


    1. http2
      18.12.2016 14:17
      -1

      Вы видимо чуток промазали :)

      Ну и что Вы изучили, что мне нравится неунылое? :)

      Писать комменты, чтобы залезли мне в профиль? :)
      О да, верх логики. :)

      Как-то тупо обвинять человека, который выступает против унылых трендов в зомбоящичестве. В зомбоящике как раз унылые тренды и формируют.

      Вдруг что, майданутость терпеть не могу. Но это оффтоп, прошу о майданутости дальше не продолжать.


  1. KlimovDm
    18.12.2016 13:53
    +1

    Слова

    без использования базы данных
    в заголовке статьи сразу удивили. Т.е. сначала показалось, что вы считаете использование БД для интернализации что-то нормальным и обычным. Потом странная цель:
    хранение переводов должно осуществляться в PHP файлах в виде массивов;
    Вы цель со средством не перепутали?

    Чем gettext-то не угодил?
    Вообще-то это элементарная задача, а в статье сплошной оверкодинг, притянутый за уши к Yii2.


  1. PaulZi
    19.12.2016 10:43
    +1

    Чем данное (codemix/yii2-localeurls) решение не угодило?