feat(wallet): Add account name, emoji and color validation (#20422)
* Fix extra `0` in create/edit account title input * Validate name, color and emoji in account creation/edition screen * Refactor sub * Fix button disabled condition and placeholder
This commit is contained in:
parent
e9f98fcf85
commit
f192648518
|
@ -13,7 +13,7 @@
|
|||
{:value ""
|
||||
:max-length 24}])
|
||||
(h/fire-event :on-focus (h/query-by-label-text :profile-title-input))
|
||||
(-> (h/wait-for #(h/get-by-text "00"))
|
||||
(-> (h/wait-for #(h/get-by-text "0"))
|
||||
(.then #(h/is-truthy (h/query-by-text "/24")))))
|
||||
|
||||
(h/test "renders with max length digits and character count"
|
||||
|
@ -22,7 +22,7 @@
|
|||
:max-length 24}
|
||||
"abc"])
|
||||
(h/fire-event :on-focus (h/query-by-label-text :profile-title-input))
|
||||
(-> (h/wait-for #(h/get-by-text "03"))
|
||||
(-> (h/wait-for #(h/get-by-text "3"))
|
||||
(.then #(h/is-truthy (h/query-by-text "/24")))))
|
||||
|
||||
(h/test "text updates on change"
|
||||
|
|
|
@ -71,9 +71,7 @@
|
|||
[text/text
|
||||
{:style (style/char-count blur? theme)
|
||||
:size :paragraph-2}
|
||||
(pad-0
|
||||
(str
|
||||
(count value)))]
|
||||
(str (count value))]
|
||||
[text/text
|
||||
{:style (style/char-count blur? theme)
|
||||
:size :paragraph-2}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
(ns status-im.contexts.wallet.account.edit-account.view
|
||||
(:require [quo.core :as quo]
|
||||
(:require [clojure.string :as string]
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.contexts.wallet.account.edit-account.style :as style]
|
||||
[status-im.contexts.wallet.common.screen-base.create-or-edit-account.view
|
||||
:as create-or-edit-account]
|
||||
[status-im.contexts.wallet.common.utils :as common.utils]
|
||||
[status-im.contexts.wallet.sheets.network-preferences.view
|
||||
:as network-preferences]
|
||||
[status-im.contexts.wallet.sheets.remove-account.view :as remove-account]
|
||||
|
@ -35,6 +37,8 @@
|
|||
(defn view
|
||||
[]
|
||||
(let [edited-account-name (reagent/atom nil)
|
||||
name-error (reagent/atom nil)
|
||||
emoji-color-error (reagent/atom nil)
|
||||
on-change-color (fn [edited-color {:keys [color] :as account}]
|
||||
(when (not= edited-color color)
|
||||
(save-account {:account account
|
||||
|
@ -55,12 +59,16 @@
|
|||
:as account} (rf/sub [:wallet/current-viewing-account])
|
||||
network-details (rf/sub [:wallet/network-preference-details])
|
||||
test-networks-enabled? (rf/sub [:profile/test-networks-enabled?])
|
||||
other-account-names (rf/sub [:wallet/accounts-names-without-current-account])
|
||||
other-emojis-and-colors (rf/sub [:wallet/accounts-emojis-and-colors-without-current-account])
|
||||
network-preferences-key (if test-networks-enabled?
|
||||
:test-preferred-chain-ids
|
||||
:prod-preferred-chain-ids)
|
||||
account-name (or @edited-account-name name)
|
||||
button-disabled? (or (nil? @edited-account-name)
|
||||
(= name @edited-account-name))]
|
||||
input-error (or @emoji-color-error @name-error)
|
||||
button-disabled? (or (string/blank? @edited-account-name)
|
||||
(= name @edited-account-name)
|
||||
(some? input-error))]
|
||||
[create-or-edit-account/view
|
||||
{:page-nav-right-side [(when-not default-account?
|
||||
{:icon-name :i/delete
|
||||
|
@ -69,16 +77,32 @@
|
|||
(fn []
|
||||
[remove-account/view])}])})]
|
||||
:account-name account-name
|
||||
:placeholder (i18n/label :t/default-account-placeholder)
|
||||
:account-emoji emoji
|
||||
:account-color color
|
||||
:on-change-name #(reset! edited-account-name %)
|
||||
:on-change-color #(on-change-color % account)
|
||||
:on-change-emoji #(on-change-emoji % account)
|
||||
:on-change-name (fn [new-name]
|
||||
(reset! edited-account-name new-name)
|
||||
(reset! name-error (common.utils/get-account-name-error
|
||||
@edited-account-name
|
||||
other-account-names)))
|
||||
:on-change-color (fn [new-color]
|
||||
(if (other-emojis-and-colors [emoji new-color])
|
||||
(reset! emoji-color-error :emoji-and-color)
|
||||
(do
|
||||
(reset! emoji-color-error nil)
|
||||
(on-change-color new-color account))))
|
||||
:on-change-emoji (fn [new-emoji]
|
||||
(if (other-emojis-and-colors [new-emoji color])
|
||||
(reset! emoji-color-error :emoji-and-color)
|
||||
(do
|
||||
(reset! emoji-color-error nil)
|
||||
(on-change-emoji new-emoji account))))
|
||||
:section-label :t/account-info
|
||||
:bottom-action-label :t/confirm
|
||||
:bottom-action-props {:customization-color color
|
||||
:disabled? button-disabled?
|
||||
:on-press #(on-confirm-name account)}}
|
||||
:on-press #(on-confirm-name account)}
|
||||
:error input-error}
|
||||
[quo/data-item
|
||||
{:status :default
|
||||
:size :default
|
||||
|
|
|
@ -9,7 +9,9 @@
|
|||
(h/test "Create Account button is disabled while no account name exists"
|
||||
(h/setup-subs {:wallet/watch-only-accounts []
|
||||
:alert-banners/top-margin 0
|
||||
:get-screen-params {:address "0xmock-address"}})
|
||||
:get-screen-params {:address "0xmock-address"}
|
||||
:wallet/accounts-names #{"My account 1" "My account 2"}
|
||||
:wallet/accounts-emojis-and-colors #{["😊" :sky] ["😶" :army]}})
|
||||
(h/render [confirm-address/view])
|
||||
(h/is-truthy (h/get-by-text "0xmock-address"))
|
||||
(h/is-disabled (h/get-by-label-text :confirm-button-label))))
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
[status-im.contexts.wallet.add-account.add-address-to-watch.confirm-address.style :as style]
|
||||
[status-im.contexts.wallet.common.screen-base.create-or-edit-account.view :as
|
||||
create-or-edit-account]
|
||||
[status-im.contexts.wallet.common.utils :as common.utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
|
@ -19,10 +20,29 @@
|
|||
account-name (reagent/atom "")
|
||||
account-color (reagent/atom (rand-nth colors/account-colors))
|
||||
account-emoji (reagent/atom (emoji-picker.utils/random-emoji))
|
||||
on-change-name #(reset! account-name %)
|
||||
on-change-color #(reset! account-color %)
|
||||
on-change-emoji #(reset! account-emoji %)]
|
||||
name-error (reagent/atom nil)
|
||||
emoji-color-error (reagent/atom nil)]
|
||||
(fn []
|
||||
(let [accounts-names (rf/sub [:wallet/accounts-names])
|
||||
accounts-emojis-and-colors (rf/sub [:wallet/accounts-emojis-and-colors])
|
||||
on-change-name (fn [new-name]
|
||||
(reset! account-name new-name)
|
||||
(reset! name-error (common.utils/get-account-name-error
|
||||
@account-name
|
||||
accounts-names)))
|
||||
on-change-color (fn [new-color]
|
||||
(reset! account-color new-color)
|
||||
(reset! emoji-color-error
|
||||
(when (accounts-emojis-and-colors
|
||||
[@account-emoji @account-color])
|
||||
:emoji-and-color)))
|
||||
on-change-emoji (fn [new-emoji]
|
||||
(reset! account-emoji new-emoji)
|
||||
(reset! emoji-color-error
|
||||
(when (accounts-emojis-and-colors
|
||||
[@account-emoji @account-color])
|
||||
:emoji-and-color)))
|
||||
input-error (or @emoji-color-error @name-error)]
|
||||
[rn/view {:style style/container}
|
||||
[create-or-edit-account/view
|
||||
{:placeholder placeholder
|
||||
|
@ -33,9 +53,11 @@
|
|||
:on-change-color on-change-color
|
||||
:on-change-emoji on-change-emoji
|
||||
:watch-only? true
|
||||
:error input-error
|
||||
:bottom-action-label :t/add-watched-address
|
||||
:bottom-action-props {:customization-color @account-color
|
||||
:disabled? (string/blank? @account-name)
|
||||
:disabled? (or (string/blank? @account-name)
|
||||
(some? input-error))
|
||||
:accessibility-label :confirm-button-label
|
||||
:on-press #(rf/dispatch [:wallet/add-account
|
||||
{:type :watch
|
||||
|
@ -58,4 +80,4 @@
|
|||
;; https://github.com/status-im/status-mobile/issues/17009
|
||||
:weight :monospace}
|
||||
address])
|
||||
:container-style style/data-item}]]])))
|
||||
:container-style style/data-item}]]]))))
|
||||
|
|
|
@ -11,10 +11,11 @@
|
|||
:bottom 0
|
||||
:left 80})
|
||||
|
||||
(def title-input-container
|
||||
(defn title-input-container
|
||||
[error?]
|
||||
{:padding-horizontal 20
|
||||
:padding-top 12
|
||||
:padding-bottom 16})
|
||||
:padding-bottom (if error? 8 16)})
|
||||
|
||||
(def color-picker-container
|
||||
{:padding-vertical 12})
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
[status-im.common.standard-authentication.core :as standard-auth]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.add-account.create-account.style :as style]
|
||||
[status-im.contexts.wallet.common.utils :as common.utils]
|
||||
[status-im.contexts.wallet.sheets.account-origin.view :as account-origin]
|
||||
[status-im.feature-flags :as ff]
|
||||
[utils.i18n :as i18n]
|
||||
|
@ -74,7 +75,8 @@
|
|||
(defn- input
|
||||
[_]
|
||||
(let [placeholder (i18n/label :t/default-account-placeholder)]
|
||||
(fn [{:keys [account-color account-name on-change-text]}]
|
||||
(fn [{:keys [account-color account-name on-change-text error]}]
|
||||
[rn/view
|
||||
[quo/title-input
|
||||
{:customization-color account-color
|
||||
:placeholder placeholder
|
||||
|
@ -83,7 +85,20 @@
|
|||
:blur? true
|
||||
:disabled? false
|
||||
:default-value account-name
|
||||
:container-style style/title-input-container}])))
|
||||
:container-style (style/title-input-container error)}]
|
||||
(when error
|
||||
[quo/info-message
|
||||
{:type :error
|
||||
:size :default
|
||||
:icon :i/info
|
||||
:container-style {:margin-left 20
|
||||
:margin-bottom 16}}
|
||||
(case error
|
||||
:emoji (i18n/label :t/key-name-error-emoji)
|
||||
:special-character (i18n/label :t/key-name-error-special-char)
|
||||
:existing-name (i18n/label :t/name-must-differ-error)
|
||||
:emoji-and-color (i18n/label :t/emoji-and-colors-unique-error)
|
||||
nil)])])))
|
||||
|
||||
(defn- color-picker
|
||||
[_]
|
||||
|
@ -154,9 +169,7 @@
|
|||
children))))
|
||||
|
||||
(defn add-new-keypair-variant
|
||||
[{:keys [on-change-text set-account-color set-emoji]
|
||||
{:keys [account-name account-color emoji]}
|
||||
:state}]
|
||||
[{{:keys [account-name account-color emoji]} :state}]
|
||||
(let [on-auth-success (fn [password]
|
||||
(rf/dispatch
|
||||
[:wallet/import-and-create-keypair-with-account
|
||||
|
@ -164,7 +177,7 @@
|
|||
:account-preferences {:account-name @account-name
|
||||
:color @account-color
|
||||
:emoji @emoji}}]))]
|
||||
(fn [{:keys [customization-color keypair-name]}]
|
||||
(fn [{:keys [on-change-text set-account-color set-emoji customization-color keypair-name error]}]
|
||||
(let [{:keys [new-account-data]} (rf/sub [:wallet/create-account-new-keypair])]
|
||||
[floating-button
|
||||
{:account-color @account-color
|
||||
|
@ -178,7 +191,8 @@
|
|||
[input
|
||||
{:account-color @account-color
|
||||
:account-name @account-name
|
||||
:on-change-text on-change-text}]
|
||||
:on-change-text on-change-text
|
||||
:error error}]
|
||||
[color-picker
|
||||
{:account-color @account-color
|
||||
:set-account-color set-account-color}]
|
||||
|
@ -188,12 +202,10 @@
|
|||
:keypair-title keypair-name}]]))))
|
||||
|
||||
(defn derive-account-variant
|
||||
[{:keys [on-change-text set-account-color set-emoji]
|
||||
{:keys [account-name account-color emoji]}
|
||||
:state}]
|
||||
[{{:keys [account-name account-color emoji]} :state}]
|
||||
(let [derivation-path (reagent/atom "")
|
||||
set-derivation-path #(reset! derivation-path %)]
|
||||
(fn [{:keys [customization-color]}]
|
||||
(fn [{:keys [on-change-text set-account-color set-emoji customization-color error]}]
|
||||
(let [{:keys [derived-from
|
||||
key-uid]} (rf/sub [:wallet/selected-keypair])
|
||||
on-auth-success (rn/use-callback
|
||||
|
@ -219,7 +231,8 @@
|
|||
{:account-color @account-color
|
||||
:slide-button-props {:on-auth-success on-auth-success
|
||||
:disabled? (or (empty? @account-name)
|
||||
(= "" @derivation-path))}}
|
||||
(= "" @derivation-path)
|
||||
(some? error))}}
|
||||
[avatar
|
||||
{:account-color @account-color
|
||||
:emoji @emoji
|
||||
|
@ -227,7 +240,8 @@
|
|||
[input
|
||||
{:account-color @account-color
|
||||
:account-name @account-name
|
||||
:on-change-text on-change-text}]
|
||||
:on-change-text on-change-text
|
||||
:error error}]
|
||||
[color-picker
|
||||
{:account-color @account-color
|
||||
:set-account-color set-account-color}]
|
||||
|
@ -236,34 +250,62 @@
|
|||
:customization-color customization-color}]]))))
|
||||
|
||||
(defn view
|
||||
[_]
|
||||
[]
|
||||
(let [account-name (reagent/atom "")
|
||||
account-color (reagent/atom (rand-nth colors/account-colors))
|
||||
emoji (reagent/atom (emoji-picker.utils/random-emoji))
|
||||
on-change-text #(reset! account-name %)
|
||||
set-account-color #(reset! account-color %)
|
||||
set-emoji #(reset! emoji %)
|
||||
account-name-error (reagent/atom nil)
|
||||
emoji-and-color-error? (reagent/atom false)
|
||||
state {:account-name account-name
|
||||
:account-color account-color
|
||||
:emoji emoji}]
|
||||
:emoji emoji
|
||||
:account-name-error account-name-error
|
||||
:emoji-and-color-error? emoji-and-color-error?}]
|
||||
(fn []
|
||||
(let [customization-color (rf/sub [:profile/customization-color])
|
||||
;; Having a keypair means the user is importing it or creating it.
|
||||
{:keys [keypair-name]} (rf/sub [:wallet/create-account-new-keypair])]
|
||||
{:keys [keypair-name]} (rf/sub [:wallet/create-account-new-keypair])
|
||||
accounts-names (rf/sub [:wallet/accounts-names])
|
||||
accounts-emojis-and-colors (rf/sub [:wallet/accounts-emojis-and-colors])
|
||||
on-change-text (rn/use-callback
|
||||
(fn [new-text]
|
||||
(reset! account-name new-text)
|
||||
(reset! account-name-error
|
||||
(common.utils/get-account-name-error new-text
|
||||
accounts-names)))
|
||||
[accounts-names accounts-emojis-and-colors])
|
||||
check-emoji-and-color-error (fn [emoji color]
|
||||
(let [repeated? (accounts-emojis-and-colors [emoji color])]
|
||||
(reset! emoji-and-color-error?
|
||||
(when repeated? :emoji-and-color))))
|
||||
set-account-color (rn/use-callback
|
||||
(fn [new-color]
|
||||
(reset! account-color new-color)
|
||||
(check-emoji-and-color-error @emoji new-color))
|
||||
[accounts-emojis-and-colors @emoji])
|
||||
set-emoji (rn/use-callback
|
||||
(fn [new-emoji]
|
||||
(reset! emoji new-emoji)
|
||||
(check-emoji-and-color-error new-emoji @account-color))
|
||||
[accounts-emojis-and-colors @account-color])
|
||||
error (or @account-name-error @emoji-and-color-error?)]
|
||||
|
||||
(rn/use-mount #(check-emoji-and-color-error @emoji @account-color))
|
||||
(rn/use-unmount #(rf/dispatch [:wallet/clear-create-account]))
|
||||
|
||||
(if keypair-name
|
||||
[add-new-keypair-variant
|
||||
{:customization-color customization-color
|
||||
{:state state
|
||||
:customization-color customization-color
|
||||
:on-change-text on-change-text
|
||||
:set-account-color set-account-color
|
||||
:set-emoji set-emoji
|
||||
:state state
|
||||
:keypair-name keypair-name}]
|
||||
:keypair-name keypair-name
|
||||
:error error}]
|
||||
[derive-account-variant
|
||||
{:customization-color customization-color
|
||||
{:state state
|
||||
:customization-color customization-color
|
||||
:on-change-text on-change-text
|
||||
:set-account-color set-account-color
|
||||
:set-emoji set-emoji
|
||||
:state state}])))))
|
||||
:error error}])))))
|
||||
|
|
|
@ -15,14 +15,11 @@
|
|||
:bottom 0
|
||||
:left 76})
|
||||
|
||||
(def title-input-container
|
||||
(defn title-input-container
|
||||
[error?]
|
||||
{:padding-horizontal 20
|
||||
:padding-top 12
|
||||
:padding-bottom 16})
|
||||
|
||||
(def error-container
|
||||
{:margin-horizontal 20
|
||||
:margin-bottom 16})
|
||||
:padding-bottom (if error? 8 16)})
|
||||
|
||||
(def divider-1
|
||||
{:margin-bottom 12})
|
||||
|
|
|
@ -11,11 +11,9 @@
|
|||
|
||||
(defn view
|
||||
[{:keys [page-nav-right-side placeholder account-name account-color account-emoji
|
||||
on-change-name
|
||||
on-change-color
|
||||
on-change-emoji section-label
|
||||
bottom-action-label bottom-action-props
|
||||
custom-bottom-action watch-only?]} & children]
|
||||
on-change-name on-change-color on-change-emoji section-label bottom-action-label
|
||||
bottom-action-props custom-bottom-action watch-only? error]}
|
||||
& children]
|
||||
(let [{window-width :width} (rn/get-window)
|
||||
footer (if custom-bottom-action
|
||||
custom-bottom-action
|
||||
|
@ -52,6 +50,8 @@
|
|||
:on-press #(rf/dispatch [:emoji-picker/open {:on-select on-change-emoji}])
|
||||
:container-style style/reaction-button-container}
|
||||
:i/reaction]]
|
||||
|
||||
[rn/view
|
||||
[quo/title-input
|
||||
{:placeholder placeholder
|
||||
:max-length constants/wallet-account-name-max-length
|
||||
|
@ -59,7 +59,21 @@
|
|||
:default-value account-name
|
||||
:auto-focus true
|
||||
:on-change-text on-change-name
|
||||
:container-style style/title-input-container}]
|
||||
:container-style (style/title-input-container error)}]
|
||||
(when error
|
||||
[quo/info-message
|
||||
{:type :error
|
||||
:size :default
|
||||
:icon :i/info
|
||||
:container-style {:margin-left 20
|
||||
:margin-bottom 16}}
|
||||
(case error
|
||||
:emoji (i18n/label :t/key-name-error-emoji)
|
||||
:special-character (i18n/label :t/key-name-error-special-char)
|
||||
:existing-name (i18n/label :t/name-must-differ-error)
|
||||
:emoji-and-color (i18n/label :t/emoji-and-colors-unique-error)
|
||||
nil)])]
|
||||
|
||||
[quo/divider-line {:container-style style/divider-1}]
|
||||
[quo/section-label
|
||||
{:section (i18n/label :t/colour)
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
[status-im.common.qr-codes.view :as qr-codes]
|
||||
[status-im.constants :as constants]
|
||||
[utils.money :as money]
|
||||
[utils.number :as number]))
|
||||
[utils.number :as number]
|
||||
[utils.string]))
|
||||
|
||||
(defn get-first-name
|
||||
[full-name]
|
||||
|
@ -281,3 +282,10 @@
|
|||
(defn make-limit-label-fiat
|
||||
[amount currency-symbol]
|
||||
(str currency-symbol amount))
|
||||
|
||||
(defn get-account-name-error
|
||||
[s existing-account-names]
|
||||
(cond
|
||||
(utils.string/contains-emoji? s) :emoji
|
||||
(existing-account-names s) :existing-name
|
||||
(utils.string/contains-special-character? s) :special-character))
|
||||
|
|
|
@ -47,8 +47,7 @@
|
|||
:wallet/home-tokens-loading?
|
||||
:<- [:wallet/tokens-loading]
|
||||
(fn [tokens-loading]
|
||||
(if (empty? tokens-loading)
|
||||
true
|
||||
(or (empty? tokens-loading)
|
||||
(->> tokens-loading
|
||||
vals
|
||||
(some true?)
|
||||
|
@ -633,3 +632,34 @@
|
|||
(->> accounts
|
||||
(some #(= :partially (:operable %)))
|
||||
boolean)))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/accounts-names
|
||||
:<- [:wallet/accounts]
|
||||
(fn [accounts]
|
||||
(set (map :name accounts))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/accounts-names-without-current-account
|
||||
:<- [:wallet/accounts-names]
|
||||
:<- [:wallet/current-viewing-account]
|
||||
(fn [[account-names current-viewing-account]]
|
||||
(disj account-names (:name current-viewing-account))))
|
||||
|
||||
(defn- get-emoji-and-colors-from-accounts
|
||||
[accounts]
|
||||
(->> accounts
|
||||
(map (fn [{:keys [emoji color]}] [emoji color]))
|
||||
(set)))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/accounts-emojis-and-colors
|
||||
:<- [:wallet/accounts]
|
||||
(fn [accounts]
|
||||
(get-emoji-and-colors-from-accounts accounts)))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/accounts-emojis-and-colors-without-current-account
|
||||
:<- [:wallet/accounts-without-current-viewing-account]
|
||||
(fn [accounts]
|
||||
(get-emoji-and-colors-from-accounts accounts)))
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
(ns utils.string
|
||||
(:require
|
||||
[clojure.string :as string]))
|
||||
[clojure.string :as string]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(defn truncate-str-memo
|
||||
"Given string and max threshold, trims the string to threshold length with `...`
|
||||
|
@ -59,3 +60,16 @@
|
|||
(take n)
|
||||
(map (comp string/upper-case str first))
|
||||
string/join)))
|
||||
|
||||
(def emoji-data (transforms/js->clj (js/require "../resources/data/emojis/en.json")))
|
||||
(def emoji-unicode-values (map :unicode emoji-data))
|
||||
|
||||
(defn contains-emoji?
|
||||
[s]
|
||||
(some (fn [emoji]
|
||||
(string/includes? s emoji))
|
||||
emoji-unicode-values))
|
||||
|
||||
(defn contains-special-character?
|
||||
[s]
|
||||
(re-find #"[^a-zA-Z0-9\s]" s))
|
||||
|
|
|
@ -2639,6 +2639,8 @@
|
|||
"key-name-error-emoji": "Emojis are not allowed",
|
||||
"key-name-error-special-char": "Special characters are not allowed",
|
||||
"key-name-error-too-short": "Key pair name must be at least {{count}} characters",
|
||||
"name-must-differ-error": "Name must differ from other accounts",
|
||||
"emoji-and-colors-unique-error": "Emoji and colour combination must be unique",
|
||||
"display": "Display",
|
||||
"testnet-mode": "Testnet mode",
|
||||
"turn-on-testnet-mode": "Turn on testnet mode",
|
||||
|
|
Loading…
Reference in New Issue