Skip to main content

Multilingual Sites

View SourceEdit this page (external link)

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 = 2
  • defaultContentLanguage: 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.md

Hugo 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: 2
content/
├── en/
│   └── _index.md
└── fr/
    └── _index.md

Content 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: content

Worth 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:

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'
---
Info

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.


  1. The locale setting is the exception, for the same reason explained in Basic Configuration. ↩︎

Accessibility settings

Font size