Our expirience

Dark forest of web programming, or how we made multilingual website

03/09/18 / Longread

In order to declare ourselves as a competitive unit, we study new technologies and apply them in practice. Developing our site, it was decided to try out Jekyll.

Jekyll is a static site generator that supports hosting on Github Pages. Implemented in Ruby.This generator has all the conditions for creating a basic logic for displaying information on the pages, as well as placing these pages on the site. Its main task is to generate a static blog. But we went in a non-standard way and set ourselves the following plan of action: to create a team site with information about projects, the composition of the team, the disclosure of our policy regarding projects, and all these in three languages (Multilingual).


Multilanguage can be organized quite simply if you place all the files in a subfolder with the language flag (ru, en) www.site.ru/ru/page. But another approach was required, namely, the Russian language was supposed to be the main one, and en and de were secondary. The question was solved using the variable permalink. Jekyll treats files as static and dynamic, static files it simply migrates during generating in the same directory, and dynamically substitutes the data with YAML and Liquid. Each dynamic file contains at the beginning a construction:

#Here the variables Yaml

The permalink variable is responsible for the layout of the page after generation. That allows files with translations to en and de to be rendered in a subdirectory. It should be noted that in each file we added a variable language, to indicate the language. (see examples below)

Switching languages is also done using Jekyll. On the buttons ru/en/de it collects links leading to the same file of the desired language. Accordingly, when switching the language, the user does not throw back to the main page and he does not have to search for what he already had. Linking is as follows:

For RU:

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

For EN:

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

And the same way for DE.

handle - a variable added to each file, stores its path to the file without specifying a language.

baseurl - the variable that holds the url to the main directory in which the site is located and installed in the _config.yml file. In our case, it was not necessary to use it.

But if we were doing a separate blog on jekyll, then in this variable would be written something like /blog.

Users convenience

In the course of work it became clear that to switch between projects the user would have to go to the list page every time and look for the next or previous project. Judge for yourself - not very convenient. We decided to add buttons so that the user could flip through the projects one by one without being distracted. And then the question arose, how to collect a link to the next and previous project using only Jekyll. This tool for posts has such function by default, but it does not work for collections. The solution turned out to be simple, although it requires more processing time:

{% if page.collection == 'cases' %}
# Check whether the page enters the "Projects" collection
{% assign items = site.cases | where: "language", page.language %}
# Create an array with pages only of the language that is on the open page
{% endif %}
{% for item in items %}
# Cycle through an array with pages
{% if item.title == page.title %}
# If the title matches, then we found the project that is now open
{% assign previous = forloop.index0 | minus: 1 %}
# Add the index of the previous page to the variable
{% if previous >= 0 %}
# Check that the index of the previous page was not below zero
<a href="{{ items[previous].url | prepend: site.baseurl }}">
{% endif %} 
# Link to the previous project
# prepend before items[previous].url adding baseurl of website
# Similarly done for the "next" project
{% assign next = forloop.index0 | plus: 1 %}
{% if next < forloop.length %} # The index must be less than the length of the array
<a href="{{ items[next].url | prepend: site.baseurl }}">
{% endif %}
{% endif %} # End of the verification block item.title == page.title
{% endfor %} # End of cycle block item in items

Translations of all buttons are made in the directory _data and are broken down by files for convenience. The file looks like this:

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


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


We also decided to leave the need to show the user his location on the site, namely breadcrumbs. Jekyll supports collections located in _collection, by default it is used for posts, we added another collection cases (projects). Inside each collection there is a breakdown into languages. On the output page of the list of projects or posts, only those with the same language as the selected one are displayed.

For example:

{% assign cases = site.cases | where: "language", page.language %}
{% for case in cases %}
{% include card_case.html %} # Output of the project card
{% endfor %}

Bread crumbs for the pages are placed in a separate file breadcrumbs.html (allows them to be inserted into the page code anywhere) and implemented as follows:

{% assign pages = site.pages | where: "language", page.language %}
{% for object in pages %}
{% if object.layout == 'index' %}
# The first element displays the home page of the same language
<a class="breadcrug-margin__bottom-item" href="{{ site.baseurl }}{{ object.url }}">{{ object.caption }}</a>
# Caption - a variable added to files, contains the title of the page in the selected language, because title is used for meta tags
{% endif %}
# Next is to check whether this page belongs to a collection
{% if object.layout == page.collection %}
{% if object.layout == page.collection %}
# layout - a standard variable, contains an indication of which template to use for this file, the templates lie in _layouts.
# It is worth noting that the name of the output template for all projects coincides with the name of the collection in which they are stored
<a class="breadcrug-margin__bottom-item" href="{{ site.baseurl }}{{ object.url }}">{{ object.caption }}</a>
{% endif %}
{% endfor %} # End of cycle object in pages
# The last element displays the currently open page
<span class="breadcrug-margin__bottom-item active">{{ page.caption }}</span>

Sometimes there may be a need to output a whole piece of html code under certain conditions, in our case only for Russian segment pages, this modified Jekyll also can do. For example:

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

This code will output confirmation for processing of personal data only on pages with Russian language.

Another interesting feature of working with data is the ability to add your data from Jekyll to javascript.

At the beginning of the file, we add the construction


The file after that becomes dynamic and Jekyll checks it for the presence of Liquid insertions

Example of use:

const error = {{ site.data.modal.error | jsonify }};
# site.data.modal.error - folder _data file modal.yml array error:
# error:
#   ru: Ошибка
#   en: Error

It saves it in the js variable, and it only remains to get the value by substituting an index or a key. For example, the language of the page:

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

In this way, you can translate texts that are output by scripts. Jekyll though and is simple enough, but it does not exclude its uniqueness. If its standard functionality is not enough, you can install the finished plug-in or write it yourself and include it in the assembling. It is great for small sites, without using a database, extremely convenient with a small amount of information. It will be an excellent solution for creating a personal blog or business card site. Among the minuses, I note that when you change any files, you need to re-assemble the entire site and reload it for hosting. If you use a hosting with the unix system, then you can run jekyll directly on the hosting. It requires knowledge of an advanced user: connection to hosting by ftp, search and editing of the desired file, re-assembly of the site. Unfortunately there is a sharp lack of administrative panel. But, if you are at least a little knowledgeable in this area, then you will not be difficult to do this, instead you will get an easy site, a quick download, search engines will be glad to you, and you are happy with new customers.