From 6613f4547a8de729f570c4f57f8373c77b46436b Mon Sep 17 00:00:00 2001 From: Olivier 'reivilibre Date: Thu, 25 Jul 2024 22:15:36 +0100 Subject: [PATCH] frontend: pull out translations of SetPasswordStatus into function --- frontend/locales/en.json | 4 ++ frontend/src/i18n/password_changes.ts | 71 +++++++++++++++++++ .../src/routes/password.change.index.lazy.tsx | 31 ++------ 3 files changed, 80 insertions(+), 26 deletions(-) create mode 100644 frontend/src/i18n/password_changes.ts diff --git a/frontend/locales/en.json b/frontend/locales/en.json index cbdd3257..e72ae3bd 100644 --- a/frontend/locales/en.json +++ b/frontend/locales/en.json @@ -112,9 +112,13 @@ "current_password_label": "Current password", "failure": { "description": { + "account_locked": "Your account is locked and can not be recovered at this time. If this is not expected, please contact your server administrator.", + "expired_recovery_ticket": "The recovery link has expired. Please start the account recovery process again from the start.", "invalid_new_password": "The new password you chose is invalid; it may not meet the configured security policy.", "no_current_password": "You don't have a current password.", + "no_such_recovery_ticket": "The recovery link is invalid. If you copied the link from the recovery e-mail, please check the full link was copied.", "password_changes_disabled": "Password changes are disabled.", + "recovery_ticket_already_used": "The recovery link has already been used. It cannot be used again.", "unspecified": "This might be a temporary problem, so please try again later. If the problem persists, please contact your server administrator.", "wrong_password": "The password you supplied as your current password is incorrect. Please try again." }, diff --git a/frontend/src/i18n/password_changes.ts b/frontend/src/i18n/password_changes.ts new file mode 100644 index 00000000..79efda43 --- /dev/null +++ b/frontend/src/i18n/password_changes.ts @@ -0,0 +1,71 @@ +// Copyright 2024 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { TFunction } from "i18next"; + +import { SetPasswordStatus } from "../gql/graphql"; + +/** + * Provides a translated string representing a `SetPasswordStatus`. + * + * Returns the translated string, or undefined if a translated string is not shown at the + * top-level of a password change form for this status. + * + * The form is responsible for showing the following errors itself, inline with the form field: + * - `WrongPassword` + * - `InvalidNewPassword` + * + * Throws an error if the status is not known. + */ +export function translateSetPasswordError( + t: TFunction<"frontend", undefined>, + status: SetPasswordStatus | undefined, +): string | undefined { + switch (status) { + case SetPasswordStatus.NoCurrentPassword: + return t( + "frontend.password_change.failure.description.no_current_password", + ); + case SetPasswordStatus.PasswordChangesDisabled: + return t( + "frontend.password_change.failure.description.password_changes_disabled", + ); + case SetPasswordStatus.AccountLocked: + return t("frontend.password_change.failure.description.account_locked"); + case SetPasswordStatus.ExpiredRecoveryTicket: + return t( + "frontend.password_change.failure.description.expired_recovery_ticket", + ); + case SetPasswordStatus.NoSuchRecoveryTicket: + return t( + "frontend.password_change.failure.description.no_such_recovery_ticket", + ); + case SetPasswordStatus.RecoveryTicketAlreadyUsed: + return t( + "frontend.password_change.failure.description.recovery_ticket_already_used", + ); + + case SetPasswordStatus.WrongPassword: + case SetPasswordStatus.InvalidNewPassword: + // These cases are shown as inline errors in the form itself. + return undefined; + + case SetPasswordStatus.Allowed: + case undefined: + return undefined; + + default: + throw new Error(`unexpected error when changing password: ${status}`); + } +} diff --git a/frontend/src/routes/password.change.index.lazy.tsx b/frontend/src/routes/password.change.index.lazy.tsx index 2b3db972..90d8f93e 100644 --- a/frontend/src/routes/password.change.index.lazy.tsx +++ b/frontend/src/routes/password.change.index.lazy.tsx @@ -31,6 +31,7 @@ import PageHeading from "../components/PageHeading"; import PasswordCreationDoubleInput from "../components/PasswordCreationDoubleInput"; import { graphql } from "../gql"; import { SetPasswordStatus } from "../gql/graphql"; +import { translateSetPasswordError } from "../i18n/password_changes"; const QUERY = graphql(/* GraphQL */ ` query PasswordChangeQuery { @@ -105,32 +106,10 @@ function ChangePassword(): React.ReactNode { const unhandleableError = result.error !== undefined; - const errorMsg: string | undefined = ((): string | undefined => { - switch (result.data?.setPassword.status) { - case SetPasswordStatus.NoCurrentPassword: - return t( - "frontend.password_change.failure.description.no_current_password", - ); - case SetPasswordStatus.PasswordChangesDisabled: - return t( - "frontend.password_change.failure.description.password_changes_disabled", - ); - - case SetPasswordStatus.WrongPassword: - case SetPasswordStatus.InvalidNewPassword: - // These cases are shown as inline errors in the form itself. - return undefined; - - case SetPasswordStatus.Allowed: - case undefined: - return undefined; - - default: - throw new Error( - `unexpected error when changing password: ${result.data!.setPassword.status}`, - ); - } - })(); + const errorMsg: string | undefined = translateSetPasswordError( + t, + result.data?.setPassword.status, + ); return (