Hugo - Tutorial Part 1 - Create i18n multilingual site

Part 1 of 3 instructions for creating a Hugo multilingual website. There are always several ways to realize something. In these tutorials I describe my way.
The topics in part 1 are - hugo.toml in general, page bundle structure of web pages and front matter entries in markdown files.
To be clear, with Part 1 you will not yet be able to create a completely multilingual website.
- Hugo - Tutorial Part 2 - Creating i18n Multilingual Site
The second part goes into the depth of theme development and shows how to program the multilingual website. With the following topics: Entries in the html and head tag of the baseof.html and menu structure in the hugo.toml, including the navigation partials nav.html and sidepanel.html.
- Hugo - tutorial part 3 - create i18n multilingual site
With the following topics: The T (Translate) feature of Hugo, switching the language on the website including source code and SCSS, Hugo problems with multilingual tags, tag cloud as topic overview, tag post list including source code and SCSS, internal linking.
The terms are frequently abbreviated to the numeronyms i18n, where 18 stands for the number of letters between the first i and the last n in the word internationalization.
Post updated on June 5, 2023
I have revised this post a bit and adapted it to the Hugo changes of version 0.112.
i18n entries in the hugo.toml
Hugo’s default configuration file is renamed from config.toml to
Hugo’s general configuration options are very extensive. For the i18n entries for this website, I have limited myself to what is necessary. More parameters will be added in part 2 of this blog series.
- In the - Hugo Documentation - Configure Hugo
- all configuration parameters of the
are explained.hugo.toml
- The - Hugo Documentation - Multilingual Mode - explains how different languages are processed in Hugo.
- RΓ©gis Philibert’s blog series - Hugo Multilingual Part 1: Content translation - has made it easier for me to get started with Hugo Multilingual. That’s why I’m happy to recommend it here.
A lot of documentation. I hope I can make it a little easier to get started with my blog series. The relevant parameters, for this part 1 of the blog series, are the following in the hugo.toml
:
..
defaultContentLanguage = "de"
[languages]
[languages.de]
languageName = "Deutsch"
weight = 1
title = "Hugo, Webdev, SEO, Tools"
[languages.de.params]
description = "Blog ΓΌber Hugo, Webdev, SEO, Tools"
mydomain = "tekki-tipps.de π©πͺ"
..
[languages.en]
languageName = "English"
weight = 2
title = "Hugo, Webdev, SEO, Tools"
[languages.en.params]
description = "Blog about Hugo, Webdev, SEO, Tools"
mydomain = "tekki-tipps.de/en/ π¬π§"
..
The entries in the hugo.toml
were subsequently adapted by me to the Hugo version 0.112. See also - Multilingual - Changes in Hugo as of version 0.112
.
Hugo config parameter defaultContentLanguage
The defaultContentLanguage
parameter tells Hugo the main language. Content without a language flag will be displayed in that language. By default, en
is processed as the default language in Hugo. Since this is different for me, I have set de
. For non-translated web pages, the version with the main language is used.
Hugo config parameter languages
Below [languages]
branches to the language versions. In my case in [languages.de]
and [languages.en]
.
Below the respective language version follow the parameters
languageName
.
The languageName can be displayed as text in a language switcher. More info in part 2.weight
The sorting of the languages is done by this parameter. The main language should be assigned the lowest number.description
I explain how to use description in thebaseof.html
in part 2.mydomain
This parameter I created is used for the domain name. For the english version extended by/en
. In part 2 I will explain this in thebaseof.html
section.
What I would like to hold here now however is, also in the [languages]
part of the configuration can be defined own parameters. At the beginning this was not clear to me. Therefore I had misused the title
parameter for the domain name. But this did not make the source code more clear.
Structure decision
Hugo offers several ways to organize and structure the web pages of a multilingual site. I decided against the By Directory
method and in favor of By Filename
. With - Page Bundles
- I combine everything for a web page, i.e. documents and resources (img, pdf, etc.), in one directory. The structure of my multilingual page bundles looks like this:
content/
βββ blog/
βββ name-of-page-bundle1/
βββ img/
βββ image-name1.jpg
βββ image-name2.jpg
βββ index.en.md
βββ index.md
βββ name-of-page-bundle2/
βββ name-of-page-bundle3/
βββ _index.en.md
βββ _index.md
βββ about-me/
βββ img/
βββ image-name1.jpg
βββ index.en.md
βββ index.md
..
themes/
βββ tekki/
βββ layouts/
βββ index.en.html
βββ index.html
For each web page, a page bundle is created in the content directory. Each page bundle consists of the directory name of the page bundle, a markdown file index.md
for the main language, index.en.md
for the English translation and a subdirectory img
for the image files. I stored my blog posts in the content/blog/
directory. Over time, with more and more blog posts, this makes it more manageable for me.
I store the Page Bundles of the general web pages - About Me, Data Protection, Legal notice and the Contact page directly in the content
directory.
The page bundle directory name can also be changed later. This has no influence on the URL structure. The directory name is only used for the own organization of the page bundles.
I have stored the start pages in my theme under themes/tekki/layouts/index*.html
.
Markdown file names in the Page Bundle
The file name of Markdown files is not built into the web page by Hugo. So it doesn’t matter how the file is named. I decided to use index.md
and index.en.md
.
What and for what are _index.md files?
Short and sweet - you can use them to add title pages and content to your list templates. In the - Hugo Documentation - Index Pages: _index.md - this is described in more detail.
I have my own template in my theme under themes/layouts/blog/list.html
and do not need the default from Hugo. Nevertheless, the _index*.md
files must be present for Hugo to perform the generation process for my content/blog
directory.
The contents of content/blog/_index.md
:
---
title: Blog
description: "Blog Artikel"
sitemap_exclude: true
---
The contents of content/blog/_index.en.md
:
---
title: Blog
description: "Blog Post"
sitemap_exclude: true
---
Unintended effect on sitemap.xml
As described above, this generation statement is actually not displayed anywhere. Actually - but up to the sitemap.xml
this entry makes it without sitemap_exclude: true
nevertheless:
<url>
<loc>https://tekki-tipps.de/blog/</loc>
<lastmod>2023-01-30T20:22:03+01:00</lastmod>
<xhtml:link
rel="alternate"
hreflang="en"
href="https://tekki-tipps.de/en/blog/"
/>
<xhtml:link
rel="alternate"
hreflang="de"
href="https://tekki-tipps.de/blog/"
/>
</url>
Since this makes no sense at all, I added a custom Front Matter parameter sitemap_exclude: true
to the md
files. In the template themes/tekki/layouts/_default/sitemap.xml
I query this parameter and if true
, the entry is not created.
But that was not all. What I noticed at that time during the development - the website tekki-tipps.de/blog/
can be called. And that doesn’t make sense either and doesn’t look good because of the missing CSS classes.
The solution is a Redirect 301
in the static/.htaccess
:
RewriteEngine On
Redirect 301 /blog https://tekki-tipps.de
Redirect 301 /en/blog https://tekki-tipps.de/en/
The start page of this site - index.html and index.en.html
The whole thing has to start somewhere. I created the start pages of my site index.html
and index.en.html
in the directory themes/tekki/layouts/
. In the directory are also my 404.html
and the robots.txt
.
The only difference between index.html
and index.en.html
is the translated text of the HTML tags h1
and p
. For this reason I only show the index.en.html
here:
{{- define "main" -}}
<div class="content-header">
<div class="container">
<h1>A blog about Hugo, Webdev, SEO, Tools ..</h1>
<p>Tips and tricks around the static website generator Hugo.</p>
</div>
</div>
{{- partial "blogTeaser.html" . -}}
{{- end -}}
In the partial blogTeaser.html
the teasers of the blog posts are then displayed.
Front Matter Parameters for i18n
The relevant Front Matter parameters for this blog post look like the following in index.md
:
---
..
slug: "hugo-i18n-howto-teil-1"
translationKey: "i18n-howto-1"
description: "i18n - Teil 1 von 3 Anleitungen fΓΌr das Erstellen einer multilingualen Website mit Hugo dem Static Site Generator."
..
---
In the index.en.md
:
---
..
slug: "hugo-i18n-howto-part-1"
translationKey: "i18n-howto-1"
description: "i18n - Part 1 of 3 instructions for creating a multilingual website with Hugo the Static Site Generator."
..
---
The Hugo Front Matter parameter slug
shortens the URL from the blog post and must be adjusted in the respective language. This is not the crucial parameter for translation, but still very helpful.
The parameter translationKey
is crucial and must be the same in all index*.md
files of the page bundle. This way Hugo recognizes that this is a multilingual web page and generates all structures accordingly. Even down to the sitemap.xml
- magic, I like Hugo.
description
is a very important front matter parameter. Search engines use the text when displaying below links. But more about this in part 2.
Conclusion
If you follow a few basic rules, creating a multilingual website with Hugo is not that difficult. I hope this series makes the path a little easier for Hugo i18n beginners. It’s worth it. An English blog post of mine has just been accessed on Samoa. Thanks to Matomo for this info and the blogger is happy.
Link list for this article
This might also interest you
- Hugo - Tutorial Part 2 - Creating i18n Multilingual Site
The second part goes into the depth of theme development and shows how to program the multilingual website. With the following topics: Entries in the html and head tag of the baseof.html and menu structure in the hugo.toml, including the navigation partials nav.html and sidepanel.html.
- Hugo - tutorial part 3 - create i18n multilingual site
With the following topics: The T (Translate) feature of Hugo, switching the language on the website including source code and SCSS, Hugo problems with multilingual tags, tag cloud as topic overview, tag post list including source code and SCSS, internal linking.
- Hugo - Page Bundle shortcodes for images
Include images in the Markdown file using shortcodes from the page bundle.
- Hugo - i18n Multilingual - customize lastmod date for specific country
i18n - Adjust the country-specific notation of the lastmod date according to the language.
With the German language setting, comments are not displayed in the English version of the website and vice versa.