Multilingual Jekyll


4 min read

Earlier this week we outlined how important it is to provide access for all users, regardless of ability, to the new The website will also feature Spanish translations of all its content, another important step toward achieving full accessibility.

Usually, implementing translated content into a workflow can be a challenging task. Questions arise about administration and management of the content, URL structure, site UI and end user experience. In our latest code sprint on developing the new, we’re tackling this by focusing on creating a sustainable architecture for supporting translation and the workflow for publishing multiple translations.

How to set up a multi-lingual Jekyll site

Jekyll gives us a lot of control over our site’s structure, so we’re imposing a structure that facilitates managing multilingual content. We developed a sustainable architecture by focusing on three key components:

  1. adding and maintaining content,
  2. translating site elements,
  3. and seamless use for the end user.

Implementing multilingual support with Jekyll can be achieved by adding rules to govern how the site supports translation. Leveraging the YAML front matter for controlling page generation, we can create rules for metadata, url structure, posts with categories, custom paths, and site element translations.


Every page is defined by a language key and Jekyll builds the site based on these keys and the structure. Metadata fields are used to define what layout and other information are used to generate a page. All posts must declare a layout and lang field:

layout: default
lang: en

URL Structure

Translated posts need to have an additional categories field that will be used in the URL. The url structure of will look like /:categories/:filename-title. For translated content, the url will be /es/title-of-the-page.

layout: default
lang: es
    - es

To keep the relationship between translations, both posts must use the same filename. Translated posts are nested in a directory with the language code as a subdirectory. Note, we do not translate file names, and they are never directly seen by end users of the website. This is so that they can be matched for editing in Prose.


Additional categories can be appended, but using the rule of declaring es first, followed by the necessary categories matching both es and en translations:

layout: default
lang: es
    - es
    - blog

Site Elements

Site elements like navigation items or UI controls need a translation as well and can be controlled by posts with global metadata. We tag this post with a translations tag. For any templates that have elements that need translation, we can assign load the global translation data by assigning site translations variable at the top of the page:

`{% raw  %}{% assign t = site.tags.translations[0] %}{% endraw %}`

A title element would then look like:

`<h1>{% raw  %}{{t.[page.lang].landing-page.title}}{% endraw %}</h1>`

Since each page has a page.lang value, we can find the value we’re looking for in the appropriate language following this structure.

The global translations post includes translated version of the title, like this:

        title: 'Some Title'
        title: 'Título Ejemplo'`

By leveraging these rules and managing translated content in posts and site wide translation files, we keep authoring content simple. Prose, can now be used to create and manage posts and content. The next version of Prose will also have new features to make this process even more easy for content authors. This workflow puts an emphasis on writing content and providing human-translated content across the site.

Next up

We’re getting ready to release a Google Analytics plugin for Jekyll. It’s a drop-in plugin that will allow you to sort the content on your Jekyll site by any Google Analytics data you specify. We’re using it on to sort content by popularity, so we can surface interesting and useful posts. We’re also gearing up for a major new version of Prose, as Tristen outlined a few weeks ago.

What we're doing.