Локализация

Это гибкое и мощное решение для интернационализации (i18n) вашего приложения. Он позволяет централизованно управлять переводом контента на множество языков, обеспечивая чистоту кода и простоту поддержки.

Благодаря встроенным инструментам вы сможете не только переводить статические фразы, но и гибко адаптировать контент под локальные особенности: использовать правильные формы множественного числа, подставлять динамические данные, применять модификаторы и организовывать переводы по пакетам (namespace) для модульных приложений.

Конфигурирование

Конфигурация локализации приложения находится в файле config/app.php:

// Текущая локаль приложения
'locale' => 'en',

// Локаль, используемая как запасная, если перевод для текущей локали не найден
'fallback_locale' => 'en',
PHP

Структура файлов локализации

Файлы локализации хранятся в директории 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
BASH

JSON-файлы

JSON-файлы содержат плоские ключи и располагаются непосредственно в директории локали:

lang/
  en.json
  ru.json

Пример en.json:

{
    "welcome": "Welcome to our application",
    "goodbye": "Goodbye"
}
JSON

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

Приоритет загрузки файлов

Важно: JSON-файлы имеют приоритет над PHP-файлами групп. Это означает, что если один и тот же ключ определен и в JSON, и в PHP-группе, будет использовано значение из JSON. Например:

lang/en.json:

{
    "messages.welcome": "Welcome from JSON",
    "messages.hello": "Hello from JSON"
}
JSON

lang/en/messages.php:

<?php

return [
    'welcome' => 'Welcome from PHP group',
    'goodbye' => 'Goodbye from PHP group',
];
PHP

Результат:

lang('messages.welcome') → "Welcome from JSON" (из JSON)

lang('messages.hello') → "Hello from JSON" (из JSON)

lang('messages.goodbye') → "Goodbye from PHP group" (из PHP)
PHP

Это позволяет гибко переопределять отдельные ключи, сохраняя группировку остальных переводов.

Получение переводов

Imhotep предоставляет несколько способов работы с локализацией:

  • через глобального помощника lang() или его алиас __()
  • через фасад Imhotep\Facades\Lang
use Imhotep\Facades\Lang;

// Все три способа эквивалентны
$message = __('messages.welcome');
$message = lang('messages.welcome');
$message = Lang::get('messages.welcome');
PHP

Параметры в переводах

Вы можете использовать placeholders для замены значений в строках перевода:

// Файл перевода
'greeting' => 'Hello, :name!',

// Использование
$message = lang('greeting', ['name' => 'John']);
// Результат: "Hello, John!"
PHP

Модификаторы

Модификаторы позволяют преобразовывать значения параметров:

Модификатор Описание Пример
: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"
PHP

Множественное число

Компонент поддерживает множественное число для различных языков:

// Файл перевода
'books' => ':count {:count|book|books}',

// Использование
$lang->get('books', ['count' => 1]);   // "1 book"
$lang->get('books', ['count' => 5]);   // "5 books"
PHP

Для русского языка поддерживаются три формы:

// Файл перевода
'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 книга"
PHP

Выбор по диапазонам

Для сложных условий можно использовать диапазоны:

// Файл перевода
'apples' => '{:count |[0]нет яблок |[1]одно яблоко |[2,4]несколько яблок |[5,*]много яблок}'

// Использование
lang('apples', ['count' => 0]); // "нет яблок"
lang('apples', ['count' => 1]); // "одно яблоко"
lang('apples', ['count' => 3]); // "несколько яблок"
lang('apples', ['count' => 10]); // "много яблок"
PHP

Синтаксис диапазонов:

  • [n] — точное значение n
  • [n,m] — от n до m включительно
  • [n,*] — от n и больше
  • [*,m] — до m включительно

Проверка наличия перевода

Метод has проверяет наличие перевода для указанного ключа:

if (Lang::has('messages.welcome')) {
    // Перевод существует
}
PHP

Метод missing проверяет отсутствие перевода:

if (Lang::missing('messages.welcome')) {
    // Перевод отсутствует
}
PHP

Пространства имен

Пространства имен позволяют пакетам предоставлять собственные переводы:

Регистрация пространства имен

Lang::addNamespace('my-package', '/path/to/my-package/lang');
PHP

Использование пространств имен

// Получение перевода из пространства имен
$message = lang('my-package::messages.welcome');
PHP

При использовании пространства имен система сначала ищет перевод в файлах пакета, а затем проверяет базовую директорию вашего приложения lang/vendor/my-package/ приложения для возможных переопределений.

Добавление переводов во время выполнения

Добавление одного перевода:

Lang::add('custom_key', 'Custom Value');
Lang::add('custom_key', 'Пользовательское значение', 'ru');
PHP

Добавление нескольких переводов:

Lang::addMany([
    'key1' => 'Value 1',
    'key2' => 'Value 2',
], 'en');
PHP

Обработчики событий

Вы можете зарегистрировать callback-функции для отслеживания ситуаций, когда запрошенный перевод не найден. Доступны три типа обработчиков:

Общий обработчик отсутствующих ключей

Вызывается если перевод для переданного ключа не был найден ни в основной, ни в запасной локали:

Lang::handleNotFound(function ($key, $locale, $fallback) {
    Log::warning("Missing translation: {$key} for locale {$locale}");
});
PHP

Отсутствие ключа в основной локали

Вызывается если ключ не найден в текущей локали, но может присутствовать в запасной:

Lang::handlePrimaryNotFound(function ($key, $locale) {
    Log::warning("Missing primary translation: {$key} for locale {$locale}");
});
PHP

Отсутствие ключа в запасной локали

Вызывается если ключ не найден в запасной локали:

Lang::handleFallbackNotFound(function ($key, $fallback) {
    Log::warning("Missing fallback translation: {$key} for locale {$fallback}");
});
PHP

Расширенные возможности

Добавление модификаторов

Вы можете добавить собственные модификаторы:

$lang->addModifier('reverse', function ($value) {
    return strrev($value);
});

// Использование в переводе
'message' => 'Reversed: :reverse:text',
PHP

Добавление правил множественного числа

Вы можете добавить собственные правила множественного числа для языка:

Lang::addPlural('custom_locale', function (int $n) {
    // Вернуть индекс формы множественного числа (0, 1, 2, ...)
    if ($n === 1) return 0;
    if ($n === 2) return 1;
    return 2;
});
PHP

Установка резолвера локалей

Для кастомной логики определения порядка поиска локалей:

$lang->setLocaleResolver(function (array $locales) {
    // $locales содержит [текущая_локаль, fallback_локаль]
    // Вернуть массив локалей в нужном порядке поиска
    return array_reverse($locales);
});
PHP