Lightweight i18n using re-frame modified
A lightweight i18n solution for use with re-frame. It's inspired by Tower, a Clojure/Script i18n & L10n library.
Update: later found the Tongue library (by Nikita Prokopov).
i18n code
1(ns examplens.i18n
2 (:require [examplens.translations :refer [translations]]))
3
4(def i18n-not-found-key "*I18N-KEY*")
5(def i18n-not-found-fallback-lc "*I18N-FB-LC*")
6
7(defn- _t
8 "Returns translation for key based on supplied locale."
9 [lc key]
10 {:pre [(not (nil? key))]
11 :post [(not (nil? %))]}
12
13 (let [fb-lc (:fallback-lc translations)
14 td (:dictionary translations)
15 tdk (get td key)]
16 (if (nil? tdk)
17 i18n-not-found-key
18 (if (and (not (nil? lc)) (contains? tdk lc))
19 (get tdk lc)
20 (if (contains? tdk fb-lc)
21 (get tdk fb-lc)
22 i18n-not-found-fallback-lc)))))
23
24(def t
25 "Returns memoized translation for key (based on supplied locale)."
26 (memoize _t))
Example translations code
1(ns examplens.translations)
2
3(def translations
4 "Table with translations per locale."
5 {:fallback-lc :en-US
6 :dictionary
7 {:home-title {:en-US "Welcome"
8 :nl-NL "Welkom"}
9 :home-subtitle {:en-US "Time to start building the site."
10 :nl-NL "Tijd om de site te maken."}
11 :home-content {:en-US "The content for the home page."
12 :nl-NL "De inhoud voor de home pagina."}}})
The re-frame related code
1;; In the re-frame database a :lc field is
2;; defined (with an initial value).
3... {:lc :nl-NL} ...
4
5;; Handler.
6(f/register-handler
7 :set-lc
8 (fn [db [lc]]
9 (assoc db :lc lc)))
10
11;; A subscription handler is set up.
12(f/register-sub
13 :lc
14 (fn [db _]
15 (reaction (:lc @db))))
16
17;; Consumption in a re-frame component (when the locale
18;; changes the view is automatically updated).
19(defn home []
20 (let [lc (f/subscribe [:lc])]
21 (fn []
22 [:div
23 [:div
24 [:h1 (i18n/t @lc :home-title)]]
25 [:div
26 [:h3 (i18n/t @lc :home-subtitle)]]
27 [:div
28 [:p (i18n/t @lc :home-content)]]])))