mirror of
https://github.com/penpot/penpot.git
synced 2025-05-05 00:05:53 +02:00
🐛 Fix lost translation strings (#5846)
* 🐛 Fix lost translation strings * 🐛 Fix form error management internal issues and inconsistencies * 📎 Add better validation conditons for ::sm/text schema * 🐛 Add better touched detection mechanism for input and textarea --------- Co-authored-by: Andrey Antukh <niwi@niwi.nz>
This commit is contained in:
parent
6bb7fa26f4
commit
a7ed5228d3
8 changed files with 111 additions and 44 deletions
|
@ -963,7 +963,6 @@
|
||||||
{:title "string"
|
{:title "string"
|
||||||
:description "not whitespace string"
|
:description "not whitespace string"
|
||||||
:gen/gen (sg/word-string)
|
:gen/gen (sg/word-string)
|
||||||
:error/code "errors.invalid-text"
|
|
||||||
:error/fn
|
:error/fn
|
||||||
(fn [{:keys [value schema]}]
|
(fn [{:keys [value schema]}]
|
||||||
(let [{:keys [max min] :as props} (properties schema)]
|
(let [{:keys [max min] :as props} (properties schema)]
|
||||||
|
@ -971,16 +970,23 @@
|
||||||
(and (string? value)
|
(and (string? value)
|
||||||
(number? max)
|
(number? max)
|
||||||
(> (count value) max))
|
(> (count value) max))
|
||||||
["errors.field-max-length" max]
|
{:code ["errors.field-max-length" max]}
|
||||||
|
|
||||||
(and (string? value)
|
(and (string? value)
|
||||||
(number? min)
|
(number? min)
|
||||||
(< (count value) min))
|
(< (count value) min))
|
||||||
["errors.field-min-length" min]
|
{:code ["errors.field-min-length" min]}
|
||||||
|
|
||||||
|
(and (string? value)
|
||||||
|
(str/empty? value))
|
||||||
|
{:code "errors.field-missing"}
|
||||||
|
|
||||||
(and (string? value)
|
(and (string? value)
|
||||||
(str/blank? value))
|
(str/blank? value))
|
||||||
"errors.field-not-all-whitespace")))}})
|
{:code "errors.field-not-all-whitespace"}
|
||||||
|
|
||||||
|
:else
|
||||||
|
{:code "errors.invalid-text"})))}})
|
||||||
|
|
||||||
(register!
|
(register!
|
||||||
{:type ::password
|
{:type ::password
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
|
|
||||||
[:validation :email-as-password]
|
[:validation :email-as-password]
|
||||||
(swap! form assoc-in [:errors :password]
|
(swap! form assoc-in [:errors :password]
|
||||||
{:code "errors.email-as-password"})
|
{:message (tr "errors.email-as-password")})
|
||||||
|
|
||||||
(st/emit! (ntf/error (tr "errors.generic")))))))
|
(st/emit! (ntf/error (tr "errors.generic")))))))
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
more-classes (get props :class)
|
more-classes (get props :class)
|
||||||
auto-focus? (get props :auto-focus? false)
|
auto-focus? (get props :auto-focus? false)
|
||||||
|
|
||||||
|
data-testid (d/nilv data-testid input-name)
|
||||||
|
|
||||||
form (or form (mf/use-ctx form-ctx))
|
form (or form (mf/use-ctx form-ctx))
|
||||||
|
|
||||||
type' (mf/use-state input-type)
|
type' (mf/use-state input-type)
|
||||||
|
@ -45,7 +47,9 @@
|
||||||
(= @type' "email"))
|
(= @type' "email"))
|
||||||
placeholder (when is-text? (or placeholder label))
|
placeholder (when is-text? (or placeholder label))
|
||||||
|
|
||||||
touched? (get-in @form [:touched input-name])
|
touched? (and (contains? (:data @form) input-name)
|
||||||
|
(get-in @form [:touched input-name]))
|
||||||
|
|
||||||
error (get-in @form [:errors input-name])
|
error (get-in @form [:errors input-name])
|
||||||
|
|
||||||
value (get-in @form [:data input-name] "")
|
value (get-in @form [:data input-name] "")
|
||||||
|
@ -153,6 +157,14 @@
|
||||||
children])
|
children])
|
||||||
|
|
||||||
(cond
|
(cond
|
||||||
|
(and touched? (:message error) show-error)
|
||||||
|
(let [message (:message error)]
|
||||||
|
[:div {:id (dm/str "error-" input-name)
|
||||||
|
:class (stl/css :error)
|
||||||
|
:data-testid (dm/str data-testid "-error")}
|
||||||
|
message])
|
||||||
|
|
||||||
|
;; FIXME: DEPRECATED
|
||||||
(and touched? (:code error) show-error)
|
(and touched? (:code error) show-error)
|
||||||
(let [code (:code error)]
|
(let [code (:code error)]
|
||||||
[:div {:id (dm/str "error-" input-name)
|
[:div {:id (dm/str "error-" input-name)
|
||||||
|
@ -173,7 +185,9 @@
|
||||||
|
|
||||||
focus? (mf/use-state false)
|
focus? (mf/use-state false)
|
||||||
|
|
||||||
touched? (get-in @form [:touched input-name])
|
touched? (and (contains? (:data @form) input-name)
|
||||||
|
(get-in @form [:touched input-name]))
|
||||||
|
|
||||||
error (get-in @form [:errors input-name])
|
error (get-in @form [:errors input-name])
|
||||||
|
|
||||||
value (get-in @form [:data input-name] "")
|
value (get-in @form [:data input-name] "")
|
||||||
|
@ -211,6 +225,9 @@
|
||||||
[:label {:class (stl/css :textarea-label)} label]
|
[:label {:class (stl/css :textarea-label)} label]
|
||||||
[:> :textarea props]
|
[:> :textarea props]
|
||||||
(cond
|
(cond
|
||||||
|
(and touched? (:message error))
|
||||||
|
[:span {:class (stl/css :error)} (:message error)]
|
||||||
|
|
||||||
(and touched? (:code error))
|
(and touched? (:code error))
|
||||||
[:span {:class (stl/css :error)} (tr (:code error))]
|
[:span {:class (stl/css :error)} (tr (:code error))]
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@
|
||||||
[:map {:title "EmailChangeForm"}
|
[:map {:title "EmailChangeForm"}
|
||||||
[:email-1 ::sm/email]
|
[:email-1 ::sm/email]
|
||||||
[:email-2 ::sm/email]]
|
[:email-2 ::sm/email]]
|
||||||
[:fn {:error/code "errors.invalid-email-confirmation"
|
[:fn {:error/fn #(tr "errors.invalid-email-confirmation")
|
||||||
:error/field :email-2}
|
:error/field :email-2}
|
||||||
(fn [data]
|
(fn [data]
|
||||||
(let [email-1 (:email-1 data)
|
(let [email-1 (:email-1 data)
|
||||||
|
|
|
@ -21,10 +21,10 @@
|
||||||
(case (:code (ex-data error))
|
(case (:code (ex-data error))
|
||||||
:old-password-not-match
|
:old-password-not-match
|
||||||
(swap! form assoc-in [:errors :password-old]
|
(swap! form assoc-in [:errors :password-old]
|
||||||
{:code "errors.wrong-old-password"})
|
{:message (tr "errors.wrong-old-password")})
|
||||||
:email-as-password
|
:email-as-password
|
||||||
(swap! form assoc-in [:errors :password-1]
|
(swap! form assoc-in [:errors :password-1]
|
||||||
{:code "errors.email-as-password"})
|
{:message (tr "errors.email-as-password")})
|
||||||
|
|
||||||
(let [msg (tr "generic.error")]
|
(let [msg (tr "generic.error")]
|
||||||
(st/emit! (ntf/error msg)))))
|
(st/emit! (ntf/error msg)))))
|
||||||
|
|
|
@ -10,43 +10,78 @@
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
[app.util.i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[malli.core :as m]
|
[malli.core :as m]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
;; --- Handlers Helpers
|
;; --- Handlers Helpers
|
||||||
|
|
||||||
|
(defn- translate-code
|
||||||
|
[code]
|
||||||
|
(if (vector? code)
|
||||||
|
(tr (nth code 0) (i18n/c (nth code 1)))
|
||||||
|
(tr code)))
|
||||||
|
|
||||||
|
(defn- handle-error-fn
|
||||||
|
[props problem]
|
||||||
|
(let [v-fn (:error/fn props)
|
||||||
|
result (v-fn problem)]
|
||||||
|
(if (string? result)
|
||||||
|
{:message result}
|
||||||
|
{:message (or (some-> (get result :code)
|
||||||
|
(translate-code))
|
||||||
|
(get result :message)
|
||||||
|
(tr "errors.invalid-data"))})))
|
||||||
|
|
||||||
|
(defn- handle-error-message
|
||||||
|
[props]
|
||||||
|
{:message (get props :error/message)})
|
||||||
|
|
||||||
|
(defn- handle-error-code
|
||||||
|
[props]
|
||||||
|
(let [code (get props :error/code)]
|
||||||
|
{:message (translate-code code)}))
|
||||||
|
|
||||||
(defn- interpret-schema-problem
|
(defn- interpret-schema-problem
|
||||||
[acc {:keys [schema in value] :as problem}]
|
[acc {:keys [schema in value type] :as problem}]
|
||||||
(let [props (merge (m/type-properties schema)
|
(let [props (m/properties schema)
|
||||||
(m/properties schema))
|
tprops (m/type-properties schema)
|
||||||
field (or (first in) (:error/field props))]
|
field (or (first in)
|
||||||
|
(:error/field props))]
|
||||||
|
|
||||||
(if (contains? acc field)
|
(if (contains? acc field)
|
||||||
acc
|
acc
|
||||||
(cond
|
(cond
|
||||||
(nil? value)
|
(nil? field)
|
||||||
(assoc acc field {:code "errors.field-missing"})
|
acc
|
||||||
|
|
||||||
(contains? props :error/code)
|
(or (= type :malli.core/missing-key)
|
||||||
(assoc acc field {:code (:error/code props)})
|
(nil? value))
|
||||||
|
(assoc acc field {:message (tr "errors.field-missing")})
|
||||||
|
|
||||||
|
;; --- CHECK on schema props
|
||||||
|
(contains? props :error/fn)
|
||||||
|
(assoc acc field (handle-error-fn props problem))
|
||||||
|
|
||||||
(contains? props :error/message)
|
(contains? props :error/message)
|
||||||
(assoc acc field {:code (:error/message props)})
|
(assoc acc field (handle-error-message props))
|
||||||
|
|
||||||
(contains? props :error/fn)
|
(contains? props :error/code)
|
||||||
(let [v-fn (:error/fn props)
|
(assoc acc field (handle-error-code props))
|
||||||
code (v-fn problem)]
|
|
||||||
(assoc acc field {:code code}))
|
|
||||||
|
|
||||||
(contains? props :error/validators)
|
;; --- CHECK on type props
|
||||||
(let [validators (:error/validators props)
|
(contains? tprops :error/fn)
|
||||||
props (reduce #(%2 %1 value) props validators)]
|
(assoc acc field (handle-error-fn tprops problem))
|
||||||
(assoc acc field {:code (d/nilv (:error/code props) "errors.invalid-data")}))
|
|
||||||
|
(contains? tprops :error/message)
|
||||||
|
(assoc acc field (handle-error-message tprops))
|
||||||
|
|
||||||
|
(contains? tprops :error/code)
|
||||||
|
(assoc acc field (handle-error-code tprops))
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(assoc acc field {:code "errors.invalid-data"})))))
|
(assoc acc field {:message (tr "errors.invalid-data")})))))
|
||||||
|
|
||||||
(defn- use-rerender-fn
|
(defn- use-rerender-fn
|
||||||
[]
|
[]
|
||||||
|
@ -177,21 +212,6 @@
|
||||||
|
|
||||||
;; --- Helper Components
|
;; --- Helper Components
|
||||||
|
|
||||||
(mf/defc field-error
|
|
||||||
[{:keys [form field type]
|
|
||||||
:as props}]
|
|
||||||
(let [{:keys [message] :as error} (dm/get-in form [:errors field])
|
|
||||||
touched? (dm/get-in form [:touched field])
|
|
||||||
show? (and touched? error message
|
|
||||||
(cond
|
|
||||||
(nil? type) true
|
|
||||||
(keyword? type) (= (:type error) type)
|
|
||||||
(ifn? type) (type (:type error))
|
|
||||||
:else false))]
|
|
||||||
(when show?
|
|
||||||
[:ul
|
|
||||||
[:li {:key (:code error)} (tr (:message error))]])))
|
|
||||||
|
|
||||||
(defn error-class
|
(defn error-class
|
||||||
[form field]
|
[form field]
|
||||||
(when (and (dm/get-in form [:errors field])
|
(when (and (dm/get-in form [:errors field])
|
||||||
|
|
|
@ -1230,6 +1230,18 @@ msgstr "Something wrong has happened."
|
||||||
msgid "errors.invalid-color"
|
msgid "errors.invalid-color"
|
||||||
msgstr "Invalid color"
|
msgstr "Invalid color"
|
||||||
|
|
||||||
|
#: src/app/util/forms.cljs
|
||||||
|
msgid "errors.invalid-data"
|
||||||
|
msgstr "Invalid data"
|
||||||
|
|
||||||
|
#: src/app/util/forms.cljs
|
||||||
|
msgid "errors.field-missing"
|
||||||
|
msgstr "Empty field"
|
||||||
|
|
||||||
|
#: src/app/util/forms.cljs
|
||||||
|
msgid "errors.invalid-text"
|
||||||
|
msgstr "Invalid text"
|
||||||
|
|
||||||
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs, src/app/main/ui/auth/recovery_request.cljs
|
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs, src/app/main/ui/auth/recovery_request.cljs
|
||||||
#, unused
|
#, unused
|
||||||
msgid "errors.invalid-email"
|
msgid "errors.invalid-email"
|
||||||
|
|
|
@ -1231,6 +1231,18 @@ msgstr "Ha ocurrido algún error."
|
||||||
msgid "errors.invalid-color"
|
msgid "errors.invalid-color"
|
||||||
msgstr "Color no válido"
|
msgstr "Color no válido"
|
||||||
|
|
||||||
|
#: src/app/util/forms.cljs
|
||||||
|
msgid "errors.invalid-data"
|
||||||
|
msgstr "Datos no válidos"
|
||||||
|
|
||||||
|
#: src/app/util/forms.cljs
|
||||||
|
msgid "errors.field-missing"
|
||||||
|
msgstr "Campo vacio"
|
||||||
|
|
||||||
|
#: src/app/util/forms.cljs
|
||||||
|
msgid "errors.invalid-text"
|
||||||
|
msgstr "Texto no válido"
|
||||||
|
|
||||||
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs, src/app/main/ui/auth/recovery_request.cljs
|
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs, src/app/main/ui/auth/recovery_request.cljs
|
||||||
#, unused
|
#, unused
|
||||||
msgid "errors.invalid-email"
|
msgid "errors.invalid-email"
|
||||||
|
|
Loading…
Add table
Reference in a new issue