mirror of
https://github.com/penpot/penpot.git
synced 2025-06-06 18:41:39 +02:00
🎉 Add newsletter subscription modal
This commit is contained in:
parent
b7e0619e9a
commit
5e7e055539
14 changed files with 270 additions and 19 deletions
|
@ -8,6 +8,7 @@
|
||||||
### :arrow_up: Deps updates
|
### :arrow_up: Deps updates
|
||||||
### :heart: Community contributions by (Thank you!)
|
### :heart: Community contributions by (Thank you!)
|
||||||
|
|
||||||
|
|
||||||
## 1.13.0-beta
|
## 1.13.0-beta
|
||||||
|
|
||||||
### :boom: Breaking changes
|
### :boom: Breaking changes
|
||||||
|
|
|
@ -342,13 +342,26 @@
|
||||||
|
|
||||||
;; --- MUTATION: Update Profile (own)
|
;; --- MUTATION: Update Profile (own)
|
||||||
|
|
||||||
|
(defn- update-profile-newsletter-subscribed
|
||||||
|
[conn profile-id newsletter-subscribed]
|
||||||
|
(let [profile (profile/retrieve-profile-data conn profile-id)
|
||||||
|
props (:props profile)
|
||||||
|
props (assoc props :newsletter-subscribed newsletter-subscribed)
|
||||||
|
]
|
||||||
|
(db/update! conn :profile
|
||||||
|
{:props (db/tjson props)}
|
||||||
|
{:id profile-id})))
|
||||||
|
|
||||||
(defn- update-profile
|
(defn- update-profile
|
||||||
[conn {:keys [id fullname lang theme] :as params}]
|
[conn {:keys [id fullname lang theme newsletter-subscribed] :as params}]
|
||||||
(let [profile (db/update! conn :profile
|
(let [profile (db/update! conn :profile
|
||||||
{:fullname fullname
|
{:fullname fullname
|
||||||
:lang lang
|
:lang lang
|
||||||
:theme theme}
|
:theme theme}
|
||||||
{:id id})]
|
{:id id})
|
||||||
|
profile (if (some? newsletter-subscribed)
|
||||||
|
(update-profile-newsletter-subscribed conn id newsletter-subscribed)
|
||||||
|
profile)]
|
||||||
(-> profile
|
(-> profile
|
||||||
(profile/decode-profile-row)
|
(profile/decode-profile-row)
|
||||||
(profile/strip-private-attrs))))
|
(profile/strip-private-attrs))))
|
||||||
|
|
BIN
frontend/resources/images/deco-news-left.png
Normal file
BIN
frontend/resources/images/deco-news-left.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
BIN
frontend/resources/images/deco-news-right.png
Normal file
BIN
frontend/resources/images/deco-news-right.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
frontend/resources/images/deco-newsletter.png
Normal file
BIN
frontend/resources/images/deco-newsletter.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
|
@ -109,6 +109,38 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
max-width: 368px;
|
max-width: 368px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
.newsletter-subs {
|
||||||
|
border-bottom: 1px solid $color-gray-20;
|
||||||
|
border-top: 1px solid $color-gray-20;
|
||||||
|
padding: 30px 0;
|
||||||
|
margin-bottom: 31px;
|
||||||
|
|
||||||
|
.newsletter-title {
|
||||||
|
font-family: "worksans", sans-serif;
|
||||||
|
color: $color-gray-30;
|
||||||
|
font-size: $fs14;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-family: "worksans", sans-serif;
|
||||||
|
color: $color-gray-60;
|
||||||
|
font-size: $fs12;
|
||||||
|
margin-right: -17px;
|
||||||
|
margin-bottom: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
font-family: "worksans", sans-serif;
|
||||||
|
color: $color-gray-30;
|
||||||
|
font-size: $fs12;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-checkbox label {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.options-form,
|
.options-form,
|
||||||
|
|
|
@ -996,6 +996,57 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.newsletter {
|
||||||
|
padding: $size-5 0 0 0;
|
||||||
|
flex-direction: column;
|
||||||
|
min-width: 555px;
|
||||||
|
.modal-top {
|
||||||
|
padding: 87px 40px 0 40px;
|
||||||
|
color: $color-gray-60;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-family: sourcesanspro;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: $fs36;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-family: sourcesanspro;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: $fs16;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-bottom {
|
||||||
|
margin: 0 32px;
|
||||||
|
padding: 32px 0;
|
||||||
|
color: $color-gray-60;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
border-top: 1px solid $color-gray-10;
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-family: "worksans", sans-serif;
|
||||||
|
text-align: left;
|
||||||
|
color: $color-gray-30;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
padding: 17px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.deco {
|
.deco {
|
||||||
|
@ -1004,6 +1055,23 @@
|
||||||
top: -18px;
|
top: -18px;
|
||||||
width: 60px;
|
width: 60px;
|
||||||
|
|
||||||
|
&.top {
|
||||||
|
width: 183px;
|
||||||
|
top: -106px;
|
||||||
|
left: 161px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.newsletter-right {
|
||||||
|
left: 515px;
|
||||||
|
top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.newsletter-left {
|
||||||
|
width: 26px;
|
||||||
|
left: -15px;
|
||||||
|
top: -15px;
|
||||||
|
}
|
||||||
|
|
||||||
&.right {
|
&.right {
|
||||||
left: 590px;
|
left: 590px;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|
|
@ -304,7 +304,7 @@
|
||||||
(let [mdata (meta data)
|
(let [mdata (meta data)
|
||||||
on-success (:on-success mdata identity)
|
on-success (:on-success mdata identity)
|
||||||
on-error (:on-error mdata #(rx/throw %))]
|
on-error (:on-error mdata #(rx/throw %))]
|
||||||
(->> (rp/mutation :update-profile data)
|
(->> (rp/mutation :update-profile (dissoc data :props))
|
||||||
(rx/catch on-error)
|
(rx/catch on-error)
|
||||||
(rx/mapcat
|
(rx/mapcat
|
||||||
(fn [_]
|
(fn [_]
|
||||||
|
@ -392,7 +392,6 @@
|
||||||
(->> (rp/mutation :update-profile-props {:props props})
|
(->> (rp/mutation :update-profile-props {:props props})
|
||||||
(rx/map (constantly (fetch-profile)))))))))
|
(rx/map (constantly (fetch-profile)))))))))
|
||||||
|
|
||||||
|
|
||||||
(defn mark-questions-as-answered
|
(defn mark-questions-as-answered
|
||||||
[]
|
[]
|
||||||
(ptk/reify ::mark-questions-as-answered
|
(ptk/reify ::mark-questions-as-answered
|
||||||
|
|
|
@ -59,15 +59,15 @@
|
||||||
|
|
||||||
klass (str more-classes " "
|
klass (str more-classes " "
|
||||||
(dom/classnames
|
(dom/classnames
|
||||||
:focus @focus?
|
:focus @focus?
|
||||||
:valid (and touched? (not error))
|
:valid (and touched? (not error))
|
||||||
:invalid (and touched? error)
|
:invalid (and touched? error)
|
||||||
:disabled disabled
|
:disabled disabled
|
||||||
:empty (and is-text? (str/empty? value))
|
:empty (and is-text? (str/empty? value))
|
||||||
:with-icon (not (nil? help-icon'))
|
:with-icon (not (nil? help-icon'))
|
||||||
:custom-input is-text?
|
:custom-input is-text?
|
||||||
:input-radio is-radio?
|
:input-radio is-radio?
|
||||||
:input-checkbox is-checkbox?))
|
:input-checkbox is-checkbox?))
|
||||||
|
|
||||||
swap-text-password
|
swap-text-password
|
||||||
(fn []
|
(fn []
|
||||||
|
@ -97,6 +97,7 @@
|
||||||
:placeholder label
|
:placeholder label
|
||||||
:on-change on-change
|
:on-change on-change
|
||||||
:type @type')
|
:type @type')
|
||||||
|
(cond-> (and value is-checkbox?) (assoc :default-checked value))
|
||||||
(obj/clj->props))]
|
(obj/clj->props))]
|
||||||
|
|
||||||
[:div
|
[:div
|
||||||
|
@ -210,7 +211,7 @@
|
||||||
(let [form (or form (mf/use-ctx form-ctx))]
|
(let [form (or form (mf/use-ctx form-ctx))]
|
||||||
[:input.btn-primary.btn-large
|
[:input.btn-primary.btn-large
|
||||||
{:name "submit"
|
{:name "submit"
|
||||||
:class (when-not (:valid @form) "btn-disabled")
|
:class (when (or (not (:valid @form)) (true? disabled)) "btn-disabled")
|
||||||
:disabled (or (not (:valid @form)) (true? disabled))
|
:disabled (or (not (:valid @form)) (true? disabled))
|
||||||
:on-click on-click
|
:on-click on-click
|
||||||
:value label
|
:value label
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[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.onboarding.newsletter]
|
||||||
[app.main.ui.onboarding.questions]
|
[app.main.ui.onboarding.questions]
|
||||||
[app.main.ui.onboarding.team-choice]
|
[app.main.ui.onboarding.team-choice]
|
||||||
[app.main.ui.onboarding.templates]
|
[app.main.ui.onboarding.templates]
|
||||||
|
@ -154,7 +155,7 @@
|
||||||
skip
|
skip
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
(st/emitf (modal/hide)
|
(st/emitf (modal/hide)
|
||||||
(modal/show {:type :onboarding-choice})
|
(modal/show {:type :onboarding-newsletter-modal})
|
||||||
(du/mark-onboarding-as-viewed)))]
|
(du/mark-onboarding-as-viewed)))]
|
||||||
|
|
||||||
(mf/use-layout-effect
|
(mf/use-layout-effect
|
||||||
|
|
47
frontend/src/app/main/ui/onboarding/newsletter.cljs
Normal file
47
frontend/src/app/main/ui/onboarding/newsletter.cljs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) UXBOX Labs SL
|
||||||
|
|
||||||
|
(ns app.main.ui.onboarding.newsletter
|
||||||
|
(:require
|
||||||
|
[app.main.data.messages :as dm]
|
||||||
|
[app.main.data.modal :as modal]
|
||||||
|
[app.main.data.users :as du]
|
||||||
|
[app.main.store :as st]
|
||||||
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
|
[rumext.alpha :as mf]))
|
||||||
|
|
||||||
|
(mf/defc onboarding-newsletter-modal
|
||||||
|
{::mf/register modal/components
|
||||||
|
::mf/register-as :onboarding-newsletter-modal}
|
||||||
|
[]
|
||||||
|
(let [message (tr "onboarding.newsletter.acceptance-message")
|
||||||
|
accept
|
||||||
|
(mf/use-callback
|
||||||
|
(fn []
|
||||||
|
(st/emit! (dm/success message)
|
||||||
|
(modal/show {:type :onboarding-choice})
|
||||||
|
(du/update-profile-props {:newsletter-subscribed true}))))
|
||||||
|
|
||||||
|
decline
|
||||||
|
(mf/use-callback
|
||||||
|
(fn []
|
||||||
|
(st/emit! (modal/show {:type :onboarding-choice})
|
||||||
|
(du/update-profile-props {:newsletter-subscribed false}))))]
|
||||||
|
|
||||||
|
[:div.modal-overlay
|
||||||
|
[:div.modal-container.onboarding.newsletter.animated.fadeInUp
|
||||||
|
[:div.modal-top
|
||||||
|
[:h1.newsletter-title {:data-test "onboarding-newsletter-title"} (tr "onboarding.newsletter.title")]
|
||||||
|
[:p (tr "onboarding.newsletter.desc")]]
|
||||||
|
[:div.modal-bottom
|
||||||
|
[:p (tr "onboarding.newsletter.privacy1") [:a {:target "_blank" :href "https://penpot.app/privacy.html"} (tr "onboarding.newsletter.policy")]]
|
||||||
|
[:p (tr "onboarding.newsletter.privacy2")]]
|
||||||
|
[:div.modal-footer
|
||||||
|
[:button.btn-secondary {:on-click decline} (tr "onboarding.newsletter.decline")]
|
||||||
|
[:button.btn-primary {:on-click accept} (tr "onboarding.newsletter.accept")]]
|
||||||
|
[:img.deco.top {:src "images/deco-newsletter.png" :border "0"}]
|
||||||
|
[:img.deco.newsletter-left {:src "images/deco-news-left.png" :border "0"}]
|
||||||
|
[:img.deco.newsletter-right {:src "images/deco-news-right.png" :border "0"}]]]))
|
|
@ -43,13 +43,17 @@
|
||||||
[{:keys [locale] :as props}]
|
[{:keys [locale] :as props}]
|
||||||
(let [profile (mf/deref refs/profile)
|
(let [profile (mf/deref refs/profile)
|
||||||
form (fm/use-form :spec ::profile-form
|
form (fm/use-form :spec ::profile-form
|
||||||
:initial profile)]
|
:initial profile)
|
||||||
|
disabled-button (mf/use-state true)
|
||||||
|
activate-btn #(reset! disabled-button false)]
|
||||||
|
|
||||||
[:& fm/form {:on-submit on-submit
|
[:& fm/form {:on-submit on-submit
|
||||||
:form form
|
:form form
|
||||||
:class "profile-form"}
|
:class "profile-form"}
|
||||||
[:div.fields-row
|
[:div.fields-row
|
||||||
[:& fm/input
|
[:& fm/input
|
||||||
{:type "text"
|
{:type "text"
|
||||||
|
:on-key-down activate-btn
|
||||||
:name :fullname
|
:name :fullname
|
||||||
:label (t locale "dashboard.your-name")}]]
|
:label (t locale "dashboard.your-name")}]]
|
||||||
|
|
||||||
|
@ -66,8 +70,19 @@
|
||||||
[:a {:on-click #(modal/show! :change-email {})}
|
[:a {:on-click #(modal/show! :change-email {})}
|
||||||
(t locale "dashboard.change-email")]]]]
|
(t locale "dashboard.change-email")]]]]
|
||||||
|
|
||||||
|
[:div.newsletter-subs
|
||||||
|
[:p.newsletter-title (tr "dashboard.newsletter-title")]
|
||||||
|
[:& fm/input {:name :newsletter-subscribed
|
||||||
|
:class "check-primary"
|
||||||
|
:type "checkbox"
|
||||||
|
:label (tr "dashboard.newsletter-msg")
|
||||||
|
:on-click activate-btn}]
|
||||||
|
[:p.info (tr "onboarding.newsletter.privacy1") [:a {:target "_blank" :href "https://penpot.app/privacy.html"} (tr "onboarding.newsletter.policy")]]
|
||||||
|
[:p.info (tr "onboarding.newsletter.privacy2")]]
|
||||||
|
|
||||||
[:& fm/submit-button
|
[:& fm/submit-button
|
||||||
{:label (t locale "dashboard.update-settings")}]
|
{:label (t locale "dashboard.save-settings")
|
||||||
|
:disabled @disabled-button}]
|
||||||
|
|
||||||
[:div.links
|
[:div.links
|
||||||
[:div.link-item
|
[:div.link-item
|
||||||
|
|
|
@ -581,7 +581,19 @@ msgstr "Search results"
|
||||||
msgid "dashboard.type-something"
|
msgid "dashboard.type-something"
|
||||||
msgstr "Type to search results"
|
msgstr "Type to search results"
|
||||||
|
|
||||||
#: src/app/main/ui/settings/profile.cljs, src/app/main/ui/settings/password.cljs, src/app/main/ui/settings/options.cljs
|
#: src/app/main/ui/settings/profile.cljs
|
||||||
|
msgid "dashboard.save-settings"
|
||||||
|
msgstr "Save settings"
|
||||||
|
|
||||||
|
#: src/app/main/ui/settings/profile.cljs
|
||||||
|
msgid "dashboard.newsletter-title"
|
||||||
|
msgstr "Newsletter subscription"
|
||||||
|
|
||||||
|
#: src/app/main/ui/settings/profile.cljs
|
||||||
|
msgid "dashboard.newsletter-msg"
|
||||||
|
msgstr "Send me news, product updates and recommendations about Penpot."
|
||||||
|
|
||||||
|
#: src/app/main/ui/settings/password.cljs, src/app/main/ui/settings/options.cljs
|
||||||
msgid "dashboard.update-settings"
|
msgid "dashboard.update-settings"
|
||||||
msgstr "Update settings"
|
msgstr "Update settings"
|
||||||
|
|
||||||
|
@ -1855,6 +1867,30 @@ msgstr ""
|
||||||
msgid "onboarding.welcome.title"
|
msgid "onboarding.welcome.title"
|
||||||
msgstr "Welcome to Penpot"
|
msgstr "Welcome to Penpot"
|
||||||
|
|
||||||
|
msgid "onboarding.newsletter.title"
|
||||||
|
msgstr "Want to receive Penpot news?"
|
||||||
|
|
||||||
|
msgid "onboarding.newsletter.desc"
|
||||||
|
msgstr "Subscribe to our newsletter to stay up to date with product development progress and news."
|
||||||
|
|
||||||
|
msgid "onboarding.newsletter.privacy1"
|
||||||
|
msgstr "Because we care about privacy, here's our "
|
||||||
|
|
||||||
|
msgid "onboarding.newsletter.policy"
|
||||||
|
msgstr "Privacy Policy."
|
||||||
|
|
||||||
|
msgid "onboarding.newsletter.privacy2"
|
||||||
|
msgstr "We will only send relevant emails to you. You can unsubscribe at any time in your user profile or via the unsubscribe link in any of our newsletters."
|
||||||
|
|
||||||
|
msgid "onboarding.newsletter.accept"
|
||||||
|
msgstr "Yes, subscribe"
|
||||||
|
|
||||||
|
msgid "onboarding.newsletter.decline"
|
||||||
|
msgstr "No, thanks"
|
||||||
|
|
||||||
|
msgid "onboarding.newsletter.acceptance-message"
|
||||||
|
msgstr "Your subscription request has been sent, we will send you an email to confirm it."
|
||||||
|
|
||||||
#: src/app/main/ui/auth/recovery.cljs
|
#: src/app/main/ui/auth/recovery.cljs
|
||||||
msgid "profile.recovery.go-to-login"
|
msgid "profile.recovery.go-to-login"
|
||||||
msgstr "Go to login"
|
msgstr "Go to login"
|
||||||
|
|
|
@ -587,7 +587,20 @@ msgstr "Resultados de búsqueda"
|
||||||
msgid "dashboard.type-something"
|
msgid "dashboard.type-something"
|
||||||
msgstr "Escribe algo para buscar"
|
msgstr "Escribe algo para buscar"
|
||||||
|
|
||||||
#: src/app/main/ui/settings/profile.cljs, src/app/main/ui/settings/password.cljs, src/app/main/ui/settings/options.cljs
|
#: src/app/main/ui/settings/profile.cljs
|
||||||
|
msgid "dashboard.save-settings"
|
||||||
|
msgstr "Guardar opciones"
|
||||||
|
|
||||||
|
#: src/app/main/ui/settings/profile.cljs
|
||||||
|
msgid "dashboard.newsletter-title"
|
||||||
|
msgstr "Suscripción a newsletter"
|
||||||
|
|
||||||
|
#: src/app/main/ui/settings/profile.cljs
|
||||||
|
msgid "dashboard.newsletter-msg"
|
||||||
|
msgstr "Envíame noticias, actualizaciones de producto y recomendaciones sobre Penpot."
|
||||||
|
|
||||||
|
|
||||||
|
#: src/app/main/ui/settings/password.cljs, src/app/main/ui/settings/options.cljs
|
||||||
msgid "dashboard.update-settings"
|
msgid "dashboard.update-settings"
|
||||||
msgstr "Actualizar opciones"
|
msgstr "Actualizar opciones"
|
||||||
|
|
||||||
|
@ -1876,6 +1889,31 @@ msgstr ""
|
||||||
msgid "onboarding.welcome.title"
|
msgid "onboarding.welcome.title"
|
||||||
msgstr "Te damos la bienvenida a Penpot"
|
msgstr "Te damos la bienvenida a Penpot"
|
||||||
|
|
||||||
|
msgid "onboarding.newsletter.title"
|
||||||
|
msgstr "¿Quieres recibir noticias sobre Penpot?"
|
||||||
|
|
||||||
|
msgid "onboarding.newsletter.desc"
|
||||||
|
msgstr "Suscríbete a nuestra newsletter para estar al día de los progresos del producto y noticias."
|
||||||
|
|
||||||
|
msgid "onboarding.newsletter.privacy1"
|
||||||
|
msgstr "Porque nos importa la privacidad, aquí puedes ver nuestra "
|
||||||
|
|
||||||
|
msgid "onboarding.newsletter.policy"
|
||||||
|
msgstr "Política de Privacidad."
|
||||||
|
|
||||||
|
msgid "onboarding.newsletter.privacy2"
|
||||||
|
msgstr "Sólo te enviaremos emails relevantes para ti. Puedes desuscribirte en cualquier momento desde tu perfil o usando el vínculo de desuscripción en cualquiera de nuestras newsletters."
|
||||||
|
|
||||||
|
msgid "onboarding.newsletter.accept"
|
||||||
|
msgstr "Si, suscribirme"
|
||||||
|
|
||||||
|
msgid "onboarding.newsletter.decline"
|
||||||
|
msgstr "No, gracias"
|
||||||
|
|
||||||
|
msgid "onboarding.newsletter.acceptance-message"
|
||||||
|
msgstr "Tu solicitud de suscripción ha sido enviada, te haremos una confirmación a tu email"
|
||||||
|
|
||||||
|
|
||||||
#: src/app/main/ui/auth/recovery.cljs
|
#: src/app/main/ui/auth/recovery.cljs
|
||||||
msgid "profile.recovery.go-to-login"
|
msgid "profile.recovery.go-to-login"
|
||||||
msgstr "Ir al login"
|
msgstr "Ir al login"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue