Дебри веб-программирования или история о том, как мы наш сайт мультиязычным сделали

09 Мар 2018

Лонгрид

Дабы заявить о себе, как о конкурентоспособной единице, мы изучаем новые технологии и применяем их на практике. При разработке нашего сайта, было решено опробовать Jekyll.

Jekyll — это генератор статических сайтов, который поддерживает хостинг на Github Pages. Реализован на Ruby. Данный генератор имеет все условия для создания элементарной логики вывода информации на страницы, а также размещения этих страниц на сайте. Основная его задача — генерация статического блога.

Но мы пошли нестандартным путем и поставили перед собой следующий план действий: создать сайт команды с информацией о проектах, составе коллектива, раскрытие нашей политики относительно проектов и всё это на трёх языках (Мультиязычность).

Мультиязычность

Мультиязычность можно организовать достаточно просто, если размещать все файлы в подпапке с флагом языка (ru, en) www.site.ru/ru/страница. Но требовался другой подход, а именно, русский язык должен был быть основным, а en и de второстепенными. Вопрос был решен использованием переменной permalink. Jekyll рассматривает файлы как статические и динамические, статические файлы он просто переносит при генерации в те же директории, а в динамические подставляет данные средствами YAML и Liquid. Каждый динамический файл содержит в начале конструкцию:

---
#Тут переменные Yaml
---

Переменная permalink отвечает за расположение страницы после генерации. Что позволяет файлы с переводами на en и de вынести в поддиректории.

Следует заметить, что в каждый файл мы добавили переменную language, для указания языка. (см. примеры ниже)

Переключение языков осуществляется тоже средствами Jekyll. На кнопках ru/en/de он собирает ссылки ведущие на тот же файл нужного языка. Соответственно пользователя при переключении языка не выбрасывает обратно на главную страницу и ему не приходится искать то, что у него уже было открыто. Составление ссылок происходит так:

Для RU:

<a href ="{{ site.baseurl }}{{ page.handle }}">

Для EN:

<a href ="{{ site.baseurl }}/en{{ page.handle }}">

Аналогично для DE.

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

baseurl — переменная, хранящая в себе url до основной директории, в которой лежит сайт, устанавливается в файле _config.yml. В нашем случае не потребовалось ее использовать.

Но если бы мы делали отдельно блог на jekyll, то в эту переменную вписали бы что-то в духе /blog.

Удобство пользователей

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

{% if page.collection == 'cases' %}
#Проверка входит ли страница в коллекцию "проекты"
{% assign items = site.cases | where: "language", page.language %}
#Создаем массив со страницами только того языка, который у открытой страницы
{% endif %}
{% for item in items %}
#Циклом проходим по массиву со страницами
{% if item.title == page.title %}
#Если title совпадает, значит мы нашли проект который сейчас открыт
{% assign previous = forloop.index0 | minus: 1 %}
#Добавляем в переменную индекс предыдущей страницы
{% if previous >= 0 %}
#Проверяем чтобы индекс предыдущей страницы был не ниже нуля
<a href="{{ items[previous].url | prepend: site.baseurl }}">
{% endif %} 
#Составляем ссылку на предыдущий проект
#prepend перед items[previous].url добавляет baseurl сайта
#Аналогично делается для "следующего" проекта
{% assign next = forloop.index0 | plus: 1 %}
{% if next < forloop.length %} #Индекс должен быть меньше длины массива
<a href="{{ items[next].url | prepend: site.baseurl }}">
{% endif %}
{% endif %} #Конец блока проверки item.title == page.title
{% endfor %} #Конец блока цикла item in items

Переводы всех кнопок вынесены в директорию _data и разбиты по файлам для удобства. В файле выглядит так:

case_button_see:
  ru: Посмотреть
  en: Look
  de: Anblicken

Выводится:

<a>{{ site.data.translate.index_cases_button[page.language] }}</a>

Хлебные крошки

