i18n: extract Authorization screens into a new auth namespace

Every user-facing string under src/views/Authorization/ moves to i18next.
English only — no translations in this PR, so it is language-agnostic and
reviewable as a pure refactor.

Covered:
- LoginView — primary/sub-account tabs, credential form, social and
  Authentik buttons, welcome-back state, every auth error toast
- Signup — account creation form and each field-validation message
- ForgotPasswordView / UpdatePasswordView — reset flow and its toasts
- Authenticating — the OAuth landing screen, including its MFA branches
- MFAVerificationModal — code entry, backup codes, error states
- AuthFields / LoginSettings — shared field labels and server settings

`auth` is registered in src/i18n/config.js; public/locales/en/auth.json
holds the 103 keys. The Crowdin config picks up /public/locales/en/*.json
by glob, so the namespace flows into the pipeline with no change to
crowdin.yml.

No behaviour change: every t() value is the string that rendered before,
character for character — checked mechanically against this branch's base.
The e2e suite selects auth controls by visible text ('Create account',
'Username must be at least 4 characters'), so a green run is the proof.

Two fixes fell out of the extraction:
- AuthPasswordField had label='Password' as a prop default, so neither
  LoginView nor Signup passed one. A default cannot be translated at module
  scope, so the label moves to the call sites and both now pass it.
- AuthDivider defaulted children to 'or' for the same reason; it now falls
  back to t('or').
This commit is contained in:
everysingletear
2026-08-12 20:03:02 +08:00
parent 7eba12e718
commit 6dc7c3d370
10 changed files with 283 additions and 151 deletions

View File

@@ -1,6 +1,7 @@
import MarkEmailReadOutlined from '@mui/icons-material/MarkEmailReadOutlined'
import { Box, Button, Link, Typography } from '@mui/joy'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router-dom'
import { useNotification } from '../../service/NotificationProvider'
import { ResetPassword } from '../../utils/Fetcher'
@@ -12,6 +13,7 @@ const isInvalidEmail = email =>
!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(email)
const ForgotPasswordView = () => {
const { t } = useTranslation('auth')
const navigate = useNavigate()
const [resetStatusOk, setResetStatusOk] = useState(null)
const [email, setEmail] = useState('')
@@ -40,21 +42,21 @@ const ForgotPasswordView = () => {
setResetStatusOk(true)
showNotification({
type: 'success',
title: 'Reset Email Sent',
message: 'Check your email for password reset instructions',
title: t('resetEmailSent'),
message: t('resetEmailSentMsg'),
})
} else {
setResetStatusOk(false)
showError({
title: 'Reset Failed',
message: 'Failed to send reset email, please try again later',
title: t('resetFailed'),
message: t('resetFailedMsg'),
})
}
} catch (error) {
setResetStatusOk(false)
showError({
title: 'Reset Failed',
message: 'Failed to send reset email, please try again later',
title: t('resetFailed'),
message: t('resetFailedMsg'),
})
} finally {
setIsSubmitting(false)
@@ -79,7 +81,7 @@ const ForgotPasswordView = () => {
if (resetStatusOk !== null) {
return (
<AuthShell
title='Check your email'
title={t('checkYourEmail')}
subtitle={`If an account exists for ${email}, we've sent instructions for resetting your password.`}
footer={<LegalLinks />}
logoSize={0}
@@ -101,7 +103,7 @@ const ForgotPasswordView = () => {
sx={authButtonSx}
onClick={() => navigate('/login')}
>
Back to sign in
{t('backToSignIn')}
</Button>
</Box>
</AuthShell>
@@ -110,7 +112,7 @@ const ForgotPasswordView = () => {
return (
<AuthShell
title='Reset your password'
title={t('resetYourPassword')}
subtitle="Enter your email and we'll send you a link to get back into your account."
footer={<LegalLinks />}
logoSize={0}
@@ -126,7 +128,7 @@ const ForgotPasswordView = () => {
name='email'
type='email'
autoComplete='email'
placeholder='you@example.com'
placeholder={t('emailPlaceholder')}
autoFocus
value={email}
error={emailError}
@@ -152,7 +154,7 @@ const ForgotPasswordView = () => {
underline='hover'
onClick={() => navigate('/login')}
>
Back to sign in
{t('backToSignIn')}
</Link>
</Typography>
</AuthShell>