Продолжаем заметки про создание своего расширения для MediaWiki. Продолжим доработку созданной нами в первой и второй частях служебной страницы. Теперь по плану – локализация. А точнее – интернационализация. Общепризнанный модный термин – i18n (Internationalisation). До сих пор моя специальная страница вызывалась только по адресу http://моявики/Служебная:Phones. А хотелось бы (так будет наиболее верно), чтобы расширение показывало страницу по адресу http://моявики/Служебная:Телефоны. Для этого придется постигнуть дзэн i18n. Поехали.
i18n
Как гласит документация, все сообщения, отображаемые пользователю, должны исходить из сообщений в файлах i18n, а не из жестко закодированного текста. Это означает, что в тексте вместо сообщений вы используете идентификаторы, согласно которым в специальном файле выбирается вариант перевода. Идентификаторы должны состоять только из маленьких латинских букв, цифр, подчеркивания и тире, начинаться идентификатор должен всегда с буквы.
Создадим такой файл для нашего расширения. Перво-наперво в папке расширения создаем папку i18n – это нормальная практика. Затем, внутри нее создаем файл ru.json и поместим туда такой текст в формате json:
{ "special-title": "Телефонный справочник организации", "special-text": "Здесь будет непосредственно текст справочника." }
Здесь объявлено две фразы на русском и их идентификаторы латинскими буквами. Теперь создадим там же файл en.json и поместим туда такой текст:
{ "special-title": "Organization phonebook", "special-text": "Place the text of the directory here..." }
В нем объявлены фразы с такими же идентификаторами, но на английском языке. Теперь в коде расширения нужно использовать только идентификаторы. Изменим содержимое метода execute нашего класса служебной страницы PhoneBookSpecialPage под использование идентификаторов:
<?php class PhoneBookSpecialPage extends SpecialPage { // Конструктор класса public function __construct() { // Вызываем конструктор базового класса и передаем ему идентификатор спецстраницы. parent::__construct( 'Phones' ); } // Показываем страницу пользователю public function execute( $sub ) { $out = $this->getOutput(); $out->setPageTitle( wfMessage('special-title') ->plain()); $out->addWikiText( $this->msg ('special-text') ); $out->addWikimsg( 'special-text' ); } } ?>
Поясняю что тут происходит. $out->setPageTitle( wfMessage(‘special-title’) ); – здесь устанавливается заголовок страницы. Но вместо текста, методу $out->setPageTitle передается конструкция wfMessage(‘special-title’)->plain(). wfMessage – это глобальная функция, которая располагается в файле GlobalFunctions.php MediaWiki. Это функция для получения переведенных сообщений интерфейса. Она по идентификатору ищет переведенный текст в файлах json, расположенных в папке интернационализации, согласно текущего языка wiki. Если файл локализации для текущего языка не найден, то используется файл en.json. Если и его нет, то отображаются сами идентификаторы.
Далее: $out->addWikiText( $this->msg (‘special-text’) ); — здесь выводится некий текст в страницу. Однако для получения текста используется метод msg класса SpecialPage. По сути – этот метод есть обертка над глобальной функцией wfMessage, так что смотрим предыдущий абзац.
Третья строка — $out->addWikimsg( ‘special-text’ ); Здесь используется специальный метод addWikimsg класса OutputPage. По сути – аналог addWikiText( wfMessage( … )->plain() ).
Для того, чтобы эта магия заработала, необходимо указать движку wiki, в какой папке расширения искать языковые файлы. Для этого, как уже наверное стало ясно, необходимо допилить файл extension.json:
{ "name": "PhoneBook", "author": "StarXXX", "url": "https://hardisoft.ru/", "description": "Телефонный справочник организации", "version": "1.0", "license-name": "GPL-2.0+", "type": "other", "AutoloadClasses": { "PhoneBookSpecialPage": "src/SpecialPage.php" }, "SpecialPages": { "Phones": "PhoneBookSpecialPage" }, "MessagesDirs": { "PhoneBook": [ "i18n" ] }, "manifest_version": 1 }
Как видно, здесь добавился объект MessagesDirs, которому передается массив, названый по имени нашего расширения и содержащий названия папок локализации.
Поле MessagesDirs указывает MediaWiki, где искать файлы локализации. Они всегда должны быть в стандартном месте, в каталоге i18n. Внутри этого каталога находятся файлы локализации, по одному для каждого языка, а также специальный файл с именем qqq.JSON, который дает информацию о каждой строке сообщения в качестве руководства для переводчиков. Языковые файлы хранятся в формате “ХХХ.JSON”, где “XXX” — код языка. Например, запрос / i18n / en.json содержит английскую версию всех сообщений, используемых расширением.
Теперь wiki знает достаточно, чтобы применить на практике наши изменения. Заходим по адресу http://моявики/Служебная:Phones (да, пока еще Phones, латинскими буквами) и видим такую картину:
Сработало. Теперь, поиграемся: переключим в настройках wiki язык на английский ($wgLanguageCode=”en” в файле LocalSettings.php) и зайдем на страницу http://моявики/Special:Phones и посмотрим:
Снова переключим, но уже на немецкий ($wgLanguageCode=”de” в файле LocalSettings.php) и зайдем на страницу http://моявики/Spezial:Phones и посмотрим:
И видим снова английский. А потому что немецкого мы в папочку i18n не завезли.
Итак, интернационализация работает и более-менее ясна. Настало время, все-таки, приступить к заветной теме – локализации адреса нашей страницы.
Здравствуй, Служебная:Телефоны
Итак, будем локализовывать адрес служебной страницы. Тут ничего сложного нет. Прежде всего, идем опять в папку extensions/PhoneBook/i18n и создаем там файл aliases.php с таким содержанием:
<?php $specialPageAliases = []; // English $specialPageAliases['en'] = [ 'Phones' => [ 'Phones'], ]; // Русский $specialPageAliases['ru'] = [ 'Phones' => [ 'Телефоны'], ]; ?>
Этот файл создает алиасы (т.е. псевдонимы) для нашей служебной страницы. Один алиас для английского языка, второй для русского. Аналогично можно добавить еще алиасы на других языках.
Кроме того, необходимо добавить идентификатор Phones в языковые файлы сообщений, чтобы название страницы нормально отображалось в списке всех служебный страниц (Служебная:Спецстраницы):
{ "special-title": "Телефонный справочник организации", "special-text": "Здесь будет непосредственно текст справочника.", "phones": "Телефонный справочник" }
Этого почти достаточно. Осталось сообщить MediaWiki о наших изменениях. Для этого, как всегда, добавляем магии в файл extension.json в корне расширения:
{ "name": "PhoneBook", "author": "StarXXX", "url": "https://hardisoft.ru/", "description": "Телефонный справочник организации", "version": "1.0", "license-name": "GPL-2.0+", "type": "other", "AutoloadClasses": { "PhoneBookSpecialPage": "src/SpecialPage.php" }, "SpecialPages": { "Phones": "PhoneBookSpecialPage" }, "MessagesDirs": { "PhoneBook": [ "i18n" ] }, "ExtensionMessagesFiles": { "PhoneBookAlias": "i18n/aliases.php" }, "manifest_version": 1 }
Здесь добавился объект ExtensionMessagesFiles, который содержит указатель на файл алиасов PhoneBookAlias. Вот, собственно и все. Проверяем: набираем в адресной строке заветное http://моявики/Служебная:Телефоны и вуаля:
В заключении, зайдем на страничку http://моявики/Служебная:Телефоны и понаблюдаем вот такую красоту:
Все просто замечательно получилось. Теперь можно смело реализовать код получения справочника из базы данных и вывода его на специальной странице. К слову, нашей служебной странице еще есть куда развиваться – она может принимать параметры. Например, чтобы выводить не весь справочник целиком, а постранично, для вывода детальной информации, ну или для чего-либо еще. Но это уже другая история.
Список литературы
- Руководство:Разработка расширений
- Manual:Special pages
- Как стать MediaWiki хакером
- How to become a MediaWiki hacker/Extension Writing Tutorial
- OutputPage Class Reference
- SpecialPage Class Reference
- GlobalFunctions.php File Reference
- Manual:Messages API
- Extension:HalloWorld NewbieLessons1
- Category:Tutorials
- Category:MediaWiki development