Добавляем мультиязычность в Wordpress #1: WPGlobus
Бесплатный плагин WPGlobus, и пара хаков для его приручения.
В библиотеке плагинов имеется огромное количество решений, однако я предлагаю остановиться на WPGlobus, поскольку он позволит Вам добавить поддержку нескольких языков на сайт бесплатно (в отличие от того же WPML), а также способен адекватно работать с кастомными типами постов (в отличие от Bogo).
Установка плагина стандартная – ищем в маркете WPGlobus, устанавливаем и активируем.
Если ваша тема использует theme_options, для которых тоже требуется возможность перевода — я настоятельно рекомендую установить плагин WPGlobus Translate Options.
Настройка мультиязычности с WPGlobus довольно тривиальна — в интерфейсе настройки плагина нужно добавить требуемые языки:
На заметку
Обратите внимание, WPGlobus устанавливает первый язык из списка в качестве основного для сайта, для всех остальных будет действовать добавление кода языка в URL (напр. /en/URL).
Настройки переключателей языка устанавливаются здесь же:
Способ показа переключателей — это то, как будут отображаться кнопки для переключения языка.
Навигационное меню — меню в которое будут добавлены переключатели языка.
В разделе “Типы записей” можно отключить активацию системы переводов для определённых типов материалов — это очень удобно, если вы используете, например, Pods Templates из плагина Pods —WPGlobus может испортить код шаблона в интерфейсе PodsTemplate своей обработкой.
Перевод theme options
Если вы используете функционал theme options в wordpress customizer, то можете столкнуться с проблемой некорректной обработки значений.
Казалось бы, задали мы под каждый язык свой текст для опции:
И казалось бы, раз уж в админке работает, то и на сайте должно работать. Но в результате Вы видите такую картину:
Почему не работает??!!
Это связано с механикой работы WPGlobus — авторы плагина сделали ставку на максимальное быстродействие, поэтому при выводе данных из таблицы wp_options, по умолчанию, плагином обрабатываются только поля blogname и blogdescription.
Задача ясна — нужно как–то заставить WPGlobus обрабатывать Ваши опции, но как это сделать?
Для того чтобы обойти это ограничение, существует бесплатное дополнение для WPGlobus — WPGlobus Translate Options — оно позволяет указать WPGlobus, какие ещё опции Вы хотели бы переводить в автоматическом режиме.
Страница настроек доступна на вкладке WPGlobus → Translation options. Интерфейс этого плагина достаточно примитивный — это просто список доступных опций:
В поле Options to translate нужно вписать список требуемых опций, который будут переводиться.
Например, опции темы как правило доступны как theme_mods_<THEME_NAME>. Поэтому находим в списке ссылку с таким названием и кликаем по ней.
Вас перекинет на список всех опций, зарегистрированных под этим именем. Теперь нужно скопировать имя theme_mods_<THEME_NAME> (или просто кликнуть по одноимённой ссылке) в текстовое поле справа и сохранить изменения:
После этой простой манипуляции, получаем желаемое поведение:
Хак №1: Мультиязычный Contact Form 7
К сожалению, сам по себе Contact Form 7 не поддерживается плагином WPGlobus, однако можно продублировать формы под все требуемые языки и выводить разные шорткоды в разных вариантах переводов.
Такие манипуляции можно проделать как для содержимого постов и страниц, так и для текстовых виджетов. Соответственно, в зависимости от языка будет выводиться нужная форма.
Хак №2: Вывод переключателей языка в одну строку
К сожалению, возможность вывода переключателей в виде одной строки недоступно в бесплатной версии плагина. Однако есть возможность изменить это поведение не покупая дополнительные модули.
Далее идёт описание способа, основанного на использовании WP_Nav_Walker (почитать об этом можно здесь). Если Вам не нужна специфическая обработка вёрстки меню, то лучше воспользуйтесь новым, более простым способом.
Для реализации этой возможности нужно реализовать свой экземпляр WP_Nav_Walker и изменить обработку вывода в методе start_el. Язык ссылки доступен в свойстве language объекта $item (второй аргумент метода start_el).
Этот способ позволит вывести элементы в любом требуемом вам виде, однако, поскольку плагин WPGlobus рассчитан на работу с выпадающим списком, внутри производится сортировка ссылок, при которой активный язык становится первым в списке.
Чтобы избежать этого поведения, можно перегрузить метод walk, в котором выполнить собственную сортировку ссылок переключателя:
<?php
class My_Custom_Walker extends Walker_Nav_Menu {
/*
Сортировка флагов
*/
private static function sortFlags($a, $b) {
return strcmp($a->language, $b->language);
}
function walk($menu, $depth) {
usort($menu, array('My_Custom_Walker', 'sortFlags'));
return parent::walk($menu, -1);
}
/* ... */
}
При использовании этого кода все ссылки-флаги переключателей языка будут отсортированы по алфавиту. Однако, в этом подходе есть минус — Вам придётся задать для переключателей меню отдельное меню и выводить его отдельно от основного меню, поскольку передавая значение -1 в метод walk, мы отключаем обработку иерархической вложенности всех элементов меню, ну и сортировка выполняется по полю language, которое, если я не ошибаюсь, присутствует не только в элементах флагов.
UPDATE:
Благодаря пользователю 777, обнаружил ещё один, более простой, способ сделать это. Для этого способа не потребуются специфические навыки (как в случае с Walker) и он прекрасно работает для переключателей используемых вместе с обычным меню (т.е. без создания дополнительного меню для переключателей).
Этот код достаточно положить в functions.php, и все флажки утратят вложенность (сортировка добавлена, чтобы избежать изменение порядка флажков):
add_filter( 'wpglobus_menu_items', array('WPGlobusFlatFlagsMenu', 'wpglobusMenuItemsFilter') );
class WPGlobusFlatFlagsMenu {
private static function sortFlags ($a, $b) {
// поменяйте $a и $b местами, чтобы сменить направление сортировки
return strcmp($a->language, $b->language);
}
public static function wpglobusMenuItemsFilter ($items) {
usort($items, array(self, 'sortFlags'));
foreach ($items as $item) {
unset($item->menu_item_parent);
}
return $items;
}
}
Хак №3: перевод кастомных полей Pods Framework
В WPGlobus не встроена поддержка Pods Framework, поэтому для перевода дополнительных полей, которые Вы создаёте с помощью Pods, не получится использовать «из–коробки». Однако у меня есть решение этой проблемы.
Суть в том, что WPGlobus выполняет перевод в wordpress фильтре the_title, поэтому для использования этого функционала нужно запилить такую функцию (в functions.php):
<?php
// выполняет перевод текста с помощью WPGlobus
function theme_wpglobus_translate($text) {
return apply_filters('the_title', $text);
}
Использовать apply_filters в pods шаблоне напрямую не получится (да и не нужно) — в Pods шаблонах поддерживаются только функции с сигнатурами вида – function_name($arg) и используются в качестве фильтров контента:
[before]
<div class="row">
[/before]
<div class="col-md-3 col-sm-6 col-sm-offset-0 col-xs-10 col-xs-offset-1">
<!-- Для поля post_title автоматически выполняется apply_filters('the_title') -->
<h4 class="b-page-contacts__title">{@post_title}</h4>
<div class="b-page-contacts__line">
<div class="b-page-contacts__icon">
<i class="fa fa-phone"></i>
</div>
<div class="b-page-contacts__column">
<span>{@phone,theme_wpglobus_translate}</span>
</div>
</div>
</div>
[after]
</div>
[/after]
UPDATE:
Как верно отметили в комментарии, если Вы не используете PodsTemplates, а перегружаете шаблоны силами Wordpress (taxonomy-[название таксономии].php) — используйте функцию theme_wpglobus_translate напрямую:
<?php
/*
я всё же рекомендую использовать подход со своей функцией (theme_wpglobus_translate),
поскольку если просто поставить здесь apply_filters('the_title', $post->post_title)
то ваш преемник может не сообразить с ходу - зачем вы используете здесь фильтр.
*/
?>
<h1><?php echo theme_wpglobus_translate($post->post_title); ?></h1>
Теперь можно использовать специальные коды WPGlobus для ввода контента — {:ru}Русский{:}{:en}Englist{:}.
Как не сложно догадаться, этот метод не очень удобный, однако, можно воспользоваться Javascript API WPGlobus и прикрутить к простым текстовым полям виджет для переводов:
Реализация этой затеи довольно простая, нужно создать JS файл со следующим содержимым:
/* wpglobus_pods_custom_fields.js */
;(function($) {
$(function() {
/*
Adding support for PODS Custom fields (Input text)
*/
$('#pods-meta-more-fields').find('input.pods-form-ui-field-type-text[type=text]').each(function(i, el) {
WPGlobusDialogApp.addElement({
id: el.id,
dialogTitle: 'Edit POD Custom field',
sbTitle : 'Click for edit'
});
});
});
})(jQuery);
И добавлить этот скрипт в поток подключения javascript после скрипта wpglobus-admin:
<?php
function floris_admin_init() {
wp_enqueue_script('wpglobus_pods_custom_fields', get_template_directory_uri() . '/js/wpglobus_pods_custom_fields.js', array( 'jquery', 'wpglobus-admin' ), '1', true );
}
add_action('admin_init', 'floris_admin_init');
В будущем, возможно, я начну разработку плагина для добавления совместимости между WPGlobus и PodsFramework, но пока что, к сожалению, времени на такие затеи совершенно не хватает. Если вдруг кто вдохновится статьёй и начнёт разработку такого плагина — присылайте ссылку, буду рад поучаствовать в разработке!