Skip to main content
Deno 2 is finally here šŸŽ‰ļø
Learn more

lume_cross_language_content

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 data between different language version of your website.

For example, a product page on an e-commerce can show the same price across languages while storing the price information in one single file in a Lume project.

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@v1.14.2/",
    "lume_cross_language_content/": "https://deno.land/x/lume_cross_language_content@v1.0.4/",
  }
}

lume_cross_language_content@v1.x.x versions are compatible with lume@v1.x.x versions from lume@v1.13.x upwards.

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>
    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.