Локализация
Winter переводит строки по ключам из PHP-словарей, автоматически выбирая язык по
заголовку Accept-Language. Под Swoole выбор изолирован по корутине. Те же ключи
используются в сообщениях валидации.
Что такое локализация и зачем
Локализация — выдача текстов на языке пользователя.
Проблема. Строки, зашитые в код на одном языке, нельзя перевести без правок кода, а выбирать язык под каждого пользователя вручную неудобно.
Решение. Держите тексты в словарях по языкам и обращайтесь к ним по ключу — Winter сам подберёт язык по запросу и подставит перевод. Об этом и раздел.
Настройка
Задайте папку словарей и язык по умолчанию в bootstrap.php:
use Flytachi\Winter\K2\Localization\Locale;
Locale::setBasePath(__DIR__ . '/lang');
Locale::setDefault('en');Словарь — PHP-файл, возвращающий вложенный массив; ключи адресуются точечной нотацией:
return [
'auth' => ['welcome' => 'Добро пожаловать, %s!'],
'order' => ['created' => 'Заказ :id создан'],
];Перевод
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-RU → ru,
иначе язык по умолчанию). Приложение может переопределить язык через Locale::set().
Никогда не бросает
На отсутствующий ключ или словарь Locale::t() возвращает сам ключ — исключения не
будет. Выбор языка — по заголовку Accept-Language; отдельного выбора по cookie нет.
Связь с валидацией
Сообщение констрейнта, обёрнутое в {...}, разрешается через локализацию — с
плейсхолдерами :field и любым публичным свойством констрейнта:
#[Size(min: 0, max: 3, message: '{order.name_too_long}')]
public readonly string $name;'order' => ['name_too_long' => 'Поле «:field»: не длиннее :max символов'],Подробнее — на странице Валидация.
Дальше
- Валидация — переводы сообщений об ошибках
- Запросы и ответы — где определяется язык запроса