eleventy
eleventy copied to clipboard
How do I generate a site with one template and many data files in sub folders?
I have 56 json files in a _data/languages subfolder – one for each language – labelled 'english.json', 'arabic.json' etc. In each json file is an array of objects structured like this:
[
{
"id": "01",
"content": "هلا سكنت بذي ضغثٍ فقد زعموا — شخصت تطلب ظبياً راح مجتازا",
"notes": "",
"source" : "Wikipedia"
},
{
"id": "02",
"content": "اصبر على حفظ خضر واستشر فطنا، وزج همك في بغداذ منثملا",
"notes": "",
"source" : "Wikipedia 2014."
}
]
I'm using nunjucks for my templating.
What I'd like to do is build a single page for each language (one for each json file), and build navigation to navigate between them. I'm sure this is possible using a single template, but I can't seem to figure it out. Any pointers?
@markboulton I've done something similar before.
Here's a minimal project to get you started. Also, check out the docs for JavaScript Data Files and Create Pages From Data.
// package.json
{
"name": "the-website",
"version": "0.1.0",
"description": "A business website 👌",
"private": true,
"scripts": {
"start": "npm run dev",
"dev": "npm run clean eleventy:dev",
"build": "run-s clean eleventy:prod",
"eleventy:dev": "cross-env NODE_ENV=development eleventy --serve",
"eleventy:prod": "cross-env NODE_ENV=production eleventy",
"clean": "shx rm -rf ./dist/*",
"format": "prettier --write \"src/**/*.{css,html,js,json,md}\"",
"test": "echo \"Error: no test specified\" && exit 1"
},
"devDependencies": {
"@11ty/eleventy": "^0.11.0",
"@11ty/eleventy-plugin-rss": "^1.0.7",
"cross-env": "^7.0.2",
"npm-run-all": "^4.1.5",
"prettier": "^2.0.5",
"shx": "^0.3.2"
}
}
// .eleventy.js
const isProduction = process.env.NODE_ENV === `production`;
module.exports = function (config) {
// Plugins
config.addPlugin(require(`@11ty/eleventy-plugin-rss`));
// More config...
// Base Config
return {
dir: {
input: `src`,
output: `dist`,
includes: `_includes`,
layouts: `_layouts`,
data: `_data`,
},
templateFormats: [`njk`, `md`, `11ty.js`],
htmlTemplateEngine: `njk`,
markdownTemplateEngine: `njk`,
};
};
// src/page.11ty.js
exports.data = () => ({
title: `Default Title`,
layout: `base.njk`,
pagination: {
data: `pages`,
size: 1,
alias: `page`,
addAllPagesToCollections: true,
},
permalink: ({ page }) => `/${page.language}/${page.id}/index.html`,
});
exports.render = ({ page }) => `
<div>
<div>${page.content}</div>
<div>${page.source}</div>
<div>${page.notes}</div>
</div>`;
{# src/_layouts/base.njk #}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ page.title if page.title else title }}</title>
</head>
<body>
<div>
{{ content | safe }}
</div>
</body>
</html>
// src/_data/pages.js
const fs = require(`fs`);
const path = require(`path`);
module.exports = async () => {
const result = [];
const files = await fs.promises.readdir(path.join(__dirname, `languages`));
for (const file of files) {
const data = await fs.promises.readFile(
path.join(__dirname, `languages/${file}`),
{ encoding: `utf8` }
);
const pages = JSON.parse(data).map((page) => {
page.date = new Date(); // each pagination object needs a date
page.language = file.substring(0, file.indexOf(`.json`)); // add extra meta
page.title = `${page.language} - ${page.id}`; // some title
return page;
});
result.push(...pages);
}
return result;
};
// src/_data/languages/arabic.json
[
{
"id": "01",
"content": "هلا سكنت بذي ضغثٍ فقد زعموا — شخصت تطلب ظبياً راح مجتازا",
"notes": "",
"source": "Wikipedia"
},
{
"id": "02",
"content": "اصبر على حفظ خضر واستشر فطنا، وزج همك في بغداذ منثملا",
"notes": "",
"source": "Wikipedia 2014."
}
]
// src/_data/languages/english.json
[
{
"id": "01",
"content": "lorem ipsum dolor 01",
"notes": "",
"source": "Wikipedia"
},
{
"id": "02",
"content": "lorem ipsum dolor 02",
"notes": "",
"source": "Wikipedia 2014."
}
]
@denisbrodbeck This is great! Thank you. Works like a charm! One slight thing: how would I need to tweak this to build just one page per language json file? Thanks for your help!
@denisbrodbeck This is great! Thank you. Works like a charm! One slight thing: how would I need to tweak this to build just one page per language json file? Thanks for your help!
I should clarify - in addition to building a page for each. So, sort of an index page which would link to each further generated page.
Just circling back, much later. Just add another template for that whicih paginates over languages!
// src/indexPages.11ty.js
exports.data = () => ({
layout: `base.njk`,
pagination: {
data: `languages`,
size: 1,
alias: `language`,
addAllPagesToCollections: true,
},
permalink: ({ page }) => `/${language}/index.html`,
});
exports.render = ({ page }) => `/* Exercise left to reader */`;
I would also note that we now have i18n docs on our site too: https://www.11ty.dev/docs/i18n/