{
  "version": "https://jsonfeed.org/version/1.1",
  "title": "Thomas Citharel",
  "language": "fr",
  "home_page_url": "https://tcit.fr",
  "feed_url": "https://tcit.fr/feed.json",
  "description": "Je m’appelle Thomas, et je crée des outils web.",
  "author": {
    "name": "Thomas Citharel",
    "url": ""
  },
  "items": [{
      "id": "https://tcit.fr/post/dynamically-add-enum-values-in-elixir&amp;#39;s-graphql-library-absinthe/",
      "url": "https://tcit.fr/post/dynamically-add-enum-values-in-elixir&amp;#39;s-graphql-library-absinthe/",
      "title": "Dynamically add enum values in Elixir&#39;s GraphQL Library Absinthe",
      "content_html": "<p>Do you have a huge list of value acceptable for a GraphQL enum? Absinthe can dynamically extend the schema at runtime.</p>\n<p>While adding a &quot;category&quot; feature to the events in <a href=\"https://joinmobilizon.org/\">Mobilizon</a>, I wanted to restict the values this field could take. Usually I use an enum in the GraphQL schema definition for this kind of situation, for instance:</p>\n<pre class=\"language-elixir\"><code class=\"language-elixir\"><span class=\"token attribute variable\">@desc</span> <span class=\"token string\">\"The list of join options for an event\"</span><br />  enum <span class=\"token atom symbol\">:event_join_options</span> <span class=\"token keyword\">do</span><br />    <span class=\"token function\">value</span><span class=\"token punctuation\">(</span><span class=\"token atom symbol\">:free</span><span class=\"token punctuation\">,</span> <span class=\"token attr-name\">description:</span> <span class=\"token string\">\"Anyone can join and is automatically accepted\"</span><span class=\"token punctuation\">)</span><br />    <span class=\"token function\">value</span><span class=\"token punctuation\">(</span><span class=\"token atom symbol\">:restricted</span><span class=\"token punctuation\">,</span> <span class=\"token attr-name\">description:</span> <span class=\"token string\">\"Manual acceptation\"</span><span class=\"token punctuation\">)</span><br />    <span class=\"token function\">value</span><span class=\"token punctuation\">(</span><span class=\"token atom symbol\">:invite</span><span class=\"token punctuation\">,</span> <span class=\"token attr-name\">description:</span> <span class=\"token string\">\"Participants must be invited\"</span><span class=\"token punctuation\">)</span><br />  <span class=\"token keyword\">end</span></code></pre>\n<p>This uses the <code>enum</code> macro and three <code>value</code> macros. But in this case there would be <em>a lot</em> of options for <code>value</code>, so it wouldn't make sense to have them all in the schema declaration.</p>\n<p>Moreover, I want this list of categories to be extendable in the future by the instance administrator, who doesn't want to recompile to extend the list.</p>\n<p>So the Absinthe docs are far from being perfect, but you can find <a href=\"https://hexdocs.pm/absinthe/Absinthe.Schema.html#module-custom-schema-manipulation-in-progress\">mention of custom schema manipulation</a>. This page, with the help of a few Github issues and <a href=\"https://github.com/absinthe-graphql/absinthe/blob/master/test/absinthe/schema/manipulation_test.exs#L84-L130\">a test file</a>, helped me see clear through this.</p>\n<p>For starters, let's create a new module to dynamically build our new enum. There's a few comments inline.</p>\n<pre class=\"language-elixir\"><code class=\"language-elixir\"><span class=\"token keyword\">defmodule</span> <span class=\"token module class-name\">Mobilizon</span><span class=\"token punctuation\">.</span><span class=\"token module class-name\">GraphQL</span><span class=\"token punctuation\">.</span><span class=\"token module class-name\">Schema</span><span class=\"token punctuation\">.</span><span class=\"token module class-name\">Custom</span><span class=\"token punctuation\">.</span><span class=\"token module class-name\">EnumTypes</span> <span class=\"token keyword\">do</span><br />  <span class=\"token keyword\">alias</span> <span class=\"token module class-name\">Absinthe</span><span class=\"token punctuation\">.</span><span class=\"token module class-name\">Blueprint</span><span class=\"token punctuation\">.</span><span class=\"token module class-name\">Schema</span><br />  <span class=\"token keyword\">alias</span> <span class=\"token module class-name\">Absinthe</span><span class=\"token punctuation\">.</span><span class=\"token module class-name\">Schema</span><span class=\"token punctuation\">.</span><span class=\"token module class-name\">Notation</span><br />  <span class=\"token keyword\">alias</span> <span class=\"token module class-name\">Absinthe</span><span class=\"token punctuation\">.</span><span class=\"token punctuation\">{</span><span class=\"token module class-name\">Blueprint</span><span class=\"token punctuation\">,</span> <span class=\"token module class-name\">Pipeline</span><span class=\"token punctuation\">,</span> <span class=\"token module class-name\">Phase</span><span class=\"token punctuation\">}</span><br /><br />  <span class=\"token comment\"># The list of categories</span><br />  <span class=\"token comment\"># having an atom identifier and a string label</span><br />  <span class=\"token comment\"># This is currently being defined as a module attribute,</span><br />  <span class=\"token comment\"># but in the future it will be expanded by some admin</span><br />  <span class=\"token comment\"># configuration as well</span><br />  <span class=\"token attribute variable\">@categories</span> <span class=\"token punctuation\">[</span><br />    <span class=\"token punctuation\">%</span><span class=\"token punctuation\">{</span><br />      <span class=\"token attr-name\">id:</span> <span class=\"token atom symbol\">:arts</span><span class=\"token punctuation\">,</span><br />      <span class=\"token attr-name\">label:</span> <span class=\"token string\">\"ARTS\"</span><br />    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br />    <span class=\"token comment\"># … a long list of categories</span><br />  <span class=\"token punctuation\">]</span><br /><br />  <span class=\"token keyword\">def</span> <span class=\"token function\">pipeline</span><span class=\"token punctuation\">(</span>pipeline<span class=\"token punctuation\">)</span> <span class=\"token keyword\">do</span><br />    <span class=\"token comment\"># When to insert this override</span><br />    <span class=\"token module class-name\">Pipeline</span><span class=\"token punctuation\">.</span><span class=\"token function\">insert_after</span><span class=\"token punctuation\">(</span>pipeline<span class=\"token punctuation\">,</span> <span class=\"token module class-name\">Phase</span><span class=\"token punctuation\">.</span><span class=\"token module class-name\">Schema</span><span class=\"token punctuation\">.</span><span class=\"token module class-name\">TypeImports</span><span class=\"token punctuation\">,</span> __MODULE__<span class=\"token punctuation\">)</span><br />  <span class=\"token keyword\">end</span><br /><br />  <span class=\"token comment\"># Adding this enum to the list of schema definitions</span><br />  <span class=\"token keyword\">def</span> <span class=\"token function\">run</span><span class=\"token punctuation\">(</span>blueprint <span class=\"token operator\">=</span> <span class=\"token punctuation\">%</span><span class=\"token module class-name\">Blueprint</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> _<span class=\"token punctuation\">)</span> <span class=\"token keyword\">do</span><br />    <span class=\"token punctuation\">%</span><span class=\"token punctuation\">{</span><span class=\"token attr-name\">schema_definitions:</span> <span class=\"token punctuation\">[</span>schema<span class=\"token punctuation\">]</span><span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> blueprint<br /><br />    new_enum <span class=\"token operator\">=</span> <span class=\"token function\">build_dynamic_enum</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><br /><br />    schema <span class=\"token operator\">=</span><br />      <span class=\"token module class-name\">Map</span><span class=\"token punctuation\">.</span><span class=\"token function\">update!</span><span class=\"token punctuation\">(</span>schema<span class=\"token punctuation\">,</span> <span class=\"token atom symbol\">:type_definitions</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">fn</span> type_definitions <span class=\"token operator\">-></span><br />        <span class=\"token punctuation\">[</span>new_enum <span class=\"token operator\">|</span> type_definitions<span class=\"token punctuation\">]</span><br />      <span class=\"token keyword\">end</span><span class=\"token punctuation\">)</span><br /><br />    <span class=\"token punctuation\">{</span><span class=\"token atom symbol\">:ok</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">%</span><span class=\"token punctuation\">{</span>blueprint <span class=\"token operator\">|</span> <span class=\"token attr-name\">schema_definitions:</span> <span class=\"token punctuation\">[</span>schema<span class=\"token punctuation\">]</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span><br />  <span class=\"token keyword\">end</span><br /><br />  <span class=\"token comment\"># Building the enum itself</span><br />  <span class=\"token keyword\">def</span> build_dynamic_enum <span class=\"token keyword\">do</span><br />    <span class=\"token punctuation\">%</span><span class=\"token module class-name\">Schema</span><span class=\"token punctuation\">.</span><span class=\"token module class-name\">EnumTypeDefinition</span><span class=\"token punctuation\">{</span><br />      <span class=\"token attr-name\">name:</span> <span class=\"token string\">\"EventCategory\"</span><span class=\"token punctuation\">,</span><br />      <span class=\"token attr-name\">identifier:</span> <span class=\"token atom symbol\">:event_category</span><span class=\"token punctuation\">,</span><br />      <span class=\"token attr-name\">module:</span> __MODULE__<span class=\"token punctuation\">,</span><br />      <span class=\"token attr-name\">__reference__:</span> <span class=\"token module class-name\">Notation</span><span class=\"token punctuation\">.</span><span class=\"token function\">build_reference</span><span class=\"token punctuation\">(</span>__ENV__<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span><br />      <span class=\"token attr-name\">values:</span><br />        <span class=\"token comment\"># Create a `Schema.EnumValueDefinition`</span><br />        <span class=\"token comment\"># for each value in `@categories`</span><br />        <span class=\"token module class-name\">Enum</span><span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token attribute variable\">@categories</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">fn</span> <span class=\"token punctuation\">%</span><span class=\"token punctuation\">{</span><span class=\"token attr-name\">id:</span> id<span class=\"token punctuation\">,</span> <span class=\"token attr-name\">label:</span> label<span class=\"token punctuation\">}</span> <span class=\"token operator\">-></span><br />          <span class=\"token punctuation\">%</span><span class=\"token module class-name\">Schema</span><span class=\"token punctuation\">.</span><span class=\"token module class-name\">EnumValueDefinition</span><span class=\"token punctuation\">{</span><br />            <span class=\"token attr-name\">identifier:</span> id<span class=\"token punctuation\">,</span><br />            <span class=\"token comment\"># The `value` can either be `id` or `label`</span><br />            <span class=\"token comment\"># depending whether what you want to be given</span><br />            <span class=\"token attr-name\">value:</span> label<span class=\"token punctuation\">,</span><br />            <span class=\"token attr-name\">name:</span> label<span class=\"token punctuation\">,</span><br />            <span class=\"token attr-name\">module:</span> __MODULE__<span class=\"token punctuation\">,</span><br />            <span class=\"token attr-name\">__reference__:</span> <span class=\"token module class-name\">Notation</span><span class=\"token punctuation\">.</span><span class=\"token function\">build_reference</span><span class=\"token punctuation\">(</span>__ENV__<span class=\"token punctuation\">)</span><br />          <span class=\"token punctuation\">}</span><br />        <span class=\"token keyword\">end</span><span class=\"token punctuation\">)</span><br />    <span class=\"token punctuation\">}</span><br />  <span class=\"token keyword\">end</span><br /><span class=\"token keyword\">end</span></code></pre>\n<p>Finally, we just have to add in our schema definition file the following <code>@pipeline_modifier</code> attribute:</p>\n<pre class=\"language-elixir\"><code class=\"language-elixir\"><span class=\"token keyword\">defmodule</span> <span class=\"token module class-name\">Mobilizon</span><span class=\"token punctuation\">.</span><span class=\"token module class-name\">GraphQL</span><span class=\"token punctuation\">.</span><span class=\"token module class-name\">Schema</span> <span class=\"token keyword\">do</span><br />  <span class=\"token keyword\">use</span> <span class=\"token module class-name\">Absinthe</span><span class=\"token punctuation\">.</span><span class=\"token module class-name\">Schema</span><br /><br />  <span class=\"token attribute variable\">@pipeline_modifier</span> <span class=\"token module class-name\">Custom</span><span class=\"token punctuation\">.</span><span class=\"token module class-name\">EnumTypes</span><br /><br />  <span class=\"token comment\"># [… our whole schema]</span><br /><span class=\"token keyword\">end</span></code></pre>\n<p>And boom, we can use our new enum just like this:</p>\n<pre class=\"language-elixir\"><code class=\"language-elixir\">field <span class=\"token atom symbol\">:create_event</span><span class=\"token punctuation\">,</span> <span class=\"token attr-name\">type:</span> <span class=\"token atom symbol\">:event</span> <span class=\"token keyword\">do</span><br />  <span class=\"token comment\"># …</span><br />  <span class=\"token function\">arg</span><span class=\"token punctuation\">(</span><span class=\"token atom symbol\">:category</span><span class=\"token punctuation\">,</span><br />    <span class=\"token atom symbol\">:event_category</span><span class=\"token punctuation\">,</span><br />    <span class=\"token comment\"># string or atom depending on what you use for value above</span><br />    <span class=\"token attr-name\">default_value:</span> <span class=\"token string\">\"ARTS\"</span><span class=\"token punctuation\">,</span><br />    <span class=\"token attr-name\">description:</span> <span class=\"token string\">\"The event's category\"</span><br />  <span class=\"token punctuation\">)</span><br />  <span class=\"token comment\"># …</span><br /><span class=\"token keyword\">end</span></code></pre>\n",
      "date_published": "2022-03-27T18:22:36Z"
    },{
      "id": "https://tcit.fr/post/imprimer-en-pdf/",
      "url": "https://tcit.fr/post/imprimer-en-pdf/",
      "title": "Imprimer en PDF",
      "content_html": "<p>Quand je veux imprimer un fichier PDF sur une imprimante jamais configurée, ça prend souvent des heures sans raison.</p>\n<p>Je constate alors ce message dans les logs :</p>\n<pre><code>Use &quot;pdftops-renderer&quot; option (see README file) to use Ghostscript or MuPDF for the PDF -&gt; PostScript conversion\n</code></pre>\n<p>Globalement il me semble que c'est la conversion de PDF en un truc compréhensible par l'imprimante (Ghostscript, PostScript) qui rate.</p>\n<p>Sur le web, il est proposé d'utiliser <code>pdftops</code> comme outil de rendu (qui semble utiliser <code>Poppler</code>), mais ce qui marche le mieux pour moi c'est directement d'utiliser <code>Ghostscript</code>.</p>\n<pre class=\"language-bash\"><code class=\"language-bash\">lpadmin <span class=\"token parameter variable\">-p</span> mon_imprimante <span class=\"token parameter variable\">-o</span> pdftops-renderer-default<span class=\"token operator\">=</span>gs</code></pre>\n<p>Où <code>mon_imprimante</code> est le nom de l'imprimante, que vous pouvez trouver avec <code>lpstat -p</code>.</p>\n<p>L'impression se fait alors quasi-instantanément.</p>\n",
      "date_published": "2022-01-17T09:20:00Z"
    },{
      "id": "https://tcit.fr/post/faire-fonctionner-le-wifi-intel-sous-fedora-35/",
      "url": "https://tcit.fr/post/faire-fonctionner-le-wifi-intel-sous-fedora-35/",
      "title": "Faire fonctionner le wifi Intel sous Fedora 35",
      "content_html": "<p>Si vous avez migré vers la version 35 de Fedora et que vous utilisez une carte Wi-Fi Intel, cela peut vous aider.</p>\n<p>Tout d'abord, voyons si vous êtes concerné :</p>\n<pre><code>lspci | grep &quot;Network controller&quot;\n02:00.0 Network controller: Intel Corporation Wi-Fi 6 AX200 (rev 1a)\n</code></pre>\n<p>Si la référence de votre carte correspond à <code>AX2xx</code>, vous êtes probablement concerné.</p>\n<p>En Octobre 2021 le microcode pour cette carte <a href=\"https://bodhi.fedoraproject.org/updates/FEDORA-2021-e353a56911\">a été migré</a> dans un paquet séparé du fameux <code>linux-firmware</code>.</p>\n<p>Il faut alors installer <code>iwlax2xx-firmware</code> pour faire refonctionner le Wi-Fi. Un redémarrage et c'est reparti.</p>\n",
      "date_published": "2021-10-04T09:20:00Z"
    },{
      "id": "https://tcit.fr/post/publier-un-blog-statique-avec-gridsome/",
      "url": "https://tcit.fr/post/publier-un-blog-statique-avec-gridsome/",
      "title": "Publier un blog statique avec Gridsome",
      "content_html": "<p><strong>Gridsome</strong> est un <em>framework</em> pour générer des sites statiques à l'aide de VueJS et GraphQL.</p>\n<p>On parle aussi de <em>framework</em> <a href=\"https://jamstatic.fr/2019/02/07/c-est-quoi-la-jamstack/\">JAMStack</a>, pour Javascript, APIs et <em>Markup</em>. En gros, ce terme décrit simplement d'avoir la possibilité d'ajouter des fonctionnalités dynamiques par dessus votre site statique généré à partir de fichiers sources comme du Markdown, le HTML étant hydraté avec l'application Javascript.</p>\n<p>Il n'y a pas de fonctionnalités statiques ici, j'ai juste besoin d'un blog, il n'y aura pas grande différence à l'utilisation si jamais vous avez le Javascript activé ou non dans votre navigateur[^1].</p>\n<p>J'ai choisi Gridsome car il utilise le <em>framework</em> VueJS avec lequel je suis plus familiarisé, mais c'est quasiment le même fonctionnement que <a href=\"https://www.gatsbyjs.com/\">GatsbyJS</a> qui utilise ReactJS.</p>\n<p>J'avais eu l'occasion d'utiliser Gatsby pour <a href=\"https://entraide.chatons.org/\">entraide.chatons.org</a> et j'avais trouvé le concept intéressant. Aujourd'hui, cet article que vous lisez est justement affiché dans une page d'un site statique généré par Gridsome.</p>\n<p>Comme indiqué <a href=\"https://gridsome.org/\">sur la page de présentation de Gridsome</a> : vous prenez des sources de données en entrée, vous effectuez des traitements sur les données (sélection, transformation, affichage) et vous déployez les fichiers HTML et <em>assets</em> produits.</p>\n<h2 id=\"creer-un-projet-gridsome\" tabindex=\"-1\">Créer un projet Gridsome <a class=\"direct-link\" href=\"https://tcit.fr/post/publier-un-blog-statique-avec-gridsome/#creer-un-projet-gridsome\" aria-hidden=\"true\">#</a></h2>\n<p>On commence par installer le module qui fournit la ligne de commande :</p>\n<pre class=\"language-shell\"><code class=\"language-shell\"><span class=\"token function\">yarn</span> global <span class=\"token function\">add</span> @gridsome/cli</code></pre>\n<p>J'utilise <a href=\"https://yarnpkg.com/\"><code>yarn</code></a> dans les commandes, mais vous pouvez bien sûr utiliser les équivalents <code>npm</code> si c'est ce que vous préférez.</p>\n<p>Puis on crée un nouveau projet :</p>\n<pre class=\"language-shell\"><code class=\"language-shell\">gridsome create mon-site</code></pre>\n<p>Cela récupère le modèle du projet, le met à jour avec le nom du projet, et installe les dépendances.</p>\n<p>On peut alors se mettre dans le dossier du projet nouvellement créé puis lance le serveur de développement, par défaut sur le port 8080.</p>\n<pre class=\"language-shell\"><code class=\"language-shell\"><span class=\"token builtin class-name\">cd</span> mon-site<br />gridsome develop</code></pre>\n<h2 id=\"structure-du-projet\" tabindex=\"-1\">Structure du projet <a class=\"direct-link\" href=\"https://tcit.fr/post/publier-un-blog-statique-avec-gridsome/#structure-du-projet\" aria-hidden=\"true\">#</a></h2>\n<p>Vous devriez avoir une structure de projet équivalente voire égale à celle ci-dessous :</p>\n<pre><code>├── gridsome.config.js\n├── gridsome.server.js\n├── package.json\n├── README.md\n├── src\n│   ├── components\n│   │   └── README.md\n│   ├── favicon.png\n│   ├── layouts\n│   │   ├── Default.vue\n│   │   └── README.md\n│   ├── main.js\n│   ├── pages\n│   │   ├── About.vue\n│   │   ├── Index.vue\n│   │   └── README.md\n│   └── templates\n│       └── README.md\n├── static\n│   └── README.md\n└── yarn.lock\n</code></pre>\n<p>On voit dans <code>src/pages/</code> les fichiers <code>About.vue</code> et <code>Index.vue</code>, qui correspondent aux deux routes accessibles via la barre de navigation. Notez donc que le routage de base se fait via les fichiers disponibles dans <code>/pages/</code>. <code>Index.vue</code> correspond à la page d'accueil <code>/</code>, et un fichier <code>MonProjet.vue</code> donnerait une route <code>/mon-projet</code>.</p>\n<p>On a également le fichier <code>Default.vue</code> dans <code>/src/layouts/</code>. Les <em>layouts</em> sont utilisés pour envelopper vos pages avec des éléments communs aux pages, typiquement l'en-tête de la page, la barre de navigation, le pied-de-page… Dans nos pages, par exemple <code>About.vue</code>, le contenu est enveloppé par l'élément <code>&lt;Layout&gt;</code> :</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>template</span><span class=\"token punctuation\">></span></span><br />  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>Layout</span><span class=\"token punctuation\">></span></span><br />    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span>About us<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h1</span><span class=\"token punctuation\">></span></span><br />    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error doloremque omnis animi, eligendi magni a voluptatum, vitae, consequuntur rerum illum odit fugit assumenda rem dolores inventore iste reprehenderit maxime! Iusto.<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><br />  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>Layout</span><span class=\"token punctuation\">></span></span><br /><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>template</span><span class=\"token punctuation\">></span></span></code></pre>\n<h2 id=\"ajout-et-representation-des-donnees\" tabindex=\"-1\">Ajout et représentation des données <a class=\"direct-link\" href=\"https://tcit.fr/post/publier-un-blog-statique-avec-gridsome/#ajout-et-representation-des-donnees\" aria-hidden=\"true\">#</a></h2>\n<p>Le squelette de notre site étant exploré, voyons comment y insérer nos données. Gridsome utilise <a href=\"https://graphql.org/\">GraphQL</a>, un langage de requêtes. Nous avons par exemple un premier exemple de requête GraphQL dans le fichier <code>layouts/Default.vue</code>, où le nom du site (défini dans le fichier de configuration <code>gridsome.config.js</code>) est récupéré avec la requête suivante :</p>\n<pre class=\"language-graphql\"><code class=\"language-graphql\"><span class=\"token keyword\">query</span> <span class=\"token punctuation\">{</span><br />  <span class=\"token object\">metadata</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token property\">siteName</span><br />  <span class=\"token punctuation\">}</span><br /><span class=\"token punctuation\">}</span></code></pre>\n<p>La variable <code>siteName</code> est alors disponible via l'expression <code>$static.metadata.siteName</code> dans notre template VueJS.</p>\n<p>Pour importer nos propres données, prenons l'exemple basique de billets de blog sous forme de fichiers locaux au format Markdown.</p>\n<p>Installons les modules <a href=\"https://gridsome.org/plugins/@gridsome/source-filesystem\"><code>@gridsome/source-filesystem</code></a> afin de récupérer le contenu des fichiers et <a href=\"https://gridsome.org/plugins/@gridsome/transformer-remark\"><code>@gridsome/transformer-remark</code></a> afin de transformer notre contenu markdown en HTML et surtout convertir l'éventuel <em>front matter</em> YAML en métadonnées utilisables.</p>\n<p>Nous allons ajouter la configuration donnée en exemple dans <code>gridsome.config.js</code> :</p>\n<pre class=\"language-js\"><code class=\"language-js\">module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><br />  <span class=\"token literal-property property\">plugins</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><br />    <span class=\"token punctuation\">{</span><br />      <span class=\"token literal-property property\">use</span><span class=\"token operator\">:</span> <span class=\"token string\">'@gridsome/source-filesystem'</span><span class=\"token punctuation\">,</span><br />      <span class=\"token literal-property property\">options</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br />        <span class=\"token literal-property property\">typeName</span><span class=\"token operator\">:</span> <span class=\"token string\">'BlogPost'</span><span class=\"token punctuation\">,</span><br />        <span class=\"token literal-property property\">path</span><span class=\"token operator\">:</span> <span class=\"token string\">'./content/blog/**/*.md'</span><span class=\"token punctuation\">,</span><br />      <span class=\"token punctuation\">}</span><br />    <span class=\"token punctuation\">}</span><br />  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span><br />  <span class=\"token literal-property property\">templates</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token literal-property property\">BlogPost</span><span class=\"token operator\">:</span> <span class=\"token string\">'/blog/:year/:month/:day/:title'</span><br />  <span class=\"token punctuation\">}</span><br /><span class=\"token punctuation\">}</span></code></pre>\n<p>Puis créons l'arborescence <code>content/blog/2020</code> et un fichier <code>hello world.md</code> au bout avec le contenu de base suivant :</p>\n<pre class=\"language-markdown\"><code class=\"language-markdown\"><span class=\"token front-matter-block\"><span class=\"token punctuation\">---</span><br /><span class=\"token front-matter yaml language-yaml\">date: 2020-01-05<br />title: \"Hello World\"</span><br /><span class=\"token punctuation\">---</span></span><br />Il s'agit de mon <span class=\"token bold\"><span class=\"token punctuation\">**</span><span class=\"token content\">premier</span><span class=\"token punctuation\">**</span></span> contenu !</code></pre>\n<p>On redémarre le serveur de développement Gridsome car on a changé la configuration puis on ouvre <a href=\"http://localhost:8080/___explore\">le bac à sable</a> GraphQL pour effectuer nos premières requêtes et voir le résultat facilement.</p>\n<p>Par exemple, pour récupérer la liste de tous nos posts, on écrira :</p>\n<pre class=\"language-graphql\"><code class=\"language-graphql\"><span class=\"token keyword\">query</span> <span class=\"token punctuation\">{</span><br />   <span class=\"token object\">allBlogPost</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token object\">edges</span> <span class=\"token punctuation\">{</span><br />      <span class=\"token object\">node</span> <span class=\"token punctuation\">{</span><br />        <span class=\"token property\">title</span><span class=\"token punctuation\">,</span><br />        <span class=\"token property-query\">date</span><span class=\"token punctuation\">(</span><span class=\"token attr-name\">format</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"DD/MM/YYYY\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span><br />        <span class=\"token property\">path</span><br />      <span class=\"token punctuation\">}</span><br />    <span class=\"token punctuation\">}</span><br />  <span class=\"token punctuation\">}</span><br /><span class=\"token punctuation\">}</span></code></pre>\n<p>Si on édite notre page <code>Index.vue</code>, on peut rajouter cette requête dans un bloc <code>&lt;page-query&gt;</code> et ensuite accéder aux données via <code>$page.allBlogPost</code>, comme par comme dans l'exemple suivant où nous rajoutons une liste des billets au template :</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>ul</span> <span class=\"token attr-name\">v-for</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>edge in $page.allBlogPost.edges<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">:key</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>edge.node.id<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br />  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span><span class=\"token punctuation\">></span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span><br /><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>ul</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>Ajoutons ensuite un fichier <code>BlogPost.vue</code> dans nos <code>templates/</code> pour représenter ces entités:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>template</span><span class=\"token punctuation\">></span></span><br />  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>Layout</span><span class=\"token punctuation\">></span></span><br />    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>article</span><span class=\"token punctuation\">></span></span><br />      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span>{{ $page.blogPost.title }}<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h1</span><span class=\"token punctuation\">></span></span><br />      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>span</span><span class=\"token punctuation\">></span></span>{{ $page.blogPost.date }}<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>span</span><span class=\"token punctuation\">></span></span><br />      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span> <span class=\"token attr-name\">v-html</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>$page.blogPost.content<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br />    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>article</span><span class=\"token punctuation\">></span></span><br />  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>Layout</span><span class=\"token punctuation\">></span></span><br /><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>template</span><span class=\"token punctuation\">></span></span><br /><br /><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>page-query</span><span class=\"token punctuation\">></span></span><br />query BlogPost($path: String!) {<br />   blogPost(path: $path) {<br />        title,<br />        date(format: \"DD/MM/YYYY\"),<br />        content<br />        path<br />  }<br />}<br /><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>page-query</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>Comme on l'a vu, les données de la requête GraphQL <code>blogPost</code> sont injectées dans la variable <code>$page</code> accessible dans mon template. Maintenant que l'on a une page dédiée pour afficher chaque billet, ajoutons un lien depuis notre liste sur la page <code>Index.vue</code>, en changeant notre <code>&lt;li&gt;</code> en :</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span><span class=\"token punctuation\">></span></span><br />  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>g-link</span> <span class=\"token attr-name\">:to</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>edge.node.path<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>g-link</span><span class=\"token punctuation\">></span></span><br /><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>La balise <code>&lt;g-link&gt;</code> crée lors du rendu des balises <code>&lt;a&gt;</code> tout ce qu'il y a de plus basique, mais permet aussi le préchargement des liens (voir les notes de bas de page). En cliquant dessus, on arrive finalement sur notre page montrant un article en particulier.</p>\n<h2 id=\"generation-et-publication\" tabindex=\"-1\">Génération et publication <a class=\"direct-link\" href=\"https://tcit.fr/post/publier-un-blog-statique-avec-gridsome/#generation-et-publication\" aria-hidden=\"true\">#</a></h2>\n<p>Générons maintenant notre site avec <code>gridsome build</code>, puis servons le contenu du dossier <code>dist</code>, par exemple avec <a href=\"https://github.com/vercel/serve\">serve</a> : <code>serve dist</code>.</p>\n<p>Je vous laisse vérifier que la navigation fonctionne bien et que le HTML produit contient bien notre contenu.</p>\n<p>On peut publier le contenu de <code>dist</code> là où on le souhaite, voici un exemple de fichier de configuration pour le publier sur Gitlab Pages :</p>\n<pre class=\"language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">image</span><span class=\"token punctuation\">:</span> node<span class=\"token punctuation\">:</span><span class=\"token number\">14</span><br /><span class=\"token key atrule\">deploy</span><span class=\"token punctuation\">:</span><br />  <span class=\"token key atrule\">stage</span><span class=\"token punctuation\">:</span> deploy<br />  <span class=\"token key atrule\">script</span><span class=\"token punctuation\">:</span><br />    <span class=\"token punctuation\">-</span> yarn install<br />    <span class=\"token punctuation\">-</span> yarn build<br />    <span class=\"token punctuation\">-</span> gzip <span class=\"token punctuation\">-</span>kv <span class=\"token punctuation\">-</span>6 <span class=\"token punctuation\">-</span>r public<br />  <span class=\"token key atrule\">artifacts</span><span class=\"token punctuation\">:</span><br />    <span class=\"token key atrule\">paths</span><span class=\"token punctuation\">:</span><br />      <span class=\"token punctuation\">-</span> public</code></pre>\n<p>Je m'arrête là pour parler de Gridsome, mais j'ai quand même prévu de parler de comment gérer mes contenus sur ce site avec <a href=\"https://www.netlifycms.org/\">NetlifyCMS</a>, et comment mettre en place un <code>chroot</code> sur un serveur pour y faire un rsync depuis notre CI afin de déployer notre site.</p>\n<p>[^1]: Une différence est que si le Javascript est activé, Gridsome est censé observer les liens internes actuellement affichés à l'écran (avec <a href=\"https://developer.mozilla.org/fr/docs/Web/API/Intersection_Observer_API\"><code>IntersectionObserver</code></a>) pour les précharger afin que les chargements de page soient effectués avant même le clic éventuel sur le lien. Les gains devraient rester minimaux étant donné qu'il n'y a qu'un contenu HTML à récupérer depuis le serveur.</p>\n",
      "date_published": "2020-05-22T20:35:53Z"
    },{
      "id": "https://tcit.fr/post/terre-brulee/",
      "url": "https://tcit.fr/post/terre-brulee/",
      "title": "Terre Brûlée",
      "content_html": "<p>Au vent, des landes de pierre…<br />\nMaintenant que cette chanson est en tête, je voulais juste partager quelques photos d'Irlande.</p>\n<p>J'y étais en Juin, en <em>road trip</em> sur la plus grande partie du littoral de la moitié Nord.<br />\nVoici des photos de mes coins préférés, surtout dans le comté de Mayo, de Downpatrick Head à la vallée de Doolough, en passant par l'île d'Achill et en poussant jusqu'au parc national du Connemara.</p>\n<p>Elles sont classées par ordre chronologique.</p>\n",
      "date_published": "2019-11-09T22:57:27Z"
    },{
      "id": "https://tcit.fr/post/internationalisation-simple-des-dates-dans-le-navigateur/",
      "url": "https://tcit.fr/post/internationalisation-simple-des-dates-dans-le-navigateur/",
      "title": "Internationalisation simple des dates dans le navigateur",
      "content_html": "<p>Nous allons voir dans cet article comment formatter des dates facilement dans le navigateur en évitant de faire appel à des bibliothèques tierces.</p>\n<h2 id=\"formater-avec-momentjs\" tabindex=\"-1\">Formater avec MomentJS <a class=\"direct-link\" href=\"https://tcit.fr/post/internationalisation-simple-des-dates-dans-le-navigateur/#formater-avec-momentjs\" aria-hidden=\"true\">#</a></h2>\n<p>Lorsque l'on veut manipuler des données temporelles avec Javascript dans le navigateur, on se repose souvent sur la bibliothèque <a href=\"https://momentjs.com/\">Moment.js</a>.<br />\nElle permet en effet de formater des dates à sa convenance :</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token function\">moment</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">format</span><span class=\"token punctuation\">(</span><span class=\"token string\">'MMMM Do YYYY, HH:mm:ss'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>  <br /><span class=\"token comment\">// October 19th 2019, 19:04:56</span></code></pre>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token function\">moment</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">format</span><span class=\"token punctuation\">(</span><span class=\"token string\">'dddd, MMMM do YYYY'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>  <br /><span class=\"token comment\">// Saturday, October 6th 2019</span></code></pre>\n<p>Si vous chargez aussi le support des différentes <em>locales</em>, ça peut vous donner ceci :</p>\n<pre class=\"language-js\"><code class=\"language-js\">moment<span class=\"token punctuation\">.</span><span class=\"token function\">locale</span><span class=\"token punctuation\">(</span><span class=\"token string\">'fr'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>  <br /><span class=\"token function\">moment</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">format</span><span class=\"token punctuation\">(</span><span class=\"token string\">'LLL'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>  <br /><span class=\"token comment\">// 19 octobre 2019 19:09</span></code></pre>\n<p>Plutôt pratique, n'est-ce pas ? Du coup Moment.js est très populaire (42k <em>stars</em> sur Github) et très utilisé (presque <a href=\"https://npm-stat.com/charts.html?package=moment\">2 millions d'installations journalières</a> via npm, où plus de 36 000 paquets en sont dépendants ).</p>\n<h2 id=\"confort-vs-poids\" tabindex=\"-1\">Confort vs poids <a class=\"direct-link\" href=\"https://tcit.fr/post/internationalisation-simple-des-dates-dans-le-navigateur/#confort-vs-poids\" aria-hidden=\"true\">#</a></h2>\n<p>Le souci de Moment.js, c'est son poids énorme de 329Ko (non compressé, et avec toutes les locales).<br />\nDu coup ça fait un sacré module à charger (et il faut mieux qu'il soit chargé dès le début, c'est pas très joli quand les dates s'affichent une fois seulement que la page est chargée).</p>\n<p>Y a quelques solutions pour améliorer cela, par exemple charger uniquement la <em>locale</em> de l'utilisateur qui peut être fournie par le backend en fonction de l'en-tête <code>Accept-Language</code>.<br />\nOn peut ensuite éventuellement charger dynamiquement d'autres locales si jamais l'utilisateur⋅ice décide de changer de langue.</p>\n<p>Cela dit, même en chargeant uniquement le cœur de Moment.js, on reste à plusieurs dizaines de kilo-octets pour une utilisé potentiellement très limitée.</p>\n<p>En réaction à cette problématique, les bibliothèques <a href=\"https://github.com/iamkun/dayjs\">dayjs</a> et <a href=\"https://date-fns.org/\">date-fns</a> - de poids beaucoup plus réduit - existent. Date-fns permet de faire du <em>tree-shaking</em> avec Webpack pour importer uniquement les modules dont on a besoin et dayjs n'incorpore que le minimum, en externalisant les fonctionnalités supplémentaires via des plugins.</p>\n<p>Pour la plupart des fonctionnalités, ça remplace très bien Moment.js. Vous pouvez voir un comparatif sur ce dépôt : <a href=\"https://github.com/you-dont-need/You-Dont-Need-Momentjs\">You don't (may not) need Moment.js</a>.</p>\n<h2 id=\"encore-plus-leger\" tabindex=\"-1\">Encore plus léger <a class=\"direct-link\" href=\"https://tcit.fr/post/internationalisation-simple-des-dates-dans-le-navigateur/#encore-plus-leger\" aria-hidden=\"true\">#</a></h2>\n<p>Et si on voulait s'épargner encore quelques kilo-octets, on regarderait du côté…de Javascript. En effet, il existe depuis relativement assez longtemps (<a href=\"https://www.ecma-international.org/ecma-402/1.0\">2012</a>) une API <code>Intl</code> avec notamment un objet <code>DateTimeFormat</code> fait pour formater des dates en fonction de la <code>locale</code>.</p>\n<p>Ça s'utilise comme cela :</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">let</span> date <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">new</span> <span class=\"token class-name\">Intl<span class=\"token punctuation\">.</span>DateTimeFormat</span><span class=\"token punctuation\">(</span><span class=\"token string\">'fr-FR'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">format</span><span class=\"token punctuation\">(</span>date<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token comment\">// 10/19/2019</span></code></pre>\n<p>Ça prend en charge correctement les caractères non-latins et le sens d'écriture de droite à gauche :</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">let</span> date <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">new</span> <span class=\"token class-name\">Intl<span class=\"token punctuation\">.</span>DateTimeFormat</span><span class=\"token punctuation\">(</span><span class=\"token string\">'ar-EG'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">format</span><span class=\"token punctuation\">(</span>date<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token comment\">// ١٩‏/١٠‏/٢٠١٩</span></code></pre>\n<p>Si on ne veut pas spécifier de <em>locale</em>, on peut passer l'argument <code>'default'</code> ou bien <code>undefined</code> au constructeur de <code>Intl.DateTimeFormat</code>, ça utilisera la <em>locale</em> configurée du navigateur :</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">let</span> date <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">new</span> <span class=\"token class-name\">Intl<span class=\"token punctuation\">.</span>DateTimeFormat</span><span class=\"token punctuation\">(</span><span class=\"token string\">'default'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">format</span><span class=\"token punctuation\">(</span>date<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token comment\">// 10/19/2019</span></code></pre>\n<p>Bon, et maintenant si on veut une vraie date formattée, comment on fait ?</p>\n<p>Avec le second argument du constructeur, pardi !</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">let</span> date <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">let</span> options <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">weekday</span><span class=\"token operator\">:</span> <span class=\"token string\">'long'</span><span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">year</span><span class=\"token operator\">:</span> <span class=\"token string\">'numeric'</span><span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">month</span><span class=\"token operator\">:</span> <span class=\"token string\">'long'</span><span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">day</span><span class=\"token operator\">:</span> <span class=\"token string\">'numeric'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">new</span> <span class=\"token class-name\">Intl<span class=\"token punctuation\">.</span>DateTimeFormat</span><span class=\"token punctuation\">(</span><span class=\"token string\">'default'</span><span class=\"token punctuation\">,</span> options<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">format</span><span class=\"token punctuation\">(</span>date<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token comment\">// samedi 19 octobre 2019</span><br /><span class=\"token keyword\">new</span> <span class=\"token class-name\">Intl<span class=\"token punctuation\">.</span>DateTimeFormat</span><span class=\"token punctuation\">(</span><span class=\"token string\">'ar-EG'</span><span class=\"token punctuation\">,</span> options<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">format</span><span class=\"token punctuation\">(</span>date<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token comment\">// السبت، ١٩ أكتوبر ٢٠١٩</span></code></pre>\n<p>La référence de ces options se trouve sur <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat\">cette page du MDN</a>.</p>\n<p>Comme l'API Intl est assez ancienne, <a href=\"https://caniuse.com/#feat=internationalization\">le support</a> est plutôt bon (Internet Explorer 11, Safari 10).</p>\n<h2 id=\"formatage-de-dates-relatives\" tabindex=\"-1\">Formatage de dates relatives <a class=\"direct-link\" href=\"https://tcit.fr/post/internationalisation-simple-des-dates-dans-le-navigateur/#formatage-de-dates-relatives\" aria-hidden=\"true\">#</a></h2>\n<p>Je note qu'il existe aussi un objet <a href=\"https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/RelativeTimeFormat\"><code>Intl.RelativeTimeFormat</code></a> pour afficher des temps relatifs :</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> rtf <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Intl<span class=\"token punctuation\">.</span>RelativeTimeFormat</span><span class=\"token punctuation\">(</span><span class=\"token string\">'default'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">numeric</span><span class=\"token operator\">:</span> <span class=\"token string\">\"auto\"</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />rtf<span class=\"token punctuation\">.</span><span class=\"token function\">format</span><span class=\"token punctuation\">(</span><span class=\"token operator\">-</span><span class=\"token number\">1</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"day\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token comment\">// 'hier'</span><br /><br />rtf<span class=\"token punctuation\">.</span><span class=\"token function\">format</span><span class=\"token punctuation\">(</span><span class=\"token number\">3</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"day\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token comment\">// 'dans 3 jours'</span><br /><br />rtf<span class=\"token punctuation\">.</span><span class=\"token function\">format</span><span class=\"token punctuation\">(</span><span class=\"token operator\">-</span><span class=\"token number\">6</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"month\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token comment\">// 'il y a 6 mois'</span></code></pre>\n<p>Cette fois par contre, <a href=\"https://caniuse.com/#feat=mdn-javascript_builtins_intl_relativetimeformat\">pas de support pour Internet Explorer, Edge ou Safari</a>, ce qui rend son emploi plus hasardeux. On peut bien entendu détecter cela avec</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>Intl<span class=\"token punctuation\">.</span>DateTimeFormat<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token comment\">// do something</span><br />    <span class=\"token comment\">// it should probably work</span><br /><span class=\"token punctuation\">}</span><br /><br /><span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>Intl<span class=\"token punctuation\">.</span>RelativeTimeFormat<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token comment\">// do something</span><br />    <span class=\"token comment\">// you're using Firefox or Chrome</span><br /><span class=\"token punctuation\">}</span></code></pre>\n<h2 id=\"conclusion\" tabindex=\"-1\">Conclusion <a class=\"direct-link\" href=\"https://tcit.fr/post/internationalisation-simple-des-dates-dans-le-navigateur/#conclusion\" aria-hidden=\"true\">#</a></h2>\n<p>Voilà, même avec l'addition récente de <code>RelativeTimeFormat</code>, l'API <code>Intl</code> est vraiment loin d'avoir toutes les fonctionnalités de Moment.js ou même de date-fns, mais s'il vous faut juste afficher quelques dates au bon format, pas besoin de charger des centaines de kilooctets pour rien.🙂</p>\n<h2 id=\"bonus\" tabindex=\"-1\">Bonus <a class=\"direct-link\" href=\"https://tcit.fr/post/internationalisation-simple-des-dates-dans-le-navigateur/#bonus\" aria-hidden=\"true\">#</a></h2>\n<p>En utilisant l'API Intl, on peut facilement récupérer la liste des mois et des noms des jours traduits dans la langue de l'utilisateur :</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">function</span> <span class=\"token function\">localeMonthNames</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />  <span class=\"token keyword\">const</span> monthNames <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span><br />  <span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">let</span> i <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span> i <span class=\"token operator\">&lt;</span> <span class=\"token number\">12</span><span class=\"token punctuation\">;</span> i <span class=\"token operator\">+=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token keyword\">const</span> d <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token number\">2019</span><span class=\"token punctuation\">,</span> i<span class=\"token punctuation\">,</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />    <span class=\"token keyword\">const</span> month <span class=\"token operator\">=</span> d<span class=\"token punctuation\">.</span><span class=\"token function\">toLocaleString</span><span class=\"token punctuation\">(</span><span class=\"token string\">'default'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">month</span><span class=\"token operator\">:</span> <span class=\"token string\">'long'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />    monthNames<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span>month<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token punctuation\">}</span><br />  <span class=\"token keyword\">return</span> monthNames<span class=\"token punctuation\">;</span><br /><span class=\"token punctuation\">}</span><br /><span class=\"token function\">localeMonthNames</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token comment\">// [ \"janvier\", \"février\", \"mars\", \"avril\", \"mai\", \"juin\", \"juillet\", … ]</span></code></pre>\n<p>Là, c'est plutôt simple, on n'a qu'à itérer chaque mois dans le constructeur de <code>Date</code> pour avoir son nom textuel. On note quand même que les mois commencent à 0.</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">function</span> <span class=\"token function\">localeShortWeekDayNames</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />  <span class=\"token keyword\">const</span> weekDayNames <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span><br />  <span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">let</span> i <span class=\"token operator\">=</span> <span class=\"token number\">13</span><span class=\"token punctuation\">;</span> i <span class=\"token operator\">&lt;</span> <span class=\"token number\">20</span><span class=\"token punctuation\">;</span> i <span class=\"token operator\">+=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token keyword\">const</span> d <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token number\">2019</span><span class=\"token punctuation\">,</span> <span class=\"token number\">9</span><span class=\"token punctuation\">,</span> i<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />    <span class=\"token keyword\">const</span> weekDay <span class=\"token operator\">=</span> d<span class=\"token punctuation\">.</span><span class=\"token function\">toLocaleString</span><span class=\"token punctuation\">(</span><span class=\"token string\">'default'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">weekday</span><span class=\"token operator\">:</span> <span class=\"token string\">'short'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />    weekDayNames<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span>weekDay<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token punctuation\">}</span><br />  <span class=\"token keyword\">return</span> weekDayNames<span class=\"token punctuation\">;</span><br /><span class=\"token punctuation\">}</span><br /><span class=\"token function\">localeShortWeekDayNames</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token comment\">// [ \"dim.\", \"lun.\", \"mar.\", \"mer.\", \"jeu.\", \"ven.\", \"sam.\" ]</span></code></pre>\n<p>Ici, c'est plus compliqué, il faut partir d'une date où l'on sait qu'il s'agit d'un dimanche, puis itérer sur les 7 jours de la semaine. Et oui, le jour <code>0</code> est bien un Dimanche.  Ici j'ai mis les versions courtes des noms des jours, mais ça marche aussi évidemment avec la fonction complète.</p>\n<p>Ça peut éviter de traduire des informations inutiles.</p>\n<p>Un truc qui manque par contre, c'est déterminer en fonction de la <em>locale</em> quel jour de la semaine celle-ci commence. En effet, si la fameuse norme ISO 8601 définit lundi comme le premier jour de la semaine, certains pays comme les États-Unis d'Amérique, le Canada, le Japon et l'Australie entament leur semaine le Dimanche. Au Moyen-Orient, elle commence le Samedi. Du coup si vous n'avez pas de bibliothèque tierce, il faut fournir l'option aux traducteurs pour qu'ils mettent leur propre valeur.</p>\n<p><em><a href=\"https://pixabay.com/fr/photos/calendrier-calendrier-mural-jours-1990453/\">Image « Calendrier Mural Jours »</a> par <a href=\"https://pixabay.com/fr/users/webandi-1460261/\">Andreas Lischka</a> sur <a href=\"https://pixabay.com/fr/\">Pixabay</a></em></p>\n",
      "date_published": "2019-10-20T10:36:42Z"
    }
]
}