Vkontakte
+7 (499) 705-13-20
skype: kuzma.feskov

Многоязычные приложения с использованием PHP и GetText

Автор: Кузьма Феськов, 11 сентября 2014

Автор: Luis Argerich, перевод: Феськов Кузьма

Если вы WEB-разработчик, который создает как небольшие ресурсы, так и большие порталы с сотнями страниц, то в один прекрасный момент вы можете столкнуться с необходимостью перевода вашего проекта на другой язык или обеспечить поддержку нескольких языков в рамках одного проекта.

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

Добро пожаловать в GNU

GNU имеет в своем арсенале очень хороший набор инструментов для производства многоязычных приложений. Этот набор называется GetText. Он был разработан для языков C и C++, но так же прекрасно подходит для других языков, типа PHP.

Возможно, GetText уже установлен на вашей UNIX системе. Чтобы проверить это, наберите в командной строке getetxt и нажмите Ввод (Enter). Если указанного набора компонентов нет, возьмите его, например, здесь: ftp://ftp.gnu.org. Произведите установку. Если gettext у вас уже установлен, то мы переходим к следующей части нашей статьи.

ОТ ПЕРЕВОДЧИКА

Если вы используете в своей работе не только Unix/Linux системы, но так же и Windows, далее я опишу шаги, которые потребуется проделать для установки GetText на вашей Windows системе.

Вам необходимо скачать файлы с этой страницы: http://sourceforge.net/projects/gettext. Для работы вам понадобится gettext-win32 и пакет libconv-win32.

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

  1. скопируйте файлы intl.dll gettext.exe asprintf.dll envsubst.exe ngettext.exe из пакета gettext-win32 в папку SYSTEM32 вашей Windows. Затем, проделайте тоже самое с файлами charset.dll iconv.dll iconv.exe из пакета libconv-win32.
  2. Далее, найдите файл libintl-1.dll (он находится в папке dlls вашей инсталляции PHP) и поместите его так же в папку SYSTEM32.
  3. И, наконец, откройте для редактирования ваш php.ini и раскомментируйте в нем строку extension=php_gettext.dll.

Перезапустите WEB-сервер Apache и выполните команду phpinfo(). Если вы все сделали правильно, то PHP сообщит вам о том, что модуль GetText установлен и enabled (включен).

Интернационализация PHP скриптов

Чтобы использовать GetText в ваших приложениях, написанных на PHP, вы должны будете изменить все ваши скрипты, однако, это необходимо будет сделать всего один раз. Модификации не очень сложны и вы, возможно, даже захотите написать какую-нибудь утилиту, которая будет сканировать код и задавать вопрос типа "хотите изменить это?" и так далее. И так, что же вы должны сделать со своим кодом? Все очень просто, вы всего ли должны будете заменить все строки (string) на подобные:

print (_("Привет мир"));
echo_("Привет мир");
return _("Привет мир");

и так далее (примеры расширены переводчиком).

Да, вы используете неизвестную функцию PHP "подчеркивание" (function "underscore"), которая является псевдонимом к "длинной-чтобы-писать" функции GetText (function gettext). Каждая строка, которую вы хотите перевести, должна быть переведена. Как только вы привыкните к такому способу, вы начнете видеть его преимущества. Всегда пишите ваши строки (string) обернутыми в конструкцию _("string"); (как говорилось выше, можно писать и так: gettext("string");, прим. Переводчика).

Извлечение строк из кода

GetText имеет в своем арсенале утилиту xgettext, которая предназначена для извлечения всех "обернутых" строк из ваших исходных кодов. В результате своей работы она создает файл с расширение .po.

Чтобы создать .po файл из своих исходников введите:

