Γ—
Home RSS feed info
i18n - Part 1 of 3 sequential tutorials for creating a Hugo multilingual website.

Hugo - Tutorial Part 1 - Create i18n multilingual site

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.toml starting with version 0.110.0. This is to make it easier for code editors and build tools to identify this as a Hugo configuration file and project.

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.

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 the baseof.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 the baseof.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

Update:  |
9 minutes to read
0
This post was created with Hugo version 0.115.2.

With the German language setting, comments are not displayed in the English version of the website and vice versa.

© 2023 - Frank Kunert  -  About me