07.05.2024 10:08
Jekyll: a high-performance alternative
When building a website nowadays, you have a choice of many different approaches and frameworks. Most of them are bloated with JavaScript, and unnecessarily so. Very often, these frameworks create relatively high CPU loads on the server because they are written in, say, PHP and made to be true Swiss army knives — to have an editor for posts, to be multi-user capable, to be extensible through plugins, etc. Such frameworks always come with a database.
All these features are great, but not always truly needed. They get especially annoying, if you try running such a website on small hardware (e.g., on the level of an IoT device). This can result in strong performance drops because the big framework overwhelms the small hardware.
An alternative exists in the form of frameworks that generate static webpages (without a database) from markdown files: Jekyll, for example.
It is especially easy to build personal blogs with such tools! Are you the only user who is allowed to post and can live without an in-browser editor? In this case, you do not need a heavy database or miles of PHP code! Small, energy-saving servers will be all that you need with such static websites!
But what if you want a multilingual website? At least in Jekylls case, the main website lacks a tutorial to do so.
Multiple languages = multiple problems
A quick search on the internet will show you that many tutorials exist for just this thing. But you should be vary of following random tutorials on the internet. It may be that, at first, you succeed and get the desired result. However, authors of such tutorials may not have bothered to check if their way of doing things broke compatibility with some plugins (highly important elements of Jekyll!). So ultimately, you end up working for days on a website, only to run into a wall in the end. You might end up with a multilingual website that lacks the ability to paginate posts. This will force you to circumvent this, through some very ugly hacks. Good luck fixing everything when the next update comes.
General recomendations
If you want to build a website with Jekyll, do not reinvent the wheel! Which is really solid advice for any kind of software project. Here are my general recommendations in detail:
- Always look at the official resources first; don’t just trust your search engine.
- On GitHub, many themes for Jekyll exist. Look at those that have the most stars. Use them, or let them be your template when building your own.
- Attempt to not use Jekyll’s functionality out of context. For example, collections are not meant to organize multilingual content.
So, what are the official resources? Nr. 1: the main page of the project, Jekyll. In the docs section you can find a good first tutorial and explanation of all the necessary steps. If you want to try something not covered there, take a look at the ressources section. I especially recommend checking out Jekyll Plugins.
In this tutorial, I expect you to use the official resources. The Jekyll team has made good documentation, and it would be wrong to just copy it or ignore it all together. Use the above links.
Multilingual blog
So, how exactly do you build a multilingual blog with Jekyll? Here are the plugins that constitute the minimum amount of necessary features:
- “jekyll-paginate-v2”
- “jekyll-polyglot”
- “jekyll-sitemap”
- “jekyll-seo-tag”
You need to put them in your Gemfile:
gem "jekyll-feed", "~> 0.12"
gem "jekyll-paginate-v2"
gem "jekyll-polyglot"
gem "jekyll-sitemap"
gem "jekyll-seo-tag"
Jekyll-feed is a standard plugin, which is already there when you create a new Jekyll website.
On GitHub, you can find multiple plugins when searching for “jekyll-polyglot”. I am using untra/polyglot. It has multiple stars, looks active, and worked well for me.
If you go to the project page on GitHub, you can see all the themes using this plugin in the “Used By” section. Just take one of those ;-). You can also use them as a template for your own theme.
Data structure
The correct data structure is very important. Failure to plan your data structure correctly can lead to one of the following errors:
- The website looks fine after a
bundle exec jekyll serve
, but as soon as you go into production and try to copy the static files to a “normal” webserver (apache httpd, nginx, etc.), you get multiple broken links leading to 404 errors. - posts are not recognized as such or are shown in the wrong category.
The blog needs to be multilingual. We also want to have multiple categories, like a blog and portfolio, and possibly even a separate news feed for updates on the website.
- Every category needs its own subdirectory. These directories should be placed in the website root, e.g.:
my-website blog photos portfolio
Name your categories well; you will need to set them in each post in the front matter later, and they will be used to control pagination!
- Posts should be placed inside their respective category directory. Posts also have to be inside a directory named _posts in Jekyll. Here is how I’ve done it:
my-website blog _posts photos _posts portfolio _posts
- Since the website is multilingual, we need more subdirectories, one for each language:
my-website blog _posts de en uk photos _posts de en uk portfolio _posts de en uk
All pages and posts are generated from .md files. The path for the generated .html file can be controlled via the
permalink
attribute in the front matter of the page, as well as through thepermalink: ...
option in the_config.yml
.Each language needs a separate .md file, because variable use is impossible inside the front matter. Only cleartext is allowed. Using one .md file for multiple languages will result in the “title” attribute of the generated .html file to always be the same. Same goes for “description”, etc.
Part of my
_config.yml
(Polyglot configuration, add any desired languages here):- Let us create an
index.md
file (standard language for my website is German). Just put it in the root of your website. Here is the front matter:title: "Mehrsprachige Webseite!" lang: de permalink: / page_id: index link_title: "Start" description: "Ein Blog in mehreren Sprachen"
- The file needs to have a unique name; otherwise, it will replace the old one. Let’s make it
index.en.md
:title: "Multilang website!" lang: en permalink: / page_id: index link_title: "Home" description: "A blog with multiple languages"
And so on, for each required language.
- Let us create .md files for all categories now, these will show lists of posts for each category. I am starting with
blog.md
:title: Blog page_id: blog permalink: /blog categories: blog lang: de description: "Blog" pagination: enabled: true indexpage: blog category: blog
Now it gets more complicated. As before,
lang
shows the content language. This attribute is used by polyglot to generate correct links (following the pattern [lang]/[categories]/[permalink].html). The pagination config is necessary, to not show all posts ever created on the same page. It is important to define a name for the index page; otherwise the categories will overwrite each other, as soon as pagination starts working. To prevent posts from other categories from showing up, setcategory
accordingly. accordingly. Unfortunately,pagination
does not understand thelang
attribute. With configuration shown above, posts from all languages will show up. - In the next step, let us extend the front matter of blog.md, to only show posts in German:
title: Blog page_id: blog permalink: /blog categories: blog lang: de description: "Blog" pagination: enabled: true tag: de indexpage: blog category: blog
It goes against the rule of not using functionalities out of context. I could not find a better way, but tagging each post with it’s language and filtering for this tag here. At least it is not completely out of place to tag a post with its content language. Now, if you open the blog page, it will only show posts that:
- are in German (that have
tag
attribute set tode
, that is) that belong to the blog category (that have
categories
set toblog
, that is)- You have probably already picked a theme for your site or are building your own. Regardless, you will need to add a post listing to one of the layout files. Assume there is a
default.html
, which holds the layout for all your pages. In this case, add at least the following code in the part, where you want to display the post list:
You can find out more about configuring the paginate-v2 plugin here
- Now you only have to create .md files for all the other pages, one for each language, just as described above!
Enjoy your multilingual Jekyll website!