Explore More Passive Income Ideas

Language-Aware Navigation Menus in Jekyll

Why Multilingual Navigation Matters When building a multilingual Jekyll site, maintaining separate navigation menus for each language manually is inefficient and error-prone. To create a better user experience and simplify content management, we can use data-driven navigation with language-specific YAML files and modular Liquid includes. Step 1: Structure Your Language Folders For each supported language, create a corresponding folder in the root of your site (e.g. /en , /fr , /de ). Within each folder, include an index.md file and other localized content. This folder structure allows you to route users correctly and serve language-appropriate navigation. Step 2: Create YAML Data Files for Menus Inside your _data directory, create a subfolder called menus and place one YAML file for each language, such as: _data/menus/en.yml _data/menus/fr.yml _data/menus/de.yml Sample en.yml - title: "Home" url: "/en/" - title: "Blog" ...

Client Filtering for Multilingual Jekyll Content

Why Client-Side Filtering is Essential for UX

Static sites often lack the dynamic interactivity users expect, especially when handling complex documentation or blog archives. Adding filtering capabilities on the client side provides instant feedback, speeds up discovery, and gives your multilingual Jekyll site a modern, app-like experience.

This guide shows how to implement live filtering for multilingual content using HTML, JavaScript, and Jekyll’s built-in data structure.

Step 1: Prepare a Structured Content Block

Create a content section with clear language and category tags. Here's a simplified format in your HTML:


<div id="filter-controls">
  <select id="language-filter">
    <option value="all">All Languages</option>
    <option value="en">English</option>
    <option value="es">Spanish</option>
    <option value="fr">French</option>
  </select>
  <select id="category-filter">
    <option value="all">All Categories</option>
    <option value="docs">Docs</option>
    <option value="guides">Guides</option>
    <option value="reference">Reference</option>
  </select>
</div>

<ul id="filtered-list">
  <li data-lang="en" data-cat="docs">Getting Started (EN)</li>
  <li data-lang="es" data-cat="guides">Instalación rápida (ES)</li>
  <li data-lang="fr" data-cat="reference">Référence API (FR)</li>
</ul>

Step 2: JavaScript Filter Logic

Add this script to dynamically show/hide items based on the selected filters:

<script>
document.addEventListener("DOMContentLoaded", () => {
  const langFilter = document.getElementById("language-filter");
  const catFilter = document.getElementById("category-filter");
  const items = document.querySelectorAll("#filtered-list li");

  function applyFilters() {
    const selectedLang = langFilter.value;
    const selectedCat = catFilter.value;

    items.forEach(item => {
      const langMatch = selectedLang === "all" || item.dataset.lang === selectedLang;
      const catMatch = selectedCat === "all" || item.dataset.cat === selectedCat;

      item.style.display = langMatch && catMatch ? "" : "none";
    });
  }

  langFilter.addEventListener("change", applyFilters);
  catFilter.addEventListener("change", applyFilters);

  applyFilters(); // initialize on load
});
</script>

Step 3: Rendering Multilingual Content with Jekyll

Use Liquid to output your posts or docs with appropriate metadata for filtering:

{% raw %}
{% for doc in site.docs %}
  <li data-lang="{{ doc.lang }}" data-cat="{{ doc.category }}">
    <a href="{{ doc.url }}">{{ doc.title }} ({{ doc.lang | upcase }})</a>
  </li>
{% endfor %}
{% endraw %}

Ensure each document has front matter like this:


lang: es
category: guides

Step 4: Style the Filters and Results

Apply a bit of CSS for layout and readability:


#filter-controls {
  display: flex;
  gap: 1rem;
  margin-bottom: 1rem;
}

#filtered-list li {
  padding: 0.5rem 0;
  border-bottom: 1px solid #ccc;
}

Step 5: Extend for Tags or Search

  • Add a third dropdown for tags
  • Include a search input for live filtering using includes() on text content
  • Support combination filtering (language + category + keyword)

For example, add:


const searchInput = document.getElementById("keyword-filter");

searchInput.addEventListener("input", applyFilters);

function applyFilters() {
  // ...previous code...
  const keyword = searchInput.value.toLowerCase();

  items.forEach(item => {
    const textMatch = item.textContent.toLowerCase().includes(keyword);
    const show = langMatch && catMatch && textMatch;
    item.style.display = show ? "" : "none";
  });
}

Step 6: Translate Filter UI for Each Language

If your site supports multiple languages, localize the filter labels using _data files:

_data/ui/en.yml
filter_language: "Filter by language"
filter_category: "Filter by category"

_data/ui/es.yml
filter_language: "Filtrar por idioma"
filter_category: "Filtrar por categoría"

Then include localized labels:

{% raw %}
<label>{{ site.data.ui[page.lang].filter_language }}</label>
{% endraw %}

Use Case: Interactive Knowledge Base

Imagine a multilingual FAQ or developer documentation with 300+ entries. Users can quickly refine the list to French installation guides or English API references — no reloads, no wait time, and all powered statically via Jekyll and client-side logic.

Bonus: Filtering via URL Parameters

Let users share pre-filtered views:


https://example.com/docs?q=plugin&lang=es&cat=guides

Parse query params and apply initial filters automatically using URLSearchParams.

Conclusion

Client-side filtering brings a big UX improvement to static Jekyll sites. It's lightweight, fast, and compatible with GitHub Pages. When combined with multilingual structures, it creates a powerful browsing experience without the complexity of JavaScript frameworks or dynamic backends.

In the next article, we’ll cover **handling alternate language URLs for SEO and UX**, using the hreflang tag and language switcher components to ensure Google understands your multilingual structure.


Archives / All Content


© Zest Link Run . All rights reserved.