在站点配置文件中定义一个 languages 部分, 定义可用的语言.

也请参考 Hugo Multilingual Part 1: Content translation

配置语言 Configure Languages

下面是多语言Hugo站点的站点配置文件的例子:

config.
     
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
copyright: Everything is mine
defaultContentLanguage: en
languages:
  ar:
    languagedirection: rtl
    title: مدونتي
    weight: 2
  en:
    params:
      linkedin: https://linkedin.com/whoever
    title: My blog
    weight: 1
  fr:
    params:
      linkedin: https://linkedin.com/fr/whoever
      navigation:
        help: Aide
    title: Mon blogue
    weight: 2
  pt-pt:
    title: O meu blog
    weight: 3
params:
  navigation:
    help: Help
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
copyright = "Everything is mine"
defaultContentLanguage = "en"

[languages]
  [languages.ar]
    languagedirection = "rtl"
    title = "مدونتي"
    weight = 2
  [languages.en]
    title = "My blog"
    weight = 1
    [languages.en.params]
      linkedin = "https://linkedin.com/whoever"
  [languages.fr]
    title = "Mon blogue"
    weight = 2
    [languages.fr.params]
      linkedin = "https://linkedin.com/fr/whoever"
      [languages.fr.params.navigation]
        help = "Aide"
  [languages.pt-pt]
    title = "O meu blog"
    weight = 3

[params]
  [params.navigation]
    help = "Help"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
{
   "copyright": "Everything is mine",
   "defaultContentLanguage": "en",
   "languages": {
      "ar": {
         "languagedirection": "rtl",
         "title": "مدونتي",
         "weight": 2
      },
      "en": {
         "params": {
            "linkedin": "https://linkedin.com/whoever"
         },
         "title": "My blog",
         "weight": 1
      },
      "fr": {
         "params": {
            "linkedin": "https://linkedin.com/fr/whoever",
            "navigation": {
               "help": "Aide"
            }
         },
         "title": "Mon blogue",
         "weight": 2
      },
      "pt-pt": {
         "title": "O meu blog",
         "weight": 3
      }
   },
   "params": {
      "navigation": {
         "help": "Help"
      }
   }
}

任何不在languages配置块内定义的键会退回使用键的全局值(如英语en中的copyright). 这个规则同样适用于Params, 像例子中help展示的那样: 在法语中help的值是Aide,在其他没有设置这个参数的语言中为Help.

基于上面配置, 所有内容、sitemap、RSS feeds、导航和标签页在英语中会呈现在/路径下, 在法语中会在/fr路径下.

single page templates单页模板中处理前端设置的Params时, 请忽略翻译键中的params.

defaultContentLanguage设置项目的缺省语言。如果不设置, 默认语言是en.

如果默认语言需要同其他语言一样呈现在自己的语言代码(/en)下面, 请设置defaultContentLanguageInSubdir:true

仅仅不是明显的全局的选项可以在每个语言中重载. 全局选项包括 baseURL, buildDrafts等.

请注意: 使用小写的语言代码,即使在使用地区语言时也是如此(比如. 使用 pt-pt 代替 pt-PT). Currently Hugo language internals lowercase language codes, which can cause conflicts with settings like defaultContentLanguage which are not lowercased. Please track the evolution of this issue in Hugo repository issue tracker

禁用语言 Disable a Language

可以禁用一个或多个语言. 这在翻译的时候很有用.

1
disableLanguages = ["fr", "ja"]

注意并不能禁用默认的内容语言

为在OS environment 操作系统环境中设置简单,我们维持禁用语言的独立设置方式.

1
HUGO_DISABLELANGUAGES="fr ja" hugo

如果已经在config.toml中禁用了几种语言,可以在开发时这样设置启用它们:

1
HUGO_DISABLELANGUAGES=" " hugo server

配置多语言多站点 Configure Multilingual Multihost

从Hugo 0.31开始 hugo支持多语言多站点配置. 更多细节请参考this issue

这意味着您可以给每个语言配置一个baseURL

如果在 language 层级上设置了baseURL, 那么所有语言都必须设置并且不能相同:

例子:

