在站点配置文件中定义一个 languages
部分, 定义可用的语言.
也请参考 Hugo Multilingual Part 1: Content translation
下面是多语言Hugo站点的站点配置文件的例子:
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
28
29
30
31
32
33
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
从Hugo 0.31开始 hugo支持多语言多站点配置. 更多细节请参考this issue
这意味着您可以给每个语言配置一个baseURL
如果在 language
层级上设置了baseURL
, 那么所有语言都必须设置并且不能相同:
例子:
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
12
[ 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 也能够分语言设置:
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
19
20
21
[ 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 考虑下面例子:
/content/about.en.md
/content/about.fr.md
第一个文件是英语的,有链接到法语。
第二个文件是法语的,有链接到英语。
文件的语言值通过文件名的后缀来 赋予 .
、通过具有相同的路径和基础文件名称, 多语言内容文件和他们的翻译页面链接在一起.
如果文件没有语言代码, 它会被赋予默认的语言代码。
按内容目录翻译 Translation by content directory 这个系统对每个语言使用不同的内容目录。每个语言的内容目录通过contentDir
参数设定。
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
10
[ 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
的值可以是任何有效滤镜 – 即使是绝对路径引用也行. 唯一的限制是内容目录不能有重叠.
结合上面的配置,考虑下面例子:
/content/english/about.md
/content/french/about.md
第一个文件是英语的,有链接到第二个法语的。
第二个文件是法语的,有链接到第一个英语的。
文件的语言根据文件 所在 目录被 赋予 .
通过具有相同的路径和基础文件名称(相对于他们语言内容目录), 多语言内容文件和他们的翻译页面__链接__在一起.
忽略默认链接 Bypassing default linking. 任何页面如果在前言设定中设置了相同的 translationKey
键值, 他们会被链接在一起,并不考虑他们的基础名称或者位置。
考虑下面例子:
/content/about-us.en.md
/content/om.nn.md
/content/presentation/a-propos.fr.md
1
2
# 在所有三个页面都设置
translationKey : "about"
因为在所有三个页面的前言设定都设置了 translationKey
的相同值, 他们会作为翻译页面 链接 在一起。
永久链接本地化 Localizing permalinks 因为路径和文件名称用于处理链接, 所有的翻译页面会共享相同的URL(语言子目录除外)
需要本地化URLs, 前言设定的slug
or url
参数可以在非默认语言文件中设定。
一个例子, 法国翻译版本(content/about.fr.md
)可以具有它自己的本地化slug:
yaml
toml
json
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
函数:
函数会在i18n/en-US.toml
文件中查询id "home"
:
1
2
[home]
other = "Home"
The result will be
查询带变量的字符串 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:
If .ReadingTime.Count
in the context has value is 1. The result is:
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,
从数据文件索引月份名称.
可以独立为每个语言定义菜单. 创建多语言菜单和创建普通菜单 ,
除了他们是定义在配置文件的语言特定区块内:
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
<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).