Phase 5: Translate Auth Pages - login and signup
- Create auth.json translation files for es, en, ca - Translate login page: title, subtitle, form labels, buttons, footer - Translate signup page: invite code step and account creation step - Translate signup/[code] redirect page - Update IntlProvider to load auth namespace - Update test expectations to match Spanish translations (default language) - All frontend and e2e tests passing
This commit is contained in:
parent
a5a1a2c1ad
commit
7dd13292a0
9 changed files with 188 additions and 47 deletions
|
|
@ -6,6 +6,7 @@ import { useAuth } from "../auth-context";
|
|||
import { invitesApi } from "../api";
|
||||
import { authFormStyles as styles } from "../styles/auth-form";
|
||||
import { LanguageSelector } from "../components/LanguageSelector";
|
||||
import { useTranslation } from "../hooks/useTranslation";
|
||||
|
||||
function SignupContent() {
|
||||
const searchParams = useSearchParams();
|
||||
|
|
@ -25,6 +26,7 @@ function SignupContent() {
|
|||
|
||||
const { user, register } = useAuth();
|
||||
const router = useRouter();
|
||||
const t = useTranslation("auth");
|
||||
|
||||
// Redirect if already logged in
|
||||
useEffect(() => {
|
||||
|
|
@ -51,11 +53,11 @@ function SignupContent() {
|
|||
setInviteError("");
|
||||
} else {
|
||||
setInviteValid(false);
|
||||
setInviteError(response.error || "Invalid invite code");
|
||||
setInviteError(response.error || t("signup.invalidInviteCode"));
|
||||
}
|
||||
} catch {
|
||||
setInviteValid(false);
|
||||
setInviteError("Failed to verify invite code");
|
||||
setInviteError(t("signup.failedToVerify"));
|
||||
} finally {
|
||||
setIsCheckingInvite(false);
|
||||
}
|
||||
|
|
@ -78,12 +80,12 @@ function SignupContent() {
|
|||
setError("");
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
setError("Passwords do not match");
|
||||
setError(t("signup.passwordsDoNotMatch"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (password.length < 6) {
|
||||
setError("Password must be at least 6 characters");
|
||||
setError(t("signup.passwordTooShort"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +95,7 @@ function SignupContent() {
|
|||
await register(email, password, inviteCode.trim());
|
||||
router.push("/");
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : "Registration failed");
|
||||
setError(err instanceof Error ? err.message : t("signup.registrationFailed"));
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
|
|
@ -114,7 +116,7 @@ function SignupContent() {
|
|||
<div style={styles.container}>
|
||||
<div style={styles.card}>
|
||||
<div style={{ textAlign: "center", color: "rgba(255,255,255,0.6)" }}>
|
||||
Checking invite code...
|
||||
{t("signup.checkingInviteCode")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -132,8 +134,8 @@ function SignupContent() {
|
|||
<div style={styles.container}>
|
||||
<div style={styles.card}>
|
||||
<div style={styles.header}>
|
||||
<h1 style={styles.title}>Join with Invite</h1>
|
||||
<p style={styles.subtitle}>Enter your invite code to get started</p>
|
||||
<h1 style={styles.title}>{t("signup.title")}</h1>
|
||||
<p style={styles.subtitle}>{t("signup.subtitle")}</p>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleInviteSubmit} style={styles.form}>
|
||||
|
|
@ -141,7 +143,7 @@ function SignupContent() {
|
|||
|
||||
<div style={styles.field}>
|
||||
<label htmlFor="inviteCode" style={styles.label}>
|
||||
Invite Code
|
||||
{t("signup.inviteCode")}
|
||||
</label>
|
||||
<input
|
||||
id="inviteCode"
|
||||
|
|
@ -153,7 +155,7 @@ function SignupContent() {
|
|||
setInviteValid(null);
|
||||
}}
|
||||
style={styles.input}
|
||||
placeholder="word-word-00"
|
||||
placeholder={t("signup.inviteCodePlaceholder")}
|
||||
required
|
||||
autoFocus
|
||||
/>
|
||||
|
|
@ -165,7 +167,7 @@ function SignupContent() {
|
|||
display: "block",
|
||||
}}
|
||||
>
|
||||
Ask your inviter for this code
|
||||
{t("signup.inviteHint")}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
|
@ -177,14 +179,14 @@ function SignupContent() {
|
|||
}}
|
||||
disabled={isCheckingInvite || !inviteCode.trim()}
|
||||
>
|
||||
{isCheckingInvite ? "Checking..." : "Continue"}
|
||||
{isCheckingInvite ? t("signup.checking") : t("signup.continue")}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<p style={styles.footer}>
|
||||
Already have an account?{" "}
|
||||
{t("signup.alreadyHaveAccount")}{" "}
|
||||
<a href="/login" style={styles.link}>
|
||||
Sign in
|
||||
{t("signup.signIn")}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -202,9 +204,9 @@ function SignupContent() {
|
|||
<div style={styles.container}>
|
||||
<div style={styles.card}>
|
||||
<div style={styles.header}>
|
||||
<h1 style={styles.title}>Create account</h1>
|
||||
<h1 style={styles.title}>{t("signup.createAccountTitle")}</h1>
|
||||
<p style={styles.subtitle}>
|
||||
Using invite:{" "}
|
||||
{t("signup.createAccountSubtitle")}{" "}
|
||||
<code
|
||||
style={{
|
||||
background: "rgba(255,255,255,0.1)",
|
||||
|
|
@ -223,7 +225,7 @@ function SignupContent() {
|
|||
|
||||
<div style={styles.field}>
|
||||
<label htmlFor="email" style={styles.label}>
|
||||
Email
|
||||
{t("signup.email")}
|
||||
</label>
|
||||
<input
|
||||
id="email"
|
||||
|
|
@ -231,7 +233,7 @@ function SignupContent() {
|
|||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
style={styles.input}
|
||||
placeholder="you@example.com"
|
||||
placeholder={t("signup.emailPlaceholder")}
|
||||
required
|
||||
autoFocus
|
||||
/>
|
||||
|
|
@ -239,7 +241,7 @@ function SignupContent() {
|
|||
|
||||
<div style={styles.field}>
|
||||
<label htmlFor="password" style={styles.label}>
|
||||
Password
|
||||
{t("signup.password")}
|
||||
</label>
|
||||
<input
|
||||
id="password"
|
||||
|
|
@ -247,14 +249,14 @@ function SignupContent() {
|
|||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
style={styles.input}
|
||||
placeholder="••••••••"
|
||||
placeholder={t("signup.passwordPlaceholder")}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={styles.field}>
|
||||
<label htmlFor="confirmPassword" style={styles.label}>
|
||||
Confirm Password
|
||||
{t("signup.confirmPassword")}
|
||||
</label>
|
||||
<input
|
||||
id="confirmPassword"
|
||||
|
|
@ -262,7 +264,7 @@ function SignupContent() {
|
|||
value={confirmPassword}
|
||||
onChange={(e) => setConfirmPassword(e.target.value)}
|
||||
style={styles.input}
|
||||
placeholder="••••••••"
|
||||
placeholder={t("signup.confirmPasswordPlaceholder")}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -275,7 +277,7 @@ function SignupContent() {
|
|||
}}
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
{isSubmitting ? "Creating account..." : "Create account"}
|
||||
{isSubmitting ? t("signup.creatingAccount") : t("signup.createAccount")}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
|
|
@ -293,7 +295,7 @@ function SignupContent() {
|
|||
padding: 0,
|
||||
}}
|
||||
>
|
||||
Use a different invite code
|
||||
{t("signup.useDifferentCode")}
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue