refactor: Improve i18n for complete account

This commit is contained in:
Myzel394 2023-03-04 22:53:23 +01:00
parent 7229078778
commit e5d1ee73c6
No known key found for this signature in database
GPG Key ID: 79CC92F37B3E1A2B
7 changed files with 64 additions and 54 deletions

View File

@ -13,6 +13,17 @@
}, },
"recoveryCode": { "recoveryCode": {
"label": "Recovery Code" "label": "Recovery Code"
},
"password": {
"label": "Password",
"placeholder": "********"
},
"passwordConfirmation": {
"label": "Confirm Password",
"placeholder": "********",
"errors": {
"mismatch": "Passwords do not match."
}
} }
}, },
"messages": { "messages": {
@ -21,6 +32,9 @@
} }
}, },
"general": { "general": {
"cancelLabel": "Cancel" "cancelLabel": "Cancel",
"yesLabel": "Yes",
"noLabel": "No",
"continueLabel": "Continue"
} }
} }

View File

@ -0,0 +1,12 @@
{
"forms": {
"askForGeneration": {
"title": "Generate Email Reports?",
"description": "Would you like to create fully encrypted email reports for your mails? Only you will be able to access them. Not even we can decrypt them."
},
"enterPassword": {
"title": "Set up your password",
"description": "Please enter a safe password so that we can encrypt your data."
}
}
}

View File

