From 24677a32663be398339b5ba0ae40b4e1c515b72a Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 21 Jan 2020 21:28:29 +0100 Subject: [PATCH] :recycle: Rewrite translations messages collection using gramar based parser. --- docs/02-Frontend-Guide.md | 2 +- frontend/deps.edn | 8 +- frontend/{translations.clj => locales.clj} | 122 +++++++++------------ frontend/resources/locales.json | 31 +++++- 4 files changed, 83 insertions(+), 80 deletions(-) rename frontend/{translations.clj => locales.clj} (56%) diff --git a/docs/02-Frontend-Guide.md b/docs/02-Frontend-Guide.md index 294a059d1..2ea081d79 100644 --- a/docs/02-Frontend-Guide.md +++ b/docs/02-Frontend-Guide.md @@ -61,7 +61,7 @@ command for reformat the file, and track the usage locations (the "used-in" list) before commiting the file into the repository: ```bash -clojure -Adev translations.clj collectmessages src/uxbox/main/ resources/locales.json +clojure -Adev locales.clj collect src/uxbox/main/ resources/locales.json ``` NOTE: Later, we will need to think and implement the way to export and diff --git a/frontend/deps.edn b/frontend/deps.edn index 05c23bd94..9ae2502ad 100644 --- a/frontend/deps.edn +++ b/frontend/deps.edn @@ -27,7 +27,13 @@ com.bhauman/figwheel-main {:mvn/version "0.2.3"} org.clojure/tools.namespace {:mvn/version "0.3.1"} metosin/jsonista {:mvn/version "0.2.5"} - funcool/datoteka {:mvn/version "1.2.0"}} + funcool/datoteka {:mvn/version "1.2.0"} + + ;; i18n parsing + carocad/parcera {:mvn/version "0.11.0"} + org.antlr/antlr4-runtime {:mvn/version "4.7"}} + + :extra-paths ["test"]} :repl diff --git a/frontend/translations.clj b/frontend/locales.clj similarity index 56% rename from frontend/translations.clj rename to frontend/locales.clj index 48d122137..3ebd7f23f 100644 --- a/frontend/translations.clj +++ b/frontend/locales.clj @@ -1,16 +1,12 @@ (require '[clojure.pprint :as pp :refer [pprint]]) -(require '[clojure.java.shell :as shell]) -(require '[environ.core :refer [env]]) -(require '[clojure.walk :as walk] - '[clojure.edn :as edn] - '[clojure.set :as set]) +(require '[clojure.edn :as edn] + '[clojure.set :as set] + '[clojure.java.io :as io]) (require '[datoteka.core :as fs] - '[jsonista.core :as json]) -(require '[clojure.java.io :as io] - '[clojure.tools.reader :as r] - '[clojure.tools.reader.reader-types :as rt]) + '[jsonista.core :as json] + '[parcera.core :as pa]) (import 'java.nio.file.Paths 'java.nio.file.Path @@ -18,74 +14,51 @@ 'java.nio.file.SimpleFileVisitor 'java.nio.file.FileVisitResult) -(extend-protocol io/Coercions - Path - (as-file [it] (.toFile it)) - (as-url [it] (io/as-url (.toFile it)))) - (defmulti task first) (defn- find-translations-in-form - [env form] - (->> form - (walk/postwalk - (fn [fm] - (cond - (and (list? fm) - (= (first fm) 'tr) - (string? (second fm))) - (let [m (meta (first fm))] - (swap! env conj {:code (second fm) - :file (:file m) - :line (:line m)})) + [form] + (let [messages (atom [])] + (run! (fn [node] + (let [found (->> node + (filter #(and (seq? %) (= :string (first %)))) + (map (fn [item] + (let [mdata (meta item)] + {:code (edn/read-string (second item)) + :line (get-in mdata [::pa/start :row])}))))] + (swap! messages into found))) + (->> (tree-seq seq? seq form) + (filter #(and (seq? %) + (seq? (second %)) + (= :list (first %)) + (= :symbol (first (second %))) + (or (= "t" (second (second %))) + (= "tr" (second (second %)))))))) + @messages)) - (and (list? fm) - (= (first fm) 't) - (symbol? (second fm))) - (let [m (meta (first fm)) - code (first (drop 2 fm))] - (swap! env conj {:code code - :file (:file m) - :line (:line m)}))) - fm)))) - -(defn- find-translations-in-file - [env file] - (let [rdr (-> (io/as-file file) - (io/reader) - (rt/source-logging-push-back-reader 1 file))] - (try - (binding [r/*default-data-reader-fn* (constantly nil) - r/*alias-map* {'dw (create-ns 'user) - 'fm (create-ns 'user) - 'us (create-ns 'user) - 'dp (create-ns 'user) - 'cp (create-ns 'user)}] - (loop [] - (let [form (r/read {:eof ::end} rdr)] - (when (not= ::end form) - (find-translations-in-form env form) - (recur))))) - (catch Exception e - ;; (.printStackTrace e) - (println (str "ERROR: on procesing " file "; ignoring...")))))) - -(defn- find-translations-in-directory - [env file] - (->> (proxy [SimpleFileVisitor] [] - (visitFile [path attrs] - (when (= (fs/ext path) "cljs") - (find-translations-in-file env path)) - FileVisitResult/CONTINUE) - (postVisitDirectory [dir exc] - FileVisitResult/CONTINUE)) - (Files/walkFileTree (fs/path file)))) +(defn- find-translations + [path] + (let [forms (pa/ast (slurp path)) + spath (str path)] + (->> forms + (filter #(and (seq? %) (= :list (first %)))) + (reduce (fn [messages form] + (->> (find-translations-in-form form) + (map #(assoc % :file spath)) + (into messages))) [])))) (defn- collect-translations [path] - (let [env (atom [])] - (find-translations-in-directory env path) - @env)) + (let [messages (atom [])] + (->> (proxy [SimpleFileVisitor] [] + (visitFile [path attrs] + (when (= (fs/ext path) "cljs") + (swap! messages into (find-translations path))) + FileVisitResult/CONTINUE) + (postVisitDirectory [dir exc] + FileVisitResult/CONTINUE)) + (Files/walkFileTree (fs/path path))) + @messages)) (defn- read-json-file [path] @@ -167,16 +140,19 @@ (defn- update-translations [{:keys [find-directory output-path] :as props}] - (let [data (read-json-file output-path) + (let [ + data (read-json-file output-path) translations (collect-translations find-directory) - data (synchronize-translations data translations)] + data (synchronize-translations data translations) + ] (write-result! data output-path))) -(defmethod task "collectmessages" +(defmethod task "collect" [[_ in-path out-path]] (update-translations {:find-directory in-path :output-path out-path})) + (defmethod task "merge-with-legacy" [[_ path lang legacy-path]] (let [ldata (read-edn-file legacy-path) diff --git a/frontend/resources/locales.json b/frontend/resources/locales.json index ee3ac7132..f59f34b00 100644 --- a/frontend/resources/locales.json +++ b/frontend/resources/locales.json @@ -196,6 +196,13 @@ "fr" : null } }, + "ds.num-elements" : { + "translations" : { + "en" : null, + "fr" : null + }, + "used-in" : [ "src/uxbox/main/ui/dashboard/colors.cljs:111" ] + }, "ds.position" : { "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/icon_measures.cljs:52" ], "translations" : { @@ -231,6 +238,13 @@ "fr" : null } }, + "ds.settings.icons" : { + "translations" : { + "en" : null, + "fr" : null + }, + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/icons.cljs:72" ] + }, "ds.size" : { "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/icon_measures.cljs:33" ], "translations" : { @@ -567,6 +581,13 @@ "fr" : "Votre nom d'utilisateur" } }, + "settings.exit" : { + "translations" : { + "en" : null, + "fr" : null + }, + "used-in" : [ "src/uxbox/main/ui/settings/header.cljs:46" ] + }, "settings.notifications" : { "used-in" : [ "src/uxbox/main/ui/settings/header.cljs:43" ], "translations" : { @@ -862,7 +883,7 @@ } }, "workspace.options.measures" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/measures.cljs:115", "src/uxbox/main/ui/workspace/sidebar/options/image.cljs:62", "src/uxbox/main/ui/workspace/sidebar/options/circle.cljs:65", "src/uxbox/main/ui/workspace/sidebar/options/rect.cljs:64", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:70" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/measures.cljs:115", "src/uxbox/main/ui/workspace/sidebar/options/image.cljs:62", "src/uxbox/main/ui/workspace/sidebar/options/circle.cljs:65", "src/uxbox/main/ui/workspace/sidebar/options/rect.cljs:67", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:70", "src/uxbox/main/ui/workspace/sidebar/options/canvas.cljs:51" ], "translations" : { "en" : "Size, position & rotation", "fr" : "Taille, position et rotation" @@ -876,21 +897,21 @@ } }, "workspace.options.position" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/measures.cljs:74", "src/uxbox/main/ui/workspace/sidebar/options/image.cljs:91", "src/uxbox/main/ui/workspace/sidebar/options/circle.cljs:93", "src/uxbox/main/ui/workspace/sidebar/options/rect.cljs:93", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:99" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/measures.cljs:74", "src/uxbox/main/ui/workspace/sidebar/options/image.cljs:91", "src/uxbox/main/ui/workspace/sidebar/options/circle.cljs:93", "src/uxbox/main/ui/workspace/sidebar/options/rect.cljs:96", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:99", "src/uxbox/main/ui/workspace/sidebar/options/canvas.cljs:80" ], "translations" : { "en" : "Position", "fr" : "Position" } }, "workspace.options.rotation-radius" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/measures.cljs:92", "src/uxbox/main/ui/workspace/sidebar/options/image.cljs:108", "src/uxbox/main/ui/workspace/sidebar/options/circle.cljs:108", "src/uxbox/main/ui/workspace/sidebar/options/rect.cljs:110", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:116" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/measures.cljs:92", "src/uxbox/main/ui/workspace/sidebar/options/image.cljs:108", "src/uxbox/main/ui/workspace/sidebar/options/circle.cljs:108", "src/uxbox/main/ui/workspace/sidebar/options/rect.cljs:113", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:116" ], "translations" : { "en" : "Rotation & Radius", "fr" : "TODO" } }, "workspace.options.size" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/measures.cljs:38", "src/uxbox/main/ui/workspace/sidebar/options/image.cljs:64", "src/uxbox/main/ui/workspace/sidebar/options/circle.cljs:69", "src/uxbox/main/ui/workspace/sidebar/options/page.cljs:114", "src/uxbox/main/ui/workspace/sidebar/options/rect.cljs:66", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:72" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/measures.cljs:38", "src/uxbox/main/ui/workspace/sidebar/options/image.cljs:64", "src/uxbox/main/ui/workspace/sidebar/options/circle.cljs:69", "src/uxbox/main/ui/workspace/sidebar/options/page.cljs:114", "src/uxbox/main/ui/workspace/sidebar/options/rect.cljs:69", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:72", "src/uxbox/main/ui/workspace/sidebar/options/canvas.cljs:53" ], "translations" : { "en" : "Size", "fr" : "Taille" @@ -953,7 +974,7 @@ } }, "workspace.sidebar.layers" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/layers.cljs:261" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/layers.cljs:289" ], "translations" : { "en" : "Layers", "fr" : "Couches"