Локализация
Это гибкое и мощное решение для интернационализации (i18n) вашего приложения. Он позволяет централизованно управлять переводом контента на множество языков, обеспечивая чистоту кода и простоту поддержки.
Благодаря встроенным инструментам вы сможете не только переводить статические фразы, но и гибко адаптировать контент под локальные особенности: использовать правильные формы множественного числа, подставлять динамические данные, применять модификаторы и организовывать переводы по пакетам (namespace) для модульных приложений.
Конфигурирование
Конфигурация локализации приложения находится в файле config/app.php:
// Текущая локаль приложения
'locale' => 'en',
// Локаль, используемая как запасная, если перевод для текущей локали не найден
'fallback_locale' => 'en',
Структура файлов локализации
Файлы локализации хранятся в директории lang/ приложения. Поддерживаются два формата json и php.
lang/ # Корневая директория переводов
├── en.json # Плоские ключи для английского
├── ru.json # Плоские ключи для русского
├── en/ # Групповые переводы для английского
│ ├── messages.php
│ ├── validation.php
│ └── auth.php
├── ru/ # Групповые переводы для русского
│ ├── messages.php
│ ├── validation.php
│ └── auth.php
└── vendor/ # Переопределения переводов пакетов
└── package-name/
├── en.json
└── ru/
└── messages.php
JSON-файлы
JSON-файлы содержат плоские ключи и располагаются непосредственно в директории локали:
lang/
en.json
ru.json
Пример en.json:
{
"welcome": "Welcome to our application",
"goodbye": "Goodbye"
}
PHP-файлы
PHP-файлы организованы по группам и располагаются в поддиректориях:
lang/
en/
messages.php
validation.php
ru/
messages.php
validation.php
Пример en/messages.php:
<?php
return [
'welcome' => 'Welcome to our application',
'goodbye' => 'Goodbye',
];
Приоритет загрузки файлов
Важно: JSON-файлы имеют приоритет над PHP-файлами групп. Это означает, что если один и тот же ключ определен и в JSON, и в PHP-группе, будет использовано значение из JSON. Например:
lang/en.json:
{
"messages.welcome": "Welcome from JSON",
"messages.hello": "Hello from JSON"
}
lang/en/messages.php:
<?php
return [
'welcome' => 'Welcome from PHP group',
'goodbye' => 'Goodbye from PHP group',
];
Результат:
lang('messages.welcome') → "Welcome from JSON" (из JSON)
lang('messages.hello') → "Hello from JSON" (из JSON)
lang('messages.goodbye') → "Goodbye from PHP group" (из PHP)
Это позволяет гибко переопределять отдельные ключи, сохраняя группировку остальных переводов.
Получение переводов
Imhotep предоставляет несколько способов работы с локализацией:
- через глобального помощника
lang()или его алиас__() - через фасад
Imhotep\Facades\Lang
use Imhotep\Facades\Lang;
// Все три способа эквивалентны
$message = __('messages.welcome');
$message = lang('messages.welcome');
$message = Lang::get('messages.welcome');
Параметры в переводах
Вы можете использовать placeholders для замены значений в строках перевода:
// Файл перевода
'greeting' => 'Hello, :name!',
// Использование
$message = lang('greeting', ['name' => 'John']);
// Результат: "Hello, John!"
Модификаторы
Модификаторы позволяют преобразовывать значения параметров:
| Модификатор | Описание | Пример |
|---|---|---|
:upper: |
Верхний регистр | :upper:value → "FOO" |
:lower: |
Нижний регистр | :lower:value → "bar" |
:ucfirst: |
Первая буква заглавная | :ucfirst:value → "Foo" |
:lcfirst: |
Первая буква строчная | :lcfirst:value → "fOO" |
:ucwords: |
Каждое слово с заглавной | :ucwords:value → "Foo Bar" |
:slug: |
Slug-формат | :slug:value → "foo-bar" |
// Файл перевода
'message' => 'Hello, :ucfirst:name! Today is :upper:day',
// Использование
lang('message', ['name' => 'john', 'day' => 'monday']);
// Результат: "Hello, John! Today is MONDAY"
Множественное число
Компонент поддерживает множественное число для различных языков:
// Файл перевода
'books' => ':count {:count|book|books}',
// Использование
$lang->get('books', ['count' => 1]); // "1 book"
$lang->get('books', ['count' => 5]); // "5 books"
Для русского языка поддерживаются три формы:
// Файл перевода
'books' => ':count {:count|книга|книги|книг}',
// Использование
$lang->get('books', ['count' => 1]); // "1 книга"
$lang->get('books', ['count' => 2]); // "2 книги"
$lang->get('books', ['count' => 5]); // "5 книг"
$lang->get('books', ['count' => 21]); // "21 книга"
Выбор по диапазонам
Для сложных условий можно использовать диапазоны:
// Файл перевода
'apples' => '{:count |[0]нет яблок |[1]одно яблоко |[2,4]несколько яблок |[5,*]много яблок}'
// Использование
lang('apples', ['count' => 0]); // "нет яблок"
lang('apples', ['count' => 1]); // "одно яблоко"
lang('apples', ['count' => 3]); // "несколько яблок"
lang('apples', ['count' => 10]); // "много яблок"
Синтаксис диапазонов:
-
[n]— точное значение n -
[n,m]— от n до m включительно -
[n,*]— от n и больше -
[*,m]— до m включительно
Проверка наличия перевода
Метод has проверяет наличие перевода для указанного ключа:
if (Lang::has('messages.welcome')) {
// Перевод существует
}
Метод missing проверяет отсутствие перевода:
if (Lang::missing('messages.welcome')) {
// Перевод отсутствует
}
Пространства имен
Пространства имен позволяют пакетам предоставлять собственные переводы:
Регистрация пространства имен
Lang::addNamespace('my-package', '/path/to/my-package/lang');
Использование пространств имен
// Получение перевода из пространства имен
$message = lang('my-package::messages.welcome');
При использовании пространства имен система сначала ищет перевод в файлах пакета, а затем проверяет базовую директорию вашего приложения lang/vendor/my-package/ приложения для возможных переопределений.
Добавление переводов во время выполнения
Добавление одного перевода:
Lang::add('custom_key', 'Custom Value');
Lang::add('custom_key', 'Пользовательское значение', 'ru');
Добавление нескольких переводов:
Lang::addMany([
'key1' => 'Value 1',
'key2' => 'Value 2',
], 'en');
Обработчики событий
Вы можете зарегистрировать callback-функции для отслеживания ситуаций, когда запрошенный перевод не найден. Доступны три типа обработчиков:
Общий обработчик отсутствующих ключей
Вызывается если перевод для переданного ключа не был найден ни в основной, ни в запасной локали:
Lang::handleNotFound(function ($key, $locale, $fallback) {
Log::warning("Missing translation: {$key} for locale {$locale}");
});
Отсутствие ключа в основной локали
Вызывается если ключ не найден в текущей локали, но может присутствовать в запасной:
Lang::handlePrimaryNotFound(function ($key, $locale) {
Log::warning("Missing primary translation: {$key} for locale {$locale}");
});
Отсутствие ключа в запасной локали
Вызывается если ключ не найден в запасной локали:
Lang::handleFallbackNotFound(function ($key, $fallback) {
Log::warning("Missing fallback translation: {$key} for locale {$fallback}");
});
Расширенные возможности
Добавление модификаторов
Вы можете добавить собственные модификаторы:
$lang->addModifier('reverse', function ($value) {
return strrev($value);
});
// Использование в переводе
'message' => 'Reversed: :reverse:text',
Добавление правил множественного числа
Вы можете добавить собственные правила множественного числа для языка:
Lang::addPlural('custom_locale', function (int $n) {
// Вернуть индекс формы множественного числа (0, 1, 2, ...)
if ($n === 1) return 0;
if ($n === 2) return 1;
return 2;
});
Установка резолвера локалей
Для кастомной логики определения порядка поиска локалей:
$lang->setLocaleResolver(function (array $locales) {
// $locales содержит [текущая_локаль, fallback_локаль]
// Вернуть массив локалей в нужном порядке поиска
return array_reverse($locales);
});