Dynamic Navigation with Jekyll

When I started to plan the functionality of this blog, I wanted the site’s navigation to change according the the user’s choice of language, while giving the option to easily switch back and forth from one language to another. To accomplish this, I created a custom navigation file in a Jekyll data folder (_data). Within Jekyll, a data file can be used to store additional, non-out-of-the-box functionality to customize a site.

In my case, I wanted two seperate navigations that would alter according to the language (page.lang) the user was currently on. To start I created navigation.yml inside of _data.

├── _data
│   └── navigation.yml

In navigation.yml I created two sets of navigations- one in English (en) and one in Spanish (es). The “title” is what will appear on the navbar, with its corresponding “url” below it. One thing to keep in mind here- YAML, like Python, is pretty specific about its whitespace, so make sure to use the spacebar instead of tab for spacing.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
en:
  posts:
    title: "Posts"
    url: "/index/"
  projects:
    title: "Projects"
    url: "/projects/"
  about:
    title: "About"
    url: "/about/"

es:
  entradas: 
    title: "Entradas"
    url: "/entradas/"
  proyectos:
    title: "Proyectos"
    url: "/proyectos/"
  acerca:
    title: "Acerca De"
    url: "/acerca-de/"

To complete the navigation functionality, in default.html I looped through navigation.yml according to the current [page.lang]. This code allows the user to navigate through the rest of the site in that same language.

1
2
3
4
5
6
7
8
            
<ul class="nav navbar-nav pull-right">
    {% for menu in site.data.navigation[page.lang] %}
    <li class="list-inline">
        <a href="{{ menu[1].url }}">{{ menu[1].title }}</a>
    </li>
    {% endfor %}
</ul>

I also wanted the ability to transition from one language to another in the navbar, but only wanted the counterpart language link to show. So, if the user was on an English post, only see the “Español” link and the opposite for a Spanish post. I chose that for two reasons. First, I didn’t want the navbar to look crowded with unnecessary links, and second, there is no need to link to the page/post the user is already on.

First, on lines 1 and 2, I had to create the variable to be able to loop through the posts. The ‘where:“name”’ filter traverses through the posts to look for its post/page counterpart. I then had to “capture” the language of the page. Line 4 depicts the capture tag- which is a block tag that captures text into a variable to then use that variable to determine the result of the following if/else statement. As that variable goes through the if/else statement, that determines which languge link to display- English or Español. Once the languge is determined, I used a liquid filter, line 7, to replace “en” (the variable used to differentiate between the two languages) with the word “English” and remove the “es” (for Español), since the user is already reading in a Spanish language page. And vice versa on line 11, when the user is on an English page.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    {% assign posts=site.posts | where:"name", page.name | sort: 'path' %} 
    {% for post in posts %}
    <li class="lang">
        {% capture language %}{{page.lang}}{% endcapture %} 
        {% if language == "es" %}
            <a href="{{ post.url }}" class="{{ post.lang }}">
                {{ post.lang | where: "post.lang", "en" | replace: "en", "English" | remove: "es" }}
            </a> 
        {% else %}
            <a href="{{ post.url }}" class="{{ post.lang }}">
                {{ post.lang | where: "post.lang", "es" | replace: "es", "Español" | remove: "en" }}
            </a> 
        {% endif %}
    </li>
    {% endfor %}
</ul>

I then used the same format on the templates for projects and posts.