From a80b35a8061e43d4e96c396fb31ecc2d77e4a706 Mon Sep 17 00:00:00 2001 From: poduck Date: Wed, 17 Dec 2025 00:49:48 -0500 Subject: [PATCH] Add dashboard and navigation translations with date-fns locale support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add translations for all dashboard widgets (de, es, fr) - Add navigation menu translations for all languages - Create useDateFnsLocale hook for localized date formatting - Add translate="no" to prevent browser auto-translation - Update dashboard components to use translation keys 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- frontend/index.html | 3 +- .../components/dashboard/CapacityWidget.tsx | 2 +- .../dashboard/CustomerBreakdownWidget.tsx | 12 +-- .../dashboard/OpenTicketsWidget.tsx | 14 +-- .../dashboard/RecentActivityWidget.tsx | 22 ++--- .../dashboard/WidgetConfigModal.tsx | 16 ++-- frontend/src/components/dashboard/types.ts | 34 +++++++ frontend/src/hooks/useDateFnsLocale.ts | 30 +++++++ frontend/src/i18n/locales/de.json | 88 ++++++++++++++++++- frontend/src/i18n/locales/en.json | 58 +++++++++++- frontend/src/i18n/locales/es.json | 88 ++++++++++++++++++- frontend/src/i18n/locales/fr.json | 88 ++++++++++++++++++- frontend/src/pages/Dashboard.tsx | 6 +- 13 files changed, 420 insertions(+), 41 deletions(-) create mode 100644 frontend/src/hooks/useDateFnsLocale.ts diff --git a/frontend/index.html b/frontend/index.html index 86d15b95..42047f8c 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -1,7 +1,8 @@ - + + diff --git a/frontend/src/components/dashboard/CapacityWidget.tsx b/frontend/src/components/dashboard/CapacityWidget.tsx index 067e4c93..4109dd8d 100644 --- a/frontend/src/components/dashboard/CapacityWidget.tsx +++ b/frontend/src/components/dashboard/CapacityWidget.tsx @@ -92,7 +92,7 @@ const CapacityWidget: React.FC = ({

- Capacity This Week + {t('dashboard.capacityThisWeek')}

diff --git a/frontend/src/components/dashboard/CustomerBreakdownWidget.tsx b/frontend/src/components/dashboard/CustomerBreakdownWidget.tsx index 2ed9f6bc..c13087f8 100644 --- a/frontend/src/components/dashboard/CustomerBreakdownWidget.tsx +++ b/frontend/src/components/dashboard/CustomerBreakdownWidget.tsx @@ -32,11 +32,11 @@ const CustomerBreakdownWidget: React.FC = ({ newPercentage: total > 0 ? Math.round((newCustomers / total) * 100) : 0, returningPercentage: total > 0 ? Math.round((returning / total) * 100) : 0, chartData: [ - { name: 'New', value: newCustomers, color: '#8b5cf6' }, - { name: 'Returning', value: returning, color: '#10b981' }, + { name: t('dashboard.new'), value: newCustomers, color: '#8b5cf6' }, + { name: t('dashboard.returning'), value: returning, color: '#10b981' }, ], }; - }, [customers]); + }, [customers, t]); return (
@@ -55,7 +55,7 @@ const CustomerBreakdownWidget: React.FC = ({ )}

- Customers This Month + {t('dashboard.customersThisMonth')}

@@ -88,7 +88,7 @@ const CustomerBreakdownWidget: React.FC = ({
-

New

+

{t('dashboard.new')}

{breakdownData.new}{' '} @@ -103,7 +103,7 @@ const CustomerBreakdownWidget: React.FC = ({

-

Returning

+

{t('dashboard.returning')}

{breakdownData.returning}{' '} diff --git a/frontend/src/components/dashboard/OpenTicketsWidget.tsx b/frontend/src/components/dashboard/OpenTicketsWidget.tsx index 788f43fe..a0061080 100644 --- a/frontend/src/components/dashboard/OpenTicketsWidget.tsx +++ b/frontend/src/components/dashboard/OpenTicketsWidget.tsx @@ -4,6 +4,7 @@ import { Link } from 'react-router-dom'; import { GripVertical, X, AlertCircle, Clock, ChevronRight } from 'lucide-react'; import { Ticket } from '../../types'; import { formatDistanceToNow } from 'date-fns'; +import { useDateFnsLocale } from '../../hooks/useDateFnsLocale'; interface OpenTicketsWidgetProps { tickets: Ticket[]; @@ -17,6 +18,7 @@ const OpenTicketsWidget: React.FC = ({ onRemove, }) => { const { t } = useTranslation(); + const dateFnsLocale = useDateFnsLocale(); const openTickets = tickets.filter(ticket => ticket.status === 'open' || ticket.status === 'in_progress'); const urgentCount = openTickets.filter(t => t.priority === 'urgent' || t.isOverdue).length; @@ -58,17 +60,17 @@ const OpenTicketsWidget: React.FC = ({

- Open Tickets + {t('dashboard.openTickets')}

{urgentCount > 0 && ( - {urgentCount} urgent + {urgentCount} {t('dashboard.urgent')} )} - {openTickets.length} open + {openTickets.length} {t('dashboard.open')}
@@ -93,11 +95,11 @@ const OpenTicketsWidget: React.FC = ({

- {ticket.isOverdue ? 'Overdue' : ticket.priority} + {ticket.isOverdue ? t('dashboard.overdue') : ticket.priority} - {formatDistanceToNow(new Date(ticket.createdAt), { addSuffix: true })} + {formatDistanceToNow(new Date(ticket.createdAt), { addSuffix: true, locale: dateFnsLocale })}
@@ -113,7 +115,7 @@ const OpenTicketsWidget: React.FC = ({ to="/dashboard/tickets" className="mt-3 text-sm text-brand-600 dark:text-brand-400 hover:underline text-center" > - View all {openTickets.length} tickets + {t('dashboard.viewAllTickets', { count: openTickets.length })} )}
diff --git a/frontend/src/components/dashboard/RecentActivityWidget.tsx b/frontend/src/components/dashboard/RecentActivityWidget.tsx index e8b6e8d2..0a0aa8d7 100644 --- a/frontend/src/components/dashboard/RecentActivityWidget.tsx +++ b/frontend/src/components/dashboard/RecentActivityWidget.tsx @@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next'; import { GripVertical, X, Calendar, UserPlus, XCircle, CheckCircle, DollarSign } from 'lucide-react'; import { formatDistanceToNow } from 'date-fns'; import { Appointment, Customer } from '../../types'; +import { useDateFnsLocale } from '../../hooks/useDateFnsLocale'; interface ActivityItem { id: string; @@ -28,6 +29,7 @@ const RecentActivityWidget: React.FC = ({ onRemove, }) => { const { t } = useTranslation(); + const dateFnsLocale = useDateFnsLocale(); const activities = useMemo(() => { const items: ActivityItem[] = []; @@ -39,8 +41,8 @@ const RecentActivityWidget: React.FC = ({ items.push({ id: `booking-${appt.id}`, type: 'booking', - title: 'New Booking', - description: `${appt.customerName} booked an appointment`, + title: t('dashboard.newBooking'), + description: t('dashboard.customerBookedAppointment', { customerName: appt.customerName }), timestamp, icon: , iconBg: 'bg-blue-100 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400', @@ -49,8 +51,8 @@ const RecentActivityWidget: React.FC = ({ items.push({ id: `cancel-${appt.id}`, type: 'cancellation', - title: 'Cancellation', - description: `${appt.customerName} cancelled their appointment`, + title: t('dashboard.cancellation'), + description: t('dashboard.customerCancelledAppointment', { customerName: appt.customerName }), timestamp, icon: , iconBg: 'bg-red-100 dark:bg-red-900/30 text-red-600 dark:text-red-400', @@ -59,8 +61,8 @@ const RecentActivityWidget: React.FC = ({ items.push({ id: `complete-${appt.id}`, type: 'completion', - title: 'Completed', - description: `${appt.customerName}'s appointment completed`, + title: t('dashboard.completed'), + description: t('dashboard.customerAppointmentCompleted', { customerName: appt.customerName }), timestamp, icon: , iconBg: 'bg-green-100 dark:bg-green-900/30 text-green-600 dark:text-green-400', @@ -76,8 +78,8 @@ const RecentActivityWidget: React.FC = ({ items.push({ id: `customer-${customer.id}`, type: 'new_customer', - title: 'New Customer', - description: `${customer.name} signed up`, + title: t('dashboard.newCustomer'), + description: t('dashboard.customerSignedUp', { customerName: customer.name }), timestamp: new Date(), // Approximate - would need createdAt field icon: , iconBg: 'bg-purple-100 dark:bg-purple-900/30 text-purple-600 dark:text-purple-400', @@ -107,7 +109,7 @@ const RecentActivityWidget: React.FC = ({ )}

- Recent Activity + {t('dashboard.recentActivity')}

@@ -131,7 +133,7 @@ const RecentActivityWidget: React.FC = ({ {activity.description}

- {formatDistanceToNow(activity.timestamp, { addSuffix: true })} + {formatDistanceToNow(activity.timestamp, { addSuffix: true, locale: dateFnsLocale })}

diff --git a/frontend/src/components/dashboard/WidgetConfigModal.tsx b/frontend/src/components/dashboard/WidgetConfigModal.tsx index f4e5957a..7e02b347 100644 --- a/frontend/src/components/dashboard/WidgetConfigModal.tsx +++ b/frontend/src/components/dashboard/WidgetConfigModal.tsx @@ -1,6 +1,7 @@ import React from 'react'; +import { useTranslation } from 'react-i18next'; import { X, Plus, Check, LayoutDashboard, BarChart2, Ticket, Activity, Users, UserX, PieChart } from 'lucide-react'; -import { WIDGET_DEFINITIONS, WidgetType } from './types'; +import { WIDGET_DEFINITIONS, WidgetType, getWidgetTitle, getWidgetDescription } from './types'; interface WidgetConfigModalProps { isOpen: boolean; @@ -31,6 +32,7 @@ const WidgetConfigModal: React.FC = ({ onToggleWidget, onResetLayout, }) => { + const { t } = useTranslation(); if (!isOpen) return null; const widgets = Object.values(WIDGET_DEFINITIONS); @@ -45,7 +47,7 @@ const WidgetConfigModal: React.FC = ({ {/* Header */}

- Configure Dashboard Widgets + {t('dashboard.configureWidgets')}

@@ -114,13 +116,13 @@ const WidgetConfigModal: React.FC = ({ onClick={onResetLayout} className="text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300" > - Reset to Default + {t('dashboard.resetToDefault')}
diff --git a/frontend/src/components/dashboard/types.ts b/frontend/src/components/dashboard/types.ts index e5a37939..fb478634 100644 --- a/frontend/src/components/dashboard/types.ts +++ b/frontend/src/components/dashboard/types.ts @@ -1,4 +1,5 @@ import { Layout } from 'react-grid-layout'; +import { TFunction } from 'i18next'; export type WidgetType = | 'appointments-metric' @@ -119,6 +120,39 @@ export const WIDGET_DEFINITIONS: Record = { }, }; +// Widget ID to translation key mapping +const WIDGET_TRANSLATION_KEYS: Record = { + 'appointments-metric': 'appointmentsMetric', + 'customers-metric': 'customersMetric', + 'services-metric': 'servicesMetric', + 'resources-metric': 'resourcesMetric', + 'revenue-chart': 'revenueChart', + 'appointments-chart': 'appointmentsChart', + 'open-tickets': 'openTickets', + 'recent-activity': 'recentActivity', + 'capacity-utilization': 'capacityUtilization', + 'no-show-rate': 'noShowRate', + 'customer-breakdown': 'customerBreakdown', +}; + +// Helper function to get translated widget title +export const getWidgetTitle = (widgetId: string, t: TFunction): string => { + const key = WIDGET_TRANSLATION_KEYS[widgetId as WidgetType]; + if (key) { + return t(`dashboard.widgetTitles.${key}`); + } + return WIDGET_DEFINITIONS[widgetId as WidgetType]?.title || widgetId; +}; + +// Helper function to get translated widget description +export const getWidgetDescription = (widgetId: string, t: TFunction): string => { + const key = WIDGET_TRANSLATION_KEYS[widgetId as WidgetType]; + if (key) { + return t(`dashboard.widgetDescriptions.${key}`); + } + return WIDGET_DEFINITIONS[widgetId as WidgetType]?.description || ''; +}; + // Default layout for new users export const DEFAULT_LAYOUT: DashboardLayout = { widgets: [ diff --git a/frontend/src/hooks/useDateFnsLocale.ts b/frontend/src/hooks/useDateFnsLocale.ts new file mode 100644 index 00000000..9beae55f --- /dev/null +++ b/frontend/src/hooks/useDateFnsLocale.ts @@ -0,0 +1,30 @@ +import { useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Locale } from 'date-fns'; +import { enUS, de, es, fr } from 'date-fns/locale'; + +const localeMap: Record = { + en: enUS, + de: de, + es: es, + fr: fr, +}; + +/** + * Hook to get the date-fns locale based on the current i18n language. + * Use this with date-fns functions that support locale, like formatDistanceToNow. + * + * @example + * const locale = useDateFnsLocale(); + * formatDistanceToNow(date, { addSuffix: true, locale }); + */ +export const useDateFnsLocale = (): Locale => { + const { i18n } = useTranslation(); + + return useMemo(() => { + const lang = i18n.language?.split('-')[0] || 'en'; + return localeMap[lang] || enUS; + }, [i18n.language]); +}; + +export default useDateFnsLocale; diff --git a/frontend/src/i18n/locales/de.json b/frontend/src/i18n/locales/de.json index 33145770..14d998db 100644 --- a/frontend/src/i18n/locales/de.json +++ b/frontend/src/i18n/locales/de.json @@ -50,10 +50,12 @@ "nav": { "dashboard": "Dashboard", "scheduler": "Terminplaner", + "tasks": "Aufgaben", "customers": "Kunden", "resources": "Ressourcen", "services": "Dienstleistungen", "payments": "Zahlungen", + "paymentsDisabledTooltip": "Zahlungen sind deaktiviert. Aktivieren Sie sie in den Geschäftseinstellungen, um Zahlungen von Kunden zu akzeptieren.", "messages": "Nachrichten", "staff": "Personal", "businessSettings": "Geschäftseinstellungen", @@ -65,9 +67,31 @@ "platformSettings": "Plattform-Einstellungen", "tickets": "Tickets", "help": "Hilfe", + "contracts": "Verträge", + "locations": "Standorte", "platformGuide": "Plattform-Handbuch", "ticketingHelp": "Ticket-System", - "apiDocs": "API-Dokumentation" + "apiDocs": "API-Dokumentation", + "automationDocs": "Automatisierungs-Dokumentation", + "contactSupport": "Support kontaktieren", + "automations": "Automatisierungen", + "automationMarketplace": "Marktplatz", + "myAutomations": "Meine Automatisierungen", + "expandSidebar": "Seitenleiste erweitern", + "collapseSidebar": "Seitenleiste einklappen", + "smoothSchedule": "Smooth Schedule", + "gallery": "Mediengalerie", + "siteBuilder": "Website-Baukasten", + "mySchedule": "Mein Zeitplan", + "myAvailability": "Meine Verfügbarkeit", + "timeBlocks": "Zeitblöcke", + "helpDocs": "Hilfe & Dokumentation", + "sections": { + "manage": "Verwalten", + "communicate": "Kommunizieren", + "money": "Finanzen", + "extend": "Erweitern" + } }, "help": { "guide": { @@ -769,7 +793,67 @@ "totalRevenue": "Gesamtumsatz", "totalAppointments": "Termine Gesamt", "newCustomers": "Neue Kunden", - "pendingPayments": "Ausstehende Zahlungen" + "pendingPayments": "Ausstehende Zahlungen", + "noResourcesConfigured": "Keine Ressourcen konfiguriert", + "noRecentActivity": "Keine aktuellen Aktivitäten", + "noOpenTickets": "Keine offenen Tickets", + "totalCustomers": "Kunden gesamt", + "noShowRate": "No-Show-Quote", + "thisMonth": "diesen Monat", + "week": "Woche", + "month": "Monat", + "weekLabel": "Woche:", + "monthLabel": "Monat:", + "done": "Fertig", + "editLayout": "Layout bearbeiten", + "widgets": "Widgets", + "editModeHint": "Ziehen Sie Widgets, um sie neu zu positionieren. Ziehen Sie die Ecke, um die Größe zu ändern. Fahren Sie mit der Maus über ein Widget und klicken Sie auf X, um es zu entfernen.", + "configureWidgets": "Dashboard-Widgets konfigurieren", + "configureWidgetsDescription": "Wählen Sie, welche Widgets auf Ihrem Dashboard angezeigt werden sollen. Sie können Widgets ziehen, um sie neu zu positionieren.", + "resetToDefault": "Auf Standard zurücksetzen", + "openTickets": "Offene Tickets", + "urgent": "dringend", + "open": "offen", + "overdue": "Überfällig", + "viewAllTickets": "Alle {{count}} Tickets anzeigen", + "newBooking": "Neue Buchung", + "customerBookedAppointment": "{{customerName}} hat einen Termin gebucht", + "cancellation": "Stornierung", + "customerCancelledAppointment": "{{customerName}} hat seinen Termin storniert", + "completed": "Abgeschlossen", + "customerAppointmentCompleted": "{{customerName}}s Termin wurde abgeschlossen", + "newCustomer": "Neuer Kunde", + "customerSignedUp": "{{customerName}} hat sich registriert", + "capacityThisWeek": "Kapazität diese Woche", + "customersThisMonth": "Kunden diesen Monat", + "new": "Neu", + "returning": "Wiederkehrend", + "widgetTitles": { + "appointmentsMetric": "Termine gesamt", + "customersMetric": "Aktive Kunden", + "servicesMetric": "Dienstleistungen", + "resourcesMetric": "Ressourcen", + "revenueChart": "Umsatz", + "appointmentsChart": "Termintrend", + "openTickets": "Offene Tickets", + "recentActivity": "Letzte Aktivitäten", + "capacityUtilization": "Kapazitätsauslastung", + "noShowRate": "No-Show-Quote", + "customerBreakdown": "Neu vs. Wiederkehrend" + }, + "widgetDescriptions": { + "appointmentsMetric": "Zeigt die Terminanzahl mit wöchentlichem und monatlichem Wachstum", + "customersMetric": "Zeigt die Kundenanzahl mit wöchentlichem und monatlichem Wachstum", + "servicesMetric": "Zeigt die Anzahl der angebotenen Dienstleistungen", + "resourcesMetric": "Zeigt die Anzahl der verfügbaren Ressourcen", + "revenueChart": "Wöchentliches Umsatz-Balkendiagramm", + "appointmentsChart": "Wöchentliches Termin-Liniendiagramm", + "openTickets": "Zeigt offene Support-Tickets, die Aufmerksamkeit erfordern", + "recentActivity": "Zeitachse der letzten Geschäftsereignisse", + "capacityUtilization": "Zeigt, wie ausgebucht Ihre Ressourcen diese Woche sind", + "noShowRate": "Prozentsatz der als No-Show markierten Termine", + "customerBreakdown": "Kundenaufteilung diesen Monat" + } }, "scheduler": { "title": "Terminplaner", diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index c699a503..fe824361 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -132,6 +132,12 @@ "expandSidebar": "Expand sidebar", "collapseSidebar": "Collapse sidebar", "smoothSchedule": "Smooth Schedule", + "gallery": "Media Gallery", + "siteBuilder": "Site Builder", + "mySchedule": "My Schedule", + "myAvailability": "My Availability", + "timeBlocks": "Time Blocks", + "helpDocs": "Help & Docs", "sections": { "manage": "Manage", "communicate": "Communicate", @@ -1322,7 +1328,57 @@ "week": "Week", "month": "Month", "weekLabel": "Week:", - "monthLabel": "Month:" + "monthLabel": "Month:", + "done": "Done", + "editLayout": "Edit Layout", + "widgets": "Widgets", + "editModeHint": "Drag widgets to reposition them. Drag the corner to resize. Hover over a widget and click the X to remove it.", + "configureWidgets": "Configure Dashboard Widgets", + "configureWidgetsDescription": "Select which widgets to show on your dashboard. You can drag widgets to reposition them.", + "resetToDefault": "Reset to Default", + "openTickets": "Open Tickets", + "urgent": "urgent", + "open": "open", + "overdue": "Overdue", + "viewAllTickets": "View all {{count}} tickets", + "newBooking": "New Booking", + "customerBookedAppointment": "{{customerName}} booked an appointment", + "cancellation": "Cancellation", + "customerCancelledAppointment": "{{customerName}} cancelled their appointment", + "completed": "Completed", + "customerAppointmentCompleted": "{{customerName}}'s appointment completed", + "newCustomer": "New Customer", + "customerSignedUp": "{{customerName}} signed up", + "capacityThisWeek": "Capacity This Week", + "customersThisMonth": "Customers This Month", + "new": "New", + "returning": "Returning", + "widgetTitles": { + "appointmentsMetric": "Total Appointments", + "customersMetric": "Active Customers", + "servicesMetric": "Services", + "resourcesMetric": "Resources", + "revenueChart": "Revenue", + "appointmentsChart": "Appointments Trend", + "openTickets": "Open Tickets", + "recentActivity": "Recent Activity", + "capacityUtilization": "Capacity Utilization", + "noShowRate": "No-Show Rate", + "customerBreakdown": "New vs Returning" + }, + "widgetDescriptions": { + "appointmentsMetric": "Shows appointment count with weekly and monthly growth", + "customersMetric": "Shows customer count with weekly and monthly growth", + "servicesMetric": "Shows number of services offered", + "resourcesMetric": "Shows number of resources available", + "revenueChart": "Weekly revenue bar chart", + "appointmentsChart": "Weekly appointments line chart", + "openTickets": "Shows open support tickets requiring attention", + "recentActivity": "Timeline of recent business events", + "capacityUtilization": "Shows how booked your resources are this week", + "noShowRate": "Percentage of appointments marked as no-show", + "customerBreakdown": "Customer breakdown this month" + } }, "scheduler": { "title": "Scheduler", diff --git a/frontend/src/i18n/locales/es.json b/frontend/src/i18n/locales/es.json index 9ed18540..1d7ff137 100644 --- a/frontend/src/i18n/locales/es.json +++ b/frontend/src/i18n/locales/es.json @@ -50,10 +50,12 @@ "nav": { "dashboard": "Panel", "scheduler": "Agenda", + "tasks": "Tareas", "customers": "Clientes", "resources": "Recursos", "services": "Servicios", "payments": "Pagos", + "paymentsDisabledTooltip": "Los pagos están desactivados. Actívalos en Configuración del Negocio para aceptar pagos de los clientes.", "messages": "Mensajes", "staff": "Personal", "businessSettings": "Configuración del Negocio", @@ -65,9 +67,31 @@ "platformSettings": "Configuración de Plataforma", "tickets": "Tickets", "help": "Ayuda", + "contracts": "Contratos", + "locations": "Ubicaciones", "platformGuide": "Guía de Plataforma", "ticketingHelp": "Sistema de Tickets", - "apiDocs": "Documentación API" + "apiDocs": "Documentación API", + "automationDocs": "Documentación de Automatización", + "contactSupport": "Contactar Soporte", + "automations": "Automatizaciones", + "automationMarketplace": "Mercado", + "myAutomations": "Mis Automatizaciones", + "expandSidebar": "Expandir barra lateral", + "collapseSidebar": "Contraer barra lateral", + "smoothSchedule": "Smooth Schedule", + "gallery": "Galería de Medios", + "siteBuilder": "Constructor de Sitio", + "mySchedule": "Mi Agenda", + "myAvailability": "Mi Disponibilidad", + "timeBlocks": "Bloques de Tiempo", + "helpDocs": "Ayuda y Documentación", + "sections": { + "manage": "Gestionar", + "communicate": "Comunicar", + "money": "Dinero", + "extend": "Extender" + } }, "help": { "guide": { @@ -829,7 +853,67 @@ "totalRevenue": "Ingresos Totales", "totalAppointments": "Citas Totales", "newCustomers": "Nuevos Clientes", - "pendingPayments": "Pagos Pendientes" + "pendingPayments": "Pagos Pendientes", + "noResourcesConfigured": "No hay recursos configurados", + "noRecentActivity": "Sin actividad reciente", + "noOpenTickets": "No hay tickets abiertos", + "totalCustomers": "Clientes totales", + "noShowRate": "Tasa de no-show", + "thisMonth": "este mes", + "week": "Semana", + "month": "Mes", + "weekLabel": "Semana:", + "monthLabel": "Mes:", + "done": "Listo", + "editLayout": "Editar diseño", + "widgets": "Widgets", + "editModeHint": "Arrastra los widgets para reposicionarlos. Arrastra la esquina para cambiar el tamaño. Pasa el cursor sobre un widget y haz clic en X para eliminarlo.", + "configureWidgets": "Configurar widgets del panel", + "configureWidgetsDescription": "Selecciona qué widgets mostrar en tu panel. Puedes arrastrar los widgets para reposicionarlos.", + "resetToDefault": "Restablecer valores predeterminados", + "openTickets": "Tickets abiertos", + "urgent": "urgente", + "open": "abierto", + "overdue": "Vencido", + "viewAllTickets": "Ver todos los {{count}} tickets", + "newBooking": "Nueva reserva", + "customerBookedAppointment": "{{customerName}} reservó una cita", + "cancellation": "Cancelación", + "customerCancelledAppointment": "{{customerName}} canceló su cita", + "completed": "Completado", + "customerAppointmentCompleted": "La cita de {{customerName}} se completó", + "newCustomer": "Nuevo cliente", + "customerSignedUp": "{{customerName}} se registró", + "capacityThisWeek": "Capacidad esta semana", + "customersThisMonth": "Clientes este mes", + "new": "Nuevo", + "returning": "Recurrente", + "widgetTitles": { + "appointmentsMetric": "Total de citas", + "customersMetric": "Clientes activos", + "servicesMetric": "Servicios", + "resourcesMetric": "Recursos", + "revenueChart": "Ingresos", + "appointmentsChart": "Tendencia de citas", + "openTickets": "Tickets abiertos", + "recentActivity": "Actividad reciente", + "capacityUtilization": "Utilización de capacidad", + "noShowRate": "Tasa de no-show", + "customerBreakdown": "Nuevos vs. Recurrentes" + }, + "widgetDescriptions": { + "appointmentsMetric": "Muestra el recuento de citas con crecimiento semanal y mensual", + "customersMetric": "Muestra el recuento de clientes con crecimiento semanal y mensual", + "servicesMetric": "Muestra el número de servicios ofrecidos", + "resourcesMetric": "Muestra el número de recursos disponibles", + "revenueChart": "Gráfico de barras de ingresos semanales", + "appointmentsChart": "Gráfico de líneas de citas semanales", + "openTickets": "Muestra tickets de soporte abiertos que requieren atención", + "recentActivity": "Línea de tiempo de eventos comerciales recientes", + "capacityUtilization": "Muestra qué tan ocupados están tus recursos esta semana", + "noShowRate": "Porcentaje de citas marcadas como no-show", + "customerBreakdown": "Desglose de clientes este mes" + } }, "scheduler": { "title": "Agenda", diff --git a/frontend/src/i18n/locales/fr.json b/frontend/src/i18n/locales/fr.json index b3cdf472..aaffe573 100644 --- a/frontend/src/i18n/locales/fr.json +++ b/frontend/src/i18n/locales/fr.json @@ -50,10 +50,12 @@ "nav": { "dashboard": "Tableau de Bord", "scheduler": "Planificateur", + "tasks": "Tâches", "customers": "Clients", "resources": "Ressources", "services": "Services", "payments": "Paiements", + "paymentsDisabledTooltip": "Les paiements sont désactivés. Activez-les dans les Paramètres de l'Entreprise pour accepter les paiements des clients.", "messages": "Messages", "staff": "Personnel", "businessSettings": "Paramètres de l'Entreprise", @@ -65,9 +67,31 @@ "platformSettings": "Paramètres Plateforme", "tickets": "Tickets", "help": "Aide", + "contracts": "Contrats", + "locations": "Emplacements", "platformGuide": "Guide de la Plateforme", "ticketingHelp": "Système de Tickets", - "apiDocs": "Documentation API" + "apiDocs": "Documentation API", + "automationDocs": "Documentation des Automations", + "contactSupport": "Contacter le Support", + "automations": "Automations", + "automationMarketplace": "Marché", + "myAutomations": "Mes Automations", + "expandSidebar": "Développer la barre latérale", + "collapseSidebar": "Réduire la barre latérale", + "smoothSchedule": "Smooth Schedule", + "gallery": "Galerie Multimédia", + "siteBuilder": "Constructeur de Site", + "mySchedule": "Mon Emploi du Temps", + "myAvailability": "Ma Disponibilité", + "timeBlocks": "Blocs de Temps", + "helpDocs": "Aide & Documentation", + "sections": { + "manage": "Gérer", + "communicate": "Communiquer", + "money": "Argent", + "extend": "Étendre" + } }, "help": { "guide": { @@ -769,7 +793,67 @@ "totalRevenue": "Revenus Totaux", "totalAppointments": "Total des Rendez-vous", "newCustomers": "Nouveaux Clients", - "pendingPayments": "Paiements en Attente" + "pendingPayments": "Paiements en Attente", + "noResourcesConfigured": "Aucune ressource configurée", + "noRecentActivity": "Aucune activité récente", + "noOpenTickets": "Aucun ticket ouvert", + "totalCustomers": "Clients totaux", + "noShowRate": "Taux de no-show", + "thisMonth": "ce mois-ci", + "week": "Semaine", + "month": "Mois", + "weekLabel": "Semaine :", + "monthLabel": "Mois :", + "done": "Terminé", + "editLayout": "Modifier la disposition", + "widgets": "Widgets", + "editModeHint": "Faites glisser les widgets pour les repositionner. Faites glisser le coin pour redimensionner. Survolez un widget et cliquez sur X pour le supprimer.", + "configureWidgets": "Configurer les widgets du tableau de bord", + "configureWidgetsDescription": "Sélectionnez les widgets à afficher sur votre tableau de bord. Vous pouvez faire glisser les widgets pour les repositionner.", + "resetToDefault": "Réinitialiser par défaut", + "openTickets": "Tickets ouverts", + "urgent": "urgent", + "open": "ouvert", + "overdue": "En retard", + "viewAllTickets": "Voir tous les {{count}} tickets", + "newBooking": "Nouvelle réservation", + "customerBookedAppointment": "{{customerName}} a réservé un rendez-vous", + "cancellation": "Annulation", + "customerCancelledAppointment": "{{customerName}} a annulé son rendez-vous", + "completed": "Terminé", + "customerAppointmentCompleted": "Le rendez-vous de {{customerName}} est terminé", + "newCustomer": "Nouveau client", + "customerSignedUp": "{{customerName}} s'est inscrit", + "capacityThisWeek": "Capacité cette semaine", + "customersThisMonth": "Clients ce mois-ci", + "new": "Nouveau", + "returning": "Récurrent", + "widgetTitles": { + "appointmentsMetric": "Total des rendez-vous", + "customersMetric": "Clients actifs", + "servicesMetric": "Services", + "resourcesMetric": "Ressources", + "revenueChart": "Revenus", + "appointmentsChart": "Tendance des rendez-vous", + "openTickets": "Tickets ouverts", + "recentActivity": "Activité récente", + "capacityUtilization": "Utilisation de la capacité", + "noShowRate": "Taux de no-show", + "customerBreakdown": "Nouveaux vs. Récurrents" + }, + "widgetDescriptions": { + "appointmentsMetric": "Affiche le nombre de rendez-vous avec la croissance hebdomadaire et mensuelle", + "customersMetric": "Affiche le nombre de clients avec la croissance hebdomadaire et mensuelle", + "servicesMetric": "Affiche le nombre de services proposés", + "resourcesMetric": "Affiche le nombre de ressources disponibles", + "revenueChart": "Graphique à barres des revenus hebdomadaires", + "appointmentsChart": "Graphique linéaire des rendez-vous hebdomadaires", + "openTickets": "Affiche les tickets de support ouverts nécessitant une attention", + "recentActivity": "Chronologie des événements commerciaux récents", + "capacityUtilization": "Affiche le taux de réservation de vos ressources cette semaine", + "noShowRate": "Pourcentage de rendez-vous marqués comme no-show", + "customerBreakdown": "Répartition des clients ce mois-ci" + } }, "scheduler": { "title": "Planificateur", diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx index db97457a..489c5004 100644 --- a/frontend/src/pages/Dashboard.tsx +++ b/frontend/src/pages/Dashboard.tsx @@ -385,14 +385,14 @@ const Dashboard: React.FC = () => { }`} > {isEditing ? : } - {isEditing ? 'Done' : 'Edit Layout'} + {isEditing ? t('dashboard.done') : t('dashboard.editLayout')} @@ -400,7 +400,7 @@ const Dashboard: React.FC = () => { {/* Edit mode hint */} {isEditing && (
- Drag widgets to reposition them. Drag the corner to resize. Hover over a widget and click the X to remove it. + {t('dashboard.editModeHint')}
)}