$xgettext src/*.php 

Чтобы узнать о возможностях этой утилиты подробнее, обратитесь к документации.

В результате работы утилиты вы получили .po файл, который должен быть похож на этот:

# SOME DESCRIPTIVE TITLE. 
# Copyright (C) YEAR Free Software Foundation, Inc. 
# FIRST AUTHOR , YEAR. 
# 
#, fuzzy 
msgid "" 
msgstr "" 
"Project-Id-Version: PACKAGE VERSION
" 
"POT-Creation-Date: 2000-12-08 19:15-0300
" 
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE
" 
"Last-Translator: FULL NAME 
" 
"Language-Team: LANGUAGE 
" 
"MIME-Version: 1.0
" 
"Content-Type: text/plain; charset=CHARSET
" 
"Content-Transfer-Encoding: ENCODING
" 

#: prueba.php:12 
msgid "Hello world" 
msgstr "" 

#: prueba.php:12 prueba.php:13 
msgid "
" 
msgstr "" 

#: prueba.php:13 
msgid "This is a test" 
msgstr "" 

Это и есть тот файл, который вы дожны отдать переводчикам. Переводчик должен будет дать значение всем msgstr для конкретного языка. Вы можете сделать в файле комментарии, чтобы дать переводчику контекст или какие-либо пояснения. Для этого используйте знак #.

Например:

#: prueba.php:12 
# This is displayed at the beginning of the script
# (это выводится в начале скрипта)
msgid "Hello world" 
msgstr "" 

И так далее. Теперь вы имеете "мастер" .po файл для всех "обернутых" строк в ваших скриптах. Если вы будете использовать gettext для непереведенных строк, то в качестве результата будет выдаваться строка из msgid, что является очень хорошим свойством системы.

ОТ ПЕРЕВОДЧИКА

Для Windows-систем существует специализированный бесплатный редактор .po файлов, который позволяет облегчить работу переводчиков и упростить получение переведенных файлов. Для детальной информации обратитесь на сайт http://poedit.sourceforge.net/. Редактор поддерживает множество языков интерфейса, в том числе и русский язык.

Для полноценной работы с .po файлами, необходимо заполнить поля в его заголовке:

"Project-Id-Version: PACKAGE VERSION " - Замените PACKAGE VERSION названием своего продукта.

"Last-Translator: FULL NAME " – Замените FULL NAME на имя, фамилию переводчика и его e-mail-адрес.

"Language-Team: LANGUAGE " – Замените LANGUAGE на название языка, на который переводится приложение (например, Russian).

"Content-Type: text/plain; charset=CHARSET " – Замените CHARSET на точное название кодировки, в которой будут переводимые строки (например, UTF-8, Windows-1251).

Создание .mo файлов

.mo файл – это компилированный для использования с GetText .po файл. Вы должны создать .mo файл для каждого, поддерживаемого вашей системой, языка. Делается он таким способом:

$msgfmt messages.po -o messages.mo 

Редактор poedit при сохранении переведенного .po файла автоматически генерирует .mo файл, что создает дополнительные удобства от его использования, прим. Переводчика).

Создание каталогов

Лучший способ для использования gettext – это создание в корне директорий вашего продукта папки locale. Внутри этой директории необходимо создать поддиректории для всех поддерживаемых системой языков. Внутри них необходимо создать директорию LC_MESSAGES, куда, собственно, вы и положите, имеющиеся у вас к данному моменту, .mo файлы. Приведу пример дерева папок:

/src 
   /locale/en/LC_MESSAGES/messages.mo 
                          messages.po 
           ru/LC_MESSAGES/messages.po 
                          messages.mo 

Чтобы найти буквенные сочетания для всех возможных языков, воспользуйтесь этой ссылкой: http://www.loc.gov/standards/iso639-2/php/code_list.php (оригинальная ссылка автора статьи была перемещена на другое место. Здесь указана новая ссылка, прим. переводчика), либо документацией на GetText. Обращаю ваше внимание, что в официальной документации на GetText есть ошибки в буквенных сочетаниях (прим. переводчика).

И так, вы создали дерево директорий и поместили в них необходимые файлы с языковыми ресурсами (.mo файлы). Что же необходимо сделать в ваших PHP скриптах, чтобы все это начало работать? Примеры несколько расширены и изменены, поскольку в оригинальной статье есть некоторые неточности. Эта часть статьи очень сильно отличается от оригинала (прим. переводчика).

В соответствии с пожеланиями пользователя, включаем выбранный им язык приложения:

// Задать русский язык текущим
putenv ("LC_ALL=ru_RU");

или

// Задать английский язык текущим
putenv ("LC_ALL=en_US");

Далее, указываем текущие настройки локали:

// Задать русскую кодировку Windows-1251 (если у вас Windows)
// или KOI-8 (если у вас Linux)
setlocale (LC_ALL, "Russian");

или

// Задать анлийскую кодировку Windows-1252 (если у вас Windows)
setlocale (LC_ALL, "English");

Все сообщения вашего приложения будут выводиться в указанной здесь кодировке. Если вы, по каким-либо причинам, хотите выводить сообщения в другой кодировке, скажем в UTF-8, то в PHP есть команда, которая принудительно указывает gettext в какой кодировке вы хотите получать сообщения:

bind_textdomain_codeset($domain, 'UTF-8');

Значение переменной $domain я объясню ниже.

Теперь следует указать домен (корневую папку), в котором у нас содержатся все языки проекта.

$domain = 'my_site';
bindtextdomain ($domain, "./locale");

"my_site" в данном случае название нашего приложения. Замечу, что все файлы с переводом должны иметь название вида my_site.mo, иначе gettext их не увидит.

Как вы могли заметить, у нас появилась та самая переменная $domain, о которой я говорил выше. Она содержит название текущего домена.

Как вы понимаете, доменов может быть несколько. Это нужно, если ваше приложение состоит из нескольких независимых частей.

Далее, мы выбираем текущий домен, тем самым указывая gettext откуда брать переведенные сообщения:

textdomain ($domain);

И так, на этом настройки gettext в вашем скрипте закончены. Приведу листинг полностью, в порядке следования действий:

// Задаем текущий язык проекта
putenv("LANG=ru_RU");

// Задаем текущую локаль (кодировку)
setlocale (LC_ALL,"English");

// Указываем имя домена
$domain = 'my_site';

// Задаем каталог домена, где содержатся переводы
bindtextdomain ($domain, "./locale");

// Выбираем домен для работы

textdomain ($domain);

// Если необходимо, принудительно указываем кодировку
// (эта строка не обязательна, она нужна,
// если вы хотите выводить текст в отличной от текущей локали кодировке).
bind_textdomain_codeset($domain, 'UTF-8');

Ну что ж, остается только проверить, все ли правильно мы сделали. Для этого установите нужный вам язык и запустите свое приложение. Все сообщения должны выводить на заданном вами языке. Если этого не произошло, то где-то вкралась ошибка: либо вы не перевели все сообщения, либо неправильно создали дерево каталогов с переводами, возможно, неправильно подобрали буквенное сочетание для нужного вам языка. В общем, вариантов много. Надеюсь все же, что все у вас заработало!