Before reading: This article deals with categories page generation by language using Jekyll and the problems I personally have to implement it. This article don’t list the limits of Jekyll in a general point of view.

As you maybe noticed, I have been using Jekyll to build this website from the beginning. I’m a Ruby developer and that’s the main reason why I chose Jekyll. Middleman is also another good static website generator in Ruby but Jekyll was just more popular at this time.

I started small with a single page describing myself, added new pages progressively and finally decided to create a blog to share some good stuff with you :stuck_out_tongue_winking_eye:

After the blog launch, I added few posts in French, English and Japanese.
Until then, everything was great as you can see:

Frontpage Blog section of fcbrossard.net

Blog posts page of fcbrossard.net

Localization (i18n)

However for better clarity I decided to split posts by language instead of mixing them all together.

Front page

My posts front matter are following this pattern:

---
title:  "Limits of Jekyll"
category: "Web Development"
image:
description: "Let me explain you the struggles I have been facing using Jekyll recently"
lang: en
---

lang can have 3 different values: en, fr or ja (I know it doesn’t follow the ISO standard, forgive me).
To view a list of separate posts by language I just did:


<!-- French -->
{% assign posts_fr = (site.posts | where: "lang" , "fr") %}
{% for post in posts_fr limit:5 %}
  ...
{% endfor %}

<!-- English -->
{% assign posts_en = (site.posts | where: "lang" , "en") %}
{% for post in posts_en limit:5 %}
  ...
{% endfor %}

<!-- Japanese -->
{% assign posts_ja = (site.posts | where: "lang" , "ja") %}
{% for post in posts_ja limit:5 %}
  ...
{% endfor %}

And here is the result after the changes:

Frontpage Blog section by language of fcbrossard.net

Languages pages (EN, FR, JA)

After that we have to create the blog pages for each language using the page collection provided by default in Jekyll. Here is the file structure I implemented:

blog/
  index.html
  - en/
    index.html
  - fr/
    index.html
  - ja/
    index.html

The first index.html file include all the posts (in all languages) similar to the second screenshot of this article.

Basically we only need to loop over site.posts:


{% for post in site.posts %}
  ...
{% endfor%}

For the other index.html we repeat what we have done in the Front Page section without forgetting to remove the limit: 5.

— Easy right?

Languages post URLs

All the posts are listed correctly now, however my posts URLs are still the same.
A typical blog post URL looks like this:

https://fcbrossard.net/blog/post_title

And changing the URLs to this would be better:

https://fcbrossard.net/blog/en/post_title

https://fcbrossard.net/blog/fr/post_title

https://fcbrossard.net/blog/ja/post_title

To achieve that, I created sub-folders for each language inside my _posts collection:

_posts/
  - en/
    2018-04-25-post1.md
  - fr/
    2018-04-25-post2.md
  - ja/
    2018-04-25-post3.md

And added the following scopes in my _config.yml:

defaults:
  # Blog Posts - EN
  - scope:
    path: _posts/en
    type: posts
    values:
    lang: en
    permalink: /blog/en/:title

  # Blog Posts - FR
  - scope:
    path: _posts/fr
    type: posts
    values:
    lang: fr
    permalink: /blog/fr/:title

  # Blog Posts - JA
  - scope:
    path: _posts/ja
    type: posts
    values:
    lang: ja
    permalink: /blog/ja/:title

Language URLs might be not enabled yet on fcbrossard.net at the time you are reading this post.

Categories by language

— It’s the moment where the things become tricky.

So now we have some pretty URLs for each language, why not adding categories to those URLs ?

Reminder: we have a category attribute in our posts front matter

Back to our scope let’s try to change the permalinks to add the category to our URLs:

defaults:
  # Blog Posts - EN
  - scope:
    path: _posts/en
    type: posts
    values:
    lang: en
    permalink: /blog/en/:categories/:title

  # Blog Posts - FR
  - scope:
    path: _posts/fr
    type: posts
    values:
    lang: fr
    permalink: /blog/fr/:categories/:title

  # Blog Posts - JA
  - scope:
    path: _posts/ja
    type: posts
    values:
    lang: ja
    permalink: /blog/ja/:categories/:title

— And voilà! :tada:

It works but… How can we get the pages for our categories (by language)?

For example:

https://fcbrossard.net/blog/en/category1/

All English posts having the category1

or

https://fcbrossard.net/blog/fr/category2/

All French posts having the category2

When we just have few categories it’s fine, we create the folders inside the blog directory we created earlier. But imagine if we have a huge amount of categories. Creating a folder manually for each category will be time consuming and unmanageable at the end.

You can’t imagine how much time I spent to wrap my head around this without even finding a sustainable solution.

I found an amazing gem called jekyll-archives which create each category page and list all the posts. Unfortunately I don’t think it’s possible do the same thing with posts “sub-directories” (languages in our case).

The only solution I can think of is to create my own Jekyll Generator but I didn’t have enough time for that yet.

Pagination

Another problem I have found is related to pagination. It seems Jekyll paginator instance only accepts to loop over paginator.posts. I assume we can’t use our posts_en posts_fr and posts_ja for the pagination. The pagination was not generated when I tried.

I’ve also experimented with:

  • jekyll-paginatev2
  • octopress-paginate

If you have any idea how I could fix those issues, it would be really appreciated :smile:

It’s not an happy ending for the moment but I keep hope. That’s how I discovered what I call the limits of Jekyll. To sum up, Jekyll is the perfect choice to build and run a simple blog or static website but for sure you’ll face to some problems if you try to get beyond the philosophy or the principles of it.