config.
     
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
languages:
  en:
    baseURL: https://example.com
    languageName: English
    title: In English
    weight: 2
  fr:
    baseURL: https://example.fr
    languageName: Français
    title: En Français
    weight: 1
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
[languages]
  [languages.en]
    baseURL = "https://example.com"
    languageName = "English"
    title = "In English"
    weight = 2
  [languages.fr]
    baseURL = "https://example.fr"
    languageName = "Français"
    title = "En Français"
    weight = 1
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
   "languages": {
      "en": {
         "baseURL": "https://example.com",
         "languageName": "English",
         "title": "In English",
         "weight": 2
      },
      "fr": {
         "baseURL": "https://example.fr",
         "languageName": "Français",
         "title": "En Français",
         "weight": 1
      }
   }
}

使用上面设置, 会在public目录下生成具有自己根目录的两个站点:

1
2
3
public
├── en
└── fr

所有URLs (i.e .Permalink etc.) 会相对于根生成. 因此English首页的.Permalink 会被设置成 https://example.com/

当我们使用 hugo server 命令时,Hugo会启动多个HTTP服务器. 在命令行界面您会看到类似的输出:

1
2
3
Web Server is available at 127.0.0.1:1313 (bind address 127.0.0.1)
Web Server is available at 127.0.0.1:1314 (bind address 127.0.0.1)
Press Ctrl+C to stop

热加载和服务器间的 --navigateToChanged 如预期工作。

Taxonomies and Blackfriday

标签分类 和 Blackfriday设置

Taxonomies and Blackfriday configuration也能够分语言设置:

config.
     
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
Taxonomies:
  tag: tags
blackfriday:
  angledQuotes: true
  hrefTargetBlank: true
languages:
  en:
    blackfriday:
      angledQuotes: false
    title: English
    weight: 1
  fr:
    Taxonomies:
      plaque: plaques
    title: Français
    weight: 2
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
[Taxonomies]
  tag = "tags"

[blackfriday]
  angledQuotes = true
  hrefTargetBlank = true

[languages]
  [languages.en]
    title = "English"
    weight = 1
    [languages.en.blackfriday]
      angledQuotes = false
  [languages.fr]
    title = "Français"
    weight = 2
    [languages.fr.Taxonomies]
      plaque = "plaques"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
   "Taxonomies": {
      "tag": "tags"
   },
   "blackfriday": {
      "angledQuotes": true,
      "hrefTargetBlank": true
   },
   "languages": {
      "en": {
         "blackfriday": {
            "angledQuotes": false
         },
         "title": "English",
         "weight": 1
      },
      "fr": {
         "Taxonomies": {
            "plaque": "plaques"
         },
         "title": "Français",
         "weight": 2
      }
   }
}

内容翻译 Translate Your Content

管理内容翻译有两种方式. 每种方式都保证了每个页面被赋予了语言并且被链接到其他翻译版本。

按文件名称翻译 Translation by filename

考虑下面例子:

  1. /content/about.en.md
  2. /content/about.fr.md

第一个文件是英语的,有链接到法语。 第二个文件是法语的,有链接到英语。

文件的语言值通过文件名的后缀来 赋予.

、通过具有相同的路径和基础文件名称, 多语言内容文件和他们的翻译页面链接在一起.

按内容目录翻译 Translation by content directory

这个系统对每个语言使用不同的内容目录。每个语言的内容目录通过contentDir 参数设定。

config.
     
1
2
3
4
5
6
7
8
9
languages:
  en:
    contentDir: content/english
    languageName: English
    weight: 10
  fr:
    contentDir: content/french
    languageName: Français
    weight: 20
1
2
3
4
5
6
7
8
9
[languages]
  [languages.en]
    contentDir = "content/english"
    languageName = "English"
    weight = 10
  [languages.fr]
    contentDir = "content/french"
    languageName = "Français"
    weight = 20
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
   "languages": {
      "en": {
         "contentDir": "content/english",
         "languageName": "English",
         "weight": 10
      },
      "fr": {
         "contentDir": "content/french",
         "languageName": "Français",
         "weight": 20
      }
   }
}

contentDir 的值可以是任何有效滤镜 – 即使是绝对路径引用也行. 唯一的限制是内容目录不能有重叠.

结合上面的配置,考虑下面例子:

  1. /content/english/about.md
  2. /content/french/about.md

第一个文件是英语的,有链接到第二个法语的。 第二个文件是法语的,有链接到第一个英语的。

