Dopo la prima parte dedicata all’installazione e alla configurazione iniziale di Jekyll, con questa seconda parte di note commentate si entra nel vivo dello sviluppo di un sito in Jekyll a partire da un tema già pronto. Sviluppare da zero un tema per Jekyll, invece, va molto oltre le mie competenze, ma del resto chi è in grado di farlo non ha bisogno di leggere queste notarelle.
Cosa vogliamo?
Per prima cosa dobbiamo avere una idea chiara di come dovrebbe essere il sito dal punto di vista grafico e quali funzioni deve supportare. Vogliamo un blog personale con un semplice elenco di post? Vogliamo un sito più elaborato stile rivista? Vogliamo un sito vetrina per presentare la nostra attività o un progetto specifico? Vogliamo un sito fotografico o di documentazione?
Una volta chiarite le “specifiche” del sito, facciamo un giro su questo sito di temi per Jekyll, oppure su questo, o su questo, o infine su questo (non posso distinguerli per nome, perché si chiamano tutti Jekyll Themes). I più pazienti potranno scorrerli uno ad uno, gli altri preferiranno selezionate la tipologia di sito che gli interessa e guardare solo quei temi. In ogni caso, è bene prendere nota di quelli che ci piacciono di più e provate i siti demo, quando ci sono. È bene essere aperti, magari troviamo un tema interessante che esce fuori dalle specifiche, meglio segnarsi anche quello.1
Come è fatto un tema
A questo punto non resta che provare. Per evitare di essere generico, descriverò l’installazione del tema Mundana che, guarda caso, è quello che ho usato per melabit.com.
Ma, proprio come Mundana, la maggior parte dei temi non gem-based di Jekyll si installa clonando il suo repository su GitHub oppure scaricando un file compresso (nel qual caso, tutto la parte qui sotto relativa a git
può essere saltata a piè pari). In entrambi i casi, ciò che installiamo è sia il tema che il sito vero e proprio, perché in Jekyll non c’è una separazione netta fra grafica e contenuti.
La prima cosa da fare è installare git
sul computer. Su macOS è installato di default, ma è sempre una versione un po’ datata, e comunque come dicevo la volta scorsa, è sempre meglio separare i tool di sistema da quelli che usate per lo sviluppo. Del resto, con Homebrew ci vogliono pochi secondi, basta eseguire
$ brew install git
e avremo l’ultima (o quasi) versione di git
installata sul Mac.
Con Linux non è molto diverso, ma questa volta dovremo usare l’installatore dei pacchetti per la distribuzione in uso, per cui eseguiamo uno dei comandi qui sotto
$ sudo apt install git
$ sudo dnf install git
$ sudo pacman -S git
a seconda che usiamo Debian/Ubuntu, Fedora/CentOS, Arch, o uno degli infiniti derivati.
Come dicevo, l’installazione di Mundana avviene clonando il suo repository,
$ git clone https://github.com/wowthemesnet/mundana-theme-jekyll.git
Cloning into 'mundana-theme-jekyll'...
remote: Enumerating objects: 324, done.
remote: Total 324 (delta 0), reused 0 (delta 0), pack-reused 324 (from 1)
Receiving objects: 100% (324/324), 4.12 MiB | 24.52 MiB/s, done.
Resolving deltas: 100% (116/116), done.
oppure scaricando ed espandendo il file zip
del progetto.
Gli sviluppatori suggeriscono di fare il prima un fork sul nostro account GitHub e poi di clonare da lì. Secondo me ha senso se vogliamo contribuire al codice, altrimenti mi sembra un passaggio inutile. E comunque, chi sa cos’è un fork non ha bisogno di altre istruzioni.
Una volta finita l’installazione, possiamo spostarci nella directory di Mundana e curiosare un po’ in giro (per maggior chiarezza, tutti i nomi delle directory finiscono con uno /
).
$ cd mundana-theme-jekyll
% ls -nhp
total 72
-rw-r--r-- 1 501 20 398B Feb 12 19:58 404.html
-rw-r--r-- 1 501 20 510B Feb 12 19:58 Gemfile
-rw-r--r-- 1 501 20 1.7K Feb 12 19:58 Gemfile.lock
-rw-r--r-- 1 501 20 2.0K Feb 12 19:58 README.md
-rw-r--r-- 1 501 20 1.7K Feb 12 19:58 _config.yml
drwxr-xr-x 11 501 20 352B Feb 12 19:58 _includes/
drwxr-xr-x 6 501 20 192B Feb 12 19:58 _layouts/
drwxr-xr-x 11 501 20 352B Feb 12 19:58 _pages/
drwxr-xr-x 20 501 20 640B Feb 12 19:58 _posts/
drwxr-xr-x 5 501 20 160B Feb 12 19:58 assets/
-rw-r--r-- 1 501 20 149B Feb 12 19:58 docker-compose.yml
-rw-r--r-- 1 501 20 9.2K Feb 12 19:58 index.html
La directory di Mundana contiene due file di servizio di RubyGems
, Gemfile
e Gemfile.lock
, oltre al file docker-compose.yml
che serve solo se usiamo Jekyll all’interno di un container Docker (cosa che qui non interessa). Tutto il resto fa capo a Jekyll.
Le pagine statiche del sito vanno messe nella cartella _pages
, mentre tutti i contenuti dinamici, cioè quelli che vengono modificati di frequente come i post di un blog, vanno in _posts
. Il contenuto delle pagine statiche e dei post può essere scritto indifferentemente sia in html
che in Markdown
.
La cartella _layouts
contiene i file che generano le parti principali del sito, come le pagine statiche e quelle dei post o la barra laterale, mentre la cartella _includes
contiene delle porzioni di codice che possono essere incluse nelle diverse pagine, più o meno come se fossero delle funzioni di libreria.
Queste quattro cartelle, che iniziano tutte con un underscore _
, vengono elaborate dal motore di Jekyll, che le usa per costruire le pagine html vere e proprie del sito statico.
L’ultima cartella assets
, invece, è dedicata ai contenuti del sito che non vengono elaborati dal motore di Jekyll, come i file css
che specificano tutti i dettagli dell’aspetto grafico del sito, i file JavaScript
necessari per svolgere certe funzioni che richiedono interattività,2 e tutte le immagini del sito. Quando Jekyll genera un sito questa cartella viene copiata così com’è e il sistema crea automaticamente i link ai vari file.
Infine, il file _config.yml
contiene tutti i parametri di configurazione del sito, fra cui il nome e la descrizione del sito, il link al logo o alla favicon, i plugin necessari per generare il sito, i parametri di paginazione, o l’elenco dei file e delle cartelle di servizio che non devono essere elaborati da Jekyll. Il file _config.yml
può diventare piuttosto lungo e complesso, qui sotto per semplicità faccio vedere solo una piccola parte del file _config.yml
di default di Mundana.
# Site
name: 'Mundana'
description: 'Mundana is a free Jekyll theme for awesome people like you, Medium like.'
logo: 'assets/images/logo.png'
favicon: 'assets/images/favicon.ico'
baseurl: '/mundana-theme-jekyll'
[...]
# Plugins
plugins:
- jekyll-feed
- jekyll-sitemap
- jekyll-paginate
- jekyll-seo-tag
[...]
# Paginate
paginate: 10
# Exclude metadata and development time dependencies (like Grunt plugins)
exclude: [README.markdown, package.json, grunt.js, Gruntfile.js, Gruntfile.coffee, node_modules]
Già che ci siamo, semplifichiamoci il lavoro futuro con una piccola modifica al file _config.yml
, sostituendo la riga baseurl: '/mundana-theme-jekyll'
con baseurl: ''
.
Dimenticavo, anche i plugin (e le relative dipendenze) sono anch’essi delle gemme di Ruby e non sono installati di default, per cui ci tocca farlo con
$ rm Gemfile.lock
che serve per evitare di avere conflitti quando Ruby ci propone di installare plugin più recenti di quelli riportati nel file Gemfile.lock
. Subito dopo,
$ bundle install
[...]
Fetching gem metadata from https://rubygems.org/............
Resolving dependencies...
Fetching jekyll-paginate 1.1.0
Installing jekyll-paginate 1.1.0
Fetching jekyll-sitemap 1.4.0
Installing jekyll-sitemap 1.4.0
Bundle complete! 4 Gemfile dependencies, 39 gems now installed.
Bundled gems are installed into `[...]/.gems`
che installa i plugin veri e propri (e rigenera automaticamente il file Gemfile.lock
con le versioni appena installate dei vari plugin).
Mettiamo di nuovo Jekyll alla prova
A questo punto non ci rimane che mettere di nuovo Jekyll alla prova, ma questa volta con il tema che abbiamo installato.
$ bundle exec jekyll serve --host=0.0.0.0
Il sito verrà rigenerato rapidamente e potrà essere visto all’URL http://localhost:4000
della nostra macchina reale, oppure all’URL della macchina virtuale o del server cloud che stiamo usando, sempre utilizzando la porta 4000
(per i server cloud l’URL ha una etichetta del tipo reverse DNS name
o simili).
Rispetto ai semplici temi gem-based visti nell’articolo precedente Mundana è chiaramente un’altra cosa.
Qui la struttura del sito è molto più efficace: in cima vengono mostrati gli ultimi quattro post con le relative immagini, al centro spicca in grande evidenza un post con uno sfondo contrastante (ad esempio l’ultimo pubblicato) e, più in basso, tutti gli altri post sono disposti in ordine cronologico inverso. A fianco, una barra laterale ospita i post che desideriamo mettere in risalto.
Ora basterebbe sostituire i post preconfezionati di Mundana con i propri, aggiungere le immagini, fare due o tre modifiche al file _config.yml
e in pochi minuti si avrebbe il sito pronto da mettere online, con tutti i post già organizzati in tante pagine belle ordinate (come si può vedere qui).
Il tema di default non basta
Un tema ben fatto è molto comodo e, come abbiamo appena visto, permette di andare online rapidamente e con pochissimo sforzo. Ma non è detto che così com’è riesca a soddisfare le esigenze di tutti.
Io ad esempio volevo realizzare un sito multilingua in italiano e in inglese, una funzionalità che Mundana non supporta di default.
Inoltre volevo che la Home
del sito mostrasse un riassunto degli ultimi post con le miniature delle immagini di testa, ma senza che queste apparissero nelle pagine dei singoli post. Mundana gestisce correttamente la prima richiesta, ma non la seconda.
Un altro problema riguarda la paginazione: quella di default è bella, ma mostra un’unica striscia orizzontale di link a tutte le pagine generate. Quando queste sono troppe, la striscia si allarga a dismisura, finendo per sovrapporsi ad altri elementi grafici della pagina o per uscire dai margini del browser.
Infine, Mundana supporta di default il sistema di commenti Disqus, ma io preferivo una soluzione gestita in casa, evitando di appoggiarmi a servizi di terze parti che possono cambiare le regole di utilizzo o, peggio, cessare di esistere da un giorno all’altro.
Al lavoro!
Premetto che tutto il codice del tema modificato è disponibile su GitHub, all’URL https://github.com/sabinomaggi/mundana-theme-jekyll-multilang.
Paginazione
Cominciamo dalla paginazione. A partire dalla versione 3 di Jekyll (ora siamo alla 4.4.1), la paginazione è gestita dal plugin jekyll-paginate-v2
. In Mundana, il codice di paginazione è integrato nel file index.html
ed è molto semplice, tanto da dare problemi quando il numero di pagine del sito cresce.
Io ho spostato la paginazione in _includes/custom/paginator.html
,3 facendo in modo che i link puntassero solo ad una parte delle pagine disponibili: quelle immediatamente intorno alla pagina corrente, la prima e l’ultima pagine e una pagina intermedia calcolata in base alla distanza della pagina corrente dalla prima (o dall’ultima). In questo modo la paginazione funziona correttamente anche in finestre molto strette o sui dispositivi mobili.
Sul codice c’è poco da dire: partendo dalla pagina corrente vengono determinati tutti gli altri elementi della paginazione, generando dinamicamente il codice HTML di ciascun link. Tutta la logica del codice è in Liquid
, che è il linguaggio di templating usato da Jekyll. La sintassi di Liquid è un po’ astrusa e obbliga a fare qualche giochetto con le variabili, ma l’importante è che alla fine tutto funzioni.
Secondo me, la parte più interessante del codice è la prima riga, che serve per cambiare dinamicamente le stringhe di testo in base alla lingua in uso. Ma questo ci porta alla prossima sezione.
Supporto multilingue
Jekyll può gestire i siti multilingua tramite il plugin jekyll-polyglot
, che però non comunica bene con il plugin di paginazione jekyll-paginate-v2
,4 per cui mi serviva un’altra soluzione.
Polyglot è facilissimo da usare, basta aggiungere il plugin sotto la voce relativa nel file di configurazione _config.yml
e definire due nuove variabili con tutte le lingue che ci interessano.
[...]
# Plugins
plugins:
[...]
- jekyll-polyglot
[...]
# Polyglot
languages: [en, it, de, fr]
default_lang: en
A questo punto basta definire la lingua di ciascun post, aggiungendo nel suo front matter la variabile lang:
(ad esempio, lang: en
o lang: it
) e il gioco è fatto.
Il front matter di Jekyll è un blocco di metadati in formato YAML inserito all’inizio di un file Markdown (.md
) o HTML (.html
). È racchiuso tra tre trattini (---
) e serve a fornire informazioni su quella pagina o post, come il titolo, la lingua, il layout, e per personalizzare il comportamento delle pagine. Ad esempio:
---
title: "Benvenuto"
layout: default
permalink: /it/
lang: it
---
Quando Jekyll elabora il sito, utilizza il front matter per:
- definire il template utilizzare per la visualizzazione del sito (
layout: default
). - personalizzare l’URL associato alla pagina (
permalink: /it/
). - impostare delle variabili specifiche per quel file, da usare nei layout e nei temi (
lang: it
). Se una data pagina o post contiene nel front matter la variabilelang:it
, Polyglot potrà utilizzare questa variabile per applicare contenuti o stili specifici per la versione italiana del sito.
L’idea quindi era quella di emulare a mano il comportamento di polyglot
. La prima cosa che ho fatto è stata definire nel file _config.yml
due variabili analoghe a quelle usate da Polyglot,
#--- Custom localization variables ---
# Polyglot does not work well with Paginate-v2
# define these two variables instead
locales: [en, it]
default_locale: en
e aggiungere nel front matter di ciascuna pagina o post una variabile che in analogia con le variabili definite in _config.yml
_ può essere locale: en
oppure locale: it
.
Per semplificare la gestione delle due lingue ho creato, all’interno della cartella principale _posts
, due sottocartelle en
e it
dove inserire i post nelle rispettive lingue (in questo modo, aggiungere con sed
la variabile locale
giusta è una questione di pochi secondi).
Fatto questo, ho sfruttato una caratteristica specifica di Jekyll che, quando trova un file che nel nome contiene un indicatore di lingua, lo considera un’altra versione del file originale (senza indicatore), con sue variabili specifiche definite nel front matter.
In altri termini, se ho un file index.html
che contiene tutto il codice necessario per costruire la pagina Home
del sito e poi creo un secondo file index_it.html
vuoto, ad eccezione del front matter in cui è definita la variabile locale: it
, questo file index_it.html
erediterà tutto il contenuto di index.html
ma utilizzerà il valore della variabile locale
per adattare la pagina alla lingua italiana. Questo meccanismo è spiegato molto bene in qualche pagina che ho consultato, ma purtroppo non trovo più i link relativi.
Ultimo mattoncino: quando si usa la paginazione, la variabile locale: it
deve essere definita all’interno della variabile pagination:
del front matter,
pagination:
enabled: true
locale: it
per cui tutto il codice usato per determinare in modo dinamico la lingua in cui è scritta una data pagina deve controllare sempre sia il contenuto della variabile page.locale
che di page.pagination.locale
,
Ovviamente bisogna adattare alla lingua anche tutte le stringhe di testo presenti nel sito. Per questo, c’è il file _data/translations.yml
che contiene le traduzioni in inglese e in italiano di tutte le stringhe utilizzate.
Inutile dire che mettere a punto correttamente il meccanismo di localizzazione è stata la cosa che ha richiesto più tempo nel corso dello sviluppo di melabit.com
. Il modo in cui è stato fatto, però, consente di aggiungere una nuova lingua in pochi minuti: basta modificare la variabile locales
in _config.yml
, aggiungere un’altra cartella in _posts
e un’altra bandierina in assets/images
. Quasi quasi viene voglia di provare… 😂
Miniature e commenti
Superato lo scoglio della localizzazione, togliere la miniatura dell’immagine di testa dalla pagina dei post è stato uno scherzo. È bastato trovare le righe di codice coinvolte e commentarle e il gioco è fatto.
I commenti invece sono stati tutta un’altra storia, perfino più complicata di quella della localizzazione. E proprio ai commenti sarà destinato il prossimo articolo.
-
Ad esempio, proprio mentre scrivevo questo articolo, ho messo gli occhi su questo tema che non si adatta alla mia idea originale di sito, ma che forse avrebbe potuto fare lo stesso al caso mio (ma ormai non cambio). ↩
-
Jekyll è un generatore di siti statico, ma ormai anche un sito statico richiede un certo livello di dinamicità per gestire al meglio cose come le ricerche, come i commenti, e così via. ↩
-
Tutto il nuovo codice da includere l’ho messo nella cartella
custom
per distinguerlo, anche fisicamente, da quello originale del tema. ↩ -
Dato che diversi post di 4-5 anni fa riportano di aver usato senza problemi sia
jekyll-polyglot
chejekyll-paginate-v2
, questo potrebbe essere un problema specifico di Mundana. Oppure è una incompatibilità venuta fuori nelle ultime versioni di Jekyll o dei due plugin. ↩