Creating localized blog posts
This post is part of a series of posts that explain how to set up your own site based on the al-folio theme and add support for a second language:
- Running locally your own al-folio website
- Turning your al-folio into a dual-language website
- Creating localized CV pages
- Creating localized Projects pages
- Creating localized blog posts
We created a local al-folio website, added support for another language in it, created localized CV pages, and project pages. Now, let’s localize the blog part.
Creating the structure
If you go to the blog section of your al-folio site, you’ll realize that it is quite empty, although there are posts in the template. Actually, the Jekyll Multiple Languages Plugin already support localized blog posts. It is not displaying them because it is not finding them. So, let’s create the correct structure for them. Create a _posts/
directory inside each language under the _i18n/
directory, and copy the content of the _posts/
directory from the root of the website to the language directories. So, for example, if you have a _posts/
directory with the following content:
- _posts/2015-03-15-formatting-and-links.md
- _posts/2015-05-15-images.md
- _posts/2015-07-15-code.md
- _posts/2015-10-20-comments.md
- _posts/2015-10-20-math.md
- _posts/2018-12-22-distill.md
- _posts/2020-09-28-github-metadata.md
- _posts/2020-09-28-twitter.md
- _posts/2021-07-04-diagrams.md
- _posts/2022-02-01-redirect.md
You should create the following structure for all your languages, in this example, the English language:
- _i18n/en/_posts/2015-03-15-formatting-and-links.md
- _i18n/en/_posts/2015-05-15-images.md
- _i18n/en/_posts/2015-07-15-code.md
- _i18n/en/_posts/2015-10-20-comments.md
- _i18n/en/_posts/2015-10-20-math.md
- _i18n/en/_posts/2018-12-22-distill.md
- _i18n/en/_posts/2020-09-28-github-metadata.md
- _i18n/en/_posts/2020-09-28-twitter.md
- _i18n/en/_posts/2021-07-04-diagrams.md
- _i18n/en/_posts/2022-02-01-redirect.md
Create that, translate the pages contents, and it will now show the missing blog posts. Easy, right? Errr, you are missing a few small details: the date format, the reading time, and the link when clicking on a tag in the header of the blog section. The bad news is that Jekyll doesn’t natively support localized date formats. The good news is that it is not that hard to create it though. Let’s start with the date format.
Localizing the date format
There are two main formats of date used in the template: in the posts list and inside the posts, with the format September 28, 2020
, and when filtering the posts (e.g.: by tag), with the format Sep 28, 2020
. The easiest way I found of localizing them is by first manually translating the months names. For this, add the following section to your language files (_i18n/en.yml
and _i18n/pt-br.yml
), translating the months names to your language:
months:
long:
january: January
february: February
march: March
april: April
may: May
june: June
july: July
august: August
september: September
october: October
november: November
december: December
short:
january: Jan
february: Feb
march: Mar
april: Apr
may: May
june: Jun
july: Jul
august: Aug
september: Sep
october: Oct
november: Nov
december: Dec
Since the dates are used in a variety of locations, let’s create a function to reuse the code. Create the file _includes/date_format.html
with the following code:
{% assign months = 'january|february|march|april|may|june|july|august|september|october|november|december' | split: '|' %}
{% assign m = include.date_from.date | date: '%-m' | minus: 1 %}
{% assign day = include.date_from.date | date: '%d' %}
{% capture month %}months.{{ include.format }}.{{ months[m] }}{% endcapture %}
{% assign year = include.date_from.date | date: '%Y' %}
{% if site.lang == 'en' -%}
{%- t month %}
{{ day }}, {{ year -}}
{%- else -%}
{{- day }} de {% t month %}, {{ year -}}
{%- endif %}
This code defines a function that extracts the month, day, and year from the date_from
variable, formats according to format
, and returns the formatted localized string. Notice that, to access the given variables, we must refer to them preceded with include.
. The format
variable can be either long
or short
, as we defined above, and the date_from
variable must have a date object inside it. The function also considers the current language. Now, let’s call the function with the proper parameters. Inside the file blog/index.html
, do the following changes:
<!-- {{ post.date | date: '%B %-d, %Y' }} -->
{% include date_format.html format="long" date_from=post %}
The posts list will now display the date format correctly. Just do the same changes for every other place where the date format appears, like the filters pages, changing the month format to "short"
when needed, and also giving the correct date_from
parameter. For example, for the file _layouts/archive-category.html
the change will be:
<!-- <th scope="row">{{ post.date | date: "%b %-d, %Y" }}</th> -->
<th scope="row">{% include date_format.html format="short" date_from=post %}</th>
Localizing the reading time
Now, let’s localize the reading time. Do the following changes to the file blog/index.html
:
<!-- {{ read_time }} min read · -->
{% if site.lang == 'en' %}{{ read_time }} min read{% else %}Leitura de {{ read_time }} min{% endif %} ·
Fixing blog archive navigation
When you click to filter blog posts by tag, year, or category, the page will show the posts, but the navigation will be broken. This is because these navigations are not localized. To fix this, modify the following lines in files _layouts/archive-category.html
, _layouts/archive-tag.html
, and _layouts/archive-year.html
:
<!-- <a class="post-link" href="{{ post.url | relative_url }}">{{ post.title }}</a> -->
<a class="post-link" href="{{ post.url | prepend: site.baseurl }}">{{ post.title }}</a>
Also, change the following line in the file blog/index.html
:
<!-- <i class="fas fa-hashtag fa-sm"></i> <a href="{{ tag | prepend: '/blog/tag/' | relative_url }}">{{ tag }}</a> -->
<i class="fas fa-hashtag fa-sm"></i> <a href="{{ tag | prepend: '/blog/tag/' | prepend: site.baseurl }}">{{ tag }}</a>
Fixing pagination
If your blog has enough posts to enable more pages with results (pagination), you’ll realize that it is not yet translated. To fix this, first we need to create localized words for Older
and Newer
in the language files _i18n/en.yml
and _i18n/pt-br.yml
, respectivelly:
pagination:
newer: Newer
older: Older
pagination:
newer: Recentes
older: Antigas
Next, we change all uses of relative_url
for prepend: site.baseurl
in the file _includes/pagination.html
, so it correctly handles the language urls. Also, change the words “Newer” and “Older” for its correspondent translation from the correct language file:
{%- if paginator.total_pages > 1 -%}
<nav aria-label="Blog page naviation">
<ul class="pagination pagination-lg justify-content-center">
<li class="page-item {% unless paginator.previous_page %}disabled{% endunless %}">
<!-- <a class="page-link" href="{{ paginator.previous_page_path | relative_url }}" tabindex="-1" aria-disabled="{{ paginator.previous_page }}">Newer</a> -->
<a
class="page-link"
href="{{ paginator.previous_page_path | prepend: site.baseurl }}"
tabindex="-1"
aria-disabled="{{ paginator.previous_page }}"
>{% t pagination.newer %}</a
>
</li>
{%- if paginator.page_trail -%} {% for trail in paginator.page_trail -%}
<!-- <li class="page-item {% if page.url == trail.path %}active{% endif %}"><a class="page-link" href="{{ trail.path | relative_url }}" title="{{trail.title}}">{{ trail.num }}</a></li> -->
<li class="page-item {% if page.url == trail.path %}active{% endif %}">
<a class="page-link" href="{{ trail.path | prepend: site.baseurl }}" title="{{trail.title}}">{{ trail.num }}</a>
</li>
{% endfor -%} {%- endif -%}
<li class="page-item {% unless paginator.next_page %}disabled{% endunless %}">
<!-- <a class="page-link" href="{{ paginator.next_page_path | relative_url }}">Older</a> -->
<a class="page-link" href="{{ paginator.next_page_path | prepend: site.baseurl }}">{% t pagination.older %}</a>
</li>
</ul>
</nav>
{%- endif -%}
Fixing page title in the browser
If you filter your blog posts by year, you’ll notice that the year is not displayed in the browser title. To fix this, modify the following lines in the file _includes/metadata.html
:
{% if page.url == '/blog/index.html' %}
{{ site.blog_nav_title }} | {{ title }}
{% elsif page.url contains '/blog/' %}
{{ page.title }} | {{ title }}
{%- elsif page.title contains 'Announcement' -%}
{{ title }}
{%- elsif page.title != 'blank' and page.url != '/' -%}
{% t page.title %} | {{ title }}
{%- else -%}
{{ title }}
{%- endif -%}
for these:
{% if page.url == '/blog/index.html' %}
{{ site.blog_nav_title }} | {{ title }}
{% elsif page.url contains '/blog/' %}
{%- capture blog_year -%}{{ page.url | slice: 0, 11 }}{%- endcapture -%}
{%- if page.url == blog_year -%}
{{ page.date | date: '%Y' }} | {{ title }}
{%- else -%}
{{ page.title }} | {{ title }}
{%- endif -%}
{%- elsif page.title != 'blank' and page.url != '/' -%}
{%- if page.title contains 'Announcement' -%}
{{ title }}
{%- else -%}
{% t page.title %} | {{ title }}
{%- endif -%}
{%- else -%}
{{ title }}
{%- endif -%}