Localized Tag and Category Navigation in Jekyll
Why Localized Navigation Matters
When building a multilingual site, it’s common to translate content. But what about navigation structures like categories and tags? If users switch to a different language, the taxonomy must follow. Showing English tags on a Spanish page creates confusion and breaks consistency.
In this guide, we’ll show how to create a tag-category navigation structure in Jekyll that automatically adapts based on the current language context. The solution works without JavaScript, external plugins, or third-party CMS—just plain Liquid, YAML, and data-driven design.
Site Structure for Multilingual Content
We’ll assume you have a language-aware directory structure:
├── _config.yml
├── _data
│ └── navigation.yml
├── _resources
│ ├── en
│ │ └── optimizing-includes.md
│ ├── es
│ │ └── optimizacion-includes.md
Each document contains language-specific lang, category, and tags metadata.
---
title: Optimizing Includes
lang: en
category: performance
tags: [includes,html]
---
---
title: Optimizando Includes
lang: es
category: rendimiento
tags: [includes,html]
---
Step 1: Localize Tags and Categories in _data
We create a centralized translation map:
_data/navigation.yml
en:
categories:
performance: Performance
theming: Theming
tags:
includes: HTML Includes
html: HTML
es:
categories:
rendimiento: Rendimiento
tematica: Temática
tags:
includes: HTML Includes
html: HTML
Step 2: Filter by Language in Your Template
We assume a layout variable page.lang exists. This allows filtering:
{% raw %}
{% assign lang = page.lang %}
{% assign localized_data = site.data.navigation[lang] %}
{% assign lang_items = site.resources | where: "lang", lang %}
{% assign categories = lang_items | map: "category" | uniq | sort_natural %}
{% for cat in categories %}
{{ localized_data.categories[cat] }}
{% assign cat_items = lang_items | where: "category", cat %}
{% assign tags = cat_items | map: "tags" | join: "," | split: "," | uniq | sort_natural %}
{% for tag in tags %}
{{ localized_data.tags[tag] }}
{% for item in cat_items %}
{% if item.tags contains tag %}
- {{ item.title }}
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endraw %}
Step 3: Language Switching UI (Optional)
If your pages support language toggles, ensure URLs follow the structure:
/en/resources/optimizing-includes//es/resources/optimizacion-includes/
Add a toggle at the top:
Styling Suggestions
.lang-switch {
display: flex;
gap: 1em;
margin-bottom: 1.5em;
}
.lang-switch a {
text-decoration: none;
color: #007acc;
}
Key Advantages of This Approach
- Language-specific navigation
- No duplication of template code
- Translation is centralized in one data file
- Compatible with GitHub Pages, no plugin required
Common Pitfalls to Avoid
- Using translated slugs in URLs without fallback links
- Hardcoding translated titles in front matter
- Ignoring plural and singular forms in category mapping
Bonus: Fallback to Default Language
If a tag or category translation is missing, display the raw key:
{% raw %}
{{ localized_data.categories[cat] | default: cat }}
{% endraw %}
Testing Your Localized Navigation
- Ensure both
enandesresources exist with correct tags/categories - Verify the YAML in
navigation.ymlis free of indentation errors - Open
/en/tags/and/es/tags/pages and validate output
Conclusion
Multilingual sites need more than just translated posts—they need translated structure. With Liquid logic and a data-driven YAML strategy, Jekyll allows you to create fully localized tag and category navigation without heavy frameworks or backend systems.
In the next article, we’ll explore building a custom multilingual search interface that respects language context while using client-side JavaScript and Lunr.js.