Еще мы решили оставить необходимость показывать пользователю его местоположение на сайте, а именно breadcrumbs (хлебные крошки).

Jekyll поддерживает коллекции, расположены в _collection, по умолчанию используется для posts (постов), мы же добавили еще одну коллекцию cases (проекты). Внутри каждой коллекции идет разбивка на языки. На странице вывода списка проектов или постов, выводятся только те, у которых язык соответствует выбранному.

Пример:

{% assign cases = site.cases | where: "language", page.language %}
{% for case in cases %}
{% include card_case.html %} # Вывод карточки проекта
{% endfor %}

Хлебные крошки для страниц вынесены в отдельный файл breadcrumbs.html (позволяет вставлять их в код страниц в любом месте) и реализованы так:

{% assign pages = site.pages | where: "language", page.language %}
{% for object in pages %}
{% if object.layout == 'index' %}
# Первым элементом выводится домашняя страница этого же языка
<a class="breadcrumb-item" href="{{ site.baseurl }}{{ object.url }}">{{ object.caption }}</a>
# Caption — переменная добавленная в файлы, содержит заголовок страницы на выбранном языке, т.к. title используется для meta тегов
{% endif %}
# Далее идет проверка принадлежит ли данная страница какой-нибудь коллекции
{% if object.layout == page.collection %}
{% if object.layout == page.collection %}
# layout — стандартная переменная, содержит указание какой шаблон использовать для данного файла, шаблоны лежат в _layouts.
# Стоит отметить что название шаблона вывода всех проектов, совпадает с названием коллекции в которой они хранятся
<a class="breadcrumb-item" href="{{ site.baseurl }}{{ object.url }}">{{ object.caption }}</a>
{% endif %}
{% endfor %} # Конец цикла object in pages
# Последним элементом выводится страница открытая в данный момент
<span class="breadcrumb-item active">{{ page.caption }}</span>

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

{% if page.language == 'ru' %}
<p><input type="checkbox" name="agree" checked="checked">
Я согласен с <a href="/assets/docs/policy-for-personal-data-processing.pdf">обработкой персональных данных</a>
</p>
{% endif %}

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

Еще одна интересная особенность работы с данными, это возможность добавлять свои данные из Jekyll в javascript.

В начале файла добавляем конструкцию

---
---

Файл после этого становится динамичным и Jekyll проверяет его на наличие Liquid вставок

Пример использования:

const error = {{ site.data.modal.error | jsonify }};
#
# site.data.modal.error — директория _data файл modal.yml массив error:
#
# error:
#   ru: Ошибка
#   en: Error
#

Он сохраняет его в переменную js, и остается только получить значение путем подставления индекса или ключа. Например, язык страницы:

const lang = document.querySelector('html').getAttribute('lang');
# <html lang="{{ page.language }}"> //так выглядит начало каждой страницы
document.innerHTML = error[lang];

Таким образом можно осуществлять переводы текстов выводящихся скриптами.

Jekyll хоть и достаточно прост, но это не исключает его уникальности. Если его стандартного функционала недостаточно, то можно установить готовый плагин или же написать его самому и включить в сборку. Он отлично подходит для небольших сайтов, без использования базы данных. Крайне удобен при небольшом количестве информации. Он станет отличным решением для создания личного блога или сайта-визитки. Из минусов отмечу, что при изменений каких либо файлов требуется пересборка всего сайта и перезалив на хостинг. Если используется хостинг с системой unix, то jekyll можно запускать прямо на хостинге. Он требует знаний продвинутого пользователя: подключение к хостингу по ftp, поиск и редактирование нужного файла, пересборка сайта. Как не прискорбно, чувствуется отсутствие административной панели. Но, если вы хоть немного разбираетесь в данной сфере, то вам не составит труда сделать это, взамен вы получите легкий сайт, быструю загрузку, поисковики будут вам рады, а вы рады новым клиентам.

Авторы статьи
Александр ВласовАлександр Власов