You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

520 lines
57 KiB

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>YBlog - Hakyll setup</title>
<meta name="keywords" content="programming, hakyll, Haskell, nanoc" />
<link rel="shortcut icon" type="image/x-icon" href="../../../../Scratch/img/favicon.ico" />
<link rel="stylesheet" type="text/css" href="/css/y.css" />
<link rel="stylesheet" type="text/css" href="/css/legacy.css" />
<link rel="alternate" type="application/rss+xml" title="RSS" href="/rss.xml" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="apple-touch-icon" href="../../../../Scratch/img/about/FlatAvatar@2x.png" />
<!--[if lt IE 9]>
<script src="http://ie7-js.googlecode.com/svn/version/2.1(beta4)/IE9.js"></script>
<![endif]-->
<!-- IndieAuth -->
<link href="https://twitter.com/yogsototh" rel="me">
<link href="https://github.com/yogsototh" rel="me">
<link href="mailto:yann.esposito@gmail.com" rel="me">
<link rel="pgpkey" href="../../../../pubkey.txt">
</head>
<body lang="en" class="article">
<div id="content">
<div id="header">
<div id="choix">
<span id="choixlang">
<a href="../../../../Scratch/fr/blog/Hakyll-setup/">French</a>
</span>
<span class="tomenu"><a href="#navigation">↓ Menu ↓</a></span>
<span class="flush"></span>
</div>
</div>
<div id="titre">
<h1>Hakyll setup</h1>
</div>
<div class="flush"></div>
<div id="afterheader" class="article">
<div class="corps">
<div>
<img src="../../../../Scratch/img/blog/Hakyll-setup/main.png" alt="Main image" />
</div>
<div class="intro">
<p><span class="sc"><abbr title="Too long; didn't read">tl;dr</abbr>: </span> How I use <a href="http://jaspervdj.be/hakyll">hakyll</a>. Abbreviations, typography corrections, multi-language, use <code>index.html</code>, etc…</p>
</div>
<p>This website is done with <a href="http://jaspervdj.be/hakyll">Hakyll</a>.</p>
<p><a href="http://jaspervdj.be/hakyll">Hakyll</a> can be considered as a minimal <span class="sc"><abbr title="Content Management System">cms</abbr></span>. But more generally it is a library helping file generation. We can view it as an advanced build system (like <code>make</code>).</p>
<p>From the user perspective I blog this way:</p>
<ol type="1">
<li>I open an editor (vim in my case) and edit a markdown file. It looks like this</li>
</ol>
<div class="sourceCode" id="cb1"><pre class="sourceCode markdown"><code class="sourceCode markdown"><a class="sourceLine" id="cb1-1" title="1">A First Level Header</a>
<a class="sourceLine" id="cb1-2" title="2">====================</a>
<a class="sourceLine" id="cb1-3" title="3"></a>
<a class="sourceLine" id="cb1-4" title="4">A Second Level Header</a>
<a class="sourceLine" id="cb1-5" title="5">---------------------</a>
<a class="sourceLine" id="cb1-6" title="6"></a>
<a class="sourceLine" id="cb1-7" title="7">Who would cross the Bridge of Death must answer me</a>
<a class="sourceLine" id="cb1-8" title="8">these questions three, ere the other side he see.</a>
<a class="sourceLine" id="cb1-9" title="9">This is just a regular paragraph.</a>
<a class="sourceLine" id="cb1-10" title="10"></a>
<a class="sourceLine" id="cb1-11" title="11">Ask me the questions, bridgekeeper. I am not afraid.</a>
<a class="sourceLine" id="cb1-12" title="12"></a>
<a class="sourceLine" id="cb1-13" title="13"><span class="fu">### Header 3</span></a>
<a class="sourceLine" id="cb1-14" title="14"></a>
<a class="sourceLine" id="cb1-15" title="15">&gt;<span class="dt"> This is a blockquote.</span></a>
<a class="sourceLine" id="cb1-16" title="16"><span class="dt">&gt;</span></a>
<a class="sourceLine" id="cb1-17" title="17"><span class="dt">&gt; This is the second paragraph in the blockquote.</span></a>
<a class="sourceLine" id="cb1-18" title="18"><span class="dt">&gt;</span></a>
<a class="sourceLine" id="cb1-19" title="19"><span class="dt">&gt; ## This is an H2 in a blockquote</span></a></code></pre></div>
<ol start="2" type="1">
<li>I open a browser and reload time to time to see the change.</li>
<li>Once I finished I’ve written a very minimal script which mainly do a <code>git push</code>. My blog is hosted on <a href="http://github.com">github</a>.</li>
</ol>
<p>Being short sighted one could reduce the role of Hakyll to:</p>
<blockquote>
<p>create (resp. update) <span class="sc"><abbr title="HyperText Markup Language">html</abbr></span> file when I create (resp. change) a markdown file.</p>
</blockquote>
<p>While it sounds easy, there are a lot of hidden details:</p>
<ul>
<li>Add metadatas like keywords.</li>
<li>Create an archive page containing a list of all the posts.</li>
<li>Deal with static files.</li>
<li>Creating an <span class="sc"><abbr title="Rich Site Summary">rss</abbr></span> feed.</li>
<li>Filter the content with some function.</li>
<li>Dealing with dependencies.</li>
</ul>
<p>The work of Hakyll is to help you with these. But let’s start with the basic concepts.</p>
<h2 id="the-concepts-and-syntax">The concepts and syntax</h2>
<div>
<img src="../../../../Scratch/img/blog/Hakyll-setup/overview.png" alt="Overview" />
</div>
<p>For each file you create, you have to provide:</p>
<ul>
<li>a destination path</li>
<li>a list of content filters.</li>
</ul>
<p>First, let’s start with the simplest case: static files (images, fonts, etc…). Generally, you have a source directory (here is the current directory) and a destination directory <code>_site</code>.</p>
<p>The Hakyll code is:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb2-1" title="1"><span class="co">-- for each file in the static directory</span></a>
<a class="sourceLine" id="cb2-2" title="2">match <span class="st">&quot;static/*&quot;</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb2-3" title="3"> <span class="co">-- don't change its name nor directory</span></a>
<a class="sourceLine" id="cb2-4" title="4"> route idRoute</a>
<a class="sourceLine" id="cb2-5" title="5"> <span class="co">-- don't change its content</span></a>
<a class="sourceLine" id="cb2-6" title="6"> compile copyFileCompiler</a></code></pre></div>
<p>This program will copy <code>static/foo.jpg</code> to <code>_site/static/foo.jpg</code>. I concede this is a bit overkill for a simple <code>cp</code>. Now how to write a markdown file and generate an <span class="sc"><abbr title="HyperText Markup Language">html</abbr></span> one?</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb3-1" title="1"><span class="co">-- for each file with md extension in the &quot;posts/&quot; directory</span></a>
<a class="sourceLine" id="cb3-2" title="2">match <span class="st">&quot;posts/*.md&quot;</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb3-3" title="3"> <span class="co">-- change its extension to html</span></a>
<a class="sourceLine" id="cb3-4" title="4"> route <span class="op">$</span> setExtension <span class="st">&quot;html&quot;</span></a>
<a class="sourceLine" id="cb3-5" title="5"> <span class="co">-- use pandoc library to compile the markdown content into html</span></a>
<a class="sourceLine" id="cb3-6" title="6"> compile <span class="op">$</span> pandocCompiler</a></code></pre></div>
<p>If you create a file <code>posts/foo.md</code>, it will create a file <code>_site/posts/foo.html</code>.</p>
<p>If the file <code>posts/foo.md</code> contains</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode markdown"><code class="sourceCode markdown"><a class="sourceLine" id="cb4-1" title="1"><span class="fu"># Cthulhu</span></a>
<a class="sourceLine" id="cb4-2" title="2"></a>
<a class="sourceLine" id="cb4-3" title="3">ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn</a></code></pre></div>
<p>the file <code>_site/posts/foo.html</code>, will contain</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode html"><code class="sourceCode html"><a class="sourceLine" id="cb5-1" title="1"><span class="kw">&lt;h1&gt;</span>Cthulhu<span class="kw">&lt;/h1&gt;</span></a>
<a class="sourceLine" id="cb5-2" title="2"><span class="kw">&lt;p&gt;</span>ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn<span class="kw">&lt;/p&gt;</span></a></code></pre></div>
<p>But horror! <code>_site/posts/cthulhu.html</code> is not a complete <span class="sc"><abbr title="HyperText Markup Language">html</abbr></span> file. It doesn’t have any header nor footer, etc… This is where you use templates. I simply add a new directive in the compile block.</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb6-1" title="1">match <span class="st">&quot;posts/*.md&quot;</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb6-2" title="2"> route <span class="op">$</span> setExtension <span class="st">&quot;html&quot;</span></a>
<a class="sourceLine" id="cb6-3" title="3"> compile <span class="op">$</span> pandocCompiler</a>
<a class="sourceLine" id="cb6-4" title="4"> <span class="co">-- use the template with the current content</span></a>
<a class="sourceLine" id="cb6-5" title="5"> <span class="highlight"><span class="op">&gt;&gt;=</span> loadAndApplyTemplate <span class="st">&quot;templates/post.html&quot;</span> defaultContext</span></a></code></pre></div>
<p>Now if <code>templates/posts.html</code> contains:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode html"><code class="sourceCode html"><a class="sourceLine" id="cb7-1" title="1"><span class="kw">&lt;html&gt;</span></a>
<a class="sourceLine" id="cb7-2" title="2"> <span class="kw">&lt;head&gt;</span></a>
<a class="sourceLine" id="cb7-3" title="3"> <span class="kw">&lt;title&gt;</span>How could I get the title?<span class="kw">&lt;/title&gt;</span></a>
<a class="sourceLine" id="cb7-4" title="4"> <span class="kw">&lt;/head&gt;</span></a>
<a class="sourceLine" id="cb7-5" title="5"> <span class="kw">&lt;body&gt;</span></a>
<a class="sourceLine" id="cb7-6" title="6"> <span class="highlight">$body$</span></a>
<a class="sourceLine" id="cb7-7" title="7"> <span class="kw">&lt;/body&gt;</span></a>
<a class="sourceLine" id="cb7-8" title="8"><span class="kw">&lt;/html&gt;</span></a></code></pre></div>
<p>our <code>cthulhu.html</code> contains (indentation added for readability):</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode html"><code class="sourceCode html"><a class="sourceLine" id="cb8-1" title="1"><span class="kw">&lt;html&gt;</span></a>
<a class="sourceLine" id="cb8-2" title="2"> <span class="kw">&lt;head&gt;</span></a>
<a class="sourceLine" id="cb8-3" title="3"> <span class="kw">&lt;title&gt;</span>How could I get the title?<span class="kw">&lt;/title&gt;</span></a>
<a class="sourceLine" id="cb8-4" title="4"> <span class="kw">&lt;/head&gt;</span></a>
<a class="sourceLine" id="cb8-5" title="5"> <span class="kw">&lt;body&gt;</span></a>
<a class="sourceLine" id="cb8-6" title="6"> <span class="highlight"><span class="kw">&lt;h1&gt;</span>Cthulhu<span class="kw">&lt;/h1&gt;</span></span></a>
<a class="sourceLine" id="cb8-7" title="7"> <span class="highlight"><span class="kw">&lt;p&gt;</span>ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn<span class="kw">&lt;/p&gt;</span></span></a>
<a class="sourceLine" id="cb8-8" title="8"> <span class="kw">&lt;/body&gt;</span></a>
<a class="sourceLine" id="cb8-9" title="9"><span class="kw">&lt;/html&gt;</span></a></code></pre></div>
<p>See, it’s easy But we have a problem. How could we change the title or add keywords?</p>
<p>The solution is to use <code>Context</code>s. For this, we first need to add some <em>metadatas</em> to our markdown<a href="#fn1" class="footnote-ref" id="fnref1"><sup>1</sup></a>.</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode markdown"><code class="sourceCode markdown"><a class="sourceLine" id="cb9-1" title="1"><span class="highlight">--- </span></a>
<a class="sourceLine" id="cb9-2" title="2"><span class="highlight">title: Cthulhu</span></a>
<a class="sourceLine" id="cb9-3" title="3"><span class="highlight">--- </span></a>
<a class="sourceLine" id="cb9-4" title="4"><span class="fu"># Cthulhu</span></a>
<a class="sourceLine" id="cb9-5" title="5"></a>
<a class="sourceLine" id="cb9-6" title="6">ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn</a></code></pre></div>
<p>And modify slightly our template:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode html"><code class="sourceCode html"><a class="sourceLine" id="cb10-1" title="1"><span class="kw">&lt;html&gt;</span></a>
<a class="sourceLine" id="cb10-2" title="2"> <span class="kw">&lt;head&gt;</span></a>
<a class="sourceLine" id="cb10-3" title="3"> <span class="kw">&lt;title&gt;</span><span class="highlight">$title$</span><span class="kw">&lt;/title&gt;</span></a>
<a class="sourceLine" id="cb10-4" title="4"> <span class="kw">&lt;/head&gt;</span></a>
<a class="sourceLine" id="cb10-5" title="5"> <span class="kw">&lt;body&gt;</span></a>
<a class="sourceLine" id="cb10-6" title="6"> $body$</a>
<a class="sourceLine" id="cb10-7" title="7"> <span class="kw">&lt;/body&gt;</span></a>
<a class="sourceLine" id="cb10-8" title="8"><span class="kw">&lt;/html&gt;</span></a></code></pre></div>
<p>As Sir Robin said just before dying before the Bridge of Death:</p>
<blockquote>
<p><strong>“That’s EASY!”</strong></p>
<p><cite>Sir Robin, the Not-Quite-So-Brave-As-Sir-Lancelot</cite></p>
</blockquote>
<h2 id="real-customization">Real customization</h2>
<p>Now that we understand the basic functionality. How to:</p>
<ul>
<li>use SASS?</li>
<li>add keywords?</li>
<li>simplify <span class="sc"><abbr title="Uniform Ressource Locator">url</abbr></span>?</li>
<li>create an archive page?</li>
<li>create an <span class="sc"><abbr title="Rich Site Summary">rss</abbr></span> feed?</li>
<li>filter the content?</li>
<li>add abbreviations support?</li>
<li>manage two languages?</li>
</ul>
<h3 id="use-sass">Use SASS</h3>
<p>That’s easy. Simply call the executable using <code>unixFilter</code>. Of course you’ll have to install SASS (<code>gem install sass</code>). And we also use compressCss to gain some space.</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb11-1" title="1">match <span class="st">&quot;css/*&quot;</span> <span class="op">$</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb11-2" title="2"> route <span class="op">$</span> setExtension <span class="st">&quot;css&quot;</span></a>
<a class="sourceLine" id="cb11-3" title="3"> compile <span class="op">$</span> getResourceString <span class="op">&gt;&gt;=</span></a>
<a class="sourceLine" id="cb11-4" title="4"> withItemBody (unixFilter <span class="st">&quot;sass&quot;</span> [<span class="st">&quot;--trace&quot;</span>]) <span class="op">&gt;&gt;=</span></a>
<a class="sourceLine" id="cb11-5" title="5"> <span class="fu">return</span> <span class="op">.</span> <span class="fu">fmap</span> compressCss</a></code></pre></div>
<h3 id="add-keywords">Add keywords</h3>
<p>In order to help to reference your website on the web, it is nice to add some keywords as meta datas to your <span class="sc"><abbr title="HyperText Markup Language">html</abbr></span> page.</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode html"><code class="sourceCode html"><a class="sourceLine" id="cb12-1" title="1"><span class="kw">&lt;meta</span><span class="ot"> name=</span><span class="st">&quot;keywords&quot;</span></a>
<a class="sourceLine" id="cb12-2" title="2"><span class="ot"> content=</span><span class="st">&quot;Cthulhu, Yog-Sothoth, Shub-Niggurath&quot;</span><span class="kw">&gt;</span></a></code></pre></div>
<p>In order to add keywords, we could not directly use the markdown metadatas. Because, without any, there should be any meta tag in the <span class="sc"><abbr title="HyperText Markup Language">html</abbr></span>.</p>
<p>An easy answer is to create a <code>Context</code> that will contains the meta tag.</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb13-1" title="1"><span class="co">-- metaKeywordContext will return a Context containing a String</span></a>
<a class="sourceLine" id="cb13-2" title="2"><span class="ot">metaKeywordContext ::</span> <span class="dt">Context</span> <span class="dt">String</span></a>
<a class="sourceLine" id="cb13-3" title="3"><span class="co">-- can be reached using $metaKeywords$ in the templates</span></a>
<a class="sourceLine" id="cb13-4" title="4"><span class="co">-- Use the current item (markdown file)</span></a>
<a class="sourceLine" id="cb13-5" title="5">metaKeywordContext <span class="ot">=</span> field <span class="st">&quot;metaKeywords&quot;</span> <span class="op">$</span> \item <span class="ot">-&gt;</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb13-6" title="6"> <span class="co">-- tags contains the content of the &quot;tags&quot; metadata</span></a>
<a class="sourceLine" id="cb13-7" title="7"> <span class="co">-- inside the item (understand the source)</span></a>
<a class="sourceLine" id="cb13-8" title="8"> tags <span class="ot">&lt;-</span> getMetadataField (itemIdentifier item) <span class="st">&quot;tags&quot;</span></a>
<a class="sourceLine" id="cb13-9" title="9"> <span class="co">-- if tags is empty return an empty string</span></a>
<a class="sourceLine" id="cb13-10" title="10"> <span class="co">-- in the other case return</span></a>
<a class="sourceLine" id="cb13-11" title="11"> <span class="co">-- &lt;meta name=&quot;keywords&quot; content=&quot;$tags$&quot;&gt;</span></a>
<a class="sourceLine" id="cb13-12" title="12"> <span class="fu">return</span> <span class="op">$</span> <span class="fu">maybe</span> <span class="st">&quot;&quot;</span> showMetaTags tags</a>
<a class="sourceLine" id="cb13-13" title="13"> <span class="kw">where</span></a>
<a class="sourceLine" id="cb13-14" title="14"> showMetaTags t <span class="ot">=</span> <span class="st">&quot;&lt;meta name=\&quot;keywords\&quot; content=\&quot;&quot;</span></a>
<a class="sourceLine" id="cb13-15" title="15"> <span class="op">++</span> t <span class="op">++</span> <span class="st">&quot;\&quot;&gt;\n&quot;</span></a></code></pre></div>
<p>Then we pass this <code>Context</code> to the <code>loadAndApplyTemplate</code> function:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb14-1" title="1">match <span class="st">&quot;posts/*.md&quot;</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb14-2" title="2"> route <span class="op">$</span> setExtension <span class="st">&quot;html&quot;</span></a>
<a class="sourceLine" id="cb14-3" title="3"> compile <span class="op">$</span> pandocCompiler</a>
<a class="sourceLine" id="cb14-4" title="4"> <span class="co">-- use the template with the current content</span></a>
<a class="sourceLine" id="cb14-5" title="5"> <span class="op">&gt;&gt;=</span> loadAndApplyTemplate <span class="st">&quot;templates/post.html&quot;</span></a>
<a class="sourceLine" id="cb14-6" title="6"> (defaultContext <span class="highlight"><span class="op">&lt;&gt;</span> metaKeywordContext</span>)</a></code></pre></div>
<blockquote>
<p>☞ Here are the imports I use for this tutorial.</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb15-1" title="1"><span class="ot">{-# LANGUAGE OverloadedStrings #-}</span></a>
<a class="sourceLine" id="cb15-2" title="2"><span class="kw">import</span> <span class="dt">Control.Monad</span> (forM,forM_)</a>
<a class="sourceLine" id="cb15-3" title="3"><span class="kw">import</span> <span class="dt">Data.List</span> (sortBy,isInfixOf)</a>
<a class="sourceLine" id="cb15-4" title="4"><span class="kw">import</span> <span class="dt">Data.Monoid</span> ((&lt;&gt;),mconcat)</a>
<a class="sourceLine" id="cb15-5" title="5"><span class="kw">import</span> <span class="dt">Data.Ord</span> (comparing)</a>
<a class="sourceLine" id="cb15-6" title="6"><span class="kw">import</span> <span class="dt">Hakyll</span></a>
<a class="sourceLine" id="cb15-7" title="7"><span class="kw">import</span> <span class="dt">System.Locale</span> (defaultTimeLocale)</a>
<a class="sourceLine" id="cb15-8" title="8"><span class="kw">import</span> <span class="dt">System.FilePath.Posix</span> (takeBaseName,takeDirectory</a>
<a class="sourceLine" id="cb15-9" title="9"> ,(<span class="op">&lt;/&gt;</span>),splitFileName)</a></code></pre></div>
</blockquote>
<h3 id="simplify-url">Simplify <span class="sc"><abbr title="Uniform Ressource Locator">url</abbr></span></h3>
<p>What I mean is to use url of the form:</p>
<pre><code>http://domain.name/post/title-of-the-post/</code></pre>
<p>I prefer this than having to add file with <code>.html</code> extension. We have to change the default Hakyll route behavior. We create another function <code>niceRoute</code>.</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb17-1" title="1"><span class="co">-- replace a foo/bar.md by foo/bar/index.html</span></a>
<a class="sourceLine" id="cb17-2" title="2"><span class="co">-- this way the url looks like: foo/bar in most browsers</span></a>
<a class="sourceLine" id="cb17-3" title="3"><span class="ot">niceRoute ::</span> <span class="dt">Routes</span></a>
<a class="sourceLine" id="cb17-4" title="4">niceRoute <span class="ot">=</span> customRoute createIndexRoute</a>
<a class="sourceLine" id="cb17-5" title="5"> <span class="kw">where</span></a>
<a class="sourceLine" id="cb17-6" title="6"> createIndexRoute ident <span class="ot">=</span></a>
<a class="sourceLine" id="cb17-7" title="7"> takeDirectory p <span class="op">&lt;/&gt;</span> takeBaseName p <span class="op">&lt;/&gt;</span> <span class="st">&quot;index.html&quot;</span></a>
<a class="sourceLine" id="cb17-8" title="8"> <span class="kw">where</span> p<span class="ot">=</span>toFilePath ident</a></code></pre></div>
<p>Not too difficult. But! There might be a problem. What if there is a <code>foo/index.html</code> link instead of a clean <code>foo/</code> in some content?</p>
<p>Very simple, we simply remove all <code>/index.html</code> to all our links.</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb18-1" title="1"><span class="co">-- replace url of the form foo/bar/index.html by foo/bar</span></a>
<a class="sourceLine" id="cb18-2" title="2"><span class="ot">removeIndexHtml ::</span> <span class="dt">Item</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Compiler</span> (<span class="dt">Item</span> <span class="dt">String</span>)</a>
<a class="sourceLine" id="cb18-3" title="3">removeIndexHtml item <span class="ot">=</span> <span class="fu">return</span> <span class="op">$</span> <span class="fu">fmap</span> (withUrls removeIndexStr) item</a>
<a class="sourceLine" id="cb18-4" title="4"> <span class="kw">where</span></a>
<a class="sourceLine" id="cb18-5" title="5"><span class="ot"> removeIndexStr ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">String</span></a>
<a class="sourceLine" id="cb18-6" title="6"> removeIndexStr url <span class="ot">=</span> <span class="kw">case</span> splitFileName url <span class="kw">of</span></a>
<a class="sourceLine" id="cb18-7" title="7"> (dir, <span class="st">&quot;index.html&quot;</span>) <span class="op">|</span> isLocal dir <span class="ot">-&gt;</span> dir</a>
<a class="sourceLine" id="cb18-8" title="8"> _ <span class="ot">-&gt;</span> url</a>
<a class="sourceLine" id="cb18-9" title="9"> <span class="kw">where</span> isLocal uri <span class="ot">=</span> <span class="fu">not</span> (isInfixOf <span class="st">&quot;://&quot;</span> uri)</a></code></pre></div>
<p>And we apply this filter at the end of our compilation</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb19-1" title="1">match <span class="st">&quot;posts/*.md&quot;</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb19-2" title="2"> <span class="highlight">route <span class="op">$</span> niceRoute</span></a>
<a class="sourceLine" id="cb19-3" title="3"> compile <span class="op">$</span> pandocCompiler</a>
<a class="sourceLine" id="cb19-4" title="4"> <span class="co">-- use the template with the current content</span></a>
<a class="sourceLine" id="cb19-5" title="5"> <span class="op">&gt;&gt;=</span> loadAndApplyTemplate <span class="st">&quot;templates/post.html&quot;</span> defaultContext</a>
<a class="sourceLine" id="cb19-6" title="6"> <span class="highlight"><span class="op">&gt;&gt;=</span> removeIndexHtml</span></a></code></pre></div>
<h3 id="create-an-archive-page">Create an archive page</h3>
<p>Creating an archive start to be difficult. There is an example in the default Hakyll example. Unfortunately, it assumes all posts prefix their name with a date like in <code>2013-03-20-My-New-Post.md</code>.</p>
<p>I migrated from an older blog and didn’t want to change my <span class="sc"><abbr title="Uniform Ressource Locator">url</abbr></span>. Also I prefer not to use any filename convention. Therefore, I add the date information in the metadata <code>published</code>. And the solution is here:</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb20-1" title="1">match <span class="st">&quot;archive.md&quot;</span> <span class="op">$</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb20-2" title="2"> route <span class="op">$</span> niceRoute</a>
<a class="sourceLine" id="cb20-3" title="3"> compile <span class="op">$</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb20-4" title="4"> body <span class="ot">&lt;-</span> getResourceBody</a>
<a class="sourceLine" id="cb20-5" title="5"> <span class="fu">return</span> <span class="op">$</span> renderPandoc body</a>
<a class="sourceLine" id="cb20-6" title="6"> <span class="highlight"><span class="op">&gt;&gt;=</span> loadAndApplyTemplate <span class="st">&quot;templates/archive.html&quot;</span> archiveCtx</span></a>
<a class="sourceLine" id="cb20-7" title="7"> <span class="op">&gt;&gt;=</span> loadAndApplyTemplate <span class="highlight"><span class="st">&quot;templates/base.html&quot;</span></span> defaultContext</a>
<a class="sourceLine" id="cb20-8" title="8"> <span class="op">&gt;&gt;=</span> removeIndexHtml</a></code></pre></div>
<p>Where <code>templates/archive.html</code> contains</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode html"><code class="sourceCode html"><a class="sourceLine" id="cb21-1" title="1">$body$</a>
<a class="sourceLine" id="cb21-2" title="2"></a>
<a class="sourceLine" id="cb21-3" title="3"><span class="kw">&lt;ul&gt;</span></a>
<a class="sourceLine" id="cb21-4" title="4"> $posts$</a>
<a class="sourceLine" id="cb21-5" title="5"><span class="kw">&lt;/ul&gt;</span></a></code></pre></div>
<p>And <code>base.html</code> is a standard template (simpler than <code>post.html</code>).</p>
<p><code>archiveCtx</code> provide a context containing an <span class="sc"><abbr title="HyperText Markup Language">html</abbr></span> representation of a list of posts in the metadata named <code>posts</code>. It will be used in the <code>templates/archive.html</code> file with <code>$posts$</code>.</p>
<div class="sourceCode" id="cb22"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb22-1" title="1">archiveCtx <span class="ot">=</span></a>
<a class="sourceLine" id="cb22-2" title="2"> defaultContext <span class="op">&lt;&gt;</span></a>
<a class="sourceLine" id="cb22-3" title="3"> metaKeywordContext <span class="op">&lt;&gt;</span></a>
<a class="sourceLine" id="cb22-4" title="4"> <span class="highlight">field <span class="st">&quot;posts&quot;</span> (\_ <span class="ot">-&gt;</span> postList createdFirst)</span></a></code></pre></div>
<p><code>postList</code> returns an <span class="sc"><abbr title="HyperText Markup Language">html</abbr></span> representation of a list of posts given an Item sort function. The representation will apply a minimal template on all posts. Then it concatenate all the results. The template is <code>post-item.html</code>:</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode html"><code class="sourceCode html"><a class="sourceLine" id="cb23-1" title="1"><span class="kw">&lt;li&gt;&lt;a</span><span class="ot"> href=</span><span class="st">&quot;$url$&quot;</span><span class="kw">&gt;</span>$published$ - $title$<span class="kw">&lt;/a&gt;&lt;/li&gt;</span></a></code></pre></div>
<p>Here is how it is done:</p>
<div class="sourceCode" id="cb24"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb24-1" title="1"><span class="ot">postList ::</span> [<span class="dt">Item</span> <span class="dt">String</span>] <span class="ot">-&gt;</span> <span class="dt">Compiler</span> [<span class="dt">Item</span> <span class="dt">String</span>]</a>
<a class="sourceLine" id="cb24-2" title="2"> <span class="ot">-&gt;</span> <span class="dt">Compiler</span> <span class="dt">String</span></a>
<a class="sourceLine" id="cb24-3" title="3">postList sortFilter <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb24-4" title="4"> <span class="co">-- sorted posts</span></a>
<a class="sourceLine" id="cb24-5" title="5"> posts <span class="ot">&lt;-</span> loadAll <span class="st">&quot;post/*&quot;</span> <span class="op">&gt;&gt;=</span> sortFilter</a>
<a class="sourceLine" id="cb24-6" title="6"> itemTpl <span class="ot">&lt;-</span> loadBody <span class="st">&quot;templates/post-item.html&quot;</span></a>
<a class="sourceLine" id="cb24-7" title="7"> <span class="co">-- we apply the template to all post</span></a>
<a class="sourceLine" id="cb24-8" title="8"> <span class="co">-- and we concatenate the result.</span></a>
<a class="sourceLine" id="cb24-9" title="9"> <span class="co">-- list is a string</span></a>
<a class="sourceLine" id="cb24-10" title="10"> list <span class="ot">&lt;-</span> applyTemplateList itemTpl defaultContext posts</a>
<a class="sourceLine" id="cb24-11" title="11"> <span class="fu">return</span> list</a></code></pre></div>
<p><code>createdFirst</code> sort a list of item and put it inside <code>Compiler</code> context. We need to be in the <code>Compiler</code> context to access metadatas.</p>
<div class="sourceCode" id="cb25"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb25-1" title="1"><span class="ot">createdFirst ::</span> [<span class="dt">Item</span> <span class="dt">String</span>] <span class="ot">-&gt;</span> <span class="dt">Compiler</span> [<span class="dt">Item</span> <span class="dt">String</span>]</a>
<a class="sourceLine" id="cb25-2" title="2">createdFirst items <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb25-3" title="3"> <span class="co">-- itemsWithTime is a list of couple (date,item)</span></a>
<a class="sourceLine" id="cb25-4" title="4"> itemsWithTime <span class="ot">&lt;-</span> forM items <span class="op">$</span> \item <span class="ot">-&gt;</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb25-5" title="5"> <span class="co">-- getItemUTC will look for the metadata &quot;published&quot; or &quot;date&quot;</span></a>
<a class="sourceLine" id="cb25-6" title="6"> <span class="co">-- then it will try to get the date from some standard formats</span></a>
<a class="sourceLine" id="cb25-7" title="7"> utc <span class="ot">&lt;-</span> getItemUTC defaultTimeLocale <span class="op">$</span> itemIdentifier item</a>
<a class="sourceLine" id="cb25-8" title="8"> <span class="fu">return</span> (utc,item)</a>
<a class="sourceLine" id="cb25-9" title="9"> <span class="co">-- we return a sorted item list</span></a>
<a class="sourceLine" id="cb25-10" title="10"> <span class="fu">return</span> <span class="op">$</span> <span class="fu">map</span> <span class="fu">snd</span> <span class="op">$</span> <span class="fu">reverse</span> <span class="op">$</span> sortBy (comparing <span class="fu">fst</span>) itemsWithTime</a></code></pre></div>
<p>It wasn’t so easy. But it works pretty well.</p>
<h3 id="create-an-rss-feed">Create an <span class="sc"><abbr title="Rich Site Summary">rss</abbr></span> feed</h3>
<p>To create an <span class="sc"><abbr title="Rich Site Summary">rss</abbr></span> feed, we have to:</p>
<ul>
<li>select only the lasts posts.</li>
<li>generate partially rendered posts (no css, js, etc…)</li>
</ul>
<p>We could then render the posts twice. One for <span class="sc"><abbr title="HyperText Markup Language">html</abbr></span> rendering and another time for <span class="sc"><abbr title="Rich Site Summary">rss</abbr></span>. Remark we need to generate the <span class="sc"><abbr title="Rich Site Summary">rss</abbr></span> version to create the <span class="sc"><abbr title="HyperText Markup Language">html</abbr></span> one.</p>
<p>One of the great feature of Hakyll is to be able to save snapshots. Here is how:</p>
<div class="sourceCode" id="cb26"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb26-1" title="1">match <span class="st">&quot;posts/*.md&quot;</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb26-2" title="2"> route <span class="op">$</span> setExtension <span class="st">&quot;html&quot;</span></a>
<a class="sourceLine" id="cb26-3" title="3"> compile <span class="op">$</span> pandocCompiler</a>
<a class="sourceLine" id="cb26-4" title="4"> <span class="co">-- save a snapshot to be used later in rss generation</span></a>
<a class="sourceLine" id="cb26-5" title="5"> <span class="highlight"><span class="op">&gt;&gt;=</span> saveSnapshot <span class="st">&quot;content&quot;</span></span></a>
<a class="sourceLine" id="cb26-6" title="6"> <span class="op">&gt;&gt;=</span> loadAndApplyTemplate <span class="st">&quot;templates/post.html&quot;</span> defaultContext</a></code></pre></div>
<p>Now for each post there is a snapshot named “content” associated. The snapshots are created before applying a template and after applying pandoc. Furthermore feed don’t need a source markdown file. Then we create a new file from no one. Instead of using <code>match</code>, we use <code>create</code>:</p>
<div class="sourceCode" id="cb27"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb27-1" title="1">create [<span class="st">&quot;feed.xml&quot;</span>] <span class="op">$</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb27-2" title="2"> route idRoute</a>
<a class="sourceLine" id="cb27-3" title="3"> compile <span class="op">$</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb27-4" title="4"> <span class="co">-- load all &quot;content&quot; snapshots of all posts</span></a>
<a class="sourceLine" id="cb27-5" title="5"> loadAllSnapshots <span class="st">&quot;posts/*&quot;</span> <span class="st">&quot;content&quot;</span></a>
<a class="sourceLine" id="cb27-6" title="6"> <span class="co">-- take the latest 10</span></a>
<a class="sourceLine" id="cb27-7" title="7"> <span class="op">&gt;&gt;=</span> (<span class="fu">fmap</span> (<span class="fu">take</span> <span class="dv">10</span>)) <span class="op">.</span> createdFirst</a>
<a class="sourceLine" id="cb27-8" title="8"> <span class="co">-- renderAntom feed using some configuration</span></a>
<a class="sourceLine" id="cb27-9" title="9"> <span class="op">&gt;&gt;=</span> renderAtom feedConfiguration feedCtx</a>
<a class="sourceLine" id="cb27-10" title="10"> <span class="kw">where</span></a>
<a class="sourceLine" id="cb27-11" title="11"><span class="ot"> feedCtx ::</span> <span class="dt">Context</span> <span class="dt">String</span></a>
<a class="sourceLine" id="cb27-12" title="12"> feedCtx <span class="ot">=</span> defaultContext <span class="op">&lt;&gt;</span></a>
<a class="sourceLine" id="cb27-13" title="13"> <span class="co">-- $description$ will render as the post body</span></a>
<a class="sourceLine" id="cb27-14" title="14"> <span class="highlight">bodyField <span class="st">&quot;description&quot;</span></span></a></code></pre></div>
<p>The <code>feedConfiguration</code> contains some general informations about the feed.</p>
<div class="sourceCode" id="cb28"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb28-1" title="1"><span class="ot">feedConfiguration ::</span> <span class="dt">FeedConfiguration</span></a>
<a class="sourceLine" id="cb28-2" title="2">feedConfiguration <span class="ot">=</span> <span class="dt">FeedConfiguration</span></a>
<a class="sourceLine" id="cb28-3" title="3"> { feedTitle <span class="ot">=</span> <span class="st">&quot;Great Old Ones&quot;</span></a>
<a class="sourceLine" id="cb28-4" title="4"> , feedDescription <span class="ot">=</span> <span class="st">&quot;This feed provide information about Great Old Ones&quot;</span></a>
<a class="sourceLine" id="cb28-5" title="5"> , feedAuthorName <span class="ot">=</span> <span class="st">&quot;Abdul Alhazred&quot;</span></a>
<a class="sourceLine" id="cb28-6" title="6"> , feedAuthorEmail <span class="ot">=</span> <span class="st">&quot;abdul.alhazred@great-old-ones.com&quot;</span></a>
<a class="sourceLine" id="cb28-7" title="7"> , feedRoot <span class="ot">=</span> <span class="st">&quot;http://great-old-ones.com&quot;</span></a>
<a class="sourceLine" id="cb28-8" title="8"> }</a></code></pre></div>
<p>Great idea certainly steal from <a href="http://nanoc.ws">nanoc</a> (my previous blog engine)!</p>
<h3 id="filter-the-content">Filter the content</h3>
<p>As I just said, <a href="http://nanoc.ws">nanoc</a> was my preceding blog engine. It is written in Ruby and as Hakyll, it is quite awesome. And one thing Ruby does more naturally than Haskell is regular expressions. I had a <em>lot</em> of filters in nanoc. I lost some because I don’t use them much. But I wanted to keep some. Generally, filtering the content is just a way to apply to the body a function of type <code>String -&gt; String</code>.</p>
<p>Also we generally want prefilters (to filter the markdown) and postfilters (to filter the <span class="sc"><abbr title="HyperText Markup Language">html</abbr></span> after the pandoc compilation).</p>
<p>Here is how I do it:</p>
<div class="sourceCode" id="cb29"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb29-1" title="1">markdownPostBehavior <span class="ot">=</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb29-2" title="2"> route <span class="op">$</span> niceRoute</a>
<a class="sourceLine" id="cb29-3" title="3"> compile <span class="op">$</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb29-4" title="4"> body <span class="ot">&lt;-</span> getResourceBody</a>
<a class="sourceLine" id="cb29-5" title="5"> <span class="highlight">prefilteredText <span class="ot">&lt;-</span> <span class="fu">return</span> <span class="op">$</span> (<span class="fu">fmap</span> preFilters body)</span></a>
<a class="sourceLine" id="cb29-6" title="6"> <span class="highlight"><span class="fu">return</span> <span class="op">$</span> renderPandoc prefilteredText</span></a>
<a class="sourceLine" id="cb29-7" title="7"> <span class="highlight"><span class="op">&gt;&gt;=</span> applyFilter postFilters</span></a>
<a class="sourceLine" id="cb29-8" title="8"> <span class="op">&gt;&gt;=</span> saveSnapshot <span class="st">&quot;content&quot;</span></a>
<a class="sourceLine" id="cb29-9" title="9"> <span class="op">&gt;&gt;=</span> loadAndApplyTemplate <span class="st">&quot;templates/post.html&quot;</span> yContext</a>
<a class="sourceLine" id="cb29-10" title="10"> <span class="op">&gt;&gt;=</span> loadAndApplyTemplate <span class="st">&quot;templates/boilerplate.html&quot;</span> yContext</a>
<a class="sourceLine" id="cb29-11" title="11"> <span class="op">&gt;&gt;=</span> relativizeUrls</a>
<a class="sourceLine" id="cb29-12" title="12"> <span class="op">&gt;&gt;=</span> removeIndexHtml</a></code></pre></div>
<p>Where</p>
<div class="sourceCode" id="cb30"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb30-1" title="1">applyFilter strfilter str <span class="ot">=</span> <span class="fu">return</span> <span class="op">$</span> (<span class="fu">fmap</span> <span class="op">$</span> strfilter) str</a>
<a class="sourceLine" id="cb30-2" title="2"><span class="ot">preFilters ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">String</span></a>
<a class="sourceLine" id="cb30-3" title="3"><span class="ot">postFilters ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">String</span></a></code></pre></div>
<p>Now we have a simple way to filter the content. Let’s augment the markdown ability.</p>
<h3 id="add-abbreviations-support">Add abbreviations support</h3>
<p>Comparing to <span style="text-transform: uppercase">L<sup style="vertical-align: 0.15em; margin-left: -0.36em; margin-right: -0.15em; font-size: .85em">a</sup>T<sub style="vertical-align: -0.5ex; margin-left: -0.1667em; margin-right: -0.125em; font-size: 1em">e</sub>X</span>, a very annoying markdown limitation is the lack of abbreviations.</p>
<p>Fortunately we can filter our content. And here is the filter I use:</p>
<div class="sourceCode" id="cb31"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb31-1" title="1"><span class="ot">abbreviationFilter ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">String</span></a>
<a class="sourceLine" id="cb31-2" title="2">abbreviationFilter <span class="ot">=</span> replaceAll <span class="st">&quot;%[a-zA-Z0-9_]*&quot;</span> newnaming</a>
<a class="sourceLine" id="cb31-3" title="3"> <span class="kw">where</span></a>
<a class="sourceLine" id="cb31-4" title="4"> newnaming matched <span class="ot">=</span> <span class="kw">case</span> M.lookup (<span class="fu">tail</span> matched) abbreviations <span class="kw">of</span></a>
<a class="sourceLine" id="cb31-5" title="5"> <span class="dt">Nothing</span> <span class="ot">-&gt;</span> matched</a>
<a class="sourceLine" id="cb31-6" title="6"> <span class="dt">Just</span> v <span class="ot">-&gt;</span> v</a>
<a class="sourceLine" id="cb31-7" title="7"><span class="ot">abbreviations ::</span> <span class="dt">Map</span> <span class="dt">String</span> <span class="dt">String</span></a>
<a class="sourceLine" id="cb31-8" title="8">abbreviations <span class="ot">=</span> M.fromList</a>
<a class="sourceLine" id="cb31-9" title="9"> [ (<span class="st">&quot;html&quot;</span>, <span class="st">&quot;&lt;span class=\&quot;sc\&quot;&gt;html&lt;/span&gt;&quot;</span>)</a>
<a class="sourceLine" id="cb31-10" title="10"> , (<span class="st">&quot;css&quot;</span>, <span class="st">&quot;&lt;span class=\&quot;sc\&quot;&gt;css&lt;/span&gt;&quot;</span>)</a>
<a class="sourceLine" id="cb31-11" title="11"> , (<span class="st">&quot;svg&quot;</span>, <span class="st">&quot;&lt;span class=\&quot;sc\&quot;&gt;svg&lt;/span&gt;&quot;</span>)</a>
<a class="sourceLine" id="cb31-12" title="12"> , (<span class="st">&quot;xml&quot;</span>, <span class="st">&quot;&lt;span class=\&quot;sc\&quot;&gt;xml&lt;/span&gt;&quot;</span>)</a>
<a class="sourceLine" id="cb31-13" title="13"> , (<span class="st">&quot;xslt&quot;</span>, <span class="st">&quot;&lt;span class=\&quot;sc\&quot;&gt;xslt&lt;/span&gt;&quot;</span>) ]</a></code></pre></div>
<p>It will search for all string starting by ‘%’ and it will search in the <code>Map</code> if there is a corresponding abbreviation. If there is one, we replace the content. Otherwise we do nothing.</p>
<p>Do you really believe I type</p>
<div class="sourceCode" id="cb32"><pre class="sourceCode html wrap"><code class="sourceCode html"><a class="sourceLine" id="cb32-1" title="1"><span class="kw">&lt;span</span><span class="ot"> style=</span><span class="st">&quot;text-transform: uppercase&quot;</span><span class="kw">&gt;</span>L<span class="kw">&lt;sup</span><span class="ot"> style=</span><span class="st">&quot;vertical-align: 0.15em; margin-left: -0.36em; margin-right: -0.15em; font-size: .85em&quot;</span><span class="kw">&gt;</span>a<span class="kw">&lt;/sup&gt;</span>T<span class="kw">&lt;sub</span><span class="ot"> style=</span><span class="st">&quot;vertical-align: -0.5ex; margin-left: -0.1667em; margin-right: -0.125em; font-size: 1em&quot;</span><span class="kw">&gt;</span>e<span class="kw">&lt;/sub&gt;</span>X<span class="kw">&lt;/span&gt;</span></a></code></pre></div>
<p>each time I write <span style="text-transform: uppercase">L<sup style="vertical-align: 0.15em; margin-left: -0.36em; margin-right: -0.15em; font-size: .85em">a</sup>T<sub style="vertical-align: -0.5ex; margin-left: -0.1667em; margin-right: -0.125em; font-size: 1em">e</sub>X</span>?</p>
<h3 id="manage-two-languages">Manage two languages</h3>
<p>Generally I write my post in English and French. And this is more difficult than it appears. For example, I need to filter the language in order to get the right list of posts. I also use some words in the templates and I want them to be translated.</p>
<div class="sourceCode" id="cb33"><pre class="sourceCode html"><code class="sourceCode html"><a class="sourceLine" id="cb33-1" title="1"><span class="kw">&lt;a</span><span class="ot"> href=</span><span class="st">&quot;$otherLanguagePath$&quot;</span></a>
<a class="sourceLine" id="cb33-2" title="2"><span class="ot"> onclick=</span><span class="st">&quot;setLanguage('$otherlanguage$')&quot;</span><span class="kw">&gt;</span></a>
<a class="sourceLine" id="cb33-3" title="3"> <span class="highlight">$changeLanguage$</span> <span class="kw">&lt;/a&gt;</span></a></code></pre></div>
<p>First I create a Map containing all translations.</p>
<div class="sourceCode" id="cb34"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb34-1" title="1"><span class="kw">data</span> <span class="dt">Trad</span> <span class="ot">=</span> <span class="dt">Trad</span> {<span class="ot"> frTrad ::</span> <span class="dt">String</span>,<span class="ot"> enTrad ::</span> <span class="dt">String</span> }</a>
<a class="sourceLine" id="cb34-2" title="2"></a>
<a class="sourceLine" id="cb34-3" title="3"><span class="ot">trads ::</span> <span class="dt">Map</span> <span class="dt">String</span> <span class="dt">Trad</span></a>
<a class="sourceLine" id="cb34-4" title="4">trads <span class="ot">=</span> M.fromList <span class="op">$</span> <span class="fu">map</span> toTrad [</a>
<a class="sourceLine" id="cb34-5" title="5"> (<span class="st">&quot;changeLanguage&quot;</span>,</a>
<a class="sourceLine" id="cb34-6" title="6"> (<span class="st">&quot;English&quot;</span></a>
<a class="sourceLine" id="cb34-7" title="7"> , <span class="st">&quot;Français&quot;</span>))</a>
<a class="sourceLine" id="cb34-8" title="8"> ,(<span class="st">&quot;switchCss&quot;</span>,</a>
<a class="sourceLine" id="cb34-9" title="9"> (<span class="st">&quot;Changer de theme&quot;</span></a>
<a class="sourceLine" id="cb34-10" title="10"> ,<span class="st">&quot;Change Theme&quot;</span>))</a>
<a class="sourceLine" id="cb34-11" title="11"> ,(<span class="st">&quot;socialPrivacy&quot;</span>,</a>
<a class="sourceLine" id="cb34-12" title="12"> (<span class="st">&quot;Ces liens sociaux préservent votre vie privée&quot;</span></a>
<a class="sourceLine" id="cb34-13" title="13"> ,<span class="st">&quot;These social sharing links preserve your privacy&quot;</span>))</a>
<a class="sourceLine" id="cb34-14" title="14"> ]</a>
<a class="sourceLine" id="cb34-15" title="15"> <span class="kw">where</span></a>
<a class="sourceLine" id="cb34-16" title="16"> toTrad (key,(french,english)) <span class="ot">=</span></a>
<a class="sourceLine" id="cb34-17" title="17"> (key, <span class="dt">Trad</span> { frTrad <span class="ot">=</span> french , enTrad <span class="ot">=</span> english })</a></code></pre></div>
<p>Then I create a context for all key:</p>
<div class="sourceCode" id="cb35"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb35-1" title="1"><span class="ot">tradsContext ::</span> <span class="dt">Context</span> a</a>
<a class="sourceLine" id="cb35-2" title="2">tradsContext <span class="ot">=</span> <span class="fu">mconcat</span> (<span class="fu">map</span> addTrad (M.keys trads))</a>
<a class="sourceLine" id="cb35-3" title="3"> <span class="kw">where</span></a>
<a class="sourceLine" id="cb35-4" title="4"><span class="ot"> addTrad ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Context</span> a</a>
<a class="sourceLine" id="cb35-5" title="5"> addTrad name <span class="ot">=</span></a>
<a class="sourceLine" id="cb35-6" title="6"> field name <span class="op">$</span> \item <span class="ot">-&gt;</span> <span class="kw">do</span></a>
<a class="sourceLine" id="cb35-7" title="7"> lang <span class="ot">&lt;-</span> itemLang item</a>
<a class="sourceLine" id="cb35-8" title="8"> <span class="kw">case</span> M.lookup name trads <span class="kw">of</span></a>
<a class="sourceLine" id="cb35-9" title="9"> <span class="dt">Just</span> (<span class="dt">Trad</span> lmap) <span class="ot">-&gt;</span> <span class="kw">case</span> M.lookup (<span class="dt">L</span> lang) lmap <span class="kw">of</span></a>
<a class="sourceLine" id="cb35-10" title="10"> <span class="dt">Just</span> tr <span class="ot">-&gt;</span> <span class="fu">return</span> tr</a>
<a class="sourceLine" id="cb35-11" title="11"> <span class="dt">Nothing</span> <span class="ot">-&gt;</span> <span class="fu">return</span> (<span class="st">&quot;NO TRANSLATION FOR &quot;</span> <span class="op">++</span> name)</a>
<a class="sourceLine" id="cb35-12" title="12"> <span class="dt">Nothing</span> <span class="ot">-&gt;</span> <span class="fu">return</span> (<span class="st">&quot;NO TRANSLATION FOR &quot;</span> <span class="op">++</span> name)</a></code></pre></div>
<h2 id="conclusion">Conclusion</h2>
<p>The full code is <a href="http://github.com/yogsototh/yblog.git">here</a>. And except from the main file, I use literate Haskell. This way the code should be easier to understand.</p>
<p>If you want to know why I switched from nanoc:</p>
<p>My preceding nanoc website was a bit too messy. So much in fact, that the dependency system recompiled the entire website for any change.</p>
<p>So I had to do something about it. I had two choices:</p>
<ol type="1">
<li>Correct my old code (in Ruby)</li>
<li>Duplicate the core functionalities with Hakyll (in Haskell)</li>
</ol>
<p>I added too much functionalities in my nanoc system. Starting from scratch (almost) remove efficiently a lot of unused crap.</p>
<p>So far I am very happy with the switch. A complete build is about 4x faster. I didn’t broke the dependency system this time. As soon as I modify and save the markdown source, I can reload the page in the browser.</p>
<p>I removed a lot of feature thought. Some of them will be difficult to achieve with Hakyll. A typical example:</p>
<p>In nanoc I could take a file like this as source:</p>
<div class="sourceCode" id="cb36"><pre class="sourceCode markdown"><code class="sourceCode markdown"><a class="sourceLine" id="cb36-1" title="1"><span class="fu"># Title</span></a>
<a class="sourceLine" id="cb36-2" title="2"></a>
<a class="sourceLine" id="cb36-3" title="3">content</a>
<a class="sourceLine" id="cb36-4" title="4"></a>
<a class="sourceLine" id="cb36-5" title="5">&lt;code file=&quot;foo.hs&quot;&gt;</a>
<a class="sourceLine" id="cb36-6" title="6">main = putStrLn &quot;Cthulhu!&quot;</a>
<a class="sourceLine" id="cb36-7" title="7">&lt;/code&gt;</a></code></pre></div>
<p>And it will create a file <code>foo.hs</code> which could then be downloaded.</p>
<div class="sourceCode" id="cb37"><pre class="sourceCode html"><code class="sourceCode html"><a class="sourceLine" id="cb37-1" title="1"><span class="kw">&lt;h1&gt;</span>Title<span class="kw">&lt;/h1&gt;</span></a>
<a class="sourceLine" id="cb37-2" title="2"></a>
<a class="sourceLine" id="cb37-3" title="3"><span class="kw">&lt;p&gt;</span>content<span class="kw">&lt;/p&gt;</span></a>
<a class="sourceLine" id="cb37-4" title="4"></a>
<a class="sourceLine" id="cb37-5" title="5"><span class="kw">&lt;a</span><span class="ot"> href=</span><span class="st">&quot;code/foo.hs&quot;</span><span class="kw">&gt;</span>Download foo.hs<span class="kw">&lt;/a&gt;</span></a>
<a class="sourceLine" id="cb37-6" title="6"><span class="kw">&lt;pre&gt;&lt;code&gt;</span>main = putStrLn &quot;Cthulhu!&quot;<span class="kw">&lt;/code&gt;&lt;/pre&gt;</span></a></code></pre></div>
<section class="footnotes">
<hr />
<ol>
<li id="fn1"><p>We could also add the metadatas in an external file (<code>foo.md.metadata</code>).<a href="#fnref1" class="footnote-back"></a></p></li>
</ol>
</section>
</div>
<div id="afterarticle">
<div id="social">
<a href="/rss.xml" target="_blank" rel="noopener noreferrer nofollow" class="social">RSS</a>
·
<a href="https://twitter.com/home?status=http%3A%2F%2Fyannesposito.com/Scratch/en/blog/Hakyll-setup/%20via%20@yogsototh" target="_blank" rel="noopener noreferrer nofollow" class="social">Tweet</a>
·
<a href="http://www.facebook.com/sharer/sharer.php?u=http%3A%2F%2Fyannesposito.com/Scratch/en/blog/Hakyll-setup/" target="_blank" rel="noopener noreferrer nofollow" class="social">FB</a>
<br />
<a class="message" href="../../../../Scratch/en/blog/Social-link-the-right-way/">These social sharing links preserve your privacy</a>
</div>
<div id="navigation">
<a href="../../../../">Home</a>
<span class="sep">¦</span>
<a href="../../../../Scratch/en/blog">Blog</a>
<span class="sep">¦</span>
<a href="../../../../Scratch/en/softwares">Softwares</a>
<span class="sep">¦</span>
<a href="../../../../Scratch/en/about">About</a>
</div>
<div id="totop"><a href="#header">↑ Top ↑</a></div>
<div id="bottom">
<div>
Published on 2013-03-16
</div>
<div>
<a href="https://twitter.com/yogsototh">Follow @yogsototh</a>
</div>
<div>
<a rel="license" href="http://creativecommons.org/licenses/by/3.0/deed.en_US">Yann Esposito©</a>
</div>
<div>
Done with
<a href="http://www.vim.org" target="_blank" rel="noopener noreferrer nofollow"><strike>Vim</strike></a>
<a href="http://spacemacs.org" target="_blank" rel="noopener noreferrer nofollow">spacemacs</a>
<span class="pala">&amp;</span>
<a href="http://nanoc.ws" target="_blank" rel="noopener noreferrer nofollow"><strike>nanoc</strike></a>
<a href="http://jaspervdj.be/hakyll" target="_blank" rel="noopener noreferrer nofollow">Hakyll</a>
</div>
<hr />
<div style="max-width: 100%">
<a href="https://cardanohub.org">
<img src="../../../../Scratch/img/ada-logo.png" class="simple" style="height: 16px;
border-radius: 50%;
vertical-align:middle;
display:inline-block;" />
ADA:
</a>
<code style="display:inline-block;
word-wrap:break-word;
text-align: left;
vertical-align: top;
max-width: 85%;">
DdzFFzCqrhtAvdkmATx5Fm8NPJViDy85ZBw13p4XcNzVzvQg8e3vWLXq23JQWFxPEXK6Kvhaxxe7oJt4VMYHxpA2vtCFiP8fziohN6Yp
</code>
</div>
</div>
</div>
</div>
</div>
</body>
</html>