Now that your related post system supports multiple languages, let’s boost the user experience even further by allowing multilingual search that only shows results in the same language. This approach ensures both search and related posts remain contextual.
Why Use Client-Side Search in Jekyll
GitHub Pages is a static hosting platform. It doesn’t support server-side scripts like PHP or databases. So if you want search functionality, you need a static search engine — and Lunr.js or ElasticLunr are perfect for this.
Step 1: Add Lunr or ElasticLunr to Your Project
First, include the JavaScript library in your layout, usually in _layouts/default.html
:
<script src="https://cdnjs.cloudflare.com/ajax/libs/lunr.js/2.3.9/lunr.min.js"></script>
If you need multilingual support (e.g., Indonesian), ElasticLunr or Lunr with language plugins may be better.
<script src="https://unpkg.com/[email protected]/elasticlunr.min.js"></script>
Step 2: Build a Language-Specific Search Index
Instead of one giant search index for all content, we generate separate JSON index files by language using a Jekyll collection.
Create a new template file in your repo like search-index.json
:
---
layout: null
permalink: /search-index-{{ page.lang }}.json
---
[
{% assign posts = site.posts | where: "lang", page.lang %}
{% for post in posts %}
{
"title": "{{ post.title | escape }}",
"url": "{{ post.url }}",
"excerpt": "{{ post.excerpt | strip_html | strip_newlines | escape }}",
"tags": "{{ post.tags | join: ', ' }}",
"lang": "{{ post.lang }}"
} {% unless forloop.last %},{% endunless %}
{% endfor %}
]
Then create separate search pages for each language like /en/search.html
and /id/search.html
that load the correct JSON file.
Example: Loading Index for Bahasa Indonesia
<script>
fetch('/search-index-id.json')
.then(response => response.json())
.then(function(docs) {
const idx = elasticlunr(function () {
this.addField('title')
this.addField('excerpt')
this.setRef('url')
docs.forEach(doc => {
this.addDoc(doc)
})
})
document.querySelector('#search-input').addEventListener('input', function() {
const results = idx.search(this.value, { expand: true })
const container = document.querySelector('#search-results')
container.innerHTML = ''
results.forEach(result => {
const post = docs.find(p => p.url === result.ref)
const item = document.createElement('div')
item.innerHTML = '<a href="' + post.url + '">' + post.title + '</a><p>' + post.excerpt + '</p>'
container.appendChild(item)
})
})
})
</script>
Step 3: Connect Search Result with Related Posts
Once users land on a post from search, the related posts will already be filtered by language (thanks to our previous setup). However, we can also enhance the search page itself by offering “related tags” filters to narrow down results.
Creating Tag Filters on the Search Page
Extract all tags from your index and create filter buttons:
<script>
let currentTag = ''
function renderTags(docs) {
const tagSet = new Set()
docs.forEach(doc => {
doc.tags.split(',').forEach(tag => tagSet.add(tag.trim()))
})
const tagContainer = document.querySelector('#tag-filters')
tagSet.forEach(tag => {
const button = document.createElement('button')
button.textContent = tag
button.onclick = () => {
currentTag = tag
document.querySelector('#search-input').dispatchEvent(new Event('input'))
}
tagContainer.appendChild(button)
})
}
</script>
Update Your Search Function with Tag Filter
const results = idx.search(query, { expand: true })
.map(r => docs.find(p => p.url === r.ref))
.filter(post => !currentTag || post.tags.includes(currentTag))
Step 4: Display Language-Aware Suggestions
In addition to normal search, you can offer a “You might also like” section below search results, showing random posts from the same language with similar tags.
const suggestions = docs.filter(p => p.tags.includes(currentTag) && p.url !== currentUrl)
const sample = suggestions.slice(0, 4) // top 4 suggestions
Benefits of Language-Specific Search and Related Posts
- Improves user engagement and reduces bounce rate
- Respects user language preference
- Makes your content structure more SEO-friendly
- Works fully offline (all client-side)
What's Next
In the next part, we’ll explore how to use Jekyll data files and collections to build interactive documentation systems — like FAQs or tutorials — where search and related articles work in tandem with multilingual support.
Would you like to proceed with that?