Documentation — Table of Contents
Build a Multilingual Baseline Site
Create a two-language Eleventy site (en + nl) using @apleasantview/eleventy-plugin-baseline. We’ll enable Baseline’s multilingual support, add localized pages, render hreflang/alternate links, and confirm per-language sitemaps. Uses npm, Node 20.15.0, and the same minimal layout style as the previous tutorial.
What you’ll build
- A basic site with English and Dutch pages.
- Baseline configured with
multilingual: trueand language metadata. - Layout with hreflang/alternate links; automatic per-language sitemaps.
Prerequisites
- Node 20.15.0 (or >=20) and npm.
package.jsonwith"type": "module".- Minimal scripts (same as prior tutorial):
{ "type": "module", "scripts": { "dev": "npx @11ty/eleventy --serve", "build": "npx @11ty/eleventy" } }
1) Install Eleventy, Eleventy Image and Baseline
npm install @11ty/eleventy @apleasantview/eleventy-plugin-baseline @11ty/eleventy-img
2) Configure Eleventy with Baseline multilingual
Create eleventy.config.js:
import baseline, { config as baselineConfig } from "@apleasantview/eleventy-plugin-baseline";
import i18n from "./src/_data/i18n.js";
/** @param {import("@11ty/eleventy").UserConfig} eleventyConfig */
export default function (eleventyConfig) {
// Multilingual on; default language and languages pulled from i18n data.
eleventyConfig.addPlugin(baseline({
multilingual: true,
defaultLanguage: i18n.defaultLanguage,
languages: i18n.languages
}));
}
export const config = baselineConfig;
Baseline’s multilang support uses Eleventy’s built-in i18n plugin. For plugin details, see the Eleventy i18n docs: https://www.11ty.dev/docs/plugins/i18n/.
Baseline will configure HtmlBasePlugin to use process.env.URL automatically; create a local .env for dev, and set URL in your host/CI for production so canonicals, hreflang, and sitemaps use the right origin.
Create a local .env now:
ELEVENTY_ENV="development"
URL="http://localhost:8080/"
3) Required site data
src/_data/site.js:
export default {
title: "Multilingual Baseline Site",
tagline: "Hello, Eleventy + Baseline (i18n)",
url: process.env.URL || "http://localhost:8080/",
defaultLanguage: "en",
noindex: false
};
src/_data/head.js:
export default {
link: [{ rel: "stylesheet", href: "/assets/css/index.css" }],
script: [{ src: "/assets/js/index.js", defer: true }]
};
4) Define languages
Create src/_data/i18n.js:
export default {
defaultLanguage: "en",
languages: {
en: {
contentDir: "content/en/",
languageCode: "en",
languageName: "English",
title: "Baseline (EN)",
tagline: "Hello"
},
nl: {
contentDir: "content/nl/",
languageCode: "nl",
languageName: "Nederlands",
title: "Baseline (NL)",
tagline: "Hallo"
}
}
};
5) Per-language directory data
src/content/en/en.11tydata.js:
export default { lang: "en" };
src/content/nl/nl.11tydata.js:
export default { lang: "nl" };
6) Minimal layout with hreflang
Use the same simple layout as before, plus alternates. Create src/_includes/layouts/base.njk:
<!DOCTYPE html>
<html lang="{{ lang | default(site.defaultLanguage) }}">
<head>
<baseline-head></baseline-head>
{# hreflang/alternate links from collections.translations #}
{% set translations = collections.translations[translationKey] %}
{% set defaultLang = site.defaultLanguage %}
{% if translations %}
{% for language, item in translations %}
<link rel="alternate" hreflang="{{ item.lang }}" href="{{ item.url }}">
{% if item.isDefault %}<link rel="alternate" hreflang="x-default" href="{{ item.url }}">{% endif %}
{% endfor %}
{% endif %}
<meta name="color-scheme" content="light dark">
</head>
<body>
<main id="main">
<h1>{{ title }}</h1>
{{ content | safe }}
{% if page.url !== "/" %}
<p><a id="go-back" href=""><span style="vertical-align: text-bottom;">←</span> Go back</a></p>
{% endif %}
</main>
<script>
const backBtn = document.getElementById("go-back");
if ( backBtn ) {
backBtn.addEventListener("click", (event) => {
event.preventDefault();
history.back();
});
}
</script>
</body>
</html>
7) Add localized pages
src/content/en/pages/index.md:
---
title: "Hello Baseline (EN)"
description: "English home"
permalink: "/en/"
layout: "layouts/base.njk"
translationKey: homepage
---
Welcome to the English home page.
src/content/nl/pages/index.md:
---
title: "Hallo Baseline (NL)"
description: "Nederlandse home"
permalink: "/nl/"
layout: "layouts/base.njk"
translationKey: homepage
---
Welkom op de Nederlandse homepagina.
8) Minimal assets (reuse from prior tutorial)
src/assets/css/index.css— same minimal styles as before.src/assets/js/index.js— optional small script (e.g., DOMContentLoaded log).
9) Run the site locally
npx rimraf dist/ && npm run dev
- Visit
/en/for English and/nl/for Dutch. - View page source to see
<link rel="alternate" hreflang="...">entries. - While dev runs, Eleventy also writes to
dist/, so you can peek at the generated files (includingsitemap.xmland individual language sitemapsdist/lang/sitemap.xml).
10) Production build and inspect output
npx rimraf dist/ && npm run build
- Check
dist/for per-language output. dist/sitemap.xmlplus per-language sitemaps (e.g.,dist/en/sitemap.xml,dist/nl/sitemap.xml) if multiple languages are present.
11) Next steps
- Add more pages under
src/content/en/andsrc/content/nl/with matchingtranslationKeyvalues to link translations. - Localize labels (e.g., nav text) via data files keyed by
lang. - Set
pathPrefixif deploying under a subpath; ensuresite.urlis set to your production URL for correct canonicals and sitemap links.
Previous: Build a Simple Baseline Site