Add i18n support for candidate registration

This commit is contained in:
Tiago Yamamoto 2025-12-22 14:44:12 -03:00
parent b3e21c9b64
commit f04550ee0d
4 changed files with 416 additions and 91 deletions

View file

@ -1,6 +1,6 @@
"use client";
import { useState } from "react";
import { useMemo, useState } from "react";
import { useRouter } from "next/navigation";
import Link from "next/link";
import Image from "next/image";
@ -41,37 +41,43 @@ import { motion } from "framer-motion";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { useTranslation } from "@/lib/i18n";
const candidateSchema = z.object({
fullName: z.string().min(2, "Nome deve ter pelo menos 2 caracteres"),
email: z.string().email("Email inválido"),
password: z.string().min(6, "Senha deve ter pelo menos 6 caracteres"),
confirmPassword: z.string(),
phone: z.string().min(10, "Telefone deve ter pelo menos 10 dígitos"),
birthDate: z.string().min(1, "Data de nascimento é obrigatória"),
address: z.string().min(5, "Endereço deve ter pelo menos 5 caracteres"),
city: z.string().min(2, "Cidade é obrigatória"),
state: z.string().min(2, "Estado é obrigatório"),
zipCode: z.string().min(8, "CEP deve ter 8 dígitos"),
education: z.string().min(1, "Nível de escolaridade é obrigatório"),
experience: z.string().min(1, "Experiência profissional é obrigatória"),
skills: z.string().optional(),
objective: z.string().optional(),
acceptTerms: z.boolean().refine(val => val === true, "Você deve aceitar os termos"),
acceptNewsletter: z.boolean().optional(),
}).refine(data => data.password === data.confirmPassword, {
message: "Senhas não coincidem",
path: ["confirmPassword"],
});
const createCandidateSchema = (t: (key: string, params?: Record<string, string | number>) => string) =>
z.object({
fullName: z.string().min(2, t("register.candidate.validation.fullName")),
email: z.string().email(t("register.candidate.validation.email")),
password: z.string().min(6, t("register.candidate.validation.password")),
confirmPassword: z.string(),
phone: z.string().min(10, t("register.candidate.validation.phone")),
birthDate: z.string().min(1, t("register.candidate.validation.birthDate")),
address: z.string().min(5, t("register.candidate.validation.address")),
city: z.string().min(2, t("register.candidate.validation.city")),
state: z.string().min(2, t("register.candidate.validation.state")),
zipCode: z.string().min(8, t("register.candidate.validation.zipCode")),
education: z.string().min(1, t("register.candidate.validation.education")),
experience: z.string().min(1, t("register.candidate.validation.experience")),
skills: z.string().optional(),
objective: z.string().optional(),
acceptTerms: z
.boolean()
.refine(val => val === true, t("register.candidate.validation.acceptTerms")),
acceptNewsletter: z.boolean().optional(),
}).refine(data => data.password === data.confirmPassword, {
message: t("register.candidate.validation.passwordMismatch"),
path: ["confirmPassword"],
});
type CandidateFormData = z.infer<typeof candidateSchema>;
type CandidateFormData = z.infer<ReturnType<typeof createCandidateSchema>>;
export default function CandidateRegisterPage() {
const router = useRouter();
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
const [showPassword, setShowPassword] = useState(false);
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
const [currentStep, setCurrentStep] = useState(1);
const candidateSchema = useMemo(() => createCandidateSchema(t), [t]);
const {
register,
@ -94,7 +100,7 @@ export default function CandidateRegisterPage() {
console.log("Dados do candidato:", data);
// Redirecionar para login após cadastro
router.push("/login?message=Cadastro realizado com sucesso! Faça login para continuar.");
router.push(`/login?message=${encodeURIComponent(t("register.candidate.success"))}`);
} catch (error) {
console.error("Erro no cadastro:", error);
} finally {
@ -130,30 +136,29 @@ export default function CandidateRegisterPage() {
</div>
<h1 className="text-4xl font-bold mb-4">
Cadastre-se como Candidato
{t("register.candidate.hero.title")}
</h1>
<p className="text-lg opacity-90 leading-relaxed mb-6">
Crie sua conta e tenha acesso às melhores oportunidades de emprego.
Encontre a vaga dos seus sonhos hoje mesmo!
{t("register.candidate.hero.subtitle")}
</p>
<div className="space-y-4 text-left">
<div className="flex items-center gap-3">
<div className="w-2 h-2 bg-white rounded-full"></div>
<span>Acesso a milhares de vagas</span>
<span>{t("register.candidate.hero.bullets.jobs")}</span>
</div>
<div className="flex items-center gap-3">
<div className="w-2 h-2 bg-white rounded-full"></div>
<span>Candidaturas rápidas e fáceis</span>
<span>{t("register.candidate.hero.bullets.fastApplications")}</span>
</div>
<div className="flex items-center gap-3">
<div className="w-2 h-2 bg-white rounded-full"></div>
<span>Perfil profissional completo</span>
<span>{t("register.candidate.hero.bullets.profile")}</span>
</div>
<div className="flex items-center gap-3">
<div className="w-2 h-2 bg-white rounded-full"></div>
<span>Notificações de novas oportunidades</span>
<span>{t("register.candidate.hero.bullets.notifications")}</span>
</div>
</div>
</motion.div>
@ -169,25 +174,27 @@ export default function CandidateRegisterPage() {
className="inline-flex items-center gap-2 text-muted-foreground hover:text-foreground mb-4 transition-colors"
>
<ArrowLeft className="w-4 h-4" />
Voltar ao Login
{t("register.candidate.actions.backToLogin")}
</Link>
<h2 className="text-2xl font-bold text-foreground mb-2">
Criar Conta - Candidato
{t("register.candidate.title")}
</h2>
<p className="text-muted-foreground">
Preencha seus dados para criar sua conta
{t("register.candidate.subtitle")}
</p>
</div>
{/* Progress Indicator */}
<div className="mb-8">
<div className="flex items-center justify-between mb-2">
<span className="text-sm font-medium">Etapa {currentStep} de 3</span>
<span className="text-sm font-medium">
{t("register.candidate.progress.step", { current: currentStep, total: 3 })}
</span>
<span className="text-sm text-muted-foreground">
{currentStep === 1 && "Dados Pessoais"}
{currentStep === 2 && "Endereço e Contato"}
{currentStep === 3 && "Perfil Profissional"}
{currentStep === 1 && t("register.candidate.steps.personal")}
{currentStep === 2 && t("register.candidate.steps.address")}
{currentStep === 3 && t("register.candidate.steps.professional")}
</span>
</div>
<div className="w-full bg-muted rounded-full h-2">
@ -210,13 +217,13 @@ export default function CandidateRegisterPage() {
className="space-y-4"
>
<div className="space-y-2">
<Label htmlFor="fullName">Nome Completo</Label>
<Label htmlFor="fullName">{t("register.candidate.fields.fullName")}</Label>
<div className="relative">
<User className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
<Input
id="fullName"
type="text"
placeholder="Seu nome completo"
placeholder={t("register.candidate.placeholders.fullName")}
className="pl-10"
{...register("fullName")}
/>
@ -227,13 +234,13 @@ export default function CandidateRegisterPage() {
</div>
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Label htmlFor="email">{t("register.candidate.fields.email")}</Label>
<div className="relative">
<Mail className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
<Input
id="email"
type="email"
placeholder="seu@email.com"
placeholder={t("register.candidate.placeholders.email")}
className="pl-10"
{...register("email")}
/>
@ -244,13 +251,13 @@ export default function CandidateRegisterPage() {
</div>
<div className="space-y-2">
<Label htmlFor="password">Senha</Label>
<Label htmlFor="password">{t("register.candidate.fields.password")}</Label>
<div className="relative">
<Lock className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
<Input
id="password"
type={showPassword ? "text" : "password"}
placeholder="Sua senha"
placeholder={t("register.candidate.placeholders.password")}
className="pl-10 pr-10"
{...register("password")}
/>
@ -274,13 +281,13 @@ export default function CandidateRegisterPage() {
</div>
<div className="space-y-2">
<Label htmlFor="confirmPassword">Confirmar Senha</Label>
<Label htmlFor="confirmPassword">{t("register.candidate.fields.confirmPassword")}</Label>
<div className="relative">
<Lock className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
<Input
id="confirmPassword"
type={showConfirmPassword ? "text" : "password"}
placeholder="Confirme sua senha"
placeholder={t("register.candidate.placeholders.confirmPassword")}
className="pl-10 pr-10"
{...register("confirmPassword")}
/>
@ -304,7 +311,7 @@ export default function CandidateRegisterPage() {
</div>
<div className="space-y-2">
<Label htmlFor="birthDate">Data de Nascimento</Label>
<Label htmlFor="birthDate">{t("register.candidate.fields.birthDate")}</Label>
<div className="relative">
<Calendar className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
<Input
@ -320,7 +327,7 @@ export default function CandidateRegisterPage() {
</div>
<Button type="button" onClick={nextStep} className="w-full">
Próxima Etapa
{t("register.candidate.actions.next")}
</Button>
</motion.div>
)}
@ -336,13 +343,13 @@ export default function CandidateRegisterPage() {
className="space-y-4"
>
<div className="space-y-2">
<Label htmlFor="phone">Telefone</Label>
<Label htmlFor="phone">{t("register.candidate.fields.phone")}</Label>
<div className="relative">
<Phone className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
<Input
id="phone"
type="tel"
placeholder="(11) 99999-9999"
placeholder={t("register.candidate.placeholders.phone")}
className="pl-10"
{...register("phone")}
/>
@ -353,13 +360,13 @@ export default function CandidateRegisterPage() {
</div>
<div className="space-y-2">
<Label htmlFor="address">Endereço</Label>
<Label htmlFor="address">{t("register.candidate.fields.address")}</Label>
<div className="relative">
<MapPin className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
<Input
id="address"
type="text"
placeholder="Rua, número, complemento"
placeholder={t("register.candidate.placeholders.address")}
className="pl-10"
{...register("address")}
/>
@ -371,11 +378,11 @@ export default function CandidateRegisterPage() {
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="city">Cidade</Label>
<Label htmlFor="city">{t("register.candidate.fields.city")}</Label>
<Input
id="city"
type="text"
placeholder="Sua cidade"
placeholder={t("register.candidate.placeholders.city")}
{...register("city")}
/>
{errors.city && (
@ -384,10 +391,10 @@ export default function CandidateRegisterPage() {
</div>
<div className="space-y-2">
<Label htmlFor="state">Estado</Label>
<Label htmlFor="state">{t("register.candidate.fields.state")}</Label>
<Select onValueChange={(value) => setValue("state", value)}>
<SelectTrigger>
<SelectValue placeholder="Estado" />
<SelectValue placeholder={t("register.candidate.placeholders.state")} />
</SelectTrigger>
<SelectContent>
<SelectItem value="AC">Acre</SelectItem>
@ -426,11 +433,11 @@ export default function CandidateRegisterPage() {
</div>
<div className="space-y-2">
<Label htmlFor="zipCode">CEP</Label>
<Label htmlFor="zipCode">{t("register.candidate.fields.zipCode")}</Label>
<Input
id="zipCode"
type="text"
placeholder="00000-000"
placeholder={t("register.candidate.placeholders.zipCode")}
{...register("zipCode")}
/>
{errors.zipCode && (
@ -440,10 +447,10 @@ export default function CandidateRegisterPage() {
<div className="flex gap-4">
<Button type="button" variant="outline" onClick={prevStep} className="flex-1">
Voltar
{t("register.candidate.actions.back")}
</Button>
<Button type="button" onClick={nextStep} className="flex-1">
Próxima Etapa
{t("register.candidate.actions.next")}
</Button>
</div>
</motion.div>
@ -460,19 +467,19 @@ export default function CandidateRegisterPage() {
className="space-y-4"
>
<div className="space-y-2">
<Label htmlFor="education">Nível de Escolaridade</Label>
<Label htmlFor="education">{t("register.candidate.fields.education")}</Label>
<Select onValueChange={(value) => setValue("education", value)}>
<SelectTrigger>
<SelectValue placeholder="Selecione sua escolaridade" />
<SelectValue placeholder={t("register.candidate.placeholders.education")} />
</SelectTrigger>
<SelectContent>
<SelectItem value="fundamental">Ensino Fundamental</SelectItem>
<SelectItem value="medio">Ensino Médio</SelectItem>
<SelectItem value="tecnico">Técnico</SelectItem>
<SelectItem value="superior">Ensino Superior</SelectItem>
<SelectItem value="pos">Pós-graduação</SelectItem>
<SelectItem value="mestrado">Mestrado</SelectItem>
<SelectItem value="doutorado">Doutorado</SelectItem>
<SelectItem value="fundamental">{t("register.candidate.education.fundamental")}</SelectItem>
<SelectItem value="medio">{t("register.candidate.education.highSchool")}</SelectItem>
<SelectItem value="tecnico">{t("register.candidate.education.technical")}</SelectItem>
<SelectItem value="superior">{t("register.candidate.education.college")}</SelectItem>
<SelectItem value="pos">{t("register.candidate.education.postgrad")}</SelectItem>
<SelectItem value="mestrado">{t("register.candidate.education.masters")}</SelectItem>
<SelectItem value="doutorado">{t("register.candidate.education.phd")}</SelectItem>
</SelectContent>
</Select>
{errors.education && (
@ -481,18 +488,18 @@ export default function CandidateRegisterPage() {
</div>
<div className="space-y-2">
<Label htmlFor="experience">Experiência Profissional</Label>
<Label htmlFor="experience">{t("register.candidate.fields.experience")}</Label>
<Select onValueChange={(value) => setValue("experience", value)}>
<SelectTrigger>
<SelectValue placeholder="Selecione sua experiência" />
<SelectValue placeholder={t("register.candidate.placeholders.experience")} />
</SelectTrigger>
<SelectContent>
<SelectItem value="sem-experiencia">Sem experiência</SelectItem>
<SelectItem value="ate-1-ano">Até 1 ano</SelectItem>
<SelectItem value="1-2-anos">1 a 2 anos</SelectItem>
<SelectItem value="2-5-anos">2 a 5 anos</SelectItem>
<SelectItem value="5-10-anos">5 a 10 anos</SelectItem>
<SelectItem value="mais-10-anos">Mais de 10 anos</SelectItem>
<SelectItem value="sem-experiencia">{t("register.candidate.experience.none")}</SelectItem>
<SelectItem value="ate-1-ano">{t("register.candidate.experience.upToOne")}</SelectItem>
<SelectItem value="1-2-anos">{t("register.candidate.experience.oneToTwo")}</SelectItem>
<SelectItem value="2-5-anos">{t("register.candidate.experience.twoToFive")}</SelectItem>
<SelectItem value="5-10-anos">{t("register.candidate.experience.fiveToTen")}</SelectItem>
<SelectItem value="mais-10-anos">{t("register.candidate.experience.moreThanTen")}</SelectItem>
</SelectContent>
</Select>
{errors.experience && (
@ -501,20 +508,20 @@ export default function CandidateRegisterPage() {
</div>
<div className="space-y-2">
<Label htmlFor="skills">Habilidades e Competências (opcional)</Label>
<Label htmlFor="skills">{t("register.candidate.fields.skills")}</Label>
<Textarea
id="skills"
placeholder="Ex: JavaScript, React, Photoshop, Inglês fluente..."
placeholder={t("register.candidate.placeholders.skills")}
className="min-h-[80px]"
{...register("skills")}
/>
</div>
<div className="space-y-2">
<Label htmlFor="objective">Objetivo Profissional (opcional)</Label>
<Label htmlFor="objective">{t("register.candidate.fields.objective")}</Label>
<Textarea
id="objective"
placeholder="Descreva seus objetivos e o que busca em uma oportunidade..."
placeholder={t("register.candidate.placeholders.objective")}
className="min-h-[80px]"
{...register("objective")}
/>
@ -532,13 +539,13 @@ export default function CandidateRegisterPage() {
htmlFor="acceptTerms"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Aceito os{" "}
{t("register.candidate.acceptTerms.prefix")}{" "}
<Link href="/termos" className="text-primary hover:underline">
Termos de Uso
{t("register.candidate.acceptTerms.terms")}
</Link>{" "}
e{" "}
{t("register.candidate.acceptTerms.and")}{" "}
<Link href="/privacidade" className="text-primary hover:underline">
Política de Privacidade
{t("register.candidate.acceptTerms.privacy")}
</Link>
</label>
</div>
@ -558,7 +565,7 @@ export default function CandidateRegisterPage() {
htmlFor="acceptNewsletter"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Quero receber notificações sobre novas vagas por email
{t("register.candidate.acceptNewsletter")}
</label>
</div>
</div>
@ -566,10 +573,10 @@ export default function CandidateRegisterPage() {
<div className="flex gap-4">
<Button type="button" variant="outline" onClick={prevStep} className="flex-1">
Voltar
{t("register.candidate.actions.back")}
</Button>
<Button type="submit" disabled={loading} className="flex-1">
{loading ? "Criando conta..." : "Criar Conta"}
{loading ? t("register.candidate.actions.creating") : t("register.candidate.actions.submit")}
</Button>
</div>
</motion.div>
@ -578,9 +585,9 @@ export default function CandidateRegisterPage() {
<div className="mt-6 text-center">
<p className="text-sm text-muted-foreground">
tem uma conta?{" "}
{t("register.candidate.footer.prompt")}{" "}
<Link href="/login" className="text-primary hover:underline font-medium">
Faça login
{t("register.candidate.footer.login")}
</Link>
</p>
</div>
@ -588,4 +595,4 @@ export default function CandidateRegisterPage() {
</div>
</div>
);
}
}

View file

@ -105,5 +105,111 @@
"backLogin": "← Back to login"
}
},
"register": {
"candidate": {
"title": "Create Account - Candidate",
"subtitle": "Fill in your details to create your account",
"success": "Registration completed! Please sign in to continue.",
"hero": {
"title": "Sign up as a Candidate",
"subtitle": "Create your account and get access to the best job opportunities. Find your dream job today!",
"bullets": {
"jobs": "Access to thousands of jobs",
"fastApplications": "Fast and easy applications",
"profile": "Complete professional profile",
"notifications": "New opportunity notifications"
}
},
"progress": {
"step": "Step {current} of {total}"
},
"steps": {
"personal": "Personal Details",
"address": "Address & Contact",
"professional": "Professional Profile"
},
"fields": {
"fullName": "Full Name",
"email": "Email",
"password": "Password",
"confirmPassword": "Confirm Password",
"birthDate": "Date of Birth",
"phone": "Phone",
"address": "Address",
"city": "City",
"state": "State",
"zipCode": "ZIP Code",
"education": "Education Level",
"experience": "Professional Experience",
"skills": "Skills & Competencies (optional)",
"objective": "Career Objective (optional)"
},
"placeholders": {
"fullName": "Your full name",
"email": "you@email.com",
"password": "Your password",
"confirmPassword": "Confirm your password",
"phone": "(11) 99999-9999",
"address": "Street, number, complement",
"city": "Your city",
"state": "State",
"zipCode": "00000-000",
"education": "Select your education level",
"experience": "Select your experience",
"skills": "e.g. JavaScript, React, Photoshop, Fluent English...",
"objective": "Describe your goals and what you're looking for..."
},
"education": {
"fundamental": "Primary School",
"highSchool": "High School",
"technical": "Technical",
"college": "College",
"postgrad": "Postgraduate",
"masters": "Master's",
"phd": "PhD"
},
"experience": {
"none": "No experience",
"upToOne": "Up to 1 year",
"oneToTwo": "1 to 2 years",
"twoToFive": "2 to 5 years",
"fiveToTen": "5 to 10 years",
"moreThanTen": "More than 10 years"
},
"acceptTerms": {
"prefix": "I accept the",
"terms": "Terms of Use",
"and": "and",
"privacy": "Privacy Policy"
},
"acceptNewsletter": "I want to receive notifications about new jobs by email",
"actions": {
"backToLogin": "Back to Login",
"back": "Back",
"next": "Next Step",
"submit": "Create Account",
"creating": "Creating account..."
},
"footer": {
"prompt": "Already have an account?",
"login": "Sign in"
},
"validation": {
"fullName": "Name must be at least 2 characters",
"email": "Invalid email",
"password": "Password must be at least 6 characters",
"passwordMismatch": "Passwords do not match",
"phone": "Phone must be at least 10 digits",
"birthDate": "Date of birth is required",
"address": "Address must be at least 5 characters",
"city": "City is required",
"state": "State is required",
"zipCode": "ZIP code must be 8 digits",
"education": "Education level is required",
"experience": "Professional experience is required",
"acceptTerms": "You must accept the terms"
}
}
},
"common": { "loading": "Loading...", "error": "Error", "retry": "Retry", "noResults": "No results found" }
}

View file

@ -105,5 +105,111 @@
"backLogin": "← Volver al login"
}
},
"register": {
"candidate": {
"title": "Crear Cuenta - Candidato",
"subtitle": "Completa tus datos para crear tu cuenta",
"success": "¡Registro completado! Inicia sesión para continuar.",
"hero": {
"title": "Regístrate como Candidato",
"subtitle": "Crea tu cuenta y accede a las mejores oportunidades laborales. ¡Encuentra tu empleo soñado hoy mismo!",
"bullets": {
"jobs": "Acceso a miles de empleos",
"fastApplications": "Postulaciones rápidas y fáciles",
"profile": "Perfil profesional completo",
"notifications": "Notificaciones de nuevas oportunidades"
}
},
"progress": {
"step": "Paso {current} de {total}"
},
"steps": {
"personal": "Datos personales",
"address": "Dirección y contacto",
"professional": "Perfil profesional"
},
"fields": {
"fullName": "Nombre completo",
"email": "Correo electrónico",
"password": "Contraseña",
"confirmPassword": "Confirmar contraseña",
"birthDate": "Fecha de nacimiento",
"phone": "Teléfono",
"address": "Dirección",
"city": "Ciudad",
"state": "Estado",
"zipCode": "Código postal",
"education": "Nivel de estudios",
"experience": "Experiencia profesional",
"skills": "Habilidades y competencias (opcional)",
"objective": "Objetivo profesional (opcional)"
},
"placeholders": {
"fullName": "Tu nombre completo",
"email": "tu@email.com",
"password": "Tu contraseña",
"confirmPassword": "Confirma tu contraseña",
"phone": "(11) 99999-9999",
"address": "Calle, número, complemento",
"city": "Tu ciudad",
"state": "Estado",
"zipCode": "00000-000",
"education": "Selecciona tu nivel de estudios",
"experience": "Selecciona tu experiencia",
"skills": "Ej: JavaScript, React, Photoshop, Inglés fluido...",
"objective": "Describe tus objetivos y lo que buscas..."
},
"education": {
"fundamental": "Educación primaria",
"highSchool": "Educación secundaria",
"technical": "Técnico",
"college": "Universidad",
"postgrad": "Posgrado",
"masters": "Maestría",
"phd": "Doctorado"
},
"experience": {
"none": "Sin experiencia",
"upToOne": "Hasta 1 año",
"oneToTwo": "1 a 2 años",
"twoToFive": "2 a 5 años",
"fiveToTen": "5 a 10 años",
"moreThanTen": "Más de 10 años"
},
"acceptTerms": {
"prefix": "Acepto los",
"terms": "Términos de Uso",
"and": "y",
"privacy": "Política de Privacidad"
},
"acceptNewsletter": "Quiero recibir notificaciones sobre nuevas vacantes por email",
"actions": {
"backToLogin": "Volver al login",
"back": "Volver",
"next": "Siguiente paso",
"submit": "Crear cuenta",
"creating": "Creando cuenta..."
},
"footer": {
"prompt": "¿Ya tienes una cuenta?",
"login": "Inicia sesión"
},
"validation": {
"fullName": "El nombre debe tener al menos 2 caracteres",
"email": "Correo electrónico inválido",
"password": "La contraseña debe tener al menos 6 caracteres",
"passwordMismatch": "Las contraseñas no coinciden",
"phone": "El teléfono debe tener al menos 10 dígitos",
"birthDate": "La fecha de nacimiento es obligatoria",
"address": "La dirección debe tener al menos 5 caracteres",
"city": "La ciudad es obligatoria",
"state": "El estado es obligatorio",
"zipCode": "El código postal debe tener 8 dígitos",
"education": "El nivel de estudios es obligatorio",
"experience": "La experiencia profesional es obligatoria",
"acceptTerms": "Debes aceptar los términos"
}
}
},
"common": { "loading": "Cargando...", "error": "Error", "retry": "Reintentar", "noResults": "No se encontraron resultados" }
}

View file

@ -105,5 +105,111 @@
"backLogin": "← Voltar para login"
}
},
"register": {
"candidate": {
"title": "Criar Conta - Candidato",
"subtitle": "Preencha seus dados para criar sua conta",
"success": "Cadastro realizado com sucesso! Faça login para continuar.",
"hero": {
"title": "Cadastre-se como Candidato",
"subtitle": "Crie sua conta e tenha acesso às melhores oportunidades de emprego. Encontre a vaga dos seus sonhos hoje mesmo!",
"bullets": {
"jobs": "Acesso a milhares de vagas",
"fastApplications": "Candidaturas rápidas e fáceis",
"profile": "Perfil profissional completo",
"notifications": "Notificações de novas oportunidades"
}
},
"progress": {
"step": "Etapa {current} de {total}"
},
"steps": {
"personal": "Dados Pessoais",
"address": "Endereço e Contato",
"professional": "Perfil Profissional"
},
"fields": {
"fullName": "Nome Completo",
"email": "Email",
"password": "Senha",
"confirmPassword": "Confirmar Senha",
"birthDate": "Data de Nascimento",
"phone": "Telefone",
"address": "Endereço",
"city": "Cidade",
"state": "Estado",
"zipCode": "CEP",
"education": "Nível de Escolaridade",
"experience": "Experiência Profissional",
"skills": "Habilidades e Competências (opcional)",
"objective": "Objetivo Profissional (opcional)"
},
"placeholders": {
"fullName": "Seu nome completo",
"email": "seu@email.com",
"password": "Sua senha",
"confirmPassword": "Confirme sua senha",
"phone": "(11) 99999-9999",
"address": "Rua, número, complemento",
"city": "Sua cidade",
"state": "Estado",
"zipCode": "00000-000",
"education": "Selecione sua escolaridade",
"experience": "Selecione sua experiência",
"skills": "Ex: JavaScript, React, Photoshop, Inglês fluente...",
"objective": "Descreva seus objetivos e o que busca em uma oportunidade..."
},
"education": {
"fundamental": "Ensino Fundamental",
"highSchool": "Ensino Médio",
"technical": "Técnico",
"college": "Ensino Superior",
"postgrad": "Pós-graduação",
"masters": "Mestrado",
"phd": "Doutorado"
},
"experience": {
"none": "Sem experiência",
"upToOne": "Até 1 ano",
"oneToTwo": "1 a 2 anos",
"twoToFive": "2 a 5 anos",
"fiveToTen": "5 a 10 anos",
"moreThanTen": "Mais de 10 anos"
},
"acceptTerms": {
"prefix": "Aceito os",
"terms": "Termos de Uso",
"and": "e",
"privacy": "Política de Privacidade"
},
"acceptNewsletter": "Quero receber notificações sobre novas vagas por email",
"actions": {
"backToLogin": "Voltar ao Login",
"back": "Voltar",
"next": "Próxima Etapa",
"submit": "Criar Conta",
"creating": "Criando conta..."
},
"footer": {
"prompt": "Já tem uma conta?",
"login": "Faça login"
},
"validation": {
"fullName": "Nome deve ter pelo menos 2 caracteres",
"email": "Email inválido",
"password": "Senha deve ter pelo menos 6 caracteres",
"passwordMismatch": "Senhas não coincidem",
"phone": "Telefone deve ter pelo menos 10 dígitos",
"birthDate": "Data de nascimento é obrigatória",
"address": "Endereço deve ter pelo menos 5 caracteres",
"city": "Cidade é obrigatória",
"state": "Estado é obrigatório",
"zipCode": "CEP deve ter 8 dígitos",
"education": "Nível de escolaridade é obrigatório",
"experience": "Experiência profissional é obrigatória",
"acceptTerms": "Você deve aceitar os termos"
}
}
},
"common": { "loading": "Carregando...", "error": "Erro", "retry": "Tentar novamente", "noResults": "Nenhum resultado encontrado" }
}