diff --git a/public/locales/en/check.json b/public/locales/en/check.json
new file mode 100644
index 0000000..f43b962
--- /dev/null
+++ b/public/locales/en/check.json
@@ -0,0 +1,30 @@
+{
+ "back_to_home_page": "Back to Home Page",
+ "daily_checkin_checkout": "Daily Check-In/Check-Out",
+ "i_want_to": "I want to",
+ "check_in": "Check In",
+ "check_out": "Check Out",
+ "select_type": "Select type",
+ "individual": "Individual",
+ "group": "Group",
+ "your_email": "Your Email",
+ "continue": "Continue",
+ "back": "Back",
+ "shift_signup_info": "Here is your shift signup information:",
+ "shifts_choose_one": "Shift(s) (choose one)",
+ "start": "Start",
+ "end": "End",
+ "confirm_check_in": "Confirm Your Check-In",
+ "must_check_in_first": "You must check in before checking out again.",
+ "checkout_error": "There was an error during check-out.",
+ "group_already_checked_out": "This group has already checked out.",
+ "already_checked_in": "You have already checked in and must check out before checking in again.",
+ "checkin_error": "There was an error during check-in. Please try again.",
+ "check_success_message": "Hooray! You have checked {{action}} at {{time}}.",
+ "in": "in",
+ "out": "out",
+ "checkin_caption": "Do not forget to check out before you leave!",
+ "checkout_caption": "Thank you for your hard work today! We look forward to seeing you again soon.",
+ "back_to_first_page": "Back to First Page",
+ "organization_name": "Organization Name"
+}
diff --git a/public/locales/en/communication.json b/public/locales/en/communication.json
new file mode 100644
index 0000000..6a3fffd
--- /dev/null
+++ b/public/locales/en/communication.json
@@ -0,0 +1,15 @@
+{
+ "send_email_to_volunteers": "Send Email To Volunteers",
+ "email_subject": "Subject",
+ "email_from": "Email From",
+ "default_email_note": "This is the default email.",
+ "email_body": "Email Body",
+ "email_reach_note": "This will be sent to all volunteers on the site.",
+ "email_example": "ex: Welcome to Bread & Roses!",
+ "click_to_upload": "Click to upload",
+ "type_email_content": "Type your email content",
+ "send_email": "Send Email",
+ "complete": "Complete",
+ "email_sent_confirmation": "Email sent! You will receive a copy via email.",
+ "back_to_original_page": "Back to the original page"
+}
diff --git a/public/locales/en/events.json b/public/locales/en/events.json
new file mode 100644
index 0000000..6c86792
--- /dev/null
+++ b/public/locales/en/events.json
@@ -0,0 +1,45 @@
+{
+ "events": "Events",
+ "sign_up_prompt": "Sign up for your volunteering time!",
+ "your_volunteer_hours": "Your Volunteer Hours",
+ "no_time_slots": "No time slots!",
+ "choose_your_time": "Choose Your Time",
+ "we_are_open_from": "We are open from",
+ "start_time": "Start Time",
+ "end_time": "End Time",
+ "add_time_slot": "Add This Time Slot",
+ "confirm": "Confirm",
+ "close": "Close",
+ "signup_success": "You have signed up! We look forward to seeing you!",
+ "time_slot_info_prompt": "Below is your time slot information. You can check it out on the homepage.",
+ "time": "Time",
+ "select_date": "Select Date",
+ "group_name": "Name of group",
+ "group_description": "Group description",
+ "group_signup_reason": "Reason(s) for group signup",
+ "capacity": "Capacity",
+ "send": "Send",
+ "group_signup_success": "Group sign up is successful! We hope to see you soon.",
+ "must_belong_to_org": "You must belong to an organization to create time slots.",
+ "create_time_slots_failed": "Failed to create time slots. Please try again.",
+ "time_slot_registrations": "Time Slot Registrations",
+ "opening_time": "Opening Time",
+ "total_individual_signups": "Total Individual Signups",
+ "volunteer": "Volunteer",
+ "volunteers": "Volunteers",
+ "individuals": "Individuals",
+ "groups": "Groups",
+ "page": "Page",
+ "previous": "Previous",
+ "next": "Next",
+ "no_individuals": "It seems like no individuals have signed up!",
+ "no_groups": "It seems like no groups have signed up!",
+ "add_event_title": "Add event title",
+ "start_date": "Start Date",
+ "event_description_optional": "Event description (if any)",
+ "enter_description": "Enter description...",
+ "add": "Add",
+ "event_saved_success": "Event saved successfully!",
+ "event_save_failed": "Failed to save event.",
+ "event_save_error": "An error occurred while saving."
+}
diff --git a/public/locales/en/home.json b/public/locales/en/home.json
index 0dd83b3..0a1b75d 100644
--- a/public/locales/en/home.json
+++ b/public/locales/en/home.json
@@ -3,5 +3,24 @@
"welcome_subtitle": "What's the next event you want to join",
"upcoming_times": "Your upcoming volunteer times",
"volunteer_hours": "Personal volunteer hours",
- "events_attended": "Events attended"
+ "events_attended": "Events attended",
+ "days_volunteered": "Days volunteered",
+ "no_upcoming_slots": "It seems like you have not signed up for any time slots yet!",
+ "opening_time": "Opening Time",
+ "total_volunteer_count": "Total volunteers",
+ "volunteers_list": "Volunteers List",
+ "upcoming_events": "Upcoming Events",
+ "manage": "Manage",
+ "stats_updated_by": "Stats updated by:",
+ "time_slot": "Time Slot",
+ "see_details": "See details",
+ "total_volunteer_hours": "Total volunteer hours",
+ "name": "Name",
+ "email_address": "Email Address",
+ "hours_volunteered": "Hours Volunteered",
+ "hour": "hour",
+ "hours": "hours",
+ "view": "View",
+ "times": "Time(s)",
+ "times_and_group_size": "Time(s) and Group Size"
}
diff --git a/public/locales/en/profile.json b/public/locales/en/profile.json
new file mode 100644
index 0000000..f6f143b
--- /dev/null
+++ b/public/locales/en/profile.json
@@ -0,0 +1,41 @@
+{
+ "volunteer_log": "Volunteer Log",
+ "personal_stats": "Personal Stats",
+ "volunteer_timesheet": "Volunteer Timesheet",
+ "personal_volunteer_hours": "Personal volunteer hours",
+ "days_volunteered": "Days volunteered",
+ "start_date": "Start Date",
+ "end_date": "End Date",
+ "date": "Date",
+ "total_hours_worked": "Total Hours Worked",
+ "volunteer_sessions": "Volunteer Session(s)",
+ "hours": "hours",
+ "page": "Page",
+ "previous": "Previous",
+ "next": "Next",
+ "personal_information": "Personal Information",
+ "edit": "Edit",
+ "organization": "Organization",
+ "over_14_question": "Are you over 14?",
+ "over_14_note": "Note: we require volunteers to be over 14 years old to work with us.",
+ "first_time_question": "Is this your first time volunteering with us?",
+ "address": "Address",
+ "drivers_license_question": "Do you have a driver's license?",
+ "speak_spanish_question": "Do you speak Spanish?",
+ "why_volunteer_question": "Why do you want to volunteer with us?",
+ "other_questions_prompt": "Do you have any other questions or comments?",
+ "yes": "Yes",
+ "no": "No",
+ "no_time_slots_in_range": "It looks like there are no time slots in this range!",
+ "edit_info": "Edit Info",
+ "cancel": "Cancel",
+ "save": "Save",
+ "name": "Name",
+ "group_log": "Group Log",
+ "group_stats": "Group Stats",
+ "group_timesheet": "Group Timesheet",
+ "people": "People",
+ "loading": "Loading",
+ "must_be_logged_in": "You must be logged in to edit your profile.",
+ "go_back": "Go back"
+}
diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json
index 6afb31c..9d5c0ad 100644
--- a/public/locales/en/translation.json
+++ b/public/locales/en/translation.json
@@ -10,5 +10,11 @@
"profile": "Profile",
"logout": "Logout",
"see_all": "See all",
- "ver_more": "See all"
+ "ver_more": "See all",
+ "customize_event": "Customize Event",
+ "sign_up_group": "Sign Up As a Group",
+ "admin": "Admin",
+ "communication": "Communication",
+ "organization": "Organization",
+ "check_in_out": "Check-in/out"
}
diff --git a/public/locales/en/volunteers.json b/public/locales/en/volunteers.json
new file mode 100644
index 0000000..43677cf
--- /dev/null
+++ b/public/locales/en/volunteers.json
@@ -0,0 +1,27 @@
+{
+ "volunteer_list": "Volunteer List",
+ "organizations_list": "Organizations List",
+ "search": "Search",
+ "selected": "Selected",
+ "delete": "Delete",
+ "number_of_people": "Number of People",
+ "volunteer": "Volunteer",
+ "volunteer_lower": "volunteer",
+ "volunteers": "volunteers",
+ "organizations": "Organizations",
+ "list": "List",
+ "individuals": "Individuals",
+ "delete_confirmation_title": "Are you sure you want to delete {{count}} {{type}}?",
+ "delete_warning": "You will not be able to recover {{article}} deleted {{type}}.",
+ "user": "user",
+ "users": "users",
+ "organization": "organization",
+ "organizations_lower": "organizations",
+ "profile": "profile",
+ "profiles": "profiles",
+ "a": "a",
+ "cancel": "Cancel",
+ "no_individuals_found": "No individuals found!",
+ "no_organizations_found": "No organizations found!",
+ "loading": "Loading"
+}
diff --git a/public/locales/es/check.json b/public/locales/es/check.json
new file mode 100644
index 0000000..3ff1ebc
--- /dev/null
+++ b/public/locales/es/check.json
@@ -0,0 +1,30 @@
+{
+ "back_to_home_page": "Volver a la página de inicio",
+ "daily_checkin_checkout": "Registro de entrada/salida diario",
+ "i_want_to": "Quiero",
+ "check_in": "Entrada",
+ "check_out": "Salida",
+ "select_type": "Seleccionar tipo",
+ "individual": "Individuo",
+ "group": "Grupo",
+ "your_email": "Tu correo electrónico",
+ "continue": "Continuar",
+ "back": "Volver",
+ "shift_signup_info": "Aquí está la información de tu turno:",
+ "shifts_choose_one": "Turno(s) (elige uno)",
+ "start": "Inicio",
+ "end": "Fin",
+ "confirm_check_in": "Confirma tu registro de entrada",
+ "must_check_in_first": "Debes registrar entrada antes de volver a registrar salida.",
+ "checkout_error": "Hubo un error durante el registro de salida.",
+ "group_already_checked_out": "Este grupo ya ha registrado salida.",
+ "already_checked_in": "Ya registraste entrada y debes registrar salida antes de volver a registrarte.",
+ "checkin_error": "Hubo un error durante el registro de entrada. Por favor, inténtalo de nuevo.",
+ "check_success_message": "¡Bien hecho! Has registrado {{action}} a las {{time}}.",
+ "in": "entrada",
+ "out": "salida",
+ "checkin_caption": "¡No olvides registrar salida antes de irte!",
+ "checkout_caption": "Gracias por tu gran trabajo hoy. ¡Esperamos verte de nuevo pronto!",
+ "back_to_first_page": "Volver a la primera página",
+ "organization_name": "Nombre de la organización"
+}
diff --git a/public/locales/es/communication.json b/public/locales/es/communication.json
new file mode 100644
index 0000000..ad05870
--- /dev/null
+++ b/public/locales/es/communication.json
@@ -0,0 +1,15 @@
+{
+ "send_email_to_volunteers": "Enviar correo a los voluntarios",
+ "email_subject": "Asunto",
+ "email_from": "Correo del remitente",
+ "default_email_note": "Este es el correo predeterminado.",
+ "email_body": "Cuerpo del correo",
+ "email_reach_note": "Este mensaje se enviará a todos los voluntarios en el sitio.",
+ "email_example": "ej: ¡Bienvenido a Bread & Roses!",
+ "click_to_upload": "Haz clic para subir",
+ "type_email_content": "Escribe el contenido del correo",
+ "send_email": "Enviar correo",
+ "complete": "Completado",
+ "email_sent_confirmation": "¡Correo enviado! Recibirás una copia por correo electrónico.",
+ "back_to_original_page": "Volver a la página original"
+}
diff --git a/public/locales/es/events.json b/public/locales/es/events.json
new file mode 100644
index 0000000..29a5874
--- /dev/null
+++ b/public/locales/es/events.json
@@ -0,0 +1,45 @@
+{
+ "events": "Eventos",
+ "sign_up_prompt": "¡Regístrate para tu turno de voluntariado!",
+ "your_volunteer_hours": "Tus horas de voluntariado",
+ "no_time_slots": "¡No hay turnos!",
+ "choose_your_time": "Elige tu horario",
+ "we_are_open_from": "Estamos abiertos desde",
+ "start_time": "Hora de inicio",
+ "end_time": "Hora de fin",
+ "add_time_slot": "Agregar este turno",
+ "confirm": "Confirmar",
+ "close": "Cerrar",
+ "signup_success": "¡Te has registrado! ¡Esperamos verte pronto!",
+ "time_slot_info_prompt": "A continuación está la información de tu turno. Puedes verla en la página principal.",
+ "time": "Hora",
+ "select_date": "Seleccionar fecha",
+ "group_name": "Nombre del grupo",
+ "group_description": "Descripción del grupo",
+ "group_signup_reason": "Razón(es) para el registro del grupo",
+ "capacity": "Capacidad",
+ "send": "Enviar",
+ "group_signup_success": "¡El registro del grupo fue exitoso! Esperamos verte pronto.",
+ "must_belong_to_org": "Debes pertenecer a una organización para crear turnos.",
+ "create_time_slots_failed": "No se pudieron crear los turnos. Por favor, inténtalo de nuevo.",
+ "time_slot_registrations": "Registros de turnos",
+ "opening_time": "Hora de apertura",
+ "total_individual_signups": "Total de inscripciones individuales",
+ "volunteer": "voluntario",
+ "volunteers": "voluntarios",
+ "individuals": "Individuos",
+ "groups": "Grupos",
+ "page": "Página",
+ "previous": "Anterior",
+ "next": "Siguiente",
+ "no_individuals": "¡Parece que ningún individuo se ha registrado!",
+ "no_groups": "¡Parece que ningún grupo se ha registrado!",
+ "add_event_title": "Agregar título del evento",
+ "start_date": "Fecha de inicio",
+ "event_description_optional": "Descripción del evento (opcional)",
+ "enter_description": "Ingresa una descripción...",
+ "add": "Agregar",
+ "event_saved_success": "¡Evento guardado con éxito!",
+ "event_save_failed": "No se pudo guardar el evento.",
+ "event_save_error": "Ocurrió un error al guardar."
+}
diff --git a/public/locales/es/home.json b/public/locales/es/home.json
index 9deca7a..0df67af 100644
--- a/public/locales/es/home.json
+++ b/public/locales/es/home.json
@@ -3,5 +3,24 @@
"welcome_subtitle": "¿Cuál es el próximo evento al que quieres unirte?",
"upcoming_times": "Tus próximos tiempos de voluntariado",
"volunteer_hours": "Horas de voluntariado",
- "events_attended": "Eventos asistidos"
+ "events_attended": "Eventos asistidos",
+ "days_volunteered": "Días como voluntario",
+ "no_upcoming_slots": "¡Parece que aún no te has registrado en ningún turno!",
+ "opening_time": "Hora de apertura",
+ "total_volunteer_count": "Total de voluntarios",
+ "volunteers_list": "Lista de voluntarios",
+ "upcoming_events": "Próximos eventos",
+ "manage": "Administrar",
+ "stats_updated_by": "Estadísticas actualizadas el:",
+ "time_slot": "Turno",
+ "see_details": "Ver detalles",
+ "total_volunteer_hours": "Total de horas voluntarias",
+ "name": "Nombre",
+ "email_address": "Correo electrónico",
+ "hours_volunteered": "Horas como voluntario",
+ "hour": "hora",
+ "hours": "horas",
+ "view": "Ver",
+ "times": "Hora(s)",
+ "times_and_group_size": "Hora(s) y tamaño del grupo"
}
diff --git a/public/locales/es/profile.json b/public/locales/es/profile.json
new file mode 100644
index 0000000..c9aa378
--- /dev/null
+++ b/public/locales/es/profile.json
@@ -0,0 +1,41 @@
+{
+ "volunteer_log": "Registro de voluntariado",
+ "personal_stats": "Estadísticas personales",
+ "volunteer_timesheet": "Hoja de tiempos de voluntariado",
+ "personal_volunteer_hours": "Horas de voluntariado personales",
+ "days_volunteered": "Días como voluntario",
+ "start_date": "Fecha de inicio",
+ "end_date": "Fecha de fin",
+ "date": "Fecha",
+ "total_hours_worked": "Total de horas trabajadas",
+ "volunteer_sessions": "Sesión(es) de voluntariado",
+ "hours": "horas",
+ "page": "Página",
+ "previous": "Anterior",
+ "next": "Siguiente",
+ "personal_information": "Información personal",
+ "edit": "Editar",
+ "organization": "Organización",
+ "over_14_question": "¿Tienes más de 14 años?",
+ "over_14_note": "Nota: requerimos que los voluntarios tengan más de 14 años para trabajar con nosotros.",
+ "first_time_question": "¿Es tu primera vez haciendo voluntariado con nosotros?",
+ "address": "Dirección",
+ "drivers_license_question": "¿Tienes licencia de conducir?",
+ "speak_spanish_question": "¿Hablas español?",
+ "why_volunteer_question": "¿Por qué quieres ser voluntario con nosotros?",
+ "other_questions_prompt": "¿Tienes alguna otra pregunta o comentario?",
+ "yes": "Sí",
+ "no": "No",
+ "no_time_slots_in_range": "¡Parece que no hay turnos en este rango de fechas!",
+ "edit_info": "Editar información",
+ "cancel": "Cancelar",
+ "save": "Guardar",
+ "name": "Nombre",
+ "group_log": "Registro del grupo",
+ "group_stats": "Estadísticas del grupo",
+ "group_timesheet": "Hoja de horas del grupo",
+ "people": "Personas",
+ "loading": "Cargando",
+ "must_be_logged_in": "Debes iniciar sesión para editar tu perfil.",
+ "go_back": "Volver"
+}
diff --git a/public/locales/es/translation.json b/public/locales/es/translation.json
index 0ca4510..ba31655 100644
--- a/public/locales/es/translation.json
+++ b/public/locales/es/translation.json
@@ -10,5 +10,11 @@
"profile": "Perfil",
"logout": "Cerrar sesión",
"see_all": "Ver más",
- "ver_more": "Ver más"
+ "ver_more": "Ver más",
+ "customize_event": "Personalizar evento",
+ "sign_up_group": "Registrarse como grupo",
+ "admin": "Administrador",
+ "communication": "Comunicación",
+ "organization": "Organización",
+ "check_in_out": "Entrada/Salida"
}
diff --git a/public/locales/es/volunteers.json b/public/locales/es/volunteers.json
new file mode 100644
index 0000000..a2856d1
--- /dev/null
+++ b/public/locales/es/volunteers.json
@@ -0,0 +1,28 @@
+{
+ "volunteer_list": "Lista de voluntarios",
+ "organizations_list": "Lista de organizaciones",
+ "search": "Buscar",
+ "selected": "Seleccionado(s)",
+ "delete": "Eliminar",
+ "number_of_people": "Número de personas",
+ "volunteer": "Voluntario",
+ "volunteer_lower": "voluntario",
+ "volunteers": "voluntarios",
+ "organizations": "Organizaciones",
+ "list": "Lista",
+ "individuals": "Individuos",
+ "delete_confirmation_title": "¿Estás seguro de que deseas eliminar {{count}} {{type}}?",
+ "delete_warning": "No podrás recuperar {{article}} {{type}} eliminado{{pluralSuffix}}.",
+ "user": "usuario",
+ "users": "usuarios",
+ "organization": "organización",
+ "organizations_lower": "organizaciones",
+ "profile": "perfil",
+ "profiles": "perfiles",
+ "a": "un",
+ "cancel": "Cancelar",
+ "pluralSuffix": "s",
+ "no_individuals_found": "¡No se encontraron individuos!",
+ "no_organizations_found": "¡No se encontraron organizaciones!",
+ "loading": "Cargando"
+}
diff --git a/src/app/private/communication/page.tsx b/src/app/private/communication/page.tsx
index 25c4418..60d2569 100644
--- a/src/app/private/communication/page.tsx
+++ b/src/app/private/communication/page.tsx
@@ -9,6 +9,7 @@ import FileUploadRoundedIcon from "@mui/icons-material/FileUploadRounded";
import UploadFileIcon from "@mui/icons-material/UploadFile";
import DeleteIcon from "@mui/icons-material/Delete";
import { Attachment } from "nodemailer/lib/mailer";
+import { useTranslation } from "react-i18next";
export default function CommunicationPage() {
const [step, setStep] = useState(1);
@@ -17,6 +18,7 @@ export default function CommunicationPage() {
code: "SUCCESS" | "ERROR";
message: string;
}
+ const { t } = useTranslation("communication");
const [subject, setSubject] = React.useState("");
const [fromEmail] = React.useState("breadandrosesjc@gmail.com");
@@ -104,18 +106,18 @@ export default function CommunicationPage() {
- Send Email To Volunteers
+ {t("send_email_to_volunteers")}
{step === 1 && (
<>
-
Subject
+
{t("email_subject")}
setSubject(e.target.value)}
@@ -125,8 +127,8 @@ export default function CommunicationPage() {
-
Email From
-
This is the default email.
+
{t("email_from")}
+
{t("default_email_note")}
-
Email Body
-
- This will be sent to all volunteers on the site.
-
+
{t("email_body")}
+
{t("email_reach_note")}
- Click to upload
+ {t("click_to_upload")}
{" "}
- or drag and drop
{formatFileSize(src.size)}
•
-
Complete
+
{t("complete")}
setText(e.target.value)}
rows={10}
@@ -222,7 +221,7 @@ export default function CommunicationPage() {
}
}}
>
- Send Email
+ {t("send_email")}
@@ -241,14 +240,14 @@ export default function CommunicationPage() {
quality={100}
/>
- Email sent! You will receive a copy via email.
+ {t("email_sent_confirmation")}
>
diff --git a/src/app/private/events/page.tsx b/src/app/private/events/page.tsx
index 4139405..9da8f2c 100644
--- a/src/app/private/events/page.tsx
+++ b/src/app/private/events/page.tsx
@@ -19,9 +19,11 @@ import { useSearchParams } from "next/navigation";
import { getStandardDate } from "../../utils";
import { getCustomDay } from "@api/customDay/route.client";
import useApiThrottle from "../../../hooks/useApiThrottle";
+import { useTranslation } from "react-i18next";
export default function EventsPage() {
const { data: session } = useSession();
+ const { t } = useTranslation(["translation", "events"]);
const searchParams = useSearchParams();
const date = searchParams.get("date");
@@ -314,7 +316,7 @@ export default function EventsPage() {
if (pageLoading || !session) {
return (
- Loading...
+ {t("Loading", { ns: "translation" })}...
);
}
@@ -323,7 +325,7 @@ export default function EventsPage() {
- Events
+ {t("events", { ns: "events" })}
@@ -356,8 +358,8 @@ export default function EventsPage() {
{customDayTitle === ""
? !isPastOrToday(selectedDate)
- ? `Sign up for your volunteering time!`
- : "Your Volunteer Hours"
+ ? t("sign_up_prompt", { ns: "events" })
+ : t("your_volunteer_hours", { ns: "events" })
: customDayTitle}
{customDayDescription !== "" && (
@@ -376,7 +378,12 @@ export default function EventsPage() {
{formattedDate
? !isPastOrToday(selectedDate)
- ? `Choose Your Time (${formattedDate}). We are open from${" "}
+ ? `${t("choose_your_time", {
+ ns: "events",
+ })} (${formattedDate}). ${t(
+ "we_are_open_from",
+ { ns: "events" }
+ )}${" "}
${formatTime(customDayHours.start)} -${" "}
${formatTime(customDayHours.end)}.`
: `${formattedDate} (${formatTime(
@@ -392,7 +399,7 @@ export default function EventsPage() {
{isPastOrToday(selectedDate) &&
timeSlots.length === 1 ? (
-
No time slots!
+
{t("no_time_slots", { ns: "events" })}
) : (
timeSlots.map((slot, index) => (
@@ -434,7 +441,9 @@ export default function EventsPage() {
type="time"
variant="outlined"
size="small"
- label="Start Time"
+ label={t("start_time", {
+ ns: "events",
+ })}
value={slot.start}
onChange={(e) => {
const newSlots = [...timeSlots];
@@ -466,7 +475,7 @@ export default function EventsPage() {
type="time"
variant="outlined"
size="small"
- label="End Time"
+ label={t("end_time", { ns: "events" })}
value={slot.end}
onChange={(e) => {
const newSlots = [...timeSlots];
@@ -519,7 +528,9 @@ export default function EventsPage() {
width="20"
height="20"
/>
-
Add This Time Slot
+
+ {t("add_time_slot", { ns: "events" })}
+
) : null}
@@ -534,7 +545,7 @@ export default function EventsPage() {
) : (
- You have signed up! We look forward to seeing you!
+ {t("signup_success", { ns: "events" })}
- Below is your time slot information. You can check it out on
- the homepage.
+ {t("time_slot_info_prompt", { ns: "events" })}
- {page === 0 ? "Confirm" : "Close"}
+ {page === 0
+ ? t("confirm", { ns: "events" })
+ : t("close", { ns: "events" })}
) : null}
@@ -624,7 +636,7 @@ export default function EventsPage() {
{customDayTitle === ""
- ? "Time Slot Registrations"
+ ? t("time_slot_registrations", { ns: "events" })
: customDayTitle}
{customDayDescription !== "" && (
@@ -641,7 +653,8 @@ export default function EventsPage() {
height="20"
/>
- Opening Time: {formatTime(customDayHours.start)} -{" "}
+ {t("opening_time", { ns: "events" })}:{" "}
+ {formatTime(customDayHours.start)} -{" "}
{formatTime(customDayHours.end)}
@@ -653,10 +666,15 @@ export default function EventsPage() {
height="20"
/>
- Total Individual Signups: {individuals.length}{" "}
- {individuals.length === 1 ? "volunteer" : "volunteers"} /{" "}
- Capacity: {customDayCapacity}{" "}
- {customDayCapacity === 1 ? "volunteer" : "volunteers"}
+ {t("total_individual_signups", { ns: "events" })}:{" "}
+ {individuals.length}{" "}
+ {individuals.length === 1
+ ? t("volunteer", { ns: "events" })
+ : t("volunteers", { ns: "events" })}{" "}
+ / {t("capacity", { ns: "events" })}: {customDayCapacity}{" "}
+ {customDayCapacity === 1
+ ? t("volunteer", { ns: "events" })
+ : t("volunteers", { ns: "events" })}
@@ -683,7 +701,7 @@ export default function EventsPage() {
width="20"
height="20"
/>
-
{tab}
+
{t(tab.toLowerCase(), { ns: "events" })}
))}
@@ -699,7 +717,7 @@ export default function EventsPage() {
/>
- It seems like no individuals have signed up!
+ {t("no_individuals", { ns: "events" })}
) : (
@@ -721,7 +739,7 @@ export default function EventsPage() {
/>
- It seems like no groups have signed up!
+ {t("no_groups", { ns: "events" })}
) : (
diff --git a/src/app/private/organization/[organizationId]/page.tsx b/src/app/private/organization/[organizationId]/page.tsx
index 0242bf8..fa7ffb5 100644
--- a/src/app/private/organization/[organizationId]/page.tsx
+++ b/src/app/private/organization/[organizationId]/page.tsx
@@ -14,11 +14,13 @@ import { OrganizationWithUsers } from "../../../types";
import { useSession } from "next-auth/react";
import { getOrganization } from "@api/organization/route.client";
import VolunteerTable from "@components/VolunteerTable";
+import { useTranslation } from "react-i18next";
export default function ProfileContent() {
const { organizationId } = useParams();
const { data: session, status } = useSession();
const router = useRouter();
+ const { t } = useTranslation("profile");
const startButtonRef = React.useRef(null);
const startCalendarRef = React.useRef(null);
@@ -128,7 +130,7 @@ export default function ProfileContent() {
if (loading || !organization) {
return (
- Loading...
+ {t("loading")}...
);
}
@@ -152,7 +154,9 @@ export default function ProfileContent() {
{organization.name}
- Organization
+
+ {t("organization")}
+
@@ -161,7 +165,7 @@ export default function ProfileContent() {
- Group Log
+ {t("group_log")}
@@ -170,7 +174,7 @@ export default function ProfileContent() {
className="border border-gray-300 rounded-md px-3 py-2 w-[215.5px] focus:outline-none focus:ring-1 focus:ring-blue-500"
placeholder="MM/DD/YYYY"
variant="outlined"
- label="Start Date"
+ label={t("start_date")}
autoComplete="off"
size="small"
onFocus={() => setShowStartCalendar(!showStartCalendar)}
@@ -229,7 +233,7 @@ export default function ProfileContent() {
className="border border-gray-300 rounded-md px-3 py-2 w-[215.5px] focus:outline-none focus:ring-1 focus:ring-blue-500"
placeholder="MM/DD/YYYY"
variant="outlined"
- label="End Date"
+ label={t("end_date")}
autoComplete="off"
size="small"
onFocus={() => setShowEndCalendar(!showEndCalendar)}
@@ -282,22 +286,22 @@ export default function ProfileContent() {
-
Group Stats
+
{t("group_stats")}
-
Group Timesheet
+
{t("group_timesheet")}
{filteredSessions.length === 0 ? (
@@ -310,7 +314,7 @@ export default function ProfileContent() {
/>
- It looks like there are no time slots in this range!
+ {t("no_time_slots_in_range")}
) : (
@@ -321,7 +325,9 @@ export default function ProfileContent() {
-
People
+
+ {t("people")}
+
{organization.users?.length === 0 ? (
diff --git a/src/app/private/page.tsx b/src/app/private/page.tsx
index a5b432a..afd98a2 100644
--- a/src/app/private/page.tsx
+++ b/src/app/private/page.tsx
@@ -157,7 +157,7 @@ export default function HomePage() {
if (!session || pageLoading) {
return (
- Loading...
+ {t("Loading")}...
);
}
@@ -192,7 +192,9 @@ export default function HomePage() {
className="flex justify-end flex-row gap-x-2 bg-teal-600 px-3.5 py-1 text-white rounded-lg place-items-center text-[14px] font-semibold leading-[20px]"
onClick={action}
>
- {session.user.role === Role.VOLUNTEER ? t("Manage") : t("See details")}
+ {session.user.role === Role.VOLUNTEER
+ ? t("manage", { ns: "home" })
+ : t("see_details", { ns: "home" })}
);
@@ -203,7 +205,7 @@ export default function HomePage() {
{t("welcome_title", { ns: "home" })}, {session.user.firstName} 👋
- Stats updated by:{" "}
+ {t("stats_updated_by", { ns: "home" })}{" "}
{(() => {
const date = new Date().toLocaleDateString("en-GB", {
weekday: "long",
@@ -222,7 +224,7 @@ export default function HomePage() {
{session.user.role === Role.ADMIN && (
@@ -230,7 +232,7 @@ export default function HomePage() {
{session.user.role === Role.VOLUNTEER && (
@@ -249,7 +251,7 @@ export default function HomePage() {
{session.user.role === Role.ADMIN
- ? "Upcoming Events"
+ ? t("upcoming_events", { ns: "home" })
: t("upcoming_times", { ns: "home" })}
- It seems like you have not signed up for any time slots yet!
+ {t("no_upcoming_slots", { ns: "home" })}
) : (
@@ -288,7 +290,7 @@ export default function HomePage() {
{timeSlots.slice(0, 6).map((timeSlot, index) => (
- Volunteers List
+ {t("volunteers_list", { ns: "home" })}
(null);
const [volunteerDetails, setVolunteerDetails] =
@@ -171,7 +173,7 @@ export default function EditProfilePage() {
if (status === "loading" || loading) {
return (
- Loading...
+ {t("loading", { ns: "profile" })}...
);
}
@@ -179,7 +181,7 @@ export default function EditProfilePage() {
if (!session) {
return (
- You must be logged in to edit your profile.
+ {t("must_be_logged_in")}
);
}
@@ -192,7 +194,7 @@ export default function EditProfilePage() {
onClick={() => router.push(`/private/profile/${userId}`)}
className="px-4 py-2 bg-gray-200 rounded"
>
- Go back
+ {t("go_back")}
);
@@ -201,7 +203,7 @@ export default function EditProfilePage() {
if (!user) {
return (
- Loading...
+ {t("loading", { ns: "profile" })}...
);
}
@@ -209,14 +211,16 @@ export default function EditProfilePage() {
return (
-
Edit Info
+
+ {t("edit_info", { ns: "profile" })}
+
@@ -232,7 +236,7 @@ export default function EditProfilePage() {
{/* First Name / Last Name */}
- Name *
+ {t("name", { ns: "profile" })} *
@@ -262,7 +266,9 @@ export default function EditProfilePage() {
<>
-
Organization
+
+ {t("organization", { ns: "profile" })}
+
- Are you over 14? *
+ {t("over_14_question", { ns: "profile" })}{" "}
+ *
- Note: we require volunteers to be over 14 years old to work with
- us.
+ {t("over_14_note", { ns: "profile" })}
handleChange("ageOver14", true)}
/>
@@ -328,12 +334,12 @@ export default function EditProfilePage() {
{/* First time volunteering? */}
handleChange("firstTime", true)}
/>
@@ -350,7 +356,8 @@ export default function EditProfilePage() {
{/* Address Row */}
- Address *
+ {t("address", { ns: "profile" })}{" "}
+ *
handleChange("hasLicense", true)}
/>
@@ -429,11 +436,12 @@ export default function EditProfilePage() {
{/* Speak Spanish? */}
handleChange("speaksEsp", true)}
/>
@@ -451,7 +459,7 @@ export default function EditProfilePage() {
@@ -469,7 +477,7 @@ export default function EditProfilePage() {
- Do you have any other questions or comments?
+ {t("other_questions_prompt", { ns: "profile" })}
diff --git a/src/app/private/profile/[userId]/page.tsx b/src/app/private/profile/[userId]/page.tsx
index cec8df1..c5d13b5 100644
--- a/src/app/private/profile/[userId]/page.tsx
+++ b/src/app/private/profile/[userId]/page.tsx
@@ -7,11 +7,13 @@ import ProfileContent from "@components/ProfileContent";
import { UserWithVolunteerDetail } from "../../../types";
import { VolunteerSession } from "@prisma/client";
import { getUser } from "@api/user/route.client";
+import { useTranslation } from "react-i18next";
export default function UserProfilePage() {
const { userId } = useParams();
const { data: session, status } = useSession();
const router = useRouter();
+ const { t } = useTranslation("profile");
const [user, setUser] = useState
(null);
const [sessions, setSessions] = useState([]);
@@ -48,7 +50,7 @@ export default function UserProfilePage() {
if (loading || !user) {
return (
- Loading...
+ {t("loading")}...
);
}
diff --git a/src/app/private/profile/page.tsx b/src/app/private/profile/page.tsx
index b45f2d4..0ba06fc 100644
--- a/src/app/private/profile/page.tsx
+++ b/src/app/private/profile/page.tsx
@@ -3,10 +3,12 @@
import { useEffect } from "react";
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";
+import { useTranslation } from "react-i18next";
export default function ProfilePage() {
const { data: session, status } = useSession();
const router = useRouter();
+ const { t } = useTranslation("profile");
useEffect(() => {
if (status === "loading") return;
@@ -17,7 +19,7 @@ export default function ProfilePage() {
return (
- Loading...
+ {t("loading")}...
);
}
diff --git a/src/app/private/volunteers/page.tsx b/src/app/private/volunteers/page.tsx
index a0f8132..68b5191 100644
--- a/src/app/private/volunteers/page.tsx
+++ b/src/app/private/volunteers/page.tsx
@@ -15,8 +15,10 @@ import {
getOrganizations,
} from "@api/organization/route.client";
import OrganizationTable from "@components/OrganizationTable";
+import { useTranslation } from "react-i18next";
export default function VolunteersPage() {
+ const { t } = useTranslation("volunteers");
const [pageLoading, setPageLoading] = React.useState(true);
const [users, setUsers] = React.useState();
const [organizations, setOrganizations] = React.useState();
@@ -27,6 +29,21 @@ export default function VolunteersPage() {
"Individuals" | "Organizations"
>("Individuals");
+ const isIndividual = activeTab === "Individuals";
+ const isSingular = selected.length === 1;
+
+ const typeKey = isIndividual
+ ? isSingular
+ ? "user"
+ : "users"
+ : isSingular
+ ? "organization"
+ : "organizations";
+
+ const profileKey = isSingular ? "profile" : "profiles";
+
+ const article = isSingular ? t("a") : "";
+
React.useEffect(() => {
const fetchData = async () => {
try {
@@ -122,7 +139,7 @@ export default function VolunteersPage() {
if (pageLoading) {
return (
- Loading...
+ {t("loading")}...
);
}
@@ -133,7 +150,10 @@ export default function VolunteersPage() {
- {activeTab === "Individuals" ? "Volunteer" : "Organizations"} List (
+ {`${t(
+ activeTab === "Individuals" ? "volunteer" : "organizations"
+ )} ${t("list")}`}{" "}
+ (
{activeTab === "Individuals" && users
? users.length
: organizations
@@ -144,7 +164,9 @@ export default function VolunteersPage() {
{selected.length > 0 ? (
-
{selected.length} Selected
+
+ {selected.length} {t("selected")}
+
) : (
@@ -195,7 +217,7 @@ export default function VolunteersPage() {
width="24"
height="24"
/>
-
{tab}
+
{t(tab.toLowerCase())}
))}
@@ -230,8 +252,9 @@ export default function VolunteersPage() {
/>
- No {activeTab === "Individuals" ? "individuals" : "organizations"}{" "}
- found!
+ {activeTab === "Individuals"
+ ? t("no_individuals_found")
+ : t("no_organizations_found")}
)}
@@ -240,19 +263,17 @@ export default function VolunteersPage() {
- Are you sure you want to delete {selected.length}{" "}
- {activeTab === "Individuals"
- ? selected.length === 1
- ? "user"
- : "users"
- : selected.length === 1
- ? "organization"
- : "organizations"}
- ?
+ {t("delete_confirmation_title", {
+ count: selected.length,
+ type: t(typeKey),
+ })}
- You will not be able to recover {selected.length === 1 ? "a" : ""}{" "}
- deleted {selected.length === 1 ? "profile" : "profiles"}.
+ {t("delete_warning", {
+ article,
+ type: t(profileKey),
+ pluralSuffix: isSingular ? "" : t("pluralSuffix"),
+ })}
diff --git a/src/components/CheckInOut.tsx b/src/components/CheckInOut.tsx
index f420d8e..cfdaa31 100644
--- a/src/components/CheckInOut.tsx
+++ b/src/components/CheckInOut.tsx
@@ -19,9 +19,11 @@ import { useRouter } from "next/navigation";
import useApiThrottle from "../hooks/useApiThrottle";
import { OrganizationWithUsers, UserWithVolunteerDetail } from "../app/types";
import { getOrganizationsByDate } from "@api/organization/route.client";
+import { useTranslation } from "react-i18next";
export default function CheckInOutForm() {
const router = useRouter();
+ const { t } = useTranslation("check");
const [email, setEmail] = useState("");
const [activeButton, setActiveButton] = useState<
@@ -120,10 +122,10 @@ export default function CheckInOutForm() {
} catch (err) {
const errorData = JSON.parse((err as Error).message);
if (errorData.code === "ALREADY_CHECKED_OUT") {
- alert("You must check in before checking out again.");
+ alert(t("must_check_in_first"));
} else {
console.error("Check-out failed:", errorData.message);
- alert("There was an error during check-out.");
+ alert(t("checkout_error"));
}
}
}
@@ -161,10 +163,10 @@ export default function CheckInOutForm() {
} catch (err) {
const errorData = JSON.parse((err as Error).message);
if (errorData.code === "ALREADY_CHECKED_OUT") {
- alert("This group has already checked out.");
+ alert(t("group_already_checked_out"));
} else {
console.error("Group check-out failed:", errorData.message);
- alert("There was an error during check-out.");
+ alert(t("checkout_error"));
}
}
}
@@ -233,12 +235,10 @@ export default function CheckInOutForm() {
const errorData = JSON.parse(err.message);
if (errorData.code === "ALREADY_CHECKED_IN") {
- alert(
- "You have already checked in and must check out before checking in again."
- );
+ alert(t("already_checked_in"));
} else {
console.error("Check-in failed:", errorData.message);
- alert("There was an error during check-in. Please try again.");
+ alert(t("checkin_error"));
}
} else {
console.error("Unexpected error:", err);
@@ -275,7 +275,7 @@ export default function CheckInOutForm() {
}}
>
- Back
+ {t("back")}
- Daily Check-In/Check-Out
+ {t("daily_checkin_checkout")}
{new Date().toLocaleDateString("en-US", {
@@ -310,9 +310,9 @@ export default function CheckInOutForm() {
- Here is your shift signup information:
+ {t("shift_signup_info")}
- Shift(s) (choose one)
+ {t("shifts_choose_one")}
{timeSlots.map((slot, index) => {
const start = new Date(slot.startTime);
const end = new Date(slot.endTime);
@@ -343,7 +343,7 @@ export default function CheckInOutForm() {
/>
- Confirm Your Check-In
+ {t("confirm_check_in")}
@@ -387,23 +387,22 @@ export default function CheckInOutForm() {
} else if (stage === "confirmation") {
return (
{
setEmail("");
@@ -428,7 +427,7 @@ export default function CheckInOutForm() {
}}
>
- Back to Home Page
+ {t("back_to_home_page")}
- Daily Check-In/Check-Out
+ {t("daily_checkin_checkout")}
{new Date().toLocaleDateString("en-US", {
@@ -463,7 +462,7 @@ export default function CheckInOutForm() {
- I want to
+ {t("i_want_to")}
- Select type
+ {t("select_type")}
{activeTab === "individual" ? (
<>
-
Your Email
+
{t("your_email")}
) : (
<>
-
Organization Name
+
{t("organization_name")}
- Continue
+ {t("continue")}
diff --git a/src/components/CustomizeEventModal.tsx b/src/components/CustomizeEventModal.tsx
index c23adad..a986102 100644
--- a/src/components/CustomizeEventModal.tsx
+++ b/src/components/CustomizeEventModal.tsx
@@ -10,6 +10,7 @@ import { format } from "date-fns";
import { Icon } from "@iconify/react/dist/iconify.js";
import { addCustomDay, getCustomDay } from "@api/customDay/route.client";
import useApiThrottle from "../hooks/useApiThrottle";
+import { useTranslation } from "react-i18next";
interface CustomizeEventProps {
modalVisible: boolean;
@@ -18,6 +19,7 @@ interface CustomizeEventProps {
const CustomizeEventModal = (props: CustomizeEventProps) => {
const { modalVisible, setModalVisible } = props;
+ const { t } = useTranslation("events");
const modalRef = useRef(null);
const buttonRef = React.useRef(null);
@@ -155,13 +157,13 @@ const CustomizeEventModal = (props: CustomizeEventProps) => {
if (result.code === "SUCCESS") {
setModalVisible(false);
- alert("Event saved successfully!");
+ alert(t("event_saved_success"));
} else {
- alert("Failed to save event.");
+ alert(t("event_save_failed"));
}
} catch (err) {
console.error(err);
- alert("An error occurred while saving.");
+ alert(t("event_save_error"));
}
};
@@ -188,7 +190,7 @@ const CustomizeEventModal = (props: CustomizeEventProps) => {
/>
{
/>
- Time
+ {t("time")}
@@ -223,7 +225,7 @@ const CustomizeEventModal = (props: CustomizeEventProps) => {
className="border border-gray-300 rounded-md px-3 py-2 w-[215.5px] focus:outline-none focus:ring-1 focus:ring-blue-500"
placeholder="MM/DD/YYYY"
variant="outlined"
- label="Start Date"
+ label={t("start_date")}
autoComplete="off"
size="small"
onFocus={() => setShowCalendar(!showCalendar)}
@@ -279,7 +281,7 @@ const CustomizeEventModal = (props: CustomizeEventProps) => {
- Event description (if any)
+ {t("event_description_optional")}
diff --git a/src/components/GroupSignUpModal.tsx b/src/components/GroupSignUpModal.tsx
index 5b255cb..be338f1 100644
--- a/src/components/GroupSignUpModal.tsx
+++ b/src/components/GroupSignUpModal.tsx
@@ -12,9 +12,11 @@ import { useSession } from "next-auth/react";
import { addTimeSlot } from "@api/timeSlot/route.client";
import { TimeSlotStatus } from "@prisma/client";
import useApiThrottle from "../hooks/useApiThrottle";
+import { useTranslation } from "react-i18next";
const GroupSignUpModal = ({ onClose }: { onClose: () => void }) => {
const { data: session } = useSession();
+ const { t } = useTranslation("events");
const [selectedDate, setSelectedDate] = useState
(() => {
const tomorrow = new Date();
@@ -82,7 +84,7 @@ const GroupSignUpModal = ({ onClose }: { onClose: () => void }) => {
if (hasErrors()) return;
if (!session?.user || !session.user.organizationId) {
- alert("You must belong to an organization to create time slots.");
+ alert(t("must_belong_to_org"));
return;
}
@@ -123,11 +125,11 @@ const GroupSignUpModal = ({ onClose }: { onClose: () => void }) => {
);
}
- alert("Group sign up is successful! We hope to see you soon.");
+ alert(t("group_signup_success"));
onClose();
} catch (err) {
console.error("Error creating time slots:", err);
- alert("Failed to create time slots. Please try again.");
+ alert(t("create_time_slots_failed"));
}
};
@@ -202,14 +204,14 @@ const GroupSignUpModal = ({ onClose }: { onClose: () => void }) => {
setShowCalendar(!showCalendar)}
@@ -262,7 +264,7 @@ const GroupSignUpModal = ({ onClose }: { onClose: () => void }) => {
void }) => {
void }) => {
void }) => {
void }) => {
onClick={throttledHandleSubmit}
disabled={submitLoading || isDisabled()}
>
- Send
+ {t("send")}
diff --git a/src/components/OrganizationTable.tsx b/src/components/OrganizationTable.tsx
index 5dc726a..d3f9acd 100644
--- a/src/components/OrganizationTable.tsx
+++ b/src/components/OrganizationTable.tsx
@@ -15,6 +15,7 @@ import { Box, Button, Typography } from "@mui/material";
import UserAvatar from "@components/UserAvatar";
import { OrganizationWithUsers } from "../app/types";
import { useRouter } from "next/navigation";
+import { useTranslation } from "react-i18next";
interface OrganizationTableProps {
showPagination: boolean;
@@ -30,6 +31,7 @@ export default function OrganizationTable({
setSelected,
}: OrganizationTableProps) {
const router = useRouter();
+ const { t } = useTranslation(["name", "events", "volunteers"]);
const [page, setPage] = useState(0);
const tableContainerRef = useRef(null);
@@ -158,7 +160,7 @@ export default function OrganizationTable({
width: "255px",
}}
>
- Name
+ {t("name", { ns: "home" })}
- Number of People
+ {t("number_of_people", { ns: "volunteers" })}
- Hours Volunteered
+ {t("hours_volunteered", { ns: "home" })}
{row.users ? row.users.length : 0}{" "}
{row.users && row.users.length === 1
- ? "volunteer"
- : "volunteers"}
+ ? t("volunteer_lower", { ns: "volunteers" })
+ : t("volunteers", { ns: "volunteers" })}
{row.totalHours.toFixed(1)}{" "}
- {row.totalHours === 1 ? "hour" : "hours"}
+ {row.totalHours === 1
+ ? t("hour", { ns: "home" })
+ : t("hours", { ns: "home" })}
- View
+ {t("view", { ns: "home" })}
- Page {page + 1} of {Math.ceil((organizations.length || 0) / 6)}
+ {t("page", { ns: "events" })} {page + 1} of{" "}
+ {Math.ceil((organizations.length || 0) / 6)}
@@ -357,7 +362,7 @@ export default function OrganizationTable({
border: "1px solid var(--Grey-300, #D0D5DD)",
}}
>
- Previous
+ {t("previous", { ns: "events" })}
diff --git a/src/components/ProfileContent.tsx b/src/components/ProfileContent.tsx
index 09c6bea..dd49b6a 100644
--- a/src/components/ProfileContent.tsx
+++ b/src/components/ProfileContent.tsx
@@ -14,6 +14,7 @@ import { InputAdornment, TextField } from "@mui/material";
import Image from "next/image";
import { useRouter } from "next/navigation";
import { UserWithVolunteerDetail } from "../app/types";
+import { useTranslation } from "react-i18next";
interface ProfileContentProps {
user: UserWithVolunteerDetail;
@@ -27,6 +28,7 @@ export default function ProfileContent({
editable,
}: ProfileContentProps) {
const router = useRouter();
+ const { t } = useTranslation(["translation", "profile"]);
const startButtonRef = React.useRef(null);
const startCalendarRef = React.useRef(null);
@@ -126,7 +128,7 @@ export default function ProfileContent({
className="flex items-center gap-2 bg-teal-600 p-2.5 px-3 text-white rounded-md font-semibold"
>
- Edit
+ {t("edit", { ns: "profile" })}
) : null}
@@ -138,7 +140,7 @@ export default function ProfileContent({
- Volunteer Log
+ {t("volunteer_log", { ns: "profile" })}
@@ -147,7 +149,7 @@ export default function ProfileContent({
className="border border-gray-300 rounded-md px-3 py-2 w-[215.5px] focus:outline-none focus:ring-1 focus:ring-blue-500"
placeholder="MM/DD/YYYY"
variant="outlined"
- label="Start Date"
+ label={t("start_date", { ns: "profile" })}
autoComplete="off"
size="small"
onFocus={() => setShowStartCalendar(!showStartCalendar)}
@@ -206,7 +208,7 @@ export default function ProfileContent({
className="border border-gray-300 rounded-md px-3 py-2 w-[215.5px] focus:outline-none focus:ring-1 focus:ring-blue-500"
placeholder="MM/DD/YYYY"
variant="outlined"
- label="End Date"
+ label={t("end_date", { ns: "profile" })}
autoComplete="off"
size="small"
onFocus={() => setShowEndCalendar(!showEndCalendar)}
@@ -263,22 +265,22 @@ export default function ProfileContent({
-
Personal Stats
+
{t("personal_stats", { ns: "profile" })}
-
Volunteer Timesheet
+
{t("volunteer_timesheet", { ns: "profile" })}
{filteredSessions.length === 0 ? (
@@ -291,7 +293,7 @@ export default function ProfileContent({
/>
- It looks like there are no time slots in this range!
+ {t("no_time_slots_in_range", { ns: "profile" })}
) : (
@@ -303,7 +305,7 @@ export default function ProfileContent({
- Personal Information
+ {t("personal_information", { ns: "profile" })}
{editable ? (
@@ -314,13 +316,15 @@ export default function ProfileContent({
className="flex items-center gap-2 bg-teal-600 p-2.5 px-3 text-white rounded-md font-semibold"
>
- Edit
+ {t("edit", { ns: "profile" })}
) : null}
{/* Volunteer Reason Field */}
-
Organization
+
+ {t("organization", { ns: "profile" })}
+
@@ -334,20 +338,20 @@ export default function ProfileContent({
- Are you over 14? *
+ {t("over_14_question", { ns: "profile" })}{" "}
+ *
- Note: we require volunteers to be over 14 years old to work
- with us.
+ {t("over_14_note", { ns: "profile" })}
@@ -355,12 +359,12 @@ export default function ProfileContent({
{/* First Time Volunteering Field */}
- Is this your first time volunteering with us?{" "}
+ {t("first_time_question", { ns: "profile" })}{" "}
*
- Address *
+ {t("address", { ns: "profile" })}{" "}
+ *
{/* Street Field */}
@@ -430,12 +435,12 @@ export default function ProfileContent({
{/* Driver's License Field */}
- Do you have a driver's license?{" "}
+ {t("drivers_license_question", { ns: "profile" })}{" "}
*
- Do you speak Spanish? *
+ {t("speak_spanish_question", { ns: "profile" })}{" "}
+ *
- Why do you want to volunteer with us?{" "}
+ {t("why_volunteer_question", { ns: "profile" })}{" "}
*
@@ -478,7 +484,7 @@ export default function ProfileContent({
{/* Questions/Comments Field */}
- Do you have any other questions or comments?
+ {t("other_questions_prompt", { ns: "profile" })}
diff --git a/src/components/SearchBar.tsx b/src/components/SearchBar.tsx
index 7641950..7ace3ac 100644
--- a/src/components/SearchBar.tsx
+++ b/src/components/SearchBar.tsx
@@ -1,6 +1,7 @@
import React from "react";
import { Box, InputBase } from "@mui/material";
import SearchIcon from "@mui/icons-material/Search";
+import { useTranslation } from "react-i18next";
interface SearchBarProps {
onSearchChange: (searchText: string) => void;
@@ -8,6 +9,8 @@ interface SearchBarProps {
}
const SearchBar = ({ onSearchChange, width = 400 }: SearchBarProps) => {
+ const { t } = useTranslation("volunteers");
+
return (
{
>
onSearchChange(e.target.value)}
sx={{
width: "100%",
diff --git a/src/components/SideNavBar.tsx b/src/components/SideNavBar.tsx
index 65ba68b..abe5f6b 100644
--- a/src/components/SideNavBar.tsx
+++ b/src/components/SideNavBar.tsx
@@ -26,7 +26,7 @@ const currentYear = new Date().getFullYear();
const SideNavBar = ({ user }: SideNavBarProps) => {
const router = useRouter();
const pathname = usePathname();
- const { t } = useTranslation(["translation"]);
+ const { t } = useTranslation("translation");
const adminTabs = [
{ name: t("home"), icon: "tabler:home", href: "/private" },
@@ -37,12 +37,12 @@ const SideNavBar = ({ user }: SideNavBarProps) => {
href: "/private/volunteers",
},
{
- name: "Communication",
+ name: t("communication"),
icon: "material-symbols:inbox-outline",
href: "/private/communication",
},
{
- name: "Check-in/out",
+ name: t("check_in_out"),
icon: "material-symbols:check-circle-outline-rounded",
href: "/private/check-in-out",
},
diff --git a/src/components/TimeSlotFields.tsx b/src/components/TimeSlotFields.tsx
index 9b4dd20..2b5e2b2 100644
--- a/src/components/TimeSlotFields.tsx
+++ b/src/components/TimeSlotFields.tsx
@@ -1,6 +1,7 @@
import { TextField } from "@mui/material";
import { Icon } from "@iconify/react/dist/iconify.js";
import React from "react";
+import { useTranslation } from "react-i18next";
interface TimeSlotProps {
timeSlots: { start: string; end: string; submitted: boolean }[];
@@ -11,6 +12,7 @@ interface TimeSlotProps {
const TimeSlotFields = (props: TimeSlotProps) => {
const { timeSlots, setTimeSlots } = props;
+ const { t } = useTranslation("events");
const formatTime = (time: string) => {
if (!time) return "";
@@ -76,7 +78,7 @@ const TimeSlotFields = (props: TimeSlotProps) => {
type="time"
variant="outlined"
size="small"
- label="Start Time"
+ label={t("start_time")}
value={slot.start}
onChange={(e) => {
const newSlots = [...timeSlots];
@@ -100,7 +102,7 @@ const TimeSlotFields = (props: TimeSlotProps) => {
type="time"
variant="outlined"
size="small"
- label="End Time"
+ label={t("end_time")}
value={slot.end}
onChange={(e) => {
const newSlots = [...timeSlots];
diff --git a/src/components/TimeTable.tsx b/src/components/TimeTable.tsx
index 264c871..b0090f9 100644
--- a/src/components/TimeTable.tsx
+++ b/src/components/TimeTable.tsx
@@ -11,12 +11,15 @@ import {
} from "@mui/material";
import { VolunteerSession } from "@prisma/client";
import React from "react";
+import { useTranslation } from "react-i18next";
interface TimeTableProps {
volunteerSessions: VolunteerSession[];
}
export default function TimeTable({ volunteerSessions }: TimeTableProps) {
+ const { t } = useTranslation(["translation", "profile"]);
+
const [page, setPage] = React.useState(0);
const sortedSessions = [...volunteerSessions].sort((a, b) => {
@@ -60,7 +63,7 @@ export default function TimeTable({ volunteerSessions }: TimeTableProps) {
width: "255px",
}}
>
- Date
+ {t("date", { ns: "profile" })}
- Total Hours Worked
+ {t("total_hours_worked", { ns: "profile" })}
- Volunteer Session(s)
+ {t("volunteer_sessions", { ns: "profile" })}
@@ -139,7 +142,7 @@ export default function TimeTable({ volunteerSessions }: TimeTableProps) {
}}
align="left"
>
- {hoursWorked} hours
+ {hoursWorked} {t("hours", { ns: "profile" })}
- Page {page + 1} of {Math.ceil((volunteerSessions?.length || 0) / 5)}
+ {t("page", { ns: "profile" })} {page + 1} of{" "}
+ {Math.ceil((volunteerSessions?.length || 0) / 5)}
@@ -186,7 +190,7 @@ export default function TimeTable({ volunteerSessions }: TimeTableProps) {
border: "1px solid var(--Grey-300, #D0D5DD)",
}}
>
- Previous
+ {t("previous", { ns: "profile" })}
diff --git a/src/components/TopHeader.tsx b/src/components/TopHeader.tsx
index 1995d92..c104d0a 100644
--- a/src/components/TopHeader.tsx
+++ b/src/components/TopHeader.tsx
@@ -57,8 +57,8 @@ const TopHeader = ({ user }: TopHeaderProps) => {
};
const getTitle = () => {
- const pathSegments = pathname.split("/");
- return pathSegments[2].charAt(0).toUpperCase() + pathSegments[2].slice(1);
+ const pathKey = pathname.split("/")[2];
+ return t(pathKey);
};
// display form when requesting group sign up
@@ -68,16 +68,16 @@ const TopHeader = ({ user }: TopHeaderProps) => {
{pathname === "/private" ? (
-
Home
+
{t("home")}
) : pathname === "/private/events" && user.role === Role.ADMIN ? (
) : pathname === "/private/events" &&
user.role === Role.VOLUNTEER &&
@@ -95,7 +95,7 @@ const TopHeader = ({ user }: TopHeaderProps) => {
}}
>
-
Sign Up As a Group
+
{t("sign_up_group")}
{showModal && (
@@ -110,7 +110,7 @@ const TopHeader = ({ user }: TopHeaderProps) => {
>
) : (
- {getTitle() === "Organization" ? "Profile" : getTitle()}
+ {getTitle() === "Organization" ? t("profile") : getTitle()}
)}
(null);
@@ -169,7 +171,7 @@ export default function VolunteerTable({
width: "255px",
}}
>
- Name
+ {t("name", { ns: "home" })}
- Email Address
+ {t("email_address", { ns: "home" })}
{fromAttendeePage
- ? `Time(s) ${showOrganizationName ? "and Group Size" : ""}`
- : "Hours Volunteered"}
+ ? showOrganizationName
+ ? t("times_and_group_size", { ns: "home" })
+ : t("times", { ns: "home" })
+ : t("hours_volunteered", { ns: "home" })}
router.push(`/private/profile/${row.id}`)}
>
- View
+ {t("view", { ns: "home" })}
- Page {page + 1} of {Math.ceil((users?.length || 0) / 6)}
+ {t("page", { ns: "events" })} {page + 1} of{" "}
+ {Math.ceil((users?.length || 0) / 6)}
@@ -404,7 +411,7 @@ export default function VolunteerTable({
border: "1px solid var(--Grey-300, #D0D5DD)",
}}
>
- Previous
+ {t("previous", { ns: "events" })}