diff --git a/.gitignore b/.gitignore index 017880e82c..2e61a4e02c 100644 --- a/.gitignore +++ b/.gitignore @@ -162,5 +162,6 @@ conan.cmake /.ran-setup /.nix-gcroots/ -#modules +# modules status-modules/translations +status-modules/cljs diff --git a/Makefile b/Makefile index c5fc814d52..4833b44d9f 100644 --- a/Makefile +++ b/Makefile @@ -63,6 +63,7 @@ endif release: release-android release-ios ##@build build release for Android and iOS release-android: export TARGET_OS ?= android +release-android: export BUILD_ENV ?= prod release-android: ##@build build release for Android @$(MAKE) prod-build-android && \ cp -R translations status-modules/translations && \ @@ -70,6 +71,7 @@ release-android: ##@build build release for Android react-native run-android --variant=release release-ios: export TARGET_OS ?= ios +release-ios: export BUILD_ENV ?= prod release-ios: ##@build build release for iOS release # Open XCode inside the Nix context @$(MAKE) prod-build-ios && \ @@ -100,16 +102,21 @@ prod-build: prod-build-android: export TARGET_OS ?= android prod-build-android: - lein prod-build-android + BUILD_ENV=prod lein prod-build-android && \ + node prepare-modules.js prod-build-ios: export TARGET_OS ?= ios +prod-build-ios: export BUILD_ENV = prod prod-build-ios: - lein prod-build-ios + BUILD_ENV=prod lein prod-build-ios && \ + node prepare-modules.js prod-build-desktop: export TARGET_OS ?= $(HOST_OS) +prod-build-desktop: export BUILD_ENV = prod prod-build-desktop: git clean -qdxf -f ./index.desktop.js desktop/ && \ - lein prod-build-desktop + BUILD_ENV=prod lein prod-build-desktop && \ + node prepare-modules.js #-------------- # REPL diff --git a/externs.js b/externs.js index 57235e7386..2f914c1940 100644 --- a/externs.js +++ b/externs.js @@ -559,5 +559,5 @@ var TopLevel = { "decimalPlaces": function () {}, "_android": function () {}, "isSupported" : function () {}, - "authenticate" : function () {}, + "authenticate" : function () {} } diff --git a/prepare-modules.js b/prepare-modules.js new file mode 100644 index 0000000000..053a9eff04 --- /dev/null +++ b/prepare-modules.js @@ -0,0 +1,20 @@ +var fs = require("fs"); + +var modules = [ + "i18n" +]; + +modules.forEach( + function (moduleName) { + fs.readFile(`status-modules/cljs/${moduleName}-raw.js`, "utf8", function (err, data) { + if (err) throw err; + fs.writeFile(`status-modules/cljs/${moduleName}.js`, + ("module.exports=`" + data.replace(/[\\$'"]/g, "\\$&") + "`;"), + function (err) { + if (err) { + return console.log(err); + } + }); + }); + }); + diff --git a/project.clj b/project.clj index d4db066aef..2eb8da516b 100644 --- a/project.clj +++ b/project.clj @@ -29,7 +29,7 @@ :githooks {:auto-install true :pre-commit ["lein cljfmt check src/status_im/core.cljs $(git diff --diff-filter=d --cached --name-only src test/cljs)"]} :cljfmt {:indents {letsubs [[:inner 0]]}} - :clean-targets ["target/" "index.ios.js" "index.android.js"] + :clean-targets ["target/" "index.ios.js" "index.android.js" "status-modules/cljs"] :aliases {"prod-build" ^{:doc "Recompile code with prod profile."} ["do" "clean" ["with-profile" "prod" "cljsbuild" "once" "ios"] @@ -91,12 +91,12 @@ :target :nodejs}} {:id "protocol" :source-paths ["components/src" "src" "test/cljs" "dev"] - :compiler {:main status-im.test.protocol.runner - :output-to "target/test/test.js" - :output-dir "target/test" - :optimizations :none - :preamble ["js/hook-require.js"] - :target :nodejs}} + :compiler {:main status-im.test.protocol.runner + :output-to "target/test/test.js" + :output-dir "target/test" + :optimizations :none + :preamble ["js/hook-require.js"] + :target :nodejs}} {:id "env-dev-utils" :source-paths ["env/dev/env/utils.cljs" "test/env/dev" "dev"] :compiler {:main env.test.runner @@ -107,8 +107,7 @@ :prod {:cljsbuild {:builds {:ios {:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/mobile" "src" "env/prod" "prod"] - :compiler {:output-to "index.ios.js" - :main "env.ios.main" + :compiler {:main "env.ios.main" :output-dir "target/ios-prod" :static-fns true :fn-invoke-direct true @@ -120,12 +119,15 @@ :parallel-build false :elide-asserts true :externs ["externs.js"] - :language-in :ecmascript5} + :language-in :es-2015 + :language-out :es-2015 + :modules {:cljs-base {:output-to "index.ios.js"} + :i18n {:entries #{"status_im.goog.i18n"} + :output-to "status-modules/cljs/i18n-raw.js"}}} :warning-handlers [status-im.utils.build/warning-handler]} :android {:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/mobile" "src" "env/prod" "prod"] - :compiler {:output-to "index.android.js" - :main "env.android.main" + :compiler {:main "env.android.main" :output-dir "target/android-prod" :static-fns true :fn-invoke-direct true @@ -137,18 +139,28 @@ :parallel-build false :elide-asserts true :externs ["externs.js"] - :language-in :ecmascript5} + :language-in :es-2015 + :language-out :es-2015 + :modules {:cljs-base {:output-to "index.android.js"} + :i18n {:entries #{"status_im.goog.i18n"} + :output-to "status-modules/cljs/i18n-raw.js"}}} :warning-handlers [status-im.utils.build/warning-handler]} :desktop {:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/desktop" "src" "env/prod" "prod"] - :compiler {:output-to "index.desktop.js" - :main "env.desktop.main" + :compiler {:main "env.desktop.main" :output-dir "target/desktop-prod" :static-fns true + :fn-invoke-direct true :optimize-constants true :optimizations :simple :closure-defines {"goog.DEBUG" false} + :pseudo-names false + :pretty-print false :parallel-build false :elide-asserts true - :language-in :ecmascript5} + :language-in :es-2015 + :language-out :es-2015 + :modules {:cljs-base {:output-to "index.desktop.js"} + :i18n {:entries #{"status_im.goog.i18n"} + :output-to "status-modules/cljs/i18n-raw.js"}}} :warning-handlers [status-im.utils.build/warning-handler]}}}}}) diff --git a/src/status_im/goog/i18n.cljs b/src/status_im/goog/i18n.cljs new file mode 100644 index 0000000000..a780a723f5 --- /dev/null +++ b/src/status_im/goog/i18n.cljs @@ -0,0 +1,448 @@ +(ns status-im.goog.i18n + (:require [clojure.string :as string] + goog.i18n.DateTimeSymbols + goog.i18n.DateTimeSymbolsType + goog.i18n.DateTimeSymbols_af + goog.i18n.DateTimeSymbols_am + goog.i18n.DateTimeSymbols_ar + goog.i18n.DateTimeSymbols_ar_DZ + goog.i18n.DateTimeSymbols_ar_EG + goog.i18n.DateTimeSymbols_az + goog.i18n.DateTimeSymbols_be + goog.i18n.DateTimeSymbols_bg + goog.i18n.DateTimeSymbols_bn + goog.i18n.DateTimeSymbols_br + goog.i18n.DateTimeSymbols_bs + goog.i18n.DateTimeSymbols_ca + goog.i18n.DateTimeSymbols_chr + goog.i18n.DateTimeSymbols_cs + goog.i18n.DateTimeSymbols_cy + goog.i18n.DateTimeSymbols_da + goog.i18n.DateTimeSymbols_de + goog.i18n.DateTimeSymbols_de_AT + goog.i18n.DateTimeSymbols_de_CH + goog.i18n.DateTimeSymbols_el + goog.i18n.DateTimeSymbols_en + goog.i18n.DateTimeSymbols_en_AU + goog.i18n.DateTimeSymbols_en_CA + goog.i18n.DateTimeSymbols_en_GB + goog.i18n.DateTimeSymbols_en_IE + goog.i18n.DateTimeSymbols_en_IN + goog.i18n.DateTimeSymbols_en_ISO + goog.i18n.DateTimeSymbols_en_SG + goog.i18n.DateTimeSymbols_en_US + goog.i18n.DateTimeSymbols_en_ZA + goog.i18n.DateTimeSymbols_es + goog.i18n.DateTimeSymbols_es_419 + goog.i18n.DateTimeSymbols_es_ES + goog.i18n.DateTimeSymbols_es_MX + goog.i18n.DateTimeSymbols_es_US + goog.i18n.DateTimeSymbols_et + goog.i18n.DateTimeSymbols_eu + goog.i18n.DateTimeSymbols_fa + goog.i18n.DateTimeSymbols_fi + goog.i18n.DateTimeSymbols_fil + goog.i18n.DateTimeSymbols_fr + goog.i18n.DateTimeSymbols_fr_CA + goog.i18n.DateTimeSymbols_ga + goog.i18n.DateTimeSymbols_gl + goog.i18n.DateTimeSymbols_gsw + goog.i18n.DateTimeSymbols_gu + goog.i18n.DateTimeSymbols_haw + goog.i18n.DateTimeSymbols_he + goog.i18n.DateTimeSymbols_hi + goog.i18n.DateTimeSymbols_hr + goog.i18n.DateTimeSymbols_hu + goog.i18n.DateTimeSymbols_hy + goog.i18n.DateTimeSymbols_id + goog.i18n.DateTimeSymbols_in + goog.i18n.DateTimeSymbols_is + goog.i18n.DateTimeSymbols_it + goog.i18n.DateTimeSymbols_iw + goog.i18n.DateTimeSymbols_ja + goog.i18n.DateTimeSymbols_ka + goog.i18n.DateTimeSymbols_kk + goog.i18n.DateTimeSymbols_km + goog.i18n.DateTimeSymbols_kn + goog.i18n.DateTimeSymbols_ko + goog.i18n.DateTimeSymbols_ky + goog.i18n.DateTimeSymbols_ln + goog.i18n.DateTimeSymbols_lo + goog.i18n.DateTimeSymbols_lt + goog.i18n.DateTimeSymbols_lv + goog.i18n.DateTimeSymbols_mk + goog.i18n.DateTimeSymbols_ml + goog.i18n.DateTimeSymbols_mn + goog.i18n.DateTimeSymbols_mo + goog.i18n.DateTimeSymbols_mr + goog.i18n.DateTimeSymbols_ms + goog.i18n.DateTimeSymbols_mt + goog.i18n.DateTimeSymbols_my + goog.i18n.DateTimeSymbols_nb + goog.i18n.DateTimeSymbols_ne + goog.i18n.DateTimeSymbols_nl + goog.i18n.DateTimeSymbols_no + goog.i18n.DateTimeSymbols_no_NO + goog.i18n.DateTimeSymbols_or + goog.i18n.DateTimeSymbols_pa + goog.i18n.DateTimeSymbols_pl + goog.i18n.DateTimeSymbols_pt + goog.i18n.DateTimeSymbols_pt_BR + goog.i18n.DateTimeSymbols_pt_PT + goog.i18n.DateTimeSymbols_ro + goog.i18n.DateTimeSymbols_ru + goog.i18n.DateTimeSymbols_sh + goog.i18n.DateTimeSymbols_si + goog.i18n.DateTimeSymbols_sk + goog.i18n.DateTimeSymbols_sl + goog.i18n.DateTimeSymbols_sq + goog.i18n.DateTimeSymbols_sr + goog.i18n.DateTimeSymbols_sr_Latn + goog.i18n.DateTimeSymbols_sv + goog.i18n.DateTimeSymbols_sw + goog.i18n.DateTimeSymbols_ta + goog.i18n.DateTimeSymbols_te + goog.i18n.DateTimeSymbols_th + goog.i18n.DateTimeSymbols_tl + goog.i18n.DateTimeSymbols_tr + goog.i18n.DateTimeSymbols_uk + goog.i18n.DateTimeSymbols_ur + goog.i18n.DateTimeSymbols_uz + goog.i18n.DateTimeSymbols_vi + goog.i18n.DateTimeSymbols_zh + goog.i18n.DateTimeSymbols_zh_CN + goog.i18n.DateTimeSymbols_zh_HK + goog.i18n.DateTimeSymbols_zh_TW + goog.i18n.DateTimeSymbols_zu + goog.i18n.CompactNumberFormatSymbols + goog.i18n.CompactNumberFormatSymbols_af + goog.i18n.CompactNumberFormatSymbols_am + goog.i18n.CompactNumberFormatSymbols_ar + goog.i18n.CompactNumberFormatSymbols_ar_DZ + goog.i18n.CompactNumberFormatSymbols_ar_EG + goog.i18n.CompactNumberFormatSymbols_az + goog.i18n.CompactNumberFormatSymbols_be + goog.i18n.CompactNumberFormatSymbols_bg + goog.i18n.CompactNumberFormatSymbols_bn + goog.i18n.CompactNumberFormatSymbols_br + goog.i18n.CompactNumberFormatSymbols_bs + goog.i18n.CompactNumberFormatSymbols_ca + goog.i18n.CompactNumberFormatSymbols_chr + goog.i18n.CompactNumberFormatSymbols_cs + goog.i18n.CompactNumberFormatSymbols_cy + goog.i18n.CompactNumberFormatSymbols_da + goog.i18n.CompactNumberFormatSymbols_de + goog.i18n.CompactNumberFormatSymbols_de_AT + goog.i18n.CompactNumberFormatSymbols_de_CH + goog.i18n.CompactNumberFormatSymbols_el + goog.i18n.CompactNumberFormatSymbols_en + goog.i18n.CompactNumberFormatSymbols_en_AU + goog.i18n.CompactNumberFormatSymbols_en_CA + goog.i18n.CompactNumberFormatSymbols_en_GB + goog.i18n.CompactNumberFormatSymbols_en_IE + goog.i18n.CompactNumberFormatSymbols_en_IN + goog.i18n.CompactNumberFormatSymbols_en_SG + goog.i18n.CompactNumberFormatSymbols_en_US + goog.i18n.CompactNumberFormatSymbols_en_ZA + goog.i18n.CompactNumberFormatSymbols_es + goog.i18n.CompactNumberFormatSymbols_es_419 + goog.i18n.CompactNumberFormatSymbols_es_ES + goog.i18n.CompactNumberFormatSymbols_es_MX + goog.i18n.CompactNumberFormatSymbols_es_US + goog.i18n.CompactNumberFormatSymbols_et + goog.i18n.CompactNumberFormatSymbols_eu + goog.i18n.CompactNumberFormatSymbols_fa + goog.i18n.CompactNumberFormatSymbols_fi + goog.i18n.CompactNumberFormatSymbols_fil + goog.i18n.CompactNumberFormatSymbols_fr + goog.i18n.CompactNumberFormatSymbols_fr_CA + goog.i18n.CompactNumberFormatSymbols_ga + goog.i18n.CompactNumberFormatSymbols_gl + goog.i18n.CompactNumberFormatSymbols_gsw + goog.i18n.CompactNumberFormatSymbols_gu + goog.i18n.CompactNumberFormatSymbols_haw + goog.i18n.CompactNumberFormatSymbols_he + goog.i18n.CompactNumberFormatSymbols_hi + goog.i18n.CompactNumberFormatSymbols_hr + goog.i18n.CompactNumberFormatSymbols_hu + goog.i18n.CompactNumberFormatSymbols_hy + goog.i18n.CompactNumberFormatSymbols_id + goog.i18n.CompactNumberFormatSymbols_in + goog.i18n.CompactNumberFormatSymbols_is + goog.i18n.CompactNumberFormatSymbols_it + goog.i18n.CompactNumberFormatSymbols_iw + goog.i18n.CompactNumberFormatSymbols_ja + goog.i18n.CompactNumberFormatSymbols_ka + goog.i18n.CompactNumberFormatSymbols_kk + goog.i18n.CompactNumberFormatSymbols_km + goog.i18n.CompactNumberFormatSymbols_kn + goog.i18n.CompactNumberFormatSymbols_ko + goog.i18n.CompactNumberFormatSymbols_ky + goog.i18n.CompactNumberFormatSymbols_ln + goog.i18n.CompactNumberFormatSymbols_lo + goog.i18n.CompactNumberFormatSymbols_lt + goog.i18n.CompactNumberFormatSymbols_lv + goog.i18n.CompactNumberFormatSymbols_mk + goog.i18n.CompactNumberFormatSymbols_ml + goog.i18n.CompactNumberFormatSymbols_mn + goog.i18n.CompactNumberFormatSymbols_mo + goog.i18n.CompactNumberFormatSymbols_mr + goog.i18n.CompactNumberFormatSymbols_ms + goog.i18n.CompactNumberFormatSymbols_mt + goog.i18n.CompactNumberFormatSymbols_my + goog.i18n.CompactNumberFormatSymbols_nb + goog.i18n.CompactNumberFormatSymbols_ne + goog.i18n.CompactNumberFormatSymbols_nl + goog.i18n.CompactNumberFormatSymbols_no + goog.i18n.CompactNumberFormatSymbols_no_NO + goog.i18n.CompactNumberFormatSymbols_or + goog.i18n.CompactNumberFormatSymbols_pa + goog.i18n.CompactNumberFormatSymbols_pl + goog.i18n.CompactNumberFormatSymbols_pt + goog.i18n.CompactNumberFormatSymbols_pt_BR + goog.i18n.CompactNumberFormatSymbols_pt_PT + goog.i18n.CompactNumberFormatSymbols_ro + goog.i18n.CompactNumberFormatSymbols_ru + goog.i18n.CompactNumberFormatSymbols_sh + goog.i18n.CompactNumberFormatSymbols_si + goog.i18n.CompactNumberFormatSymbols_sk + goog.i18n.CompactNumberFormatSymbols_sl + goog.i18n.CompactNumberFormatSymbols_sq + goog.i18n.CompactNumberFormatSymbols_sr + goog.i18n.CompactNumberFormatSymbols_sr_Latn + goog.i18n.CompactNumberFormatSymbols_sv + goog.i18n.CompactNumberFormatSymbols_sw + goog.i18n.CompactNumberFormatSymbols_ta + goog.i18n.CompactNumberFormatSymbols_te + goog.i18n.CompactNumberFormatSymbols_th + goog.i18n.CompactNumberFormatSymbols_tl + goog.i18n.CompactNumberFormatSymbols_tr + goog.i18n.CompactNumberFormatSymbols_uk + goog.i18n.CompactNumberFormatSymbols_ur + goog.i18n.CompactNumberFormatSymbols_uz + goog.i18n.CompactNumberFormatSymbols_vi + goog.i18n.CompactNumberFormatSymbols_zh + goog.i18n.CompactNumberFormatSymbols_zh_CN + goog.i18n.CompactNumberFormatSymbols_zh_HK + goog.i18n.CompactNumberFormatSymbols_zh_TW + goog.i18n.CompactNumberFormatSymbols_zu + goog.i18n.currency + goog.i18n.currency.CurrencyInfo + goog.i18n.currency.CurrencyInfoTier2 + goog.i18n.DateTimeFormat + goog.i18n.DateTimeFormat.Format + goog.i18n.MessageFormat + goog.i18n.NumberFormat + goog.i18n.NumberFormat.CurrencyStyle + goog.i18n.NumberFormat.Format + goog.i18n.ordinalRules + goog.i18n.pluralRules + goog.i18n.TimeZone)) + +(def locales + {"af" goog/i18n.DateTimeSymbols_af + "am" goog/i18n.DateTimeSymbols_am + "ar" goog/i18n.DateTimeSymbols_ar + "ar_DZ" goog/i18n.DateTimeSymbols_ar_DZ + "ar_EG" goog/i18n.DateTimeSymbols_ar_EG + "az" goog/i18n.DateTimeSymbols_az + "be" goog/i18n.DateTimeSymbols_be + "bg" goog/i18n.DateTimeSymbols_bg + "bn" goog/i18n.DateTimeSymbols_bn + "br" goog/i18n.DateTimeSymbols_br + "bs" goog/i18n.DateTimeSymbols_bs + "ca" goog/i18n.DateTimeSymbols_ca + "chr" goog/i18n.DateTimeSymbols_chr + "cs" goog/i18n.DateTimeSymbols_cs + "cy" goog/i18n.DateTimeSymbols_cy + "da" goog/i18n.DateTimeSymbols_da + "de" goog/i18n.DateTimeSymbols_de + "de_AT" goog/i18n.DateTimeSymbols_de_AT + "de_CH" goog/i18n.DateTimeSymbols_de_CH + "el" goog/i18n.DateTimeSymbols_el + "en" goog/i18n.DateTimeSymbols_en + "en_AU" goog/i18n.DateTimeSymbols_en_AU + "en_CA" goog/i18n.DateTimeSymbols_en_CA + "en_GB" goog/i18n.DateTimeSymbols_en_GB + "en_IE" goog/i18n.DateTimeSymbols_en_IE + "en_IN" goog/i18n.DateTimeSymbols_en_IN + "en_ISO" goog/i18n.DateTimeSymbols_en_ISO + "en_SG" goog/i18n.DateTimeSymbols_en_SG + "en_US" goog/i18n.DateTimeSymbols_en_US + "en_ZA" goog/i18n.DateTimeSymbols_en_ZA + "es" goog/i18n.DateTimeSymbols_es + "es_419" goog/i18n.DateTimeSymbols_es_419 + "es_ES" goog/i18n.DateTimeSymbols_es_ES + "es_MX" goog/i18n.DateTimeSymbols_es_MX + "es_US" goog/i18n.DateTimeSymbols_es_US + "et" goog/i18n.DateTimeSymbols_et + "eu" goog/i18n.DateTimeSymbols_eu + "fa" goog/i18n.DateTimeSymbols_fa + "fi" goog/i18n.DateTimeSymbols_fi + "fil" goog/i18n.DateTimeSymbols_fil + "fr" goog/i18n.DateTimeSymbols_fr + "fr_CA" goog/i18n.DateTimeSymbols_fr_CA + "ga" goog/i18n.DateTimeSymbols_ga + "gl" goog/i18n.DateTimeSymbols_gl + "gsw" goog/i18n.DateTimeSymbols_gsw + "gu" goog/i18n.DateTimeSymbols_gu + "haw" goog/i18n.DateTimeSymbols_haw + "he" goog/i18n.DateTimeSymbols_he + "hi" goog/i18n.DateTimeSymbols_hi + "hr" goog/i18n.DateTimeSymbols_hr + "hu" goog/i18n.DateTimeSymbols_hu + "hy" goog/i18n.DateTimeSymbols_hy + "id" goog/i18n.DateTimeSymbols_id + "in" goog/i18n.DateTimeSymbols_in + "is" goog/i18n.DateTimeSymbols_is + "it" goog/i18n.DateTimeSymbols_it + "iw" goog/i18n.DateTimeSymbols_iw + "ja" goog/i18n.DateTimeSymbols_ja + "ka" goog/i18n.DateTimeSymbols_ka + "kk" goog/i18n.DateTimeSymbols_kk + "km" goog/i18n.DateTimeSymbols_km + "kn" goog/i18n.DateTimeSymbols_kn + "ko" goog/i18n.DateTimeSymbols_ko + "ky" goog/i18n.DateTimeSymbols_ky + "ln" goog/i18n.DateTimeSymbols_ln + "lo" goog/i18n.DateTimeSymbols_lo + "lt" goog/i18n.DateTimeSymbols_lt + "lv" goog/i18n.DateTimeSymbols_lv + "mk" goog/i18n.DateTimeSymbols_mk + "ml" goog/i18n.DateTimeSymbols_ml + "mn" goog/i18n.DateTimeSymbols_mn + "mo" goog/i18n.DateTimeSymbols_mo + "mr" goog/i18n.DateTimeSymbols_mr + "ms" goog/i18n.DateTimeSymbols_ms + "mt" goog/i18n.DateTimeSymbols_mt + "my" goog/i18n.DateTimeSymbols_my + "nb" goog/i18n.DateTimeSymbols_nb + "ne" goog/i18n.DateTimeSymbols_ne + "nl" goog/i18n.DateTimeSymbols_nl + "no" goog/i18n.DateTimeSymbols_no + "no_NO" goog/i18n.DateTimeSymbols_no_NO + "or" goog/i18n.DateTimeSymbols_or + "pa" goog/i18n.DateTimeSymbols_pa + "pl" goog/i18n.DateTimeSymbols_pl + "pt" goog/i18n.DateTimeSymbols_pt + "pt_BR" goog/i18n.DateTimeSymbols_pt_BR + "pt_PT" goog/i18n.DateTimeSymbols_pt_PT + "ro" goog/i18n.DateTimeSymbols_ro + "ru" goog/i18n.DateTimeSymbols_ru + "sh" goog/i18n.DateTimeSymbols_sh + "si" goog/i18n.DateTimeSymbols_si + "sk" goog/i18n.DateTimeSymbols_sk + "sl" goog/i18n.DateTimeSymbols_sl + "sq" goog/i18n.DateTimeSymbols_sq + "sr" goog/i18n.DateTimeSymbols_sr + "sr_Latn" goog/i18n.DateTimeSymbols_sr_Latn + "sv" goog/i18n.DateTimeSymbols_sv + "sw" goog/i18n.DateTimeSymbols_sw + "ta" goog/i18n.DateTimeSymbols_ta + "te" goog/i18n.DateTimeSymbols_te + "th" goog/i18n.DateTimeSymbols_th + "tl" goog/i18n.DateTimeSymbols_tl + "tr" goog/i18n.DateTimeSymbols_tr + "uk" goog/i18n.DateTimeSymbols_uk + "ur" goog/i18n.DateTimeSymbols_ur + "uz" goog/i18n.DateTimeSymbols_uz + "vi" goog/i18n.DateTimeSymbols_vi + "zh" goog/i18n.DateTimeSymbols_zh + "zh_CN" goog/i18n.DateTimeSymbols_zh_CN + "zh_HK" goog/i18n.DateTimeSymbols_zh_HK + "zh_TW" goog/i18n.DateTimeSymbols_zh_TW + "zu" goog/i18n.DateTimeSymbols_zu}) + +;; xx-YY locale, xx locale or en fallback +(defn locale-symbols [locale-name] + (if-let [loc (get locales locale-name)] + loc + (let [name-first (string/replace (or locale-name "") #"-.*$" "") + loc (get locales name-first)] + (or loc goog/i18n.DateTimeSymbols_en)))) + +;; get formatter for current locale symbols and format function +(defn mk-fmt [locale format-fn] + (let [locsym (locale-symbols locale)] + (goog/i18n.DateTimeFormat. (format-fn locsym) locsym))) + +(defn format-currency + ([value currency-code] + (format-currency value currency-code true)) + ([value currency-code currency-symbol?] + (.addTier2Support goog/i18n.currency) + (let [currency-code-to-nfs-map {"ZAR" goog/i18n.NumberFormatSymbols_af + "ETB" goog/i18n.NumberFormatSymbols_am + "EGP" goog/i18n.NumberFormatSymbols_ar + "DZD" goog/i18n.NumberFormatSymbols_ar_DZ + "AZN" goog/i18n.NumberFormatSymbols_az + "BYN" goog/i18n.NumberFormatSymbols_be + "BGN" goog/i18n.NumberFormatSymbols_bg + "BDT" goog/i18n.NumberFormatSymbols_bn + "EUR" goog/i18n.NumberFormatSymbols_br + "BAM" goog/i18n.NumberFormatSymbols_bs + "USD" goog/i18n.NumberFormatSymbols_en + "CZK" goog/i18n.NumberFormatSymbols_cs + "GBP" goog/i18n.NumberFormatSymbols_cy + "DKK" goog/i18n.NumberFormatSymbols_da + "CHF" goog/i18n.NumberFormatSymbols_de_CH + "AUD" goog/i18n.NumberFormatSymbols_en_AU + "CAD" goog/i18n.NumberFormatSymbols_en_CA + "INR" goog/i18n.NumberFormatSymbols_en_IN + "SGD" goog/i18n.NumberFormatSymbols_en_SG + "MXN" goog/i18n.NumberFormatSymbols_es_419 + "IRR" goog/i18n.NumberFormatSymbols_fa + "PHP" goog/i18n.NumberFormatSymbols_fil + "ILS" goog/i18n.NumberFormatSymbols_he + "HRK" goog/i18n.NumberFormatSymbols_hr + "HUF" goog/i18n.NumberFormatSymbols_hu + "AMD" goog/i18n.NumberFormatSymbols_hy + "IDR" goog/i18n.NumberFormatSymbols_id + "ISK" goog/i18n.NumberFormatSymbols_is + "JPY" goog/i18n.NumberFormatSymbols_ja + "GEL" goog/i18n.NumberFormatSymbols_ka + "KZT" goog/i18n.NumberFormatSymbols_kk + "KHR" goog/i18n.NumberFormatSymbols_km + "KRW" goog/i18n.NumberFormatSymbols_ko + "KGS" goog/i18n.NumberFormatSymbols_ky + "CDF" goog/i18n.NumberFormatSymbols_ln + "LAK" goog/i18n.NumberFormatSymbols_lo + "MKD" goog/i18n.NumberFormatSymbols_mk + "MNT" goog/i18n.NumberFormatSymbols_mn + "MDL" goog/i18n.NumberFormatSymbols_mo + "MYR" goog/i18n.NumberFormatSymbols_ms + "MMK" goog/i18n.NumberFormatSymbols_my + "NOK" goog/i18n.NumberFormatSymbols_nb + "NPR" goog/i18n.NumberFormatSymbols_ne + "PLN" goog/i18n.NumberFormatSymbols_pl + "BRL" goog/i18n.NumberFormatSymbols_pt + "RON" goog/i18n.NumberFormatSymbols_ro + "RUB" goog/i18n.NumberFormatSymbols_ru + "RSD" goog/i18n.NumberFormatSymbols_sh + "LKR" goog/i18n.NumberFormatSymbols_si + "ALL" goog/i18n.NumberFormatSymbols_sq + "SEK" goog/i18n.NumberFormatSymbols_sv + "TZS" goog/i18n.NumberFormatSymbols_sw + "THB" goog/i18n.NumberFormatSymbols_th + "TRY" goog/i18n.NumberFormatSymbols_tr + "UAH" goog/i18n.NumberFormatSymbols_uk + "PKR" goog/i18n.NumberFormatSymbols_ur + "UZS" goog/i18n.NumberFormatSymbols_uz + "VND" goog/i18n.NumberFormatSymbols_vi + "CNY" goog/i18n.NumberFormatSymbols_zh + "HKD" goog/i18n.NumberFormatSymbols_zh_HK + "TWD" goog/i18n.NumberFormatSymbols_zh_TW} + nfs (or (get currency-code-to-nfs-map currency-code) + goog/i18n.NumberFormatSymbols_en)] + (set! goog/i18n.NumberFormatSymbols + (if currency-symbol? + nfs + (-> nfs + (js->clj :keywordize-keys true) + ;; Remove any currency symbol placeholders in the pattern + (update :CURRENCY_PATTERN (fn [pat] + (string/replace pat #"\s*¤\s*" ""))) + clj->js))) + (.format + (new goog/i18n.NumberFormat goog/i18n.NumberFormat.Format.CURRENCY currency-code) + value)))) diff --git a/src/status_im/goog/i18n_module.cljs b/src/status_im/goog/i18n_module.cljs new file mode 100644 index 0000000000..fec8a1a439 --- /dev/null +++ b/src/status_im/goog/i18n_module.cljs @@ -0,0 +1,15 @@ +(ns status-im.goog.i18n-module + (:require-macros [status-im.modules :as modules])) + +(modules/defmodule i18n + {:mk-fmt 'status-im.goog.i18n/mk-fmt + :format-currency 'status-im.goog.i18n/format-currency}) + +(defn mk-fmt [locale format-fn] + ((get-symbol :mk-fmt) locale format-fn)) + +(defn format-currency + ([value currency-code] + ((get-symbol :format-currency) value currency-code true)) + ([value currency-code currency-symbol?] + ((get-symbol :format-currency) value currency-code currency-symbol?))) diff --git a/src/status_im/i18n.cljs b/src/status_im/i18n.cljs index d01e548369..fc53057eb9 100644 --- a/src/status_im/i18n.cljs +++ b/src/status_im/i18n.cljs @@ -2,7 +2,8 @@ (:require [status-im.react-native.js-dependencies :as rn-dependencies] [clojure.string :as string] - [status-im.i18n-resources :as i18n-resources])) + [status-im.i18n-resources :as i18n-resources] + [status-im.goog.i18n-module :as goog.i18n])) (set! (.-locale rn-dependencies/i18n) (name i18n-resources/default-device-language)) (set! (.-fallbacks rn-dependencies/i18n) true) @@ -67,84 +68,5 @@ (def locale (.-locale rn-dependencies/i18n)) -(defn format-currency - ([value currency-code] - (format-currency value currency-code true)) - ([value currency-code currency-symbol?] - (.addTier2Support goog/i18n.currency) - (let [currency-code-to-nfs-map {"ZAR" goog/i18n.NumberFormatSymbols_af - "ETB" goog/i18n.NumberFormatSymbols_am - "EGP" goog/i18n.NumberFormatSymbols_ar - "DZD" goog/i18n.NumberFormatSymbols_ar_DZ - "AZN" goog/i18n.NumberFormatSymbols_az - "BYN" goog/i18n.NumberFormatSymbols_be - "BGN" goog/i18n.NumberFormatSymbols_bg - "BDT" goog/i18n.NumberFormatSymbols_bn - "EUR" goog/i18n.NumberFormatSymbols_br - "BAM" goog/i18n.NumberFormatSymbols_bs - "USD" goog/i18n.NumberFormatSymbols_en - "CZK" goog/i18n.NumberFormatSymbols_cs - "GBP" goog/i18n.NumberFormatSymbols_cy - "DKK" goog/i18n.NumberFormatSymbols_da - "CHF" goog/i18n.NumberFormatSymbols_de_CH - "AUD" goog/i18n.NumberFormatSymbols_en_AU - "CAD" goog/i18n.NumberFormatSymbols_en_CA - "INR" goog/i18n.NumberFormatSymbols_en_IN - "SGD" goog/i18n.NumberFormatSymbols_en_SG - "MXN" goog/i18n.NumberFormatSymbols_es_419 - "IRR" goog/i18n.NumberFormatSymbols_fa - "PHP" goog/i18n.NumberFormatSymbols_fil - "ILS" goog/i18n.NumberFormatSymbols_he - "HRK" goog/i18n.NumberFormatSymbols_hr - "HUF" goog/i18n.NumberFormatSymbols_hu - "AMD" goog/i18n.NumberFormatSymbols_hy - "IDR" goog/i18n.NumberFormatSymbols_id - "ISK" goog/i18n.NumberFormatSymbols_is - "JPY" goog/i18n.NumberFormatSymbols_ja - "GEL" goog/i18n.NumberFormatSymbols_ka - "KZT" goog/i18n.NumberFormatSymbols_kk - "KHR" goog/i18n.NumberFormatSymbols_km - "KRW" goog/i18n.NumberFormatSymbols_ko - "KGS" goog/i18n.NumberFormatSymbols_ky - "CDF" goog/i18n.NumberFormatSymbols_ln - "LAK" goog/i18n.NumberFormatSymbols_lo - "MKD" goog/i18n.NumberFormatSymbols_mk - "MNT" goog/i18n.NumberFormatSymbols_mn - "MDL" goog/i18n.NumberFormatSymbols_mo - "MYR" goog/i18n.NumberFormatSymbols_ms - "MMK" goog/i18n.NumberFormatSymbols_my - "NOK" goog/i18n.NumberFormatSymbols_nb - "NPR" goog/i18n.NumberFormatSymbols_ne - "PLN" goog/i18n.NumberFormatSymbols_pl - "BRL" goog/i18n.NumberFormatSymbols_pt - "RON" goog/i18n.NumberFormatSymbols_ro - "RUB" goog/i18n.NumberFormatSymbols_ru - "RSD" goog/i18n.NumberFormatSymbols_sh - "LKR" goog/i18n.NumberFormatSymbols_si - "ALL" goog/i18n.NumberFormatSymbols_sq - "SEK" goog/i18n.NumberFormatSymbols_sv - "TZS" goog/i18n.NumberFormatSymbols_sw - "THB" goog/i18n.NumberFormatSymbols_th - "TRY" goog/i18n.NumberFormatSymbols_tr - "UAH" goog/i18n.NumberFormatSymbols_uk - "PKR" goog/i18n.NumberFormatSymbols_ur - "UZS" goog/i18n.NumberFormatSymbols_uz - "VND" goog/i18n.NumberFormatSymbols_vi - "CNY" goog/i18n.NumberFormatSymbols_zh - "HKD" goog/i18n.NumberFormatSymbols_zh_HK - "TWD" goog/i18n.NumberFormatSymbols_zh_TW} - nfs (or (get currency-code-to-nfs-map currency-code) - goog/i18n.NumberFormatSymbols_en)] - (set! goog/i18n.NumberFormatSymbols - (if currency-symbol? - nfs - (-> nfs - (js->clj :keywordize-keys true) - ;; Remove any currency symbol placeholders in the pattern - (update :CURRENCY_PATTERN (fn [pat] - (string/replace pat #"\s*¤\s*" ""))) - clj->js))) - (.format - (new goog/i18n.NumberFormat goog/i18n.NumberFormat.Format.CURRENCY currency-code) - value)))) +(def format-currency goog.i18n/format-currency) diff --git a/src/status_im/modules.clj b/src/status_im/modules.clj new file mode 100644 index 0000000000..ccd0b89386 --- /dev/null +++ b/src/status_im/modules.clj @@ -0,0 +1,47 @@ +(ns status-im.modules) + +(def prod? (= "prod" (System/getenv "BUILD_ENV"))) + +(defn prepare-symbols [symbols] + (mapcat (fn [[k v]] + [k `(resolve ~v)]) + symbols)) + +(defn require-namespaces [symbols] + (distinct + (map (fn [[_ [_ v]]] + `(quote ~(symbol (namespace v)))) + symbols))) + +(defmacro defmodule [module-name symbols] + (let [module (gensym "module") + loaded? (gensym "loaded?") + path (str "status-modules/cljs/" module-name ".js") + k (gensym) + get-symbol 'get-symbol + load-module 'load-module] + (if prod? + `(do + (defonce ~loaded? (atom false)) + (defonce ~module (atom {})) + (defn ~load-module [] + (when-not @~loaded? + (js/eval (js/require ~path)) + (reset! ~module + (hash-map ~@(prepare-symbols symbols))) + (reset! ~loaded? true))) + (defn ~get-symbol [~k] + (~load-module) + (get @~module ~k))) + `(do + (require ~@(require-namespaces symbols)) + (defonce ~loaded? (atom false)) + (defonce ~module (atom {})) + (defn ~load-module [] + (when-not @~loaded? + (reset! ~module + (hash-map ~@(prepare-symbols symbols))) + (reset! ~loaded? true))) + (defn ~get-symbol [~k] + (~load-module) + (get @~module ~k)))))) diff --git a/src/status_im/ui/screens/browser/open_dapp/views.cljs b/src/status_im/ui/screens/browser/open_dapp/views.cljs index 6980d23510..2cf577ea22 100644 --- a/src/status_im/ui/screens/browser/open_dapp/views.cljs +++ b/src/status_im/ui/screens/browser/open_dapp/views.cljs @@ -32,7 +32,7 @@ [vector-icons/icon :main-icons/browser {:color colors/gray}]]}]]) (def dapp-image-data {:image (resources/get-image :dapp-store) :width 768 :height 333}) -(def dapp-image (components.common/image-contain nil dapp-image-data)) +(defn dapp-image [] [components.common/image-contain nil dapp-image-data]) (def privacy-otions-visible? (reagent/atom true)) diff --git a/src/status_im/ui/screens/home/views.cljs b/src/status_im/ui/screens/home/views.cljs index 122a5f97b4..791d27c175 100644 --- a/src/status_im/ui/screens/home/views.cljs +++ b/src/status_im/ui/screens/home/views.cljs @@ -3,7 +3,6 @@ [reagent.core :as reagent] [status-im.i18n :as i18n] [status-im.react-native.resources :as resources] - [status-im.ui.components.colors :as colors] [status-im.ui.components.connectivity.view :as connectivity] [status-im.ui.components.icons.vector-icons :as icons] [status-im.ui.components.list.views :as list] diff --git a/src/status_im/utils/datetime.cljs b/src/status_im/utils/datetime.cljs index a47ce8e8f4..b2207e7e59 100644 --- a/src/status_im/utils/datetime.cljs +++ b/src/status_im/utils/datetime.cljs @@ -7,11 +7,9 @@ unparse]] [status-im.i18n :refer [label label-pluralize]] [status-im.native-module.core :as status] - [goog.string :as gstring] - goog.string.format - goog.i18n.DateTimeFormat [clojure.string :as s] - [goog.object :refer [get]])) + [goog.object :refer [get]] + [status-im.goog.i18n-module :as goog.18n])) (defn now [] (t/now)) @@ -26,14 +24,6 @@ (def time-zone-offset (hours (- (/ (.getTimezoneOffset (js/Date.)) 60)))) -;; xx-YY locale, xx locale or en fallback -(defn- locale-symbols [locale-name] - (if-let [loc (get goog/i18n (str "DateTimeSymbols_" locale-name))] - loc - (let [name-first (s/replace (or locale-name "") #"-.*$" "") - loc (get goog/i18n (str "DateTimeSymbols_" name-first))] - (or loc goog/i18n.DateTimeSymbols_en)))) - ;; detects if given locale symbols timeformat generates AM/PM ("a") (defn- is24Hour-locsym [locsym] (not (s/includes? @@ -59,20 +49,22 @@ (defn- medium-date-time-format [locsym] (str (medium-date-format locsym) ", " (time-format locsym))) -;; get formatter for current locale symbols and format function -(defn- mk-fmt [locale format-fn] - (let [locsym (locale-symbols locale)] - (goog/i18n.DateTimeFormat. (format-fn locsym) locsym))) +(defn get-formatter-fn [format] + (let [formatter (atom nil)] + (fn [] + (or @formatter + (reset! formatter + (goog.18n/mk-fmt status-im.i18n/locale format)))))) ;; generate formatters for different formats (def date-time-fmt - (mk-fmt status-im.i18n/locale medium-date-time-format)) + (get-formatter-fn medium-date-time-format)) (def date-fmt - (mk-fmt status-im.i18n/locale medium-date-format)) + (get-formatter-fn medium-date-format)) (def time-fmt - (mk-fmt status-im.i18n/locale short-time-format)) + (get-formatter-fn short-time-format)) (def short-date-fmt - (mk-fmt status-im.i18n/locale short-date-format)) + (get-formatter-fn short-date-format)) ;; ;; functions which apply formats for the given timestamp @@ -90,25 +82,25 @@ (defn to-short-str [ms] (to-str ms - #(.format date-fmt %) + #(.format (date-fmt) %) #(label :t/datetime-yesterday) - #(.format time-fmt %))) + #(.format (time-fmt) %))) (defn day-relative [ms] (to-str ms - #(.format date-fmt %) + #(.format (date-fmt) %) #(label :t/datetime-yesterday) #(label :t/datetime-today))) (defn timestamp->mini-date [ms] - (.format short-date-fmt (-> ms - from-long - (plus time-zone-offset)))) + (.format (short-date-fmt) (-> ms + from-long + (plus time-zone-offset)))) (defn timestamp->time [ms] - (.format time-fmt (-> ms - from-long - (plus time-zone-offset)))) + (.format (time-fmt) (-> ms + from-long + (plus time-zone-offset)))) (defn timestamp->date-key [ms] (keyword (unparse (formatter "YYYYMMDD") (-> ms @@ -116,9 +108,9 @@ (plus time-zone-offset))))) (defn timestamp->long-date [ms] - (.format date-time-fmt (-> ms - from-long - (plus time-zone-offset)))) + (.format (date-time-fmt) (-> ms + from-long + (plus time-zone-offset)))) (defn format-time-ago [diff unit] (let [name (label-pluralize diff (:name unit))] diff --git a/test/cljs/status_im/test/utils/datetime.cljs b/test/cljs/status_im/test/utils/datetime.cljs index 933d667d9f..cc0e8a97fd 100644 --- a/test/cljs/status_im/test/utils/datetime.cljs +++ b/test/cljs/status_im/test/utils/datetime.cljs @@ -1,10 +1,12 @@ (ns status-im.test.utils.datetime (:require [cljs.test :refer-macros [deftest is]] [status-im.utils.datetime :as d] + [status-im.goog.i18n-module :as i18n-module] + [status-im.goog.i18n :as i18n] [cljs-time.core :as t])) (defn match [name symbols] - (is (identical? (.-dateTimeSymbols_ (d/mk-fmt name d/medium-date-format)) + (is (identical? (.-dateTimeSymbols_ (i18n-module/mk-fmt name d/medium-date-format)) symbols))) (deftest date-time-formatter-test @@ -22,68 +24,68 @@ (def epoch-plus-3d 172800000) (deftest is24Hour-locale-en-test - (is (= (d/is24Hour-locsym (d/locale-symbols "en")) false))) + (is (= (d/is24Hour-locsym (i18n/locale-symbols "en")) false))) (deftest is24Hour-locale-it-test - (is (= (d/is24Hour-locsym (d/locale-symbols "it")) true))) + (is (= (d/is24Hour-locsym (i18n/locale-symbols "it")) true))) (deftest is24Hour-locale-nb-test - (is (= (d/is24Hour-locsym (d/locale-symbols "nb-NO")) true))) + (is (= (d/is24Hour-locsym (i18n/locale-symbols "nb-NO")) true))) (deftest to-short-str-today-test (with-redefs [t/*ms-fn* (constantly epoch-plus-3d) - d/time-fmt (d/mk-fmt "us" d/short-time-format) + d/time-fmt (fn [] (i18n-module/mk-fmt "us" d/short-time-format)) d/time-zone-offset (t/period :hours 0)] (is (= (d/to-short-str epoch-plus-3d) "12:00 AM")))) #_((deftest to-short-str-today-force-24H-test (with-redefs [t/*ms-fn* (constantly epoch-plus-3d) d/is24Hour (constantly true) - d/time-fmt (d/mk-fmt "us" d/short-time-format) + d/time-fmt (i18n-module/mk-fmt "us" d/short-time-format) d/time-zone-offset (t/period :hours 0)] (is (= (d/to-short-str epoch-plus-3d) "00:00")))) (deftest to-short-str-today-force-AMPM-test (with-redefs [t/*ms-fn* (constantly epoch-plus-3d) d/is24Hour (constantly false) - d/time-fmt (d/mk-fmt "it" d/short-time-format) + d/time-fmt (i18n-module/mk-fmt "it" d/short-time-format) d/time-zone-offset (t/period :hours 0)] (is (= (d/to-short-str epoch-plus-3d) "12:00 AM"))))) (deftest to-short-str-before-yesterday-us-test (with-redefs [t/*ms-fn* (constantly epoch-plus-3d) d/time-zone-offset (t/period :hours 0) - d/date-fmt (d/mk-fmt "us" d/medium-date-format)] + d/date-fmt (fn [] (i18n-module/mk-fmt "us" d/medium-date-format))] (is (= (d/to-short-str epoch) "Jan 1, 1970")))) (deftest to-short-str-before-yesterday-nb-test (with-redefs [d/time-zone-offset (t/period :hours 0) - d/date-fmt (d/mk-fmt "nb-NO" d/medium-date-format) + d/date-fmt (fn [] (i18n-module/mk-fmt "nb-NO" d/medium-date-format)) t/*ms-fn* (constantly epoch-plus-3d)] (is (= (d/to-short-str epoch) "1. jan. 1970")))) (deftest day-relative-before-yesterday-us-test (with-redefs [t/*ms-fn* (constantly epoch-plus-3d) d/time-zone-offset (t/period :hours 0) - d/date-fmt (d/mk-fmt "us" d/medium-date-time-format)] + d/date-fmt (fn [] (i18n-module/mk-fmt "us" d/medium-date-time-format))] (is (= (d/day-relative epoch) "Jan 1, 1970, 12:00:00 AM")))) (deftest day-relative-before-yesterday-nb-test (with-redefs [t/*ms-fn* (constantly epoch-plus-3d) d/time-zone-offset (t/period :hours 0) - d/date-fmt (d/mk-fmt "nb-NO" d/medium-date-time-format)] + d/date-fmt (fn [] (i18n-module/mk-fmt "nb-NO" d/medium-date-time-format))] (is (= (d/day-relative epoch) "1. jan. 1970, 00:00:00")))) #_((deftest day-relative-before-yesterday-force-24H-test (with-redefs [t/*ms-fn* (constantly epoch-plus-3d) d/is24Hour (constantly true) d/time-zone-offset (t/period :hours 0) - d/date-fmt (d/mk-fmt "us" d/medium-date-time-format)] + d/date-fmt (i18n-module/mk-fmt "us" d/medium-date-time-format)] (is (= (d/day-relative epoch) "Jan 1, 1970, 00:00:00")))) (deftest day-relative-before-yesterday-force-AMPM-test (with-redefs [t/*ms-fn* (constantly epoch-plus-3d) d/is24Hour (constantly false) d/time-zone-offset (t/period :hours 0) - d/date-fmt (d/mk-fmt "it" d/medium-date-time-format)] + d/date-fmt (i18n-module/mk-fmt "it" d/medium-date-time-format)] (is (= (d/day-relative epoch) "01 gen 1970, 12:00:00 AM")))))