feat: add react-i18next bilingual support (ES/EN)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-15 01:23:52 +00:00
parent 6b5e270984
commit a77aefa440
6 changed files with 483 additions and 8 deletions

View File

@@ -15,8 +15,11 @@
"bootstrap": "^5.3.8",
"multer": "^2.0.2",
"prop-types": "^15.8.1",
"i18next": "^23.16.8",
"i18next-browser-languagedetector": "^8.0.4",
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react-i18next": "^15.4.1",
"react-hook-form": "^7.66.1",
"react-icons": "^5.5.0",
"react-router-dom": "^7.8.2",

View File

@@ -1,18 +1,16 @@
import { createContext, useState, useEffect, useContext } from "react";
import { createContext, useContext } from "react";
import { useTranslation } from "react-i18next";
export const langContext = createContext();
export const LangProvider = ({ children }) => {
const [lang, setLang] = useState("en"); // Estado para el idioma
const { i18n } = useTranslation();
const lang = i18n.language?.startsWith('es') ? 'es' : 'en';
// Ahora 'event' es el objeto de evento de React
const toggleLang = (event) => {
// Extraemos el valor de la opción seleccionada (ej: "es" o "en")
const newLang = event.target.value;
console.log("Nuevo idioma seleccionado:", newLang);
// Establecemos el estado 'lang' con el valor seleccionado
setLang(newLang);
}
i18n.changeLanguage(newLang);
};
return (
<langContext.Provider value={{ lang, toggleLang }}>

View File

@@ -0,0 +1,21 @@
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import en from './locales/en.json';
import es from './locales/es.json';
i18n
.use(LanguageDetector)
.use(initReactI18next)
.init({
resources: {
en: { translation: en },
es: { translation: es },
},
fallbackLng: 'en',
interpolation: {
escapeValue: false,
},
});
export default i18n;

View File

@@ -0,0 +1,226 @@
{
"nav": {
"dashboards": "Dashboards",
"roomDashboard": "Room Dashboard",
"reservations": "Reservations",
"guests": "Guests",
"housekeeping": "Housekeeping",
"roomService": "Room Service",
"eventsVenues": "Events & Venues",
"schedules": "Schedules",
"operationalReports": "Operational Reports",
"income": "Income",
"expenses": "Expenses",
"expensesApproval": "Expenses to be approved",
"inventory": "Inventory",
"payroll": "Payroll",
"hotel": "Hotel",
"housekeeper": "Housekeeper",
"services": "Services",
"operations": "Operations",
"staff": "Staff"
},
"common": {
"save": "Save",
"cancel": "Cancel",
"delete": "Delete",
"edit": "Edit",
"create": "Create",
"search": "Search",
"filter": "Filter",
"loading": "Loading...",
"noResults": "No results found",
"confirm": "Confirm",
"back": "Back",
"actions": "Actions",
"status": "Status",
"date": "Date",
"total": "Total",
"notes": "Notes",
"name": "Name",
"phone": "Phone",
"email": "Email",
"description": "Description",
"price": "Price",
"quantity": "Quantity",
"category": "Category",
"type": "Type",
"priority": "Priority",
"room": "Room",
"all": "All"
},
"rooms": {
"title": "Room Dashboard",
"available": "Available",
"occupied": "Occupied",
"cleaning": "Cleaning",
"maintenance": "Maintenance",
"occupancyRate": "Occupancy Rate",
"availableRooms": "Available Rooms",
"todayCheckIns": "Today's Check-ins",
"todayCheckOuts": "Today's Check-outs",
"dailyRevenue": "Daily Revenue",
"floor": "Floor",
"roomNumber": "Room Number",
"roomType": "Room Type",
"pricePerNight": "Price per Night",
"amenities": "Amenities",
"guestInfo": "Guest Information"
},
"reservations": {
"title": "Reservations",
"newReservation": "New Reservation",
"checkIn": "Check-in",
"checkOut": "Check-out",
"guestName": "Guest Name",
"roomType": "Room Type",
"channel": "Channel",
"duration": "Duration",
"nights": "nights",
"adults": "Adults",
"children": "Children",
"totalAmount": "Total Amount",
"status": {
"pending": "Pending",
"confirmed": "Confirmed",
"checkedIn": "Checked In",
"checkedOut": "Checked Out",
"cancelled": "Cancelled"
},
"channels": {
"direct": "Direct",
"booking": "Booking.com",
"expedia": "Expedia",
"airbnb": "Airbnb",
"other": "Other"
},
"actions": {
"confirm": "Confirm",
"checkIn": "Check In",
"checkOut": "Check Out",
"cancel": "Cancel"
}
},
"guests": {
"title": "Guests",
"newGuest": "New Guest",
"firstName": "First Name",
"lastName": "Last Name",
"email": "Email",
"phone": "Phone",
"idType": "ID Type",
"idNumber": "ID Number",
"nationality": "Nationality",
"address": "Address",
"stayHistory": "Stay History",
"currentRoom": "Current Room",
"totalStays": "Total Stays",
"totalSpent": "Total Spent"
},
"housekeeping": {
"title": "Housekeeping",
"pendingTasks": "Pending Tasks",
"inProgress": "In Progress",
"completedTasks": "Completed",
"assignTo": "Assign to",
"priority": {
"high": "High",
"normal": "Normal",
"low": "Low"
},
"type": {
"checkout": "Checkout",
"maintenance": "Maintenance",
"deepClean": "Deep Clean",
"turndown": "Turndown"
},
"startTask": "Start",
"completeTask": "Complete",
"staffAvailability": "Staff Availability"
},
"roomService": {
"title": "Room Service",
"activeOrders": "Active Orders",
"orderHistory": "Order History",
"newOrder": "New Order",
"menuManagement": "Menu Management",
"status": {
"pending": "Pending",
"preparing": "Preparing",
"delivering": "Delivering",
"delivered": "Delivered",
"cancelled": "Cancelled"
},
"menuItem": "Menu Item",
"price": "Price",
"quantity": "Quantity",
"category": "Category",
"addItem": "Add Item",
"orderTotal": "Order Total"
},
"events": {
"title": "Events & Venues",
"venues": "Venues",
"upcomingEvents": "Upcoming Events",
"newEvent": "New Event",
"newVenue": "New Venue",
"venueName": "Venue Name",
"capacity": "Capacity",
"area": "Area (m\u00b2)",
"pricePerHour": "Price per Hour",
"eventName": "Event Name",
"organizer": "Organizer",
"guestCount": "Guest Count",
"eventDate": "Date",
"startTime": "Start Time",
"endTime": "End Time",
"venueStatus": {
"available": "Available",
"reserved": "Reserved"
}
},
"schedules": {
"title": "Schedules",
"shifts": {
"morning": "Morning",
"afternoon": "Afternoon",
"night": "Night",
"off": "Off"
},
"shiftTimes": {
"morning": "7:00 - 15:00",
"afternoon": "15:00 - 23:00",
"night": "23:00 - 7:00"
},
"department": "Department",
"employee": "Employee",
"week": "Week",
"saveSchedule": "Save Schedule"
},
"reports": {
"title": "Operational Reports",
"occupancyRate": "Occupancy Rate",
"revenue": "Revenue",
"guestSatisfaction": "Guest Satisfaction",
"bookingSources": "Booking Sources",
"period": {
"week": "Week",
"month": "Month",
"quarter": "Quarter",
"year": "Year"
},
"vsTarget": "vs Target",
"trend": "Trend",
"revenueByRoomType": "Revenue by Room Type",
"bookingSourceDistribution": "Booking Source Distribution"
},
"auth": {
"login": "Login",
"logout": "Logout",
"email": "Email",
"password": "Password",
"forgotPassword": "Forgot Password?",
"signIn": "Sign In",
"welcome": "Welcome"
}
}

View File

@@ -0,0 +1,226 @@
{
"nav": {
"dashboards": "Tableros",
"roomDashboard": "Panel de Habitaciones",
"reservations": "Reservaciones",
"guests": "Huespedes",
"housekeeping": "Limpieza",
"roomService": "Servicio a Habitacion",
"eventsVenues": "Eventos y Salones",
"schedules": "Horarios",
"operationalReports": "Reportes Operativos",
"income": "Ingresos",
"expenses": "Gastos",
"expensesApproval": "Gastos por aprobar",
"inventory": "Inventario",
"payroll": "Nomina",
"hotel": "Hotel",
"housekeeper": "Cuidador de Habitaciones",
"services": "Servicios",
"operations": "Operaciones",
"staff": "Personal"
},
"common": {
"save": "Guardar",
"cancel": "Cancelar",
"delete": "Eliminar",
"edit": "Editar",
"create": "Crear",
"search": "Buscar",
"filter": "Filtrar",
"loading": "Cargando...",
"noResults": "Sin resultados",
"confirm": "Confirmar",
"back": "Regresar",
"actions": "Acciones",
"status": "Estado",
"date": "Fecha",
"total": "Total",
"notes": "Notas",
"name": "Nombre",
"phone": "Telefono",
"email": "Correo",
"description": "Descripcion",
"price": "Precio",
"quantity": "Cantidad",
"category": "Categoria",
"type": "Tipo",
"priority": "Prioridad",
"room": "Habitacion",
"all": "Todos"
},
"rooms": {
"title": "Panel de Habitaciones",
"available": "Disponible",
"occupied": "Ocupada",
"cleaning": "Limpieza",
"maintenance": "Mantenimiento",
"occupancyRate": "Tasa de Ocupacion",
"availableRooms": "Habitaciones Disponibles",
"todayCheckIns": "Check-ins de Hoy",
"todayCheckOuts": "Check-outs de Hoy",
"dailyRevenue": "Ingreso Diario",
"floor": "Piso",
"roomNumber": "Numero de Habitacion",
"roomType": "Tipo de Habitacion",
"pricePerNight": "Precio por Noche",
"amenities": "Amenidades",
"guestInfo": "Informacion del Huesped"
},
"reservations": {
"title": "Reservaciones",
"newReservation": "Nueva Reservacion",
"checkIn": "Entrada",
"checkOut": "Salida",
"guestName": "Nombre del Huesped",
"roomType": "Tipo de Habitacion",
"channel": "Canal",
"duration": "Duracion",
"nights": "noches",
"adults": "Adultos",
"children": "Ninos",
"totalAmount": "Monto Total",
"status": {
"pending": "Pendiente",
"confirmed": "Confirmada",
"checkedIn": "Registrado",
"checkedOut": "Check-out",
"cancelled": "Cancelada"
},
"channels": {
"direct": "Directo",
"booking": "Booking.com",
"expedia": "Expedia",
"airbnb": "Airbnb",
"other": "Otro"
},
"actions": {
"confirm": "Confirmar",
"checkIn": "Registrar Entrada",
"checkOut": "Registrar Salida",
"cancel": "Cancelar"
}
},
"guests": {
"title": "Huespedes",
"newGuest": "Nuevo Huesped",
"firstName": "Nombre",
"lastName": "Apellido",
"email": "Correo",
"phone": "Telefono",
"idType": "Tipo de ID",
"idNumber": "Numero de ID",
"nationality": "Nacionalidad",
"address": "Direccion",
"stayHistory": "Historial de Estadias",
"currentRoom": "Habitacion Actual",
"totalStays": "Total de Estadias",
"totalSpent": "Total Gastado"
},
"housekeeping": {
"title": "Limpieza",
"pendingTasks": "Tareas Pendientes",
"inProgress": "En Progreso",
"completedTasks": "Completadas",
"assignTo": "Asignar a",
"priority": {
"high": "Alta",
"normal": "Normal",
"low": "Baja"
},
"type": {
"checkout": "Check-out",
"maintenance": "Mantenimiento",
"deepClean": "Limpieza Profunda",
"turndown": "Preparacion Nocturna"
},
"startTask": "Iniciar",
"completeTask": "Completar",
"staffAvailability": "Disponibilidad del Personal"
},
"roomService": {
"title": "Servicio a Habitacion",
"activeOrders": "Ordenes Activas",
"orderHistory": "Historial de Ordenes",
"newOrder": "Nueva Orden",
"menuManagement": "Gestion del Menu",
"status": {
"pending": "Pendiente",
"preparing": "Preparando",
"delivering": "Entregando",
"delivered": "Entregado",
"cancelled": "Cancelado"
},
"menuItem": "Platillo",
"price": "Precio",
"quantity": "Cantidad",
"category": "Categoria",
"addItem": "Agregar Platillo",
"orderTotal": "Total de la Orden"
},
"events": {
"title": "Eventos y Salones",
"venues": "Salones",
"upcomingEvents": "Proximos Eventos",
"newEvent": "Nuevo Evento",
"newVenue": "Nuevo Salon",
"venueName": "Nombre del Salon",
"capacity": "Capacidad",
"area": "Area (m\u00b2)",
"pricePerHour": "Precio por Hora",
"eventName": "Nombre del Evento",
"organizer": "Organizador",
"guestCount": "Numero de Invitados",
"eventDate": "Fecha",
"startTime": "Hora de Inicio",
"endTime": "Hora de Fin",
"venueStatus": {
"available": "Disponible",
"reserved": "Reservado"
}
},
"schedules": {
"title": "Horarios",
"shifts": {
"morning": "Matutino",
"afternoon": "Vespertino",
"night": "Nocturno",
"off": "Descanso"
},
"shiftTimes": {
"morning": "7:00 - 15:00",
"afternoon": "15:00 - 23:00",
"night": "23:00 - 7:00"
},
"department": "Departamento",
"employee": "Empleado",
"week": "Semana",
"saveSchedule": "Guardar Horario"
},
"reports": {
"title": "Reportes Operativos",
"occupancyRate": "Tasa de Ocupacion",
"revenue": "Ingresos",
"guestSatisfaction": "Satisfaccion del Huesped",
"bookingSources": "Fuentes de Reservacion",
"period": {
"week": "Semana",
"month": "Mes",
"quarter": "Trimestre",
"year": "Ano"
},
"vsTarget": "vs Objetivo",
"trend": "Tendencia",
"revenueByRoomType": "Ingresos por Tipo de Habitacion",
"bookingSourceDistribution": "Distribucion de Fuentes de Reservacion"
},
"auth": {
"login": "Iniciar Sesion",
"logout": "Cerrar Sesion",
"email": "Correo",
"password": "Contrasena",
"forgotPassword": "Olvido su contrasena?",
"signIn": "Ingresar",
"welcome": "Bienvenido"
}
}

View File

@@ -1,3 +1,4 @@
import './i18n';
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";