Добавляем мультиязычность в 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, но пока что, к сожалению, времени на такие затеи совершенно не хватает. Если вдруг кто вдохновится статьёй и начнёт разработку такого плагина — присылайте ссылку, буду рад поучаствовать в разработке!