How to Set Up a Multilingual Website in Hugo
- Author: Md. Saad
- Published at: September 13, 2023
- Updated at: May 26, 2024
Hugo supports the creation of vibrant websites in multiple languages. No More Language Barriers!
With Hugo's native multilingual support, you can manage translations and localization more effectively. What's more, Hugo will assist in generating language-specific URLs, handling content translation, and managing language-specific metadata. Here's how you can set up a multilingual website in Hugo:
Set Language
The first step in creating a multilingual website is defining the languages you wish to provide in the config.toml file. In my situation, I chose English and French according to the following criteria:
[params]
…
[languages]
[languages.en]
contentDir = 'content/en'
languageName = 'En'
[languages.fr]
contentDir = 'content/fr'
languageName = 'Fr'
Note: Anything not defined in a [Languages] block will fall back to the global value for that key.
The configuration above will render all content, sitemap, RSS feeds, paginations, and taxonomy pages below /en in English (your default content language) and below /fr in French. We can also add defaultContentLanguage to set the project’s default language. If not specified, the default language will be en.
defaultContentLanguage = 'en'
You can also add language-wise parameters. To do that, follow the following style:
[languages.fr.params]
linkedin = 'https://linkedin.com/fr/whoever'
[languages.fr.params.navigation]
help = 'Aide'
Menus
There are many patterns for adding multilingual menus in Hugo. Here, we use i18n files to add menus. At first, we added a menu list in the config.toml file.
[Menu]
# Main Menu
[[menu.Main]]
identifier = 'exhibition'
name = "Exibhition"
url= "#gallery"
weight = 1
[[menu.Main]]
identifier = 'feature'
name = "Feature"
url= "#service"
weight = 1
[[menu.Main]]
identifier = 'about'
name = "About"
url= "/about/"
weight = 3
[[menu.Main]]
identifier = 'blog'
name = "Blog"
url= "#blog"
weight = 4
[[menu.Main]]
identifier = 'pricing'
name = "Pricing"
url= "#pricing"
weight = 5
[[menu.Main]]
identifier = 'faq'
name = "FAQ"
url= "#faq"
weight = 6
[[menu.Main]]
identifier = 'contact'
name = "Contact"
url= "/contact/"
weight = 7
The identifier is the key that you use to add or change menu names in various languages. Now we have to create an i18n folder. Inside, it creates files for English and french language. This file name must be the same as the languages. In this case, en and fr. So, our file name will be i18n/en.toml and i18n/fr.toml. You can also use YAML or JSON file type.
Now add the following codes on en.toml file
# Menu Items
[exhibition]
other="Exibhition"
[feature]
other="Feature"
[about]
other="About"
[blog]
other="Blog"
[pricing]
other="Pricing"
[faq]
other="FAQ"
[contact]
other="Contact"
Here, you have to change only other values on each language file. Thus The fr.toml file will look like this:
# Éléments de menu
[exhibition]
other="Exposition"
[feature]
other="Caractéristique"
[about]
other="À propos de"
[blog]
other="Blog"
[pricing]
other="Tarification"
[faq]
other="FAQ"
[contact]
other="Contactez"
Next, we have to use these in head.html/header.html in the partial folder to show menu items. Add the following codes to do these:
<ul >
<!-- Site Nav Bar -->
{{ $currentPage := . }}
{{ $menu := .Site.Menus.main}}
{{range $index, $element := $menu}}
<li class=" {{ if or ($currentPage.IsMenuCurrent "main" .) ($currentPage.HasMenuCurrent "main" .) }} active{{ end }}">
<a class="nav-link scroll-to" href="{{ .URL | relLangURL }}"> {{ i18n .Identifier | default .Name}} </a>
</li>
{{end}}
<li class="">
<select class="" id="selectLangauge" onchange="location = this.value ">
<!-- Language Menu -->
{{ $siteLanguages := $.Site.Home.AllTranslations }}
{{ $pageLang := .Page.Lang }}
{{ range .Page.AllTranslations }}
{{ $translation := . }}
{{ range $siteLanguages }}
{{if eq $translation.Lang .Lang}}
{{ $selected := false }}
{{ if eq $pageLang .Lang}}
<option id="{{ $translation.Language }}" value="{{ $translation.URL }}" selected>
{{ .Language.LanguageName }}
</option>
{{ else }}
<option id="{{ $translation.Language }}" value="{{ $translation.URL }}">
{{ .Language.LanguageName }}
</option>
{{ end }}
{{ end }}
{{ end }}
{{end}}
</select>
</li>
</ul>
Please follow the links for more details on adding Hugo Menu.
Content
There are several ways to add multilingual content files in Hugo also. here I have added the easiest way. First, add the content file directory on config.toml file using contentDir param.
[languages.fr]
contentDir = 'content/fr'
Now add a folder in a content folder using the name of the languages. Now add content inside of the folder. In this case, there will be two folders. These are the content/en and content/fr folders. Inside these folders will be files with the same name for each language. Only values inside the files should be changed according to the language.
Such as, for English, the code will look like these:
---
title: "A Cancer Survivor Built a Wellness Platform"
date: 2022-01-06T11:16:38+06:00
---
Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptate eius eum dolor voluptatum autem minima magni soluta reiciendis corrupti, iste odio, minus odit voluptates rerum veritatis nam vel! Odio, totam?
### A sample heading
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Tempore mollitia quas maiores, error magnam distinctio doloribus fugiat ea minima incidunt odio facere nam nisi quod nobis aut quae aliquid. Atque voluptas esse voluptate. Placeat laudantium veniam, repellendus laboriosam blanditiis commodi!
And its french version will be like the following:
---
title: "Une survivante du cancer a créé une plateforme de bien-être"
date: 2022-01-06T11:16:38+06:00
---
Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptate eius eum dolor voluptatum autem minima magni soluta reiciendis corrupti, iste odio, minus odit voluptates rerum veritatis nam vel! Odio, totam?
### A sample heading
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Tempore mollitia quas maiores, error magnam distinctio doloribus fugiat ea minima incidunt odio facere nam nisi quod nobis aut quae aliquid. Atque voluptas esse voluptate. Placeat laudantium veniam, repellendus laboriosam blanditiis commodi!
Data
Like the content folder, create folders for various languages inside the data folder. In our case, there will be two folders. These are data/en and data/fr folder. Now add the following codes to use translated data on-site for each data section.
{{ $myData := index .Site.Data .Lang }}
{{with $myData.about}}
—----------
{{end}}
$myData is the variable that indexes your language data. about is the data file where the data is added.
i18n
Hugo uses go-i18n to support string translations. Translations are collected from the themes/<THEME>/i18n/ languageName.toml or your-project/i18n/languageName.toml. Language files should be named according to RFC 5646, such as en.toml, fr.toml, etc.
From within your templates, use the i18n function like this:
{{ i18n "footerDescription" }}
The function will search for the "footerDescription " id. This is the id that will be translated using i18n. Now use the following pattern to add translated value in the 1i8n folder, such as with the file i18n/en.toml:
[footerDescription]
other= "Lorem, ipsum dolor sit amet consectetur adipisicing elit"
And in the i18n/fr.toml the code will be like
[footerDescription]
other= "french translation of the text"
How to Set Up Internationalization (i18n) in Next.js
Internationalization (i18n) in Next.js applications entails converting your app's content and routing according to the user's preferred language. In this article, we will go over step-by-step instructions for configuring i18n with Next.js app router.
Read articleMultilingual Themes support
And Finally, To support Multilingual mode in your themes, some considerations must be taken for the URLs in the templates. If there is more than one language, URLs must meet the following criteria:
- Come from the built-in .Permalink or .URL
- Be constructed with
The relLangURL template function or the absLangURL template function OR
Prefixed with {{ .LanguagePrefix }}
If more than one language is defined, the LanguagePrefix variable will equal /en (or whatever your Current Language is). If not enabled, it will be an empty string and is therefore harmless for single-language Hugo websites.
For more details, visit the official page for Hugo’s documentation.
Need a Hugo Developer to create an amazing multilingual website? StaticMania is ready to help you. Contact us here or shoot us an email at hello@staticmania.com.