Speaking in tongues

I am learning wintersmith, anf now it is time to write first plugin. I write in multiple kanguages and can use some organisation so my readers can find suitable text easily. Of course it is based on basic paginatorplugin, but we have to start somewhere. Let’s do it.

What it shall do

  • group articles by language
  • take language from meta tag lang
  • sort by date
  • generate overview pages with pattern /lang/<tag>/index.html
  • use configurable template

This pllugin will generate new pages, so it will be generator plugin.

… let’s make it

First we mark our documents with proper meta tags:

title: Spare, spare, Häusle baue!
author: pribluda
date: 2018-02-05
template: article.jade
tags: haus,vilnius,bau,project
lang: de

Files without language set will be ignored

First we start with reasonable defaults (they can be overrriden later)

module.exports = (env, callback) ->
    Genereate per language  overview pages collecting all the documents with proper tag
  defaults =
    template: 'articles.jade' # template that renders pages
    filename: 'lang/%s/index.html' # directory containing generated language pages
    base: 'articles' # where do we start

Find all pages with language setting (and ignore all others):

  getArticles = (contents) ->
# helper that returns a list of articles found in *contents*
# note that each article is assumed to have its own directory in the articles directory
    articles = contents[options.base]._.directories.map (item) -> item.index
    console.log articles.length

    #filter out all the articles woithout template and lang is defined
    articles = articles.filter (item) -> item.template isnt 'none' and item.metadata.lang?
    console.log articles.length
    # filtered and sorted articles
    articles.sort (a, b) -> b.date - a.date

    return articles

OUr plugin will generate overview pages listing all the articles on this page. We subclass basic page class and add properties to store language and page list:

  class PolyglotPage extends env.plugins.Page
    # polyglot page bundles all the articles sharing certain language

    constructor: (@lang, @articles) ->

    getFilename: ->
      options.filename.replace '%s', @lang

    getView: -> (env, locals, contents, templates, callback) ->

      # simple view to pass articles defined template
      # note that this function returns a funciton

      # get the template for page
      template = templates[options.template]
      if not template?
        return callback new Error "unknown polyglot template '#{ options.template }'"

      # setup the template context - add language and articles
      ctx = {@articles, @lang}

      # extend the template context with the enviroment locals
      env.utils.extend ctx, locals

      # finally render the template
      template.render ctx, callback

Notable methods

  • getFilename - where generated content shall go ( we use template substitution here with language property)
  • getView - retrieves template, populates context ( Language and article will be available in template) and performs actual rendering

And now generate those pages. Register generator function (will be called by framework):

  env.registerGenerator 'polyglot', (contents, callback) ->

Retrieve artricles and languages:

    # find all articles suitable aricles
    articles = getArticles contents
    languages = articles.map (item) -> item.metadata.lang

    ll = {}
    for lang in languages
      ll[lang] = lang

    languages = Object.keys(ll)

And create page objects:

   # create page objects for each of the languages and add articles there
    pages = []
    for lang in languages
      la = articles.filter (article) -> article.metadata.lang == lang
      pages.push new PolyglotPage lang, la

    rv = {lang: {}}

    for page in pages
      rv.lang[page.lang + ".page"] = page # file extension is arbitrary

    # callback with the generated contents
    callback null, rv

As you may guess, generated pages will be available in contents under contents[lang]

And here comes template, list of articles is available in context:

    each article in articles
                    span= moment.utc(article.date).format('DD. MMMM YYYY')
                    a(href=article.url)= article.title
                if article.intro.length > 0
                    != typogr(article.intro).typogrify()
                if article.hasMore
                        a(href=article.url) more

… and now check those little flag icons on top navbar

  • See full source on Github
  • Question and discussion on G+