Статьи

Локализация PHP-приложений «Правильный путь», часть 3

Во второй части вы узнали больше об использовании библиотеки gettext, изучив наиболее важные функции расширения. В этой части вы узнаете, как наилучшим образом использовать резервную локаль, переключаться между локалями и переопределять текущий выбранный домен сообщений. Так что без дальнейших церемоний, давайте погрузимся в!

Структура каталогов и резервные локали

Если вы следовали предыдущим статьям, у вас должна быть следующая структура каталогов для тестирования библиотеки gettext. Хотя это типично, оно не предназначено для достижения наилучшей производительности.

directory recap

Вообще говоря, вы должны определить язык / локаль вашего приложения по умолчанию, прежде чем углубляться в процесс локализации, поскольку это решение повлияет на то, как вы создаете файлы основного домена. Например, если вы решите использовать американский английский в качестве локали по умолчанию — как это делают большинство людей — тогда вы, вероятно, вообще не создадите каталог en_US ! Предпочтительно создавать каждый целевой домен с сообщениями, которые являются фактическими строками, которые были бы найдены в локали по умолчанию. Поэтому вместо использования идентификатора «HELLO_WORLD» вы должны использовать настоящую английскую строку.

  # Тестовый токен 1
 msgstr "Привет, мир!"
 msgstr "Добрый день!" 

Помните, что gettext отобразит сообщение, если не может найти домен перевода. Так что речь идет не о самом каталоге en_US , а об избежании ненужных переводов, когда пользователь запрашивает локаль по умолчанию. Использование настоящих текстовых строк, подобных этому, экономит время выполнения и память, избавляя от необходимости переводить с английского на английский «HELLO_WORLD» на «Hello World!».

Хотя некоторые разработчики предпочитают сохранять перевод с английского на английский, поэтому существует четкое различие между строками приложения («HELLO_WORLD») и текстом интерфейса («Hello World!»), Я очень предпочитаю этот запасной подход. Конечно, вы можете выбирать, что лучше всего соответствует вашим потребностям и личному стилю.

После удаления каталога en_US я добавлю еще две локали, на которые может ориентироваться приложение: испанский ( es_ES ) и египетский арабский ( ar_EG ). Вот так должен выглядеть каталог Locale :

ar_EG and es_ES directories

Не забудьте создать необходимые домены перевода для каждого, используя те же процедуры, которые описаны в части 1 .

Французский домен содержит:

  # Тестовый токен 1
 msgstr "Привет, мир!"
 msgstr "Добрый день!"

 # Тестовый токен 2
 msgstr "Тестирование перевода ..."
 msgstr "Тест de traduction ..." 

Испанский домен содержит:

  # Тестовый токен 1
 msgstr "Привет, мир!"
 msgstr "Привет, Мундо!"

 # Тестовый токен 2
 msgstr "Тестирование перевода ..."
 msgstr "Prueba de traducción ..." 

И арабский домиан содержит:

  # Тестовый токен 1
 msgstr "Привет, мир!"
 msgstr "! أهلا بالعالم"

 # Тестовый токен 2
 msgstr "Тестирование перевода ..."
 msgstr "... اختبار الترجمة" 

Посмотрите, как msgid во всех целевых доменах на самом деле являются строками из локали en_US которая была удалена, поскольку вы теперь используете ее по умолчанию. Теперь у вас есть реальная структура каталогов с доменами перевода!

Переключение языков

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

Создайте новый файл с именем locale.php со следующим содержимым:

 <?php // use sessions session_start(); // get language preference if (isset($_GET["lang"])) { $language = $_GET["lang"]; } else if (isset($_SESSION["lang"])) { $language = $_SESSION["lang"]; } else { $language = "en_US"; } // save language preference for future page requests $_SESSION["Language"] = $language; $folder = "Locale"; $domain = "messages"; $encoding = "UTF-8"; putenv("LANG=" . $language); setlocale(LC_ALL, $language); bindtextdomain($domain, $folder); bind_textdomain_codeset($domain, $encoding); textdomain($domain); 

