多语言
按语言组织内容与翻译表,生成多语言站点与语言切换入口。
配置
多语言站点的语言清单与默认语言都在项目配置中声明。以下是基础设置:
defaultContentLanguage = "en"
defaultContentLanguageInSubdir = false
disableDefaultLanguageRedirect = false
disableLanguages = []defaultContentLanguage 是项目的默认语言,写法遵循 RFC 5646;定义了一种或多种语言后,该值必须与某个已定义的语言键匹配。
defaultContentLanguageInSubdir 决定是否把默认语言的内容也输出到同名子目录中,默认值为 false。
disableDefaultLanguageRedirect 用于关闭默认语言的重定向别名,默认值为 false。当 defaultContentLanguageInSubdir 为 true 时,它会阻止根目录跳转到语言子目录;为 false 时,它会阻止语言子目录跳转回根目录。
disableLanguages 是一个语言键切片,用于在构建时停用这些语言。虽然可用,但更推荐在每个语言下使用 disabled 键。完整的语言设置说明见 配置。
翻译内容
管理内容翻译有两种方式,两者都会为每个页面指定语言,并把它与对应的翻译页面互相链接。
按文件名翻译
以两个文件为例:
content/about.en.md
content/about.fr.md第一个文件被指派为英语并与第二个链接,第二个被指派为法语并与第一个链接。语言取自文件名后缀中的语言代码;只要路径与文件基名相同,这些内容就会作为彼此的翻译页面链接起来。
按目录翻译
这种方式为每种语言使用不同的内容目录,通过 contentDir 参数设置:
[languages.en]
contentDir = "content/english"
label = "English"
weight = 10
[languages.fr]
contentDir = "content/french"
label = "Français"
weight = 20contentDir 的取值可以是任何合法路径,甚至可以是绝对路径,唯一的限制是各内容目录之间不能重叠。
配合上面的配置:
content/english/about.md
content/french/about.md第一个文件被指派为英语并与第二个链接,第二个被指派为法语并与第一个链接。语言由文件所在的 content 目录决定;只要相对于各自语言的内容目录而言路径与基名相同,这些内容就会作为翻译页面链接起来。
绕开默认链接规则
只要在 front matter 中设置相同的 translationKey,无论基名或位置如何,页面都会被链接为翻译页面。例如下面三个文件:
content/about-us.en.md
content/om.nn.md
content/presentation/a-propos.fr.md在三个页面中都写入以下 front matter,它们就会被视为彼此的翻译:
translationKey = "about"本地化永久链接
由于链接依赖路径与文件名,所有翻译页面通常共享同一个 URL(只有语言子目录不同)。要本地化 URL,可在 front matter 中设置 slug 或 url。
例如法语翻译可以使用自己的本地化 slug:
---
title: A Propos
slug: "a-propos"
---最终 URL 为:
content/about.md -> https://example.org/about/
content/about.fr.md -> https://example.org/fr/a-propos/两个页面仍然是彼此的翻译。
自 v0.167.0 起,在 section、分类法或术语页面上设置 slug 时,Hugo 会把该 slug 应用到其下所有页面的 URL。例如本地化 products section 及其子页面的地址:
---
title: Produits
slug: "produits"
---最终 URL 为:
content/products/_index.fr.md -> https://example.org/fr/produits/
content/products/electronics/_index.fr.md -> https://example.org/fr/produits/electronics/
content/products/electronics/tv.fr.md -> https://example.org/fr/produits/electronics/tv/slug 与 url 的详细行为见 URL 管理。
页面包
为避免重复维护文件,每个页面包(page bundle)都会继承其翻译页面所在包的资源,内容文件(Markdown、HTML 等)除外。因此模板中可以直接访问所有关联包中的文件。
如果关联的多个包中存在基名相同的文件,只会保留其中的一个,选择顺序是:
- 优先使用当前语言包中的文件;
- 否则按语言
weight的顺序,取最先找到的文件。
界面文案的翻译表
模板中的固定文案通过翻译表维护,放在 i18n/ 目录下,每种语言一个文件:
# i18n/de.toml
products = "Produkte"
services = "Leistungen"在模板中用翻译函数取值,键名即翻译表中的键:
<a href="{{ .RelPermalink }}">{{ T "products" }}</a>i18n 与 T 是同一个函数的两种写法,可以交替使用。翻译表还支持按数量区分单复数等形式,具体写法以当前版本的官方文档为准。
本地化
以下示例假定项目的主语言是英语,另有法语与德语翻译:
defaultContentLanguage = "en"
[languages.en]
contentDir = "content/en"
label = "English"
weight = 1
[languages.fr]
contentDir = "content/fr"
label = "Français"
weight = 2
[languages.de]
contentDir = "content/de"
label = "Deutsch"
weight = 3日期、货币、数字与百分比
日期用 time.Format 格式化,例如模板中写入 {{ .Date | time.Format ":date_full" }},2021-11-03T12:34:56+01:00 会分别渲染为 Wednesday, November 3, 2021(英语)、mercredi 3 novembre 2021(法语)、Mittwoch, 3. November 2021(德语)。
货币、数字与百分比分别使用 lang.FormatCurrency、lang.FormatNumber、lang.FormatPercent。同一个数值 512.5032 在三种语言下的输出如下:
| 格式化方式 | English | Français | Deutsch |
|---|---|---|---|
FormatCurrency 2 "USD" |
$512.50 | 512,50 $US | 512,50 $ |
FormatNumber 2 |
512.50 | 512,50 | 512,50 |
FormatPercent 2 |
512.50% | 512,50 % | 512,50 % |
菜单
菜单项的本地化方式取决于菜单的定义位置:
- 使用 section 页面菜单自动定义菜单项时,必须借助翻译表来本地化每一项;
- 在 front matter 中定义菜单项时,菜单本身已经按语言区分;若其中的名称不够用,再用翻译表补充;
- 在项目配置中定义菜单项时,必须在每个语言键下分别创建菜单项;名称不够用时同样借助翻译表。
按语言定义菜单
既可以写在单个配置文件中,也可以使用配置目录结构。
单个配置文件
条目较少时使用单个配置文件即可:
# 单个配置文件,按语言分别定义菜单项
[languages.de]
label = "Deutsch"
locale = "de-DE"
weight = 1
[[languages.de.menus.main]]
name = "Produkte"
pageRef = "/products"
weight = 10
[[languages.de.menus.main]]
name = "Leistungen"
pageRef = "/services"
weight = 20
[languages.en]
label = "English"
locale = "en-US"
weight = 2
[[languages.en.menus.main]]
name = "Products"
pageRef = "/products"
weight = 10
[[languages.en.menus.main]]
name = "Services"
pageRef = "/services"
weight = 20配置目录
菜单结构较复杂时,可以创建配置目录,把菜单项按语言拆成多个文件:
config/
└── _default/
├── menus.de.toml
├── menus.en.toml
└── hugo.toml# config/_default/menus.de.toml
[[main]]
name = "Produkte"
pageRef = "/products"
weight = 10
[[main]]
name = "Leistungen"
pageRef = "/services"
weight = 20# config/_default/menus.en.toml
[[main]]
name = "Products"
pageRef = "/products"
weight = 10
[[main]]
name = "Services"
pageRef = "/services"
weight = 20使用翻译表
渲染菜单项文本时,示例菜单模板会查询当前语言的翻译表,为此需要使用菜单项的 identifier:
{{ or (T .Identifier) .Name | safeHTML }}如果翻译表不存在,或者翻译表中没有对应的 identifier 键,模板会回退到 name。identifier 的取值取决于菜单的定义方式:
- 使用 section 页面菜单自动定义时,
identifier是页面的.Section; - 在项目配置或 front matter 中定义时,需要为菜单项显式设置
identifier。
例如在项目配置中定义菜单项,并为每项指定 identifier:
# 项目配置
[[menus.main]]
identifier = "products"
name = "Products"
pageRef = "/products"
weight = 10
[[menus.main]]
identifier = "services"
name = "Services"
pageRef = "/services"
weight = 20再在翻译表中建立同名的条目:
# i18n/de.toml
products = "Produkte"
services = "Leistungen"缺失的翻译
如果某个字符串在当前语言下没有翻译,Hugo 会使用默认语言的值;若默认值也不存在,则显示空字符串。
翻译过程中,可视化地标出缺失项会很有帮助。配置项 enableMissingTranslationPlaceholders 会用占位符 [i18n] identifier 标记所有未翻译的字符串,其中 identifier 是缺失翻译的 id。
至于内容缺失翻译时的合并,请使用 lang.Merge。
要定位缺失的翻译字符串,可以在构建时加上 --printI18nWarnings 参数:
hugo build --printI18nWarnings | grep i18n
i18n|MISSING_TRANSLATION|en|wordCount多语言主题支持
要让主题支持多语言模式,模板中的 URL 需要满足以下条件:
- 来自内建的
.Permalink或.RelPermalink; - 或由
urls.RelLangURL、urls.AbsLangURL函数构造,或者带上页面的LanguagePrefix。
定义了多种语言时,LanguagePrefix 会返回 /en(或当前语言的对应前缀);单语言站点中它是空字符串,因此不会产生副作用。
生成多语言内容
如果翻译内容放在同一目录中:
hugo new content post/test.en.md
hugo new content post/test.de.md如果翻译内容分目录存放:
hugo new content content/en/post/test.md
hugo new content content/de/post/test.md生成命令的完整参数见 基础用法。