0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-31 09:01:20 -05:00

Merge pull request #4765 from penpot/niwinz-refactor-forms

♻️ Refactor forms (spec -> schema)
This commit is contained in:
Alejandro 2024-07-03 08:45:42 +02:00 committed by GitHub
commit 7ed25d2dba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
63 changed files with 883 additions and 1185 deletions

View file

@ -9,7 +9,7 @@
data resources."
(:refer-clojure :exclude [read-string hash-map merge name update-vals
parse-double group-by iteration concat mapcat
parse-uuid max min])
parse-uuid max min regexp?])
#?(:cljs
(:require-macros [app.common.data]))
@ -641,6 +641,13 @@
;; Utilities
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn regexp?
"Return `true` if `x` is a regexp pattern
instance."
[x]
#?(:cljs (cljs.core/regexp? x)
:clj (instance? java.util.regex.Pattern x)))
(defn nilf
"Returns a new function that if you pass nil as any argument will
return nil"

View file

@ -21,6 +21,7 @@
[cuerdas.core :as str]
[malli.core :as m]
[malli.dev.pretty :as mdp]
[malli.dev.virhe :as v]
[malli.error :as me]
[malli.generator :as mg]
[malli.registry :as mr]
@ -44,6 +45,14 @@
[o]
(m/schema? o))
(defn properties
[s]
(m/properties s))
(defn type-properties
[s]
(m/type-properties s))
(defn lazy-schema?
[s]
(satisfies? ILazySchema s))
@ -96,6 +105,10 @@
[exp]
(malli.error/error-value exp {:malli.error/mask-valid-values '...}))
(defn optional-keys
[schema]
(mu/optional-keys schema default-options))
(def default-transformer
(let [default-decoder
{:compile (fn [s _registry]
@ -144,6 +157,8 @@
(m/encode s val options transformer)))
(defn decode
([s val]
(m/decode s val default-options default-transformer))
([s val transformer]
(m/decode s val default-options transformer))
([s val options transformer]
@ -180,9 +195,10 @@
(fn [v] (@vfn v))))
(defn lazy-decoder
[s transformer]
(let [vfn (delay (decoder (if (delay? s) (deref s) s) transformer))]
(fn [v] (@vfn v))))
([s] (lazy-decoder s default-transformer))
([s transformer]
(let [vfn (delay (decoder (if (delay? s) (deref s) s) transformer))]
(fn [v] (@vfn v)))))
(defn humanize-explain
[{:keys [schema errors value]} & {:keys [length level]}]
@ -197,9 +213,29 @@
:level (d/nilv level 8)
:length (d/nilv length 12)})))))
(defmethod v/-format ::schemaless-explain
[_ {:keys [schema] :as explanation} printer]
{:body [:group
(v/-block "Value" (v/-visit (me/error-value explanation printer) printer) printer) :break :break
(v/-block "Errors" (v/-visit (me/humanize (me/with-spell-checking explanation)) printer) printer) :break :break
(v/-block "Schema" (v/-visit schema printer) printer)]})
(defmethod v/-format ::explain
[_ {:keys [schema] :as explanation} printer]
{:body [:group
(v/-block "Value" (v/-visit (me/error-value explanation printer) printer) printer) :break :break
(v/-block "Errors" (v/-visit (me/humanize (me/with-spell-checking explanation)) printer) printer) :break :break
(v/-block "Schema" (v/-visit schema printer) printer)]})
(defn pretty-explain
[s d]
(mdp/explain (schema s) d))
[explain & {:keys [variant message]
:or {variant ::explain
message "Validation Error"}}]
(let [explain (fn [] (me/with-error-messages explain))]
((mdp/prettifier variant message explain default-options))))
(defmacro ignoring
[expr]
@ -287,7 +323,7 @@
(throw (ex-info hint options))))))
(defn validate-fn
"Create a predefined validate function"
"Create a predefined validate function that raises an expception"
[s]
(let [schema (if (lazy-schema? s) s (define s))]
(partial fast-validate! schema)))
@ -307,6 +343,7 @@
hint (get options :hint "schema validation error")]
(throw (ex-info hint options)))))))
;; FIXME: revisit
(defn conform!
[schema value]
(assert (lazy-schema? schema) "expected `schema` to satisfy ILazySchema protocol")
@ -428,23 +465,33 @@
[s]
(if (string? s)
(re-matches email-re s)
s))
nil))
(defn email-string?
[s]
(and (string? s)
(re-seq email-re s)))
;; FIXME: add proper email generator
(define! ::email
{:type ::email
:pred (fn [s]
(and (string? s)
(< (count s) 250)
(re-seq email-re s)))
{:type :string
:pred email-string?
:property-pred
(fn [{:keys [max] :as props}]
(if (some? max)
(fn [value]
(<= (count value) max))
(constantly true)))
:type-properties
{:title "email"
:description "string with valid email address"
:error/message "expected valid email"
:gen/gen (-> :string sg/generator)
:error/code "errors.invalid-email"
:gen/gen (sg/email)
::oapi/type "string"
::oapi/format "email"
::oapi/decode parse-email}})
::oapi/decode
(fn [v]
(or (parse-email v) v))}})
(def non-empty-strings-xf
(comp
@ -452,6 +499,121 @@
(remove str/empty?)
(remove str/blank?)))
;; NOTE: this is general purpose set spec and should be used over the other
(define! ::set
{:type :set
:min 0
:max 1
:compile
(fn [{:keys [coerce kind max min] :as props} children _]
(let [xform (if coerce
(comp non-empty-strings-xf (map coerce))
non-empty-strings-xf)
kind (or (last children) kind)
pred (cond
(fn? kind) kind
(nil? kind) any?
:else (validator kind))
pred (cond
(and max min)
(fn [value]
(let [size (count value)]
(and (set? value)
(<= min size max)
(every? pred value))))
min
(fn [value]
(let [size (count value)]
(and (set? value)
(<= min size)
(every? pred value))))
max
(fn [value]
(let [size (count value)]
(and (set? value)
(<= size max)
(every? pred value))))
:else
(fn [value]
(every? pred value)))]
{:pred pred
:type-properties
{:title "set"
:description "Set of Strings"
:error/message "should be a set of strings"
:gen/gen (-> kind sg/generator sg/set)
::oapi/type "array"
::oapi/format "set"
::oapi/items {:type "string"}
::oapi/unique-items true
::oapi/decode (fn [v]
(let [v (if (string? v) (str/split v #"[\s,]+") v)]
(into #{} xform v)))}}))})
(define! ::vec
{:type :vector
:min 0
:max 1
:compile
(fn [{:keys [coerce kind max min] :as props} children _]
(let [xform (if coerce
(comp non-empty-strings-xf (map coerce))
non-empty-strings-xf)
kind (or (last children) kind)
pred (cond
(fn? kind) kind
(nil? kind) any?
:else (validator kind))
pred (cond
(and max min)
(fn [value]
(let [size (count value)]
(and (set? value)
(<= min size max)
(every? pred value))))
min
(fn [value]
(let [size (count value)]
(and (set? value)
(<= min size)
(every? pred value))))
max
(fn [value]
(let [size (count value)]
(and (set? value)
(<= size max)
(every? pred value))))
:else
(fn [value]
(every? pred value)))]
{:pred pred
:type-properties
{:title "set"
:description "Set of Strings"
:error/message "should be a set of strings"
:gen/gen (-> kind sg/generator sg/set)
::oapi/type "array"
::oapi/format "set"
::oapi/items {:type "string"}
::oapi/unique-items true
::oapi/decode (fn [v]
(let [v (if (string? v) (str/split v #"[\s,]+") v)]
(into [] xform v)))}}))})
(define! ::set-of-strings
{:type ::set-of-strings
:pred #(and (set? %) (every? string? %))
@ -634,6 +796,8 @@
(define! ::fn
[:schema fn?])
;; FIXME: deprecated, replace with ::text
(define! ::word-string
{:type ::word-string
:pred #(and (string? %) (not (str/blank? %)))
@ -649,16 +813,102 @@
(define! ::uri
{:type ::uri
:pred u/uri?
:property-pred
(fn [{:keys [min max prefix] :as props}]
(if (seq props)
(fn [value]
(let [value (str value)
size (count value)]
(and
(cond
(and min max)
(<= min size max)
min
(<= min size)
max
(<= size max))
(cond
(d/regexp? prefix)
(some? (re-seq prefix value))
:else
true))))
(constantly true)))
:type-properties
{:title "uri"
:description "URI formatted string"
:error/message "expected URI instance"
:error/code "errors.invalid-uri"
:gen/gen (sg/uri)
::oapi/type "string"
::oapi/format "uri"
::oapi/decode (comp u/uri str/trim)}})
(def! ::plugin-data
(define! ::text
{:type :string
:pred #(and (string? %) (not (str/blank? %)))
:property-pred
(fn [{:keys [min max] :as props}]
(if (seq props)
(fn [value]
(let [size (count value)]
(cond
(and min max)
(<= min size max)
min
(<= min size)
max
(<= size max))))
(constantly true)))
:type-properties
{:title "string"
:description "not whitespace string"
:gen/gen (sg/word-string)
:error/code "errors.invalid-text"
:error/fn
(fn [{:keys [value schema]}]
(let [{:keys [max min] :as props} (properties schema)]
(cond
(and (string? value)
(number? max)
(> (count value) max))
["errors.field-max-length" max]
(and (string? value)
(number? min)
(< (count value) min))
["errors.field-min-length" min]
(and (string? value)
(str/blank? value))
"errors.field-not-all-whitespace")))}})
(define! ::password
{:type :string
:pred
(fn [value]
(and (string? value)
(>= (count value) 8)
(not (str/blank? value))))
:type-properties
{:title "password"
:gen/gen (->> (sg/word-string)
(sg/filter #(>= (count %) 8)))
:error/code "errors.password-too-short"
::oapi/type "string"
::oapi/format "password"}})
;; FIXME: this should not be here
(define! ::plugin-data
[:map-of {:gen/max 5} :string :string])
;; ---- PREDICATES

View file

@ -77,10 +77,23 @@
(defn word-string
[]
(->> (tg/such-that #(re-matches #"\w+" %)
tg/string-alphanumeric
50)
(tg/such-that (complement str/blank?))))
(as-> tg/string-alphanumeric $$
(tg/such-that (fn [v] (re-matches #"\w+" v)) $$ 50)
(tg/such-that (fn [v]
(and (not (str/blank? v))
(not (re-matches #"^\d+.*" v))))
$$
50)))
(defn email
[]
(->> (word-string)
(tg/such-that (fn [v] (>= (count v) 4)))
(tg/fmap str/lower)
(tg/fmap (fn [v]
(str v "@example.net")))))
(defn uri
[]

View file

@ -7,9 +7,8 @@
(ns app.main.ui.auth.login
(:require-macros [app.main.style :as stl])
(:require
[app.common.data :as d]
[app.common.logging :as log]
[app.common.spec :as us]
[app.common.schema :as sm]
[app.config :as cf]
[app.main.data.messages :as msg]
[app.main.data.users :as du]
@ -25,7 +24,6 @@
[app.util.keyboard :as k]
[app.util.router :as rt]
[beicon.v2.core :as rx]
[cljs.spec.alpha :as s]
[rumext.v2 :as mf]))
(def show-alt-login-buttons?
@ -64,28 +62,18 @@
:else
(st/emit! (msg/error (tr "errors.generic"))))))))
(s/def ::email ::us/email)
(s/def ::password ::us/not-empty-string)
(s/def ::invitation-token ::us/not-empty-string)
(s/def ::login-form
(s/keys :req-un [::email ::password]
:opt-un [::invitation-token]))
(defn handle-error-messages
[errors _data]
(d/update-when errors :email
(fn [{:keys [code] :as error}]
(cond-> error
(= code ::us/email)
(assoc :message (tr "errors.email-invalid"))))))
(def ^:private schema:login-form
[:map {:title "LoginForm"}
[:email [::sm/email {:error/code "errors.invalid-email"}]]
[:password [:string {:min 1}]]
[:invitation-token {:optional true}
[:string {:min 1}]]])
(mf/defc login-form
[{:keys [params on-success-callback origin] :as props}]
(let [initial (mf/use-memo (mf/deps params) (constantly params))
(let [initial (mf/with-memo [params] params)
error (mf/use-state false)
form (fm/use-form :spec ::login-form
:validators [handle-error-messages]
form (fm/use-form :schema schema:login-form
:initial initial)
on-error

View file

@ -7,39 +7,29 @@
(ns app.main.ui.auth.recovery
(:require-macros [app.main.style :as stl])
(:require
[app.common.spec :as us]
[app.common.schema :as sm]
[app.main.data.messages :as msg]
[app.main.data.users :as du]
[app.main.store :as st]
[app.main.ui.components.forms :as fm]
[app.util.i18n :as i18n :refer [tr]]
[app.util.router :as rt]
[cljs.spec.alpha :as s]
[rumext.v2 :as mf]))
(s/def ::password-1 ::us/not-empty-string)
(s/def ::password-2 ::us/not-empty-string)
(s/def ::token ::us/not-empty-string)
(s/def ::recovery-form
(s/keys :req-un [::password-1
::password-2]))
(defn- password-equality
[errors data]
(let [password-1 (:password-1 data)
password-2 (:password-2 data)]
(cond-> errors
(and password-1 password-2
(not= password-1 password-2))
(assoc :password-2 {:message "errors.password-invalid-confirmation"})
(and password-1 (> 8 (count password-1)))
(assoc :password-1 {:message "errors.password-too-short"}))))
(def ^:private schema:recovery-form
[:and
[:map {:title "RecoveryForm"}
[:token ::sm/text]
[:password-1 ::sm/password]
[:password-2 ::sm/password]]
[:fn {:error/code "errors.password-invalid-confirmation"
:error/field :password-2}
(fn [{:keys [password-1 password-2]}]
(= password-1 password-2))]])
(defn- on-error
[_form _error]
(st/emit! (msg/error (tr "auth.notifications.invalid-token-error"))))
(st/emit! (msg/error (tr "errors.invalid-recovery-token"))))
(defn- on-success
[_]
@ -56,14 +46,13 @@
(mf/defc recovery-form
[{:keys [params] :as props}]
(let [form (fm/use-form :spec ::recovery-form
:validators [password-equality
(fm/validate-not-empty :password-1 (tr "auth.password-not-empty"))
(fm/validate-not-empty :password-2 (tr "auth.password-not-empty"))]
(let [form (fm/use-form :schema schema:recovery-form
:initial params)]
[:& fm/form {:on-submit on-submit
:class (stl/css :recovery-form)
:form form}
[:div {:class (stl/css :fields-row)}
[:& fm/input {:type "password"
:name :password-1

View file

@ -7,8 +7,7 @@
(ns app.main.ui.auth.recovery-request
(:require-macros [app.main.style :as stl])
(:require
[app.common.data :as d]
[app.common.spec :as us]
[app.common.schema :as sm]
[app.main.data.messages :as msg]
[app.main.data.users :as du]
[app.main.store :as st]
@ -17,30 +16,24 @@
[app.util.i18n :as i18n :refer [tr]]
[app.util.router :as rt]
[beicon.v2.core :as rx]
[cljs.spec.alpha :as s]
[rumext.v2 :as mf]))
(s/def ::email ::us/email)
(s/def ::recovery-request-form (s/keys :req-un [::email]))
(defn handle-error-messages
[errors _data]
(d/update-when errors :email
(fn [{:keys [code] :as error}]
(cond-> error
(= code :missing)
(assoc :message (tr "errors.email-invalid"))))))
(def ^:private schema:recovery-request-form
[:map {:title "RecoverRequestForm"}
[:email ::sm/email]])
(mf/defc recovery-form
[{:keys [on-success-callback] :as props}]
(let [form (fm/use-form :spec ::recovery-request-form
:validators [handle-error-messages]
(let [form (fm/use-form :schema schema:recovery-request-form
:initial {})
submitted (mf/use-state false)
default-success-finish #(st/emit! (msg/info (tr "auth.notifications.recovery-token-sent")))
default-success-finish
(mf/use-fn
#(st/emit! (msg/info (tr "auth.notifications.recovery-token-sent"))))
on-success
(mf/use-callback
(mf/use-fn
(fn [cdata _]
(reset! submitted false)
(if (nil? on-success-callback)
@ -48,7 +41,7 @@
(on-success-callback (:email cdata)))))
on-error
(mf/use-callback
(mf/use-fn
(fn [data cause]
(reset! submitted false)
(let [code (-> cause ex-data :code)]
@ -65,7 +58,7 @@
(rx/throw cause)))))
on-submit
(mf/use-callback
(mf/use-fn
(fn []
(reset! submitted true)
(let [cdata (:clean-data @form)

View file

@ -7,8 +7,7 @@
(ns app.main.ui.auth.register
(:require-macros [app.main.style :as stl])
(:require
[app.common.data :as d]
[app.common.spec :as us]
[app.common.schema :as sm]
[app.config :as cf]
[app.main.data.messages :as msg]
[app.main.data.users :as du]
@ -22,67 +21,42 @@
[app.util.router :as rt]
[app.util.storage :as sto]
[beicon.v2.core :as rx]
[cljs.spec.alpha :as s]
[rumext.v2 :as mf]))
;; --- PAGE: Register
(defn- validate-password-length
[errors data]
(let [password (:password data)]
(cond-> errors
(> 8 (count password))
(assoc :password {:message "errors.password-too-short"}))))
(defn- validate-email
[errors _]
(d/update-when errors :email
(fn [{:keys [code] :as error}]
(cond-> error
(= code ::us/email)
(assoc :message (tr "errors.email-invalid"))))))
(s/def ::fullname ::us/not-empty-string)
(s/def ::password ::us/not-empty-string)
(s/def ::email ::us/email)
(s/def ::invitation-token ::us/not-empty-string)
(s/def ::terms-privacy ::us/boolean)
(s/def ::register-form
(s/keys :req-un [::password ::email]
:opt-un [::invitation-token]))
(defn- on-prepare-register-error
[form cause]
(let [{:keys [type code]} (ex-data cause)]
(condp = [type code]
[:restriction :registration-disabled]
(st/emit! (msg/error (tr "errors.registration-disabled")))
[:restriction :email-domain-is-not-allowed]
(st/emit! (msg/error (tr "errors.email-domain-not-allowed")))
[:validation :email-as-password]
(swap! form assoc-in [:errors :password]
{:message "errors.email-as-password"})
(st/emit! (msg/error (tr "errors.generic"))))))
(defn- on-prepare-register-success
[params]
(st/emit! (rt/nav :auth-register-validate {} params)))
(def ^:private schema:register-form
[:map {:title "RegisterForm"}
[:password ::sm/password]
[:email ::sm/email]
[:invitation-token {:optional true} ::sm/text]])
(mf/defc register-form
{::mf/props :obj}
[{:keys [params on-success-callback]}]
(let [initial (mf/use-memo (mf/deps params) (constantly params))
form (fm/use-form :spec ::register-form
:validators [validate-password-length
validate-email
(fm/validate-not-empty :password (tr "auth.password-not-empty"))]
form (fm/use-form :schema schema:register-form
:initial initial)
submitted? (mf/use-state false)
on-error
(mf/use-fn
(fn [form cause]
(let [{:keys [type code]} (ex-data cause)]
(condp = [type code]
[:restriction :registration-disabled]
(st/emit! (msg/error (tr "errors.registration-disabled")))
[:restriction :email-domain-is-not-allowed]
(st/emit! (msg/error (tr "errors.email-domain-not-allowed")))
[:validation :email-as-password]
(swap! form assoc-in [:errors :password]
{:code "errors.email-as-password"})
(st/emit! (msg/error (tr "errors.generic")))))))
on-submit
(mf/use-fn
(mf/deps on-success-callback)
@ -90,16 +64,14 @@
(reset! submitted? true)
(let [cdata (:clean-data @form)
on-success (fn [data]
(if (nil? on-success-callback)
(on-prepare-register-success data)
(on-success-callback data)))
on-error (fn [data]
(on-prepare-register-error form data))]
(if (fn? on-success-callback)
(on-success-callback data)
(st/emit! (rt/nav :auth-register-validate {} data))))]
(->> (rp/cmd! :prepare-register-profile cdata)
(rx/map #(merge % params))
(rx/finalize #(reset! submitted? false))
(rx/subs! on-success on-error)))))]
(rx/subs! on-success (partial on-error form))))))]
[:& fm/form {:on-submit on-submit :form form}
[:div {:class (stl/css :fields-row)}
@ -164,33 +136,6 @@
;; --- PAGE: register validation
(defn- on-register-success
[data]
(cond
(some? (:invitation-token data))
(let [token (:invitation-token data)]
(st/emit! (rt/nav :auth-verify-token {} {:token token})))
(:is-active data)
(st/emit! (du/login-from-register))
:else
(do
(swap! sto/storage assoc ::email (:email data))
(st/emit! (rt/nav :auth-register-success)))))
(s/def ::accept-terms-and-privacy (s/and ::us/boolean true?))
(s/def ::accept-newsletter-subscription ::us/boolean)
(if (contains? cf/flags :terms-and-privacy-checkbox)
(s/def ::register-validate-form
(s/keys :req-un [::token ::fullname ::accept-terms-and-privacy]
:opt-un [::accept-newsletter-subscription]))
(s/def ::register-validate-form
(s/keys :req-un [::token ::fullname]
:opt-un [::accept-terms-and-privacy
::accept-newsletter-subscription])))
(mf/defc terms-and-privacy
{::mf/props :obj
::mf/private true}
@ -210,34 +155,48 @@
:default-checked false
:label terms-label}]]))
(def ^:private schema:register-validate-form
[:map {:title "RegisterValidateForm"}
[:token ::sm/text]
[:fullname [::sm/text {:max 250}]]
[:accept-terms-and-privacy {:optional (not (contains? cf/flags :terms-and-privacy-checkbox))}
[:and :boolean [:= true]]]])
(mf/defc register-validate-form
{::mf/props :obj}
{::mf/props :obj
::mf/private true}
[{:keys [params on-success-callback]}]
(let [validators (mf/with-memo []
[(fm/validate-not-empty :fullname (tr "auth.name.not-all-space"))
(fm/validate-length :fullname fm/max-length-allowed (tr "auth.name.too-long"))])
form (fm/use-form :spec ::register-validate-form
:validators validators
:initial params)
(let [form (fm/use-form :schema schema:register-validate-form :initial params)
submitted? (mf/use-state false)
on-success
(mf/use-fn
(mf/deps on-success-callback)
(fn [params]
(if (nil? on-success-callback)
(on-register-success params)
(on-success-callback (:email params)))))
(if (fn? on-success-callback)
(on-success-callback (:email params))
(cond
(some? (:invitation-token params))
(let [token (:invitation-token params)]
(st/emit! (rt/nav :auth-verify-token {} {:token token})))
(:is-active params)
(st/emit! (du/login-from-register))
:else
(do
(swap! sto/storage assoc ::email (:email params))
(st/emit! (rt/nav :auth-register-success)))))))
on-error
(mf/use-fn
(fn [_cause]
(fn [_]
(st/emit! (msg/error (tr "errors.generic")))))
on-submit
(mf/use-fn
(mf/deps on-success on-error)
(fn [form _]
(reset! submitted? true)
(let [params (:clean-data @form)]

View file

@ -17,7 +17,6 @@
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.dropdown :refer [dropdown]]
[app.main.ui.components.forms :as fm]
[app.main.ui.icons :as i]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
@ -96,7 +95,7 @@
(let [show-buttons? (mf/use-state false)
content (mf/use-state "")
disabled? (or (fm/all-spaces? @content)
disabled? (or (str/blank? @content)
(str/empty-or-nil? @content))
on-focus
@ -155,7 +154,7 @@
pos-x (* (:x position) zoom)
pos-y (* (:y position) zoom)
disabled? (or (fm/all-spaces? content)
disabled? (or (str/blank? content)
(str/empty-or-nil? content))
on-esc
@ -225,7 +224,7 @@
(mf/deps @content)
(fn [] (on-submit @content)))
disabled? (or (fm/all-spaces? @content)
disabled? (or (str/blank? @content)
(str/empty-or-nil? @content))]
[:div {:class (stl/css :edit-form)}

View file

@ -18,7 +18,6 @@
[app.util.keyboard :as kbd]
[app.util.object :as obj]
[cljs.core :as c]
[clojure.string]
[cuerdas.core :as str]
[rumext.v2 :as mf]))
@ -26,7 +25,9 @@
(def use-form fm/use-form)
(mf/defc input
[{:keys [label help-icon disabled form hint trim children data-testid on-change-value placeholder show-success?] :as props}]
[{:keys [label help-icon disabled form hint trim children data-testid on-change-value placeholder show-success? show-error]
:or {show-error true}
:as props}]
(let [input-type (get props :type "text")
input-name (get props :name)
more-classes (get props :class)
@ -152,11 +153,14 @@
children])
(cond
(and touched? (:message error))
[:div {:id (dm/str "error-" input-name)
:class (stl/css :error)
:data-testid (clojure.string/join [data-testid "-error"])}
(tr (:message error))]
(and touched? (:code error) show-error)
(let [code (:code error)]
[:div {:id (dm/str "error-" input-name)
:class (stl/css :error)
:data-testid (dm/str data-testid "-error")}
(if (vector? code)
(tr (nth code 0) (i18n/c (nth code 1)))
(tr code))])
(string? hint)
[:div {:class (stl/css :hint)} hint])]]))
@ -207,8 +211,8 @@
[:label {:class (stl/css :textarea-label)} label]
[:> :textarea props]
(cond
(and touched? (:message error))
[:span {:class (stl/css :error)} (tr (:message error))]
(and touched? (:code error))
[:span {:class (stl/css :error)} (tr (:code error))]
(string? hint)
[:span {:class (stl/css :hint)} hint])]))
@ -550,41 +554,3 @@
[:span {:class (stl/css :text)} (:text item)]
[:button {:class (stl/css :icon)
:on-click #(remove-item! item)} i/close]]])])]))
;; --- Validators
(defn all-spaces?
[value]
(let [trimmed (str/trim value)]
(str/empty? trimmed)))
(def max-length-allowed 250)
(def max-uri-length-allowed 2048)
(defn max-length?
[value length]
(> (count value) length))
(defn validate-length
[field length errors-msg]
(fn [errors data]
(cond-> errors
(max-length? (get data field) length)
(assoc field {:message errors-msg}))))
(defn validate-not-empty
[field error-msg]
(fn [errors data]
(cond-> errors
(all-spaces? (get data field))
(assoc field {:message error-msg}))))
(defn validate-not-all-spaces
[field error-msg]
(fn [errors data]
(let [value (get data field)]
(cond-> errors
(and
(all-spaces? value)
(> (count value) 0))
(assoc field {:message error-msg})))))

View file

@ -7,25 +7,24 @@
(ns app.main.ui.dashboard.change-owner
(:require-macros [app.main.style :as stl])
(:require
[app.common.spec :as us]
[app.common.schema :as sm]
[app.main.data.modal :as modal]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.forms :as fm]
[app.main.ui.icons :as i]
[app.util.i18n :as i18n :refer [tr]]
[cljs.spec.alpha :as s]
[rumext.v2 :as mf]))
(s/def ::member-id ::us/uuid)
(s/def ::leave-modal-form
(s/keys :req-un [::member-id]))
(def ^:private schema:leave-modal-form
[:map {:title "LeaveModalForm"}
[:member-id ::sm/uuid]])
(mf/defc leave-and-reassign-modal
{::mf/register modal/components
::mf/register-as :leave-and-reassign}
[{:keys [profile team accept]}]
(let [form (fm/use-form :spec ::leave-modal-form :initial {})
(let [form (fm/use-form :schema schema:leave-modal-form :initial {})
members-map (mf/deref refs/dashboard-team-members)
members (vals members-map)

View file

@ -9,6 +9,7 @@
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.schema :as sm]
[app.common.spec :as us]
[app.config :as cfg]
[app.main.data.dashboard :as dd]
@ -33,7 +34,6 @@
[cuerdas.core :as str]
[rumext.v2 :as mf]))
(def ^:private arrow-icon
(i/icon-xref :arrow (stl/css :arrow-icon)))
@ -131,6 +131,12 @@
(s/def ::invite-member-form
(s/keys :req-un [::role ::emails ::team-id]))
(def ^:private schema:invite-member-form
[:map {:title "InviteMemberForm"}
[:role :keyword]
[:emails [::sm/set {:kind ::sm/email :min 1}]]
[:team-id ::sm/uuid]])
(mf/defc invite-members-modal
{::mf/register modal/components
::mf/register-as :invite-members
@ -139,9 +145,14 @@
(let [members-map (mf/deref refs/dashboard-team-members)
perms (:permissions team)
roles (mf/use-memo (mf/deps perms) #(get-available-roles perms))
initial (mf/use-memo (constantly {:role "editor" :team-id (:id team)}))
form (fm/use-form :spec ::invite-member-form
roles (mf/with-memo [perms]
(get-available-roles perms))
team-id (:id team)
initial (mf/with-memo [team-id]
{:role "editor" :team-id team-id})
form (fm/use-form :schema schema:invite-member-form
:initial initial)
error-text (mf/use-state "")
@ -746,10 +757,11 @@
;; WEBHOOKS SECTION
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(s/def ::uri ::us/uri)
(s/def ::mtype ::us/not-empty-string)
(s/def ::webhook-form
(s/keys :req-un [::uri ::mtype]))
(def ^:private schema:webhook-form
[:map {:title "WebhookForm"}
[:uri [::sm/uri {:max 4069 :prefix #"^http[s]?://"
:error/code "errors.webhooks.invalid-uri"}]]
[:mtype ::sm/text]])
(def valid-webhook-mtypes
[{:label "application/json" :value "application/json"}
@ -763,12 +775,12 @@
{::mf/register modal/components
::mf/register-as :webhook}
[{:keys [webhook] :as props}]
;; FIXME: this is a workaround because input fields do not support rendering hooks
(let [initial (mf/use-memo (fn [] (or (some-> webhook (update :uri str))
{:is-active false :mtype "application/json"})))
form (fm/use-form :spec ::webhook-form
:initial initial
:validators [(fm/validate-length :uri fm/max-uri-length-allowed (tr "team.webhooks.max-length"))])
(let [initial (mf/with-memo []
(or (some-> webhook (update :uri str))
{:is-active false :mtype "application/json"}))
form (fm/use-form :schema schema:webhook-form
:initial initial)
on-success
(mf/use-fn
(fn [_]

View file

@ -7,7 +7,7 @@
(ns app.main.ui.dashboard.team-form
(:require-macros [app.main.style :as stl])
(:require
[app.common.spec :as us]
[app.common.schema :as sm]
[app.main.data.dashboard :as dd]
[app.main.data.messages :as msg]
[app.main.data.modal :as modal]
@ -19,12 +19,11 @@
[app.util.keyboard :as kbd]
[app.util.router :as rt]
[beicon.v2.core :as rx]
[cljs.spec.alpha :as s]
[rumext.v2 :as mf]))
(s/def ::name ::us/not-empty-string)
(s/def ::team-form
(s/keys :req-un [::name]))
(def ^:private schema:team-form
[:map {:title "TeamForm"}
[:name [::sm/text {:max 250}]]])
(defn- on-create-success
[_form response]
@ -68,24 +67,23 @@
(on-update-submit form)
(on-create-submit form))))
(mf/defc team-form-modal {::mf/register modal/components
::mf/register-as :team-form}
(mf/defc team-form-modal
{::mf/register modal/components
::mf/register-as :team-form}
[{:keys [team] :as props}]
(let [initial (mf/use-memo (fn [] (or team {})))
form (fm/use-form :spec ::team-form
:validators [(fm/validate-not-empty :name (tr "auth.name.not-all-space"))
(fm/validate-length :name fm/max-length-allowed (tr "auth.name.too-long"))]
form (fm/use-form :schema schema:team-form
:initial initial)
handle-keydown
(mf/use-callback
(mf/deps)
(mf/use-fn
(fn [e]
(when (kbd/enter? e)
(dom/prevent-default e)
(dom/stop-propagation e)
(on-submit form e))))
on-close #(st/emit! (modal/hide))]
on-close
(mf/use-fn #(st/emit! (modal/hide)))]
[:div {:class (stl/css :modal-overlay)}
[:div {:class (stl/css :modal-container)}

View file

@ -10,13 +10,13 @@
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.schema :as sm]
[app.main.data.events :as-alias ev]
[app.main.data.users :as du]
[app.main.store :as st]
[app.main.ui.components.forms :as fm]
[app.main.ui.icons :as i]
[app.util.i18n :as i18n :refer [tr]]
[cljs.spec.alpha :as s]
[cuerdas.core :as str]
[potok.v2.core :as ptk]
[rumext.v2 :as mf]))
@ -56,25 +56,20 @@
(tr "labels.start"))
:class (stl/css :next-button)}]]]))
(s/def ::questions-form-step-1
(s/keys :req-un [::planning
::expected-use]
:opt-un [::planning-other]))
(def ^:private schema:questions-form-1
[:and
(defn- step-1-form-validator
[errors data]
(let [planning (:planning data)
planning-other (:planning-other data)]
(cond-> errors
(and (= planning "other")
(str/blank? planning-other))
(assoc :planning-other {:code "missing"})
[:map {:title "QuestionsFormStep1"}
[:planning ::sm/text]
[:expected-use [:enum "work" "education" "personal"]]
[:planning-other {:optional true}
[::sm/text {:max 512}]]]
(not= planning "other")
(assoc :planning-other nil)
(str/blank? planning)
(assoc :planning {:code "missing"}))))
[:fn {:error/field :planning-other}
(fn [{:keys [planning planning-other]}]
(or (not= planning "other")
(and (= planning "other")
(not (str/blank? planning-other)))))]])
(mf/defc step-1
{::mf/props :obj}
@ -143,24 +138,24 @@
[:& fm/input {:name :planning-other
:class (stl/css :input-spacing)
:placeholder (tr "labels.other")
:show-error false
:label ""}])]]))
(s/def ::questions-form-step-2
(s/keys :req-un [::experience-design-tool]
:opt-un [::experience-design-tool-other]))
(def ^:private schema:questions-form-2
[:and
[:map {:title "QuestionsFormStep2"}
[:experience-design-tool
[:enum "figma" "sketch" "adobe-xd" "canva" "invision" "other"]]
[:experience-design-tool-other {:optional true}
[::sm/text {:max 512}]]]
(defn- step-2-form-validator
[errors data]
(let [experience (:experience-design-tool data)
experience-other (:experience-design-tool-other data)]
(cond-> errors
(and (= experience "other")
(str/blank? experience-other))
(assoc :experience-design-tool-other {:code "missing"})
(not= experience "other")
(assoc :experience-design-tool-other nil))))
[:fn {:error/field :experience-design-tool-other}
(fn [data]
(let [experience (:experience-design-tool data)
experience-other (:experience-design-tool-other data)]
(or (not= experience "other")
(and (= experience "other")
(not (str/blank? experience-other))))))]])
(mf/defc step-2
{::mf/props :obj}
@ -180,7 +175,7 @@
(conj {:label (tr "labels.other-short") :value "other" :icon i/curve})))
current-experience
(dm/get-in @form [:clean-data :experience-design-tool])
(dm/get-in @form [:data :experience-design-tool])
on-design-tool-change
(mf/use-fn
@ -212,33 +207,34 @@
[:& fm/input {:name :experience-design-tool-other
:class (stl/css :input-spacing)
:placeholder (tr "labels.other")
:show-error false
:label ""}])]]))
(s/def ::questions-form-step-3
(s/keys :req-un [::team-size ::role ::responsability]
:opt-un [::role-other ::responsability-other]))
(defn- step-3-form-validator
[errors data]
(let [role (:role data)
role-other (:role-other data)
responsability (:responsability data)
responsability-other (:responsability-other data)]
(def ^:private schema:questions-form-3
[:and
[:map {:title "QuestionsFormStep3"}
[:team-size
[:enum "more-than-50" "31-50" "11-30" "2-10" "freelancer" "personal-project"]]
[:role
[:enum "designer" "developer" "student-teacher" "graphic-design" "marketing" "manager" "other"]]
[:responsability
[:enum "team-leader" "team-member" "freelancer" "ceo-founder" "director" "student-teacher" "other"]]
(cond-> errors
(and (= role "other")
(str/blank? role-other))
(assoc :role-other {:code "missing"})
[:role-other {:optional true} [::sm/text {:max 512}]]
[:responsability-other {:optional true} [::sm/text {:max 512}]]]
(not= role "other")
(assoc :role-other nil)
[:fn {:error/field :role-other}
(fn [{:keys [role role-other]}]
(or (not= role "other")
(and (= role "other")
(not (str/blank? role-other)))))]
(and (= responsability "other")
(str/blank? responsability-other))
(assoc :responsability-other {:code "missing"})
(not= responsability "other")
(assoc :responsability-other nil))))
[:fn {:error/field :responsability-other}
(fn [{:keys [responsability responsability-other]}]
(or (not= responsability "other")
(and (= responsability "other")
(not (str/blank? responsability-other)))))]])
(mf/defc step-3
{::mf/props :obj}
@ -264,7 +260,6 @@
{:label (tr "labels.director") :value "director"}])
(conj {:label (tr "labels.other-short") :value "other"})))
team-size-options
(mf/with-memo []
[{:label (tr "labels.select-option") :value "" :key "team-size" :disabled true}
@ -301,6 +296,7 @@
[:& fm/input {:name :role-other
:class (stl/css :input-spacing)
:placeholder (tr "labels.other")
:show-error false
:label ""}])]
[:div {:class (stl/css :modal-question)}
@ -314,6 +310,7 @@
[:& fm/input {:name :responsability-other
:class (stl/css :input-spacing)
:placeholder (tr "labels.other")
:show-error false
:label ""}])]
[:div {:class (stl/css :modal-question)}
@ -323,21 +320,18 @@
:select-class (stl/css :select-class)
:name :team-size}]]]))
(s/def ::questions-form-step-4
(s/keys :req-un [::start-with]
:opt-un [::start-with-other]))
(def ^:private schema:questions-form-4
[:and
[:map {:title "QuestionsFormStep4"}
[:start-with
[:enum "ui" "wireframing" "prototyping" "ds" "code" "other"]]
[:start-with-other {:optional true} [::sm/text {:max 512}]]]
(defn- step-4-form-validator
[errors data]
(let [start (:start-with data)
start-other (:start-with-other data)]
(cond-> errors
(and (= start "other")
(str/blank? start-other))
(assoc :start-with-other {:code "missing"})
(not= start "other")
(assoc :start-with-other nil))))
[:fn {:error/field :start-with-other}
(fn [{:keys [start-with start-with-other]}]
(or (not= start-with "other")
(and (= start-with "other")
(not (str/blank? start-with-other)))))]])
(mf/defc step-4
{::mf/props :obj}
@ -386,23 +380,21 @@
[:& fm/input {:name :start-with-other
:class (stl/css :input-spacing)
:label ""
:show-error false
:placeholder (tr "labels.other")}])]]))
(s/def ::questions-form-step-5
(s/keys :req-un [::referer]
:opt-un [::referer-other]))
(def ^:private schema:questions-form-5
[:and
[:map {:title "QuestionsFormStep5"}
[:referer
[:enum "youtube" "event" "search" "social" "article" "other"]]
[:referer-other {:optional true} [::sm/text {:max 512}]]]
(defn- step-5-form-validator
[errors data]
(let [referer (:referer data)
referer-other (:referer-other data)]
(cond-> errors
(and (= referer "other")
(str/blank? referer-other))
(assoc :referer-other {:code "missing"})
(not= referer "other")
(assoc :referer-other nil))))
[:fn {:error/field :referer-other}
(fn [{:keys [referer referer-other]}]
(or (not= referer "other")
(and (= referer "other")
(not (str/blank? referer-other)))))]])
(mf/defc step-5
{::mf/props :obj}
@ -444,6 +436,7 @@
[:& fm/input {:name :referer-other
:class (stl/css :input-spacing)
:label ""
:show-error false
:placeholder (tr "labels.other")}])]]))
(mf/defc questions-modal
@ -456,28 +449,23 @@
;; and we want to keep the filled info
step-1-form (fm/use-form
:initial {}
:validators [step-1-form-validator]
:spec ::questions-form-step-1)
:schema schema:questions-form-1)
step-2-form (fm/use-form
:initial {}
:validators [step-2-form-validator]
:spec ::questions-form-step-2)
:schema schema:questions-form-2)
step-3-form (fm/use-form
:initial {}
:validators [step-3-form-validator]
:spec ::questions-form-step-3)
:schema schema:questions-form-3)
step-4-form (fm/use-form
:initial {}
:validators [step-4-form-validator]
:spec ::questions-form-step-4)
:schema schema:questions-form-4)
step-5-form (fm/use-form
:initial {}
:validators [step-5-form-validator]
:spec ::questions-form-step-5)
:schema schema:questions-form-5)
on-next
(mf/use-fn

View file

@ -8,7 +8,7 @@
(:require-macros [app.main.style :as stl])
(:require
[app.common.data.macros :as dm]
[app.common.spec :as us]
[app.common.schema :as sm]
[app.main.data.dashboard :as dd]
[app.main.data.events :as ev]
[app.main.data.messages :as msg]
@ -18,7 +18,6 @@
[app.main.ui.icons :as i]
[app.util.i18n :as i18n :refer [tr]]
[app.util.router :as rt]
[cljs.spec.alpha :as s]
[potok.v2.core :as ptk]
[rumext.v2 :as mf]))
@ -55,11 +54,10 @@
[:p {:class (stl/css :modal-desc)}
(tr "onboarding.team-modal.create-team-feature-5")]]]])
(s/def ::emails (s/and ::us/set-of-valid-emails))
(s/def ::role ::us/keyword)
(s/def ::invite-form
(s/keys :req-un [::role ::emails]))
(def ^:private schema:invite-form
[:map {:title "InviteForm"}
[:role :keyword]
[:emails [::sm/set {:kind ::sm/email}]]])
(defn- get-available-roles
[]
@ -73,7 +71,7 @@
#(do {:role "editor"
:name name}))
form (fm/use-form :spec ::invite-form
form (fm/use-form :schema schema:invite-form
:initial initial)
params (:clean-data @form)
@ -151,7 +149,7 @@
:name :emails
:auto-focus? true
:trim true
:valid-item-fn us/parse-email
:valid-item-fn sm/parse-email
:caution-item-fn #{}
:label (tr "modals.invite-member.emails")
:on-submit on-submit}]]
@ -172,18 +170,16 @@
[:div {:class (stl/css :paginator)} "2/2"]]))
(def ^:private schema:team-form
[:map {:title "TeamForm"}
[:name [::sm/text {:max 250}]]])
(mf/defc team-form-step-1
{::mf/props :obj
::mf/private true}
[{:keys [on-submit]}]
(let [validators (mf/with-memo []
[(fm/validate-not-empty :name (tr "auth.name.not-all-space"))
(fm/validate-length :name fm/max-length-allowed (tr "auth.name.too-long"))])
form (fm/use-form
:spec ::team-form
:initial {}
:validators validators)
(let [form (fm/use-form :schema schema:team-form
:initial {})
on-submit*
(mf/use-fn
@ -240,10 +236,6 @@
[:div {:class (stl/css :paginator)} "1/2"]]))
(s/def ::name ::us/not-empty-string)
(s/def ::team-form
(s/keys :req-un [::name]))
(mf/defc onboarding-team-modal
{::mf/props :obj}
[]

View file

@ -7,7 +7,7 @@
(ns app.main.ui.settings.access-tokens
(:require-macros [app.main.style :as stl])
(:require
[app.common.spec :as us]
[app.common.schema :as sm]
[app.main.data.messages :as msg]
[app.main.data.modal :as modal]
[app.main.data.users :as du]
@ -20,8 +20,6 @@
[app.util.keyboard :as kbd]
[app.util.time :as dt]
[app.util.webapi :as wapi]
[cljs.spec.alpha :as s]
[cuerdas.core :as str]
[okulary.core :as l]
[rumext.v2 :as mf]))
@ -40,17 +38,10 @@
(def token-created-ref
(l/derived :access-token-created st/state))
(s/def ::name ::us/not-empty-string)
(s/def ::expiration-date ::us/not-empty-string)
(s/def ::access-token-form
(s/keys :req-un [::name ::expiration-date]))
(defn- name-validator
[errors data]
(let [name (:name data)]
(cond-> errors
(str/blank? name)
(assoc :name {:message (tr "dashboard.access-tokens.errors-required-name")}))))
(def ^:private schema:form
[:map {:title "AccessTokenForm"}
[:name [::sm/text {:max 250}]]
[:expiration-date [::sm/text {:max 250}]]])
(def initial-data
{:name "" :expiration-date "never"})
@ -61,10 +52,8 @@
[]
(let [form (fm/use-form
:initial initial-data
:spec ::access-token-form
:validators [name-validator
(fm/validate-not-empty :name (tr "auth.name.not-all-space"))
(fm/validate-length :name fm/max-length-allowed (tr "auth.name.too-long"))])
:schema schema:form)
created (mf/deref token-created-ref)
created? (mf/use-state false)
locale (mf/deref i18n/locale)

View file

@ -7,9 +7,7 @@
(ns app.main.ui.settings.change-email
(:require-macros [app.main.style :as stl])
(:require
[app.common.data :as d]
[app.common.data.macros :as dma]
[app.common.spec :as us]
[app.common.schema :as sm]
[app.main.data.messages :as msg]
[app.main.data.modal :as modal]
[app.main.data.users :as du]
@ -20,24 +18,8 @@
[app.main.ui.notifications.context-notification :refer [context-notification]]
[app.util.i18n :as i18n :refer [tr]]
[beicon.v2.core :as rx]
[cljs.spec.alpha :as s]
[rumext.v2 :as mf]))
(s/def ::email-1 ::us/email)
(s/def ::email-2 ::us/email)
(defn- email-equality
[errors data]
(let [email-1 (:email-1 data)
email-2 (:email-2 data)]
(cond-> errors
(and email-1 email-2 (not= email-1 email-2))
(assoc :email-2 {:message (tr "errors.email-invalid-confirmation")
:code :different-emails}))))
(s/def ::email-change-form
(s/keys :req-un [::email-1 ::email-2]))
(defn- on-error
[form error]
(case (:code (ex-data error))
@ -71,30 +53,32 @@
:on-success (partial on-success profile)}]
(st/emit! (du/request-email-change (with-meta params mdata)))))
(def ^:private schema:email-change-form
[:and
[:map {:title "EmailChangeForm"}
[:email-1 ::sm/email]
[:email-2 ::sm/email]]
[:fn {:error/code "errors.invalid-email-confirmation"
:error/field :email-2}
(fn [data]
(let [email-1 (:email-1 data)
email-2 (:email-2 data)]
(= email-1 email-2)))]])
(mf/defc change-email-modal
{::mf/register modal/components
::mf/register-as :change-email}
[]
(let [profile (mf/deref refs/profile)
form (fm/use-form :spec ::email-change-form
:validators [email-equality]
form (fm/use-form :schema schema:email-change-form
:initial profile)
on-close
(mf/use-callback #(st/emit! (modal/hide)))
(mf/use-fn #(st/emit! (modal/hide)))
on-submit
(mf/use-callback
(mf/use-fn
(mf/deps profile)
(partial on-submit profile))
on-email-change
(mf/use-callback
(fn [_ _]
(let [different-emails-error? (= (dma/get-in @form [:errors :email-2 :code]) :different-emails)
email-1 (dma/get-in @form [:clean-data :email-1])
email-2 (dma/get-in @form [:clean-data :email-2])]
(when (and different-emails-error? (= email-1 email-2))
(swap! form d/dissoc-in [:errors :email-2])))))]
(partial on-submit profile))]
[:div {:class (stl/css :modal-overlay)}
[:div {:class (stl/css :modal-container)}
@ -118,16 +102,14 @@
:name :email-1
:label (tr "modals.change-email.new-email")
:trim true
:show-success? true
:on-change-value on-email-change}]]
:show-success? true}]]
[:div {:class (stl/css :fields-row)}
[:& fm/input {:type "email"
:name :email-2
:label (tr "modals.change-email.confirm-email")
:trim true
:show-success? true
:on-change-value on-email-change}]]]
:show-success? true}]]]
[:div {:class (stl/css :modal-footer)}
[:div {:class (stl/css :action-buttons)

View file

@ -8,7 +8,7 @@
"Feedback form."
(:require-macros [app.main.style :as stl])
(:require
[app.common.spec :as us]
[app.common.schema :as sm]
[app.main.data.messages :as msg]
[app.main.refs :as refs]
[app.main.repo :as rp]
@ -17,25 +17,22 @@
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
[beicon.v2.core :as rx]
[cljs.spec.alpha :as s]
[rumext.v2 :as mf]))
(s/def ::content ::us/not-empty-string)
(s/def ::subject ::us/not-empty-string)
(s/def ::feedback-form
(s/keys :req-un [::subject ::content]))
(def ^:private schema:feedback-form
[:map {:title "FeedbackForm"}
[:subject [::sm/text {:max 250}]]
[:content [::sm/text {:max 5000}]]])
(mf/defc feedback-form
{::mf/private true}
[]
(let [profile (mf/deref refs/profile)
form (fm/use-form :spec ::feedback-form
:validators [(fm/validate-length :subject fm/max-length-allowed (tr "auth.name.too-long"))
(fm/validate-not-empty :subject (tr "auth.name.not-all-space"))])
form (fm/use-form :schema schema:feedback-form)
loading (mf/use-state false)
on-succes
(mf/use-callback
(mf/use-fn
(mf/deps profile)
(fn [_]
(reset! loading false)
@ -43,7 +40,7 @@
(swap! form assoc :data {} :touched {} :errors {})))
on-error
(mf/use-callback
(mf/use-fn
(mf/deps profile)
(fn [{:keys [code] :as error}]
(reset! loading false)
@ -52,7 +49,7 @@
(st/emit! (msg/error (tr "errors.generic"))))))
on-submit
(mf/use-callback
(mf/use-fn
(mf/deps profile)
(fn [form _]
(reset! loading true)
@ -106,8 +103,8 @@
(mf/defc feedback-page
[]
(mf/use-effect
#(dom/set-html-title (tr "title.settings.feedback")))
(mf/with-effect []
(dom/set-html-title (tr "title.settings.feedback")))
[:div {:class (stl/css :dashboard-settings)}
[:div {:class (stl/css :form-container)}

View file

@ -7,7 +7,6 @@
(ns app.main.ui.settings.options
(:require-macros [app.main.style :as stl])
(:require
[app.common.spec :as us]
[app.main.data.messages :as msg]
[app.main.data.users :as du]
[app.main.refs :as refs]
@ -15,14 +14,12 @@
[app.main.ui.components.forms :as fm]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
[cljs.spec.alpha :as s]
[rumext.v2 :as mf]))
(s/def ::lang (s/nilable ::us/string))
(s/def ::theme (s/nilable ::us/not-empty-string))
(s/def ::options-form
(s/keys :opt-un [::lang ::theme]))
(def ^:private schema:options-form
[:map {:title "OptionsForm"}
[:lang {:optional true} [:string {:max 20}]]
[:theme {:optional true} [:string {:max 250}]]])
(defn- on-success
[profile]
@ -41,7 +38,7 @@
(let [profile (mf/deref refs/profile)
initial (mf/with-memo [profile]
(update profile :lang #(or % "")))
form (fm/use-form :spec ::options-form
form (fm/use-form :schema schema:options-form
:initial initial)]
[:& fm/form {:class (stl/css :options-form)

View file

@ -7,14 +7,13 @@
(ns app.main.ui.settings.password
(:require-macros [app.main.style :as stl])
(:require
[app.common.spec :as us]
[app.common.schema :as sm]
[app.main.data.messages :as msg]
[app.main.data.users :as udu]
[app.main.store :as st]
[app.main.ui.components.forms :as fm]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
[cljs.spec.alpha :as s]
[rumext.v2 :as mf]))
(defn- on-error
@ -22,10 +21,10 @@
(case (:code (ex-data error))
:old-password-not-match
(swap! form assoc-in [:errors :password-old]
{:message (tr "errors.wrong-old-password")})
{:code "errors.wrong-old-password"})
:email-as-password
(swap! form assoc-in [:errors :password-1]
{:message (tr "errors.email-as-password")})
{:code "errors.email-as-password"})
(let [msg (tr "generic.error")]
(st/emit! (msg/error msg)))))
@ -47,40 +46,29 @@
:on-error (partial on-error form)})]
(st/emit! (udu/update-password params))))
(s/def ::password-1 ::us/not-empty-string)
(s/def ::password-2 ::us/not-empty-string)
(s/def ::password-old (s/nilable ::us/string))
(defn- password-equality
[errors data]
(let [password-1 (:password-1 data)
password-2 (:password-2 data)]
(cond-> errors
(and password-1 password-2 (not= password-1 password-2))
(assoc :password-2 {:message (tr "errors.password-invalid-confirmation")})
(and password-1 (> 8 (count password-1)))
(assoc :password-1 {:message (tr "errors.password-too-short")}))))
(s/def ::password-form
(s/keys :req-un [::password-1
::password-2
::password-old]))
(def ^:private schema:password-form
[:and
[:map {:title "PasswordForm"}
[:password-1 ::sm/password]
[:password-2 ::sm/password]
[:password-old ::sm/password]]
[:fn {:error/code "errors.password-invalid-confirmation"
:error/field :password-2}
(fn [{:keys [password-1 password-2]}]
(= password-1 password-2))]])
(mf/defc password-form
[]
(let [initial (mf/use-memo (constantly {:password-old nil}))
form (fm/use-form :spec ::password-form
:validators [(fm/validate-not-all-spaces :password-old (tr "auth.password-not-empty"))
(fm/validate-not-empty :password-1 (tr "auth.password-not-empty"))
(fm/validate-not-empty :password-2 (tr "auth.password-not-empty"))
password-equality]
:initial initial)]
(let [initial (mf/with-memo []
{:password-old ""
:password-1 ""
:password-2 ""})
form (fm/use-form :schema schema:password-form
:initial initial)]
[:& fm/form {:class (stl/css :password-form)
:on-submit on-submit
:form form}
[:div {:class (stl/css :fields-row)}
[:& fm/input
{:type "password"

View file

@ -7,7 +7,7 @@
(ns app.main.ui.settings.profile
(:require-macros [app.main.style :as stl])
(:require
[app.common.spec :as us]
[app.common.schema :as sm]
[app.config :as cf]
[app.main.data.messages :as msg]
[app.main.data.modal :as modal]
@ -18,14 +18,12 @@
[app.main.ui.components.forms :as fm]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
[cljs.spec.alpha :as s]
[rumext.v2 :as mf]))
(s/def ::fullname ::us/not-empty-string)
(s/def ::email ::us/email)
(s/def ::profile-form
(s/keys :req-un [::fullname ::email]))
(def ^:private schema:profile-form
[:map {:title "ProfileForm"}
[:fullname [::sm/text {:max 250}]]
[:email ::sm/email]])
(defn- on-submit
[form _event]
@ -37,19 +35,18 @@
;; --- Profile Form
(mf/defc profile-form
{::mf/private true}
[]
(let [profile (mf/deref refs/profile)
form (fm/use-form :spec ::profile-form
:initial profile
:validators [(fm/validate-length :fullname fm/max-length-allowed (tr "auth.name.too-long"))
(fm/validate-not-empty :fullname (tr "auth.name.not-all-space"))])
form (fm/use-form :schema schema:profile-form
:initial profile)
handle-show-change-email
(mf/use-callback
on-show-change-email
(mf/use-fn
#(modal/show! :change-email {}))
handle-show-delete-account
(mf/use-callback
on-show-delete-account
(mf/use-fn
#(modal/show! :delete-account {}))]
[:& fm/form {:on-submit on-submit
@ -62,7 +59,7 @@
:label (tr "dashboard.your-name")}]]
[:div {:class (stl/css :fields-row)
:on-click handle-show-change-email}
:on-click on-show-change-email}
[:& fm/input
{:type "email"
:name :email
@ -71,7 +68,7 @@
[:div {:class (stl/css :options)}
[:div.change-email
[:a {:on-click handle-show-change-email}
[:a {:on-click on-show-change-email}
(tr "dashboard.change-email")]]]]
[:> fm/submit-button*
@ -81,17 +78,25 @@
[:div {:class (stl/css :links)}
[:div {:class (stl/css :link-item)}
[:a {:on-click handle-show-delete-account
[:a {:on-click on-show-delete-account
:data-testid "remove-acount-btn"}
(tr "dashboard.remove-account")]]]]))
;; --- Profile Photo Form
(mf/defc profile-photo-form []
(let [file-input (mf/use-ref nil)
profile (mf/deref refs/profile)
photo (cf/resolve-profile-photo-url profile)
on-image-click #(dom/click (mf/ref-val file-input))
(mf/defc profile-photo-form
{::mf/private true}
[]
(let [input-ref (mf/use-ref nil)
profile (mf/deref refs/profile)
photo
(mf/with-memo [profile]
(cf/resolve-profile-photo-url profile))
on-image-click
(mf/use-fn
#(dom/click (mf/ref-val input-ref)))
on-file-selected
(fn [file]
@ -104,15 +109,17 @@
[:img {:src photo}]
[:& file-uploader {:accept "image/jpeg,image/png"
:multi false
:ref file-input
:ref input-ref
:on-selected on-file-selected
:data-testid "profile-image-input"}]]]))
;; --- Profile Page
(mf/defc profile-page []
(mf/defc profile-page
[]
(mf/with-effect []
(dom/set-html-title (tr "title.settings.profile")))
[:div {:class (stl/css :dashboard-settings)}
[:div {:class (stl/css :form-container)}
[:h2 (tr "labels.profile")]

View file

@ -8,7 +8,7 @@
(:require-macros [app.main.style :as stl])
(:require
[app.common.files.helpers :as cfh]
[app.common.spec :as us]
[app.common.schema :as sm]
[app.main.data.modal :as modal]
[app.main.data.workspace :as dw]
[app.main.store :as st]
@ -18,7 +18,6 @@
[app.main.ui.workspace.sidebar.assets.common :as cmm]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
[cljs.spec.alpha :as s]
[rumext.v2 :as mf]))
(mf/defc asset-group-title
@ -92,21 +91,18 @@
(compare key1 key2))))
assets)))
(s/def ::asset-name ::us/not-empty-string)
(s/def ::name-group-form
(s/keys :req-un [::asset-name]))
(def ^:private schema:group-form
[:map {:title "GroupForm"}
[:name [::sm/text {:max 250}]]])
(mf/defc name-group-dialog
{::mf/register modal/components
::mf/register-as :name-group-dialog}
[{:keys [path last-path accept] :as ctx
:or {path "" last-path ""}}]
(let [initial (mf/use-memo
(mf/deps last-path)
(constantly {:asset-name last-path}))
form (fm/use-form :spec ::name-group-form
:validators [(fm/validate-not-empty :asset-name (tr "auth.name.not-all-space"))
(fm/validate-length :asset-name fm/max-length-allowed (tr "auth.name.too-long"))]
(let [initial (mf/with-memo [last-path]
{:asset-name last-path})
form (fm/use-form :schema schema:group-form
:initial initial)
create? (empty? path)
@ -117,7 +113,7 @@
(mf/use-fn
(mf/deps form)
(fn [_]
(let [asset-name (get-in @form [:clean-data :asset-name])]
(let [asset-name (get-in @form [:clean-data :name])]
(if create?
(accept asset-name)
(accept path asset-name))
@ -135,7 +131,7 @@
[:div {:class (stl/css :modal-content)}
[:& fm/form {:form form :on-submit on-accept}
[:& fm/input {:name :asset-name
[:& fm/input {:name :name
:class (stl/css :input-wrapper)
:auto-focus? true
:label (tr "workspace.assets.group-name")

View file

@ -8,119 +8,146 @@
(:refer-clojure :exclude [uuid])
(:require
[app.common.data :as d]
[app.common.spec :as us]
[app.common.data.macros :as dm]
[app.common.schema :as sm]
[app.util.i18n :refer [tr]]
[cljs.spec.alpha :as s]
[cuerdas.core :as str]
[malli.core :as m]
[rumext.v2 :as mf]))
;; --- Handlers Helpers
(defn- interpret-problem
[acc {:keys [path pred via] :as problem}]
(cond
(and (empty? path)
(list? pred)
(= (first (last pred)) 'cljs.core/contains?))
(let [field (last (last pred))
path (conj path field)
root (first via)]
(assoc-in acc path {:code :missing :type :builtin :root root :field field}))
(defn- interpret-schema-problem
[acc {:keys [schema in value] :as problem}]
(let [props (merge (m/type-properties schema)
(m/properties schema))
field (or (first in) (:error/field props))]
(and (seq path) (seq via))
(let [field (first path)
code (last via)
root (first via)]
(assoc-in acc path {:code code :type :builtin :root root :field field}))
(if (contains? acc field)
acc
(cond
(nil? value)
(assoc acc field {:code "errors.field-missing"})
:else acc))
(contains? props :error/code)
(assoc acc field {:code (:error/code props)})
(declare create-form-mutator)
(contains? props :error/message)
(assoc acc field {:code (:error/message props)})
(defn use-form
[& {:keys [initial] :as opts}]
(let [state (mf/useState 0)
render (aget state 1)
(contains? props :error/fn)
(let [v-fn (:error/fn props)
code (v-fn problem)]
(assoc acc field {:code code}))
get-state (mf/use-callback
(mf/deps initial)
(fn []
{:data (if (fn? initial) (initial) initial)
:errors {}
:touched {}}))
(contains? props :error/validators)
(let [validators (:error/validators props)
props (reduce #(%2 %1 value) props validators)]
(assoc acc field {:code (d/nilv (:error/code props) "errors.invalid-data")}))
state-ref (mf/use-ref (get-state))
form (mf/use-memo (mf/deps initial) #(create-form-mutator state-ref render get-state opts))]
:else
(assoc acc field {:code "errors.invalid-data"})))))
(mf/use-effect
(mf/deps initial)
(defn- use-rerender-fn
[]
(let [state (mf/useState 0)
render-fn (aget state 1)]
(mf/use-fn
(mf/deps render-fn)
(fn []
(if (fn? initial)
(swap! form update :data merge (initial))
(swap! form update :data merge initial))))
(render-fn inc)))))
form))
(defn- apply-validators
[validators state errors]
(reduce (fn [errors validator-fn]
(merge errors (validator-fn errors (:data state))))
errors
validators))
(defn- wrap-update-fn
[f {:keys [spec validators]}]
(defn- collect-schema-errors
[schema validators state]
(let [explain (sm/explain schema (:data state))
errors (->> (reduce interpret-schema-problem {} (:errors explain))
(apply-validators validators state))]
(-> (:errors state)
(merge errors)
(d/without-nils)
(not-empty))))
(defn- wrap-update-schema-fn
[f {:keys [schema validators]}]
(fn [& args]
(let [state (apply f args)
cleaned (s/conform spec (:data state))
problems (when (= ::s/invalid cleaned)
(::s/problems (s/explain-data spec (:data state))))
errors (reduce interpret-problem {} problems)
errors (reduce (fn [errors vf]
(merge errors (vf errors (:data state))))
errors
validators)
errors (merge (:errors state) errors)
errors (d/without-nils errors)]
(let [state (apply f args)
cleaned (sm/decode schema (:data state))
valid? (sm/validate schema cleaned)
errors (when-not valid?
(collect-schema-errors schema validators state))]
(assoc state
:errors errors
:clean-data (when (not= cleaned ::s/invalid) cleaned)
:valid (and (empty? errors)
(not= cleaned ::s/invalid))))))
:clean-data (when valid? cleaned)
:valid (and (not errors) valid?)))))
(defn- create-form-mutator
[state-ref render get-state opts]
[internal-state rerender-fn wrap-update-fn initial opts]
(reify
IDeref
(-deref [_]
(mf/ref-val state-ref))
(mf/ref-val internal-state))
IReset
(-reset! [_ new-value]
(if (nil? new-value)
(mf/set-ref-val! state-ref (get-state))
(mf/set-ref-val! state-ref new-value))
(render inc))
(mf/set-ref-val! internal-state (if (fn? initial) (initial) initial))
(mf/set-ref-val! internal-state new-value))
(rerender-fn))
ISwap
(-swap! [_ f]
(let [f (wrap-update-fn f opts)]
(mf/set-ref-val! state-ref (f (mf/ref-val state-ref)))
(render inc)))
(mf/set-ref-val! internal-state (f (mf/ref-val internal-state)))
(rerender-fn)))
(-swap! [_ f x]
(let [f (wrap-update-fn f opts)]
(mf/set-ref-val! state-ref (f (mf/ref-val state-ref) x))
(render inc)))
(mf/set-ref-val! internal-state (f (mf/ref-val internal-state) x))
(rerender-fn)))
(-swap! [_ f x y]
(let [f (wrap-update-fn f opts)]
(mf/set-ref-val! state-ref (f (mf/ref-val state-ref) x y))
(render inc)))
(mf/set-ref-val! internal-state (f (mf/ref-val internal-state) x y))
(rerender-fn)))
(-swap! [_ f x y more]
(let [f (wrap-update-fn f opts)]
(mf/set-ref-val! state-ref (apply f (mf/ref-val state-ref) x y more))
(render inc)))))
(mf/set-ref-val! internal-state (apply f (mf/ref-val internal-state) x y more))
(rerender-fn)))))
(defn use-form
[& {:keys [initial] :as opts}]
(let [rerender-fn (use-rerender-fn)
internal-state
(mf/use-ref nil)
form-mutator
(mf/with-memo [initial]
(create-form-mutator internal-state rerender-fn wrap-update-schema-fn initial opts))]
;; Initialize internal state once
(mf/with-effect []
(mf/set-ref-val! internal-state
{:data {}
:errors {}
:touched {}}))
(mf/with-effect [initial]
(if (fn? initial)
(swap! form-mutator update :data merge (initial))
(swap! form-mutator update :data merge initial)))
form-mutator))
(defn on-input-change
([form field value]
@ -150,8 +177,8 @@
(mf/defc field-error
[{:keys [form field type]
:as props}]
(let [{:keys [message] :as error} (get-in form [:errors field])
touched? (get-in form [:touched field])
(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
@ -164,12 +191,6 @@
(defn error-class
[form field]
(when (and (get-in form [:errors field])
(get-in form [:touched field]))
(when (and (dm/get-in form [:errors field])
(dm/get-in form [:touched field]))
"invalid"))
;; --- Form Specs and Conformers
(s/def ::email ::us/email)
(s/def ::not-empty-string ::us/not-empty-string)
(s/def ::color ::us/rgb-color-str)

View file

@ -76,20 +76,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit"
msgstr "OpenID"
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space"
msgstr "Die naam moet 'n ander karakter as spasie bevat."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "Die naam moet hoogstens 250 karakters bevat."
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password"
msgstr "Tik 'n nuwe wagwoord in"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "Die hersteltoken is ongeldig."
#: src/app/main/ui/auth/recovery.cljs
@ -118,10 +110,6 @@ msgstr "Wagwoord"
msgid "auth.password-length-hint"
msgstr "Ten minste 8 karakters"
#: src/app/main/ui/auth/register.cljs
msgid "auth.password-not-empty"
msgstr "Wagwoord moet 'n ander karakter as spasie bevat."
msgid "auth.privacy-policy"
msgstr "Privaatheidsbeleid"
@ -275,7 +263,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Genereer nuwe token"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "Toegangstoken is suksesvol geskep."
#: src/app/main/ui/settings/access-tokens.cljs
@ -286,10 +274,6 @@ msgstr "Druk die knoppie \"Genereer nuwe token\" om een te genereer."
msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Jy het tot dusver geen tokens nie."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.errors-required-name"
msgstr "Die naam word vereis"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 dae"

View file

@ -78,7 +78,7 @@ msgid "auth.new-password"
msgstr "اكتب كلمة مرور جديدة"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "رمز الاسترداد غير صالح."
#: src/app/main/ui/auth/recovery.cljs
@ -743,11 +743,11 @@ msgstr "يحتوي البريد الإلكتروني «%s» على العديد
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "أدخل بريدًا إلكترونيًا صالحًا من فضلك"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "يجب أن يتطابق البريد الإلكتروني للتأكيد"
msgid "errors.email-spam-or-permanent-bounces"
@ -2292,10 +2292,6 @@ msgstr "زيادة عدسة التكبير"
msgid "shortcuts.zoom-selected"
msgstr "كبر المحدد"
#: src/app/main/ui/dashboard/team.cljs
msgid "team.webhooks.max-length"
msgstr "يجب الا يزيد اسم الويبهوك على 2048 حرفا"
#: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files"
msgstr "%s - Penpotعنوان ملفات لوحة القيادة"
@ -4307,14 +4303,6 @@ msgstr "الرمز منسوخ"
msgid "auth.login-tagline"
msgstr "Penpot هو أداة تصميم مجانية ومفتوحة المصدر للتعاون بين التصميم والبرمجة"
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space"
msgstr "يجب أن يحتوي الاسم على بعض الأحرف غير الفراغات."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "يجب أن يحتوي الاسم على 250 حرفًا كحد أقصى."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.empty.add-one"
msgstr "اضغط على الزر \"إنشاء رمز جديد\" لإنشاء واحد."
@ -4332,5 +4320,5 @@ msgid "dashboard.access-tokens.create"
msgstr "قم بإنشاء رمز جديد"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "تم إنشاء رمز الوصول بنجاح."

View file

@ -77,5 +77,5 @@ msgid "auth.new-password"
msgstr "নতুন পাসওয়ার্ড টাইপ করুন"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "রিকভারি টোকেন সঠিক নয়।"

View file

@ -81,7 +81,7 @@ msgid "auth.new-password"
msgstr "Escriviu una contrasenya nova"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "El codi de recuperació no és vàlid."
#: src/app/main/ui/auth/recovery.cljs
@ -722,7 +722,7 @@ msgid "errors.email-has-permanent-bounces"
msgstr "El correu «%s» té molts informes de retorn permanents."
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "El correu de confirmació ha de coincidir"
msgid "errors.email-spam-or-permanent-bounces"

View file

@ -76,20 +76,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit"
msgstr "OpenID"
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space"
msgstr "Název musí obsahovat jiný znak než mezeru."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "Název musí obsahovat maximálně 250 znaků."
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password"
msgstr "Zadejte nové heslo"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "Token pro obnovení je neplatný."
#: src/app/main/ui/auth/recovery.cljs
@ -116,10 +108,6 @@ msgstr "Heslo"
msgid "auth.password-length-hint"
msgstr "Minimálně 8 znaků"
#: src/app/main/ui/auth/register.cljs
msgid "auth.password-not-empty"
msgstr "Heslo musí obsahovat jiný znak než mezeru."
msgid "auth.privacy-policy"
msgstr "Zásady ochrany osobních údajů"
@ -278,7 +266,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Generovat nový token"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "Přístupový token byl úspěšně vytvořen."
#: src/app/main/ui/settings/access-tokens.cljs
@ -291,10 +279,6 @@ msgstr ""
msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Zatím nemáte žádné tokeny."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.errors-required-name"
msgstr "Jméno je povinné"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 dní"
@ -865,11 +849,11 @@ msgstr "E-mail «%s» má mnoho trvalých zpráv o nedoručitelnosti."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "Zadejte prosím platný email"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "Potvrzovací e-mail se musí shodovat"
msgid "errors.email-spam-or-permanent-bounces"
@ -2974,10 +2958,6 @@ msgstr "Zvětšení zoomu"
msgid "shortcuts.zoom-selected"
msgstr "Přiblížit na vybrané"
#: src/app/main/ui/dashboard/team.cljs
msgid "team.webhooks.max-length"
msgstr "Název webhooku musí obsahovat maximálně 2048 znaků."
#: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files"
msgstr "%s - Penpot"

View file

@ -81,7 +81,7 @@ msgid "auth.new-password"
msgstr "Indtast et nyt kodeord"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "Genopretningspoletten er ugyldig."
#: src/app/main/ui/auth/recovery.cljs

View file

@ -86,32 +86,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit"
msgstr "OpenID"
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs,
#: src/app/main/ui/dashboard/team_form.cljs,
#: src/app/main/ui/onboarding/team_choice.cljs,
#: src/app/main/ui/settings/access_tokens.cljs,
#: src/app/main/ui/settings/feedback.cljs,
#: src/app/main/ui/settings/profile.cljs,
#: src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space"
msgstr "Der Name darf keine Leerzeichen enthalten."
#: src/app/main/ui/auth/register.cljs,
#: src/app/main/ui/dashboard/team_form.cljs,
#: src/app/main/ui/onboarding/team_choice.cljs,
#: src/app/main/ui/settings/access_tokens.cljs,
#: src/app/main/ui/settings/feedback.cljs,
#: src/app/main/ui/settings/profile.cljs,
#: src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "Der Name darf höchstens 250 Zeichen lang sein."
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password"
msgstr "Geben Sie ein neues Passwort ein"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "Der Wiederherstellungscode ist ungültig."
#: src/app/main/ui/auth/recovery.cljs
@ -141,10 +121,6 @@ msgstr "Passwort"
msgid "auth.password-length-hint"
msgstr "Mindestens 8 Zeichen"
#: src/app/main/ui/auth/register.cljs
msgid "auth.password-not-empty"
msgstr "Das Passwort darf keine Leerzeichen enthalten."
msgid "auth.privacy-policy"
msgstr "Datenschutzerklärung"
@ -305,7 +281,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Neues Token generieren"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "Der Zugangstoken wurde erfolgreich erstellt."
#: src/app/main/ui/settings/access-tokens.cljs
@ -318,10 +294,6 @@ msgstr ""
msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Du hast bisher keine Token."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.errors-required-name"
msgstr "Der Name ist erforderlich"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 Tage"
@ -921,11 +893,11 @@ msgstr ""
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "Geben Sie bitte eine gültige E-Mail-Adresse ein"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "Bestätigungs-E-Mail muss übereinstimmen"
msgid "errors.email-spam-or-permanent-bounces"
@ -3099,10 +3071,6 @@ msgstr "Ansicht mit Zoomwerkzeug vergrößern"
msgid "shortcuts.zoom-selected"
msgstr "Zur Auswahl zoomen"
#: src/app/main/ui/dashboard/team.cljs
msgid "team.webhooks.max-length"
msgstr "Der Name des Webhooks darf höchstens 2048 Zeichen lang sein."
#: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files"
msgstr "%s - Penpot"

View file

@ -77,7 +77,7 @@ msgid "auth.new-password"
msgstr "Πληκτρολογήστε έναν νέο κωδικό πρόσβασης."
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "Ο κωδικός ανάκτησης δεν είναι έγκυρος."
#: src/app/main/ui/auth/recovery.cljs
@ -384,7 +384,7 @@ msgid "errors.email-has-permanent-bounces"
msgstr "Το email «%s» έχει πολλές μόνιμες αναφορές αναπήδησης."
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "Το email επιβεβαίωσης πρέπει να ταιριάζει"
#: src/app/main/ui/auth/verify_token.cljs,

View file

@ -98,19 +98,24 @@ msgid "auth.login-with-oidc-submit"
msgstr "OpenID"
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space"
msgid "errors.field-not-all-whitespace"
msgstr "The name must contain some character other than space."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "The name must contain at most 250 characters."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/setti ngs/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "errors.field-max-length"
msgstr[0] "Must contain at most 1 characters."
msgstr[1] "Must contain at most %s characters."
msgid "errors.field-min-length"
msgstr[0] "Must contain at least 1 character."
msgstr[1] "Must contain at least %s characters."
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password"
msgstr "Type a new password"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "The recovery token is invalid."
#: src/app/main/ui/auth/recovery.cljs
@ -137,10 +142,6 @@ msgstr "Password"
msgid "auth.password-length-hint"
msgstr "At least 8 characters"
#: src/app/main/ui/auth/register.cljs
msgid "auth.password-not-empty"
msgstr "Password must contain some character other than space."
msgid "auth.privacy-policy"
msgstr "Privacy policy"
@ -309,7 +310,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Generate new token"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "Access token created successfully."
#: src/app/main/ui/settings/access-tokens.cljs
@ -320,10 +321,6 @@ msgstr "Press the button \"Generate new token\" to generate one."
msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "You have no tokens so far."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.errors-required-name"
msgstr "The name is required"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 days"
@ -898,11 +895,11 @@ msgid "errors.email-has-permanent-bounces"
msgstr "The email «%s» has many permanent bounce reports."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs, src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "Enter a valid email please"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "Confirmation email must match"
msgid "errors.email-spam-or-permanent-bounces"
@ -3131,10 +3128,6 @@ msgstr "Zoom lense increase"
msgid "shortcuts.zoom-selected"
msgstr "Zoom to selected"
#: src/app/main/ui/dashboard/team.cljs
msgid "team.webhooks.max-length"
msgstr "The webhook name must contain at most 2048 characters."
#: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files"
msgstr "%s - Penpot"

View file

@ -98,19 +98,24 @@ msgid "auth.login-with-oidc-submit"
msgstr "OpenID"
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space"
msgstr "El nombre debe contener algún carácter diferente de espacio"
msgid "errors.field-not-all-whitespace"
msgstr "Debe contener algún carácter diferente de espacio."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "El nombre debe contener como máximo 250 caracteres."
msgid "errors.field-max-length"
msgstr[0] "Debe contener como máximo 1 caracter."
msgstr[1] "Debe contener como máximo %s caracteres."
msgid "errors.field-min-length"
msgstr[0] "Debe contener como mínimo 1 caracter."
msgstr[1] "Debe contener como mínimo %s caracteres."
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password"
msgstr "Introduce la nueva contraseña"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "El código de recuperación no es válido."
#: src/app/main/ui/auth/recovery.cljs
@ -139,10 +144,6 @@ msgstr "Contraseña"
msgid "auth.password-length-hint"
msgstr "8 caracteres como mínimo"
#: src/app/main/ui/auth/register.cljs
msgid "auth.password-not-empty"
msgstr "La contraseña debe contener algún caracter diferente de espacio"
msgid "auth.privacy-policy"
msgstr "Política de privacidad"
@ -315,7 +316,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Generar nuevo token"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "Access token creado con éxito."
#: src/app/main/ui/settings/access-tokens.cljs
@ -326,10 +327,6 @@ msgstr "Pulsa el botón \"Generar nuevo token\" para generar uno."
msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Todavía no tienes ningún token."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.errors-required-name"
msgstr "El nombre es obligatorio"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 días"
@ -924,11 +921,11 @@ msgid "errors.email-has-permanent-bounces"
msgstr "El correo electrónico «%s» tiene varios reportes de rebote permanente."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs, src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "Por favor, escribe un email válido"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "El correo de confirmación debe coincidir"
msgid "errors.email-spam-or-permanent-bounces"
@ -3188,10 +3185,6 @@ msgstr "Incrementar zoom a objetivo"
msgid "shortcuts.zoom-selected"
msgstr "Zoom a selección"
#: src/app/main/ui/dashboard/team.cljs
msgid "team.webhooks.max-length"
msgstr "El nombre del webhook debe contener como máximo 2048 caracteres."
#: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files"
msgstr "%s - Penpot"

View file

@ -77,19 +77,20 @@ msgid "auth.login-with-oidc-submit"
msgstr "Open ID"
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space"
msgid "errors.field-not-all-whitespace"
msgstr "El nombre debe contener algún carácter distinto al del espacio."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "El nombre debe contener como máximo 250 caracteres."
msgid "errors.field-max-length"
msgstr[0] "El nombre debe contener como máximo 1 caracter."
msgstr[1] "El nombre debe contener como máximo %s caracteres."
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password"
msgstr "Escribe una nueva contraseña"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "El token de recuperación no es válido."
#: src/app/main/ui/auth/recovery.cljs
@ -118,10 +119,6 @@ msgstr "Contraseña"
msgid "auth.password-length-hint"
msgstr "Al menos 8 carácteres"
#: src/app/main/ui/auth/register.cljs
msgid "auth.password-not-empty"
msgstr "La contraseña debe contener algún carácter que no sea espacio."
msgid "auth.privacy-policy"
msgstr "Política de privacidad"
@ -280,7 +277,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Generar nuevo token"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "Token de acceso creado correctamente."
#: src/app/main/ui/settings/access-tokens.cljs
@ -291,10 +288,6 @@ msgstr "Presione el botón \"Generar nuevo token\" para generar uno."
msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "No tienes tokens hasta el momento."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.errors-required-name"
msgstr "El nombre es requerido"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 días"

View file

@ -81,7 +81,7 @@ msgid "auth.new-password"
msgstr "Sartu Pasahitz berria"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "Berreskuratzeko kodea ez da zuzena."
#: src/app/main/ui/auth/recovery.cljs
@ -758,11 +758,11 @@ msgstr "«%s» helbideak ez ditu mezuak ondo jasotzen, itzuli egiten ditu."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "Mesedez, idatzi eposta helbide zuzen bat"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "Egiaztapenereko epostak bat etorri behar du aurrekoarekin"
msgid "errors.email-spam-or-permanent-bounces"

View file

@ -81,7 +81,7 @@ msgid "auth.new-password"
msgstr "یک رمزعبور جدید تایپ کنید"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "توکن بازیابی نامعتبر است."
#: src/app/main/ui/auth/recovery.cljs
@ -728,7 +728,7 @@ msgid "errors.email-as-password"
msgstr "شما نمی‌توانید از ایمیل خود به عنوان رمزعبور استفاده کنید"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "ایمیل تأیید باید مطابقت داشته باشد"
#: src/app/main/ui/auth/verify_token.cljs,

View file

@ -81,7 +81,7 @@ msgid "auth.new-password"
msgstr "Syötä uusi salasana"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "Palautustunnus on virheellinen."
#: src/app/main/ui/auth/recovery.cljs

View file

@ -76,20 +76,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit"
msgstr "OpenID"
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space"
msgstr "Le nom doit contenir au moins un caractère autre que l'espace."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "Le nom ne doit pas contenir plus de 250 caractères."
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password"
msgstr "Saisissez un nouveau mot de passe"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "Le code de récupération nest pas valide."
#: src/app/main/ui/auth/recovery.cljs
@ -116,10 +108,6 @@ msgstr "Mot de passe"
msgid "auth.password-length-hint"
msgstr "Au moins 8 caractères"
#: src/app/main/ui/auth/register.cljs
msgid "auth.password-not-empty"
msgstr "Le mot de passe doit contenir au moins un caractère autre que l'espace."
msgid "auth.privacy-policy"
msgstr "Politique de confidentialité"
@ -271,7 +259,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Générer un nouveau jeton"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "Jeton d'accès créé avec succès."
#: src/app/main/ui/settings/access-tokens.cljs
@ -282,10 +270,6 @@ msgstr "Pressez le bouton \"Générer un nouveau jeton\" pour en générer un."
msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Vous n'avez pas encore de jeton."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.errors-required-name"
msgstr "Le nom est requis"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 jours"
@ -874,11 +858,11 @@ msgid "errors.email-has-permanent-bounces"
msgstr "L'adresse e-mail « %s » a un taux de rebond trop élevé."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs, src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "Veuillez entrer une adresse mail valide"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "Ladresse email de confirmation doit correspondre"
msgid "errors.email-spam-or-permanent-bounces"
@ -2930,10 +2914,6 @@ msgstr "Augmenter le zoom"
msgid "shortcuts.zoom-selected"
msgstr "Zoomer sur la sélection"
#: src/app/main/ui/dashboard/team.cljs
msgid "team.webhooks.max-length"
msgstr "Le nom du webhook ne peut pas contenir plus de 2048 caractères."
#: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files"
msgstr "%s - Penpot"

View file

@ -81,7 +81,7 @@ msgid "auth.new-password"
msgstr "Escribe un contrasinal novo"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "O código de recuperación non é correcto."
#: src/app/main/ui/auth/recovery.cljs

View file

@ -76,20 +76,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit"
msgstr "shaidar buxewa"
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space"
msgstr "dole suna ya qumshi waxansu alamimon rubutu, sannan tazara."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "suna dole ya qunshi alamomin rubutu 250."
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password"
msgstr "sanya sabuwar lambar tsaro"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "lambar tsaron da ka sanya ba daidai ba ce."
#: src/app/main/ui/auth/recovery.cljs
@ -252,7 +244,7 @@ msgid "dashboard.access-tokens.create"
msgstr "samo sabuwar lambar tsaro"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "ka sami lambar tsaron da aka yi."
#: src/app/main/ui/settings/access-tokens.cljs
@ -265,10 +257,6 @@ msgstr ""
msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "ba ka da wasu lambobin tsaro yanzu."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.errors-required-name"
msgstr "ana buqatar suna"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days"
msgstr "kwanaki 180"
@ -819,11 +807,11 @@ msgid "errors.email-has-permanent-bounces"
msgstr "imel «%s» na da bayanan matsaloli na dindindin."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs, src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "sanya imel mai amfani"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "tabbata imel xinka ya yi daidai"
msgid "errors.email-spam-or-permanent-bounces"
@ -2790,10 +2778,6 @@ msgstr "Zuko karuwar ido"
msgid "shortcuts.zoom-selected"
msgstr "Zuko wanda aka zaba"
#: src/app/main/ui/dashboard/team.cljs
msgid "team.webhooks.max-length"
msgstr "Sunan shafin yanar gizon zai kunshi a mafi yawa haruffa 2048."
#: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files"
msgstr "%s - Tukunyar aje biro"

View file

@ -83,32 +83,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit"
msgstr "OpenID Connect"
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs,
#: src/app/main/ui/dashboard/team_form.cljs,
#: src/app/main/ui/onboarding/team_choice.cljs,
#: src/app/main/ui/settings/access_tokens.cljs,
#: src/app/main/ui/settings/feedback.cljs,
#: src/app/main/ui/settings/profile.cljs,
#: src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space"
msgstr "השם חייב להכיל תווים שאינם רווחים."
#: src/app/main/ui/auth/register.cljs,
#: src/app/main/ui/dashboard/team_form.cljs,
#: src/app/main/ui/onboarding/team_choice.cljs,
#: src/app/main/ui/settings/access_tokens.cljs,
#: src/app/main/ui/settings/feedback.cljs,
#: src/app/main/ui/settings/profile.cljs,
#: src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "השם חייב להכיל 250 תווים לכל היותר."
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password"
msgstr "נא להקליד סיסמה חדשה"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "אסימון השחזור שגוי."
#: src/app/main/ui/auth/recovery.cljs
@ -135,10 +115,6 @@ msgstr "סיסמה"
msgid "auth.password-length-hint"
msgstr "8 תווים לפחות"
#: src/app/main/ui/auth/register.cljs
msgid "auth.password-not-empty"
msgstr "הסיסמה חייבת להכיל תווים שאינם רווחים."
msgid "auth.privacy-policy"
msgstr "מדיניות פרטיות"
@ -293,7 +269,7 @@ msgid "dashboard.access-tokens.create"
msgstr "יצירת אסימון חדש"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "אסימון הגישה נוצר בהצלחה."
#: src/app/main/ui/settings/access-tokens.cljs
@ -304,10 +280,6 @@ msgstr "נא ללחוץ על הכפתור „יצירת אסימון חדש”
msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "אין לך אסימונים עדיין."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.errors-required-name"
msgstr "השם הוא בגדר חובה"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 יום"
@ -889,11 +861,11 @@ msgstr "לכתובת הדוא״ל „%s” יש יותר מדי דוחות הח
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "נא למלא כתובת דוא״ל תקפה בבקשה"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "כתובת הדוא״ל לאימות חייבת להיות תואמת"
msgid "errors.email-spam-or-permanent-bounces"
@ -3009,10 +2981,6 @@ msgstr "הגדלת עדשת תקריב"
msgid "shortcuts.zoom-selected"
msgstr "התמקדות על הנבחר"
#: src/app/main/ui/dashboard/team.cljs
msgid "team.webhooks.max-length"
msgstr "אורך שם ההתליה הוא עד 2048 תווים."
#: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files"
msgstr "%s - Penpot"

View file

@ -80,7 +80,7 @@ msgid "auth.new-password"
msgstr "Unesi novu lozinku"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "Token za oporavak je nevažeći."
#: src/app/main/ui/auth/recovery.cljs
@ -715,7 +715,7 @@ msgid "errors.email-has-permanent-bounces"
msgstr "E-pmail «%s» ima mnogo trajnih izvješća o odbijanju."
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "E-mail za potvrdu mora odgovarati"
msgid "errors.email-spam-or-permanent-bounces"

View file

@ -76,32 +76,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit"
msgstr "OpenID Connect"
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs,
#: src/app/main/ui/dashboard/team_form.cljs,
#: src/app/main/ui/onboarding/team_choice.cljs,
#: src/app/main/ui/settings/access_tokens.cljs,
#: src/app/main/ui/settings/feedback.cljs,
#: src/app/main/ui/settings/profile.cljs,
#: src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space"
msgstr "Nama harus berisi beberapa karakter selain spasi."
#: src/app/main/ui/auth/register.cljs,
#: src/app/main/ui/dashboard/team_form.cljs,
#: src/app/main/ui/onboarding/team_choice.cljs,
#: src/app/main/ui/settings/access_tokens.cljs,
#: src/app/main/ui/settings/feedback.cljs,
#: src/app/main/ui/settings/profile.cljs,
#: src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "Nama harus berisi setidaknya 250 karakter."
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password"
msgstr "Ketik kata sandi baru"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "Token pemulihan tidak sah."
#: src/app/main/ui/auth/recovery.cljs
@ -129,10 +109,6 @@ msgstr "Kata sandi"
msgid "auth.password-length-hint"
msgstr "Setidaknya 8 karakter"
#: src/app/main/ui/auth/register.cljs
msgid "auth.password-not-empty"
msgstr "Kata sandi harus berisi beberapa karakter selain spasi."
msgid "auth.privacy-policy"
msgstr "Kebijakan privasi"
@ -291,7 +267,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Buat token baru"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "Token akses berhasil dibuat."
#: src/app/main/ui/settings/access-tokens.cljs
@ -302,10 +278,6 @@ msgstr "Tekan tombol \"Buat token baru\" untuk membuat token."
msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Anda belum memiliki token."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.errors-required-name"
msgstr "Nama diperlukan"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 hari"
@ -878,11 +850,11 @@ msgstr "Surel “%s” memiliki banyak laporan lompatan permanen."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "Silakan menyediakan surel yang valid"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "Surel konfirmasi harus cocok"
msgid "errors.email-spam-or-permanent-bounces"
@ -2964,10 +2936,6 @@ msgstr "Tambahkan lensa zum"
msgid "shortcuts.zoom-selected"
msgstr "Zum ke terpilih"
#: src/app/main/ui/dashboard/team.cljs
msgid "team.webhooks.max-length"
msgstr "Nama webhook berisi sampai 2048 karakter."
#: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files"
msgstr "%s - Penpot"

View file

@ -70,20 +70,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit"
msgstr "Mepe ID"
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space"
msgstr "Aha ga-enweriri ụfọdụ mkpụrụ edemede karịa oghere ."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "Aha ga-enweriri ọ karịa mkpụrụ okwu narị abụọ na iri ise"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password"
msgstr "Pinye akara mpịbanye ọhụrụ"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "Ọdịmara e nweghachitere adabaghị ."
#: src/app/main/ui/auth/recovery.cljs
@ -106,10 +98,6 @@ msgstr "Sonyere n'otu nke ọma"
msgid "auth.password-length-hint"
msgstr "Ọ karịa mkpụrụ ederede asatọ"
#: src/app/main/ui/auth/register.cljs
msgid "auth.password-not-empty"
msgstr "Akara mpịbanye ga-enweriri ụfọdụ leta/akara mpị karịa oghere ."
msgid "auth.privacy-policy"
msgstr "Iwu oñiño onwe"
@ -245,17 +233,13 @@ msgid "dashboard.access-tokens.create"
msgstr "Mepụta ọdịmara ọhụrụ"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "Mmepụtara ọdịmara nnweta gara nke ọma ."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.empty.add-one"
msgstr "Pịa mpi \"Nweta ọdịmara ọhụrụ \" inweta otu ."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.errors-required-name"
msgstr "A chọrọ aha"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days"
msgstr "Mkpụrụ ụbọchị narị na iri asatọ"
@ -724,11 +708,11 @@ msgid "errors.email-has-permanent-bounces"
msgstr "Ozi-n «%s» nwere ọtụtụ ozi nkọwa mbịaghachigide."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs, src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "Debanye aha ozi-n dabara adaba"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "Ozi-n nnabata ga-adabrịrị"
msgid "errors.email-spam-or-permanent-bounces"

View file

@ -81,7 +81,7 @@ msgid "auth.new-password"
msgstr "Inserisci una nuova password"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "Il codice di recupero non è valido."
#: src/app/main/ui/auth/recovery.cljs
@ -706,7 +706,7 @@ msgid "errors.email-as-password"
msgstr "Non è possibile utilizzare il tuo indirizzo e-mail come password"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "L'indirizzo e-mail di conferma deve corrispondere"
msgid "errors.email-spam-or-permanent-bounces"

View file

@ -77,7 +77,7 @@ msgid "auth.new-password"
msgstr "新しいパスワードを入力"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "リカバリコードが無効です。"
#: src/app/main/ui/auth/recovery.cljs
@ -519,7 +519,7 @@ msgid "errors.email-has-permanent-bounces"
msgstr "メールアドレス «%s» には多くの受信失敗レポートがあります。"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "メールアドレスは同じものを入力する必要があります"
msgid "errors.email-spam-or-permanent-bounces"

View file

@ -683,7 +683,7 @@ msgstr "데모 서비스입니다. 실제 작업에 사용하지 마십시오.
"주기적으로 삭제될 것입니다."
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "복구 토큰이 유효하지 않습니다."
msgid "common.share-link.destroy-link"
@ -717,14 +717,6 @@ msgstr "개인용 엑세스 토큰"
msgid "dashboard.access-tokens.expired-on"
msgstr "%s에 만료되었습니다"
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "이름은 최대 250자까지만 입력 가능합니다."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.errors-required-name"
msgstr "이름을 입력하십시오"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.copied-success"
msgstr "복사된 토큰"
@ -754,8 +746,10 @@ msgid "auth.login-tagline"
msgstr "펜팟은 디자인과 코딩의 협업을 위한 무료 오픈소스 디자인 도구입니다"
#: src/app/main/ui/auth/register.cljs
msgid "auth.password-not-empty"
msgstr "비밀번호는 공백 이외의 글자를 포함해야 합니다."
#, markdown
msgid "auth.terms-privacy-agreement-md"
msgstr "새로운 계정을 생성하시면, 사용자는 펜팟의 [서비스 정책](%s)과 [개인 정보 "
"정책](%s)에 동의하는 것으로 간주됩니다."
#: src/app/main/ui/dashboard/projects.cljs
msgid "dasboard.team-hero.text"
@ -774,16 +768,12 @@ msgstr "실습용 튜토리얼"
msgid "auth.login-account-title"
msgstr "내 계정에 로그인하기"
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space"
msgstr "이름은 공백 이외의 글자를 포함해야 합니다."
#: src/app/main/ui/dashboard/projects.cljs
msgid "dasboard.tutorial-hero.info"
msgstr "본 실습용 튜토리얼을 통해 펜팟의 기본 기능에 대하여 재미있게 학습하십시오."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "엑세스 토큰이 성공적으로 생성되었습니다."
#: src/app/main/ui/settings/access-tokens.cljs

View file

@ -83,7 +83,7 @@ msgstr "Įveskite naują slaptažodį"
#: src/app/main/ui/auth/recovery.cljs
#, fuzzy
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "Atkūrimo prieigos raktas neteisingas."
#: src/app/main/ui/auth/recovery.cljs

View file

@ -85,20 +85,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit"
msgstr "AtvērtoID (OpenID)"
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space"
msgstr "Nosaukumam jāsatur simboli, kas nav atstarpe."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "Nosaukumus nedrīkst pārsniegt 250 simbolus."
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password"
msgstr "Ierakstiet jaunu paroli"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "Atkopšanas tekstvienība nav derīga."
#: src/app/main/ui/auth/recovery.cljs
@ -127,10 +119,6 @@ msgstr "Parole"
msgid "auth.password-length-hint"
msgstr "Vismaz 8 rakstzīmes"
#: src/app/main/ui/auth/register.cljs
msgid "auth.password-not-empty"
msgstr "Parolē ir jābūt arī citām rakstzīmēm bez atstarpes."
msgid "auth.privacy-policy"
msgstr "Privātuma politika"
@ -287,7 +275,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Izveidot jaunu pilnvaru"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "Piekļuves pilnvara ir veiksmīgi izveidota."
#: src/app/main/ui/settings/access-tokens.cljs
@ -298,10 +286,6 @@ msgstr "Jānospiež poga \"Izveidot jaunu pilnvaru\", lai izveidotu kādu."
msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Pagaidām vēl nav pilnvaru."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.errors-required-name"
msgstr "Nosaukums ir obligāts"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 dienas"
@ -890,11 +874,11 @@ msgstr "E-pastam “%s” ir daudz pastāvīgu atlēcienu atskaišu."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "Lūgums ievadīt derīgu e-pasta adresi"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "Apstiprinājuma e-pastam jāatbilst"
msgid "errors.email-spam-or-permanent-bounces"
@ -3062,10 +3046,6 @@ msgstr "Tālummaiņas palielinājums"
msgid "shortcuts.zoom-selected"
msgstr "Tālummainīt uz atlasi"
#: src/app/main/ui/dashboard/team.cljs
msgid "team.webhooks.max-length"
msgstr "Tīmekļa aizķeres nosaukumā drīkst būt ne vairāk kā 2048 rakstzīmes."
#: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files"
msgstr "%s - Penpot"

View file

@ -81,7 +81,7 @@ msgid "auth.new-password"
msgstr "പുതിയൊരു പാസ്‌വേഡ് ചേർക്കുക"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "റിക്കവറി ടോക്കൺ അസാധുവാണ്."
#: src/app/main/ui/auth/recovery.cljs

View file

@ -62,20 +62,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit"
msgstr "OpenID Connect"
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space"
msgstr "Nama mesti mengandungi beberapa aksara selain ruang."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "Nama mesti mengandungi paling banyak 250 aksara."
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password"
msgstr "Taip kata laluan baharu"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "Token pemulihan adalah tidak sah."
#: src/app/main/ui/auth/recovery.cljs
@ -102,10 +94,6 @@ msgstr "Kata laluan"
msgid "auth.password-length-hint"
msgstr "Sekurang-kurangnya 8 aksara"
#: src/app/main/ui/auth/register.cljs
msgid "auth.password-not-empty"
msgstr "Kata laluan mesti mengandungi beberapa aksara selain daripada ruang."
msgid "auth.privacy-policy"
msgstr "Dasar privasi"
@ -263,7 +251,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Jana token baru"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "Token capaian berjaya dihasilkan."
#: src/app/main/ui/settings/access-tokens.cljs
@ -274,10 +262,6 @@ msgstr "Tekan butang \"Jana token baharu\" untuk menjana token."
msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Anda tidak mempunyai token setakat ini."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.errors-required-name"
msgstr "Nama diperlukan"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 hari"
@ -840,11 +824,11 @@ msgid "errors.email-has-permanent-bounces"
msgstr "E-mel «%s» mempunyai banyak laporan lantunan kekal."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs, src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "Sila masukkan e-mel yang sah"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "E-mel pengesahan mesti sepadan"
msgid "errors.email-spam-or-permanent-bounces"

View file

@ -28,7 +28,7 @@ msgid "auth.new-password"
msgstr "Skriv inn et nytt passord"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "Gjenopprettelsessymbolet er ugyldig."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs

View file

@ -86,32 +86,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit"
msgstr "OpenID"
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs,
#: src/app/main/ui/dashboard/team_form.cljs,
#: src/app/main/ui/onboarding/team_choice.cljs,
#: src/app/main/ui/settings/access_tokens.cljs,
#: src/app/main/ui/settings/feedback.cljs,
#: src/app/main/ui/settings/profile.cljs,
#: src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space"
msgstr "De naam mag geen spatie bevatten."
#: src/app/main/ui/auth/register.cljs,
#: src/app/main/ui/dashboard/team_form.cljs,
#: src/app/main/ui/onboarding/team_choice.cljs,
#: src/app/main/ui/settings/access_tokens.cljs,
#: src/app/main/ui/settings/feedback.cljs,
#: src/app/main/ui/settings/profile.cljs,
#: src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "De naam mag maximaal 250 tekens bevatten."
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password"
msgstr "Typ een nieuw wachtwoord"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "De herstelbewijsstuk is ongeldig."
#: src/app/main/ui/auth/recovery.cljs
@ -138,10 +118,6 @@ msgstr "Wachtwoord"
msgid "auth.password-length-hint"
msgstr "Minimaal 8 tekens"
#: src/app/main/ui/auth/register.cljs
msgid "auth.password-not-empty"
msgstr "Het wachtwoord mag geen spatie bevatten."
msgid "auth.privacy-policy"
msgstr "Privacybeleid"
@ -301,7 +277,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Nieuw toegangsbewijs aanmaken"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "Toegangsbewijs is succesvol aangemaakt."
#: src/app/main/ui/settings/access-tokens.cljs
@ -312,10 +288,6 @@ msgstr "Klik op de knop \"Nieuw toegangsbewijs aanmaken\" om er een aan te maken
msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Je hebt nog geen toegangsbewijzen."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.errors-required-name"
msgstr "De naam is verplicht"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 dagen"
@ -909,11 +881,11 @@ msgstr "Het emailadres «%s» heeft veel permanente bounce-rapporten."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "Voer een geldig e-mailadres in"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "Bevestigingsmail moet overeenkomen"
msgid "errors.email-spam-or-permanent-bounces"
@ -3056,10 +3028,6 @@ msgstr "Zoomlens vergroten"
msgid "shortcuts.zoom-selected"
msgstr "Zoomen naar selectie"
#: src/app/main/ui/dashboard/team.cljs
msgid "team.webhooks.max-length"
msgstr "De webhooknaam mag maximaal 2048 tekens bevatten."
#: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files"
msgstr "%s - Penpot"

View file

@ -82,7 +82,7 @@ msgid "auth.new-password"
msgstr "Wpisz nowe hasło"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "Token odzyskiwania jest nieprawidłowy."
#: src/app/main/ui/auth/recovery.cljs
@ -732,11 +732,11 @@ msgid "errors.email-has-permanent-bounces"
msgstr "Email «%s» zawiera wiele stałych raportów o odrzuceniu."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs, src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "Podaj prawidłowy adres e-mail"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "E-mail potwierdzający musi być zgodny"
msgid "errors.email-spam-or-permanent-bounces"

View file

@ -81,7 +81,7 @@ msgid "auth.new-password"
msgstr "Digite uma nova senha"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "O código de recuperação é inválido."
#: src/app/main/ui/auth/recovery.cljs
@ -731,11 +731,11 @@ msgid "errors.email-has-permanent-bounces"
msgstr "O e-mail «%s» tem muitos relatórios de devolução permanentes."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs, src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "Por favor, insira um email válido"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "E-mail de confirmação deve ser o mesmo"
msgid "errors.email-spam-or-permanent-bounces"

View file

@ -76,32 +76,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit"
msgstr "OpenID Connect"
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs,
#: src/app/main/ui/dashboard/team_form.cljs,
#: src/app/main/ui/onboarding/team_choice.cljs,
#: src/app/main/ui/settings/access_tokens.cljs,
#: src/app/main/ui/settings/feedback.cljs,
#: src/app/main/ui/settings/profile.cljs,
#: src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space"
msgstr "O nome deve conter pelo menos um caractere que não seja um espaço."
#: src/app/main/ui/auth/register.cljs,
#: src/app/main/ui/dashboard/team_form.cljs,
#: src/app/main/ui/onboarding/team_choice.cljs,
#: src/app/main/ui/settings/access_tokens.cljs,
#: src/app/main/ui/settings/feedback.cljs,
#: src/app/main/ui/settings/profile.cljs,
#: src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "O nome deve conter um máximo de 250 caracteres."
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password"
msgstr "Escreve uma nova palavra-passe"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "O token de recuperação é inválido."
#: src/app/main/ui/auth/recovery.cljs
@ -128,11 +108,6 @@ msgstr "Palavra-passe"
msgid "auth.password-length-hint"
msgstr "Mínimo de 8 caracteres"
#: src/app/main/ui/auth/register.cljs
msgid "auth.password-not-empty"
msgstr ""
"A palavra-passe deve conter pelo menos um caractere que não seja um espaço."
msgid "auth.privacy-policy"
msgstr "Política de privacidade"
@ -291,7 +266,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Gerar novo token"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "Token de acesso criado com sucesso."
#: src/app/main/ui/settings/access-tokens.cljs
@ -302,10 +277,6 @@ msgstr "Clica no botão \"Gerar novo token\" para gerar um."
msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Ainda não tens nenhum token."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.errors-required-name"
msgstr "O nome é obrigatório"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 dias"
@ -887,11 +858,11 @@ msgstr "O e-mail «%s» tem muitos relatórios de rejeição permanentes."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "Por favor introduz um email válido"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "O e-mail de confirmação deve combinar"
msgid "errors.email-spam-or-permanent-bounces"
@ -2989,10 +2960,6 @@ msgstr "Aumentar zoom na lupa"
msgid "shortcuts.zoom-selected"
msgstr "Zoom para selecionados"
#: src/app/main/ui/dashboard/team.cljs
msgid "team.webhooks.max-length"
msgstr "O nome do webhook deve conter um máximo de 2048 caracteres."
#: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files"
msgstr "%s - Penpot"

View file

@ -77,20 +77,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit"
msgstr "OpenID"
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space"
msgstr "Numele trebuie să conțină un caracter altul decât spațiu."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "Numele trebuie să conțină cel mult 250 caractere."
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password"
msgstr "Introduceți o parolă nouă"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "Codul de recuperare nu este valid."
#: src/app/main/ui/auth/recovery.cljs
@ -119,10 +111,6 @@ msgstr "Parola"
msgid "auth.password-length-hint"
msgstr "Cel puțin 8 caractere"
#: src/app/main/ui/auth/register.cljs
msgid "auth.password-not-empty"
msgstr "Parola trebuie să conțină un caracter altul decât spațiu."
msgid "auth.privacy-policy"
msgstr "Politica de Confidențialitate"
@ -277,7 +265,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Generați jeton nou"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "Jeton de acces creat cu succes."
#: src/app/main/ui/settings/access-tokens.cljs
@ -288,10 +276,6 @@ msgstr "Apăsați butonul 'Generați jeton nou' pentru a genera unul."
msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Nu aveți încă jetoane."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.errors-required-name"
msgstr "Numele este obligatoriu"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 zile"
@ -872,11 +856,11 @@ msgstr "Adresa de email «%s» are multe rapoarte permanente de respingere."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "Vă rugăm să introduceți un e-mail valid"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "E-mailul de confirmare trebuie să se potrivească"
msgid "errors.email-spam-or-permanent-bounces"
@ -2893,10 +2877,6 @@ msgstr "Creștere obiectiv de zoom"
msgid "shortcuts.zoom-selected"
msgstr "Mărește la selecție"
#: src/app/main/ui/dashboard/team.cljs
msgid "team.webhooks.max-length"
msgstr "Numele webhook-ului trebuie să conțină maxim 2048 caractere."
#: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files"
msgstr "%s - Penpot"

View file

@ -79,7 +79,7 @@ msgid "auth.new-password"
msgstr "Введите новый пароль"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "Неверный код восстановления."
#: src/app/main/ui/auth/recovery.cljs
@ -745,7 +745,7 @@ msgid "errors.email-has-permanent-bounces"
msgstr "Эл. почта «%s» постоянно недоступна."
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "Эл. почта для подтверждения должна совпадать"
msgid "errors.email-spam-or-permanent-bounces"

View file

@ -81,7 +81,7 @@ msgid "auth.new-password"
msgstr "புதிய கடவுச்சொல்லை உள்ளிடவும்"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "மீட்பு டோக்கன் செல்லுபடியாகாது."
#: src/app/main/ui/auth/recovery.cljs

View file

@ -86,20 +86,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit"
msgstr "OpenID"
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space"
msgstr "İsim boşluk dışında bir karakter içermelidir."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "İsim en fazla 250 karakter içermelidir."
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password"
msgstr "Yeni bir parola gir"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "Kurtarma jetonu geçerli değil."
#: src/app/main/ui/auth/recovery.cljs
@ -126,10 +118,6 @@ msgstr "Parola"
msgid "auth.password-length-hint"
msgstr "En az 8 karakter"
#: src/app/main/ui/auth/register.cljs
msgid "auth.password-not-empty"
msgstr "Parola boşluk dışında bir karakter içermelidir."
msgid "auth.privacy-policy"
msgstr "Gizlilik politikası"
@ -289,7 +277,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Yeni belirteç oluştur"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "Erişim belirteci başarıyla oluşturuldu."
#: src/app/main/ui/settings/access-tokens.cljs
@ -300,10 +288,6 @@ msgstr "Bir belirteç oluşturmak için \"Yeni belirteç oluştur\" düğmesine
msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Şu ana kadar hiç belirteciniz yok."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.errors-required-name"
msgstr "İsim gereklidir"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 gün"
@ -895,11 +879,11 @@ msgstr "«%s» adresi için çok fazla geri dönme raporu var."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "Lütfen geçerli bir e-posta adresi girin"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "Doğrulama e-postası eşleşmiyor"
msgid "errors.email-spam-or-permanent-bounces"
@ -3048,10 +3032,6 @@ msgstr "Görüntüyü büyült"
msgid "shortcuts.zoom-selected"
msgstr "Seçilene yakınlaştır"
#: src/app/main/ui/dashboard/team.cljs
msgid "team.webhooks.max-length"
msgstr "Webhook adı en fazla 2048 karakter içermelidir."
#: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files"
msgstr "%s - Penpot"

View file

@ -58,7 +58,7 @@ msgid "auth.new-password"
msgstr "Введіть новий пароль"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "Невірний код відновлення."
#: src/app/main/ui/auth/recovery.cljs

View file

@ -72,16 +72,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit"
msgstr "ṣílẹ̀kuǹ ìdánimọ̀"
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "orúkọ kò gbọdọ̀ ju àádọ́jọ́ lẹ́tà lọ."
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password"
msgstr "tẹ ọ̀rọ̀ ìgbaniwọlé tuntun"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "àmì àtúnwárí ti díbàjẹ́."
#: src/app/main/ui/auth/recovery.cljs
@ -110,10 +106,6 @@ msgstr "ọ̀rọ̀- ìgbaniwọlé"
msgid "auth.password-length-hint"
msgstr "kò gbọdọ̀ ju ohun kíkọ mẹ́jọ lọ"
#: src/app/main/ui/auth/register.cljs
msgid "auth.password-not-empty"
msgstr "ọ̀rọ̀-ìgbaniwọlé gbọ́dọ̀ ní nǹkan kíkọ láìsí àlàfo."
msgid "auth.privacy-policy"
msgstr "ìpamọ ètò ìmúló"
@ -252,7 +244,7 @@ msgid "dashboard.access-tokens.create"
msgstr "ṣe ìpilẹ̀sẹ̀ àmì tókìnnì"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "ṣe àyẹ̀wò àmì tókìnnì tí o ṣẹ̀dá bó ṣeyẹ."
#: src/app/main/ui/settings/access-tokens.cljs
@ -263,10 +255,6 @@ msgstr "tẹ bọ́tìnnì \" ṣe ìpilẹ̀sẹ̀ àmì tókìnnì tuntun\" l
msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "o kò tí ì ní àmì tókínnì títí di ìsinsìn yìí."
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.errors-required-name"
msgstr "a nílò orúkọ"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days"
msgstr "ọgọ́saǹ-ań ọjọ́"
@ -793,11 +781,11 @@ msgid "errors.email-has-permanent-bounces"
msgstr "Ímeèlì «%s» ti ní ìjábọ̀ ọ̀pọ̀ọlọpọ̀ ìta-bọn-ọ̀n ti pẹ́."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs, src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "Tẹ àti wọlé pẹ̀lú ímeèlì tó wúlo jọ̀wọ́"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "Ímeèlì tí a ti mọ̀dájú gbọ́dọ̀ báramu"
msgid "errors.email-spam-or-permanent-bounces"
@ -2643,10 +2631,6 @@ msgstr "Lílọ̀soké lẹnsi sisun"
msgid "shortcuts.zoom-selected"
msgstr "Yiyan pelu sun-un"
#: src/app/main/ui/dashboard/team.cljs
msgid "team.webhooks.max-length"
msgstr "Orúkọ̀ webhook kò gbọ́dọ̀ kọjà awọ́n óhun kíkọ́ 2048."
#: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files"
msgstr "%s - Penpot"

View file

@ -72,32 +72,12 @@ msgstr "LDAP登录"
msgid "auth.login-with-oidc-submit"
msgstr "OpenID登录"
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs,
#: src/app/main/ui/dashboard/team_form.cljs,
#: src/app/main/ui/onboarding/team_choice.cljs,
#: src/app/main/ui/settings/access_tokens.cljs,
#: src/app/main/ui/settings/feedback.cljs,
#: src/app/main/ui/settings/profile.cljs,
#: src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space"
msgstr "姓名必须包含一些空格以外的字符。"
#: src/app/main/ui/auth/register.cljs,
#: src/app/main/ui/dashboard/team_form.cljs,
#: src/app/main/ui/onboarding/team_choice.cljs,
#: src/app/main/ui/settings/access_tokens.cljs,
#: src/app/main/ui/settings/feedback.cljs,
#: src/app/main/ui/settings/profile.cljs,
#: src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "姓名最多包含250个字符。"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password"
msgstr "输入新的密码"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "恢复令牌无效。"
#: src/app/main/ui/auth/recovery.cljs
@ -124,10 +104,6 @@ msgstr "密码"
msgid "auth.password-length-hint"
msgstr "至少8位字符"
#: src/app/main/ui/auth/register.cljs
msgid "auth.password-not-empty"
msgstr "密码必须包含一些空格以外的字符。"
msgid "auth.privacy-policy"
msgstr "隐私政策"
@ -279,7 +255,7 @@ msgid "dashboard.access-tokens.create"
msgstr "生成新令牌"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "成功创建访问令牌。"
#: src/app/main/ui/settings/access-tokens.cljs
@ -290,10 +266,6 @@ msgstr "点击“生成新令牌”按钮来生成一个。"
msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "你目前还没有令牌。"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.errors-required-name"
msgstr "名称是必填项"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180天"
@ -850,11 +822,11 @@ msgstr "电子邮件“%s”收到了非常多的永久退信报告。"
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "请输入有效的电子邮件"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "确认电子邮件必须保持一致"
msgid "errors.email-spam-or-permanent-bounces"
@ -2877,10 +2849,6 @@ msgstr "变焦镜头放大"
msgid "shortcuts.zoom-selected"
msgstr "缩放到选定对象"
#: src/app/main/ui/dashboard/team.cljs
msgid "team.webhooks.max-length"
msgstr "Webhook的名称最多包含2048个字符。"
#: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files"
msgstr "%s - Penpot"

View file

@ -77,7 +77,7 @@ msgid "auth.new-password"
msgstr "輸入新密碼"
#: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error"
msgid "errors.invalid-recovery-token"
msgstr "此 Recovery token 是無效的。"
#: src/app/main/ui/auth/recovery.cljs
@ -684,11 +684,11 @@ msgid "errors.email-has-permanent-bounces"
msgstr "電子郵件«%s»有許多永久退件報告。"
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs, src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid"
msgid "errors.invalid-email"
msgstr "請輸入一個有效的電郵地址"
#: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation"
msgid "errors.invalid-email-confirmation"
msgstr "電郵地址必須相同"
msgid "errors.email-spam-or-permanent-bounces"
@ -2343,7 +2343,7 @@ msgid "dashboard.access-tokens.empty.add-one"
msgstr "按下\"產生新 Token\" 按鈕來產生一個。"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success"
msgid "dashboard.access-tokens.create-success"
msgstr "已成功建立 Access Token。"
#: src/app/main/ui/settings/access-tokens.cljs
@ -2354,10 +2354,6 @@ msgstr "沒有到期時間"
msgid "dashboard.access-tokens.copied-success"
msgstr "已複製 Token"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.errors-required-name"
msgstr "名稱是必填的"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.token-will-expire"
msgstr "權杖將於 %s 到期"
@ -2365,14 +2361,6 @@ msgstr "權杖將於 %s 到期"
msgid "dashboard.export.options.merge.title"
msgstr "將共享資料庫的內容加入檔案資料庫"
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space"
msgstr "名稱內必須包含空白以外的文字。"
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long"
msgstr "名稱最多包含 250 個字元。"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-90-days"
msgstr "90 天"
@ -2408,10 +2396,6 @@ msgstr "Penpot 是用於設計與開發協作,免費且開源的設計工具"
msgid "branding-illustrations-marketing-pieces"
msgstr "...品牌設計、插畫、行銷素材等。"
#: src/app/main/ui/auth/register.cljs
msgid "auth.password-not-empty"
msgstr "密碼必須包含空白以外的字元。"
#: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.personal"
msgstr "個人存取權杖"