[perf] Move translation to node_modules in release build
This commit is contained in:
parent
4f125aec43
commit
632bbf3bc1
|
@ -163,3 +163,6 @@ conan.cmake
|
||||||
# nix
|
# nix
|
||||||
/.ran-setup
|
/.ran-setup
|
||||||
/.nix-gcroots/
|
/.nix-gcroots/
|
||||||
|
|
||||||
|
#modules
|
||||||
|
status-modules/translations
|
||||||
|
|
8
Makefile
8
Makefile
|
@ -65,6 +65,8 @@ release: release-android release-ios ##@build build release for Android and iOS
|
||||||
release-android: export TARGET_OS ?= android
|
release-android: export TARGET_OS ?= android
|
||||||
release-android: ##@build build release for Android
|
release-android: ##@build build release for Android
|
||||||
@$(MAKE) prod-build-android && \
|
@$(MAKE) prod-build-android && \
|
||||||
|
cp -R translations status-modules/translations && \
|
||||||
|
cp -R status-modules node_modules/status-modules && \
|
||||||
react-native run-android --variant=release
|
react-native run-android --variant=release
|
||||||
|
|
||||||
release-ios: export TARGET_OS ?= ios
|
release-ios: export TARGET_OS ?= ios
|
||||||
|
@ -72,16 +74,22 @@ release-ios: ##@build build release for iOS release
|
||||||
# Open XCode inside the Nix context
|
# Open XCode inside the Nix context
|
||||||
@$(MAKE) prod-build-ios && \
|
@$(MAKE) prod-build-ios && \
|
||||||
echo "Build in XCode, see https://status.im/build_status/ for instructions" && \
|
echo "Build in XCode, see https://status.im/build_status/ for instructions" && \
|
||||||
|
cp -R translations status-modules/translations && \
|
||||||
|
cp -R status-modules node_modules/status-modules && \
|
||||||
open ios/StatusIm.xcworkspace
|
open ios/StatusIm.xcworkspace
|
||||||
|
|
||||||
release-desktop: export TARGET_OS ?= $(HOST_OS)
|
release-desktop: export TARGET_OS ?= $(HOST_OS)
|
||||||
release-desktop: ##@build build release for desktop release
|
release-desktop: ##@build build release for desktop release
|
||||||
@$(MAKE) prod-build-desktop && \
|
@$(MAKE) prod-build-desktop && \
|
||||||
|
cp -R translations status-modules/translations && \
|
||||||
|
cp -R status-modules node_modules/status-modules && \
|
||||||
scripts/build-desktop.sh
|
scripts/build-desktop.sh
|
||||||
|
|
||||||
release-windows-desktop: export TARGET_OS ?= windows
|
release-windows-desktop: export TARGET_OS ?= windows
|
||||||
release-windows-desktop: ##@build build release for desktop release
|
release-windows-desktop: ##@build build release for desktop release
|
||||||
@$(MAKE) prod-build-desktop && \
|
@$(MAKE) prod-build-desktop && \
|
||||||
|
cp -R translations status-modules/translations && \
|
||||||
|
cp -R status-modules node_modules/status-modules && \
|
||||||
scripts/build-desktop.sh
|
scripts/build-desktop.sh
|
||||||
|
|
||||||
prod-build: export TARGET_OS ?= all
|
prod-build: export TARGET_OS ?= all
|
||||||
|
|
|
@ -234,7 +234,7 @@
|
||||||
|
|
||||||
(defn hawk-handler-translations
|
(defn hawk-handler-translations
|
||||||
[ctx e]
|
[ctx e]
|
||||||
(let [path "src/status_im/i18n.cljs"
|
(let [path "dev/status_im/i18n_resources.cljs"
|
||||||
i18n (slurp path)]
|
i18n (slurp path)]
|
||||||
(spit path (str i18n " ;;"))
|
(spit path (str i18n " ;;"))
|
||||||
(spit path i18n))
|
(spit path i18n))
|
||||||
|
|
|
@ -71,6 +71,7 @@ def prep(type = 'nightly') {
|
||||||
}
|
}
|
||||||
/* node deps, pods, and status-go download */
|
/* node deps, pods, and status-go download */
|
||||||
utils.nix.shell("scripts/prepare-for-platform.sh ${prepareTarget}", pure: false)
|
utils.nix.shell("scripts/prepare-for-platform.sh ${prepareTarget}", pure: false)
|
||||||
|
sh("cp -R translations status-modules/translations && cp -R status-modules node_modules/status-modules")
|
||||||
}
|
}
|
||||||
|
|
||||||
return this
|
return this
|
||||||
|
|
|
@ -98,7 +98,7 @@
|
||||||
"cider.piggieback/wrap-cljs-repl"]}
|
"cider.piggieback/wrap-cljs-repl"]}
|
||||||
|
|
||||||
:builds [{:id :desktop
|
:builds [{:id :desktop
|
||||||
:source-paths ["react-native/src/desktop" "src" "env/dev" "components/src"]
|
:source-paths ["react-native/src/desktop" "src" "env/dev" "components/src" "dev"]
|
||||||
:compiler {:output-to "target/desktop/app.js"
|
:compiler {:output-to "target/desktop/app.js"
|
||||||
:main "env.desktop.main"
|
:main "env.desktop.main"
|
||||||
:output-dir "target/desktop"
|
:output-dir "target/desktop"
|
||||||
|
@ -106,7 +106,7 @@
|
||||||
:optimizations :none}
|
:optimizations :none}
|
||||||
:figwheel true}
|
:figwheel true}
|
||||||
{:id :ios
|
{:id :ios
|
||||||
:source-paths ["react-native/src/mobile" "src" "env/dev" "components/src"]
|
:source-paths ["react-native/src/mobile" "src" "env/dev" "components/src" "dev"]
|
||||||
:compiler {:output-to "target/ios/app.js"
|
:compiler {:output-to "target/ios/app.js"
|
||||||
:main "env.ios.main"
|
:main "env.ios.main"
|
||||||
:output-dir "target/ios"
|
:output-dir "target/ios"
|
||||||
|
@ -114,7 +114,7 @@
|
||||||
:optimizations :none}
|
:optimizations :none}
|
||||||
:figwheel true}
|
:figwheel true}
|
||||||
{:id :android
|
{:id :android
|
||||||
:source-paths ["react-native/src/mobile" "src" "env/dev" "components/src"]
|
:source-paths ["react-native/src/mobile" "src" "env/dev" "components/src" "dev"]
|
||||||
:compiler {:output-to "target/android/app.js"
|
:compiler {:output-to "target/android/app.js"
|
||||||
:main "env.android.main"
|
:main "env.android.main"
|
||||||
:output-dir "target/android"
|
:output-dir "target/android"
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
(ns status-im.i18n-resources
|
||||||
|
(:require-macros [status-im.i18n :as i18n])
|
||||||
|
(:require [status-im.react-native.js-dependencies :as rn-dependencies]
|
||||||
|
[status-im.utils.types :as types]
|
||||||
|
[clojure.string :as string]))
|
||||||
|
|
||||||
|
(def default-device-language
|
||||||
|
(keyword (.-language rn-dependencies/react-native-languages)))
|
||||||
|
|
||||||
|
;; translations
|
||||||
|
(def translations-by-locale
|
||||||
|
(->> (i18n/translations [:en :es_419 :fa :ko :ms :pl :ru :zh_Hans_CN])
|
||||||
|
(map (fn [[k t]]
|
||||||
|
(let [k' (-> (name k)
|
||||||
|
(string/replace "_" "-")
|
||||||
|
keyword)]
|
||||||
|
[k' (types/json->clj t)])))
|
||||||
|
(into {})))
|
||||||
|
|
||||||
|
;; API compatibility
|
||||||
|
(defn load-language [lang])
|
|
@ -0,0 +1,49 @@
|
||||||
|
(ns status-im.i18n-resources
|
||||||
|
(:require-macros [status-im.utils.js-require :as js-require])
|
||||||
|
(:require [status-im.react-native.js-dependencies :as rn-dependencies]))
|
||||||
|
|
||||||
|
(def default-device-language
|
||||||
|
(keyword (.-language rn-dependencies/react-native-languages)))
|
||||||
|
|
||||||
|
(def languages [:en :es_419 :fa :ko :ms :pl :ru :zh_Hans_CN])
|
||||||
|
|
||||||
|
(defonce loaded-languages
|
||||||
|
(atom
|
||||||
|
(conj #{:en} default-device-language)))
|
||||||
|
|
||||||
|
(def prod-translations
|
||||||
|
{:en (js-require/js-require "status-modules/translations/en.json")
|
||||||
|
:es_419 (js-require/js-require "status-modules/translations/es_419.json")
|
||||||
|
:fa (js-require/js-require "status-modules/translations/fa.json")
|
||||||
|
:ko (js-require/js-require "status-modules/translations/ko.json")
|
||||||
|
:ms (js-require/js-require "status-modules/translations/ms.json")
|
||||||
|
:pl (js-require/js-require "status-modules/translations/pl.json")
|
||||||
|
:ru (js-require/js-require "status-modules/translations/ru.json")
|
||||||
|
:zh_Hans_CN (js-require/js-require "status-modules/translations/zh_Hans_CN.json")})
|
||||||
|
|
||||||
|
(defn valid-language [lang]
|
||||||
|
(if (contains? prod-translations lang)
|
||||||
|
lang
|
||||||
|
(let [short-lang (keyword (subs (name lang) 0 2))]
|
||||||
|
(when (contains? prod-translations short-lang)
|
||||||
|
short-lang))))
|
||||||
|
|
||||||
|
(defn require-translation [lang-key]
|
||||||
|
(when-let [lang (valid-language lang-key)]
|
||||||
|
((get prod-translations lang))))
|
||||||
|
|
||||||
|
;; translations
|
||||||
|
(def translations-by-locale
|
||||||
|
(cond->
|
||||||
|
{:en (require-translation :en)}
|
||||||
|
(not= :en default-device-language)
|
||||||
|
(assoc default-device-language
|
||||||
|
(require-translation default-device-language))))
|
||||||
|
|
||||||
|
(defn load-language [lang]
|
||||||
|
(let [lang-key (valid-language (keyword lang))]
|
||||||
|
(when-not (contains? @loaded-languages lang-key)
|
||||||
|
(aset (.-translations rn-dependencies/i18n)
|
||||||
|
lang
|
||||||
|
(require-translation lang-key))
|
||||||
|
(swap! loaded-languages conj lang-key))))
|
20
project.clj
20
project.clj
|
@ -50,20 +50,20 @@
|
||||||
:profiles {:dev {:dependencies [[cider/piggieback "0.4.0"]]
|
:profiles {:dev {:dependencies [[cider/piggieback "0.4.0"]]
|
||||||
:cljsbuild {:builds
|
:cljsbuild {:builds
|
||||||
{:ios
|
{:ios
|
||||||
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/mobile" "src"]
|
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/mobile" "src" "dev"]
|
||||||
:compiler {:output-to "target/ios/app.js"
|
:compiler {:output-to "target/ios/app.js"
|
||||||
:main "env.ios.main"
|
:main "env.ios.main"
|
||||||
:output-dir "target/ios"
|
:output-dir "target/ios"
|
||||||
:optimizations :none}}
|
:optimizations :none}}
|
||||||
:android
|
:android
|
||||||
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/mobile" "src"]
|
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/mobile" "src" "dev"]
|
||||||
:compiler {:output-to "target/android/app.js"
|
:compiler {:output-to "target/android/app.js"
|
||||||
:main "env.android.main"
|
:main "env.android.main"
|
||||||
:output-dir "target/android"
|
:output-dir "target/android"
|
||||||
:optimizations :none}
|
:optimizations :none}
|
||||||
:warning-handlers [status-im.utils.build/warning-handler]}
|
:warning-handlers [status-im.utils.build/warning-handler]}
|
||||||
:desktop
|
:desktop
|
||||||
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/desktop" "src"]
|
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/desktop" "src" "dev"]
|
||||||
:compiler {:output-to "target/desktop/app.js"
|
:compiler {:output-to "target/desktop/app.js"
|
||||||
:main "env.desktop.main"
|
:main "env.desktop.main"
|
||||||
:output-dir "target/desktop"
|
:output-dir "target/desktop"
|
||||||
|
@ -76,12 +76,12 @@
|
||||||
[re-frisk-sidecar "0.5.7"]
|
[re-frisk-sidecar "0.5.7"]
|
||||||
[day8.re-frame/tracing "0.5.0"]
|
[day8.re-frame/tracing "0.5.0"]
|
||||||
[hawk "0.2.11"]]
|
[hawk "0.2.11"]]
|
||||||
:source-paths ["src" "env/dev" "react-native/src/cljsjs" "components/src"]}]
|
:source-paths ["src" "env/dev" "react-native/src/cljsjs" "components/src" "dev"]}]
|
||||||
:test {:dependencies [[day8.re-frame/test "0.1.5"]]
|
:test {:dependencies [[day8.re-frame/test "0.1.5"]]
|
||||||
:plugins [[lein-doo "0.1.9"]]
|
:plugins [[lein-doo "0.1.9"]]
|
||||||
:cljsbuild {:builds
|
:cljsbuild {:builds
|
||||||
[{:id "test"
|
[{:id "test"
|
||||||
:source-paths ["components/src" "src" "test/cljs"]
|
:source-paths ["components/src" "src" "test/cljs" "dev"]
|
||||||
:compiler {:main status-im.test.runner
|
:compiler {:main status-im.test.runner
|
||||||
:output-to "target/test/test.js"
|
:output-to "target/test/test.js"
|
||||||
:output-dir "target/test"
|
:output-dir "target/test"
|
||||||
|
@ -89,7 +89,7 @@
|
||||||
:preamble ["js/hook-require.js"]
|
:preamble ["js/hook-require.js"]
|
||||||
:target :nodejs}}
|
:target :nodejs}}
|
||||||
{:id "protocol"
|
{:id "protocol"
|
||||||
:source-paths ["components/src" "src" "test/cljs"]
|
:source-paths ["components/src" "src" "test/cljs" "dev"]
|
||||||
:compiler {:main status-im.test.protocol.runner
|
:compiler {:main status-im.test.protocol.runner
|
||||||
:output-to "target/test/test.js"
|
:output-to "target/test/test.js"
|
||||||
:output-dir "target/test"
|
:output-dir "target/test"
|
||||||
|
@ -97,7 +97,7 @@
|
||||||
:preamble ["js/hook-require.js"]
|
:preamble ["js/hook-require.js"]
|
||||||
:target :nodejs}}
|
:target :nodejs}}
|
||||||
{:id "env-dev-utils"
|
{:id "env-dev-utils"
|
||||||
:source-paths ["env/dev/env/utils.cljs" "test/env/dev"]
|
:source-paths ["env/dev/env/utils.cljs" "test/env/dev" "dev"]
|
||||||
:compiler {:main env.test.runner
|
:compiler {:main env.test.runner
|
||||||
:output-to "target/test/test.js"
|
:output-to "target/test/test.js"
|
||||||
:output-dir "target/test"
|
:output-dir "target/test"
|
||||||
|
@ -105,7 +105,7 @@
|
||||||
:target :nodejs}}]}}
|
:target :nodejs}}]}}
|
||||||
:prod {:cljsbuild {:builds
|
:prod {:cljsbuild {:builds
|
||||||
{:ios
|
{:ios
|
||||||
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/mobile" "src" "env/prod"]
|
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/mobile" "src" "env/prod" "prod"]
|
||||||
:compiler {:output-to "index.ios.js"
|
:compiler {:output-to "index.ios.js"
|
||||||
:main "env.ios.main"
|
:main "env.ios.main"
|
||||||
:output-dir "target/ios-prod"
|
:output-dir "target/ios-prod"
|
||||||
|
@ -122,7 +122,7 @@
|
||||||
:language-in :ecmascript5}
|
:language-in :ecmascript5}
|
||||||
:warning-handlers [status-im.utils.build/warning-handler]}
|
:warning-handlers [status-im.utils.build/warning-handler]}
|
||||||
:android
|
:android
|
||||||
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/mobile" "src" "env/prod"]
|
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/mobile" "src" "env/prod" "prod"]
|
||||||
:compiler {:output-to "index.android.js"
|
:compiler {:output-to "index.android.js"
|
||||||
:main "env.android.main"
|
:main "env.android.main"
|
||||||
:output-dir "target/android-prod"
|
:output-dir "target/android-prod"
|
||||||
|
@ -139,7 +139,7 @@
|
||||||
:language-in :ecmascript5}
|
:language-in :ecmascript5}
|
||||||
:warning-handlers [status-im.utils.build/warning-handler]}
|
:warning-handlers [status-im.utils.build/warning-handler]}
|
||||||
:desktop
|
:desktop
|
||||||
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/desktop" "src" "env/prod"]
|
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/desktop" "src" "env/prod" "prod"]
|
||||||
:compiler {:output-to "index.desktop.js"
|
:compiler {:output-to "index.desktop.js"
|
||||||
:main "env.desktop.main"
|
:main "env.desktop.main"
|
||||||
:output-dir "target/desktop-prod"
|
:output-dir "target/desktop-prod"
|
||||||
|
|
|
@ -9,17 +9,16 @@
|
||||||
[status-im.ui.screens.views :as views]
|
[status-im.ui.screens.views :as views]
|
||||||
[status-im.ui.components.react :as react]
|
[status-im.ui.components.react :as react]
|
||||||
[status-im.native-module.core :as status]
|
[status-im.native-module.core :as status]
|
||||||
[status-im.notifications.core :as notifications]
|
|
||||||
[status-im.core :as core]
|
[status-im.core :as core]
|
||||||
[status-im.react-native.js-dependencies :as rn-dependencies]
|
[status-im.react-native.js-dependencies :as rn-dependencies]
|
||||||
[status-im.utils.snoopy :as snoopy]
|
[status-im.utils.snoopy :as snoopy]
|
||||||
[taoensso.timbre :as log]))
|
[status-im.i18n :as i18n]))
|
||||||
|
|
||||||
(defn app-state-change-handler [state]
|
(defn app-state-change-handler [state]
|
||||||
(dispatch [:app-state-change state]))
|
(dispatch [:app-state-change state]))
|
||||||
|
|
||||||
(defn on-languages-change [event]
|
(defn on-languages-change [event]
|
||||||
(set! (.-locale rn-dependencies/i18n) (.-language event)))
|
(i18n/set-language (.-language event)))
|
||||||
|
|
||||||
(defn on-shake []
|
(defn on-shake []
|
||||||
(dispatch [:shake-event]))
|
(dispatch [:shake-event]))
|
||||||
|
|
|
@ -1,232 +1,19 @@
|
||||||
(ns status-im.i18n
|
(ns status-im.i18n
|
||||||
(:require-macros [status-im.i18n :as i18n])
|
|
||||||
(:require
|
(:require
|
||||||
[cljs.spec.alpha :as spec]
|
|
||||||
[status-im.react-native.js-dependencies :as rn-dependencies]
|
[status-im.react-native.js-dependencies :as rn-dependencies]
|
||||||
[clojure.string :as string]
|
[clojure.string :as string]
|
||||||
[clojure.set :as set]
|
[status-im.i18n-resources :as i18n-resources]))
|
||||||
[status-im.utils.types :as types]))
|
|
||||||
|
|
||||||
(set! (.-locale rn-dependencies/i18n) (.-language rn-dependencies/react-native-languages))
|
(set! (.-locale rn-dependencies/i18n) (name i18n-resources/default-device-language))
|
||||||
(set! (.-fallbacks rn-dependencies/i18n) true)
|
(set! (.-fallbacks rn-dependencies/i18n) true)
|
||||||
(set! (.-defaultSeparator rn-dependencies/i18n) "/")
|
(set! (.-defaultSeparator rn-dependencies/i18n) "/")
|
||||||
|
|
||||||
;; translations
|
|
||||||
(def translations-by-locale
|
|
||||||
(->> (i18n/translations [:en :es_419 :fa :ko :ms :pl :ru :zh_Hans_CN])
|
|
||||||
(map (fn [[k t]]
|
|
||||||
(let [k' (-> (name k)
|
|
||||||
(string/replace "_" "-")
|
|
||||||
keyword)]
|
|
||||||
[k' (types/json->clj t)])))
|
|
||||||
(into {})))
|
|
||||||
|
|
||||||
;; english as source of truth
|
|
||||||
(def labels (set (keys (:en translations-by-locale))))
|
|
||||||
|
|
||||||
(spec/def ::label labels)
|
|
||||||
(spec/def ::labels (spec/coll-of ::label :kind set? :into #{}))
|
|
||||||
|
|
||||||
(defn labels-for-all-locales []
|
|
||||||
(->> translations-by-locale
|
|
||||||
(mapcat #(-> % val keys))
|
|
||||||
set))
|
|
||||||
|
|
||||||
;; checkpoints
|
|
||||||
|
|
||||||
;; Checkpoints specify milestones for locales.
|
|
||||||
;;
|
|
||||||
;; With milestones we can ensure that expected supported languages
|
|
||||||
;; are actually supported, and visualize the translation state for
|
|
||||||
;; the rest of locales according to these milestones.
|
|
||||||
;;
|
|
||||||
;; Checkpoints are defined by indicating the labels that need to be present
|
|
||||||
;; in a locale to achieve that checkpoint.
|
|
||||||
;;
|
|
||||||
;; We need to define the checkpoint that needs to be achieved for
|
|
||||||
;; a locale to be considered supported. This is why as we develop
|
|
||||||
;; we add translations, so we need to be defining a new target
|
|
||||||
;; for supported languages to achieve.
|
|
||||||
;;
|
|
||||||
;; Checkpoints are only used in dev and test. In dev when we want to
|
|
||||||
;; manually check the state of checkpoints for locales, and in test
|
|
||||||
;; to automatically check supported locales against the target checkpoint.
|
|
||||||
|
|
||||||
(spec/def ::checkpoint.id keyword?)
|
|
||||||
(spec/def ::checkpoint-defs (spec/map-of ::checkpoint.id ::labels))
|
|
||||||
|
|
||||||
;; We define here the labels for the first specified checkpoint.
|
|
||||||
(def checkpoint-0-9-12-labels
|
|
||||||
#{:validation-amount-invalid-number :transaction-details :confirm :description
|
|
||||||
:phone-national :amount :open :close-app-title :members-active :chat-name
|
|
||||||
:phew-here-is-your-passphrase :public-group-topic :debug-enabled
|
|
||||||
:chat-settings :offline :update-status :invited :chat-send-eth :address
|
|
||||||
:new-public-group-chat :datetime-hour :wallet-settings
|
|
||||||
:datetime-ago-format :close-app-button :block :camera-access-error
|
|
||||||
:wallet-invalid-address :wallet-invalid-address-checksum :address-explication :remove
|
|
||||||
:transactions-delete-content :transactions-unsigned-empty
|
|
||||||
:transaction-moved-text :add-members :sign-later-title
|
|
||||||
:yes :dapps :popular-tags :network-settings :twelve-words-in-correct-order
|
|
||||||
:transaction-moved-title :photos-access-error :hash
|
|
||||||
:removed-from-chat :done :remove-from-contacts :delete-chat :new-group-chat
|
|
||||||
:edit-chats :wallet :wallet-exchange :wallet-request :sign-in
|
|
||||||
:datetime-yesterday :create-new-account :sign-in-to-status :save-password :save-password-unavailable :dapp-profile
|
|
||||||
:sign-later-text :datetime-ago :no-hashtags-discovered-body :contacts
|
|
||||||
:search-chat :got-it :delete-group-confirmation :public-chats
|
|
||||||
:not-applicable :move-to-internal-failure-message :active-online
|
|
||||||
:password :status-seen-by-everyone :edit-group :not-specified
|
|
||||||
:delete-group :send-request :paste-json :browsing-title
|
|
||||||
:wallet-add-asset :reorder-groups :transactions-history-empty :discover
|
|
||||||
:browsing-cancel :faucet-success :intro-status :name :gas-price
|
|
||||||
:view-transaction-details :wallet-error
|
|
||||||
:validation-amount-is-too-precise :copy-transaction-hash :unknown-address
|
|
||||||
:received-invitation :show-qr :edit-network-config :connect
|
|
||||||
:choose-from-contacts :edit :wallet-address-from-clipboard
|
|
||||||
:account-generation-message :remove-network :no-messages :passphrase
|
|
||||||
:recipient :members-title :new-group :suggestions-requests
|
|
||||||
:connected :rpc-url :settings :remove-from-group :specify-rpc-url
|
|
||||||
:transactions-sign-all :gas-limit :wallet-browse-photos
|
|
||||||
:add-new-contact :no-statuses-discovered-body :add-json-file :delete
|
|
||||||
:search-contacts :chats :transaction-sent :transaction :public-group-status
|
|
||||||
:leave-chat :transactions-delete :mainnet-text :image-source-make-photo
|
|
||||||
:chat :start-conversation :topic-format :add-new-network :save
|
|
||||||
:enter-valid-public-key :faucet-error :all
|
|
||||||
:confirmations-helper-text :search-for :sharing-copy-to-clipboard
|
|
||||||
:your-wallets :sync-in-progress :enter-password
|
|
||||||
:enter-address :switch-users :send-transaction :confirmations
|
|
||||||
:recover-access :image-source-gallery :sync-synced
|
|
||||||
:currency :status-pending :delete-contact :connecting-requires-login
|
|
||||||
:no-hashtags-discovered-title :datetime-day :request-transaction
|
|
||||||
:wallet-send :mute-notifications :scan-qr :contact-s
|
|
||||||
:unsigned-transaction-expired :status-sending :gas-used
|
|
||||||
:transactions-filter-type :next :recent
|
|
||||||
:open-on-etherscan :share :status :from
|
|
||||||
:wrong-password :search-chats :transactions-sign-later :in-contacts
|
|
||||||
:transactions-sign :sharing-share :type-a-message
|
|
||||||
:usd-currency :existing-networks :node-unavailable :url :shake-your-phone
|
|
||||||
:add-network :unknown-status-go-error :contacts-group-new-chat :and-you
|
|
||||||
:wallets :clear-history :wallet-choose-from-contacts
|
|
||||||
:signing-phrase-description :no-contacts :here-is-your-signing-phrase
|
|
||||||
:soon :close-app-content :status-sent :status-prompt
|
|
||||||
:delete-contact-confirmation :datetime-today :add-a-status
|
|
||||||
:web-view-error :notifications-title :error :transactions-sign-transaction
|
|
||||||
:edit-contacts :more :cancel :no-statuses-found :can-not-add-yourself
|
|
||||||
:transaction-description :add-to-contacts :available
|
|
||||||
:paste-json-as-text :You :main-wallet :process-json :testnet-text
|
|
||||||
:transactions :transactions-unsigned :members :intro-message1
|
|
||||||
:public-chat-user-count :eth :transactions-history :not-implemented
|
|
||||||
:new-contact :datetime-second :status-failed :is-typing :recover
|
|
||||||
:suggestions-commands :nonce :new-network :contact-already-added :datetime-minute
|
|
||||||
:browsing-open-in-ios-web-browser :browsing-open-in-android-web-browser
|
|
||||||
:delete-group-prompt :wallet-total-value
|
|
||||||
:wallet-insufficient-funds :edit-profile :active-unknown
|
|
||||||
:search-tags :transaction-failed :public-key :error-processing-json
|
|
||||||
:status-seen :transactions-filter-tokens :status-delivered :profile
|
|
||||||
:wallet-choose-recipient :no-statuses-discovered :none :removed :empty-topic
|
|
||||||
:no :transactions-filter-select-all :transactions-filter-title :message
|
|
||||||
:here-is-your-passphrase :wallet-assets :image-source-title :current-network
|
|
||||||
:left :edit-network-warning :to :data :cost-fee})
|
|
||||||
|
|
||||||
;; NOTE: the rest checkpoints are based on the previous one, defined
|
|
||||||
;; like this:
|
|
||||||
;; (def checkpoint-2-labels (set/union checkpoint-1-labels #{:foo :bar})
|
|
||||||
;; (def checkpoint-3-labels (set/union checkpoint-2-labels #{:baz})
|
|
||||||
|
|
||||||
;; NOTE: This defines the scope of each checkpoint. To support a checkpoint,
|
|
||||||
;; change the var `checkpoint-to-consider-locale-supported` a few lines
|
|
||||||
;; below.
|
|
||||||
(def checkpoints-def (spec/assert ::checkpoint-defs
|
|
||||||
{::checkpoint-0-9-12 checkpoint-0-9-12-labels}))
|
|
||||||
(def checkpoints (set (keys checkpoints-def)))
|
|
||||||
|
|
||||||
(spec/def ::checkpoint checkpoints)
|
|
||||||
|
|
||||||
(def checkpoint-to-consider-locale-supported ::checkpoint-0-9-12)
|
|
||||||
|
|
||||||
(defn checkpoint->labels [checkpoint]
|
|
||||||
(get checkpoints-def checkpoint))
|
|
||||||
|
|
||||||
(defn checkpoint-val-to-compare [c]
|
|
||||||
(-> c name (string/replace #"^.*\|" "") int))
|
|
||||||
|
|
||||||
(defn >checkpoints [& cs]
|
|
||||||
(apply > (map checkpoint-val-to-compare cs)))
|
|
||||||
|
|
||||||
(defn labels-that-are-not-in-current-checkpoint []
|
|
||||||
(set/difference labels (checkpoint->labels checkpoint-to-consider-locale-supported)))
|
|
||||||
|
|
||||||
;; locales
|
|
||||||
|
|
||||||
(def locales (set (keys translations-by-locale)))
|
|
||||||
|
|
||||||
(spec/def ::locale locales)
|
|
||||||
(spec/def ::locales (spec/coll-of ::locale :kind set? :into #{}))
|
|
||||||
|
|
||||||
;; NOTE: Add new locale keywords here to indicate support for them.
|
|
||||||
#_(def supported-locales (spec/assert ::locales #{:fr
|
|
||||||
:zh
|
|
||||||
:zh-hans
|
|
||||||
:zh-hans-cn
|
|
||||||
:zh-hans-mo
|
|
||||||
:zh-hant
|
|
||||||
:zh-hant-sg
|
|
||||||
:zh-hant-hk
|
|
||||||
:zh-hant-tw
|
|
||||||
:zh-hant-mo
|
|
||||||
:zh-hant-cn
|
|
||||||
:sr-RS_#Cyrl
|
|
||||||
:el
|
|
||||||
:en
|
|
||||||
:de
|
|
||||||
:lt
|
|
||||||
:sr-RS_#Latn
|
|
||||||
:sr
|
|
||||||
:sv
|
|
||||||
:ja
|
|
||||||
:uk}))
|
|
||||||
(def supported-locales (spec/assert ::locales #{:en}))
|
|
||||||
|
|
||||||
(spec/def ::supported-locale supported-locales)
|
|
||||||
(spec/def ::supported-locales (spec/coll-of ::supported-locale :kind set? :into #{}))
|
|
||||||
|
|
||||||
(defn locale->labels [locale]
|
|
||||||
(-> translations-by-locale (get locale) keys set))
|
|
||||||
|
|
||||||
(defn locale->checkpoint [locale]
|
|
||||||
(let [locale-labels (locale->labels locale)
|
|
||||||
checkpoint (->> checkpoints-def
|
|
||||||
(filter (fn [[checkpoint checkpoint-labels]]
|
|
||||||
(set/subset? checkpoint-labels locale-labels)))
|
|
||||||
ffirst)]
|
|
||||||
checkpoint))
|
|
||||||
|
|
||||||
(defn locales-with-checkpoint []
|
|
||||||
(->> locales
|
|
||||||
(map (fn [locale]
|
|
||||||
[locale (locale->checkpoint locale)]))
|
|
||||||
(into {})))
|
|
||||||
|
|
||||||
(defn locale-is-supported-based-on-translations? [locale]
|
|
||||||
(let [c (locale->checkpoint locale)]
|
|
||||||
(and c (or (= c checkpoint-to-consider-locale-supported)
|
|
||||||
(>checkpoints checkpoint-to-consider-locale-supported c)))))
|
|
||||||
|
|
||||||
(defn actual-supported-locales []
|
|
||||||
(->> locales
|
|
||||||
(filter locale-is-supported-based-on-translations?)
|
|
||||||
set))
|
|
||||||
|
|
||||||
(defn locales-with-full-support []
|
|
||||||
(->> locales
|
|
||||||
(filter (fn [locale]
|
|
||||||
(set/subset? labels (locale->labels locale))))
|
|
||||||
set))
|
|
||||||
|
|
||||||
(defn supported-locales-that-are-not-considered-supported []
|
|
||||||
(set/difference (actual-supported-locales) supported-locales))
|
|
||||||
|
|
||||||
(set! (.-translations rn-dependencies/i18n)
|
(set! (.-translations rn-dependencies/i18n)
|
||||||
(clj->js translations-by-locale))
|
(clj->js i18n-resources/translations-by-locale))
|
||||||
|
|
||||||
|
(defn set-language [lang]
|
||||||
|
(i18n-resources/load-language lang)
|
||||||
|
(set! (.-locale rn-dependencies/i18n) lang))
|
||||||
|
|
||||||
;;:zh, :zh-hans-xx, :zh-hant-xx have been added until this bug will be fixed https://github.com/fnando/i18n-js/issues/460
|
;;:zh, :zh-hans-xx, :zh-hant-xx have been added until this bug will be fixed https://github.com/fnando/i18n-js/issues/460
|
||||||
|
|
||||||
|
|
|
@ -9,15 +9,15 @@
|
||||||
[status-im.react-native.js-dependencies :as rn-dependencies]
|
[status-im.react-native.js-dependencies :as rn-dependencies]
|
||||||
[status-im.ui.screens.views :as views]
|
[status-im.ui.screens.views :as views]
|
||||||
[status-im.ui.components.react :as react]
|
[status-im.ui.components.react :as react]
|
||||||
[status-im.notifications.core :as notifications]
|
|
||||||
[status-im.core :as core]
|
[status-im.core :as core]
|
||||||
[status-im.utils.snoopy :as snoopy]))
|
[status-im.utils.snoopy :as snoopy]
|
||||||
|
[status-im.i18n :as i18n]))
|
||||||
|
|
||||||
(defn app-state-change-handler [state]
|
(defn app-state-change-handler [state]
|
||||||
(dispatch [:app-state-change state]))
|
(dispatch [:app-state-change state]))
|
||||||
|
|
||||||
(defn on-languages-change [event]
|
(defn on-languages-change [event]
|
||||||
(set! (.-locale rn-dependencies/i18n) (.-language event)))
|
(i18n/set-language (.-language event)))
|
||||||
|
|
||||||
(defn on-shake []
|
(defn on-shake []
|
||||||
(dispatch [:shake-event]))
|
(dispatch [:shake-event]))
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"name": "status-modules",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"files": []
|
||||||
|
}
|
|
@ -1,29 +1,217 @@
|
||||||
(ns status-im.test.i18n
|
(ns status-im.test.i18n
|
||||||
(:require [cljs.test :refer-macros [deftest is]]
|
(:require [cljs.test :refer-macros [deftest is]]
|
||||||
[status-im.i18n :as i18n]
|
[status-im.i18n :as i18n]
|
||||||
|
[status-im.i18n-resources :as i18n-resources]
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
[cljs.spec.alpha :as spec]))
|
[cljs.spec.alpha :as spec]
|
||||||
|
[clojure.string :as string]))
|
||||||
|
|
||||||
|
;; english as source of truth
|
||||||
|
(def labels (set (keys (:en i18n-resources/translations-by-locale))))
|
||||||
|
|
||||||
|
(spec/def ::label labels)
|
||||||
|
(spec/def ::labels (spec/coll-of ::label :kind set? :into #{}))
|
||||||
|
|
||||||
|
(defn labels-for-all-locales []
|
||||||
|
(->> i18n-resources/translations-by-locale
|
||||||
|
(mapcat #(-> % val keys))
|
||||||
|
set))
|
||||||
|
|
||||||
|
;; checkpoints
|
||||||
|
|
||||||
|
;; Checkpoints specify milestones for locales.
|
||||||
|
;;
|
||||||
|
;; With milestones we can ensure that expected supported languages
|
||||||
|
;; are actually supported, and visualize the translation state for
|
||||||
|
;; the rest of locales according to these milestones.
|
||||||
|
;;
|
||||||
|
;; Checkpoints are defined by indicating the labels that need to be present
|
||||||
|
;; in a locale to achieve that checkpoint.
|
||||||
|
;;
|
||||||
|
;; We need to define the checkpoint that needs to be achieved for
|
||||||
|
;; a locale to be considered supported. This is why as we develop
|
||||||
|
;; we add translations, so we need to be defining a new target
|
||||||
|
;; for supported languages to achieve.
|
||||||
|
;;
|
||||||
|
;; Checkpoints are only used in dev and test. In dev when we want to
|
||||||
|
;; manually check the state of checkpoints for locales, and in test
|
||||||
|
;; to automatically check supported locales against the target checkpoint.
|
||||||
|
|
||||||
|
(spec/def ::checkpoint.id keyword?)
|
||||||
|
(spec/def ::checkpoint-defs (spec/map-of ::checkpoint.id ::labels))
|
||||||
|
|
||||||
|
;; We define here the labels for the first specified checkpoint.
|
||||||
|
(def checkpoint-0-9-12-labels
|
||||||
|
#{:validation-amount-invalid-number :transaction-details :confirm :description
|
||||||
|
:phone-national :amount :open :close-app-title :members-active :chat-name
|
||||||
|
:phew-here-is-your-passphrase :public-group-topic :debug-enabled
|
||||||
|
:chat-settings :offline :update-status :invited :chat-send-eth :address
|
||||||
|
:new-public-group-chat :datetime-hour :wallet-settings
|
||||||
|
:datetime-ago-format :close-app-button :block :camera-access-error
|
||||||
|
:wallet-invalid-address :wallet-invalid-address-checksum :address-explication :remove
|
||||||
|
:transactions-delete-content :transactions-unsigned-empty
|
||||||
|
:transaction-moved-text :add-members :sign-later-title
|
||||||
|
:yes :dapps :popular-tags :network-settings :twelve-words-in-correct-order
|
||||||
|
:transaction-moved-title :photos-access-error :hash
|
||||||
|
:removed-from-chat :done :remove-from-contacts :delete-chat :new-group-chat
|
||||||
|
:edit-chats :wallet :wallet-exchange :wallet-request :sign-in
|
||||||
|
:datetime-yesterday :create-new-account :sign-in-to-status :save-password :save-password-unavailable :dapp-profile
|
||||||
|
:sign-later-text :datetime-ago :no-hashtags-discovered-body :contacts
|
||||||
|
:search-chat :got-it :delete-group-confirmation :public-chats
|
||||||
|
:not-applicable :move-to-internal-failure-message :active-online
|
||||||
|
:password :status-seen-by-everyone :edit-group :not-specified
|
||||||
|
:delete-group :send-request :paste-json :browsing-title
|
||||||
|
:wallet-add-asset :reorder-groups :transactions-history-empty :discover
|
||||||
|
:browsing-cancel :faucet-success :intro-status :name :gas-price
|
||||||
|
:view-transaction-details :wallet-error
|
||||||
|
:validation-amount-is-too-precise :copy-transaction-hash :unknown-address
|
||||||
|
:received-invitation :show-qr :edit-network-config :connect
|
||||||
|
:choose-from-contacts :edit :wallet-address-from-clipboard
|
||||||
|
:account-generation-message :remove-network :no-messages :passphrase
|
||||||
|
:recipient :members-title :new-group :suggestions-requests
|
||||||
|
:connected :rpc-url :settings :remove-from-group :specify-rpc-url
|
||||||
|
:transactions-sign-all :gas-limit :wallet-browse-photos
|
||||||
|
:add-new-contact :no-statuses-discovered-body :add-json-file :delete
|
||||||
|
:search-contacts :chats :transaction-sent :transaction :public-group-status
|
||||||
|
:leave-chat :transactions-delete :mainnet-text :image-source-make-photo
|
||||||
|
:chat :start-conversation :topic-format :add-new-network :save
|
||||||
|
:enter-valid-public-key :faucet-error :all
|
||||||
|
:confirmations-helper-text :search-for :sharing-copy-to-clipboard
|
||||||
|
:your-wallets :sync-in-progress :enter-password
|
||||||
|
:enter-address :switch-users :send-transaction :confirmations
|
||||||
|
:recover-access :image-source-gallery :sync-synced
|
||||||
|
:currency :status-pending :delete-contact :connecting-requires-login
|
||||||
|
:no-hashtags-discovered-title :datetime-day :request-transaction
|
||||||
|
:wallet-send :mute-notifications :scan-qr :contact-s
|
||||||
|
:unsigned-transaction-expired :status-sending :gas-used
|
||||||
|
:transactions-filter-type :next :recent
|
||||||
|
:open-on-etherscan :share :status :from
|
||||||
|
:wrong-password :search-chats :transactions-sign-later :in-contacts
|
||||||
|
:transactions-sign :sharing-share :type-a-message
|
||||||
|
:usd-currency :existing-networks :node-unavailable :url :shake-your-phone
|
||||||
|
:add-network :unknown-status-go-error :contacts-group-new-chat :and-you
|
||||||
|
:wallets :clear-history :wallet-choose-from-contacts
|
||||||
|
:signing-phrase-description :no-contacts :here-is-your-signing-phrase
|
||||||
|
:soon :close-app-content :status-sent :status-prompt
|
||||||
|
:delete-contact-confirmation :datetime-today :add-a-status
|
||||||
|
:web-view-error :notifications-title :error :transactions-sign-transaction
|
||||||
|
:edit-contacts :more :cancel :no-statuses-found :can-not-add-yourself
|
||||||
|
:transaction-description :add-to-contacts :available
|
||||||
|
:paste-json-as-text :You :main-wallet :process-json :testnet-text
|
||||||
|
:transactions :transactions-unsigned :members :intro-message1
|
||||||
|
:public-chat-user-count :eth :transactions-history :not-implemented
|
||||||
|
:new-contact :datetime-second :status-failed :is-typing :recover
|
||||||
|
:suggestions-commands :nonce :new-network :contact-already-added :datetime-minute
|
||||||
|
:browsing-open-in-ios-web-browser :browsing-open-in-android-web-browser
|
||||||
|
:delete-group-prompt :wallet-total-value
|
||||||
|
:wallet-insufficient-funds :edit-profile :active-unknown
|
||||||
|
:search-tags :transaction-failed :public-key :error-processing-json
|
||||||
|
:status-seen :transactions-filter-tokens :status-delivered :profile
|
||||||
|
:wallet-choose-recipient :no-statuses-discovered :none :removed :empty-topic
|
||||||
|
:no :transactions-filter-select-all :transactions-filter-title :message
|
||||||
|
:here-is-your-passphrase :wallet-assets :image-source-title :current-network
|
||||||
|
:left :edit-network-warning :to :data :cost-fee})
|
||||||
|
|
||||||
|
;; NOTE: the rest checkpoints are based on the previous one, defined
|
||||||
|
;; like this:
|
||||||
|
;; (def checkpoint-2-labels (set/union checkpoint-1-labels #{:foo :bar})
|
||||||
|
;; (def checkpoint-3-labels (set/union checkpoint-2-labels #{:baz})
|
||||||
|
|
||||||
|
;; NOTE: This defines the scope of each checkpoint. To support a checkpoint,
|
||||||
|
;; change the var `checkpoint-to-consider-locale-supported` a few lines
|
||||||
|
;; below.
|
||||||
|
(def checkpoints-def (spec/assert ::checkpoint-defs
|
||||||
|
{::checkpoint-0-9-12 checkpoint-0-9-12-labels}))
|
||||||
|
(def checkpoints (set (keys checkpoints-def)))
|
||||||
|
|
||||||
|
(spec/def ::checkpoint checkpoints)
|
||||||
|
|
||||||
|
(def checkpoint-to-consider-locale-supported ::checkpoint-0-9-12)
|
||||||
|
|
||||||
|
(defn checkpoint->labels [checkpoint]
|
||||||
|
(get checkpoints-def checkpoint))
|
||||||
|
|
||||||
|
(defn checkpoint-val-to-compare [c]
|
||||||
|
(-> c name (string/replace #"^.*\|" "") int))
|
||||||
|
|
||||||
|
(defn >checkpoints [& cs]
|
||||||
|
(apply > (map checkpoint-val-to-compare cs)))
|
||||||
|
|
||||||
|
;; locales
|
||||||
|
|
||||||
|
(def locales (set (keys i18n-resources/translations-by-locale)))
|
||||||
|
|
||||||
|
(spec/def ::locale locales)
|
||||||
|
(spec/def ::locales (spec/coll-of ::locale :kind set? :into #{}))
|
||||||
|
|
||||||
|
(defn locale->labels [locale]
|
||||||
|
(-> i18n-resources/translations-by-locale (get locale) keys set))
|
||||||
|
|
||||||
|
(defn locale->checkpoint [locale]
|
||||||
|
(let [locale-labels (locale->labels locale)
|
||||||
|
checkpoint (->> checkpoints-def
|
||||||
|
(filter (fn [[checkpoint checkpoint-labels]]
|
||||||
|
(set/subset? checkpoint-labels locale-labels)))
|
||||||
|
ffirst)]
|
||||||
|
checkpoint))
|
||||||
|
|
||||||
|
(defn locale-is-supported-based-on-translations? [locale]
|
||||||
|
(let [c (locale->checkpoint locale)]
|
||||||
|
(and c (or (= c checkpoint-to-consider-locale-supported)
|
||||||
|
(>checkpoints checkpoint-to-consider-locale-supported c)))))
|
||||||
|
|
||||||
|
(defn actual-supported-locales []
|
||||||
|
(->> locales
|
||||||
|
(filter locale-is-supported-based-on-translations?)
|
||||||
|
set))
|
||||||
|
|
||||||
|
;; NOTE: Add new locale keywords here to indicate support for them.
|
||||||
|
#_(def supported-locales (spec/assert ::locales #{:fr
|
||||||
|
:zh
|
||||||
|
:zh-hans
|
||||||
|
:zh-hans-cn
|
||||||
|
:zh-hans-mo
|
||||||
|
:zh-hant
|
||||||
|
:zh-hant-sg
|
||||||
|
:zh-hant-hk
|
||||||
|
:zh-hant-tw
|
||||||
|
:zh-hant-mo
|
||||||
|
:zh-hant-cn
|
||||||
|
:sr-RS_#Cyrl
|
||||||
|
:el
|
||||||
|
:en
|
||||||
|
:de
|
||||||
|
:lt
|
||||||
|
:sr-RS_#Latn
|
||||||
|
:sr
|
||||||
|
:sv
|
||||||
|
:ja
|
||||||
|
:uk}))
|
||||||
|
(def supported-locales (spec/assert ::locales #{:en}))
|
||||||
|
|
||||||
|
(spec/def ::supported-locale supported-locales)
|
||||||
|
(spec/def ::supported-locales (spec/coll-of ::supported-locale :kind set? :into #{}))
|
||||||
|
|
||||||
(deftest label-options
|
(deftest label-options
|
||||||
(is (not (nil? (:key (i18n/label-options {:key nil}))))))
|
(is (not (nil? (:key (i18n/label-options {:key nil}))))))
|
||||||
|
|
||||||
(deftest locales-only-have-existing-tran-ids
|
(deftest locales-only-have-existing-tran-ids
|
||||||
(is (spec/valid? ::i18n/labels (i18n/labels-for-all-locales))
|
(is (spec/valid? ::labels (labels-for-all-locales))
|
||||||
(->> i18n/locales
|
(->> locales
|
||||||
(remove #(spec/valid? ::i18n/labels (i18n/locale->labels %)))
|
(remove #(spec/valid? ::labels (locale->labels %)))
|
||||||
(map (fn [l]
|
(map (fn [l]
|
||||||
(str "Extra translations in locale " l "\n"
|
(str "Extra translations in locale " l "\n"
|
||||||
(set/difference (i18n/locale->labels l) i18n/labels)
|
(set/difference (locale->labels l) labels)
|
||||||
"\n\n")))
|
"\n\n")))
|
||||||
(apply str))))
|
(apply str))))
|
||||||
|
|
||||||
(deftest supported-locales-are-actually-supported
|
(deftest supported-locales-are-actually-supported
|
||||||
(is (set/subset? i18n/supported-locales (i18n/actual-supported-locales))
|
(is (set/subset? supported-locales (actual-supported-locales))
|
||||||
(->> i18n/supported-locales
|
(->> supported-locales
|
||||||
(remove i18n/locale-is-supported-based-on-translations?)
|
(remove locale-is-supported-based-on-translations?)
|
||||||
(map (fn [l]
|
(map (fn [l]
|
||||||
(str "Missing translations in supported locale " l "\n"
|
(str "Missing translations in supported locale " l "\n"
|
||||||
(set/difference (i18n/checkpoint->labels i18n/checkpoint-to-consider-locale-supported)
|
(set/difference (checkpoint->labels checkpoint-to-consider-locale-supported)
|
||||||
(i18n/locale->labels l))
|
(locale->labels l))
|
||||||
"\n\n")))
|
"\n\n")))
|
||||||
(apply str))))
|
(apply str))))
|
||||||
|
|
Loading…
Reference in New Issue