Localizing a Ghost Theme

Lately I've spent some time setting up a blog for a friend. Ghost is where it's at these days when it comes to blogging — unless you're a nerd like me who loves to mess around with static site generators every now and then. 😅

Ghost provides many beautiful themes out of the box but most of them don't seem to support localization, which would be a nice thing to have for my friends blog. So I did some digging and essentially it comes down to:

  1. Using the {{t}} helper for any strings that should be localized (docs)
  2. Providing a locales/de.json file with mappings to localized strings

The Dawn theme that we were using was pretty light on strings that needed localization so with a little bit of vim-sandwich magic and a custom mapping I was able to update it to use the {{t}} helper in maybe half an hour.

xmap <Leader>t sai{{t "<CR>"}}<CR>

With the visual mapping above all I needed to do is select the text that I want to localize and hit <space>t.

selecting some text and using vim-sandwich to wrap it in {{t}}

Now the last step was to create the initial locales/en.json file. Later on I will use the English one as a template to create a German localization.

Since typing out the more than a dozen strings manually would have been boring I instead wrote a babashka script to generate the English locales file for me.

#!/usr/bin/env bb
(require '[clojure.java.io :as io]
         '[cheshire.core :as json]
         '[babashka.fs :as fs])

(def entries
  (->> (fs/glob "." "**/*.hbs")
       (map (fn [p] (slurp (io/file (str p)))))
       (mapcat (fn [file-contents]
                 (map second (re-seq #"\{\{t \"(.*)\"\}\}" file-contents))))
       (map (fn [s] [s s]))
       (into {})))

(println (json/generate-string entries {:pretty true}))

This script essentially finds all usages of the {{t}} helper and spits out a JSON object where the keys are identical to the values (i.e. if the theme was English, that would be the locales/en.json file).

Babashka makes figuring this stuff out such a breeze because I can just incrementally build this out in a connected babashka nREPL session instead of changing the file and running the script as a whole on every change. REPLs for the win!

In the end I created this little PR to the theme.

@martinklepsch, May 2021