Skip to main content

lume_cross_language_content

ARCHIVED PROJECT: This project is no longer maintained, as with Lume’s new Vento templating system this project is no longer needed.

A Lume post-processor add-on for developing multi-language websites. Lume is a static-site generator for the Deno JavaScript/TypeScript runtime.

Use lume_cross_language_content for sharing between different language versions of your website.

Lume already has a mechanism for sharing data between pages, but this built-in mechanism is only available for some Lume page formats such as Nunjucks but not for other formats such as YAML or Markdown.

YAML is a page format that is particularly suitable for multi-language sites, as the page can contain language-specific content while leaving it to the layouts the task of generating the HTML markup that remains the same across languages.

But the downside of YAML is that you can’t embed shared data into into these pages. lume_cross_language_content fixes that by enabling the embedding of shared data in all types of pages, not only some.

For example, with lume_cross_language_content a YAML product page can show the same price across languages while storing the price information in one single file in a Lume project.

Caveat

If a smooth development experience matters more to you than succinct code, then sticking with Lume’s built-in data sharing mechanism is a better option, because using lume_cross_language_content will involve restarting the local Lume server when the shared data is updated in order to display the new data.

Usage

Call lume_cross_language_content from your Lume project’s configuration file:

// _config.ts

import lume from 'lume/mod.ts';
import * as lume_cross_language_content from 'lume_cross_language_content/mod.ts';

const
src  = './src',
dest = './build';

export default
lume({
  src, dest,
  location: new URL('https://qworum.net'),
})
.addEventListener(
  "afterBuild",
  lume_cross_language_content.createAfterBuildListener(src, dest)
);

Don’t forget to define the lume_cross_language_content/ import prefix in your lume project’s import_map.json file:

{
  "imports": {
    "lume/"                       : "https://deno.land/x/lume@v2.0.2/",
    "lume_cross_language_content/": "https://deno.land/x/lume_cross_language_content@v2.0.1/",
  }
}

lume_cross_language_content@v1.x.x versions are compatible with lume@v2.x.x.

How it works

lume_cross_language_content assumes that your Lume project’s source directory contains a file that has the path _data/cross-language-content.yaml. This file contains data that you wish to define once in your Lume project. Note that this file mustn’t contain arrays.

cross-language-content.yaml file contents look like this:

currency: USD
plans:
  basic:
    monthly_fee: 195
    yearly_fee: 1950

Here are the rules for this file:

  • Literals can be strings or numbers, both floating point and integer numbers are supported.
  • No arrays.

Your project pages can then access this data using the §§{path.to.literal} placeholder format.

lume_cross_language_content will then modify the HTML pages after they have been built by Lume, and will not touch the Lume pages in the source directory.

In other words, lume_cross_language_content is a post-build tool. Note that the local Lume server must be restarted if the _data/cross-language-content.yaml file is modified.

Example

Here is what a Lume page might look like in YAML format:

layout: layouts/pricing.njk
title: Plans

plans: 
- title   : Basic
  price   : §§{plans.basic.monthly_fee} §§{currency} per month or §§{plans.basic.yearly_fee} §§{currency} per year. 

This page is already localised because it targets the english language, but we can do even better.

Note that the price itself isn’t localised, so let’s use the page’s layout for localising the price as well. This will happen at the expense of additional code. Here is what an improved Lume page would look like:

layout: layouts/pricing.njk
title: Plans

plans: 
- title   : Basic
  price   : >
    <span class='price' data-amount='§§{plans.basic.monthly_fee}' data-currency='§§{currency}'></span> per month or 
    <span class='price' data-amount='§§{plans.basic.yearly_fee}' data-currency='§§{currency}'></span> per year.

Given this page, the layouts/pricing.njk Lume layout can then localise the price using JavaScript.

Note that the <span> elements have no content yet, so users would only be able to see the prices if they have enabled JavaScript on their browsers. Adding support for browsers that have disabled JavaScript is possible, although the displayed price will not be localised:

layout: layouts/pricing.njk
title: Plans

plans: 
- title   : Basic
  price   : >
    <span class='price' data-amount='§§{plans.basic.monthly_fee}' data-currency='§§{currency}'>
      §§{plans.basic.monthly_fee} §§{currency}
    </span> per month or 

    <span class='price' data-amount='§§{plans.basic.yearly_fee}' data-currency='§§{currency}'>
      §§{plans.basic.yearly_fee} §§{currency}
    </span> per year.

Finally, here is the layouts/pricing.njk Lume layout that adds the final touch in the localisation process:

<!DOCTYPE html>
<html lang="{{ lang.code }}">
<head>
  <!-- … -->
</head>
<body>
  <!-- … -->
  <ul>
    {% for plan in plans %}
    <li>
      <p>{{ plan.title }}</p>
      <p>{{ plan.price | safe }}</p>
    </li>
    {% endfor %}
  </ul>
  <!-- … -->
  <script>
    // localise the prices
    const lang = document.documentElement.lang;

    document.querySelectorAll("span.price")
    .forEach(priceElement => {
      const
      amount    = parseFloat(priceElement.dataset.amount),
      currency  = priceElement.dataset.currency,
      priceHtml = new Intl.NumberFormat(lang, { style: 'currency', currency }).format(amount);

      priceElement.innerHTML = priceHtml;
    });
  </script>
  <!-- … -->
</body>
</html>

In this example the page’s language code is added by the lume_langdata Lume plugin at build time.

Other relevant Lume add-ons

If you are developing multi-language sites, the following Lume plugins are a nice complement to the lume_cross_language_content add-on:

Demo

This website project uses Lume and lume_cross_language_content.

License

lume_cross_language_content is released under the Apache 2.0 License.