diff --git a/backend/lang/es.json b/backend/lang/es.json index a3338aefb7..daa18cabfd 100644 --- a/backend/lang/es.json +++ b/backend/lang/es.json @@ -260,11 +260,11 @@ "Most capacity": "Mayor capacidad", "Sorry, these tickets are sold out": "Lo sentimos, estas entradas están agotadas", "The maximum number of tickets available is :max": "El número máximo de entradas disponibles es :max", - "Ticket is hidden without promo code": "El boleto está oculto sin código promocional", - "Ticket is sold out": "El boleto está agotado", - "Ticket is before sale start date": "El boleto es antes de la fecha de inicio de la venta", - "Ticket is after sale end date": "El boleto es después de la fecha de finalización de la venta", - "Ticket is hidden": "El boleto está oculto", + "Ticket is hidden without promo code": "La entrada está oculta sin código promocional", + "Ticket is sold out": "La entrada está agotada", + "Ticket is before sale start date": "La entrada es antes de la fecha de inicio de la venta", + "Ticket is after sale end date": "La entrada es después de la fecha de finalización de la venta", + "Ticket is hidden": "La entrada está oculta", "Price is before sale start date": "El precio es antes de la fecha de inicio de la venta", "Price is after sale end date": "El precio es después de la fecha de finalización de la venta", "Price is sold out": "El precio está agotado", @@ -393,16 +393,16 @@ "Order is not awaiting offline payment": "El pedido no está en espera de pago offline", "Refund already processed": "Reembolso ya procesado", "Stripe refund successful": "Reembolso de Stripe exitoso", - "There are no tickets available for this event": "No hay boletos disponibles para este evento", + "There are no tickets available for this event": "No hay entradas disponibles para este evento", "Address line 1 is required": "La dirección (línea 1) es obligatoria", "City is required": "La ciudad es obligatoria", "Zip or postal code is required": "El código postal es obligatorio", "Country is required": "El país es obligatorio", "If you did not request a password reset, please immediately reset your password.": "Si no solicitaste un restablecimiento de contraseña, por favor restablécela de inmediato.", - "ℹ️ Your order is pending payment. Tickets have been issued but will not be valid until payment is received.": "ℹ️ Tu pedido está pendiente de pago. Los boletos han sido emitidos, pero no serán válidos hasta que se reciba el pago.", + "ℹ️ Your order is pending payment. Tickets have been issued but will not be valid until payment is received.": "ℹ️ Tu pedido está pendiente de pago. Los entradas han sido emitidos, pero no serán válidos hasta que se reciba el pago.", "ℹ️ This order is pending payment. Please mark the payment as received on the order management page once payment is received.": "ℹ️ Este pedido está pendiente de pago. Por favor, márcalo como pagado en la página de gestión de pedidos una vez recibido el pago.", "Order Status:": "Estado del pedido:", - "Your order is pending payment. Tickets have been issued but will not be valid until payment is received.": "Tu pedido está pendiente de pago. Los boletos han sido emitidos, pero no serán válidos hasta que se reciba el pago.", + "Your order is pending payment. Tickets have been issued but will not be valid until payment is received.": "Tu pedido está pendiente de pago. Los entradas han sido emitidos, pero no serán válidos hasta que se reciba el pago.", "Payment Instructions": "Instrucciones de pago", "Please follow the instructions below to complete your payment.": "Por favor, sigue las instrucciones a continuación para completar tu pago.", "Invoice Number": "Número de factura", @@ -670,5 +670,42 @@ "View Event": "Ver evento", "Your waitlist offer has expired": "Tu oferta de la lista de espera ha expirado", "We'll notify you as soon as a spot becomes available.": "Te notificaremos en cuanto haya una plaza disponible.", - "You're on the waitlist!": "¡Estás en la lista de espera!" + "You're on the waitlist!": "¡Estás en la lista de espera!", + "Amount": "Importe", + "Amount Paid": "Importe pagado", + "Balance Due": "Saldo pendiente", + "Default": "Predeterminado", + "Description": "Descripción", + "Google Tag Manager is not available on hosted plans for security reasons.": "Google Tag Manager no está disponible en planes alojados por razones de seguridad.", + "Must be 6-30 alphanumeric characters": "Debe tener entre 6 y 30 caracteres alfanuméricos", + "Must be 9-20 digits (e.g., 1234567890)": "Debe tener entre 9 y 20 dígitos (p. ej., 1234567890)", + "Must start with G- followed by 6-20 characters (e.g., G-XXXXXXXXXX)": "Debe comenzar con G- seguido de 6 a 20 caracteres (p. ej., G-XXXXXXXXXX)", + "Must start with GTM- followed by 4-20 characters (e.g., GTM-XXXXXXX)": "Debe comenzar con GTM- seguido de 4 a 20 caracteres (p. ej., GTM-XXXXXXX)", + "Not enough products available. Please try again.": "No hay suficientes productos disponibles. Por favor, inténtelo de nuevo.", + "Only scheduled messages can be cancelled": "Solo se pueden cancelar los mensajes programados", + "Order Ascending": "Orden ascendente", + "Order Descending": "Orden descendente", + "Paid": "Pagado", + "Position ascending": "Posición ascendente", + "Position descending": "Posición descendente", + "Product not found for this event": "Producto no encontrado para este evento", + "Qty": "Cant.", + "Rate": "Tasa", + "The scheduled time must be in the future.": "La hora programada debe ser en el futuro.", + "The selected font is not supported.": "La fuente seleccionada no es compatible.", + "There are no waiting entries for this product": "No hay entradas en lista de espera para este producto", + "This event cannot be deleted because it has completed orders. Please cancel or refund all orders first.": "Este evento no se puede eliminar porque tiene pedidos completados. Por favor, cancele o reembolse todos los pedidos primero.", + "This event has completed orders. Please cancel or refund all orders before deleting.": "Este evento tiene pedidos completados. Por favor, cancele o reembolse todos los pedidos antes de eliminarlo.", + "This message can no longer be cancelled": "Este mensaje ya no se puede cancelar", + "This organizer has events with completed orders. Please cancel or refund all orders first.": "Este organizador tiene eventos con pedidos completados. Por favor, cancele o reembolse todos los pedidos primero.", + "This waitlist entry cannot be cancelled": "Esta entrada de la lista de espera no se puede cancelar", + "This waitlist entry cannot be offered in its current status": "Esta entrada de la lista de espera no se puede ofrecer en su estado actual", + "Unpaid": "No pagado", + "Void": "Anulado", + "Waitlist entry not found": "Entrada de lista de espera no encontrada", + "Waitlist is not enabled for this product": "La lista de espera no está habilitada para este producto", + "You are already on the waitlist for this product": "Ya estás en la lista de espera de este producto", + "You cannot archive the last active organizer on your account.": "No puedes archivar el último organizador activo de tu cuenta.", + "You cannot delete the last organizer on your account.": "No puedes eliminar el último organizador de tu cuenta.", + "You must acknowledge your data controller responsibilities before enabling tracking pixels.": "Debes reconocer tus responsabilidades como responsable del tratamiento de datos antes de habilitar los píxeles de seguimiento." } diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 88dbac4bbf..3bb5477c37 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -4,6 +4,7 @@ import {Notifications} from "@mantine/notifications"; import {i18n} from "@lingui/core"; import {I18nProvider} from "@lingui/react"; import {ModalsProvider} from "@mantine/modals"; +import {DatesProvider} from "@mantine/dates"; import {HydrationBoundary, QueryClient, QueryClientProvider} from "@tanstack/react-query"; import {Helmet, HelmetProvider} from "react-helmet-async"; import {generateColors} from '@mantine/colors-generator'; @@ -22,6 +23,7 @@ import {ThirdPartyScripts} from "./components/common/ThirdPartyScripts"; import {getConfig} from "./utilites/config.ts"; import {CookieConsentBanner} from "./components/common/CookieConsentBanner"; import {isConsentPending, setConsentState, updateGoogleConsentMode} from "./utilites/trackingPixels/consent"; +import "./utilites/dateLocales.ts"; declare global { interface Window { @@ -83,6 +85,7 @@ export const App: FC< > + @@ -103,6 +106,7 @@ export const App: FC< )} + diff --git a/frontend/src/components/common/AttendeeStatusBadge/index.tsx b/frontend/src/components/common/AttendeeStatusBadge/index.tsx index 24d1951d2c..1b39c4874f 100644 --- a/frontend/src/components/common/AttendeeStatusBadge/index.tsx +++ b/frontend/src/components/common/AttendeeStatusBadge/index.tsx @@ -1,5 +1,6 @@ import {Attendee} from "../../../types.ts"; import {Badge} from "@mantine/core"; +import {t} from "@lingui/macro"; interface AttendeeStatusBadgeProps { attendee: Attendee; @@ -22,7 +23,13 @@ export const AttendeeStatusBadge = ({attendee, noStyle = false}: AttendeeStatusB break; } - const status = attendee.status.replace('_', ' '); + const statusLabels: Record = { + 'ACTIVE': t`Active`, + 'CANCELLED': t`Cancelled`, + 'AWAITING_PAYMENT': t`Awaiting Payment`, + }; + + const status = statusLabels[attendee.status] || attendee.status.replace('_', ' '); if (noStyle) { return {status}; diff --git a/frontend/src/components/common/OrderStatusBadge/index.tsx b/frontend/src/components/common/OrderStatusBadge/index.tsx index a5d4ba4665..4688ce9535 100644 --- a/frontend/src/components/common/OrderStatusBadge/index.tsx +++ b/frontend/src/components/common/OrderStatusBadge/index.tsx @@ -3,27 +3,43 @@ import {Order} from "../../../types.ts"; import {getStatusColor} from "../../../utilites/helpers.ts"; import {t} from "@lingui/macro"; +const getStatusLabel = (status: string): string => { + const labels: Record = { + 'COMPLETED': t`Completed`, + 'CANCELLED': t`Cancelled`, + 'AWAITING_PAYMENT': t`Awaiting Payment`, + 'AWAITING_OFFLINE_PAYMENT': t`Awaiting offline payment`, + 'PAYMENT_RECEIVED': t`Payment Received`, + 'NO_PAYMENT_REQUIRED': t`No Payment Required`, + 'PAYMENT_FAILED': t`Payment Failed`, + 'REFUNDED': t`Refunded`, + 'PARTIALLY_REFUNDED': t`Partially Refunded`, + 'REFUND_PENDING': t`Refund Pending`, + }; + return labels[status] || status.replace('_', ' '); +}; + export const OrderStatusBadge = ({order, variant = 'outline'}: { order: Order, variant?: BadgeVariant }) => { let color; let title; if (order.status === 'CANCELLED') { color = getStatusColor(order.status); - title = t`Cancelled`; + title = getStatusLabel(order.status); } else if (order.status === 'AWAITING_OFFLINE_PAYMENT') { color = getStatusColor('AWAITING_PAYMENT'); - title = t`Awaiting offline payment`; + title = getStatusLabel(order.status); } else if (order.refund_status) { color = getStatusColor(order.refund_status); - title = order.refund_status; + title = getStatusLabel(order.refund_status); } else if (order.payment_status && order.payment_status !== 'PAYMENT_RECEIVED' && order.payment_status !== 'NO_PAYMENT_REQUIRED') { color = getStatusColor(order.payment_status); - title = order.payment_status; + title = getStatusLabel(order.payment_status); } else { color = getStatusColor(order.status); - title = order.status; + title = getStatusLabel(order.status); } - return {title.replace('_', ' ')} + return {title} }; diff --git a/frontend/src/components/forms/ProductCategoryForm/index.tsx b/frontend/src/components/forms/ProductCategoryForm/index.tsx index 40ca97afb4..f98325d8de 100644 --- a/frontend/src/components/forms/ProductCategoryForm/index.tsx +++ b/frontend/src/components/forms/ProductCategoryForm/index.tsx @@ -2,6 +2,7 @@ import {UseFormReturnType} from "@mantine/form"; import {ProductCategory} from "../../../types.ts"; import {Switch, TextInput} from "@mantine/core"; import {Editor} from "../../common/Editor"; +import {t} from "@lingui/macro"; interface ProductCategoryFormProps { form: UseFormReturnType, @@ -11,30 +12,30 @@ export const ProductCategoryForm = ({form}: ProductCategoryFormProps) => { return ( <> form.setFieldValue("description", value)} value={form.values.description || ""} maxLength={5000} />