multilingual related posts in jekyll using data and language detection
Why Multilingual Related Posts Matter
For multilingual Jekyll sites, simply reusing the same related post data across all languages leads to a poor UX. Users might click related links that aren’t in their preferred language. This breaks immersion, especially in knowledge bases or documentation.
✅ Goal:
- Only show related posts that match the current post's language
- Support shared related post groups across languages
- Optional: Fallback if translation is missing
Step 1: Add Language to Post Front Matter
Add lang to each post:
---
title: "Optimisasi Template di Jekyll"
lang: id
related_group: template-performance
---
And its English version:
---
title: "Template Optimization in Jekyll"
lang: en
related_group: template-performance
---
Step 2: Update YAML Related Group File
Reuse same group keys for all languages, keeping just URLs:
template-performance:
title:
en: "Template Optimization Series"
id: "Seri Optimisasi Template"
posts:
- /jekyll/template-basics/
- /jekyll/layout-optimizations/
- /jekyll/template-performance/
- /jekyll/minification/
Step 3: Multilingual Logic in Layout or Include
Use the following Liquid logic to render related posts that match page.lang:
{% assign group_key = page.related_group %}
{% assign group_data = site.data.related[group_key] %}
{% if group_data %}
{% assign lang = page.lang | default: "en" %}
<div class="related-posts">
<h3>{{ group_data.title[lang] | default: group_data.title["en"] }}</h3>
<ul>
{% for url in group_data.posts %}
{% assign post = site.posts | where: "url", url | where: "lang", lang | first %}
{% if post and post.url != page.url %}
<li><a href="{{ post.url }}">{{ post.title }}</a></li>
{% endif %}
{% endfor %}
</ul>
</div>
{% endif %}
This code:
- Loads the group from
_data/related.yml - Uses the correct group title based on the page language
- Only displays related posts that match the current language
Optional: Language Fallback for Missing Translations
If a translation is missing, you can show a fallback post (e.g., English):
{% assign fallback_post = site.posts | where: "url", url | where: "lang", "en" | first %}
{% assign post = site.posts | where: "url", url | where: "lang", lang | first | default: fallback_post %}
Step 4: Add Translated Titles to Related YAML
To make it fully multilingual, include title translations in your YAML:
jekyll-basics:
title:
en: "Jekyll Basics Series"
id: "Seri Dasar Jekyll"
posts:
- /jekyll/setup/
- /jekyll/structure/
- /jekyll/markdown-guide/
Use {{ group_data.title[page.lang] }} to render it dynamically.
Optional: Language-Based Navigation Menus
You can even use this data structure to build multilingual section menus per language:
<nav class="group-nav">
<h4>{{ group_data.title[lang] }}</h4>
<ul>
{% for url in group_data.posts %}
{% assign post = site.posts | where: "url", url | where: "lang", lang | first %}
{% if post %}
<li{% if post.url == page.url %} class="active"{% endif %}>
<a href="{{ post.url }}">{{ post.title }}</a>
</li>
{% endif %}
{% endfor %}
</ul>
</nav>
Recap: Why This System Works
- ๐ Keeps logic clean — data-driven instead of per-post
- ๐ Language-aware related post experience
- ๐ก Can be expanded into navigation, sidebars, or custom blocks
What’s Next?
We’ve now built:
- Basic related post system using front matter
- Advanced system using
_data/related.yml - Multilingual support based on
page.lang
In the next part, we'll explore **automatically generating related post suggestions** using Liquid filters, word overlaps, or tag intersections—ideal when you don’t want to curate related groups manually.