文件的语言根据文件 所在 目录被 赋予.

通过具有相同的路径和基础文件名称(相对于他们语言内容目录), 多语言内容文件和他们的翻译页面__链接__在一起.

忽略默认链接 Bypassing default linking.

任何页面如果在前端设置中设置了相同的 translationKey 键值, 他们会被链接在一起,并不考虑他们的基础名称或者位置。

考虑下面例子:

  1. /content/about-us.en.md
  2. /content/om.nn.md
  3. /content/presentation/a-propos.fr.md
1
2
# 在所有三个页面都设置
translationKey: "about"

因为在所有三个页面的前端设置都设置了 translationKey的相同值, 他们会作为翻译页面 链接 在一起。

因为路径和文件名称用于处理链接, 所有的翻译页面会共享相同的URL(语言子目录除外)

需要本地化URLs, 前端设定的slug or url参数可以在非默认语言文件中设定。

一个例子, 法国翻译版本(content/about.fr.md)可以具有它自己的本地化slug:

     
1
2
Title: A Propos
slug: a-propos
1
2
Title = "A Propos"
slug = "a-propos"
1
2
3
4
{
   "Title": "A Propos",
   "slug": "a-propos"
}

呈现时, Hugo会创建两个/about//fr/a-propos/, 同时维持他们的翻译链接.

页面包 Page Bundles

为避免文件重复的负担,每个页面包继承了它链接的翻译页面包的资源文件,除了内容文件(markdown, html文件等)

因此,在模板内,页面可以访问所有链接的页面包的资源。

如果在链接的多个包内, 有两个或者多个文件具有相同的基础名称, 仅仅有一个会被包含,选择顺序如下:

  • 当前语言包的文件, 如果存在.
  • 遍历按照语言Weight排序的包时第一个遇到的文件.

引用翻译内容 Reference the Translated Content

创建到达翻译内容的链接列表, 使用类似下面的模板:

layouts/partials/i18nlist.html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11

{{ if .IsTranslated }}
<h4>{{ i18n "translations" }}</h4>
<ul>
    {{ range .Translations }}
    <li>
        <a href="{{ .Permalink }}">{{ .Lang }}: {{ .Title }}{{ if .IsPage }} ({{ i18n "wordCount" . }}){{ end }}</a>
    </li>
    {{ end }}
</ul>
{{ end }}

上面代码可以放在一个partial模版中(在 layouts/partials/目录中), 可以被任何模版包含,一个独立内容页 或者 首页模版。如果特定页面没有任何翻译页面, Hugo不会打印任何内容.

上面使用了i18n function, 下节介绍.

列出所有语言 List All Available Languages

可以使用Page 页面变量.AllTranslations 获得所有翻译, 包括页面本身。 在首页可以用来构建语言导航器.

layouts/partials/allLanguages.html
1
2
3
4
5
6

<ul>
{{ range $.Site.Home.AllTranslations }}
<li><a href="{{ .Permalink }}">{{ .Language.LanguageName }}</a></li>
{{ end }}
</ul>

字符串翻译 Translation of Strings

Hugo使用 go-i18n 支持字符串翻译. 参考项目的代码库 获得可以帮助你管理翻译工作流的工具信息.

翻译的字符串从themes/<THEME>/i18n/(集成进主题中)目录汇总, 还有在项目根的i18n目录中的字符串翻译。在i18n目录的字符串翻译会被合并,优先于主题目录中的翻译. 语言文件应该按照 RFC 5646命名, 文件名称类似 en-US.toml, fr.toml等.

Query basic translation

在模版内, 这样使用 i18n 函数:

1
{{ i18n "home" }}

函数会在i18n/en-US.toml文件中查询id "home":

1
2
[home]
other = "Home"

The result will be

1
Home

查询带变量的字符串 Query a flexible translation with variables

经常会想在翻译字符串中使用页面变量. 可以在调用i18n的时候传送.上下文变量给函数。:

1
{{ i18n "wordCount" . }}

函数会将 . 上下文传递给 i18n/en-US.toml 中的"wordCount" id:

1
2
[wordCount]
other = "This article has {{ .WordCount }} words."

假设上下文的.WordCount 具有值101. 输出结果如下:

1
This article has 101 words.

