Multilanguage

Create multiple language versions of the same page

Options See on deno.land

extensions string[]

The list of extensions used for this plugin

Default:
[ ".html" ]
languages string[]

Available languages

defaultLanguage string

A prefix-free language

Description

This plugin provides some features to make easier the creation of multilanguage sites.

Installation

Import this plugin in your _config.ts file to use it:

import lume from "lume/mod.ts";
import multilanguage from "lume/plugins/multilanguage.ts";

const site = lume();

site.use(multilanguage({
  languages: ["en", "gl", "es"], // Available languages
}));

export default site;

Due to the automatic alternate links generating, the plugin must be registered after all URL modifers to work probably.

import lume from "lume/mod.ts";
import basePath from "lume/plugins/base_path.ts";
import multilanguage from "lume/plugins/multilanguage.ts";

site.use(basePath()); // modify url
site.use(multilanguage({
  languages: ["en", "gl", "es"],
})); // use the modify url
// site.use(basePath()); // this modification will not be applied

export default site;

Create pages in multiple languages

This plugin uses the id variable to detect the different translations of the same page. For example, let's say we have the following two pages:

---
lang: en
id: about
url: /about-me/
---

# About me
---
lang: gl
id: about
url: /acerca-de-min/
---

# Acerca de min

The plugin interprets these two pages as the same content but in different languages, because they have the same id (about).

The pages will be exported as /en/about-me/, /gl/acerca-de-min/. Note that the /en/ and /gl/ prefixes are automatically added.

It's possible to configure one language as default, so any page in this language won't have the prefix in the URL. For example, consider the following configuration:

site.use(multilanguage({
  languages: ["en", "gl", "es"], // Available languages
  defaultLanguage: "en", // The default language
}));

Now, the pages will be exported as /about-me/ and /gl/acerca-de-min/. The english version doesn't have the /en/ prefix because it's the default language.

Because this plugin detects the different language version for every page, it inserts automatically the <link rel="alternate" hreflang="{lang}" href="{url}" /> elements in each pages. For example:

<!doctype html>
<html lang="en">
  <head>
    <title>About me</title>

    <link rel="alternate" hreflang="gl" href="/gl/acerca-de-min/" />
  </head>
  <body>
    ...
  </body>
</html>

The attribute lang is inserted automatically in the html element if it's missing.{.tip}

Create a language switcher menu

The plugin also exposes the alternates variable, that you can use to build a menu to change the language of the current page. This is an example in nunjucks:

<ul class="languages">
{% for alt in alternates %}
  <li>
    <a href="{{ alt.url }}" {% if alt.lang == lang %}aria-current="page"{% endif %}>
      {{ alt.title }} ({{ alt.lang }})
    </a>
  </li>
{% endfor %}
</ul>

This code outputs something like:

<ul class="languages">
  <li>
    <a href="/about-me/" aria-current="page">
      About me (en)
    </a>
  </li>
  <li>
    <a href="/sobre-min/">
      Sobre min (gl)
    </a>
  </li>
  <li>
    <a href="/acerca-de-mi/">
      Acerca de mí (es)
    </a>
  </li>
</ul>

Multilanguage data

Language suffixes

With this plugin, you can have your data in different languages that will be correctly resolved according to the language of each page. For example, let's say we have the following _data.yml file:

site_name: The Óscar's blog
site_name.gl: O blog de Óscar
site_name.es: El blog de Óscar

The variable site_name has a different value for each language. Any variable ending with a dot following by one of the languages defined in the _config file is considered a translation. We can use the site_name variable in our pages and the value will be different depending on the page's language:

---
lang: en
---

<h1>{{ site_name }}</h1> <!-- Outputs: The Óscar blog -->

It's possible to translate variables inside objects and arrays. In the following example, the title value inside the links array is different for each language.

site_name: The Óscar's blog
site_name.gl: O blog de Óscar
site_name.es: El blog de Óscar

links:
  - title: My personal site
    title.gl: O meu sitio persoal # The link title in galician
    title.es: Mi sitio personal # The link title in spanish
    url: https://oscarotero.com

  - title: Lume
    url: https://lume.land

Language root variables

In addition to the suffixes, another way to define different data per language is by creating a root variable with the language code. This can be more useful in some cases. For example:

en:
  site_name: The Óscar's blog
  subtitle: My personal opinions

gl:
  site_name: O blog de Óscar
  subtitle: As miñas opinións persoais

es:
  site_name: El blog de Óscar
  subtitle: Mis opiniones personales

Multilanguage pages from a single file

With this plugin it's possible to export the same page multiple times, once per language. To configure a page as multilanguage, just set in the lang variable to an array with the available languages. For example:

# This page is in 3 different languages: English, Galician, and Spanish.
lang: [en, gl, es]
title: About me
layout: base-layout.njk

Lume will generate three pages, one per language, prefixing the output path of each page with the language code:

/en/about-me/index.html
/gl/about-me/index.html
/es/about-me/index.html

We can use the language suffixes to assign different data per language:

lang: [en, gl, es]

title: About me # The default title
title.gl: Acerca de min # The title in galician
title.es: Acerca de  # The title in spanish

layout: base-layout.njk # Common value for all languages

Customize the URLs

You can customize the URLs of the multilanguage pages by adding the language suffix to the url variable:

lang: [en, gl, es]

title: About me
title.gl: Sobre min
title.es: Acerca de 

layout: base-layout.njk

url.en: /about-me/
url.gl: /sobre-min/
url.es: /acerca-de-mi/

Multilanguage + pagination

If your site is using the paginate plugin, this is an example showing how to apply multilanguage:

export const layout = "layouts/my-layout.njk";

export default function* ({ search, paginate }) {
  const langs = ["gl", "en"];

  for (const lang of langs) {
    const pages = search.pages(`type=article lang=${lang}`);

    yield* paginate(pages, {
      url: (n) => `/${lang}/articles/${n}/`,
      each(page, number) {
        page.lang = lang;
        page.id = `articles-page-${number}`;
      },
    });
  }
}
  • In this example, the generator is generating all pages in all languages.
  • In the each option, we are adding the lang and id values to the new pages.
  • The id ensures that the page /gl/articles/1/ and /en/articles/1/ are treated as translations of the same content, because both have the same id.