Centralizing repeated values for different languages in one place
Motivation
This site is multi-language and has many parameters in front matter; many of them are repeated between pages of different languages, seeing that trend, I try to find a way to share those values between the pages within page-bundle to prevent a change from being multiplied by the number of available languages, also to avoid unforced errors in the process.
At the time of writing, this site has two languages, I plan to add more in the future, also I have multiple customised variables, and those are growing in numbers.
Limitations
Shared values cannot be applied to native variables in Hugo, for example, taxonomy variables (tags, categories). These need to be already in the document for Hugo to process taxonomies, and because of that it cannot be used in a shared document.
What is a page-bundle?
Page bundle is a way to organise content in Hugo, consisting of a folder containing different types of files, languages of a page, for example:
More info: Hugo docs - Page-bundles
Creating a shared file
Add a new file inside the page-bundle, this will be the shared file, can have any name, mine is shared.md
, following the previous example:
In this file, you will add front-matter values to be shared between languages:
---
headless: true
shared1: 1
shared2: "2"
shared3: "three"
---
It’s important to add headless: true
to this file, it will tell to Hugo to not render this page as a single page, and it only can be accessed indirectly by other pages.
Update single.html
After you add the values to shared.md
, you should modify in single.html
to be able to read shared values and be applied to pages within the bundle.
{{ $sharedParams := slice }}
{{ with .Page.Resources }}
{{ with .Match "shared.md" }}
{{ $sharedPage := index . 0 }}
{{ $sharedParams = $sharedPage.Params }}
{{ end }}
{{ end }}
{{ $params := collections.Merge .Page.Params $sharedParams }}
Initializes a variable with an empty array sharedParams
, then using .Page.Resources
obtain a list of available
resources within the page-bundle, using Match
I can filter which file I need,
and because match will return an array I use index . 0
to obtain the first element.
And finally, you merge both arrays.
Shared values only are applied in the main language
To show shared values in all languages, you must search the resources from the main language from non-main languages. To do so, you have to modify the code:
{{ $sharedParams := slice }}
{{ $page := .Page }}
{{ with .Page.Resources }}
{{ with .Match "shared.md" }}
{{ $sharedPage := index . 0 }}
{{ $sharedParams = $sharedPage.Params }}
{{ else }}
{{ with $page.Translations }}
{{ range where . "Lang" "en" }}
{{ with .Resources.Match "shared.md" }}
{{ $sharedPage = index . 0}}
{{ $sharedParams = $sharedPage.Params }}
{{ end }}
{{ end }}
{{ end }}
{{ end }}
{{ end }}
{{ $params := collections.Merge .Page.Params $sharedParams }}
If the initial search not found results, you search the main language translation,
and from its resources you access to shared.md
to then access to shared values.
From here you can make use of params including shared params, instead of using .Page.Params
you should use $params
.
Special thanks
Thanks to @Jmooring, from Hugo forums (discourse) your words helps me a lot to go in the right direction
Thanks for reading!
Namaste.