Hugo 内容适配器
概述
内容适配器是一种模板,在构建站点时动态创建页面。例如,使用内容适配器从远程数据源(如 JSON、TOML、YAML 或 XML)创建页面。
与驻留在 layouts 目录中的模板不同,内容适配器驻留在 content 目录中,每种语言每个目录不超过一个。当内容适配器创建页面时,页面的 逻辑路径 将相对于内容适配器。
content/
├── articles/
│ ├── _index.md
│ ├── article-1.md
│ └── article-2.md
├── books/
│ ├── _content.gotmpl <-- 内容适配器
│ └── _index.md
└── films/
├── _content.gotmpl <-- 内容适配器
└── _index.md每个内容适配器命名为 _content.gotmpl,使用与 layouts 目录中模板相同的 语法。你可以在内容适配器中使用任何 模板函数,以及下面描述的方法。
方法
在内容适配器中使用这些方法。
AddPage
向站点添加页面。
{{ $content := dict
"mediaType" "text/markdown"
"value" "The _Hunchback of Notre Dame_ was written by Victor Hugo."
}}
{{ $page := dict
"content" $content
"kind" "page"
"path" "the-hunchback-of-notre-dame"
"title" "The Hunchback of Notre Dame"
}}
{{ .AddPage $page }}AddResource
向站点添加页面资源。
{{ with resources.Get "images/a.jpg" }}
{{ $content := dict
"mediaType" .MediaType.Type
"value" .
}}
{{ $resource := dict
"content" $content
"path" "the-hunchback-of-notre-dame/cover.jpg"
}}
{{ $.AddResource $resource }}
{{ end }}然后使用类似以下内容检索新页面资源:
{{ with .Resources.Get "cover.jpg" }}
<img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}" alt="">
{{ end }}Site
返回将添加页面的 Site。
{{ .Site.Title }}请注意,从内容适配器调用时返回的 Site 尚未完全构建;如果你尝试调用依赖于页面的方法,例如 .Site.Pages,你会收到错误提示"this method cannot be called before the site is fully initialized"。
Store
返回一个持久的"scratch pad"来存储和操作数据。这的主要用例是在 EnableAllLanguages 设置时在多次执行之间传输值。参见 示例。
{{ .Store.Set "key" "value" }}
{{ .Store.Get "key" }}EnableAllLanguages
默认情况下,Hugo 只为 sites matrix 中第一个匹配的站点执行内容适配器一次。使用此方法将执行扩展到所有语言,同时保持当前角色和版本。
对于更细粒度的控制,在 front matter 或内容挂载中定义 sites.matrix。
{{ .EnableAllLanguages }}
{{ $content := dict
"mediaType" "text/markdown"
"value" "The _Hunchback of Notre Dame_ was written by Victor Hugo."
}}
{{ $page := dict
"content" $content
"kind" "page"
"path" "the-hunchback-of-notre-dame"
"title" "The Hunchback of Notre Dame"
}}
{{ .AddPage $page }}EnableAllDimensions
默认情况下,Hugo 只为 sites matrix 中第一个匹配的站点执行内容适配器一次。使用此方法将执行扩展到语言、角色和版本的每种可能组合。
对于更细粒度的控制,在 front matter 或内容挂载中定义 sites.matrix。
页面映射
在传递给 AddPage 方法的映射中设置任何 front matter 字段,不包括 markup。代替设置 markup 字段,如下所述指定 content.mediaType。
此表描述了最常传递给 AddPage 方法的字段。
| Key | 描述 | 必需 |
|---|---|---|
content.mediaType |
内容 media type。默认是 text/markdown。参见 内容格式 示例。 |
|
content.value |
内容值为字符串。 | |
dates.date |
页面创建日期,为 time.Time 值。 |
|
dates.expiryDate |
页面失效日期,为 time.Time 值。 |
|
dates.lastmod |
页面最后修改日期,为 time.Time 值。 |
|
dates.publishDate |
页面发布日期,为 time.Time 值。 |
|
params |
页面参数映射。 | |
path |
页面相对于内容适配器的 逻辑路径。不要包含前导斜杠或文件扩展名。 | ✔️ |
title |
页面标题。 |
虽然 path 是唯一必需字段,但我们也建议设置 title。
设置 path 时,Hugo 将给定字符串转换为逻辑路径。例如,将 path 设置为 A B C 会产生逻辑路径 /section/a-b-c。
资源映射
使用以下字段构建传递给 AddResource 方法的映射。
| Key | 描述 | 必需 |
|---|---|---|
content.mediaType |
内容 media type。 | ✔️ |
content.value |
内容值为字符串或资源。 | ✔️ |
name |
资源名称。 | |
params |
资源参数映射。 | |
path |
资源相对于内容适配器的 逻辑路径。不要包含前导斜杠。 | ✔️ |
title |
资源标题。 |
当 content.value 是字符串时,Hugo 生成一个相对于页面的发布路径的新资源。但是,如果 content.value 已经是资源,Hugo 直接使用其值并将其相对于站点根目录发布。后一种方法更高效。
设置 path 时,Hugo 将给定字符串转换为逻辑路径。例如,将 path 设置为 A B C/cover.jpg 会产生逻辑路径 /section/a-b-c/cover.jpg。
示例
从远程数据创建页面,每个页面代表一篇书评。
- Step 1
- 创建内容结构。
content/ └── books/ ├── _content.gotmpl <-- 内容适配器 └── _index.md - Step 2
- 检查远程数据以确定如何将键值对映射到 front matter 字段。
https://www.hugodoc.com/shared/examples/data/books.json - Step 3
- 创建内容适配器。
content/books/_content.gotmpl
{{/* 获取远程数据。*/}} {{ $data := dict }} {{ $url := "https://www.hugodoc.com/shared/examples/data/books.json" }} {{ with try (resources.GetRemote $url) }} {{ with .Err }} {{ errorf "Unable to get remote resource %s: %s" $url . }} {{ else with .Value }} {{ $data = . | transform.Unmarshal }} {{ else }} {{ errorf "Unable to get remote resource %s" $url }} {{ end }} {{ end }} {{/* 添加页面和页面资源。*/}} {{ range $data }} {{/* 添加页面。*/}} {{ $content := dict "mediaType" "text/markdown" "value" .summary }} {{ $dates := dict "date" (time.AsTime .date) }} {{ $params := dict "author" .author "isbn" .isbn "rating" .rating "tags" .tags }} {{ $page := dict "content" $content "dates" $dates "kind" "page" "params" $params "path" .title "title" .title }} {{ $.AddPage $page }} {{/* 添加页面资源。*/}} {{ $item := . }} {{ with $url := $item.cover }} {{ with try (resources.GetRemote $url) }} {{ with .Err }} {{ errorf "Unable to get remote resource %s: %s" $url . }} {{ else with .Value }} {{ $content := dict "mediaType" .MediaType.Type "value" .Content }} {{ $params := dict "alt" $item.title }} {{ $resource := dict "content" $content "params" $params "path" (printf "%s/cover.%s" $item.title .MediaType.SubType) }} {{ $.AddResource $resource }} {{ else }} {{ errorf "Unable to get remote resource %s" $url }} {{ end }} {{ end }} {{ end }} {{ end }} - Step 4
- 创建 page 模板来渲染每篇书评。
layouts/books/page.html
{{ define "main" }} <h1>{{ .Title }}</h1> {{ with .Resources.GetMatch "cover.*" }} <img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}" alt="{{ .Params.alt }}"> {{ end }} <p>作者:{{ .Params.author }}</p> <p> ISBN: {{ .Params.isbn }}<br> 评分:{{ .Params.rating }}<br> 评论日期:{{ .Date | time.Format ":date_long" }} </p> {{ with .GetTerms "tags" }} <p>标签:</p> <ul> {{ range . }} <li><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></li> {{ end }} </ul> {{ end }} {{ .Content }} {{ end }}
多语言站点
使用多语言站点,你可以:
- 使用上面的
EnableAllLanguages方法为所有语言创建一个内容适配器。 - 为每种语言创建独特的内容适配器。参见下面的示例。
按文件名翻译
使用此站点配置:
languages:
de:
weight: 2
en:
weight: 1
[languages]
[languages.de]
weight = 2
[languages.en]
weight = 1
{
"languages": {
"de": {
"weight": 2
},
"en": {
"weight": 1
}
}
}
在内容适配器的文件名中包含语言标识符。
content/
└── books/
├── _content.de.gotmpl
├── _content.en.gotmpl
├── _index.de.md
└── _index.en.md按内容目录翻译
使用此站点配置:
languages:
de:
contentDir: content/de
weight: 2
en:
contentDir: content/en
weight: 1
[languages]
[languages.de]
contentDir = 'content/de'
weight = 2
[languages.en]
contentDir = 'content/en'
weight = 1
{
"languages": {
"de": {
"contentDir": "content/de",
"weight": 2
},
"en": {
"contentDir": "content/en",
"weight": 1
}
}
}
在每个目录中创建单个内容适配器:
content/
├── de/
│ └── books/
│ ├── _content.gotmpl
│ └── _index.md
└── en/
└── books/
├── _content.gotmpl
└── _index.md页面冲突
当两个或多个页面具有相同的发布路径时会发生冲突。由于并发,已发布页面的内容是不确定的。考虑以下示例:
content/
└── books/
├── _content.gotmpl <-- 内容适配器
├── _index.md
└── the-hunchback-of-notre-dame.md如果内容适配器也创建 books/the-hunchback-of-notre-dame,则已发布页面的内容是不确定的。你无法定义处理顺序。
要检测页面冲突,在构建站点时使用 --printPathWarnings 标志。