@ -28,12 +28,6 @@
}, },
"CompleteAccountRoute": { "CompleteAccountRoute": {
"forms": { "forms": {
"generateReports": {
"title": "Generate Email Reports?",
"description": "Would you like to create fully encrypted email reports for your mails? Only you will be able to access them. Not even we can decrypt them.",
"continueAction": "Yes",
"cancelAction": "No"
},
"password": { "password": {
"title": "Set up your password", "title": "Set up your password",
"description": "Please enter a safe password so that we can encrypt your data.", "description": "Please enter a safe password so that we can encrypt your data.",

View File

@ -5,12 +5,13 @@ import React, {ReactElement, useEffect, useState} from "react"
import {Alert, Button, Grid, Snackbar, Typography, TypographyProps} from "@mui/material" import {Alert, Button, Grid, Snackbar, Typography, TypographyProps} from "@mui/material"
import {LoadingButton} from "@mui/lab" import {LoadingButton} from "@mui/lab"
import {OverrideProps} from "@mui/types" import {OverrideProps} from "@mui/types"
import {useTranslation} from "react-i18next"
export interface SimpleFormProps { export interface SimpleFormProps {
title: string title: string
description: string description: string
continueActionLabel: string
continueActionLabel?: string
children?: ReactElement[] children?: ReactElement[]
cancelActionLabel?: string cancelActionLabel?: string
isSubmitting?: boolean isSubmitting?: boolean
@ -32,6 +33,8 @@ export default function SimpleForm({
titleComponent = "h1", titleComponent = "h1",
isSubmitting = false, isSubmitting = false,
}: SimpleFormProps): ReactElement { }: SimpleFormProps): ReactElement {
const {t} = useTranslation("common")
const [showSnackbar, setShowSnackbar] = useState<boolean>(false) const [showSnackbar, setShowSnackbar] = useState<boolean>(false)
useEffect(() => { useEffect(() => {
@ -101,7 +104,7 @@ export default function SimpleForm({
type="submit" type="submit"
startIcon={<MdChevronRight />} startIcon={<MdChevronRight />}
> >
{continueActionLabel} {continueActionLabel || t("general.continueLabel")}
</LoadingButton> </LoadingButton>
</Grid> </Grid>
</Grid> </Grid>

View File

@ -17,7 +17,7 @@ export default function GenerateEmailReportsForm({
onNo, onNo,
onYes, onYes,
}: GenerateEmailReportsFormProps): ReactElement { }: GenerateEmailReportsFormProps): ReactElement {
const {t} = useTranslation() const {t} = useTranslation(["complete-account", "common"])
return ( return (
<MultiStepFormElement> <MultiStepFormElement>
@ -37,9 +37,7 @@ export default function GenerateEmailReportsForm({
<Grid container spacing={4} direction="column"> <Grid container spacing={4} direction="column">
<Grid item> <Grid item>
<Typography variant="h6" component="h2" align="center"> <Typography variant="h6" component="h2" align="center">
{t( {t("forms.askForGeneration.title")}
"routes.CompleteAccountRoute.forms.generateReports.title",
)}
</Typography> </Typography>
</Grid> </Grid>
<Grid item> <Grid item>
@ -49,9 +47,7 @@ export default function GenerateEmailReportsForm({
</Grid> </Grid>
<Grid item> <Grid item>
<Typography variant="subtitle1" component="p"> <Typography variant="subtitle1" component="p">
{t( {t("forms.askForGeneration.description")}
"routes.CompleteAccountRoute.forms.generateReports.description",
)}
</Typography> </Typography>
</Grid> </Grid>
</Grid> </Grid>
@ -62,9 +58,7 @@ export default function GenerateEmailReportsForm({
<Grid container spacing={2} direction="row"> <Grid container spacing={2} direction="row">
<Grid item> <Grid item>
<Button startIcon={<TiCancel />} color="secondary" onClick={onNo}> <Button startIcon={<TiCancel />} color="secondary" onClick={onNo}>
{t( {t("general.noLabel", {ns: "common"})}
"routes.CompleteAccountRoute.forms.generateReports.cancelAction",
)}
</Button> </Button>
</Grid> </Grid>
<Grid item> <Grid item>
@ -73,9 +67,7 @@ export default function GenerateEmailReportsForm({
color="primary" color="primary"
onClick={onYes} onClick={onYes}
> >
{t( {t("general.yesLabel", {ns: "common"})}
"routes.CompleteAccountRoute.forms.generateReports.continueAction",
)}
</Button> </Button>
</Grid> </Grid>
</Grid> </Grid>

View File

@ -11,7 +11,7 @@ import {Box, InputAdornment} from "@mui/material"
import {useMutation} from "@tanstack/react-query" import {useMutation} from "@tanstack/react-query"
import {AuthContext, PasswordField, SimpleForm} from "~/components" import {AuthContext, PasswordField, SimpleForm} from "~/components"
import {setupEncryptionForUser} from "~/utils" import {parseFastAPIError, setupEncryptionForUser} from "~/utils"
import {useExtensionHandler, useNavigateToNext, useSystemPreferredTheme, useUser} from "~/hooks" import {useExtensionHandler, useNavigateToNext, useSystemPreferredTheme, useUser} from "~/hooks"
import {ServerSettings, ServerUser} from "~/server-types" import {ServerSettings, ServerUser} from "~/server-types"
import {UpdateAccountData, updateAccount} from "~/apis" import {UpdateAccountData, updateAccount} from "~/apis"
@ -27,7 +27,7 @@ interface Form {
} }
export default function PasswordForm({onDone}: PasswordFormProps): ReactElement { export default function PasswordForm({onDone}: PasswordFormProps): ReactElement {
const {t} = useTranslation() const {t} = useTranslation(["complete-account", "common"])
const user = useUser() const user = useUser()
const theme = useSystemPreferredTheme() const theme = useSystemPreferredTheme()
const serverSettings = useLoaderData() as ServerSettings const serverSettings = useLoaderData() as ServerSettings
@ -36,17 +36,18 @@ export default function PasswordForm({onDone}: PasswordFormProps): ReactElement
const $password = useRef<HTMLInputElement | null>(null) const $password = useRef<HTMLInputElement | null>(null)
const $passwordConfirmation = useRef<HTMLInputElement | null>(null) const $passwordConfirmation = useRef<HTMLInputElement | null>(null)
const schema = yup.object().shape({ const schema = yup.object().shape({
password: yup.string().required(), password: yup
.string()
.required()
.label(t("fields.password.label", {ns: "common"})),
passwordConfirmation: yup passwordConfirmation: yup
.string() .string()
.required() .required()
.oneOf( .oneOf(
[yup.ref("password"), null], [yup.ref("password"), null],
t( t("fields.passwordConfirmation.errors.mismatch", {ns: "common"}) as string,
"routes.CompleteAccountRoute.forms.password.form.passwordConfirm.mustMatchHelperText",
) as string,
) )
.label(t("routes.CompleteAccountRoute.forms.password.form.passwordConfirm.label")), .label(t("fields.passwordConfirmation.label", {ns: "common"})),
}) })
const {_setEncryptionPassword, login} = useContext(AuthContext) const {_setEncryptionPassword, login} = useContext(AuthContext)
@ -89,7 +90,7 @@ export default function PasswordForm({onDone}: PasswordFormProps): ReactElement
}, },
) )
} catch (error) { } catch (error) {
setErrors({detail: t("general.defaultError")}) setErrors(parseFastAPIError(error as AxiosError))
} }
}, },
}) })
@ -109,11 +110,8 @@ export default function PasswordForm({onDone}: PasswordFormProps): ReactElement
<Box maxWidth="80vw"> <Box maxWidth="80vw">
<form onSubmit={formik.handleSubmit}> <form onSubmit={formik.handleSubmit}>
<SimpleForm <SimpleForm
title={t("routes.CompleteAccountRoute.forms.password.title")} title={t("forms.enterPassword.title")}
description={t("routes.CompleteAccountRoute.forms.password.description")} description={t("forms.enterPassword.description")}
continueActionLabel={t(
"routes.CompleteAccountRoute.forms.password.continueAction",
)}
nonFieldError={formik.errors.detail} nonFieldError={formik.errors.detail}
> >
{[ {[
@ -123,12 +121,8 @@ export default function PasswordForm({onDone}: PasswordFormProps): ReactElement
autoFocus autoFocus
id="password" id="password"
name="password" name="password"
label={t( label={t("fields.password.label", {ns: "common"})}
"routes.CompleteAccountRoute.forms.password.form.password.label", placeholder={t("fields.password.placeholder", {ns: "common"})}
)}
placeholder={t(
"routes.CompleteAccountRoute.forms.password.form.password.placeholder",
)}
autoComplete="new-password" autoComplete="new-password"
value={formik.values.password} value={formik.values.password}
onChange={formik.handleChange} onChange={formik.handleChange}
@ -148,12 +142,10 @@ export default function PasswordForm({onDone}: PasswordFormProps): ReactElement
fullWidth fullWidth
id="passwordConfirmation" id="passwordConfirmation"
name="passwordConfirmation" name="passwordConfirmation"
label={t( label={t("fields.passwordConfirmation.label", {ns: "common"})}
"routes.CompleteAccountRoute.forms.password.form.passwordConfirm.label", placeholder={t("fields.passwordConfirmation.placeholder", {
)} ns: "common",
placeholder={t( })}
"routes.CompleteAccountRoute.forms.password.form.passwordConfirm.placeholder",
)}
value={formik.values.passwordConfirmation} value={formik.values.passwordConfirmation}
onChange={formik.handleChange} onChange={formik.handleChange}
disabled={formik.isSubmitting} disabled={formik.isSubmitting}

View File

@ -1,15 +1,18 @@
import {Outlet} from "react-router-dom" import {Outlet} from "react-router-dom"
import React, {ReactElement} from "react" import React, {ReactElement, Suspense} from "react"
import {AppLoadingScreen, AuthContextProvider, ExtensionSignalHandler} from "~/components" import {AppLoadingScreen, AuthContextProvider, ExtensionSignalHandler} from "~/components"
import LoadingPage from "~/components/widgets/LoadingPage"
export default function RootRoute(): ReactElement { export default function RootRoute(): ReactElement {
return ( return (
<AuthContextProvider> <Suspense fallback={<LoadingPage />}>
<AppLoadingScreen> <AuthContextProvider>
<Outlet /> <AppLoadingScreen>
</AppLoadingScreen> <Outlet />
<ExtensionSignalHandler /> </AppLoadingScreen>
</AuthContextProvider> <ExtensionSignalHandler />
</AuthContextProvider>
</Suspense>
) )
} }