Продвинутое

Локализация

Winter переводит строки по ключам из PHP-словарей, автоматически выбирая язык по заголовку Accept-Language. Под Swoole выбор изолирован по корутине. Те же ключи используются в сообщениях валидации.

Перевод Locale::t()Словари lang/<код>.phpВыбор Accept-Language

Что такое локализация и зачем

Локализация — выдача текстов на языке пользователя.

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

Решение. Держите тексты в словарях по языкам и обращайтесь к ним по ключу — Winter сам подберёт язык по запросу и подставит перевод. Об этом и раздел.

Настройка

Задайте папку словарей и язык по умолчанию в bootstrap.php:

bootstrap.php
use Flytachi\Winter\K2\Localization\Locale;

Locale::setBasePath(__DIR__ . '/lang');
Locale::setDefault('en');

Словарь — PHP-файл, возвращающий вложенный массив; ключи адресуются точечной нотацией:

lang/ru.php
return [
  'auth'  => ['welcome' => 'Добро пожаловать, %s!'],
  'order' => ['created' => 'Заказ :id создан'],
];

Перевод

php
use Flytachi\Winter\K2\Localization\Locale;

Locale::t('auth.welcome', ['Alice']);        // → Добро пожаловать, Alice!
Locale::t('order.created', ['id' => 42]);     // → Заказ 42 создан
trans('auth.unauthorized');                   // глобальный хелпер
Locale::set('ru');                            // ручной выбор языка в запросе

Locale::t() — псевдоним Locale::translate(). Глобальная функция trans() — короткий доступ из любого места.

Плейсхолдеры

Тип массива Подстановка
Список — ['Alice'] sprintf: %s, %d, позиционные %2$s
Ассоциативный — ['id' => 42] Именованные: :id, :name

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

Выбор языка

Router::handle() вызывает Locale::initFromRequest(): читает Accept-Language, смотрит доступные словари в папке и выбирает лучший (по q, с откатом ru-RUru, иначе язык по умолчанию). Приложение может переопределить язык через Locale::set().

Никогда не бросает

На отсутствующий ключ или словарь Locale::t() возвращает сам ключ — исключения не будет. Выбор языка — по заголовку Accept-Language; отдельного выбора по cookie нет.

Связь с валидацией

Сообщение констрейнта, обёрнутое в {...}, разрешается через локализацию — с плейсхолдерами :field и любым публичным свойством констрейнта:

php
#[Size(min: 0, max: 3, message: '{order.name_too_long}')]
public readonly string $name;
lang/ru.php
'order' => ['name_too_long' => 'Поле «:field»: не длиннее :max символов'],

Подробнее — на странице Валидация.

Дальше