Установка локали в Linux
Подготовка локали к работе
Поддержка локали в РНР
Предикаты, основанные на локали
Функции библиотеки GNU Recode
Нечаянная радость: convert_cyr_string
Поддержка NLS
Рассмотренные выше функции были ориентированы на непосредственное использование решений по локализации программного обеспечения, реализованное
на уровне самой операционной системы. Но что делать с самим РНР-приложением, текстовые сообщения которого также могут быть предметом локализации?
В самом деле, неужели необходимо «перепахивать» весь исходный текст программы, чтобы перевести текстовые элементы с русского на английский или украинский?
К счастью, эта проблема является довольно общей и в рамках UNIX решение для
нее найдено достаточно давно. Вероятно, вы уже встречали аббревиатуру NLS
(Native Language Support). Это составная часть локали, которая предусматривает
автоматическую загрузку текстовых ресурсов программы, специфичных для той
или иной локали. В проектах GNU для этой цели используются программа gettext
и разработанный для ее использования API.
А в PHP-машине, в свою очередь, реализовано несколько функций, использующих этот механизм.
совет
Следует иметь в виду, что для активизации этого режима необходимо включить поддержку
gettext при конфигурировании PHP-машины .
11.7.1. Назначение домена ресурсов:bindtextdomain
string bindtextdomain (string domain, string directory)
Эта функция устанавливает имя каталога, в котором хранятся текстовые сообщения программы того или иного домена (языковой зоны).
11.7.2. Задание категории и перекрытие записи:dcgettext
string dcgettext (string domain, string message, int category)
Функция позволяет определить категорию записей домена, а также перекрыть установки текущего домена для одной отдельной записи.
11.7.3. Перекрытие текущего домена: dgettext
string dgettext (string domain, string message)
Функция dgettext () позволяет вам перекрыть текущий домен для одной отдельной записи.
11.7.4. Базовое преобразование: gettext
string gettext (string message)
Собственно говоря, в подавляющем большинстве случаев вам достаточно использовать только эту функцию. Ее задача состоит в том, чтобы найти в таблице трансляции, определяемой текущей локалью, перевод для строки-аргумента. Если такой перевод найден, он возвращается в качестве результата работы функции, а если
нет, возвращается строка-аргумент.
В листинге 11.2 приведен пример использования NLS-поддержки.
Листинг 11.2. Локализация программы с помощью gettext
<HTML>
<ТIТLE_Е>Локализация программы с помощью gettext</TITLE>
<BODY BGCOLOR="#FFFFFF">
<?php
echo "<FONT SIZE=+l>\n\n";
// Включаем поддержку русского языка, поскольку LANG не
// импортируется PHP-машиной из внешней среды
putenv("LANG=ru_RU");
// Указываем программе, где находятся текстовые ресурсы
$locale_path = bindtextdomain ("MyPHP", "./locale");
echo "Устанавливаем путь - $locale_path\n";
// Устанавливаем домен
$old = textdomain ("MyPHP");
echo "Текущий домен - $old <p>\n";
// И выдаем пользователю тестовое сообщение
print (gettext ("Welcome to My PHP Application"));
?>
Результат выполнения этой программы (при условии выполнения нескольких
дополнительных операций, описанных ниже) приведен на рис. 11.2.
Рис. 11.2. Локализация с помощью gettext выполняется вполне предсказуемым образом
11.7.5. Установка домена по умолчанию:textdomain
string textdomain (string text_domain)
Эта функция устанавливает имя домена, в котором должен производиться поиск
текстовых ресурсов программы. Обычно это имя совпадает с именем приложения.
Вы можете также считать текущее значение домена, если вызовете эту функцию
без аргументов.
11.7.6. Так как же пользоваться NLS-поддержкой?
Понятно, что после рассмотрения функций читателю хотелось бы получить простую и наглядную методику построения собственных программ с многоязыковой
поддержкой. Нет ничего проще. В качестве примера мы рассмотрим программу,
приведенную при описании функции gettext () (листинг 11.2).
Первое, на что необходимо обратить внимание, — все текстовые сообщения, которые планируется реализовать на нескольких языках, должны выводиться внутри
PHP-программы через функцию gettext (). В нашем случае это одна строка:
print (gettext ("Welcome to My PHP Application"));
Почему она написана по-английски? Это всего лишь дань традиции. Если ваш основной язык — русский, имеет смысл использовать в качестве строк по умолчанию
именно русские сообщения. Но! Как вы увидите ниже, именно по этим сообщениям вам придется ориентироваться при адаптации программы к другим языкам.
А теперь представьте, что адаптацией вашей программы на свой родной язык займется
финн, кореец или гондурасец, познания которого в русском достаточно слабы, а шрифтов и вообще русской локали на машине нет. Сможет ли он разобрать «кракозябры»? Вряд ли. Именно поэтому в качестве основного языка сообщений обычно
выбирается английский, которым худо-бедно владеет большинство программистов.
Теперь, после того как вы преобразовали весь текстовый вывод описанным выше
образом, пришло время сформировать шаблон для перевода. Для этого вам необходимо воспользоваться программой xgettext из пакета gettext, которая входит в состав большинства дистрибутивов Linux.
Вот что нам потребуется сделать:
xgettext gettext.php
В ответ вы получите предупреждение о неизвестном расширении .php и интерпретации программы как Си-кода. Ничего страшного! Синтаксис РНР в целом не отличается от Си, и на корректность получаемых результатов это не повлияет.
В результате выполнения программы в том же каталоге, где находится исходная
программа, появится новый файл — messages.ро, имеющий следующее содержание:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR Free Software Foundation, Inc.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSIONNn"
"POT-Creation-Date: 2001-09-15 10:10+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
#: gettext.php:13
msgid "Welcome to My PHP Application"
msgstr ""
Начальный блок файла предназначен для его формализованного описания, и вы
можете заполнять его по своему усмотрению, но, разумеется, с соблюдением описанных в нем формальностей. Я не буду останавливаться на этих деталях и перейду к последним трем строкам.
примечание
Расширение ро означает Portable Object, а в результате последующей компиляции вы
получите файл с расширением mo — Machine Object. Эти обозначения были введены много лет назад компанией Uniforum при разработке первых систем NLS и использовались в
операционной системе Solaris.
Первая из них — комментарий, указывающий, из какой строки исходного файла
извлечена текстовая строка. Затем следует ключ записи — текстовое сообщение,
являющееся аргументом вызова gettext () в вашей программе. А затем следует
строка трансляции — перевод этого сообщения на язык той или иной локали.
совет
Теперь вы понимаете, почему аргументы gettext() обычно пишут на английском? Локализатор программы вообще не смотрит исходный текст — он работает только с этим шаблоном! Это значительно сокращает время локализации программы, но требует понимания смысла текстовых сообщений.
Но вернемся к процессу локализации. В соответствии с логикой работы программы мы создаем подкаталог locale и переносим туда messages.ро. Затем создаем копию файла, в которую поместим русский перевод:
ср messages.ро messages.ru
Следующий шаг состоит в трансляции текстового файла в бинарный формат, используемый функциями библиотеки gettext. Для этого используется программа
msgfmt:
msgfmt -о MyPHP.mo messages.ru
Теперь нам необходимо только поместить скомпилированный файл сообщений
«куда надо» и программа со с. 229 заработает. Но как определить этот каталог? Ни
в одной книге по РНР и даже в документации к библиотеке gettext вы не найдете
исчерпывающего описания. Кроме того, при невозможности вывода переведенных
сообщений вы не получите никаких сообщений об ошибке, которые позволили бы
локализовать проблему, — вам просто будет выводиться оригинальный текст, приведенный в аргументе gettext (). Поэтому давайте разберемся не торопясь.
Изначально по умолчанию операционная система использует для хранения локализационных сообщений каталог/usr/share/locale. Но в этом каталоге объединяется информация сразу для всех приложений и для всех языков. Поэтому он, в свою очередь, разбивается на целое дерево подкаталогов. В конце концов, полное имя
файла с переведенными сообщениями приобретает вид:
корневой каталог/локаль/категория/домен.то
Но PHP-машина вовсе не использует в качестве корневого каталога упомянутый
выше /usr/share/locale! Вместо этого в качестве корневого каталога используется
текущий каталог, из которого запускается PHP-программа. Мы в нашем примере
просто добавили еще один подкаталог — locale.
Второй компонент, локалъ, извлекается из переменной окружения LANG, значение
которой вы должны установить в своей программе. Но здесь есть одна тонкость:
значение этой переменной обязательно должно совпадать с разрешенным значением локали, воспринимаемым функцией setlocale для вашей системы. В моем
случае — это ru_RU.
примечание
Казалось бы — парадокс. Саму локаль мы не настраиваем, а только пытаемся ввести в си-
стему одну-единственную строку, которая будет включаться в путевое имя файла. И тут
в силу вступают какие-то непонятные соглашения и процедуры, которые резко ограничивают свободу маневра!
Следующий компонент, категория, должен иметь вполне определенное значение —
LC_MESSAGES. Это именно та категория, которая отвечает за перевод сообщений
программы.
Осталось прояснить, что такое домен. Это имя приложения, под которым вы буде-
те идентифицировать свою программу в каталоге. В нашем случае — это МуРНР.
Итак, в результате всего изложенного, для программы, размещенной в файле:
/usr/local/apache/php/part4/gettext.php
вам необходимо поместить файл локализованных сообщений в:
/usr/local/apache/php/part4/locale/
ru_RU/
LC_MESSAGES/
MyPHP.mo
И вот только тогда вы сможете получить результат, приведенный на рис. 11.1.
Теперь вы с успехом можете использовать библиотеку gettext для построения
локализованных и многоязычных программ. Вам осталось только определить,
как программа определит предпочтения конкретного пользователя. Но для этого
в РНР также есть средства — поддержка сеансов и работа с «плюшками» (Cookies)
(см. главу 15).
|