Now that we have the media components covered, it's time for language translations. Hugo improved a lot for internationalization, also known as i18n since its beginning. They made it so easy and practical, based on their years of experience. In this checkpoint, we will cover 2 approaches one must master, in sequences:
Hugo defaults to one main language (usually English). To translate languages, we need to activate it. In your config.toml
, create the multilingual configurations as below:
defaultContentLanguage = "en"
defaultContentLanguageInSubdir = true
hasCJKLanguage = true
[languages]
[languages.en]
languageCode = "en_US"
languageName = "English"
title = "My New Hugo Site"
weight = 0
[languages.zh_cn]
languageCode = "zh_CN"
languageName = "Chinese (Simplified)"
title = "我的Hugo网站"
weight = 1
By declaring defaultContentLanguage
and providing the languages
array (en
, zh_cn
), we officially initiated the i18n features. You can get the list of language codes (also known as Locale Code) here.
hasCJKLanguage
stands for has Chinese, Japanese, Korean Languages in words as per specification. This will auto-detect the mentioned languages and adjust the work counts accordingly.
defaultContentLanguageInSubdir
, based on specification, if set to true, organize the default language into sub-directory mode. Hence, your root URL (e.g. http://localhost:8080
) will be redirected to your default language appended URL (e.g. http://localhost:8080/en/
). This unifies all languages in the same URL pattern, which is highly recommended especially for search engine optimization deployment.
Now that i18n is enabled, we can first test out translating via filename. Based on the specification, you can translate the entire contents using the language symbol before the extension in the filename. Example:
_index.en.md
_index.zh_cn.md
This is the most practical way and organize the contents in content-oriented away.
Let's rename our content/_index.md
to content/_index.en.md
.
$ mv content/_index.md content/_index.en.md
Then, let's create the _index.zh_cn.md
with a different contents.
To verify the site, you can add the language tag after the base URL. Example:
http://localhost:8080/en/
http://localhost:8080/zh_cn/
You'll notice the _index.md is printed differently, based on the en
, zh_cn
.
NOTE: depending on how many content you created, you'll need to translate ALL of them in the same format. Otherwise, it is considered 404 missing page for unavailable languages.
With language options enabled, there are a few things you need to take note:
absURL
/relURL
, you now use absLangURL
/relLangURL
. This will generate the the language specific URL for a translated content.Example:
{{ "posts/my-first-post" | absURL }} --> //localhost:8080/posts/my-first-post
{{ "post/my-first-post" | absLangURL }} --> //localhost:8080/en/posts/my-first-post
{{ "post/my-first-post" | relURL }} --> /posts/my-first-post
{{ "post/my-first-post" | relLangURL }} --> /en/posts/my-first-post
Hugo supports another method which is organize by languages instead of filename. This method groups the content by language folders so that it's easier to reflect the directory path matching the URL path. Example, the directory for our current checkpoint can be arranged as:
content/en/_index.md
content/zh_cn/_index.md
NOTE: both filename must be matching across language folders.
To activate this mode, you need to define contentDir
in your configuration, pointing to the corresponding language directory. Example:
contentDir = "content/en-us"
Hence, your languages section in the config.toml
will look something as such:
defaultContentLanguage = "en"
defaultContentLanguageInSubdir = true
hasCJKLanguage = true
[languages]
[languages.en-us]
languageCode = "en-US"
contentDir = "content/en-us"
languageName = "English"
title = "My New Hugo Site"
weight = 0
[languages.zh-cn]
languageCode = "zh-CN"
contentDir = "content/zh-cn"
languageName = "Chinese (Simplified)"
title = "我的Hugo网站"
weight = 1
Verifying the language URL and Deploying Link is the same as Method #1.
Hugo supports string translation, as per specification, through the i18n
directory automatically. This directory houses all the <language-symbol>.toml
which contains the keyword and its corresponding translations. Let's create the directory.
$ mkdir i18n
Now that we have the directory ready, it's time to create a language pack. Hugo version 0.31 and above supports matching keywords so you're not necessary locked down to the standard Locale Code.
Hugo i18n language file allows singular or plural translations and interpreting values as well. E.g.:
[readingTime]
one = "One minute read"
other = "{{ .Count }} minutes read"
It goes with the pattern:
[<keyword>]
one = "<singular translation>"
other = "<plural translation>"
Let's create one <zh-cn>
translation sample in zh-cn.toml
.
[Hello]
other = "您好! 来自i18n的语言包!"
and the English <en>
version in en.toml
.
[Hello]
other = "Hello from i18n language pack!"
NOTE: if the given keyword could not find matching pack or set, it won't print out. Hence, for our example, if you're using this method, you need to create both the English and Chinese language packs together.
Now that we have the translation for "Hello" keyword available for both languages, it's time to deploy it. Hugo uses i18n
or T
to calls in a string translation. The full shortcode is:
{{ i18n "<keyword>" <variables> }}
In our case, it is:
{{ i18n "Hello" . }}
You can use it on any of the layouts, e.g. baseof.html
. We're expecting the string printed out right after "Using Baseof Layout" layer.
You might need to restart your development server for the i18n
translation to work.
After restarting, visit your home page again. You should be able to see the hello greeting from the language pack. Switch the language to see its translation changes from English to Chinese.
If you're alert enough, you'll immediately notice that to transform our repo from single language to multiple languages mode, you need to recreate/rename a large number of filenames. Imagine you already wrote 100+ contents. That's painful to move around in order to retain the URL compatibility, left alone translating all the contents.
Hence, one good lesson is to transform your repository into multiple language mode at creation, then focus on 1 language. This way, as you grow to 100+ contents, it's easier to add a new language support by just focusing on translating the contents (instead of rearranging the contents).
Moving forwards, we'll always stick to i18n configuration, since this is a good practice. That's all for i18n. You had reached the end of the checkpoint.