Как сделать локализацию во фреймворке HLEB2 на разные языки? Вопрос

14 Ноября 2025 (ред)

На данный момент локализация присутствует в библиотеке Hlogin - для авторизации пользователей. Можно посмотреть, как это устроено там. Но из-за специфики библиотеки не все функции оттуда могут вам пригодиться. Поэтому здесь описание простой локализации для фреймворка через пользовательскую функцию (но можно переделать и через DI), которую вы можете адаптировать под свои нужды.

Локализация

В зависимости от предпочтений вы можете назвать функцию как угодно, но желательно кратко. Здесь мы рассмотрим формат t(...);. Видел еще использование как символа нижнее подчеркивание, но на одном хостинге у меня с этим была проблема, так что нижнее подчеркивание не рекомендую как функцию.

Во фреймворке HLEB2 есть возможность добавлять файлы со своими функциями, они будут инициализированы до основного пользовательского кода. Возможно, что вы уже используете такой файл и нужно будет добавить функцию в него, но если нет, в файле конфигурации config/system.php найдите настройку custom.function.files и добавьте в массив значение '/app/functions.php'. После этого создайте файл для собственных функций в папке app со следующим кодом:

<?php
// Файл app/functions.php
if (!function_exists('t')) {
    /**
     * Локализация по ключу $key.
     * Поддерживает подмену подстрок по принципу {%name%} из именованного массива $params.
     */
    function t(string $key, array $params = [], ?string $lang = null): string
    {
        return \App\Translations::t($key, $params, $lang);
    }
}

Далее нам понадобится класс Translations в той-же папке app.

<?php
// Файл app/Translations.php
declare(strict_types=1);

namespace App;

use Hleb\Static\Settings;
use InvalidArgumentException;

class Translations
{
    public const RU = 'ru';

    public const EN = 'en';

   private static array $sources = [];

    /**
     * Локализация по ключу $key.
     * Поддерживает подмену подстрок по принципу {%name%} из именованного массива $params.
     */
   public static function t(string $key, array $params = [], ?string $lang = null): string
   {
       // Попытка определить язык из первой части url, get-параметра (lang) или сессии (LANG), иначе дефолтный из конфига.
       $lang = $lang ?? Settings::getAutodetectLang();
       $languages = config('main', 'allowed.languages');
       if (!in_array($lang, $languages)) {
           throw new InvalidArgumentException("Language `{$lang}` is not supported or not defined.");
       }
       if (empty(self::$sources[$lang])) {
           self::$sources[$lang] = require_once hl_path("@/config/i18n/$lang.php");
       }
       $result =  self::$sources[$lang][$key] ?? $key;

       if ($params) {
           $replacements = [];
           foreach ($params as $name => $value) {
               $replacements['{%'.$name.'%}'] = (string)$value;
           }
           $result = strtr($result, $replacements);
       }

       return $result;
   }
}

Теперь добавим в папку config/il18n/ файлы переводов, например для русского ru.php и английского en.php. Так как поддерживаются только два эти языка, нужно оставить в настройке allowed.languages конфигурации /config/main.php только их.

<?php
// Файл config/i18n/ru.php
return [
    'hello_world' => 'Привет, Мир!',
    'unique_visits' => 'Зафиксировано {%count%} уникальных посещений',
    // ...
];
<?php
// Файл config/i18n/en.php
return [
    'hello_world' => 'Hello, World!',
    'unique_visits' => '{%count%} unique visits were recorded',
    // ...
];

Используется это так в коде (предполагается, что в стандартных шаблонах фреймворка):

use App\Translations;

echo t('hello_world'); // Автоопределяемый язык

echo t('unique_visits', ['count' => 120]); // Автоопределяемый язык

echo t('unique_visits', ['count' => 120], Translations::RU);

Здесь еще важно указать нужный параметр по умолчанию, когда язык не удалось определить - это настройка default.lang в конфигурации config/main.php.

Расширенная интернационализация

Указанной выше локализации хватит для большинства приложений, однако, если у вас очень много переводов, то можно разбить локализацию на логические части и подгружать файлы только из определенной подпапки, соответственно в функции t() нужно добавить аргумент с указанием этой части.

Также для преобразования дат и прочего в тексте предназначено расширение https://www.php.net/manual/ru/book.intl.php intl в PHP, но его подключение и использование выходит за рамки этого вопроса.

Локализация для Twig

Начиная с v2.1.18 версии фреймворка можно добавить функцию для поддержки в Twig. Для этого добавлен параметр в common раздел, в котором надо указать функцию t().

'twig.allowed.functions' => ['csrf_token', 'url', 't'],

После этого она будет доступна в Twig-шаблонах.

fomiash fomiash + 221
Опубликовано в PHP фреймворк HLEB

2 Ответа

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

    <?php
    // Файл routes/map.php
    use App\Controllers\UserController;
    
    foreach(['', '/{lang}'] as $key => $lang) {
        // Все маршруты, где необходима локализация, добавляются в этот цикл.
        Route::get("$lang/", view('default'))->name("homepage.{$key}");
        Route::get("$lang/user/{id}")->controller(UserController::class)->name("profile.{$key}");
    }
    <?php
    
    namespace App\Controllers;
    
    use Hleb\Base\Controller;
    use Hleb\Static\Settings;
    
    class UserController extends Controller
    {
        // Демонстрационный метод.
       public function index(): string
       {
           $lang = Settings::getAutodetectLang();
    
           return $lang; // Проверка правильности установленного языка.
       }
    }
    1
    fomiash 15 Ноября 2025 (ред.)
  1. Спасибо за описание локализации. Возможно следующий вопрос немного не по теме, но как сформировать маршруты так, что-бы у дефолтного языка не было локали в url, а у всех остальных присутствовала?

    Andrej 15 Ноября 2025
  1. В комментарий не добавляется код, отправил его здесь как ответ. fomiash 15 Ноября 2025
  2. Пока здесь отключено создание вопросов, так что если появятся еще, можете написать в личку — оформлю как вопрос. fomiash 15 Ноября 2025


Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.