查询单数/复数翻译 Query a singular/plural translation

In order to meet singular/plural requirement, you must pass a dictionary (map) with a numeric .Count property to the i18n function. The below example uses .ReadingTime variable which has a built-in .Count property.

1
{{ i18n "readingTime" .ReadingTime }}

The function will read .Count from .ReadingTime and evaluate where the number is singular (one) or plural (other). After that, it will pass to readingTime id in i18n/en-US.toml file:

1
2
3
[readingTime]
one = "One minute to read"
other = "{{.Count}} minutes to read"

Assume .ReadingTime.Count in the context has value of 525600. The result will be:

1
525600 minutes to read

If .ReadingTime.Count in the context has value is 1. The result is:

1
One minutes to read

In case you need to pass custom data: ((dict "Count" 25) is minimum requirement)

1
{{ i18n "readingTime" (dict "Count" 25 "FirstArgument" true "SecondArgument" false "Etc" "so on, so far") }}

定制日期 Customize Dates

在撰写本文档时,Go语言并没有支持日期的国际化语言环境, 不过通过一些简单工作,可以模拟类似效果. 比如, 想使用法国的月份名称, 您可以添加一个数据文件如 data/mois.yaml具有以下内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
1: "janvier"
2: "février"
3: "mars"
4: "avril"
5: "mai"
6: "juin"
7: "juillet"
8: "août"
9: "septembre"
10: "octobre"
11: "novembre"
12: "décembre"

然后在模版中引用非英语日期名称,类似这样:

1
2
3
<time class="post-date" datetime="{{ .Date.Format `2006-01-02T15:04:05Z07:00` | safeHTML }}">
  Article publié le {{ .Date.Day }} {{ index $.Site.Data.mois (printf "%d" .Date.Month) }} {{ .Date.Year }} (dernière modification le {{ .Lastmod.Day }} {{ index $.Site.Data.mois (printf "%d" .Lastmod.Month) }} {{ .Lastmod.Year }})
</time>

通过声明 .Date.Day, .Date.Month, and .Date.Year, 此方法提取了日、月份、年份. 使用月份数字作为Key, 从数据文件索引月份名称.

菜单 Menus

可以独立为每个语言定义菜单. 创建多语言菜单和创建普通菜单, 除了他们是定义在配置文件的语言特定区块内:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
defaultContentLanguage = "en"

[languages.en]
weight = 0
languageName = "English"

[[languages.en.menu.main]]
url    = "/"
name   = "Home"
weight = 0


[languages.de]
weight = 10
languageName = "Deutsch"

[[languages.de.menu.main]]
url    = "/"
name   = "Startseite"
weight = 0

主导航的呈现同往常一样. .Site.Menus仅包含当前语言的菜单。 注意, 下面的absLangURL会链接到网站正确语言的链接. 如果不使用这个函数, 所有语言中的菜单条目都会指向英文版本, 这是由于默认内容语言位于根目录.

1
2
3
4
5
6
7
8
9
<ul>
    {{- $currentPage := . -}}
    {{ range .Site.Menus.main -}}
    <li class="{{ if $currentPage.IsMenuCurrent "main" . }}active{{ end }}">
        <a href="{{ .URL | absLangURL }}">{{ .Name }}</a>
    </li>
    {{- end }}
</ul>

Missing Translations

如果字符串在当前语言没有翻译,Hugo会使用默认语言的值. 如果没有缺省值, 会显示空字符串.

当您翻译hugo站点是,能够又一个缺失翻译的视觉提示会很好。 设置enableMissingTranslationPlaceholders configuration option配置选项会在所有未翻译字符串的位置标记出来, 填入占位符[i18n] identifier,这个identifier是未翻译的字符串的Id.

对于从其他语言并入内容(缺少内容翻译),参考lang.Merge

为跟踪缺失翻译字符串,可以在运行hugo命令时使用 --i18n-warnings 标记:

1
2
 hugo --i18n-warnings | grep i18n
i18n|MISSING_TRANSLATION|en|wordCount

多语言的主题支持 Multilingual Themes support

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:

If there is more than one language defined, the LanguagePrefix variable will equal /en (or whatever your CurrentLanguage is). If not enabled, it will be an empty string (and is therefore harmless for single-language Hugo websites).