Роберт

Backend-разработчик
Пишу о программировании, музыке, книгах и жизни

Блог

Yii::t('app', 'message') -> trans('app.category.sub_category.message')

Переопределяем метод PhpMessageSource::loadMessages()


namespace app\components;

use Yii;

class PhpMessageSource extends \yii\i18n\PhpMessageSource
{
    protected function loadMessages($category, $language)
    {
        $newCategory = $category;
        $keys = [];
        if (false !== strpos($category, '.')) {
            $keys = explode('.', $category);
            $newCategory = array_shift($keys);
        }
        $messageFile = $this->getMessageFilePath($newCategory, $language);
        $messages = $this->loadMessagesFromFile($messageFile);

        if (false !== strpos($category, '.')) {
            $messages = $this->searchKey($messages, $keys);
        }

        $fallbackLanguage = substr($language, 0, 2);
        $fallbackSourceLanguage = substr($this->sourceLanguage, 0, 2);

        if ($language !== $fallbackLanguage) {
            $messages = $this->loadFallbackMessages($newCategory, $fallbackLanguage, $messages, $messageFile);
        } elseif ($language === $fallbackSourceLanguage) {
            $messages = $this->loadFallbackMessages($newCategory, $this->sourceLanguage, $messages, $messageFile);
        } else {
            if ($messages === null) {
                Yii::warning("The message file for category '$newCategory' does not exist: $messageFile", __METHOD__);
            }
        }

        return (array)$messages;
    }

    private function searchKey($messages, $keys)
    {
        $keyCurrent = array_shift($keys);

        if (array_key_exists($keyCurrent, $messages) && is_array($messages[$keyCurrent])) {
            if (!$keys) {
                return $messages[$keyCurrent];
            }

            return $this->searchKey($messages[$keyCurrent], $keys);
        }
    }
}

В конфиге приложения для компонента i18n указываем наш класс:


'components' => [
    ...
    'i18n' => [
            'translations' => [
                '*' => [
                    'class' => \app\components\PhpMessageSource::class,
    ...

Добавляем глобальную функцию, которая будет оберткой для стандартного вызова метода Yii::t()


function trans(string $message)
{
    return Yii::t($message, substr(strrchr($message, '.'), 1));
}

Теперь в файлах переводов можно указывать переводы с категориями


'access_denied' => 'Доступ закрыт',
'category' => [
    'sub_category' => [
        'message' => 'Сообщение',
    ],
],

Интернационализация Yii2 а-ля Laravel

I18n а-ля Laravel
Читать

Хорошо написанный код - это также тестируемый код, слабосвязанный с другими компонентами, код следует принципу единой ответственности, нет явных зависимостей и так далее. Мы все знаем правила, но всегда есть исключение.

Это довольно распространенная ситуация для модульного тестирования компонента или контроллера, который зависит от другого основного компонента Yii. Например, диспетчер событий

class EventDispatcher extends Component
{ 
    public function dispatch($event)
    {
        $this->trigger(get_class($event), $event);
    }
}

Переписать библиотеку, чтобы удалить явные зависимости, не всегда возможно, потому что это может привести к массовому рефакторингу и фактически сломать больше вещей, чем получить выгоду.

В таком случае я действительно хочу временно назначить \Yii::$app->eventDispatcher PHPUnit Mock Class, чтобы я мог переопределить возвращаемое значение метода dispatch(), например

$eventDispatcherMock = $this->getMockClass(EventDispatcher::class, ['dispatch']);
\Yii::$app->set('eventDispatcher', $eventDispatcherMock);

После данных преобразований метод dispatch() будет возвращать null, следовательно события вызвано не будет.

мОкаем компонент Yii2

мОкаем компонент Yii2
Читать

Подпишитесь на обновления