Затем откройте скрипт test-locale.php ; удалите код настройки домена и locale.php вместо него новый файл locale.php . Ваш код теперь должен выглядеть так:

 <?php // Include I18N support require_once "locale.php"; echo _("Hello World!"), "<br>"; echo _("Testing Translation..."); 

Теперь вы готовы к веселью! Перейдите в браузер, и вы получите следующий вывод:

  Привет, мир!
 Тестирование перевода ... 

Измените URL-адрес для передачи в одной из ранее созданных локалей, например: test-locale.php?lang=fr_FR . gettext отобразит вывод на французском или арабском языке, в зависимости от того, что вы указали для параметра. Переключение языков так просто!

  Bonjour Tout Le Monde!
 Тест de traduction ...

Файл locale.php использует сеансы, поэтому вам нужно только один раз передать параметр lang и он будет использоваться пользователем для последующих запросов. Если вы выполняете перезапись URL, другой возможностью является сделать язык частью URL и извлечь его оттуда, как на www.example.com/en_US/test-locale.php .

Переопределение текущего домена

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

dgettext() по сути аналогична gettext() и _() , за исключением того, что она принимает имя домена в качестве первого аргумента для поиска перевода. Это не влияет на домен по умолчанию, который был установлен textdomain() ; последующие вызовы gettext() прежнему будут использовать значение по умолчанию.

Создайте новый домен перевода по имени ошибки для французского языка ( TestI18N/Locale/fr_FR/LC_MESSAGES/errors.po ). Убедитесь, что вы создали файл с помощью Poedit, затем откройте его с помощью текстового редактора и добавьте следующие переводы:

  Ошибка теста 1
 msgstr "Ошибка при получении контента"
 msgstr "Erreur de l'obtention du contenu"

 # Ошибка проверки 2
 msgstr "Ошибка сохранения данных"
 msgstr "Erreur de sauvegarde des données" 

Сохраните errors.po , снова откройте его в Poedit и скомпилируйте в errors.mo . Затем добавьте следующие строки в конец test-locale.php :

 <?php echo "<br>"; echo _("Error getting content"), "<br>"; echo _("Error saving data"); 

Когда вы запустите скрипт test-locale.php вы увидите английские строки, даже если вы передадите lang=fr_FR в качестве параметра. Это связано с тем, что вы добавили эти сообщения в другой домен ( _() использует домен сообщений для поиска переводов, поскольку это было установлено с textdomain() ). Чтобы сообщить gettext, где найти новые строки перевода, обновите код, чтобы вместо него использовать dgettext() :

 <?php echo dgettext("errors", "Error getting content"), "<br>"; echo dgettext("errors", "Error saving data"); 

Теперь, когда вы запускаете скрипт … вы все равно видите английские сообщения! Хм … почему они не заменяются?

На самом деле мы только что совершили очень распространенную ошибку, которую допускают люди при использовании gettext. Если вы помните в первой части, я говорил о двух очень важных методах, bindtextdomain() и bind_textdomain_codeset() и упомянул, что вы можете вызывать их несколько раз, чтобы связать столько доменов, сколько вы хотите. Всякий раз, когда вам нужно использовать домен, вы должны сначала явно связать его, используя bindtextdomain() . gettext позволяет загружать только один «главный» домен, который textdomain() с помощью textdomain() и тот, который используется gettext() и _() . Вы можете искать сообщения в других доменах с помощью dgettext() только если они связаны первыми.

Обновите включаемый файл locale.php чтобы связать домен ошибок:

 <?php ... bindtextdomain($domain, $folder); bind_textdomain_codeset($domain, $encoding); bindtextdomain("errors", "Locale"); bind_textdomain_codeset("errors", "UTF-8"); textdomain($domain); 

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

Резюме

В этой части вы узнали, как использование строк локали по умолчанию в качестве msgid в целевых доменах может улучшить производительность и организацию, и как можно выполнить переключение между локалями на основе предпочтений пользователя. Вы также узнали, что, хотя gettext допускает только один домен поиска по умолчанию, вы можете использовать несколько доменов с помощью dgettext() если вы сначала связали их.

В следующей части я покажу вам, насколько мощным является gettext, когда дело доходит до обработки одного из самых требовательных аспектов языка — множественного числа.

Изображение через sgame / Shutterstock