CINXE.COM
Libreboot – Libreboot Static Site Generator (lbssg)
<!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <meta name="description" content="Learn about the Libreboot Static Site Generator, which is used to convert Markdown documents into HTML. This is what generates the Libreboot website."> <meta name="keywords" content="libreboot, coreboot, canoeboot, opensource, libre, free software, bios, uefi"> <meta name="generator" content="pandoc"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> <link rel="icon" type="image/x-icon" href="/favicon.ico"> <link rel="canonical" href="https://libreboot.org/docs/sitegen/" /> <!-- anti-social media tags --> <meta property="og:title" content="Libreboot – Libreboot Static Site Generator (lbssg)"> <meta property="og:type" content="article" /> <meta property="og:image" content="https://av.vimuser.org/bootmenu.jpg"> <meta property="og:url" content="https://libreboot.org/docs/sitegen/"> <meta name="twitter:card" content="summary_large_image"> <meta property="og:description" content="Libreboot – Libreboot Static Site Generator (lbssg)"> <meta property="og:site_name" content="Libreboot – Libreboot Static Site Generator (lbssg)"> <meta name="twitter:image:alt" content="Libreboot – Libreboot Static Site Generator (lbssg)"> <title>Libreboot – Libreboot Static Site Generator (lbssg)</title> <link rel="stylesheet" href="/global.css"> <link rel="stylesheet" href=""> <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="/feed.xml"/> </head> <body> <div class="page"> <header> <div class="title" onclick="location.href='/';"> <p class="title-logo"> <a href="/"><img loading="lazy" class="title-logo" alt="Libreboot logo" src="/favicon.ico" /></a> </p> <h1 class="title">Libreboot Static Site Generator (lbssg)</h1> </div> <ul> <li><a href="/">Home</a></li> <li><a href="/faq.html">FAQ</a></li> <li><a href="/download.html">Download</a></li> <li><a href="/git.html">Git</a></li> <li style="font-size:1.3em;"><em><strong><a href="https://minifree.org/">Buy Libreboot preinstalled</a></strong></em></li> <li><a href="/docs/install/">Install</a></li> <li><a href="/docs/">Docs</a></li> <li><a href="/news/">News</a></li> <li><a href="https://codeberg.org/libreboot/lbmk/issues">Bugs</a></li> <li><a href="/contact.html">Contact</a></li> <li style="font-size:1.3em;"><em><strong><a href="https://www.patreon.com/libreleah">Donate</a></strong></em></li> <li><a href="/other.html">Other coreboot distros</a></li> </ul> <hr/> </header> <nav id="TOC"> <h2>Navigate this page:</h2> <ul> <li><a href="#home-of-your-favourite-firmware-to-boot-gnu-linux">Home of your favourite firmware to boot GNU / Linux</a></li> <li><a href="#websites-made-easy">Websites made easy</a> <ul> <li><a href="#real-world-examples">Real-world examples</a></li> </ul></li> <li><a href="#requirements">Requirements</a> <ul> <li><a href="#posix-compatibility">POSIX compatibility</a></li> </ul></li> <li><a href="#security-notes">Security notes</a></li> <li><a href="#getting-started">Getting started</a> <ul> <li><a href="#example-website">Example website</a></li> </ul></li> <li><a href="#how-to-use">How to use</a> <ul> <li><a href="#generate-entire-websites">Generate entire websites</a></li> <li><a href="#build-specific-pages">Build specific pages</a></li> <li><a href="#cleaning-up">Cleaning up</a></li> <li><a href="#rolling-builds">Rolling builds</a></li> </ul></li> <li><a href="#markdown-files">Markdown files</a></li> <li><a href="#files-in-wwwsitename">Files in www/sitename/</a></li> <li><a href="#wwwsitenamesite.cfg">www/sitename/site.cfg</a> <ul> <li><a href="#lazy">LAZY</a></li> <li><a href="#defaultlang">DEFAULTLANG</a></li> <li><a href="#blogdir">BLOGDIR</a></li> <li><a href="#domain">DOMAIN</a></li> <li><a href="#css">CSS</a></li> <li><a href="#title">TITLE</a></li> <li><a href="#sitemap">SITEMAP</a></li> </ul></li> <li><a href="#sitetemplate.include">site/template.include</a></li> <li><a href="#sitenav.include">site/nav.include</a></li> <li><a href="#siteglobal.css">site/global.css</a></li> <li><a href="#sitesitemap.html">site/sitemap.html</a></li> <li><a href="#sitesitemap.include">site/sitemap.include</a></li> <li><a href="#sitefooter.include">site/footer.include</a></li> <li><a href="#rules-for-markdown-files">Rules for Markdown files</a> <ul> <li><a href="#toc-table-of-contents">TOC (Table of Contents)</a></li> <li><a href="#file.nav">file.nav</a></li> <li><a href="#file.css">file.css</a></li> <li><a href="#file.template">file.template</a></li> <li><a href="#file.footer">file.footer</a></li> </ul></li> <li><a href="#news-sections">News sections</a> <ul> <li><a href="#rules-for-news-pages">Rules for news pages</a></li> <li><a href="#manifest">MANIFEST</a></li> <li><a href="#news-list.md.include">news-list<em>.</em>md.include</a></li> <li><a href="#index.md-and-index.html">index<em>.</em>md and index.html</a></li> <li><a href="#news.cfg">news.cfg</a></li> <li><a href="#rss-files">RSS files</a></li> </ul></li> <li><a href="#translated-pages">Translated pages</a> <ul> <li><a href="#set-a-default-language">Set a default language</a></li> <li><a href="#how-to-translate-pages">How to translate pages</a></li> <li><a href="#translations-done-automatically">Translations done automatically</a> <ul> <li><a href="#file.md-file.pt.md-file.pl.md">file<em>.</em>md, file.pt<em>.</em>md, file.pl<em>.</em>md</a></li> <li><a href="#file.pt.md-file.pl.md">file.pt<em>.</em>md, file.pl<em>.</em>md</a></li> </ul></li> <li><a href="#template.language.include">template.LANGUAGE.include</a></li> <li><a href="#file.language.template">file.LANGUAGE.template</a></li> <li><a href="#nav.language.include">nav.LANGUAGE.include</a></li> <li><a href="#file.language.nav">file.LANGUAGE.nav</a></li> <li><a href="#footer.language.include">footer.LANGUAGE.include</a></li> <li><a href="#file.language.footer">file.LANGUAGE.footer</a></li> <li><a href="#file.language.css">file.LANGUAGE.css</a></li> </ul></li> <li><a href="#langxxstrings.cfg">lang/xx/strings.cfg</a> <ul> <li><a href="#add-new-language-support">Add new language support</a></li> <li><a href="#langname">LANGNAME</a></li> <li><a href="#langselstr">LANGSELSTR</a></li> <li><a href="#backlink_prevdir">BACKLINK_PREVDIR</a></li> <li><a href="#backlink_currentdir">BACKLINK_CURRENTDIR</a></li> <li><a href="#published_by">PUBLISHED_BY</a></li> <li><a href="#publication_date">PUBLICATION_DATE</a></li> <li><a href="#markdown_link">MARKDOWN_LINK</a></li> <li><a href="#rss_link">RSS_LINK</a></li> <li><a href="#sitemap_link">SITEMAP_LINK</a></li> <li><a href="#shameless_plug">SHAMELESS_PLUG</a></li> <li><a href="#pdir">PDIR</a></li> </ul></li> <li><a href="#other-files">Other files</a></li> <li><a href="#regarding-untitled---lbssg-transition">Regarding Untitled -> lbssg transition</a></li> </ul> </nav> <div class="pagetext"> <p><a href="../">Return to previous index</a></p> <div class="h"><h2 id="home-of-your-favourite-firmware-to-boot-gnu-linux">Home of your favourite firmware to boot GNU / Linux</h2><a aria-hidden="true" href="#home-of-your-favourite-firmware-to-boot-gnu-linux">[link]</a></div> <p>This document describes the <em>static site generator</em>, which is used to build the Libreboot website; it was previously called the <em>Untitled Static Site Generator</em> and hosted separately, but it is now an official component of the Libreboot project, since 25 January 2025.</p> <p>This static site generator is simply called the <em>Libreboot Static Site Generator</em>, or just <em>lbssg</em> for short. It can be used for any number of websites, and is in fact used elsewhere, but it is primarily used <em>by</em> and developed <em>for</em> the Libreboot project.</p> <p>The Git repository is now <code>lbssg.git</code>, which you can find linked on the <a href="../../git.html">Git page</a>.</p> <div class="h"><h2 id="websites-made-easy">Websites made easy</h2><a aria-hidden="true" href="#websites-made-easy">[link]</a></div> <p>This software is written in POSIX shell (<code>sh</code>) scripts, and uses Pandoc to generate HTML from Markdown files. It is designed to be stupidly simple, allowing Free and Open Source Software projects to easily host any number of websites.</p> <p>It is a <em>multi-site</em> static site generator; a single instance of LBSSG can handle an unlimited number of websites, all with different <em>templates</em> in Pandoc (for different page layouts), CSS files, footer, header, navigation and more.</p> <p>With lbssg, it is possible to generate an unlimited number of <em>news</em> pages and <em>blogs</em>, with auto-generated RSS feeds.</p> <p>The variant of markdown is the Pandoc variant, which you can read about here:<br /> <a href="https://pandoc.org/MANUAL.html" class="uri">https://pandoc.org/MANUAL.html</a></p> <p>The <em>templates</em> feature in Pandoc is really what makes lbssg very powerful. You can make any number of websites, with many different designs, using Pandoc templates. This is precisely why lbssg uses Pandoc. See:<br /> <a href="https://pandoc.org/MANUAL.html#templates" class="uri">https://pandoc.org/MANUAL.html#templates</a></p> <p>Pandoc’s <em>smart</em> mode is used. In this mode, it is possible to use HTML inside Markdown files. For example, if you want to embed videos, use iframes, use JavaScript and more.</p> <p>lbssg is <em>Free Software</em>, released under the terms of the GNU General Public License, version 3 of the license or, at your option, any later version as published by the Free Software Foundation. You can find a copy of this license in the <code>COPYING</code> file, when you download lbssg, or you can read it here:<br /> <a href="https://www.gnu.org/licenses/gpl-3.0.en.html" class="uri">https://www.gnu.org/licenses/gpl-3.0.en.html</a></p> <p>(some parts of it are under the MIT license)</p> <p>Learn more about Free Software:<br /> <a href="https://writefreesoftware.org/" class="uri">https://writefreesoftware.org/</a>.</p> <div class="h"><h3 id="real-world-examples">Real-world examples</h3><a aria-hidden="true" href="#real-world-examples">[link]</a></div> <p>Here are some websites built using the Libreboot Static Site Generator:</p> <ul> <li><a href="https://canoeboot.org/" class="uri">https://canoeboot.org/</a> (Libreboot fork maintained by Leah Rowe)</li> <li><a href="https://fedfree.org/" class="uri">https://fedfree.org/</a> (Leah Rowe’s self-hosted servers tutorial website)</li> <li><a href="https://libreboot.org/" class="uri">https://libreboot.org/</a> (Libreboot project, maintained by Leah Rowe)</li> <li><a href="https://trans.chat/" class="uri">https://trans.chat/</a> (Leah Rowe’s transgender advocacy website)</li> <li><a href="https://vimuser.org/" class="uri">https://vimuser.org/</a> (Leah Rowe’s personal blog)</li> </ul> <div class="h"><h2 id="requirements">Requirements</h2><a aria-hidden="true" href="#requirements">[link]</a></div> <p>Libreboot Static Site Generator is designed to be stupidly simple. You need:</p> <ul> <li>Unix-based operating system e.g. Linux-based distro, OpenBSD, FreeBSD. Etc</li> <li>Pandoc</li> <li>Web server (nginx or OpenBSD httpd recommended)</li> <li>Any implementation of these Unix utilities: <code>sh</code>, <code>find</code>, <code>grep</code> and <code>sed</code>.</li> </ul> <div class="h"><h3 id="posix-compatibility">POSIX compatibility</h3><a aria-hidden="true" href="#posix-compatibility">[link]</a></div> <p>As of revision <code>9cc6f5dc7349b7f339f99c84789b6c62ea7bb1c7</code> on 4 December 2023, lbssg works with any POSIX <code>sh</code> implementation. Various utilities like Sed, Find (that are POSIX) are now used in a POSIX way. This means that lbssg can be used on pretty much any Unix system such as GNU+Linux, Alpine Linux, Chimera Linux, BSDs like OpenBSD or FreeBSD, and so on. Older revisions only worked with GNU tools, but the newer revision also still works with GNU tools. Older revisions of lbssg were written in <code>bash</code>, not <code>sh</code>.</p> <div class="h"><h2 id="security-notes">Security notes</h2><a aria-hidden="true" href="#security-notes">[link]</a></div> <p>USE THIS SOFTWARE AT YOUR OWN RISK. A FULL SECURITY AUDIT IS NEEDED.</p> <p>Symlinks are intentionally unsupported, and <em>ignored</em>, in site directories handled by lbssg. This is for security reasons. If you find that symlinks are permitted, in any way, it’s a bug and you should report it!</p> <p>At the very least, you are advised to take the following precautions</p> <ul> <li>It is HIGHLY recommended that you run lbssg in a heavily chrooted environment, if you’re using this on a production web server.</li> <li>Disable symlinks in your web server</li> </ul> <p>DO NOT use lbssg in a shared hosting environment, especially on a crontab or other automated setup. You, the operator, must ensure full control of all sites handled by your lbssg installation. For the time being, this is recommended until lbssg is full audited for security, and modified accordingly. Efforts have already been made, but this software is very new and requires a lot of testing. In general, you should consider lbssg to be <em>alpha</em> quality, at best. It is not yet ready for a stable release; it is currently only <em>rolling release</em>, hosted in a Git repository.</p> <p>lbssg only allows sites to be processed under <code>www/</code> in the current working directory. You may choose to put <code>www/</code> under the git clone of lbssg itself. Or you could specify the full path to the <code>build</code> script and process files in a <code>www/</code> elsewhere.</p> <div class="h"><h2 id="getting-started">Getting started</h2><a aria-hidden="true" href="#getting-started">[link]</a></div> <p>Simply make a directory named <code>www/</code> somewhere.</p> <p>In <code>www/</code>, make a directory <em>per website</em>. For each website, set <code>www/sitename/site/</code> as the document root in your web server. lbssg expects this <code>site</code> directory to exist.</p> <div class="h"><h3 id="example-website">Example website</h3><a aria-hidden="true" href="#example-website">[link]</a></div> <p>Check the <code>www-example</code> directory, for an example website. Also look at the logic in the file named <code>build</code>, in the main directory of the untitled static site generator.</p> <p>The Libreboot website is also hosted in a Git repository, if you want a real-world example of a website that uses lbssg.</p> <div class="h"><h2 id="how-to-use">How to use</h2><a aria-hidden="true" href="#how-to-use">[link]</a></div> <p>You should use a normal Unix shell (<code>sh</code> implementations such as KSH, BASH, ZSH, CSH etc will all work). This, along with Pandoc.</p> <p>See: <a href="https://pandoc.org/" class="uri">https://pandoc.org/</a></p> <p>You must then install a web server. The document root for your domain should point to the <code>www/sitename/site</code> directory, where <code>sitename</code> is the name of your site, e.g. <code>libreboot</code>, and <code>www/</code> is created under your instance of lbssg.</p> <p>The way lbssg is designed, you use it directly, running directly on the server that then hosts the HTML files. However, it is possible to use it in other ways; for example, you could rsync the resulting files over ssh, to your server, while running lbssg locally. It’s up to you.</p> <div class="h"><h3 id="generate-entire-websites">Generate entire websites</h3><a aria-hidden="true" href="#generate-entire-websites">[link]</a></div> <p>For security reasons, lbssg will only operate on sites under <code>www/sitename/</code> where <code>sitename</code> can be anything.</p> <p>To interact with <code>untitled</code>, your current working directory should be the main directory <em>of untitled</em>, <em>not your website</em>. In that directory, the file named <code>build</code> and the file named <code>clean</code> will exist.</p> <p>You can have untitled go through an entire website and, if it detects that such an action is needed, it will build each page. It will check whether a page needs to be built. For example, if it was already built and no changes were made, it will skip that page. It does this, using <code>date -r file +%s</code> to check file modification dates. Files ending in <code>.date</code> are created, for files that are tracked by lbssg.</p> <p>For a given directory name under <code>www/</code>, do this:</p> <pre><code>./build sites www/directoryname</code></pre> <p>You can also do:</p> <pre><code>./build sites directoryname</code></pre> <p>For example, if your website was hosted at www/foobar:</p> <pre><code>./build sites foobar</code></pre> <p>This will only work if your website is set up correctly. Look at the example website in <code>www-example/</code> and read the sections below.</p> <p>To build <em>all</em> available websites under <code>www/</code>, just run it without an argument:</p> <pre><code>./build sites</code></pre> <p>You can specify <em>multiple</em> websites. For example:</p> <pre><code>./build sites blogsite catblogsite</code></pre> <p>In this example, the following sites would be built:</p> <ul> <li><code>www/blogsite</code></li> <li><code>www/catblogsite</code></li> </ul> <p>NOTE: If you simply run <code>./build</code> without any arguments, the <code>./build sites</code> command will be executed.</p> <div class="h"><h3 id="build-specific-pages">Build specific pages</h3><a aria-hidden="true" href="#build-specific-pages">[link]</a></div> <p>These commands will only operate on pages under <code>www/sitename/</code> where <code>sitename</code> can be anything. This is for security reasons.</p> <p>If you want to save time (e.g. if you’re just editing a few pages), you can skip checking the entire site (or sites) and update just that page. Use this command:</p> <pre><code>./build pages www/sitename/site/path/to/page.html</code></pre> <p>You can also do:</p> <pre><code>./build pages sitename/path/to/page.html</code></pre> <p>lbssg will automatically correct the path, if <code>www/</code> and <code>site/</code> are missing from the path. For example, to update the homepage:</p> <pre><code>./build pages sitename/index.html</code></pre> <p>You can specify multiple pages, <em>on multiple sites</em>. For example:</p> <pre><code>./build pages joebloggsandhisdog/index.html janedoesblog/news/guitar.html</code></pre> <p>NOTE: the <code>mksitemap</code> and <code>mknews</code> functions are not automatically executed when running these commands.</p> <p>NOTE: if you run <code>./build pages</code> without specifying any paths to pages, then the <code>./build sites</code> command will be executed instead. However, if you specify paths and none exist, nothing will happen.</p> <p>NOTE: If you simply run <code>./build</code> without any arguments, the <code>./build sites</code> command will be executed.</p> <div class="h"><h3 id="cleaning-up">Cleaning up</h3><a aria-hidden="true" href="#cleaning-up">[link]</a></div> <p>If you want to un-make your site, such that the HTML files are purged, do this:</p> <pre><code>./clean</code></pre> <p>This will clean <em>all</em> sites. If you only want to clean a specific site, do this:</p> <pre><code>./clean sitename</code></pre> <p>(sitename would be located at <code>www/sitename/</code>, in this example)</p> <p>NOTE: an HTML file is only deleted if a corresponding Markdown file exists. This means that if you permanently delete a markdown file from your site, you should ensure that the HTML file is also delete dif you don’t want that file to be available anymore.</p> <div class="h"><h3 id="rolling-builds">Rolling builds</h3><a aria-hidden="true" href="#rolling-builds">[link]</a></div> <p>If you’re running lbssg directly, SSH’d into your httpd machine, you might want to update an entire website from scratch. This ordinarily means that you must run <code>./clean</code>, first - in other words, the website will be offline (HTML files deleted) while it re-builds.</p> <p>To prevent this, you can use <code>roll</code> instead of <code>build</code>. For example:</p> <pre><code>./roll sites libreboot</code></pre> <p>This also works with pages:</p> <pre><code>./roll pages libreboot/index.html</code></pre> <p>You can also do this without argument, as with <code>build</code>, and it would build everything. e.g.:</p> <pre><code>./roll ./roll sites ./roll pages</code></pre> <p>This is especially useful for very large websites, where an entire re-build might take 30 seconds or more.</p> <div class="h"><h2 id="markdown-files">Markdown files</h2><a aria-hidden="true" href="#markdown-files">[link]</a></div> <p>Write your markdown files, with file extensions ending in <strong><em>.</em>md</strong> and the build script will automatically see them. It will convert them into HTML, stripping off the <strong><em>.</em>md</strong> file extension and replacing it with <code>.html</code></p> <p>Place these markdown files anywhere under <code>www/sitename/site/</code> where <code>sitename</code> is whatever you named your website, per directory hierarchy rules of lbssg.</p> <p>Again, the <code>www-example</code> directory can be extremely useful if you want to play around first, before you make a real website with lbssg.</p> <div class="h"><h2 id="files-in-wwwsitename">Files in www/sitename/</h2><a aria-hidden="true" href="#files-in-wwwsitename">[link]</a></div> <p>These files affect the site globally, for each website under <code>www/</code></p> <p>Each site has its own directory: www/sitename/</p> <p><code>sitename</code> can be anything you want. e.g. <code>kittenblog</code></p> <div class="h"><h2 id="wwwsitenamesite.cfg">www/sitename/site.cfg</h2><a aria-hidden="true" href="#wwwsitenamesite.cfg">[link]</a></div> <p><strong>REQUIRED</strong></p> <p>sitename can be anything.</p> <p>site.cfg is the main configuration file for your website.</p> <p>Example entries (for libreboot.org):</p> <pre><code>TITLE="Libreboot" CSS="/global.css" DOMAIN="https://libreboot.org/" BLOGDIR="news/" DEFAULTLANG="en"</code></pre> <p>NOTE: Older versions of untitled had TITLE like this:</p> <pre><code>TITLE="-T Libreboot"</code></pre> <p>You must now omit the -T option, because it’s hardcoded in the build script.</p> <div class="h"><h3 id="lazy">LAZY</h3><a aria-hidden="true" href="#lazy">[link]</a></div> <p>If <code>LAZY="y"</code>, lazy image loading will be enabled. This is useful for conserving bandwidth. The default behaviour is <code>LAZY="n"</code> if not set to <code>"y"</code>. See:</p> <p><a href="https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading" class="uri">https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading</a></p> <div class="h"><h3 id="defaultlang">DEFAULTLANG</h3><a aria-hidden="true" href="#defaultlang">[link]</a></div> <p>This is optional. If unspecified, the default language will be English. Also, if this entry defines an unsupported language, lbssg will default to English.</p> <p>It specifies the default language, for your website. It may be that you have multiple languages available on your website, where <strong>file<em>.</em>md</strong> is your chosen language (e.g. German, Japanese, Englist) and <strong>file.xx<em>.</em>md</strong> is another language for the same page. xx can be anything.</p> <div class="h"><h3 id="blogdir">BLOGDIR</h3><a aria-hidden="true" href="#blogdir">[link]</a></div> <p>This is the directory for your main news section, if you have a news section. You do not need to declare this.</p> <p>The news section is only valid if it has the right files, in the directory specified here. You can actually have as many news/blog sections as you like, but this setting specifies the “main” one. For example, if you’re a software project you might have a news section, and a release section, and they might both be news pages. News pages have RSS feeds and indexes automatically generated by <code>untitled</code>.</p> <p>If your website is primarily a blog, you might leave this string empty. That way, your <em>home page</em> is the news index. In that scenario, you would not place an index file in the root of your website. Let <code>untitled</code> generate it for you!</p> <div class="h"><h3 id="domain">DOMAIN</h3><a aria-hidden="true" href="#domain">[link]</a></div> <p>This is the URL for the home page of your website.</p> <div class="h"><h3 id="css">CSS</h3><a aria-hidden="true" href="#css">[link]</a></div> <p>Specifies the .css stylesheet that is to be used. See above example. Just add an entry saying <code>/path/to/css/file</code> for the CSS file. The <code>/</code> is the root of your website, when viewed publicly. Basically, / would be the home page, and everything after that is relative. In other words, it is the URI of your CSS file.</p> <p>The actual domain name is not prefixed, when the CSS stylesheet path is given inside the generated HTML document.</p> <div class="h"><h3 id="title">TITLE</h3><a aria-hidden="true" href="#title">[link]</a></div> <p>Use the format above. Don’t use spaces or special characters. Just keep it simply. E.g. <code>-T Gardening</code></p> <p>This would usually be the name of your website, company, project or whatever else.</p> <div class="h"><h3 id="sitemap">SITEMAP</h3><a aria-hidden="true" href="#sitemap">[link]</a></div> <p>OPTIONAL.</p> <p>Write this in <code>site.cfg</code> for a given site:</p> <pre><code>SITEMAP="n"</code></pre> <p>If you do this, the sitemap will not be generated. lbssg will otherwise generate a sitemap, by default.</p> <div class="h"><h2 id="sitetemplate.include">site/template.include</h2><a aria-hidden="true" href="#sitetemplate.include">[link]</a></div> <p><strong>REQUIRED</strong></p> <p>Put a pandoc template here, in this file.</p> <p>There is an HTML5 template in <code>www-example/</code> which you can adapt for your site. TODO: make an xhtml template. Patches welcome!</p> <p>It is recommended that you put your common site navigation section in this file (formatted in HTML).</p> <div class="h"><h2 id="sitenav.include">site/nav.include</h2><a aria-hidden="true" href="#sitenav.include">[link]</a></div> <p><strong>optional</strong></p> <p>Put this in the root of <code>www/sitename/site/</code>. You can actually put whatever you want in here, but it can be used for a navigation menu. You could also use it to put a side-wide notice, on your website.</p> <p>Write this file in Markdown. You could also put a common navigation section in the template, and use <code>nav</code> files for site-wide announcements, or for announcements on specific pages. How you use lbssg is entirely up to you!</p> <div class="h"><h2 id="siteglobal.css">site/global.css</h2><a aria-hidden="true" href="#siteglobal.css">[link]</a></div> <p><strong>optional</strong></p> <p>The filename can actually be anything, for your CSS. In fact, it’s entirely optional. You can leave the CSS string empty in <code>site.cfg</code> and just have a site without CSS.</p> <p>The name <code>global.css</code> is merely what the example website (in <code>www-example/</code>) uses, but you don’t have to use this file name yourself.</p> <p>This file is for styling your pages (HTML ones, after building your Markdown files).</p> <p>w3schools has a nice set of tutorials for learning CSS:</p> <p><a href="https://www.w3schools.com/css/" class="uri">https://www.w3schools.com/css/</a></p> <div class="h"><h2 id="sitesitemap.html">site/sitemap.html</h2><a aria-hidden="true" href="#sitesitemap.html">[link]</a></div> <p>The file named <strong>sitemap<em>.</em>md</strong> will be automatically generated, which is then assembled into <code>sitemap.html</code>. This file will sit on the root directory of your website.</p> <p>Do not manually create these files. They are automatically generated by lbssg. They simply index your entire website.</p> <p>NOTE: It only looks at pages where a Markdown file exists. It ignores pages where an HTML page exists but a Markdown page doesn’t.</p> <div class="h"><h2 id="sitesitemap.include">site/sitemap.include</h2><a aria-hidden="true" href="#sitesitemap.include">[link]</a></div> <p><strong>optional</strong></p> <p>This file MUST be included if you want a sitemap with your own text.</p> <p>If this file is missing, a sitemap will be generated but it will contain a generic header on the page.</p> <p>Simply put a title and some text in here. lbssg and Pandoc will do the rest!</p> <div class="h"><h2 id="sitefooter.include">site/footer.include</h2><a aria-hidden="true" href="#sitefooter.include">[link]</a></div> <p><strong>optional</strong></p> <p>If present, this will add a common footer to every page on your website. Write it in Markdown.</p> <div class="h"><h2 id="rules-for-markdown-files">Rules for Markdown files</h2><a aria-hidden="true" href="#rules-for-markdown-files">[link]</a></div> <p>This applies to any <strong><em>.</em>md</strong> file under <code>www/sitename/site/</code> where <code>sitename</code> is whatever you named your website, per directory hiearchy rules.</p> <p>The file named <strong>file<em>.</em>md</strong> will be converted into HTML and copied (in HTML format) to <code>file.html</code>.</p> <p>When you link to other pages, use absolute links or relative links, but don’t link to the <code>.html</code> pages. Link directly to the <strong><em>.</em>md</strong> files. lbssg static site generator will use Sed to replace these with .html when generating the HTML pages (it only skips replacing <em>external</em> links, e.g. <code>https://example.com/cats.md</code></p> <div class="h"><h3 id="toc-table-of-contents">TOC (Table of Contents)</h3><a aria-hidden="true" href="#toc-table-of-contents">[link]</a></div> <p>See pages in <code>www-example/</code> or example websites linked above (such as the Libreboot project website). Look in the markdown files for those sites, on pages that specify <code>x-toc-enable: true</code>. This is a special directive for the Pandoc variant of Markdown. Some other Markdown parsers/generators will also generate a table of contents.</p> <p>In the untitled static site generator, when a TOC is enabled, the depth is 4. This means that, in HTML, the h1, h2, h3 and h4 tags will show up on the TOC. The TOC is generated <em>based on</em> how you use headers in Markdown, and how they ultimately end up when converted into HTML.</p> <div class="h"><h3 id="file.nav">file.nav</h3><a aria-hidden="true" href="#file.nav">[link]</a></div> <p>If present, the page from <strong>file<em>.</em>md</strong> will have its own navigation menu, which will override the default nav.include file.</p> <p>This can be anything. Write it in Markdown. For example, you could use this to put announcements on a page.</p> <div class="h"><h3 id="file.css">file.css</h3><a aria-hidden="true" href="#file.css">[link]</a></div> <p>Where you have <strong>file<em>.</em>md</strong>, you can also include <code>file.css</code>, and this CSS file will be applied specifically to that page.</p> <p>This does not replace any global CSS files that you specified in <code>site.cfg</code>. It is applied <em>after</em> that one. One possible use-case for this is if you have an otherwise decent CSS file for your site, but you need to override certain rules on a specific page.</p> <div class="h"><h3 id="file.template">file.template</h3><a aria-hidden="true" href="#file.template">[link]</a></div> <p>Where you have your Markdown file, strip off the <code>md</code>, you create a new file with the same name but with <code>.template</code> file extension. This will override the default, global template, for that page only.</p> <div class="h"><h3 id="file.footer">file.footer</h3><a aria-hidden="true" href="#file.footer">[link]</a></div> <p>If present, this replaces the global footer for the specific page.</p> <div class="h"><h2 id="news-sections">News sections</h2><a aria-hidden="true" href="#news-sections">[link]</a></div> <p>This section defines what files should be placed in directories that are to be news sections. For instance, you might have a directory on your website named <code>news/</code>, and you would place these files in that directory.</p> <p>An index page will be automatically generated, so don’t bother making one yourself. Simply write your news pages. Read the notes below for how to set up news sections on your website.</p> <p>An RSS feed will also be generated, for every news section.</p> <p><em>You can have as many news sections as you would like!</em></p> <div class="h"><h3 id="rules-for-news-pages">Rules for news pages</h3><a aria-hidden="true" href="#rules-for-news-pages">[link]</a></div> <p>A table of contents is always enabled, on news pages (but not the news index), unless you want it to be so. Technically, news indexes have a TOC but the page isn’t formatted such that a TOC will appear when Pandoc does its thing.</p> <p>Start your news page like so, in the Markdown file e.g. <strong>www/catblog/site/news/spots-birthday<em>.</em>md</strong></p> <pre><code>% Page title % Author name % Date Page text goes here</code></pre> <div class="h"><h3 id="manifest">MANIFEST</h3><a aria-hidden="true" href="#manifest">[link]</a></div> <p>Place this file in the root of the directory where you want there to be a news section.</p> <p>The order of the file names dictate what order the links will appear in, on the news index that is automatically generated (see below).</p> <div class="h"><h3 id="news-list.md.include">news-list<em>.</em>md.include</h3><a aria-hidden="true" href="#news-list.md.include">[link]</a></div> <p>This will have a page title, and introductory text. When the index page is generated (see below), the resulting index will include the contents of this file, and then links to each page per the contents of <code>MANIFEST</code>.</p> <div class="h"><h3 id="index.md-and-index.html">index<em>.</em>md and index.html</h3><a aria-hidden="true" href="#index.md-and-index.html">[link]</a></div> <p>Do not place these files in directories containing a MANIFEST file. These will be generated automatically, with an index linking to news articles.</p> <div class="h"><h3 id="news.cfg">news.cfg</h3><a aria-hidden="true" href="#news.cfg">[link]</a></div> <p>In this file, write the following lines:</p> <pre><code>BLOGTITLE="The daily grind" BLOGDESCRIPTION="Hot takes, juicy gossip and everything inbetween!"</code></pre> <p>You can change these strings to whatever you want. Keep it simple! For example:</p> <pre><code>BLOGTITLE="Bianca's worldly musings" BLOGDESCRIPTION="Come see what I'm thinking about! I have many thoughts"</code></pre> <p>For news about your software project, you might say:</p> <pre><code>BLOGTITLE="Project announcements" BLOGDESCRIPTION="News about ongoing development will be documented here"</code></pre> <div class="h"><h3 id="rss-files">RSS files</h3><a aria-hidden="true" href="#rss-files">[link]</a></div> <p>Files ending in <code>.rss</code> are automatically generated, if you have news sections.</p> <div class="h"><h2 id="translated-pages">Translated pages</h2><a aria-hidden="true" href="#translated-pages">[link]</a></div> <p>lbssg supports having translated pages.</p> <p>Here is an example of a website with multiple translations available, built using untitled:<br /> <a href="https://trans.chat/" class="uri">https://trans.chat/</a></p> <div class="h"><h3 id="set-a-default-language">Set a default language</h3><a aria-hidden="true" href="#set-a-default-language">[link]</a></div> <p>English is the default in lbssg, but you can <em>change</em> the default language! For example, you might want a Chinese-language website but offer translated pages in German. lbssg will happily let you do this!</p> <p>Simply set the <code>DEFAULTLANG</code> entry in <code>site.cfg</code>.</p> <div class="h"><h3 id="how-to-translate-pages">How to translate pages</h3><a aria-hidden="true" href="#how-to-translate-pages">[link]</a></div> <p>The way it works is quite simple:</p> <ul> <li><strong>file<em>.</em>md</strong> is the original file, in your default language. The <em>default</em> default language is English (en), but it can be anything.</li> <li><strong>file.xx<em>.</em>md</strong> is the translated file. xx can be anything, e.g. de, nl, pt</li> <li><code>.include</code> files (footers, nav files, templates etc) are for your default language</li> <li><code>.xx.include</code> is the translated file. again, xx can be anything e.g. de, nl</li> </ul> <p>For translated pages, if a translated <code>.include</code> file is unavailable, the default-language one will be used.</p> <p>You can <em>also</em> do this per-page. For example, you might override the default footer on a page, by including <code>file.footer</code>. In this situation, <strong>file.de<em>.</em>md</strong> will also use <code>file.footer</code>. HOWEVER, you can include <code>file.de.footer</code> aswell, if you so choose!</p> <div class="h"><h3 id="translations-done-automatically">Translations done automatically</h3><a aria-hidden="true" href="#translations-done-automatically">[link]</a></div> <p>Translations are handled <em>automatically</em>, <em>per page</em>. It does not happen globally; this way, a website doesn’t have to have translated versions of each page. In Let’s look at example scenarios:</p> <h4 id="file.md-file.pt.md-file.pl.md">file<em>.</em>md, file.pt<em>.</em>md, file.pl<em>.</em>md</h4> <p>In this example, a language menu will appear on each of these pages, allowing selection of DEFAULT(e.g. English), Polish or Portuguese</p> <h4 id="file.pt.md-file.pl.md">file.pt<em>.</em>md, file.pl<em>.</em>md</h4> <p>In this example, no <em>default</em> page is included, but Polish and Portuguese are available. In this example, Portuguese and Polish will be available in a language select menu on each page.</p> <div class="h"><h3 id="template.language.include">template.LANGUAGE.include</h3><a aria-hidden="true" href="#template.language.include">[link]</a></div> <p>This is <em>optional</em>, so long as <code>template.include</code> is included. The translated file will override. This will override the default template, on the specified language.</p> <p>For example: <code>site/template.de.include</code></p> <div class="h"><h3 id="file.language.template">file.LANGUAGE.template</h3><a aria-hidden="true" href="#file.language.template">[link]</a></div> <p>You might have <code>file.template</code> overriding the default global <code>template.include</code> or <code>template.LANGUAGE.include</code> for a given page.</p> <p>lbssg <em>also</em> lets you override it on a specific <em>translation</em> of that page!</p> <p>For example: <code>site/file.de.template</code></p> <div class="h"><h3 id="nav.language.include">nav.LANGUAGE.include</h3><a aria-hidden="true" href="#nav.language.include">[link]</a></div> <p>Override the default global navigation file, for a given website and a given language.</p> <p>For example: <code>site/nav.de.include</code></p> <div class="h"><h3 id="file.language.nav">file.LANGUAGE.nav</h3><a aria-hidden="true" href="#file.language.nav">[link]</a></div> <p>You might have <code>file.nav</code> overriding the default global <code>nav.include</code> or <code>nav.LANGUAGE.include</code> for a given page.</p> <p>lbssg <em>also</em> lets you override it on a specific <em>translation</em> of that page!</p> <p>For example: <code>site/file.de.nav</code></p> <div class="h"><h3 id="footer.language.include">footer.LANGUAGE.include</h3><a aria-hidden="true" href="#footer.language.include">[link]</a></div> <p>Override the default global footer file, for a given website, on a given language.</p> <p>For example: <code>site/footer.de.include</code></p> <div class="h"><h3 id="file.language.footer">file.LANGUAGE.footer</h3><a aria-hidden="true" href="#file.language.footer">[link]</a></div> <p>You might have <code>file.footer</code> overriding the default global <code>footer.include</code> or <code>footer.LANGUAGE.include</code> for a given page.</p> <p>lbssg <em>also</em> lets you override it on a specific <em>translation</em> of that page!</p> <p>For example: <code>site/file.de.footer</code></p> <div class="h"><h3 id="file.language.css">file.LANGUAGE.css</h3><a aria-hidden="true" href="#file.language.css">[link]</a></div> <p>You might have <code>file.css</code> available for <strong>file<em>.</em>md</strong>. If <strong>page.LANGUAGE<em>.</em>md</strong> exists, <code>file.LANGUAGE.css</code> will still be added to that page, but that page can also have its own <code>file.LANGUAGE.css</code>.</p> <p>The <code>file.LANGUAGE.css</code> file does not override <code>file.css</code>. It is merely added.</p> <p>If <code>file.LANGUAGE.css</code> exists but <code>file.css</code> does not, it will still be applied, but only on <strong>file.LANGUAGE<em>.</em>md</strong>.</p> <div class="h"><h2 id="langxxstrings.cfg">lang/xx/strings.cfg</h2><a aria-hidden="true" href="#langxxstrings.cfg">[link]</a></div> <div class="h"><h3 id="add-new-language-support">Add new language support</h3><a aria-hidden="true" href="#add-new-language-support">[link]</a></div> <p>On language menus, if a language is unsupported, the two-letter code will be used. For example, if Russian is unsupported, <code>ru</code> will be the anchor text for selecting Russian, but you can still select it.</p> <p>In untitled, you can see the file <code>lang/en/strings.cfg</code>.</p> <p>In there, you will also see translated ones, e.g. <code>lang/pl/strings.cfg</code>.</p> <p>If one does not exist for your language, you can create one. Patches welcome!</p> <p>Check <code>lang/en/strings.cfg</code> to see how it should be done! Entries in <code>strings.cfg</code> are as follows:</p> <p>Example <code>strings.cfg</code> file:</p> <div class="h"><h3 id="langname">LANGNAME</h3><a aria-hidden="true" href="#langname">[link]</a></div> <p>This is the anchor text for a given language, on a language select menu, if a site is to have translations. For example, <code>de</code> would be <code>Deutsch</code> here, for the German language.</p> <p>Example strings:</p> <ul> <li>Deutsch</li> <li>English</li> <li>Nederlands</li> <li>Espanol</li> </ul> <div class="h"><h3 id="langselstr">LANGSELSTR</h3><a aria-hidden="true" href="#langselstr">[link]</a></div> <p>This is the text for the language selection menu. <strong>Currently not used</strong></p> <p>E.g. “Select language:”</p> <div class="h"><h3 id="backlink_prevdir">BACKLINK_PREVDIR</h3><a aria-hidden="true" href="#backlink_prevdir">[link]</a></div> <p>This is the index link, for the previous directory. This link should be <code>../</code></p> <div class="h"><h3 id="backlink_currentdir">BACKLINK_CURRENTDIR</h3><a aria-hidden="true" href="#backlink_currentdir">[link]</a></div> <p>This is the index link, for the current directory. The link should be <code>./</code></p> <div class="h"><h3 id="published_by">PUBLISHED_BY</h3><a aria-hidden="true" href="#published_by">[link]</a></div> <p>For news pages, this string says e.g. “Article published by:”</p> <div class="h"><h3 id="publication_date">PUBLICATION_DATE</h3><a aria-hidden="true" href="#publication_date">[link]</a></div> <p>For news pages, this string says e.g. “Article published on:”</p> <div class="h"><h3 id="markdown_link">MARKDOWN_LINK</h3><a aria-hidden="true" href="#markdown_link">[link]</a></div> <p>This is the anchor text for the Markdown link, to each Markdown file. lbssg displays the link to the original Markdown file, for each page, on each given page.</p> <div class="h"><h3 id="rss_link">RSS_LINK</h3><a aria-hidden="true" href="#rss_link">[link]</a></div> <p>This is the anchor text for the default feed, if a news feed is generated on a given site.</p> <p>The link should be <code>/feed.xml</code></p> <div class="h"><h3 id="sitemap_link">SITEMAP_LINK</h3><a aria-hidden="true" href="#sitemap_link">[link]</a></div> <p>This is a Markdown link to the site map, if one is included on a given site.</p> <p>The link should be <code>/sitemap.html</code></p> <div class="h"><h3 id="shameless_plug">SHAMELESS_PLUG</h3><a aria-hidden="true" href="#shameless_plug">[link]</a></div> <p>At the bottom of each page, a string of text can be inserted. By default, this is a string that says the page was generated by the lbssg Static Site Generator, along with a link to the lbssg website.</p> <div class="h"><h3 id="pdir">PDIR</h3><a aria-hidden="true" href="#pdir">[link]</a></div> <p>The <code>PDIR</code> option should be <code>ltr</code> or <code>rtl</code>. This defines which order the text should be in. Some languages, such as Arabic and Hebrew, are right-to-left languages instead of left-to-right.</p> <div class="h"><h2 id="other-files">Other files</h2><a aria-hidden="true" href="#other-files">[link]</a></div> <p>Libreboot static site generator only cares about the files specified on this page. It ignores all other files.</p> <p>For things like images, videos and other binary files, it is recommended that you create a specific directory or subdomain for them, and have only markdown files on your lbssg website.</p> <p>However, it’s up to you how you run your infrastructure.</p> <p>It is recommended that you use a Git repository to host your website. Then you can easily keep track of changes to your site. You would use a static version of lbssg on your server, and just build new changes to your site whenever you push them. This is actually <em>why</em> the <code>site/</code> directory is enforced under the <code>www/sitename/</code> directory for each site, so as to encourage good practise (because by doing it this way, the <code>.git</code> directory will not be visible on your public web server. You do <em>not</em> want that directory to be visible!)</p> <div class="h"><h2 id="regarding-untitled---lbssg-transition">Regarding Untitled -> lbssg transition</h2><a aria-hidden="true" href="#regarding-untitled---lbssg-transition">[link]</a></div> <p>Untitled Static Site Generator renamed to Libreboot Static Site Generator and became part of the Libreboot project, on 25 January 2025.</p> <p>The entire website previously hosted at <strong>https://untitled.vimuser.org/</strong> has been fully assimilated into the Libreboot website.</p> <p>The old Untitled Static Site Generator git repositories were:</p> <ul> <li><a href="https://codeberg.org/vimuser/untitled" class="uri">https://codeberg.org/vimuser/untitled</a></li> <li><a href="https://codeberg.org/vimuser/untitled-website" class="uri">https://codeberg.org/vimuser/untitled-website</a></li> <li><a href="https://notabug.org/untitled/untitled" class="uri">https://notabug.org/untitled/untitled</a></li> <li><a href="https://notabug.org/untitled/untitled-website" class="uri">https://notabug.org/untitled/untitled-website</a></li> </ul> <p>The old repositories have been retained, but are now archived. You can find the new <em>lbssg</em> repositories linked from the <a href="../../git.html">Libreboot Git page</a>.</p> <div id="footer"> <hr /> <ul> <li><a href="/news/policy.html">Binary Blob Reduction Policy</a></li> <li><a href="/freedom-status.html">Freedom status</a></li> <li><a href="https://canoeboot.org/">Canoeboot</a></li> <li><a href="/git.html">Edit this page</a></li> <li><a href="/license.html">License</a></li> <li><a href="/template-license.html">Template</a></li> <li><a href="/logo-license.html">Logo</a></li> <li><a href="/contrib.html">Authors</a></li> </ul> <hr /> </div> <p>Markdown file for this page: <a href="https://libreboot.org/docs/sitegen/index.md" class="uri">https://libreboot.org/docs/sitegen/index.md</a></p> <p><a href="/feed.xml">Subscribe to RSS for this site</a></p> <p><a href="/sitemap.html">Site map</a></p> <p>This HTML page was generated by the <a href="https://libreboot.org/docs/sitegen/">Libreboot Static Site Generator</a>.</p> </div> </div> </body> </html>