1. Meikel Brandmeyer
  2. j18n


j18n / src / main / clojure / j18n / core.clj

(ns ^{:doc
  "Provide some Clojure sugar for internationalisation using the usual
  Java infrastructure of ResourceBundles."
      :author "Meikel Brandmeyer <m@kotka.de>"}

(def ^{:private true} bundles (atom {}))

(defmacro defbundle
  "Creates a new bundle with given name. Attaches the Var to the metadata
  of the namespace. If several bundles are defined in one namespace, the
  last one wins as “the official bundle” for that namespace."
  ([bundle-name] `(defbundle ~bundle-name (name (ns-name *ns*))))
  ([bundle-name package]
      (declare ~bundle-name)
      (alter-meta! *ns* assoc ::bundle (symbol (name (ns-name *ns*)) ~(name bundle-name)))
      (swap! @#'bundles assoc (var ~bundle-name) ~package)
      (var ~bundle-name))))

(defn init-bundles!
  "Initialise all bundles defined with defbundle. This should only be called
  once during application startup and initialisation."
  (doseq [[v p] @bundles]
    (alter-var-root v (constantly (ResourceBundle/getBundle p)))))

(defn translate*
  "Translate the given message in the given bundle. This is basically a
  wrapper around ResourceBundle/getString."
  [^String message ^ResourceBundle bundle]
  (.getString bundle message))

(defmacro translate
  "Translate the given message. Message may be a qualified or non-qualified
  keyword or a String. The message is looked up in the given bundle. If no
  bundle is given, the official bundle of the namespace of the qualified
  keyword will be used. If the keyword is not qualified or the message key
  is given as String, the official bundle of the current namespace will be
   {:pre [(or (string? message) (keyword? message))]}
   (let [bundle (if (keyword? message)
                  (if-let [nspace (namespace message)]
                    (::bundle (meta (the-ns (symbol nspace))))
                    (::bundle (meta *ns*)))
                  (::bundle (meta *ns*)))]
     `(translate ~message ~bundle)))
  ([message bundle]
   {:pre [(or (string? message) (keyword? message))]}
   `(translate* ~(if (keyword? message) (name message) message) ~bundle)))