In Hugo, each language is an independent site In a multilingual website, each language is a site on the language dimension. This page explains how to configure it.
Configuration Link to this heading
Declare the languages your site uses in hugo.yaml:
defaultContentLanguage = 'en'
[languages.en]
label = 'English'
locale = 'en'
weight = 1
[languages.fr]
label = 'Français'
locale = 'fr'
weight = 2defaultContentLanguage: The default language. Content with no language tag belongs to this language.[languages.en],[languages.fr]: Used to match against a directory name or filename suffix (en,fr). Only an exact string match counts as the same language. If no matching string is found, Hugo falls back to the default language1. Because Hugo always lowercases these keys before comparing them, you should always write your settings in lowercase.weight: Determines the ordering of languages in menus and switchers.
Content Directory Structure Link to this heading
Multilingual content can be organized either by directory or by filename suffix. Pick one approach.
Filename Suffix Link to this heading
Use a language code as a suffix to distinguish files with the same path and filename:
content/
├── _index.en.md
└── _index.fr.mdHugo v0.161.0 (external link) also supports more flexible naming.
Directory Link to this heading
Use a separate content directory per language, mapped through contentDir:
languages:
en:
contentDir: content/en
weight: 1
fr:
contentDir: content/fr
weight: 2content/
├── en/
│ └── _index.md
└── fr/
└── _index.mdContent at the same path and filename under two different language directories is treated as a translation of the same page.
Under the hood, contentDir sets up a module.mount for you. It's just syntactic sugar. The contentDir setting above is equivalent to this module configuration:
module:
mounts:
- source: content/en
target: content
- source: content/fr
target: contentWorth remembering the term module here. It's a powerful part of Hugo that we'll cover in detail in Hugo Modules.
Which to Choose Link to this heading
For a personal blog, it makes no real difference either way. If you want a rule of thumb, hugo-community-docs suggests:
- Few languages, small amount of content: a filename suffix is enough.
- Many languages, or combined with other dimensions like versioning (see Sites Matrix): use separate directories. The structure is clearer and easier to extend later.
Developers who need more advanced functionality can refer to Hugo's official community discussion:
- Using the multidimensional content model to fill-in missing translations (external link)
- Do all page bundles need localized copies once you add a new language? (external link)
Page Relationships Link to this heading
Regardless of which structure you use, Hugo determines translation relationships by matching "same path plus same filename." If the path or filename differs, you need to manually set a matching translationKey in front matter, to force two pages to be linked as different language versions of the same page:
---
translationKey: 'about'
---Congratulations! if you've read this far, you're now a confident Hugo user. What follows leans toward development needs, so feel free to skip it.
The
localesetting is the exception, for the same reason explained in Basic Configuration. ↩︎