Edit: Since Hugo version 0.87, it is possible to localize dates without the process described below, see the Release Notes. Once you set a language, dates are localized accordingly (see the official documentation).

While building this website with Hugo, I wanted to show the date of posts in German or English. However, this is currently (Hugo version 0.61) not easily possible. Therefore, I want to present my solution here.

The goal

In my case, which will serve as the example, the website has two languages: German and English. For every post, its creation date is shown. For the German version, it should show as 12. Dezember 2019, and for the English version it should be December 12, 2019.

The problem

With the .Format method, Hugo offers the possiblity to format a date (see documentation). You simply give the magic date Mon Jan 2 15:04:05 MST 2006 in the desired formatting. For example, calling .Date.Format "January 2, 2006" in a Hugo template shows the date of the post as December 12, 2019.

But how does this look like in the German case? .Date.Format "2. Januar 2006" yields 12. Januar 2019, so the month is not translated as desired. Even worse: Januar is not even recognized as a month, but rather inserted as a fixed string. So how can we use a date formmatted in German?

A solution

My following solution is based on a suggestion in the Hugo documentation.

First, we build a data template under data/monate.yml with the following content:

1: "Januar"
2: "Februar"
3: "März"
4: "April"
5: "Mai"
6: "Juni"
7: "Juli"
8: "August"
9: "September"
10: "Oktober"
11: "November"
12: "Dezember"

We introduce a partial template layouts/partials/date.html for displaying multilingual dates, with the following content:

{{ if eq "de" .language.Lang }}
    {{ .date.Day }}. {{ index .monate (printf "%d" .date.Month) }} {{ .date.Year }}
{{ else }}
    {{ .date.Format "January 2, 2006" }}
{{ end }}

So our template takes three parameters: date is the date which should be shown. language is the language in which the date should be formatted. And finally, monate describes our German month names. All three parameters are required, because no other variables can be accessed in a partial template. In order to use the template, we have to insert the following line at the desired place, e.g., in a single.html template:

{{ partial "date.html" (dict "date" . "language" $.Page.Language "monate" $.Site.Data.monate) }}

The current block must be the date, .e.g., in a {{ with .Date }} block. With this (admittedly quite complicated) method, we can format dates in multiple languages in Hugo. Additional languages can be added similar to German with additional data templates and new entries in the date.html template.