Multilingual website with Jekyll

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:

  1. Always look at the official resources first; don’t just trust your search engine.
  2. 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.
  3. 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 the permalink: ... 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): Polyglot Konfiguration Permalink Konfiguration

  • 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, set category accordingly. accordingly. Unfortunately, pagination does not understand the lang 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 to de, that is)
  • that belong to the blog category (that have categories set to blog, 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:

Paginate-Beispiel

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!