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

Онлайн-тренажер Python для начинающих

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

Начать курс

Почему интернационализация PHP — это не просто «перевод слов»

Представьте: вы написали крутой PHP-проект. Он работает, радует пользователей, приносит прибыль. Но однажды в статистике вы замечаете, что 30% трафика — из Германии, 15% — из Японии, а 10% — из ОАЭ. Ваш сайт говорит только по-русски. Пользователи уходят, не найдя кнопку «Купить» на своём языке.

Знакомая ситуация? Интернационализация (i18n) PHP-приложений — это не просто замена слов в шаблоне. Это архитектурный подход, который позволяет вашему коду «понимать» культуру, валюту, даты и даже направление текста (слева направо или справа налево).

В этой статье мы разберём, как превратить обычный PHP-сайт в мультиязычную платформу, используя нативные инструменты и лучшие практики. Вы узнаете, как работает gettext в PHP, чем отличается локализация от интернационализации, и как не наступить на грабли с плюрализацией.

i18n vs l10n: в чём разница (и почему это важно)

Прежде чем писать код, давайте договоримся о терминах. Интернационализация (i18n) — это подготовка кода к переводу: вынос строк, работа с форматами чисел, дат, валют. Локализация (l10n) — это сам процесс перевода и адаптации под конкретный регион.

Простая аналогия: интернационализация — это строительство дома с пустыми комнатами, куда можно поставить любую мебель. Локализация — это расстановка мебели под вкусы конкретного жильца.

Для PHP-разработчика это означает: не хардкодьте строки! Никогда. Даже если сейчас сайт только на русском. Каждая фраза должна быть обёрнута в функцию перевода.

Стек технологий для i18n в PHP

В экосистеме PHP есть несколько мощных инструментов. Мы рассмотрим два основных подхода: классический gettext и современный ICU MessageFormat через расширение intl.

1. Gettext — дедушка мультиязычности

Gettext в PHP — это стандарт де-факто для многих CMS (WordPress, Drupal). Он использует .po и .mo файлы для хранения переводов. Плюсы: простота, поддержка плюральных форм, интеграция с Poedit.

2. ICU MessageFormat — для сложной логики

Расширение PHP intl (Internationalization) предоставляет классы MessageFormatter и NumberFormatter. Это выбор для проектов, где нужны сложные шаблоны с выбором падежа, рода и числа.

3. Библиотеки-обёртки

  • symfony/translation — компонент Symfony, работает как с YAML/XLIFF, так и с gettext.
  • laravel-localization — для Laravel (пакет mcamara/laravel-localization).
  • zend-i18n — для Laminas (бывший Zend Framework).

Практика: настраиваем gettext в PHP с нуля

Допустим, у нас есть простой скрипт index.php, который выводит приветствие. Сделаем его мультиязычным.

Шаг 1. Подготовка кода

Оберните все строки в функцию _() (алиас для gettext()):

<?php
// index.php
echo _("Добро пожаловать на наш сайт!");

$items = 5;
// Для плюральных форм используем ngettext
echo ngettext("%d товар", "%d товаров", $items);
?>

Шаг 2. Генерация .pot файла

Установите gettext на сервере или используйте xgettext:

xgettext -o locales/messages.pot index.php --from-code=UTF-8

Шаг 3. Создание перевода

Скопируйте messages.pot в locales/ru_RU/LC_MESSAGES/messages.po и отредактируйте:

msgid "Добро пожаловать на наш сайт!"
msgstr "Welcome to our site!"

msgid "%d товар"
msgid_plural "%d товаров"
msgstr[0] "%d item"
msgstr[1] "%d items"

Шаг 4. Компиляция и подключение

msgfmt locales/ru_RU/LC_MESSAGES/messages.po -o locales/ru_RU/LC_MESSAGES/messages.mo

В PHP-скрипте укажите локаль:

<?php
$locale = 'ru_RU'; // или 'en_US' по выбору пользователя
putenv("LC_ALL=$locale");
setlocale(LC_ALL, $locale);
bindtextdomain("messages", "locales");
textdomain("messages");

echo _("Добро пожаловать на наш сайт!");
?>

Сложные случаи: плюрализация и контекст

Русский язык славится сложными формами множественного числа. В PHP gettext справляется с этим через ngettext(). Но есть нюанс: для арабского, польского или чешского языков нужно больше двух форм. Интернационализация PHP приложений требует учитывать это на этапе проектирования.

Пример для русского (3 формы):

msgid "%d яблоко"
msgid_plural "%d яблока"
msgstr[0] "%d apple"
msgstr[1] "%d apples"
msgstr[2] "%d apples" // В русском 3 формы, но в английском — 2. Poedit подскажет.

Контекст перевода

Иногда одно и то же слово переводится по-разному в зависимости от контекста. Например, «Save» может быть «Сохранить» (действие) или «Кроме» (предлог). Используйте pgettext:

echo pgettext("Verb", "Save"); // Сохранить
echo pgettext("Preposition", "Save"); // Кроме

Современный подход: ICU MessageFormat через PHP intl

Расширение intl входит в стандартную поставку PHP (начиная с 5.3). Оно позволяет писать сложные шаблоны без множественных ngettext.

Пример: выбор рода и числа в одном шаблоне

<?php
$fmt = new MessageFormatter('ru_RU', 
    '{gender, select, 
        male {Пользователь {name} добавил {count, plural, one {# товар} few {# товара} other {# товаров}}}
        female {Пользовательница {name} добавила {count, plural, one {# товар} few {# товара} other {# товаров}}}
        other {Пользователь {name} добавил                

Блоги

Рекомендаций по книгам