binwiederhier 3 лет назад
Родитель
Сommit
66cb35b5fc

+ 0 - 3
server/server.go

@@ -49,10 +49,7 @@ import (
 			- "mute" setting
 			- figure out what settings are "web" or "phone"
 		UI:
-		- Translations
-		- aria-labels
 		- Home UI sign-in/login to top right
-		-
 		rate limiting:
 		- login/account endpoints
 		Tests:

+ 13 - 0
web/public/static/langs/en.json

@@ -1,4 +1,17 @@
 {
+  "signup_title": "Create a ntfy account",
+  "signup_form_username": "Username",
+  "signup_form_password": "Password",
+  "signup_form_confirm_password": "Confirm password",
+  "signup_form_button_submit": "Sign up",
+  "signup_already_have_account": "Already have an account? Sign in!",
+  "signup_disabled": "Signup is disabled",
+  "signup_error_username_taken": "Username {{username}} is already taken",
+  "signup_error_creation_limit_reached": "Account creation limit reached",
+  "signup_error_unknown": "Unknown error. Check logs for details.",
+  "login_title": "Sign in to your ntfy account",
+  "login_form_button_submit": "Sign in",
+  "login_link_signup": "Sign up",
   "action_bar_show_menu": "Show menu",
   "action_bar_logo_alt": "ntfy logo",
   "action_bar_settings": "Settings",

+ 8 - 55
web/src/components/Account.js

@@ -21,6 +21,7 @@ import IconButton from "@mui/material/IconButton";
 import {useOutletContext} from "react-router-dom";
 import {formatBytes} from "../app/utils";
 import accountApi, {UnauthorizedError} from "../app/AccountApi";
+import {Pref, PrefGroup} from "./Pref";
 
 const Account = () => {
     if (!session.exists()) {
@@ -56,9 +57,11 @@ const Basics = () => {
 const Username = () => {
     const { t } = useTranslation();
     const { account } = useOutletContext();
+    const labelId = "prefUsername";
+
     return (
-        <Pref title={t("account_basics_username_title")} description={t("account_basics_username_description")}>
-            <div>
+        <Pref labelId={labelId} title={t("account_basics_username_title")} description={t("account_basics_username_description")}>
+            <div aria-labelledby={labelId}>
                 {session.username()}
                 {account?.role === "admin"
                     ? <>{" "}<Tooltip title={t("account_basics_username_admin_tooltip")}><span style={{cursor: "default"}}>👑</span></Tooltip></>
@@ -72,6 +75,7 @@ const ChangePassword = () => {
     const { t } = useTranslation();
     const [dialogKey, setDialogKey] = useState(0);
     const [dialogOpen, setDialogOpen] = useState(false);
+    const labelId = "prefChangePassword";
 
     const handleDialogOpen = () => {
         setDialogKey(prev => prev+1);
@@ -97,8 +101,8 @@ const ChangePassword = () => {
     };
 
     return (
-        <Pref title={t("account_basics_password_title")} description={t("account_basics_password_description")}>
-            <div>
+        <Pref labelId={labelId} title={t("account_basics_password_title")} description={t("account_basics_password_description")}>
+            <div aria-labelledby={labelId}>
                 <Typography color="gray" sx={{float: "left", fontSize: "0.7rem", lineHeight: "3.5"}}>⬤⬤⬤⬤⬤⬤⬤⬤⬤⬤</Typography>
                 <IconButton onClick={handleDialogOpen} aria-label={t("account_basics_password_description")}>
                     <EditIcon/>
@@ -302,55 +306,4 @@ const DeleteAccountDialog = (props) => {
     );
 };
 
-
-// FIXME duplicate code
-
-const PrefGroup = (props) => {
-    return (
-        <div role="table">
-            {props.children}
-        </div>
-    )
-};
-
-const Pref = (props) => {
-    return (
-        <div
-            role="row"
-            style={{
-                display: "flex",
-                flexDirection: "row",
-                marginTop: "10px",
-                marginBottom: "20px",
-            }}
-        >
-            <div
-                role="cell"
-                aria-label={props.title}
-                style={{
-                    flex: '1 0 40%',
-                    display: 'flex',
-                    flexDirection: 'column',
-                    justifyContent: 'center',
-                    paddingRight: '30px'
-                }}
-            >
-                <div><b>{props.title}</b>{props.subtitle && <em> ({props.subtitle})</em>}</div>
-                {props.description && <div><em>{props.description}</em></div>}
-            </div>
-            <div
-                role="cell"
-                style={{
-                    flex: '1 0 calc(60% - 50px)',
-                    display: 'flex',
-                    flexDirection: 'column',
-                    justifyContent: 'center'
-                }}
-            >
-                {props.children}
-            </div>
-        </div>
-    );
-};
-
 export default Account;

+ 5 - 5
web/src/components/Login.js

@@ -46,7 +46,7 @@ const Login = () => {
     return (
         <AvatarBox>
             <Typography sx={{ typography: 'h6' }}>
-                {t("Sign in to your ntfy account")}
+                {t("login_title")}
             </Typography>
             <Box component="form" onSubmit={handleSubmit} noValidate sx={{mt: 1, maxWidth: 400}}>
                 <TextField
@@ -54,7 +54,7 @@ const Login = () => {
                     required
                     fullWidth
                     id="username"
-                    label={t("Username")}
+                    label={t("signup_form_username")}
                     name="username"
                     value={username}
                     onChange={ev => setUsername(ev.target.value.trim())}
@@ -65,7 +65,7 @@ const Login = () => {
                     required
                     fullWidth
                     name="password"
-                    label={t("Password")}
+                    label={t("signup_form_password")}
                     type="password"
                     id="password"
                     value={password}
@@ -79,7 +79,7 @@ const Login = () => {
                     disabled={username === "" || password === ""}
                     sx={{mt: 2, mb: 2}}
                 >
-                    {t("Sign in")}
+                    {t("login_form_button_submit")}
                 </Button>
                 {error &&
                     <Box sx={{
@@ -94,7 +94,7 @@ const Login = () => {
                 }
                 <Box sx={{width: "100%"}}>
                     {config.enableResetPassword && <div style={{float: "left"}}><NavLink to={routes.resetPassword} variant="body1">{t("Reset password")}</NavLink></div>}
-                    {config.enableSignup && <div style={{float: "right"}}><NavLink to={routes.signup} variant="body1">{t("Sign up")}</NavLink></div>}
+                    {config.enableSignup && <div style={{float: "right"}}><NavLink to={routes.signup} variant="body1">{t("login_link_signup")}</NavLink></div>}
                 </Box>
             </Box>
         </AvatarBox>

+ 50 - 0
web/src/components/Pref.js

@@ -0,0 +1,50 @@
+import * as React from "react";
+
+export const PrefGroup = (props) => {
+    return (
+        <div role="table">
+            {props.children}
+        </div>
+    )
+};
+
+export const Pref = (props) => {
+    return (
+        <div
+            role="row"
+            style={{
+                display: "flex",
+                flexDirection: "row",
+                marginTop: "10px",
+                marginBottom: "20px",
+            }}
+        >
+            <div
+                role="cell"
+                id={props.labelId ?? ""}
+                aria-label={props.title}
+                style={{
+                    flex: '1 0 40%',
+                    display: 'flex',
+                    flexDirection: 'column',
+                    justifyContent: 'center',
+                    paddingRight: '30px'
+                }}
+            >
+                <div><b>{props.title}</b>{props.subtitle && <em> ({props.subtitle})</em>}</div>
+                {props.description && <div><em>{props.description}</em></div>}
+            </div>
+            <div
+                role="cell"
+                style={{
+                    flex: '1 0 calc(60% - 50px)',
+                    display: 'flex',
+                    flexDirection: 'column',
+                    justifyContent: 'center'
+                }}
+            >
+                {props.children}
+            </div>
+        </div>
+    );
+};

+ 1 - 49
web/src/components/Preferences.js

@@ -37,6 +37,7 @@ import {useTranslation} from "react-i18next";
 import session from "../app/Session";
 import routes from "./routes";
 import accountApi, {UnauthorizedError} from "../app/AccountApi";
+import {Pref, PrefGroup} from "./Pref";
 
 const Preferences = () => {
     return (
@@ -191,55 +192,6 @@ const DeleteAfter = () => {
     )
 };
 
-const PrefGroup = (props) => {
-    return (
-        <div role="table">
-            {props.children}
-        </div>
-    )
-};
-
-const Pref = (props) => {
-    return (
-        <div
-            role="row"
-            style={{
-                display: "flex",
-                flexDirection: "row",
-                marginTop: "10px",
-                marginBottom: "20px",
-            }}
-        >
-            <div
-                role="cell"
-                id={props.labelId}
-                aria-label={props.title}
-                style={{
-                    flex: '1 0 40%',
-                    display: 'flex',
-                    flexDirection: 'column',
-                    justifyContent: 'center',
-                    paddingRight: '30px'
-                }}
-            >
-                <div><b>{props.title}</b></div>
-                {props.description && <div><em>{props.description}</em></div>}
-            </div>
-            <div
-                role="cell"
-                style={{
-                    flex: '1 0 calc(60% - 50px)',
-                    display: 'flex',
-                    flexDirection: 'column',
-                    justifyContent: 'center'
-                }}
-            >
-                {props.children}
-            </div>
-        </div>
-    );
-};
-
 const Users = () => {
     const { t } = useTranslation();
     const [dialogKey, setDialogKey] = useState(0);

+ 10 - 10
web/src/components/Signup.js

@@ -30,27 +30,27 @@ const Signup = () => {
         } catch (e) {
             console.log(`[Signup] Signup for user ${user.username} failed`, e);
             if ((e instanceof UsernameTakenError)) {
-                setError(t("Username {{username}} is already taken", { username: e.username }));
+                setError(t("signup_error_username_taken", { username: e.username }));
             } else if ((e instanceof AccountCreateLimitReachedError)) {
-                setError(t("Account creation limit reached"));
+                setError(t("signup_error_creation_limit_reached"));
             } else if (e.message) {
                 setError(e.message);
             } else {
-                setError(t("Unknown error. Check logs for details."))
+                setError(t("signup_error_unknown"))
             }
         }
     };
     if (!config.enableSignup) {
         return (
             <AvatarBox>
-                <Typography sx={{ typography: 'h6' }}>{t("Signup is disabled")}</Typography>
+                <Typography sx={{ typography: 'h6' }}>{t("signup_disabled")}</Typography>
             </AvatarBox>
         );
     }
     return (
         <AvatarBox>
             <Typography sx={{ typography: 'h6' }}>
-                {t("Create a ntfy account")}
+                {t("signup_title")}
             </Typography>
             <Box component="form" onSubmit={handleSubmit} noValidate sx={{mt: 1, maxWidth: 400}}>
                 <TextField
@@ -58,7 +58,7 @@ const Signup = () => {
                     required
                     fullWidth
                     id="username"
-                    label="Username"
+                    label={t("signup_form_username")}
                     name="username"
                     value={username}
                     onChange={ev => setUsername(ev.target.value.trim())}
@@ -69,7 +69,7 @@ const Signup = () => {
                     required
                     fullWidth
                     name="password"
-                    label="Password"
+                    label={t("signup_form_password")}
                     type="password"
                     id="password"
                     autoComplete="current-password"
@@ -81,7 +81,7 @@ const Signup = () => {
                     required
                     fullWidth
                     name="confirm-password"
-                    label="Confirm password"
+                    label={t("signup_form_confirm_password")}
                     type="password"
                     id="confirm-password"
                     value={confirm}
@@ -95,7 +95,7 @@ const Signup = () => {
                     disabled={username === "" || password === "" || password !== confirm}
                     sx={{mt: 2, mb: 2}}
                 >
-                    {t("Sign up")}
+                    {t("signup_form_button_submit")}
                 </Button>
                 {error &&
                     <Box sx={{
@@ -112,7 +112,7 @@ const Signup = () => {
             {config.enableLogin &&
                 <Typography sx={{mb: 4}}>
                     <NavLink to={routes.login} variant="body1">
-                        {t("Already have an account? Sign in!")}
+                        {t("signup_already_have_account")}
                     </NavLink>
                 </Typography>
             }