Интернационализация PHP: от простых массивов до gettext

Раздел: PHP веб-разработка -> Интернационализация

Локализация PHP приложений: ключевые подходы

Как обеспечить локализацию с помощью расширения gettext?

Расширение gettext является стандартным и наиболее эффективным решением для интернационализации в PHP. Оно поддерживает плюрализацию, категории (LC_MESSAGES, LC_TIME, LC_MONETARY) и кэширование переводов на уровне сервера.

Для работы требуется установить расширение (обычно включено в PHP, но может потребоваться пакет php-gettext). Код размещается в файле index.php:

<?php
putenv('LC_ALL=ru_RU.UTF-8');
setlocale(LC_ALL, 'ru_RU.UTF-8');
bindtextdomain('messages', './locale');
textdomain('messages');
echo _("Hello, world!");
?>

Php loc index php (локализация в php)

Шаги: подготовка файлов .po (с помощью xgettext или Poedit), компиляция в .mo, расположение в директории locale/ru_RU/LC_MESSAGES/...

Типичные ошибки: локаль не установлена на сервере, неверный путь к файлам .mo, отсутствие нужной кодировки, проблемы с кэшем (требуется перезапуск веб-сервера или очистка кэша gettext). Решение: проверить setlocale через var_dump(setlocale(LC_ALL, 0)); использовать абсолютные пути.

Цель: профессиональные проекты с множеством языков, требования к производительности и поддержка плюрализации.

Как выполнить переводы без внешних расширений с помощью массивов PHP?

Самый простой способ: создать файлы с массивами, где ключи - строковые идентификаторы, значения - переводы. Файл lang/ru.php:

<?php
return [
    'hello' => 'Привет, мир',
    'welcome' => 'Добро пожаловать',
];
?>

Index php en (локализация (язык en))

Функция перевода:

function t($key, $lang = 'ru') {
    $translations = include "lang/$lang.php";
    return $translations[$key] ?? $key;
}

Action php lang (язык в php (локализация))

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

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

Как хранить переводы в формате JSON для удобства редактирования?

JSON легко читается и редактируется внешними инструментами. Файл lang/ru.json:

{
    "hello": "Привет",
    "welcome": "Добро пожаловать"
}

PHP код:

function t($key, $lang = 'ru') {
    $json = file_get_contents("lang/$lang.json");
    $data = json_decode($json, true);
    return $data[$key] ?? $key;
}

Проблемы: каждый вызов функции читает файл с диска - медленно. Решение: кэширование в статическую переменную или использование кэша (APCu, Redis). Также JSON не поддерживает комментарии.

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

Как интегрировать профессиональную систему переводов с помощью Symfony Translation компонента?

Компонент предоставляет мощные возможности: поддержка XLIFF, YAML, PHP, плюрализация, каталоги, загрузчики. Установка через Composer:

composer require symfony/translation

Пример использования:

<?php
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\Loader\ArrayLoader;
$translator = new Translator('ru');
$translator->addLoader('array', new ArrayLoader());
$translator->addResource('array', [
    'hello' => 'Привет',
    'apples_count' => '{0} Нет яблок|[1,Inf] %count% яблок',
], 'ru');
echo $translator->trans('hello');
echo $translator->trans('apples_count', ['%count%' => 5]);
?>

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

Применяется в больших коммерческих проектах с командой переводчиков и сложной логикой локализации.

Расширенные примеры локализации в PHP

Пример 1. Плюрализация с gettext (функция ngettext).

Пример
<?php
putenv('LC_ALL=ru_RU.UTF-8');
setlocale(LC_ALL, 'ru_RU.UTF-8');
bindtextdomain('messages', './locale');
textdomain('messages');
$count = 5;
echo ngettext('%d яблоко', '%d яблок', $count);
?>
5 яблок

Пример 2. Динамическое переключение языка через сессию.

Пример
<?php
session_start();
$lang = $_SESSION['lang'] ?? 'ru';
if (isset($_GET['lang'])) {
    $lang = $_GET['lang'];
    $_SESSION['lang'] = $lang;
}
putenv("LC_ALL={$lang}_RU.UTF-8");
setlocale(LC_ALL, "{$lang}_RU.UTF-8");
bindtextdomain('messages', './locale');
textdomain('messages');
echo _('Welcome');
?>
Добро пожаловать (при lang=ru)

Пример 3. Форматирование чисел и валют с помощью intl (NumberFormatter).

Пример
<?php
$number = 123456.78;
$fmt = new NumberFormatter('ru_RU', NumberFormatter::CURRENCY);
echo $fmt->formatCurrency($number, 'RUB');
$fmt2 = new NumberFormatter('en_US', NumberFormatter::DECIMAL);
echo $fmt2->format($number);
?>
123 456,78 ₽
123,456.78

Пример 4. Сложные сообщения с MessageFormatter (плюрализация + подстановки).

Пример
<?php
$message = '{0, plural, one{# книга} few{# книги} other{# книг}}';
$fmt = new MessageFormatter('ru_RU', $message);
echo $fmt->format([0 => 1]);
echo $fmt->format([0 => 3]);
echo $fmt->format([0 => 10]);
?>
1 книга
3 книги
10 книг

Пример 5. JSON с кэшированием в статическую переменную.

Пример
<?php
function t($key, $lang = 'ru') {
    static $cache = [];
    if (!isset($cache[$lang])) {
        $json = file_get_contents("lang/$lang.json");
        $cache[$lang] = json_decode($json, true);
    }
    return $cache[$lang][$key] ?? $key;
}
echo t('hello');
?>
Привет

Пример 6. Работа с временными зонами и датами.

Пример
<?php
$date = new DateTime('2025-03-24 15:30:00', new DateTimeZone('Europe/Moscow'));
$fmt = new IntlDateFormatter('ru_RU', IntlDateFormatter::LONG, IntlDateFormatter::SHORT);
echo $fmt->format($date);
?>
24 марта 2025 г., 15:30

Локализация в PHP - comments

En
Php loc index php (php)