Hugo - Share front-matter vars within multi-lang page-bundle

Written by Lyoneel on in HUGO
 4 mins

Hugo - Share front-matter vars within multi-lang page-bundle

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: page bundle imagen de ejemplo

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:

page bundle imagen de ejemplo con el shared.md agregado

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.