Including Images in Multilingual Pages with Hugo

Including images in multilingual context is a tricky business. The problem is, an image is a piece of content in its own right, with its own attributes, most important being the caption, which for N languages translates into N captions. In a typical editorial workflow, photos and articles come from two different types of sources (photographers and writers, respectively), and it is a photographer, who writes the captions – in one language at least.

It’s usually an editor who decides, which images to use with which article. And sometimes, the same image might be used by more than one article. So, the number of places to edit to change anything about a single image can grow quite quickly.

Of course, if you run your site single-handed, and all images are made by you, the problem is not that sharp. So, let’s start with

A Simple Approach

Markdown allows for the following:

!["alt attribute"](/img/IMAG0024.jpg "title attribute")

This translates into

<img src="/img/IMAG0024.jpg" alt="alt attribute" title="title attribute">

But we probably want to translate it into something like

<figure>
    <img src="/img/IMAG0024.jpg" alt="alt attribute" title="title attribute">
    <figcaption>
        title attribute
    </figcaption>
</figure>

To make this happen, create a file themes/<YOUR THEME>/layouts/_default/_markup/render-image.html:

<figure class="main">
    <img src="{{ .Destination }}" alt="{{ .Text }}" title="{{ .Title }}">
    {{- with .Title }}
    <figcaption>
        {{.}}
    </figcaption>
    {{ end -}} 
</figure>

This is called a markup render hook and is a very new addition as of this writing. Best of all, you can define custom hooks per content type (more on that in a later chapter ).

The editing is still a bit of a hurdle: imagine, step by step, the process of changing a single image in an article with four language versions. And changing it back ten minutes later, as you change your mind. Four languages = four edits! And watch out for image-caption mismatches – this can lead to hilarious (or embarrassing) situations.

Ideally, I’d prefer to have… Let’s call it an ‘image bundle’.

Image Bundle

The idea is to create a unit containing an image and translations of the associated texts, and then link it to the page bundle. With Hugo, it is possible to create page bundles that are not listed nor rendered, but can be loaded into a page using .Site.GetPage method. So, we can create a page bundle with a single image as a resource, put the captions to that image into index.*md files – and who cares that the image is actually the main part there and that we have essentially turned the idea of a page bundle inside out?

Let’s create a dedicated directory for our image bundles called kontent/images. To prevent its contents from having an independent life of its own, let’s put this into kontent/images/_index.md:

---
draft: false
cascade:
    _build:
        list: never
        render: false
---

The cascade part will apply rendering and listing restrictions to whatever is under this directory. Repeat for every site language.

The image bundle itself would look like this:

kontent/images/myimage
├── anyname.jpg
├── index.de.md
├── index.md
└── index.ru.md

Now we can modify our markup rendering hook to lookup for an image bundle whenever it sees a .Destination without ‘extension’:

{{- with .Site.GetPage print "kontent/images/" .Destination -}} 

It will load an entire ‘page’, whose content is the image caption, with a single image resource – the image we want to place in our page. The current language will be respected, so you will get the right caption in the right language.

Referring to our image from the content file will be terse, since alt text and caption come from the image bundle:

![](myimage)

Further improvements may include ability to override alt and captions in the Markdown. This is how it works in Errorist theme. The ‘magic’ directory name should be replaced with a configuration parameter, of course.

First Image Comes Free

Of all images used in an article, there is probably one, that is a ‘representative of page’, using Schema.org jargon. Such an image is usually placed in the top part of the page, meaning it can be handled as a separate unit at the template level, so we wouldn’t need to litter our markdown at all. More to that, such image is typically used for all translations of a page, so it would be a waste to set it in four places (if there are four site languages), when we can set it in just one.

Unfortunately, Hugo doesn’t provide for a configuration file at a page bundle level. But we can make a small file with a single line pointing to the image bundle, and read it as a page resource. If we agree that such file will be called, say, main-img, we can define the main image for a multilingual page in a single edit.

Dare I call it ‘efficient’?

Built with Errorist theme for Hugo site generator.