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." data resources."
(:refer-clojure :exclude [read-string hash-map merge name update-vals (:refer-clojure :exclude [read-string hash-map merge name update-vals
parse-double group-by iteration concat mapcat parse-double group-by iteration concat mapcat
parse-uuid max min]) parse-uuid max min regexp?])
#?(:cljs #?(:cljs
(:require-macros [app.common.data])) (:require-macros [app.common.data]))
@ -641,6 +641,13 @@
;; Utilities ;; 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 (defn nilf
"Returns a new function that if you pass nil as any argument will "Returns a new function that if you pass nil as any argument will
return nil" return nil"

View file

@ -21,6 +21,7 @@
[cuerdas.core :as str] [cuerdas.core :as str]
[malli.core :as m] [malli.core :as m]
[malli.dev.pretty :as mdp] [malli.dev.pretty :as mdp]
[malli.dev.virhe :as v]
[malli.error :as me] [malli.error :as me]
[malli.generator :as mg] [malli.generator :as mg]
[malli.registry :as mr] [malli.registry :as mr]
@ -44,6 +45,14 @@
[o] [o]
(m/schema? o)) (m/schema? o))
(defn properties
[s]
(m/properties s))
(defn type-properties
[s]
(m/type-properties s))
(defn lazy-schema? (defn lazy-schema?
[s] [s]
(satisfies? ILazySchema s)) (satisfies? ILazySchema s))
@ -96,6 +105,10 @@
[exp] [exp]
(malli.error/error-value exp {:malli.error/mask-valid-values '...})) (malli.error/error-value exp {:malli.error/mask-valid-values '...}))
(defn optional-keys
[schema]
(mu/optional-keys schema default-options))
(def default-transformer (def default-transformer
(let [default-decoder (let [default-decoder
{:compile (fn [s _registry] {:compile (fn [s _registry]
@ -144,6 +157,8 @@
(m/encode s val options transformer))) (m/encode s val options transformer)))
(defn decode (defn decode
([s val]
(m/decode s val default-options default-transformer))
([s val transformer] ([s val transformer]
(m/decode s val default-options transformer)) (m/decode s val default-options transformer))
([s val options transformer] ([s val options transformer]
@ -180,9 +195,10 @@
(fn [v] (@vfn v)))) (fn [v] (@vfn v))))
(defn lazy-decoder (defn lazy-decoder
[s transformer] ([s] (lazy-decoder s default-transformer))
(let [vfn (delay (decoder (if (delay? s) (deref s) s) transformer))] ([s transformer]
(fn [v] (@vfn v)))) (let [vfn (delay (decoder (if (delay? s) (deref s) s) transformer))]
(fn [v] (@vfn v)))))
(defn humanize-explain (defn humanize-explain
[{:keys [schema errors value]} & {:keys [length level]}] [{:keys [schema errors value]} & {:keys [length level]}]
@ -197,9 +213,29 @@
:level (d/nilv level 8) :level (d/nilv level 8)
:length (d/nilv length 12)}))))) :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 (defn pretty-explain
[s d] [explain & {:keys [variant message]
(mdp/explain (schema s) d)) :or {variant ::explain
message "Validation Error"}}]
(let [explain (fn [] (me/with-error-messages explain))]
((mdp/prettifier variant message explain default-options))))
(defmacro ignoring (defmacro ignoring
[expr] [expr]
@ -287,7 +323,7 @@
(throw (ex-info hint options)))))) (throw (ex-info hint options))))))
(defn validate-fn (defn validate-fn
"Create a predefined validate function" "Create a predefined validate function that raises an expception"
[s] [s]
(let [schema (if (lazy-schema? s) s (define s))] (let [schema (if (lazy-schema? s) s (define s))]
(partial fast-validate! schema))) (partial fast-validate! schema)))
@ -307,6 +343,7 @@
hint (get options :hint "schema validation error")] hint (get options :hint "schema validation error")]
(throw (ex-info hint options))))))) (throw (ex-info hint options)))))))
;; FIXME: revisit
(defn conform! (defn conform!
[schema value] [schema value]
(assert (lazy-schema? schema) "expected `schema` to satisfy ILazySchema protocol") (assert (lazy-schema? schema) "expected `schema` to satisfy ILazySchema protocol")
@ -428,23 +465,33 @@
[s] [s]
(if (string? s) (if (string? s)
(re-matches email-re 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 (define! ::email
{:type ::email {:type :string
:pred (fn [s] :pred email-string?
(and (string? s) :property-pred
(< (count s) 250) (fn [{:keys [max] :as props}]
(re-seq email-re s))) (if (some? max)
(fn [value]
(<= (count value) max))
(constantly true)))
:type-properties :type-properties
{:title "email" {:title "email"
:description "string with valid email address" :description "string with valid email address"
:error/message "expected valid email" :error/code "errors.invalid-email"
:gen/gen (-> :string sg/generator) :gen/gen (sg/email)
::oapi/type "string" ::oapi/type "string"
::oapi/format "email" ::oapi/format "email"
::oapi/decode parse-email}}) ::oapi/decode
(fn [v]
(or (parse-email v) v))}})
(def non-empty-strings-xf (def non-empty-strings-xf
(comp (comp
@ -452,6 +499,121 @@
(remove str/empty?) (remove str/empty?)
(remove str/blank?))) (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 (define! ::set-of-strings
{:type ::set-of-strings {:type ::set-of-strings
:pred #(and (set? %) (every? string? %)) :pred #(and (set? %) (every? string? %))
@ -634,6 +796,8 @@
(define! ::fn (define! ::fn
[:schema fn?]) [:schema fn?])
;; FIXME: deprecated, replace with ::text
(define! ::word-string (define! ::word-string
{:type ::word-string {:type ::word-string
:pred #(and (string? %) (not (str/blank? %))) :pred #(and (string? %) (not (str/blank? %)))
@ -649,16 +813,102 @@
(define! ::uri (define! ::uri
{:type ::uri {:type ::uri
:pred u/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 :type-properties
{:title "uri" {:title "uri"
:description "URI formatted string" :description "URI formatted string"
:error/message "expected URI instance" :error/code "errors.invalid-uri"
:gen/gen (sg/uri) :gen/gen (sg/uri)
::oapi/type "string" ::oapi/type "string"
::oapi/format "uri" ::oapi/format "uri"
::oapi/decode (comp u/uri str/trim)}}) ::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]) [:map-of {:gen/max 5} :string :string])
;; ---- PREDICATES ;; ---- PREDICATES

View file

@ -77,10 +77,23 @@
(defn word-string (defn word-string
[] []
(->> (tg/such-that #(re-matches #"\w+" %) (as-> tg/string-alphanumeric $$
tg/string-alphanumeric (tg/such-that (fn [v] (re-matches #"\w+" v)) $$ 50)
50) (tg/such-that (fn [v]
(tg/such-that (complement str/blank?)))) (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 (defn uri
[] []

View file

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

View file

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

View file

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

View file

@ -7,8 +7,7 @@
(ns app.main.ui.auth.register (ns app.main.ui.auth.register
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.common.data :as d] [app.common.schema :as sm]
[app.common.spec :as us]
[app.config :as cf] [app.config :as cf]
[app.main.data.messages :as msg] [app.main.data.messages :as msg]
[app.main.data.users :as du] [app.main.data.users :as du]
@ -22,67 +21,42 @@
[app.util.router :as rt] [app.util.router :as rt]
[app.util.storage :as sto] [app.util.storage :as sto]
[beicon.v2.core :as rx] [beicon.v2.core :as rx]
[cljs.spec.alpha :as s]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
;; --- PAGE: Register ;; --- PAGE: Register
(defn- validate-password-length (def ^:private schema:register-form
[errors data] [:map {:title "RegisterForm"}
(let [password (:password data)] [:password ::sm/password]
(cond-> errors [:email ::sm/email]
(> 8 (count password)) [:invitation-token {:optional true} ::sm/text]])
(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)))
(mf/defc register-form (mf/defc register-form
{::mf/props :obj}
[{:keys [params on-success-callback]}] [{:keys [params on-success-callback]}]
(let [initial (mf/use-memo (mf/deps params) (constantly params)) (let [initial (mf/use-memo (mf/deps params) (constantly params))
form (fm/use-form :spec ::register-form form (fm/use-form :schema schema:register-form
:validators [validate-password-length
validate-email
(fm/validate-not-empty :password (tr "auth.password-not-empty"))]
:initial initial) :initial initial)
submitted? (mf/use-state false) 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 on-submit
(mf/use-fn (mf/use-fn
(mf/deps on-success-callback) (mf/deps on-success-callback)
@ -90,16 +64,14 @@
(reset! submitted? true) (reset! submitted? true)
(let [cdata (:clean-data @form) (let [cdata (:clean-data @form)
on-success (fn [data] on-success (fn [data]
(if (nil? on-success-callback) (if (fn? on-success-callback)
(on-prepare-register-success data) (on-success-callback data)
(on-success-callback data))) (st/emit! (rt/nav :auth-register-validate {} data))))]
on-error (fn [data]
(on-prepare-register-error form data))]
(->> (rp/cmd! :prepare-register-profile cdata) (->> (rp/cmd! :prepare-register-profile cdata)
(rx/map #(merge % params)) (rx/map #(merge % params))
(rx/finalize #(reset! submitted? false)) (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} [:& fm/form {:on-submit on-submit :form form}
[:div {:class (stl/css :fields-row)} [:div {:class (stl/css :fields-row)}
@ -164,33 +136,6 @@
;; --- PAGE: register validation ;; --- 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/defc terms-and-privacy
{::mf/props :obj {::mf/props :obj
::mf/private true} ::mf/private true}
@ -210,34 +155,48 @@
:default-checked false :default-checked false
:label terms-label}]])) :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/defc register-validate-form
{::mf/props :obj} {::mf/props :obj
::mf/private true}
[{:keys [params on-success-callback]}] [{:keys [params on-success-callback]}]
(let [validators (mf/with-memo [] (let [form (fm/use-form :schema schema:register-validate-form :initial params)
[(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)
submitted? (mf/use-state false) submitted? (mf/use-state false)
on-success on-success
(mf/use-fn (mf/use-fn
(mf/deps on-success-callback) (mf/deps on-success-callback)
(fn [params] (fn [params]
(if (nil? on-success-callback) (if (fn? on-success-callback)
(on-register-success params) (on-success-callback (:email params))
(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 on-error
(mf/use-fn (mf/use-fn
(fn [_cause] (fn [_]
(st/emit! (msg/error (tr "errors.generic"))))) (st/emit! (msg/error (tr "errors.generic")))))
on-submit on-submit
(mf/use-fn (mf/use-fn
(mf/deps on-success on-error)
(fn [form _] (fn [form _]
(reset! submitted? true) (reset! submitted? true)
(let [params (:clean-data @form)] (let [params (:clean-data @form)]

View file

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

View file

@ -18,7 +18,6 @@
[app.util.keyboard :as kbd] [app.util.keyboard :as kbd]
[app.util.object :as obj] [app.util.object :as obj]
[cljs.core :as c] [cljs.core :as c]
[clojure.string]
[cuerdas.core :as str] [cuerdas.core :as str]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
@ -26,7 +25,9 @@
(def use-form fm/use-form) (def use-form fm/use-form)
(mf/defc input (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") (let [input-type (get props :type "text")
input-name (get props :name) input-name (get props :name)
more-classes (get props :class) more-classes (get props :class)
@ -152,11 +153,14 @@
children]) children])
(cond (cond
(and touched? (:message error)) (and touched? (:code error) show-error)
[:div {:id (dm/str "error-" input-name) (let [code (:code error)]
:class (stl/css :error) [:div {:id (dm/str "error-" input-name)
:data-testid (clojure.string/join [data-testid "-error"])} :class (stl/css :error)
(tr (:message error))] :data-testid (dm/str data-testid "-error")}
(if (vector? code)
(tr (nth code 0) (i18n/c (nth code 1)))
(tr code))])
(string? hint) (string? hint)
[:div {:class (stl/css :hint)} hint])]])) [:div {:class (stl/css :hint)} hint])]]))
@ -207,8 +211,8 @@
[:label {:class (stl/css :textarea-label)} label] [:label {:class (stl/css :textarea-label)} label]
[:> :textarea props] [:> :textarea props]
(cond (cond
(and touched? (:message error)) (and touched? (:code error))
[:span {:class (stl/css :error)} (tr (:message error))] [:span {:class (stl/css :error)} (tr (:code error))]
(string? hint) (string? hint)
[:span {:class (stl/css :hint)} hint])])) [:span {:class (stl/css :hint)} hint])]))
@ -550,41 +554,3 @@
[:span {:class (stl/css :text)} (:text item)] [:span {:class (stl/css :text)} (:text item)]
[:button {:class (stl/css :icon) [:button {:class (stl/css :icon)
:on-click #(remove-item! item)} i/close]]])])])) :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 (ns app.main.ui.dashboard.change-owner
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.common.spec :as us] [app.common.schema :as sm]
[app.main.data.modal :as modal] [app.main.data.modal :as modal]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.forms :as fm] [app.main.ui.components.forms :as fm]
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[cljs.spec.alpha :as s]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(s/def ::member-id ::us/uuid) (def ^:private schema:leave-modal-form
(s/def ::leave-modal-form [:map {:title "LeaveModalForm"}
(s/keys :req-un [::member-id])) [:member-id ::sm/uuid]])
(mf/defc leave-and-reassign-modal (mf/defc leave-and-reassign-modal
{::mf/register modal/components {::mf/register modal/components
::mf/register-as :leave-and-reassign} ::mf/register-as :leave-and-reassign}
[{:keys [profile team accept]}] [{: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-map (mf/deref refs/dashboard-team-members)
members (vals members-map) members (vals members-map)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -7,9 +7,7 @@
(ns app.main.ui.settings.change-email (ns app.main.ui.settings.change-email
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.common.data :as d] [app.common.schema :as sm]
[app.common.data.macros :as dma]
[app.common.spec :as us]
[app.main.data.messages :as msg] [app.main.data.messages :as msg]
[app.main.data.modal :as modal] [app.main.data.modal :as modal]
[app.main.data.users :as du] [app.main.data.users :as du]
@ -20,24 +18,8 @@
[app.main.ui.notifications.context-notification :refer [context-notification]] [app.main.ui.notifications.context-notification :refer [context-notification]]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[beicon.v2.core :as rx] [beicon.v2.core :as rx]
[cljs.spec.alpha :as s]
[rumext.v2 :as mf])) [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 (defn- on-error
[form error] [form error]
(case (:code (ex-data error)) (case (:code (ex-data error))
@ -71,30 +53,32 @@
:on-success (partial on-success profile)}] :on-success (partial on-success profile)}]
(st/emit! (du/request-email-change (with-meta params mdata))))) (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/defc change-email-modal
{::mf/register modal/components {::mf/register modal/components
::mf/register-as :change-email} ::mf/register-as :change-email}
[] []
(let [profile (mf/deref refs/profile) (let [profile (mf/deref refs/profile)
form (fm/use-form :spec ::email-change-form form (fm/use-form :schema schema:email-change-form
:validators [email-equality]
:initial profile) :initial profile)
on-close on-close
(mf/use-callback #(st/emit! (modal/hide))) (mf/use-fn #(st/emit! (modal/hide)))
on-submit on-submit
(mf/use-callback (mf/use-fn
(mf/deps profile) (mf/deps profile)
(partial on-submit 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])))))]
[:div {:class (stl/css :modal-overlay)} [:div {:class (stl/css :modal-overlay)}
[:div {:class (stl/css :modal-container)} [:div {:class (stl/css :modal-container)}
@ -118,16 +102,14 @@
:name :email-1 :name :email-1
:label (tr "modals.change-email.new-email") :label (tr "modals.change-email.new-email")
:trim true :trim true
:show-success? true :show-success? true}]]
:on-change-value on-email-change}]]
[:div {:class (stl/css :fields-row)} [:div {:class (stl/css :fields-row)}
[:& fm/input {:type "email" [:& fm/input {:type "email"
:name :email-2 :name :email-2
:label (tr "modals.change-email.confirm-email") :label (tr "modals.change-email.confirm-email")
:trim true :trim true
:show-success? true :show-success? true}]]]
:on-change-value on-email-change}]]]
[:div {:class (stl/css :modal-footer)} [:div {:class (stl/css :modal-footer)}
[:div {:class (stl/css :action-buttons) [:div {:class (stl/css :action-buttons)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -8,119 +8,146 @@
(:refer-clojure :exclude [uuid]) (:refer-clojure :exclude [uuid])
(:require (:require
[app.common.data :as d] [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]] [app.util.i18n :refer [tr]]
[cljs.spec.alpha :as s]
[cuerdas.core :as str] [cuerdas.core :as str]
[malli.core :as m]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
;; --- Handlers Helpers ;; --- Handlers Helpers
(defn- interpret-problem (defn- interpret-schema-problem
[acc {:keys [path pred via] :as problem}] [acc {:keys [schema in value] :as problem}]
(cond (let [props (merge (m/type-properties schema)
(and (empty? path) (m/properties schema))
(list? pred) field (or (first in) (:error/field props))]
(= (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}))
(and (seq path) (seq via)) (if (contains? acc field)
(let [field (first path) acc
code (last via) (cond
root (first via)] (nil? value)
(assoc-in acc path {:code code :type :builtin :root root :field field})) (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 (contains? props :error/fn)
[& {:keys [initial] :as opts}] (let [v-fn (:error/fn props)
(let [state (mf/useState 0) code (v-fn problem)]
render (aget state 1) (assoc acc field {:code code}))
get-state (mf/use-callback (contains? props :error/validators)
(mf/deps initial) (let [validators (:error/validators props)
(fn [] props (reduce #(%2 %1 value) props validators)]
{:data (if (fn? initial) (initial) initial) (assoc acc field {:code (d/nilv (:error/code props) "errors.invalid-data")}))
:errors {}
:touched {}}))
state-ref (mf/use-ref (get-state)) :else
form (mf/use-memo (mf/deps initial) #(create-form-mutator state-ref render get-state opts))] (assoc acc field {:code "errors.invalid-data"})))))
(mf/use-effect (defn- use-rerender-fn
(mf/deps initial) []
(let [state (mf/useState 0)
render-fn (aget state 1)]
(mf/use-fn
(mf/deps render-fn)
(fn [] (fn []
(if (fn? initial) (render-fn inc)))))
(swap! form update :data merge (initial))
(swap! form update :data merge initial))))
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 (defn- collect-schema-errors
[f {:keys [spec validators]}] [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] (fn [& args]
(let [state (apply f args) (let [state (apply f args)
cleaned (s/conform spec (:data state)) cleaned (sm/decode schema (:data state))
problems (when (= ::s/invalid cleaned) valid? (sm/validate schema cleaned)
(::s/problems (s/explain-data spec (:data state)))) errors (when-not valid?
(collect-schema-errors schema validators 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)]
(assoc state (assoc state
:errors errors :errors errors
:clean-data (when (not= cleaned ::s/invalid) cleaned) :clean-data (when valid? cleaned)
:valid (and (empty? errors) :valid (and (not errors) valid?)))))
(not= cleaned ::s/invalid))))))
(defn- create-form-mutator (defn- create-form-mutator
[state-ref render get-state opts] [internal-state rerender-fn wrap-update-fn initial opts]
(reify (reify
IDeref IDeref
(-deref [_] (-deref [_]
(mf/ref-val state-ref)) (mf/ref-val internal-state))
IReset IReset
(-reset! [_ new-value] (-reset! [_ new-value]
(if (nil? new-value) (if (nil? new-value)
(mf/set-ref-val! state-ref (get-state)) (mf/set-ref-val! internal-state (if (fn? initial) (initial) initial))
(mf/set-ref-val! state-ref new-value)) (mf/set-ref-val! internal-state new-value))
(render inc)) (rerender-fn))
ISwap ISwap
(-swap! [_ f] (-swap! [_ f]
(let [f (wrap-update-fn f opts)] (let [f (wrap-update-fn f opts)]
(mf/set-ref-val! state-ref (f (mf/ref-val state-ref))) (mf/set-ref-val! internal-state (f (mf/ref-val internal-state)))
(render inc))) (rerender-fn)))
(-swap! [_ f x] (-swap! [_ f x]
(let [f (wrap-update-fn f opts)] (let [f (wrap-update-fn f opts)]
(mf/set-ref-val! state-ref (f (mf/ref-val state-ref) x)) (mf/set-ref-val! internal-state (f (mf/ref-val internal-state) x))
(render inc))) (rerender-fn)))
(-swap! [_ f x y] (-swap! [_ f x y]
(let [f (wrap-update-fn f opts)] (let [f (wrap-update-fn f opts)]
(mf/set-ref-val! state-ref (f (mf/ref-val state-ref) x y)) (mf/set-ref-val! internal-state (f (mf/ref-val internal-state) x y))
(render inc))) (rerender-fn)))
(-swap! [_ f x y more] (-swap! [_ f x y more]
(let [f (wrap-update-fn f opts)] (let [f (wrap-update-fn f opts)]
(mf/set-ref-val! state-ref (apply f (mf/ref-val state-ref) x y more)) (mf/set-ref-val! internal-state (apply f (mf/ref-val internal-state) x y more))
(render inc))))) (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 (defn on-input-change
([form field value] ([form field value]
@ -150,8 +177,8 @@
(mf/defc field-error (mf/defc field-error
[{:keys [form field type] [{:keys [form field type]
:as props}] :as props}]
(let [{:keys [message] :as error} (get-in form [:errors field]) (let [{:keys [message] :as error} (dm/get-in form [:errors field])
touched? (get-in form [:touched field]) touched? (dm/get-in form [:touched field])
show? (and touched? error message show? (and touched? error message
(cond (cond
(nil? type) true (nil? type) true
@ -164,12 +191,6 @@
(defn error-class (defn error-class
[form field] [form field]
(when (and (get-in form [:errors field]) (when (and (dm/get-in form [:errors field])
(get-in form [:touched field])) (dm/get-in form [:touched field]))
"invalid")) "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" msgid "auth.login-with-oidc-submit"
msgstr "OpenID" 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 #: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password" msgid "auth.new-password"
msgstr "Tik 'n nuwe wagwoord in" msgstr "Tik 'n nuwe wagwoord in"
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error" msgid "errors.invalid-recovery-token"
msgstr "Die hersteltoken is ongeldig." msgstr "Die hersteltoken is ongeldig."
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
@ -118,10 +110,6 @@ msgstr "Wagwoord"
msgid "auth.password-length-hint" msgid "auth.password-length-hint"
msgstr "Ten minste 8 karakters" 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" msgid "auth.privacy-policy"
msgstr "Privaatheidsbeleid" msgstr "Privaatheidsbeleid"
@ -275,7 +263,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Genereer nuwe token" msgstr "Genereer nuwe token"
#: src/app/main/ui/settings/access-tokens.cljs #: 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." msgstr "Toegangstoken is suksesvol geskep."
#: src/app/main/ui/settings/access-tokens.cljs #: 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" msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Jy het tot dusver geen tokens nie." 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 #: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days" msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 dae" msgstr "180 dae"

View file

@ -78,7 +78,7 @@ msgid "auth.new-password"
msgstr "اكتب كلمة مرور جديدة" msgstr "اكتب كلمة مرور جديدة"
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error" msgid "errors.invalid-recovery-token"
msgstr "رمز الاسترداد غير صالح." msgstr "رمز الاسترداد غير صالح."
#: src/app/main/ui/auth/recovery.cljs #: 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/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.cljs #: src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid" msgid "errors.invalid-email"
msgstr "أدخل بريدًا إلكترونيًا صالحًا من فضلك" msgstr "أدخل بريدًا إلكترونيًا صالحًا من فضلك"
#: src/app/main/ui/settings/change_email.cljs #: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation" msgid "errors.invalid-email-confirmation"
msgstr "يجب أن يتطابق البريد الإلكتروني للتأكيد" msgstr "يجب أن يتطابق البريد الإلكتروني للتأكيد"
msgid "errors.email-spam-or-permanent-bounces" msgid "errors.email-spam-or-permanent-bounces"
@ -2292,10 +2292,6 @@ msgstr "زيادة عدسة التكبير"
msgid "shortcuts.zoom-selected" msgid "shortcuts.zoom-selected"
msgstr "كبر المحدد" msgstr "كبر المحدد"
#: src/app/main/ui/dashboard/team.cljs
msgid "team.webhooks.max-length"
msgstr "يجب الا يزيد اسم الويبهوك على 2048 حرفا"
#: src/app/main/ui/dashboard/files.cljs #: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files" msgid "title.dashboard.files"
msgstr "%s - Penpotعنوان ملفات لوحة القيادة" msgstr "%s - Penpotعنوان ملفات لوحة القيادة"
@ -4307,14 +4303,6 @@ msgstr "الرمز منسوخ"
msgid "auth.login-tagline" msgid "auth.login-tagline"
msgstr "Penpot هو أداة تصميم مجانية ومفتوحة المصدر للتعاون بين التصميم والبرمجة" 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 #: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.empty.add-one" msgid "dashboard.access-tokens.empty.add-one"
msgstr "اضغط على الزر \"إنشاء رمز جديد\" لإنشاء واحد." msgstr "اضغط على الزر \"إنشاء رمز جديد\" لإنشاء واحد."
@ -4332,5 +4320,5 @@ msgid "dashboard.access-tokens.create"
msgstr "قم بإنشاء رمز جديد" msgstr "قم بإنشاء رمز جديد"
#: src/app/main/ui/settings/access-tokens.cljs #: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.create.success" msgid "dashboard.access-tokens.create-success"
msgstr "تم إنشاء رمز الوصول بنجاح." msgstr "تم إنشاء رمز الوصول بنجاح."

View file

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

View file

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

View file

@ -76,20 +76,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit" msgid "auth.login-with-oidc-submit"
msgstr "OpenID" 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 #: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password" msgid "auth.new-password"
msgstr "Zadejte nové heslo" msgstr "Zadejte nové heslo"
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error" msgid "errors.invalid-recovery-token"
msgstr "Token pro obnovení je neplatný." msgstr "Token pro obnovení je neplatný."
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
@ -116,10 +108,6 @@ msgstr "Heslo"
msgid "auth.password-length-hint" msgid "auth.password-length-hint"
msgstr "Minimálně 8 znaků" 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" msgid "auth.privacy-policy"
msgstr "Zásady ochrany osobních údajů" msgstr "Zásady ochrany osobních údajů"
@ -278,7 +266,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Generovat nový token" msgstr "Generovat nový token"
#: src/app/main/ui/settings/access-tokens.cljs #: 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." msgstr "Přístupový token byl úspěšně vytvořen."
#: src/app/main/ui/settings/access-tokens.cljs #: src/app/main/ui/settings/access-tokens.cljs
@ -291,10 +279,6 @@ msgstr ""
msgid "dashboard.access-tokens.empty.no-access-tokens" msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Zatím nemáte žádné tokeny." 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 #: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days" msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 dní" 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/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.cljs #: src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid" msgid "errors.invalid-email"
msgstr "Zadejte prosím platný email" msgstr "Zadejte prosím platný email"
#: src/app/main/ui/settings/change_email.cljs #: 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" msgstr "Potvrzovací e-mail se musí shodovat"
msgid "errors.email-spam-or-permanent-bounces" msgid "errors.email-spam-or-permanent-bounces"
@ -2974,10 +2958,6 @@ msgstr "Zvětšení zoomu"
msgid "shortcuts.zoom-selected" msgid "shortcuts.zoom-selected"
msgstr "Přiblížit na vybrané" 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 #: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files" msgid "title.dashboard.files"
msgstr "%s - Penpot" msgstr "%s - Penpot"

View file

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

View file

@ -86,32 +86,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit" msgid "auth.login-with-oidc-submit"
msgstr "OpenID" 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 #: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password" msgid "auth.new-password"
msgstr "Geben Sie ein neues Passwort ein" msgstr "Geben Sie ein neues Passwort ein"
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error" msgid "errors.invalid-recovery-token"
msgstr "Der Wiederherstellungscode ist ungültig." msgstr "Der Wiederherstellungscode ist ungültig."
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
@ -141,10 +121,6 @@ msgstr "Passwort"
msgid "auth.password-length-hint" msgid "auth.password-length-hint"
msgstr "Mindestens 8 Zeichen" 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" msgid "auth.privacy-policy"
msgstr "Datenschutzerklärung" msgstr "Datenschutzerklärung"
@ -305,7 +281,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Neues Token generieren" msgstr "Neues Token generieren"
#: src/app/main/ui/settings/access-tokens.cljs #: 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." msgstr "Der Zugangstoken wurde erfolgreich erstellt."
#: src/app/main/ui/settings/access-tokens.cljs #: src/app/main/ui/settings/access-tokens.cljs
@ -318,10 +294,6 @@ msgstr ""
msgid "dashboard.access-tokens.empty.no-access-tokens" msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Du hast bisher keine Token." 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 #: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days" msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 Tage" 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/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.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" msgstr "Geben Sie bitte eine gültige E-Mail-Adresse ein"
#: src/app/main/ui/settings/change_email.cljs #: 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" msgstr "Bestätigungs-E-Mail muss übereinstimmen"
msgid "errors.email-spam-or-permanent-bounces" msgid "errors.email-spam-or-permanent-bounces"
@ -3099,10 +3071,6 @@ msgstr "Ansicht mit Zoomwerkzeug vergrößern"
msgid "shortcuts.zoom-selected" msgid "shortcuts.zoom-selected"
msgstr "Zur Auswahl zoomen" 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 #: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files" msgid "title.dashboard.files"
msgstr "%s - Penpot" msgstr "%s - Penpot"

View file

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

View file

@ -98,19 +98,24 @@ msgid "auth.login-with-oidc-submit"
msgstr "OpenID" 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 #: 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." 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 #: 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 "auth.name.too-long" msgid "errors.field-max-length"
msgstr "The name must contain at most 250 characters." 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 #: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password" msgid "auth.new-password"
msgstr "Type a new password" msgstr "Type a new password"
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error" msgid "errors.invalid-recovery-token"
msgstr "The recovery token is invalid." msgstr "The recovery token is invalid."
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
@ -137,10 +142,6 @@ msgstr "Password"
msgid "auth.password-length-hint" msgid "auth.password-length-hint"
msgstr "At least 8 characters" 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" msgid "auth.privacy-policy"
msgstr "Privacy policy" msgstr "Privacy policy"
@ -309,7 +310,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Generate new token" msgstr "Generate new token"
#: src/app/main/ui/settings/access-tokens.cljs #: 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." msgstr "Access token created successfully."
#: src/app/main/ui/settings/access-tokens.cljs #: 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" msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "You have no tokens so far." 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 #: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days" msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 days" msgstr "180 days"
@ -898,11 +895,11 @@ msgid "errors.email-has-permanent-bounces"
msgstr "The email «%s» has many permanent bounce reports." 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 #: 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" msgstr "Enter a valid email please"
#: src/app/main/ui/settings/change_email.cljs #: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation" msgid "errors.invalid-email-confirmation"
msgstr "Confirmation email must match" msgstr "Confirmation email must match"
msgid "errors.email-spam-or-permanent-bounces" msgid "errors.email-spam-or-permanent-bounces"
@ -3131,10 +3128,6 @@ msgstr "Zoom lense increase"
msgid "shortcuts.zoom-selected" msgid "shortcuts.zoom-selected"
msgstr "Zoom to 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 #: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files" msgid "title.dashboard.files"
msgstr "%s - Penpot" msgstr "%s - Penpot"

View file

@ -98,19 +98,24 @@ msgid "auth.login-with-oidc-submit"
msgstr "OpenID" 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 #: 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 diferente de espacio" 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 #: 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" msgid "errors.field-max-length"
msgstr "El nombre debe contener como máximo 250 caracteres." 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 #: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password" msgid "auth.new-password"
msgstr "Introduce la nueva contraseña" msgstr "Introduce la nueva contraseña"
#: src/app/main/ui/auth/recovery.cljs #: 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." msgstr "El código de recuperación no es válido."
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
@ -139,10 +144,6 @@ msgstr "Contraseña"
msgid "auth.password-length-hint" msgid "auth.password-length-hint"
msgstr "8 caracteres como mínimo" 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" msgid "auth.privacy-policy"
msgstr "Política de privacidad" msgstr "Política de privacidad"
@ -315,7 +316,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Generar nuevo token" msgstr "Generar nuevo token"
#: src/app/main/ui/settings/access-tokens.cljs #: 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." msgstr "Access token creado con éxito."
#: src/app/main/ui/settings/access-tokens.cljs #: 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" msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Todavía no tienes ningún token." 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 #: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days" msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 días" 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." 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 #: 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" msgstr "Por favor, escribe un email válido"
#: src/app/main/ui/settings/change_email.cljs #: 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" msgstr "El correo de confirmación debe coincidir"
msgid "errors.email-spam-or-permanent-bounces" msgid "errors.email-spam-or-permanent-bounces"
@ -3188,10 +3185,6 @@ msgstr "Incrementar zoom a objetivo"
msgid "shortcuts.zoom-selected" msgid "shortcuts.zoom-selected"
msgstr "Zoom a selección" 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 #: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files" msgid "title.dashboard.files"
msgstr "%s - Penpot" msgstr "%s - Penpot"

View file

@ -77,19 +77,20 @@ msgid "auth.login-with-oidc-submit"
msgstr "Open ID" 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 #: 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." 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 #: 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" msgid "errors.field-max-length"
msgstr "El nombre debe contener como máximo 250 caracteres." 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 #: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password" msgid "auth.new-password"
msgstr "Escribe una nueva contraseña" msgstr "Escribe una nueva contraseña"
#: src/app/main/ui/auth/recovery.cljs #: 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." msgstr "El token de recuperación no es válido."
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
@ -118,10 +119,6 @@ msgstr "Contraseña"
msgid "auth.password-length-hint" msgid "auth.password-length-hint"
msgstr "Al menos 8 carácteres" 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" msgid "auth.privacy-policy"
msgstr "Política de privacidad" msgstr "Política de privacidad"
@ -280,7 +277,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Generar nuevo token" msgstr "Generar nuevo token"
#: src/app/main/ui/settings/access-tokens.cljs #: 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." msgstr "Token de acceso creado correctamente."
#: src/app/main/ui/settings/access-tokens.cljs #: 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" msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "No tienes tokens hasta el momento." 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 #: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days" msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 días" msgstr "180 días"

View file

@ -81,7 +81,7 @@ msgid "auth.new-password"
msgstr "Sartu Pasahitz berria" msgstr "Sartu Pasahitz berria"
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error" msgid "errors.invalid-recovery-token"
msgstr "Berreskuratzeko kodea ez da zuzena." msgstr "Berreskuratzeko kodea ez da zuzena."
#: src/app/main/ui/auth/recovery.cljs #: 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/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.cljs #: src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid" msgid "errors.invalid-email"
msgstr "Mesedez, idatzi eposta helbide zuzen bat" msgstr "Mesedez, idatzi eposta helbide zuzen bat"
#: src/app/main/ui/settings/change_email.cljs #: 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" msgstr "Egiaztapenereko epostak bat etorri behar du aurrekoarekin"
msgid "errors.email-spam-or-permanent-bounces" msgid "errors.email-spam-or-permanent-bounces"

View file

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

View file

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

View file

@ -76,20 +76,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit" msgid "auth.login-with-oidc-submit"
msgstr "OpenID" 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 #: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password" msgid "auth.new-password"
msgstr "Saisissez un nouveau mot de passe" msgstr "Saisissez un nouveau mot de passe"
#: src/app/main/ui/auth/recovery.cljs #: 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." msgstr "Le code de récupération nest pas valide."
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
@ -116,10 +108,6 @@ msgstr "Mot de passe"
msgid "auth.password-length-hint" msgid "auth.password-length-hint"
msgstr "Au moins 8 caractères" 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" msgid "auth.privacy-policy"
msgstr "Politique de confidentialité" msgstr "Politique de confidentialité"
@ -271,7 +259,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Générer un nouveau jeton" msgstr "Générer un nouveau jeton"
#: src/app/main/ui/settings/access-tokens.cljs #: 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." msgstr "Jeton d'accès créé avec succès."
#: src/app/main/ui/settings/access-tokens.cljs #: 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" msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Vous n'avez pas encore de jeton." 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 #: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days" msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 jours" 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é." 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 #: 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" msgstr "Veuillez entrer une adresse mail valide"
#: src/app/main/ui/settings/change_email.cljs #: 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" msgstr "Ladresse email de confirmation doit correspondre"
msgid "errors.email-spam-or-permanent-bounces" msgid "errors.email-spam-or-permanent-bounces"
@ -2930,10 +2914,6 @@ msgstr "Augmenter le zoom"
msgid "shortcuts.zoom-selected" msgid "shortcuts.zoom-selected"
msgstr "Zoomer sur la sélection" 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 #: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files" msgid "title.dashboard.files"
msgstr "%s - Penpot" msgstr "%s - Penpot"

View file

@ -81,7 +81,7 @@ msgid "auth.new-password"
msgstr "Escribe un contrasinal novo" msgstr "Escribe un contrasinal novo"
#: src/app/main/ui/auth/recovery.cljs #: 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." msgstr "O código de recuperación non é correcto."
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs

View file

@ -76,20 +76,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit" msgid "auth.login-with-oidc-submit"
msgstr "shaidar buxewa" 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 #: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password" msgid "auth.new-password"
msgstr "sanya sabuwar lambar tsaro" msgstr "sanya sabuwar lambar tsaro"
#: src/app/main/ui/auth/recovery.cljs #: 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." msgstr "lambar tsaron da ka sanya ba daidai ba ce."
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
@ -252,7 +244,7 @@ msgid "dashboard.access-tokens.create"
msgstr "samo sabuwar lambar tsaro" msgstr "samo sabuwar lambar tsaro"
#: src/app/main/ui/settings/access-tokens.cljs #: 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." msgstr "ka sami lambar tsaron da aka yi."
#: src/app/main/ui/settings/access-tokens.cljs #: src/app/main/ui/settings/access-tokens.cljs
@ -265,10 +257,6 @@ msgstr ""
msgid "dashboard.access-tokens.empty.no-access-tokens" msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "ba ka da wasu lambobin tsaro yanzu." 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 #: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days" msgid "dashboard.access-tokens.expiration-180-days"
msgstr "kwanaki 180" msgstr "kwanaki 180"
@ -819,11 +807,11 @@ msgid "errors.email-has-permanent-bounces"
msgstr "imel «%s» na da bayanan matsaloli na dindindin." 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 #: 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" msgstr "sanya imel mai amfani"
#: src/app/main/ui/settings/change_email.cljs #: 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" msgstr "tabbata imel xinka ya yi daidai"
msgid "errors.email-spam-or-permanent-bounces" msgid "errors.email-spam-or-permanent-bounces"
@ -2790,10 +2778,6 @@ msgstr "Zuko karuwar ido"
msgid "shortcuts.zoom-selected" msgid "shortcuts.zoom-selected"
msgstr "Zuko wanda aka zaba" 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 #: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files" msgid "title.dashboard.files"
msgstr "%s - Tukunyar aje biro" msgstr "%s - Tukunyar aje biro"

View file

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

View file

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

View file

@ -76,32 +76,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit" msgid "auth.login-with-oidc-submit"
msgstr "OpenID Connect" 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 #: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password" msgid "auth.new-password"
msgstr "Ketik kata sandi baru" msgstr "Ketik kata sandi baru"
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error" msgid "errors.invalid-recovery-token"
msgstr "Token pemulihan tidak sah." msgstr "Token pemulihan tidak sah."
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
@ -129,10 +109,6 @@ msgstr "Kata sandi"
msgid "auth.password-length-hint" msgid "auth.password-length-hint"
msgstr "Setidaknya 8 karakter" 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" msgid "auth.privacy-policy"
msgstr "Kebijakan privasi" msgstr "Kebijakan privasi"
@ -291,7 +267,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Buat token baru" msgstr "Buat token baru"
#: src/app/main/ui/settings/access-tokens.cljs #: 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." msgstr "Token akses berhasil dibuat."
#: src/app/main/ui/settings/access-tokens.cljs #: 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" msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Anda belum memiliki token." 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 #: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days" msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 hari" 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/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.cljs #: src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid" msgid "errors.invalid-email"
msgstr "Silakan menyediakan surel yang valid" msgstr "Silakan menyediakan surel yang valid"
#: src/app/main/ui/settings/change_email.cljs #: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation" msgid "errors.invalid-email-confirmation"
msgstr "Surel konfirmasi harus cocok" msgstr "Surel konfirmasi harus cocok"
msgid "errors.email-spam-or-permanent-bounces" msgid "errors.email-spam-or-permanent-bounces"
@ -2964,10 +2936,6 @@ msgstr "Tambahkan lensa zum"
msgid "shortcuts.zoom-selected" msgid "shortcuts.zoom-selected"
msgstr "Zum ke terpilih" 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 #: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files" msgid "title.dashboard.files"
msgstr "%s - Penpot" msgstr "%s - Penpot"

View file

@ -70,20 +70,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit" msgid "auth.login-with-oidc-submit"
msgstr "Mepe ID" 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 #: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password" msgid "auth.new-password"
msgstr "Pinye akara mpịbanye ọhụrụ" msgstr "Pinye akara mpịbanye ọhụrụ"
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error" msgid "errors.invalid-recovery-token"
msgstr "Ọdịmara e nweghachitere adabaghị ." msgstr "Ọdịmara e nweghachitere adabaghị ."
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
@ -106,10 +98,6 @@ msgstr "Sonyere n'otu nke ọma"
msgid "auth.password-length-hint" msgid "auth.password-length-hint"
msgstr "Ọ karịa mkpụrụ ederede asatọ" 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" msgid "auth.privacy-policy"
msgstr "Iwu oñiño onwe" msgstr "Iwu oñiño onwe"
@ -245,17 +233,13 @@ msgid "dashboard.access-tokens.create"
msgstr "Mepụta ọdịmara ọhụrụ" msgstr "Mepụta ọdịmara ọhụrụ"
#: src/app/main/ui/settings/access-tokens.cljs #: 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 ." msgstr "Mmepụtara ọdịmara nnweta gara nke ọma ."
#: src/app/main/ui/settings/access-tokens.cljs #: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.empty.add-one" msgid "dashboard.access-tokens.empty.add-one"
msgstr "Pịa mpi \"Nweta ọdịmara ọhụrụ \" inweta otu ." 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 #: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days" msgid "dashboard.access-tokens.expiration-180-days"
msgstr "Mkpụrụ ụbọchị narị na iri asatọ" 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." 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 #: 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" msgstr "Debanye aha ozi-n dabara adaba"
#: src/app/main/ui/settings/change_email.cljs #: 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ị" msgstr "Ozi-n nnabata ga-adabrịrị"
msgid "errors.email-spam-or-permanent-bounces" msgid "errors.email-spam-or-permanent-bounces"

View file

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

View file

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

View file

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

View file

@ -85,20 +85,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit" msgid "auth.login-with-oidc-submit"
msgstr "AtvērtoID (OpenID)" 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 #: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password" msgid "auth.new-password"
msgstr "Ierakstiet jaunu paroli" msgstr "Ierakstiet jaunu paroli"
#: src/app/main/ui/auth/recovery.cljs #: 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." msgstr "Atkopšanas tekstvienība nav derīga."
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
@ -127,10 +119,6 @@ msgstr "Parole"
msgid "auth.password-length-hint" msgid "auth.password-length-hint"
msgstr "Vismaz 8 rakstzīmes" 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" msgid "auth.privacy-policy"
msgstr "Privātuma politika" msgstr "Privātuma politika"
@ -287,7 +275,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Izveidot jaunu pilnvaru" msgstr "Izveidot jaunu pilnvaru"
#: src/app/main/ui/settings/access-tokens.cljs #: 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." msgstr "Piekļuves pilnvara ir veiksmīgi izveidota."
#: src/app/main/ui/settings/access-tokens.cljs #: 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" msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Pagaidām vēl nav pilnvaru." 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 #: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days" msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 dienas" 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/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.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" msgstr "Lūgums ievadīt derīgu e-pasta adresi"
#: src/app/main/ui/settings/change_email.cljs #: 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" msgstr "Apstiprinājuma e-pastam jāatbilst"
msgid "errors.email-spam-or-permanent-bounces" msgid "errors.email-spam-or-permanent-bounces"
@ -3062,10 +3046,6 @@ msgstr "Tālummaiņas palielinājums"
msgid "shortcuts.zoom-selected" msgid "shortcuts.zoom-selected"
msgstr "Tālummainīt uz atlasi" 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 #: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files" msgid "title.dashboard.files"
msgstr "%s - Penpot" msgstr "%s - Penpot"

View file

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

View file

@ -62,20 +62,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit" msgid "auth.login-with-oidc-submit"
msgstr "OpenID Connect" 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 #: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password" msgid "auth.new-password"
msgstr "Taip kata laluan baharu" msgstr "Taip kata laluan baharu"
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error" msgid "errors.invalid-recovery-token"
msgstr "Token pemulihan adalah tidak sah." msgstr "Token pemulihan adalah tidak sah."
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
@ -102,10 +94,6 @@ msgstr "Kata laluan"
msgid "auth.password-length-hint" msgid "auth.password-length-hint"
msgstr "Sekurang-kurangnya 8 aksara" 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" msgid "auth.privacy-policy"
msgstr "Dasar privasi" msgstr "Dasar privasi"
@ -263,7 +251,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Jana token baru" msgstr "Jana token baru"
#: src/app/main/ui/settings/access-tokens.cljs #: 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." msgstr "Token capaian berjaya dihasilkan."
#: src/app/main/ui/settings/access-tokens.cljs #: 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" msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Anda tidak mempunyai token setakat ini." 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 #: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days" msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 hari" msgstr "180 hari"
@ -840,11 +824,11 @@ msgid "errors.email-has-permanent-bounces"
msgstr "E-mel «%s» mempunyai banyak laporan lantunan kekal." 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 #: 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" msgstr "Sila masukkan e-mel yang sah"
#: src/app/main/ui/settings/change_email.cljs #: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation" msgid "errors.invalid-email-confirmation"
msgstr "E-mel pengesahan mesti sepadan" msgstr "E-mel pengesahan mesti sepadan"
msgid "errors.email-spam-or-permanent-bounces" msgid "errors.email-spam-or-permanent-bounces"

View file

@ -28,7 +28,7 @@ msgid "auth.new-password"
msgstr "Skriv inn et nytt passord" msgstr "Skriv inn et nytt passord"
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error" msgid "errors.invalid-recovery-token"
msgstr "Gjenopprettelsessymbolet er ugyldig." msgstr "Gjenopprettelsessymbolet er ugyldig."
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs #: 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" msgid "auth.login-with-oidc-submit"
msgstr "OpenID" 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 #: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password" msgid "auth.new-password"
msgstr "Typ een nieuw wachtwoord" msgstr "Typ een nieuw wachtwoord"
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error" msgid "errors.invalid-recovery-token"
msgstr "De herstelbewijsstuk is ongeldig." msgstr "De herstelbewijsstuk is ongeldig."
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
@ -138,10 +118,6 @@ msgstr "Wachtwoord"
msgid "auth.password-length-hint" msgid "auth.password-length-hint"
msgstr "Minimaal 8 tekens" 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" msgid "auth.privacy-policy"
msgstr "Privacybeleid" msgstr "Privacybeleid"
@ -301,7 +277,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Nieuw toegangsbewijs aanmaken" msgstr "Nieuw toegangsbewijs aanmaken"
#: src/app/main/ui/settings/access-tokens.cljs #: 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." msgstr "Toegangsbewijs is succesvol aangemaakt."
#: src/app/main/ui/settings/access-tokens.cljs #: 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" msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Je hebt nog geen toegangsbewijzen." 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 #: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days" msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 dagen" 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/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.cljs #: src/app/main/ui/auth/recovery_request.cljs
msgid "errors.email-invalid" msgid "errors.invalid-email"
msgstr "Voer een geldig e-mailadres in" msgstr "Voer een geldig e-mailadres in"
#: src/app/main/ui/settings/change_email.cljs #: src/app/main/ui/settings/change_email.cljs
msgid "errors.email-invalid-confirmation" msgid "errors.invalid-email-confirmation"
msgstr "Bevestigingsmail moet overeenkomen" msgstr "Bevestigingsmail moet overeenkomen"
msgid "errors.email-spam-or-permanent-bounces" msgid "errors.email-spam-or-permanent-bounces"
@ -3056,10 +3028,6 @@ msgstr "Zoomlens vergroten"
msgid "shortcuts.zoom-selected" msgid "shortcuts.zoom-selected"
msgstr "Zoomen naar selectie" 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 #: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files" msgid "title.dashboard.files"
msgstr "%s - Penpot" msgstr "%s - Penpot"

View file

@ -82,7 +82,7 @@ msgid "auth.new-password"
msgstr "Wpisz nowe hasło" msgstr "Wpisz nowe hasło"
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
msgid "auth.notifications.invalid-token-error" msgid "errors.invalid-recovery-token"
msgstr "Token odzyskiwania jest nieprawidłowy." msgstr "Token odzyskiwania jest nieprawidłowy."
#: src/app/main/ui/auth/recovery.cljs #: 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." 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 #: 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" msgstr "Podaj prawidłowy adres e-mail"
#: src/app/main/ui/settings/change_email.cljs #: 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" msgstr "E-mail potwierdzający musi być zgodny"
msgid "errors.email-spam-or-permanent-bounces" msgid "errors.email-spam-or-permanent-bounces"

View file

@ -81,7 +81,7 @@ msgid "auth.new-password"
msgstr "Digite uma nova senha" msgstr "Digite uma nova senha"
#: src/app/main/ui/auth/recovery.cljs #: 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." msgstr "O código de recuperação é inválido."
#: src/app/main/ui/auth/recovery.cljs #: 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." 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 #: 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" msgstr "Por favor, insira um email válido"
#: src/app/main/ui/settings/change_email.cljs #: 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" msgstr "E-mail de confirmação deve ser o mesmo"
msgid "errors.email-spam-or-permanent-bounces" msgid "errors.email-spam-or-permanent-bounces"

View file

@ -76,32 +76,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit" msgid "auth.login-with-oidc-submit"
msgstr "OpenID Connect" 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 #: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password" msgid "auth.new-password"
msgstr "Escreve uma nova palavra-passe" msgstr "Escreve uma nova palavra-passe"
#: src/app/main/ui/auth/recovery.cljs #: 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." msgstr "O token de recuperação é inválido."
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
@ -128,11 +108,6 @@ msgstr "Palavra-passe"
msgid "auth.password-length-hint" msgid "auth.password-length-hint"
msgstr "Mínimo de 8 caracteres" 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" msgid "auth.privacy-policy"
msgstr "Política de privacidade" msgstr "Política de privacidade"
@ -291,7 +266,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Gerar novo token" msgstr "Gerar novo token"
#: src/app/main/ui/settings/access-tokens.cljs #: 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." msgstr "Token de acesso criado com sucesso."
#: src/app/main/ui/settings/access-tokens.cljs #: 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" msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Ainda não tens nenhum token." 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 #: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days" msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 dias" 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/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.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" msgstr "Por favor introduz um email válido"
#: src/app/main/ui/settings/change_email.cljs #: 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" msgstr "O e-mail de confirmação deve combinar"
msgid "errors.email-spam-or-permanent-bounces" msgid "errors.email-spam-or-permanent-bounces"
@ -2989,10 +2960,6 @@ msgstr "Aumentar zoom na lupa"
msgid "shortcuts.zoom-selected" msgid "shortcuts.zoom-selected"
msgstr "Zoom para selecionados" 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 #: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files" msgid "title.dashboard.files"
msgstr "%s - Penpot" msgstr "%s - Penpot"

View file

@ -77,20 +77,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit" msgid "auth.login-with-oidc-submit"
msgstr "OpenID" 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 #: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password" msgid "auth.new-password"
msgstr "Introduceți o parolă nouă" msgstr "Introduceți o parolă nouă"
#: src/app/main/ui/auth/recovery.cljs #: 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." msgstr "Codul de recuperare nu este valid."
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
@ -119,10 +111,6 @@ msgstr "Parola"
msgid "auth.password-length-hint" msgid "auth.password-length-hint"
msgstr "Cel puțin 8 caractere" 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" msgid "auth.privacy-policy"
msgstr "Politica de Confidențialitate" msgstr "Politica de Confidențialitate"
@ -277,7 +265,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Generați jeton nou" msgstr "Generați jeton nou"
#: src/app/main/ui/settings/access-tokens.cljs #: 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." msgstr "Jeton de acces creat cu succes."
#: src/app/main/ui/settings/access-tokens.cljs #: 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" msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Nu aveți încă jetoane." 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 #: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days" msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 zile" 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/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.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" msgstr "Vă rugăm să introduceți un e-mail valid"
#: src/app/main/ui/settings/change_email.cljs #: 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ă" msgstr "E-mailul de confirmare trebuie să se potrivească"
msgid "errors.email-spam-or-permanent-bounces" msgid "errors.email-spam-or-permanent-bounces"
@ -2893,10 +2877,6 @@ msgstr "Creștere obiectiv de zoom"
msgid "shortcuts.zoom-selected" msgid "shortcuts.zoom-selected"
msgstr "Mărește la selecție" 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 #: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files" msgid "title.dashboard.files"
msgstr "%s - Penpot" msgstr "%s - Penpot"

View file

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

View file

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

View file

@ -86,20 +86,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit" msgid "auth.login-with-oidc-submit"
msgstr "OpenID" 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 #: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password" msgid "auth.new-password"
msgstr "Yeni bir parola gir" msgstr "Yeni bir parola gir"
#: src/app/main/ui/auth/recovery.cljs #: 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." msgstr "Kurtarma jetonu geçerli değil."
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
@ -126,10 +118,6 @@ msgstr "Parola"
msgid "auth.password-length-hint" msgid "auth.password-length-hint"
msgstr "En az 8 karakter" 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" msgid "auth.privacy-policy"
msgstr "Gizlilik politikası" msgstr "Gizlilik politikası"
@ -289,7 +277,7 @@ msgid "dashboard.access-tokens.create"
msgstr "Yeni belirteç oluştur" msgstr "Yeni belirteç oluştur"
#: src/app/main/ui/settings/access-tokens.cljs #: 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." msgstr "Erişim belirteci başarıyla oluşturuldu."
#: src/app/main/ui/settings/access-tokens.cljs #: 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" msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "Şu ana kadar hiç belirteciniz yok." 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 #: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days" msgid "dashboard.access-tokens.expiration-180-days"
msgstr "180 gün" 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/register.cljs, src/app/main/ui/auth/login.cljs,
#: src/app/main/ui/auth/recovery_request.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" msgstr "Lütfen geçerli bir e-posta adresi girin"
#: src/app/main/ui/settings/change_email.cljs #: 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" msgstr "Doğrulama e-postası eşleşmiyor"
msgid "errors.email-spam-or-permanent-bounces" msgid "errors.email-spam-or-permanent-bounces"
@ -3048,10 +3032,6 @@ msgstr "Görüntüyü büyült"
msgid "shortcuts.zoom-selected" msgid "shortcuts.zoom-selected"
msgstr "Seçilene yakınlaştır" 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 #: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files" msgid "title.dashboard.files"
msgstr "%s - Penpot" msgstr "%s - Penpot"

View file

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

View file

@ -72,16 +72,12 @@ msgstr "LDAP"
msgid "auth.login-with-oidc-submit" msgid "auth.login-with-oidc-submit"
msgstr "ṣílẹ̀kuǹ ìdánimọ̀" 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 #: src/app/main/ui/auth/recovery.cljs
msgid "auth.new-password" msgid "auth.new-password"
msgstr "tẹ ọ̀rọ̀ ìgbaniwọlé tuntun" msgstr "tẹ ọ̀rọ̀ ìgbaniwọlé tuntun"
#: src/app/main/ui/auth/recovery.cljs #: 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ẹ́." msgstr "àmì àtúnwárí ti díbàjẹ́."
#: src/app/main/ui/auth/recovery.cljs #: src/app/main/ui/auth/recovery.cljs
@ -110,10 +106,6 @@ msgstr "ọ̀rọ̀- ìgbaniwọlé"
msgid "auth.password-length-hint" msgid "auth.password-length-hint"
msgstr "kò gbọdọ̀ ju ohun kíkọ mẹ́jọ lọ" 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" msgid "auth.privacy-policy"
msgstr "ìpamọ ètò ìmúló" msgstr "ìpamọ ètò ìmúló"
@ -252,7 +244,7 @@ msgid "dashboard.access-tokens.create"
msgstr "ṣe ìpilẹ̀sẹ̀ àmì tókìnnì" msgstr "ṣe ìpilẹ̀sẹ̀ àmì tókìnnì"
#: src/app/main/ui/settings/access-tokens.cljs #: 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ẹ." msgstr "ṣe àyẹ̀wò àmì tókìnnì tí o ṣẹ̀dá bó ṣeyẹ."
#: src/app/main/ui/settings/access-tokens.cljs #: 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" msgid "dashboard.access-tokens.empty.no-access-tokens"
msgstr "o kò tí ì ní àmì tókínnì títí di ìsinsìn yìí." 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 #: src/app/main/ui/settings/access-tokens.cljs
msgid "dashboard.access-tokens.expiration-180-days" msgid "dashboard.access-tokens.expiration-180-days"
msgstr "ọgọ́saǹ-ań ọjọ́" 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ẹ́." 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 #: 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ọ́" msgstr "Tẹ àti wọlé pẹ̀lú ímeèlì tó wúlo jọ̀wọ́"
#: src/app/main/ui/settings/change_email.cljs #: 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" msgstr "Ímeèlì tí a ti mọ̀dájú gbọ́dọ̀ báramu"
msgid "errors.email-spam-or-permanent-bounces" msgid "errors.email-spam-or-permanent-bounces"
@ -2643,10 +2631,6 @@ msgstr "Lílọ̀soké lẹnsi sisun"
msgid "shortcuts.zoom-selected" msgid "shortcuts.zoom-selected"
msgstr "Yiyan pelu sun-un" 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 #: src/app/main/ui/dashboard/files.cljs
msgid "title.dashboard.files" msgid "title.dashboard.files"
msgstr "%s - Penpot" msgstr "%s - Penpot"

View file

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

View file

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