Кажется, что PHP сопротивляется времени и по-прежнему остается довольно популярным выбором для создания веб-приложений. Мы уже обсуждали как переводить PHP-приложения. Сегодня мы сосредоточимся на Zend Framework, объектно-ориентированной среде PHP с открытым исходным кодом, состоящей из более чем 60 пакетов, каждый из которых служит определенной цели. Именно пакет zend-i18n делает PHP i18n веб-приложений возможным. Существует еще один, называемый zend-mvc-i18n, который необходим для интеграции пакета zend-i18n в структуру MVC. Поскольку большинство веб-приложений, которые мы создаем, следуют шаблону проектирования MVC, в этом руководстве мы будем использовать zend-mvc-i18n.
Вы можете установить пакет Zend, используя следующую команду:
composer require zendframework/zendframework
Вы также можете установить только mvc-i18n, используя следующую команду:
composer require zendframework/zend-mvc-i18n
Composer — это инструмент управления зависимостями, который установит для вас все необходимые зависимости Zend Framework. Если вы еще не установили Composer на свой компьютер, вы можете получить его здесь.
Для этого урока я создал пример проекта. Вот как выглядит структура папок простого проекта:
Для нас важны три раздела: languages, public и src. Мы обсудим их по мере продвижения к руководству.
Объект переводчика
zend-i18n поставляется с полным пакетом переводов, поддерживающим все основные форматы. Он также включает в себя популярные функции, которые поставляются с объектом-переводчиком. Наша следующая задача — определить объект Translator. Для этого необходимо настроить три аспекта:
- Формат перевода
- Местоположение ресурса перевода
- Файл ресурсов перевода
Существуют различные форматы, которые вы можете использовать для представления переводов:
- Массивы PHP (хранить переведенные тексты в массивах PHP),
- gettext (переведенные тексты как обычные тексты в файле)
- Tmx (стандарт XML под названием Translation Memory Exchange)
- Xliff (формат файла на основе XML)
Использование массивов PHP — не самая оптимальная практика. Вы всегда должны отделять строки перевода от исходного кода; gettext — самый простой и, вероятно, самый распространенный метод — именно его я буду использовать в этом приложении. Тем не менее, я покажу вам, как хранить переведенные тексты в форматах xliff и Tmx.
После того, как вы создали файлы с переведенными текстами, вам нужно поместить их в легкодоступное место. Довольно распространенные места:
- Приложение/язык
- данные/язык
Как видите, я использую путь к приложению/языку для хранения файлов перевода.
Третья конфигурация передает файлы перевода объекту Translator. Вы можете добавить каждый файл по отдельности или добавить все файлы сразу, используя шаблон. Предположим, у вас есть 10 исходных файлов перевода для 10 разных языков. Добавлять каждый файл по отдельности может быть довольно обременительно. Поэтому рекомендуется использовать шаблон файла для добавления всех файлов в переводчик.
Теперь создадим объект Translator:
<?php use Zend\I18n\Translator\Translator; return Translator::factory([ 'translation_file_patterns' => [ [ 'type' => 'gettext', 'base_dir' => __DIR__ . '/../languages', 'pattern' => '%s.mo', ], ], ]);
Обратите внимание, как я установил шаблон — что-то вроде шаблона sprintf.%s.mo говорит переводчику принять любую строку с расширением MO. На моем языке есть четыре файла: es.po, es.mo, fr.po и fr.mo (ES означает испанский, а FR — французский); Файлы .PO содержат фактический перевод, а файлы .MO содержат машинный объект или файл двоичных данных. Переводчику нужны бинарные файлы. Поэтому %s.mo передает es.mo и fr.mo транслятору.
Перевод сообщений
После создания объекта Translator мы можем перейти к переводу сообщений. Это можно сделать с помощью метода translate объекта Translator. Перевод текста выполняется в представлении. В нашем приложении представление — это файл index.php в папке Public. Прежде чем использовать объект Translator, вам необходимо включить translation.php в файл index.php.
Формат метода перевода:
$translator->translate($message, $textDomain, $locale);
Его параметры представляют собой следующее:
- $message — сообщение для перевода
- $textDomain — текстовый домен, в котором находится перевод. Это необязательный параметр. Значение по умолчанию — «по умолчанию».
- $locale — Должна использоваться локаль. Это необязательный параметр. Если не установлено, будет использоваться локаль по умолчанию.
Пример метода перевода:
$translator->translate("Translated text from a custom text domain.", "customDomain",”de_DE“);
В любом случае, в нашем приложении мы будем использовать метод перевода немного по-другому. Не имеет особого смысла устанавливать локаль в каждом переведенном сообщении. Вряд ли вы когда-нибудь будете использовать несколько местных жителей в одном и том же представлении. Вы можете установить локаль, используя метод setLocale().
$lang = isset($_GET['lang']) ? $_GET['lang'] : 'en'; $translator->setLocale($lang);
Наконец, наш файл index.php будет выглядеть так:
<?php include __DIR__ . '/../vendor/autoload.php'; $lang = isset($_GET['lang']) ? $_GET['lang'] : 'en'; /** @var Zend\I18n\Translator\Translator $translator */ $translator = include __DIR__ . '/../src/translator.php'; $translator->setLocale($lang); ?> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <p><?php echo $translator->translate('Hello my friend'); ?></p> <p><?php echo $translator->translate('How are you?'); ?></p> <p><?php echo $translator->translate('My name is Adam Crik'); ?></p> </body> </html>
Форматы перевода
Как уже отмечалось в начале, я также хотел бы показать вам, как хранить переведенные тексты в разных форматах. В нашем приложении есть три строки. В gettext переведенные тексты хранятся в файлах .PO.
Наш файл fr.po выглядит так:
#: ../public/index.php:1 msgid "Hello my friend" msgstr "Bonjour, mon ami" #: ../public/index.php:2 msgid "How are you?" msgstr "Comment allez-vous?" #: ../public/index.php:3 msgid "My name is Adam Crik" msgstr "Je m'appelle Adam Crik"
Если мы используем формат XLIFF, это будет выглядеть примерно так:
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="en-US" trgLang="fr"> <file id="f1"> <unit id="1"> <segment> <source>Hello my friend</source> <target>Bonjour, mon ami</target> </segment> </unit> <unit id="2"> <segment> <source>How are you?</source> <target>Comment allez-vous?</target> </segment> </unit> <unit id="3"> <segment> <source>My name is Adam Crik</source> <target>Je m'appelle Adam Crik</target> </segment> </unit> </file> </xliff>
Если мы используем формат TMX, это будет примерно так:
<tmx version="1.4"> <body> <tu> <tuv xml:lang="en"> <seg>Hello my friend</seg> </tuv> <tuv xml:lang="fr"> <seg>Bonjour, mon ami</seg> </tuv> <tuv xml:lang="en"> <seg>How are you?</seg> </tuv> <tuv xml:lang="fr"> <seg>Comment allez-vous?</seg> </tuv> <tuv xml:lang="en"> <seg>My name is John Doe</seg> </tuv> <tuv xml:lang="fr"> <seg>Je m'appelle John Doe</seg> </tuv> </tu> </body> </tmx>
Вспомогательные классы Zend I18n
Если вы читаете наш блог, то уже знаете, что есть понятия, для которых очень важна локальность — некоторые вещи просто не могут существовать без локальности. Мы можем привести валюту, формат данных, числовые форматы в качестве примеров. Если вы собираетесь обеспечить поддержку интернационализации для своего приложения, важно, чтобы вы соответствующим образом переводили эти объекты. Вспомогательные классы Zend упрощают процесс, вводя соответствующие классы с поддержкой локальности:
- Помощник NumberFormat
- Помощник CurrencyFormat
- Помощник DateFormt
Давайте познакомимся с ними поближе, взглянув на несколько примеров.
Помощник NumberFormat
Одним из наиболее очевидных различий в разных локалях является то, как форматируются числа. Класс NumberFormat обрабатывает эти отклонения за вас. Посмотрите на следующие два примера:
echo $this->numberFormat( 2453678.26, NumberFormatter::DECIMAL, NumberFormatter::TYPE_DEFAULT, "de_DE" );
Он отобразит 2.453.678,26.
echo $this->numberFormat( 2453678.26, NumberFormatter::DECIMAL, NumberFormatter::TYPE_DEFAULT, "en_US" );
Отображается 2 453 678,26.
Помощник CurrencyFormat
Мир наводнен различными валютами. По обычаю люди в определенной стране должны иметь возможность платить за продукт или услугу в своей валюте. Валюта становится, таким образом, одним из основных факторов, которые следует учитывать при корректировке проекта интернационализации. Это метод currencyFormat, который выполняет здесь интернационализацию за вас. Проверьте следующий код:
echo $this->currencyFormat(2543.91, "USD", "en_US");
То, что он покажет, составляет 2543,91 доллара США.
echo $this->currencyFormat(2543.91, "EUR", "de_DE");
Он будет отображать 2.543,91 €.
При использовании en_US местной валютой является доллар США. Когда вы используете de_DE, что означает Германия, валюта превращается в евро. Однако это не так. Если вы присмотритесь, формат числа цены также изменился. Причина этого в том, что метод CurrencyFormat является оболочкой для класса NumberFormat.
Помощник формата даты
Последний важный вспомогательный класс, который мы рассмотрим, — это вспомогательный класс DateFormat. В разных странах используются разные форматы даты. В следующем примере сравниваются форматы даты, созданные theen_US и de_DElocales.
echo $this->dateFormat( new DateTime(), IntlDateFormatter::MEDIUM, // date "en_US" );
1 мая 2019 года отображается результат.
echo $this->dateFormat( new DateTime(), IntlDateFormatter::MEDIUM, // date "de_DE" );
В результате отображается 01.05.2019.
Zend Framework предоставляет намного больше вспомогательных классов. Полный список вы можете найти в их документации.
Подведение итогов
В этом учебном пособии вы познакомились с PHP i18n с Zend Framework. Я искренне надеюсь, что вам понравилось и вы многому научились на этом пути. Если вы все еще пытаетесь найти надежную службу локализации, попробуйте Phrase. Phrase — широко известная универсальная платформа для локализации проектов. Помимо PHP, Phrase также поддерживает другие языки программирования, включая Java, Python, Ruby или JavaScript. Подпишитесь на бесплатную 14-дневную пробную версию и попробуйте сами.
Первоначально опубликовано в The Phrase Blog.