Блог хеллоуворлдщика

Многоязычность в PHP


Многие сталкиваются с такой проблемой, как поиск подходящего решения в решение вопроса с мультиязычностью и переводами в целом. Мало кто знает, но в PHP есть такое расширение Intl, которое из коробки поддерживает различные фичи связанные с переводами, форматированием и прочими плюхами полезными не только для мультиязычных проектов, но и одноязычных тоже. Все это называется - интернационализация. И сегодня я хочу осветить такой вовсе не странный и весьма простой вопрос с переводами. Дак, как же все-таки сделать это просто, быстро и безболезненно? Читайте дальше! =)

В первую очередь, что необходимо сделать, это убедиться, что у вас установлено расширение Intl с PHP,

$  php -m | grep intl

(если вывод будет пустой, то значит расширения этого у вас нет и его следует установить),

да и вообще "покурить" документацию к нему. Расширение Intl реализовано на базе ICU, а значит, все, что справедливо для ICU справедливо и для нас.

Перейдем к коду.

Подготовим наш конфигурационный файл с сообщениями:

// config/messages.php
<?php declare(strict_types=1);
 
return [
    'User' => [
        'ru-RU' => [
            'SAY_HELLO' =>  'Привет, {0}!',
            'NUMBER_OF_APPLE' => 'У меня {0, plural, one{# яблоко} few{# яблока} many{# яблок} other{# яблока}}',
        ],
        'en-US' => [
            'SAY_HELLO' =>  'Hello, {0}!',
            'NUMBER_OF_APPLE' => 'I have {0, plural, one{# apple} other{# apples}}',
        ],
    ],
];

И сделаем интерфейс от которого мы позже можем плясать и без проблемно заменять реализации в проекте (привет SOLID):

<?php declare(strict_types=1);
 
namespace I18n;
 
interface TranslatorInterface
{
    public function t(string $message, string $domain, ...$params): string;
}

Здесь все просто: первый аргумент - сообщение, второй - группа сообщений, третий - дор. параметры для сообщения, если есть.

А сейчас реализуем сам транслятор сообщений:

<?php declare(strict_types=1);
 
namespace I18n;
 
use MessageFormatter;
 
class FsTranslator implements TranslatorInterface
{
    /**
     * @var array
     */
    private $messages;
    /**
     * @var string
     */
    private $locale;
 
    public function __construct(array $messages, string $locale)
    {
        $this->messages = $messages;
        $this->locale = $locale;
    }
 
    public function t(string $message, string $domain, ...$params): string
    {
        if (isset($this->messages[$domain][$this->locale][$message])) {
            $message = $this->messages[$domain][$this->locale][$message];
        }
 
        return (new MessageFormatter($this->locale, $message))->format($params);
    }
}

В классе FsTranslator мы использовали MessageFormatter из Intl, документация к нему здесь.

Использование:

// Russian
$translator = new \I18n\FsTranslator(require __DIR__ . '/config/messages.php', 'ru-RU');
 
$translator->t('SAY_HELLO', 'User', 'Иван'); // Привет, Иван!
 
$translator->t('NUMBER_OF_APPLE', 'User', 1); // У меня 1 яблоко
$translator->t('NUMBER_OF_APPLE', 'User', 2); // У меня 2 яблока
$translator->t('NUMBER_OF_APPLE', 'User', 3); // У меня 3 яблока
$translator->t('NUMBER_OF_APPLE', 'User', 5); // У меня 5 яблок
$translator->t('NUMBER_OF_APPLE', 'User', 1.5); // У меня 1,5 яблока
 
// English
$translator = new \I18n\FsTranslator(require __DIR__ . '/config/messages.php', 'en-US');
 
echo $translator->t('SAY_HELLO', 'User', 'Ivan'); // Hello, Ivan!
 
$translator->t('NUMBER_OF_APPLE', 'User', 1); // I have 1 apple
$translator->t('NUMBER_OF_APPLE', 'User', 2); // I have 2 apples
$translator->t('NUMBER_OF_APPLE', 'User', 3); // I have 3 apples
$translator->t('NUMBER_OF_APPLE', 'User', 5); // I have 5 apples
$translator->t('NUMBER_OF_APPLE', 'User', 1.5); // I have 1,5 apples

Вот и все. Это, конечно, не все возможности. Все я, к сожалению, охватить не могу. Поэтому, читайте документацию к ICU. =)

Полезные ссылки:

share via vkontakte share via facebook share via mailru share via odnoklassniki share via twitter

Комментарии [0]

Нет комментариев.