her.esy.fun/src/Scratch/fr/blog/Hakyll-setup/index.html

502 lines
56 KiB
HTML
Raw Normal View History

2021-04-18 10:23:24 +00:00
<!DOCTYPE html>
<html lang="fr">
<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" />
2022-10-26 09:38:50 +00:00
<link rel="stylesheet" type="text/css" href="../../../../css/y.css" />
2021-05-25 20:25:47 +00:00
<link rel="stylesheet" type="text/css" href="/css/legacy.css" />
<link rel="alternate" type="application/rss+xml" title="RSS" href="/rss.xml" />
2021-04-18 10:23:24 +00:00
<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="fr" class="article">
<div id="content">
<div id="header">
<div id="choix">
<span id="choixlang">
<a href="../../../../Scratch/en/blog/Hakyll-setup/">Anglais</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="Trop long; pas lu">tlpl</abbr>: </span> Comment jutilise <a href="http://jaspervdj.be/hakyll">hakyll</a>. Abréviations, corrections typographiques, multi-language, utilisation d<code>index.html</code>, etc…</p>
</div>
<p>Ce site web est fait avec <a href="http://jaspervdj.be/hakyll">Hakyll</a>.</p>
<p><a href="http://jaspervdj.be/hakyll">Hakyll</a> peut être vu comme un <span class="sc"><abbr title="Content Management System">cms</abbr></span> minimaliste. Dune façon plus générale, il sagit dune bibliothèque qui facilite la création automatique de fichiers.</p>
<p>Dun point de vue utilisateur voici comment jécris mes articles&nbsp;:</p>
<ol type="1">
<li>Jouvre un éditeur de texte (vim dans mon cas). Jédite un fichier markdow qui ressemble à ça :</li>
</ol>
<div class="sourceCode" id="cb1"><pre class="sourceCode markdown"><code class="sourceCode markdown"><a class="sourceLine" id="cb1-1" title="1">Un titre de page</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">Un titre de chapitre</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">Azur, nos bêtes sont bondées d'un cri.</a>
<a class="sourceLine" id="cb1-8" title="8">Je m'éveille songeant au fruit noir de l'anibe dans sa cupule</a>
<a class="sourceLine" id="cb1-9" title="9">véruqueuse et tronquée.</a>
<a class="sourceLine" id="cb1-10" title="10"></a>
<a class="sourceLine" id="cb1-11" title="11">Saint John Perse.</a>
<a class="sourceLine" id="cb1-12" title="12"></a>
<a class="sourceLine" id="cb1-13" title="13"><span class="fu">### Titre 3</span></a>
<a class="sourceLine" id="cb1-14" title="14"></a>
<a class="sourceLine" id="cb1-15" title="15">&gt;<span class="dt"> C'est un 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; C'est un second paragraphe dans le 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; ## C'est un H2 dans un blockquote</span></a></code></pre></div>
<ol start="2" type="1">
<li>Jouvre mon navigateur et je rafraichis de temps en temps pour voir les changements.</li>
<li>Une fois satisfait, je lance un script minimal qui fait grosso modo un simple <code>git push</code>. Mon blog est hébergé sur <a href="http://github.com">github</a>.</li>
</ol>
<p>A ne pas y regarder de trop près, on peut réduire le rôle dHakyll à&nbsp;:</p>
<blockquote>
<p>Créer (resp. mettre à jour) un fichier <span class="sc"><abbr title="HyperText Markup Language">html</abbr></span> lorsque je crée (resp. modifie) un fichier markdown.</p>
</blockquote>
<p>Bien que cela semble facile, il y a de nombreux détails cachés&nbsp;:</p>
<ul>
<li>Ajouter des métadatas comme des mots clés</li>
<li>Créer un page archive qui contient la liste de tous les articles</li>
<li>Gérer les fichier statiques</li>
<li>Créer un flux <span class="sc"><abbr title="Rich Site Summary">rss</abbr></span></li>
<li>Filtrer le contenu</li>
<li>Gérer les dépendances</li>
</ul>
<p>Le travail dHakyll est de vous aider avec tout ça. Commençons par expliquer les concepts basiques.</p>
<h2 id="les-concepts-et-la-syntaxe">Les concepts et la syntaxe</h2>
<div>
<img src="../../../../Scratch/img/blog/Hakyll-setup/overview.png" alt="Overview" />
</div>
<p>Pour chaque fichier que vous créer, il faut fournir&nbsp;:</p>
<ul>
<li>un chemin de destination</li>
<li>une liste de filtres du contenu</li>
</ul>
<p>Commençons par le cas le plus simple ; les fichiers statiques (images, fontes, etc…) Généralement, vous avec un répertoire source (ici le répertoire courant) et une répertoire destination <code>_site</code>.</p>
<p>Le code Hakyll est&nbsp;:</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">-- pour chaque fichier dans le répertoire static</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">-- on ne change pas le nom ni le répertoire</span></a>
<a class="sourceLine" id="cb2-4" title="4"> route idRoute</a>
<a class="sourceLine" id="cb2-5" title="5"> <span class="co">-- on ne modifie pas le contenu</span></a>
<a class="sourceLine" id="cb2-6" title="6"> compile copyFileCompiler</a></code></pre></div>
<p>Ce programme va copier <code>static/foo.jpg</code> dans <code>_site/static/foo.jpg</code>. Cest un peu lourd pour un simple <code>cp</code>. Maintenant comment faire pour transformer automatiquement un fichier markdown dans le bon <span class="sc"><abbr title="HyperText Markup Language">html</abbr></span>?</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">-- pour chaque fichier avec un extension md</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">-- changer son extension en 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">-- utiliser la librairie pandoc pour compiler le markdown en html</span></a>
<a class="sourceLine" id="cb3-6" title="6"> compile <span class="op">$</span> pandocCompiler</a></code></pre></div>
<p>Si vous créez un fichier <code>posts/toto.md</code>, cela créera un fichier <code>_site/posts/toto.html</code>.</p>
<p>Si le fichier <code>posts/foo.md</code> contient</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>le fichier <code>_site/posts/foo.html</code>, contiendra</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>Mais horreur ! <code>_site/posts/cthulhu.html</code> nest pas un <span class="sc"><abbr title="HyperText Markup Language">html</abbr></span> complet. Il ne possède ni header, ni footer, etc… Cest ici que nous utilisons des templates. Jajoute une nouvelle directive dans le bloc “compile”.</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>Maintenant si <code>templates/posts.html</code> contient:</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>Maintenant notre <code>ctuhlhu.html</code> contient</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>Cest facile. Mais il reste un problème à résoudre. Comment pouvons-nous changer le titre ? Ou par exemple, ajouter des mots clés ?</p>
<p>La solution est dutiliser les <code>Context</code>s. Pour cela, nous devrons ajouter des <em>metadonnées</em> à notre 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>Et modifier légèrement notre template&nbsp;:</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>Super facile!</p>
<p>La suite de larticle est en Anglais. Je la traduirai volontier si suffisamment de personnes me le demande gentillement.</p>
<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>Thats easy. Simply call the executable using <code>unixFilter</code>. Of course youll 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 didnt 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 wasnt 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 dont 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 dont 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. Lets 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 didnt 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>Nous pouvons aussi ajouter ces métadonnées dans un fichier externe (<code>toto.md.metadata</code>).<a href="#fnref1" class="footnote-back"></a></p></li>
</ol>
</section>
</div>
<div id="afterarticle">
<div id="social">
2021-05-25 20:25:47 +00:00
<a href="/rss.xml" target="_blank" rel="noopener noreferrer nofollow" class="social">RSS</a>
2021-04-18 10:23:24 +00:00
·
<a href="https://twitter.com/home?status=http%3A%2F%2Fyannesposito.com/Scratch/fr/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/fr/blog/Hakyll-setup/" target="_blank" rel="noopener noreferrer nofollow" class="social">FB</a>
<br />
<a class="message" href="../../../../Scratch/fr/blog/Social-link-the-right-way/">Ces liens sociaux préservent votre vie privée</a>
</div>
<div id="navigation">
<a href="../../../../">Accueil</a>
<span class="sep">¦</span>
<a href="../../../../Scratch/fr/blog">Blog</a>
<span class="sep">¦</span>
<a href="../../../../Scratch/fr/softwares">Logiciels</a>
<span class="sep">¦</span>
<a href="../../../../Scratch/fr/about">Auteur</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>
2022-10-26 09:26:08 +00:00
2021-04-18 10:23:24 +00:00
</div>
</div>
</div>
</div>
</body>
</html>