diff --git a/backend/app/DomainObjects/MessageDomainObject.php b/backend/app/DomainObjects/MessageDomainObject.php index 50f1893d..00036f3b 100644 --- a/backend/app/DomainObjects/MessageDomainObject.php +++ b/backend/app/DomainObjects/MessageDomainObject.php @@ -25,12 +25,12 @@ public static function getAllowedSorts(): AllowedSorts return new AllowedSorts( [ self::CREATED_AT => [ - 'asc' => 'Sent Date Oldest', - 'desc' => 'Sent Date Newest', + 'asc' => __('Sent Date Oldest'), + 'desc' => __('Sent Date Newest'), ], self::SUBJECT => [ - 'asc' => 'Subject A-Z', - 'desc' => 'Subject Z-A', + 'asc' => __('Subject A-Z'), + 'desc' => __('Subject Z-A'), ], ], ); diff --git a/backend/app/Http/Middleware/SetUserLocaleMiddleware.php b/backend/app/Http/Middleware/SetUserLocaleMiddleware.php index b8b3a2f7..4fc4b50a 100644 --- a/backend/app/Http/Middleware/SetUserLocaleMiddleware.php +++ b/backend/app/Http/Middleware/SetUserLocaleMiddleware.php @@ -4,12 +4,17 @@ use Closure; use HiEvents\DomainObjects\UserDomainObject; +use HiEvents\Services\Application\Locale\LocaleService; use Illuminate\Http\Request; use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Auth; class SetUserLocaleMiddleware { + public function __construct(private readonly LocaleService $localeService) + { + } + public function handle(Request $request, Closure $next) { $this->setLocale($request); @@ -34,7 +39,7 @@ protected function setLocale(Request $request): void protected function setLocaleFromCookie(Request $request): bool { if ($locale = $request->cookie('locale')) { - App::setLocale($locale); + App::setLocale($this->localeService->getLocaleOrDefault($locale)); return true; } @@ -56,7 +61,7 @@ protected function setLocaleFromUser(): bool protected function setLocaleFromAcceptLanguage(Request $request): bool { if ($request->hasHeader('Accept-Language')) { - App::setLocale($request->header('Accept-Language')); + App::setLocale($this->localeService->getLocaleOrDefault($request->getPreferredLanguage())); return true; } diff --git a/backend/lang/de.json b/backend/lang/de.json index eda84fab..06a6978e 100644 --- a/backend/lang/de.json +++ b/backend/lang/de.json @@ -245,5 +245,9 @@ "To accept the invitation, please click the link below:": "Um die Einladung anzunehmen, klicken Sie bitte auf den unten stehenden Link:", "Accept Invitation": "Einladung annehmen", "All rights reserved.": "Alle Rechte vorbehalten.", - "Congratulations 🎉": "Herzlichen Glückwunsch 🎉." -} \ No newline at end of file + "Congratulations 🎉": "Herzlichen Glückwunsch 🎉.", + "Sent Date Oldest": "Gesendet Datum Älteste", + "Sent Date Newest": "Gesendet Datum Neueste", + "Subject A-Z": "Betreff A-Z", + "Subject Z-A": "Betreff Z-A" +} diff --git a/backend/lang/es.json b/backend/lang/es.json index 54e9d70e..95c8667d 100644 --- a/backend/lang/es.json +++ b/backend/lang/es.json @@ -245,5 +245,9 @@ "To accept the invitation, please click the link below:": "Para aceptar la invitación, haga clic en el siguiente enlace:", "Accept Invitation": "Aceptar invitación", "All rights reserved.": "Todos los derechos reservados.", - "Congratulations 🎉": "Enhorabuena 🎉" -} \ No newline at end of file + "Congratulations 🎉": "Enhorabuena 🎉", + "Sent Date Oldest": "Fecha de Envío Más Antigua", + "Sent Date Newest": "Fecha de Envío Más Reciente", + "Subject A-Z": "Asunto A-Z", + "Subject Z-A": "Asunto Z-A" +} diff --git a/backend/lang/es/validation.php b/backend/lang/es/validation.php index ef62e478..81a8f283 100644 --- a/backend/lang/es/validation.php +++ b/backend/lang/es/validation.php @@ -1,156 +1,143 @@ 'El campo :attribute debe ser aceptado.', - 'accepted_if' => 'El campo :attribute debe ser aceptado cuando :other es :value.', - 'active_url' => 'El campo :attribute no es una URL válida.', - 'after' => 'El campo :attribute debe ser una fecha posterior a :date.', - 'after_or_equal' => 'El campo :attribute debe ser una fecha posterior o igual a :date.', - 'alpha' => 'El campo :attribute solo debe contener letras.', - 'alpha_dash' => 'El campo :attribute solo debe contener letras, números, guiones y guiones bajos.', - 'alpha_num' => 'El campo :attribute solo debe contener letras y números.', - 'array' => 'El campo :attribute debe ser un arreglo.', - 'ascii' => 'El campo :attribute solo debe contener caracteres alfanuméricos de un solo byte y símbolos.', - 'before' => 'El campo :attribute debe ser una fecha anterior a :date.', - 'before_or_equal' => 'El campo :attribute debe ser una fecha anterior o igual a :date.', - 'between' => [ - 'array' => 'El campo :attribute debe tener entre :min y :max elementos.', - 'file' => 'El campo :attribute debe tener entre :min y :max kilobytes.', - 'numeric' => 'El campo :attribute debe estar entre :min y :max.', - 'string' => 'El campo :attribute debe tener entre :min y :max caracteres.', - ], - 'boolean' => 'El campo :attribute debe ser verdadero o falso.', - 'confirmed' => 'La confirmación del campo :attribute no coincide.', - 'current_password' => 'La contraseña es incorrecta.', - 'date' => 'El campo :attribute no es una fecha válida.', - 'date_equals' => 'El campo :attribute debe ser una fecha igual a :date.', - 'date_format' => 'El campo :attribute no coincide con el formato :format.', - 'decimal' => 'El campo :attribute debe tener :decimal lugares decimales.', - 'declined' => 'El campo :attribute debe ser rechazado.', - 'declined_if' => 'El campo :attribute debe ser rechazado cuando :other es :value.', - 'different' => 'El campo :attribute y :other deben ser diferentes.', - 'digits' => 'El campo :attribute debe tener :digits dígitos.', - 'digits_between' => 'El campo :attribute debe tener entre :min y :max dígitos.', - 'dimensions' => 'El campo :attribute tiene dimensiones de imagen inválidas.', - 'distinct' => 'El campo :attribute tiene un valor duplicado.', - 'doesnt_end_with' => 'El campo :attribute no debe terminar con ninguno de los siguientes: :values.', - 'doesnt_start_with' => 'El campo :attribute no debe comenzar con ninguno de los siguientes: :values.', - 'email' => 'El campo :attribute debe ser una dirección de correo electrónico válida.', - 'ends_with' => 'El campo :attribute debe terminar con uno de los siguientes: :values.', - 'enum' => 'El :attribute seleccionado es inválido.', - 'exists' => 'El :attribute seleccionado es inválido.', - 'file' => 'El campo :attribute debe ser un archivo.', - 'filled' => 'El campo :attribute debe tener un valor.', - 'gt' => [ - 'array' => 'El campo :attribute debe tener más de :value elementos.', - 'file' => 'El campo :attribute debe ser mayor que :value kilobytes.', - 'numeric' => 'El campo :attribute debe ser mayor que :value.', - 'string' => 'El campo :attribute debe ser mayor que :value caracteres.', - ], - 'gte' => [ - 'array' => 'El campo :attribute debe tener :value elementos o más.', - 'file' => 'El campo :attribute debe ser mayor o igual que :value kilobytes.', - 'numeric' => 'El campo :attribute debe ser mayor o igual que :value.', - 'string' => 'El campo :attribute debe ser mayor o igual que :value caracteres.', - ], - 'image' => 'El campo :attribute debe ser una imagen.', - 'in' => 'El :attribute seleccionado es inválido.', - 'in_array' => 'El campo :attribute no existe en :other.', - 'integer' => 'El campo :attribute debe ser un número entero.', - 'ip' => 'El campo :attribute debe ser una dirección IP válida.', - 'ipv4' => 'El campo :attribute debe ser una dirección IPv4 válida.', - 'ipv6' => 'El campo :attribute debe ser una dirección IPv6 válida.', - 'json' => 'El campo :attribute debe ser una cadena JSON válida.', - 'lowercase' => 'El campo :attribute debe estar en minúsculas.', - 'lt' => [ - 'array' => 'El campo :attribute debe tener menos de :value elementos.', - 'file' => 'El campo :attribute debe ser menor que :value kilobytes.', - 'numeric' => 'El campo :attribute debe ser menor que :value.', - 'string' => 'El campo :attribute debe ser menor que :value caracteres.', - ], - 'lte' => [ - 'array' => 'El campo :attribute no debe tener más de :value elementos.', - 'file' => 'El campo :attribute debe ser menor o igual que :value kilobytes.', - 'numeric' => 'El campo :attribute debe ser menor o igual que :value.', - 'string' => 'El campo :attribute debe ser menor o igual que :value caracteres.', - ], - 'mac_address' => 'El campo :attribute debe ser una dirección MAC válida.', - 'max' => [ - 'array' => 'El campo :attribute no debe tener más de :max elementos.', - 'file' => 'El campo :attribute no debe ser mayor que :max kilobytes.', - 'numeric' => 'El campo :attribute no debe ser mayor que :max.', - 'string' => 'El campo :attribute no debe ser mayor que :max caracteres.', - ], - 'max_digits' => 'El campo :attribute no debe tener más de :max dígitos.', - 'mimes' => 'El campo :attribute debe ser un archivo de tipo: :values.', - 'mimetypes' => 'El campo :attribute debe ser un archivo de tipo: :values.', - 'min' => [ - 'array' => 'El campo :attribute debe tener al menos :min elementos.', - 'file' => 'El campo :attribute debe ser al menos :min kilobytes.', - 'numeric' => 'El campo :attribute debe ser al menos :min.', - 'string' => 'El campo :attribute debe tener al menos :min caracteres.', - ], - 'min_digits' => 'El campo :attribute debe tener al menos :min dígitos.', - 'missing' => 'El campo :attribute debe estar ausente.', - 'missing_if' => 'El campo :attribute debe estar ausente cuando :other es :value.', - 'missing_unless' => 'El campo :attribute debe estar ausente a menos que :other sea :value.', - 'missing_with' => 'El campo :attribute debe estar ausente cuando :values está presente.', - 'missing_with_all' => 'El campo :attribute debe estar ausente cuando :values están presentes.', - 'multiple_of' => 'El campo :attribute debe ser un múltiplo de :value.', - 'not_in' => 'El :attribute seleccionado es inválido.', - 'not_regex' => 'El formato del campo :attribute es inválido.', - 'numeric' => 'El campo :attribute debe ser un número.', - 'password' => [ - 'letters' => 'El campo :attribute debe contener al menos una letra.', - 'mixed' => 'El campo :attribute debe contener al menos una letra mayúscula y una minúscula.', - 'numbers' => 'El campo :attribute debe contener al menos un número.', - 'symbols' => 'El campo :attribute debe contener al menos un símbolo.', - 'uncompromised' => 'El :attribute proporcionado ha aparecido en una filtración de datos. Por favor, elija un :attribute diferente.', - ], - 'present' => 'El campo :attribute debe estar presente.', - 'prohibited' => 'El campo :attribute está prohibido.', - 'prohibited_if' => 'El campo :attribute está prohibido cuando :other es :value.', - 'prohibited_unless' => 'El campo :attribute está prohibido a menos que :other esté en :values.', - 'prohibits' => 'El campo :attribute prohíbe que :other esté presente.', - 'regex' => 'El formato del campo :attribute es inválido.', - 'required' => 'El campo :attribute es obligatorio.', - 'required_array_keys' => 'El campo :attribute debe contener entradas para: :values.', - 'required_if' => 'El campo :attribute es obligatorio cuando :other es :value.', - 'required_if_accepted' => 'El campo :attribute es obligatorio cuando :other es aceptado.', - 'required_unless' => 'El campo :attribute es obligatorio a menos que :other esté en :values.', - 'required_with' => 'El campo :attribute es obligatorio cuando :values está presente.', - 'required_with_all' => 'El campo :attribute es obligatorio cuando :values están presentes.', - 'required_without' => 'El campo :attribute es obligatorio cuando :values no está presente.', - 'required_without_all' => 'El campo :attribute es obligatorio cuando ninguno de los :values está presente.', - 'same' => 'El campo :attribute debe coincidir con :other.', - 'size' => [ - 'array' => 'El campo :attribute debe contener :size elementos.', - 'file' => 'El campo :attribute debe ser :size kilobytes.', - 'numeric' => 'El campo :attribute debe ser :size.', - 'string' => 'El campo :attribute debe tener :size caracteres.', - ], - 'starts_with' => 'El campo :attribute debe comenzar con uno de los siguientes: :values.', - 'string' => 'El campo :attribute debe ser una cadena de texto.', - 'timezone' => 'El campo :attribute debe ser una zona horaria válida.', - 'unique' => 'El :attribute ya ha sido tomado.', - 'uploaded' => 'El :attribute no se pudo subir.', - 'uppercase' => 'El campo :attribute debe estar en mayúsculas.', - 'url' => 'El campo :attribute debe ser una URL válida.', - 'ulid' => 'El campo :attribute debe ser un ULID válido.', - 'uuid' => 'El campo :attribute debe ser un UUID válido.', - ]; + 'accepted' => 'El campo :attribute debe ser aceptado.', + 'accepted_if' => 'El campo :attribute debe ser aceptado cuando :other es :value.', + 'active_url' => 'El campo :attribute no es una URL válida.', + 'after' => 'El campo :attribute debe ser una fecha posterior a :date.', + 'after_or_equal' => 'El campo :attribute debe ser una fecha posterior o igual a :date.', + 'alpha' => 'El campo :attribute solo debe contener letras.', + 'alpha_dash' => 'El campo :attribute solo debe contener letras, números, guiones y guiones bajos.', + 'alpha_num' => 'El campo :attribute solo debe contener letras y números.', + 'array' => 'El campo :attribute debe ser un arreglo.', + 'ascii' => 'El campo :attribute solo debe contener caracteres alfanuméricos de un solo byte y símbolos.', + 'before' => 'El campo :attribute debe ser una fecha anterior a :date.', + 'before_or_equal' => 'El campo :attribute debe ser una fecha anterior o igual a :date.', + 'between' => [ + 'array' => 'El campo :attribute debe tener entre :min y :max elementos.', + 'file' => 'El campo :attribute debe tener entre :min y :max kilobytes.', + 'numeric' => 'El campo :attribute debe estar entre :min y :max.', + 'string' => 'El campo :attribute debe tener entre :min y :max caracteres.', + ], + 'boolean' => 'El campo :attribute debe ser verdadero o falso.', + 'confirmed' => 'La confirmación del campo :attribute no coincide.', + 'current_password' => 'La contraseña es incorrecta.', + 'date' => 'El campo :attribute no es una fecha válida.', + 'date_equals' => 'El campo :attribute debe ser una fecha igual a :date.', + 'date_format' => 'El campo :attribute no coincide con el formato :format.', + 'decimal' => 'El campo :attribute debe tener :decimal lugares decimales.', + 'declined' => 'El campo :attribute debe ser rechazado.', + 'declined_if' => 'El campo :attribute debe ser rechazado cuando :other es :value.', + 'different' => 'El campo :attribute y :other deben ser diferentes.', + 'digits' => 'El campo :attribute debe tener :digits dígitos.', + 'digits_between' => 'El campo :attribute debe tener entre :min y :max dígitos.', + 'dimensions' => 'El campo :attribute tiene dimensiones de imagen inválidas.', + 'distinct' => 'El campo :attribute tiene un valor duplicado.', + 'doesnt_end_with' => 'El campo :attribute no debe terminar con ninguno de los siguientes: :values.', + 'doesnt_start_with' => 'El campo :attribute no debe comenzar con ninguno de los siguientes: :values.', + 'email' => 'El campo :attribute debe ser una dirección de correo electrónico válida.', + 'ends_with' => 'El campo :attribute debe terminar con uno de los siguientes: :values.', + 'enum' => 'El :attribute seleccionado es inválido.', + 'exists' => 'El :attribute seleccionado es inválido.', + 'file' => 'El campo :attribute debe ser un archivo.', + 'filled' => 'El campo :attribute debe tener un valor.', + 'gt' => [ + 'array' => 'El campo :attribute debe tener más de :value elementos.', + 'file' => 'El campo :attribute debe ser mayor que :value kilobytes.', + 'numeric' => 'El campo :attribute debe ser mayor que :value.', + 'string' => 'El campo :attribute debe ser mayor que :value caracteres.', + ], + 'gte' => [ + 'array' => 'El campo :attribute debe tener :value elementos o más.', + 'file' => 'El campo :attribute debe ser mayor o igual que :value kilobytes.', + 'numeric' => 'El campo :attribute debe ser mayor o igual que :value.', + 'string' => 'El campo :attribute debe ser mayor o igual que :value caracteres.', + ], + 'image' => 'El campo :attribute debe ser una imagen.', + 'in' => 'El :attribute seleccionado es inválido.', + 'in_array' => 'El campo :attribute no existe en :other.', + 'integer' => 'El campo :attribute debe ser un número entero.', + 'ip' => 'El campo :attribute debe ser una dirección IP válida.', + 'ipv4' => 'El campo :attribute debe ser una dirección IPv4 válida.', + 'ipv6' => 'El campo :attribute debe ser una dirección IPv6 válida.', + 'json' => 'El campo :attribute debe ser una cadena JSON válida.', + 'lowercase' => 'El campo :attribute debe estar en minúsculas.', + 'lt' => [ + 'array' => 'El campo :attribute debe tener menos de :value elementos.', + 'file' => 'El campo :attribute debe ser menor que :value kilobytes.', + 'numeric' => 'El campo :attribute debe ser menor que :value.', + 'string' => 'El campo :attribute debe ser menor que :value caracteres.', + ], + 'lte' => [ + 'array' => 'El campo :attribute no debe tener más de :value elementos.', + 'file' => 'El campo :attribute debe ser menor o igual que :value kilobytes.', + 'numeric' => 'El campo :attribute debe ser menor o igual que :value.', + 'string' => 'El campo :attribute debe ser menor o igual que :value caracteres.', + ], + 'mac_address' => 'El campo :attribute debe ser una dirección MAC válida.', + 'max' => [ + 'array' => 'El campo :attribute no debe tener más de :max elementos.', + 'file' => 'El campo :attribute no debe ser mayor que :max kilobytes.', + 'numeric' => 'El campo :attribute no debe ser mayor que :max.', + 'string' => 'El campo :attribute no debe ser mayor que :max caracteres.', + ], + 'max_digits' => 'El campo :attribute no debe tener más de :max dígitos.', + 'mimes' => 'El campo :attribute debe ser un archivo de tipo: :values.', + 'mimetypes' => 'El campo :attribute debe ser un archivo de tipo: :values.', + 'min' => [ + 'array' => 'El campo :attribute debe tener al menos :min elementos.', + 'file' => 'El campo :attribute debe ser al menos :min kilobytes.', + 'numeric' => 'El campo :attribute debe ser al menos :min.', + 'string' => 'El campo :attribute debe tener al menos :min caracteres.', + ], + 'min_digits' => 'El campo :attribute debe tener al menos :min dígitos.', + 'missing' => 'El campo :attribute debe estar ausente.', + 'missing_if' => 'El campo :attribute debe estar ausente cuando :other es :value.', + 'missing_unless' => 'El campo :attribute debe estar ausente a menos que :other sea :value.', + 'missing_with' => 'El campo :attribute debe estar ausente cuando :values está presente.', + 'missing_with_all' => 'El campo :attribute debe estar ausente cuando :values están presentes.', + 'multiple_of' => 'El campo :attribute debe ser un múltiplo de :value.', + 'not_in' => 'El :attribute seleccionado es inválido.', + 'not_regex' => 'El formato del campo :attribute es inválido.', + 'numeric' => 'El campo :attribute debe ser un número.', + 'password' => [ + 'letters' => 'El campo :attribute debe contener al menos una letra.', + 'mixed' => 'El campo :attribute debe contener al menos una letra mayúscula y una minúscula.', + 'numbers' => 'El campo :attribute debe contener al menos un número.', + 'symbols' => 'El campo :attribute debe contener al menos un símbolo.', + 'uncompromised' => 'El :attribute proporcionado ha aparecido en una filtración de datos. Por favor, elija un :attribute diferente.', + ], + 'present' => 'El campo :attribute debe estar presente.', + 'prohibited' => 'El campo :attribute está prohibido.', + 'prohibited_if' => 'El campo :attribute está prohibido cuando :other es :value.', + 'prohibited_unless' => 'El campo :attribute está prohibido a menos que :other esté en :values.', + 'prohibits' => 'El campo :attribute prohíbe que :other esté presente.', + 'regex' => 'El formato del campo :attribute es inválido.', + 'required' => 'El campo :attribute es obligatorio.', + 'required_array_keys' => 'El campo :attribute debe contener entradas para: :values.', + 'required_if' => 'El campo :attribute es obligatorio cuando :other es :value.', + 'required_if_accepted' => 'El campo :attribute es obligatorio cuando :other es aceptado.', + 'required_unless' => 'El campo :attribute es obligatorio a menos que :other esté en :values.', + 'required_with' => 'El campo :attribute es obligatorio cuando :values está presente.', + 'required_with_all' => 'El campo :attribute es obligatorio cuando :values están presentes.', + 'required_without' => 'El campo :attribute es obligatorio cuando :values no está presente.', + 'required_without_all' => 'El campo :attribute es obligatorio cuando ninguno de los :values está presente.', + 'same' => 'El campo :attribute debe coincidir con :other.', + 'size' => [ + 'array' => 'El campo :attribute debe contener :size elementos.', + 'file' => 'El campo :attribute debe ser :size kilobytes.', + 'numeric' => 'El campo :attribute debe ser :size.', + 'string' => 'El campo :attribute debe tener :size caracteres.', + ], + 'starts_with' => 'El campo :attribute debe comenzar con uno de los siguientes: :values.', + 'string' => 'El campo :attribute debe ser una cadena de texto.', + 'timezone' => 'El campo :attribute debe ser una zona horaria válida.', + 'unique' => 'El :attribute ya ha sido tomado.', + 'uploaded' => 'El :attribute no se pudo subir.', + 'uppercase' => 'El campo :attribute debe estar en mayúsculas.', + 'url' => 'El campo :attribute debe ser una URL válida.', + 'ulid' => 'El campo :attribute debe ser un ULID válido.', + 'uuid' => 'El campo :attribute debe ser un UUID válido.', /* |-------------------------------------------------------------------------- diff --git a/backend/lang/fr.json b/backend/lang/fr.json index d57b71a7..83b2a817 100644 --- a/backend/lang/fr.json +++ b/backend/lang/fr.json @@ -245,5 +245,9 @@ "To accept the invitation, please click the link below:": "Pour accepter l'invitation, veuillez cliquer sur le lien ci-dessous :", "Accept Invitation": "Accepter l'invitation", "All rights reserved.": "Tous droits réservés.", - "Congratulations 🎉": "Félicitations 🎉" -} \ No newline at end of file + "Congratulations 🎉": "Félicitations 🎉", + "Sent Date Oldest": "Date d'Envoi la Plus Ancienne", + "Sent Date Newest": "Date d'Envoi la Plus Récente", + "Subject A-Z": "Objet A-Z", + "Subject Z-A": "Objet Z-A" +} diff --git a/backend/lang/pt-br.json b/backend/lang/pt-br.json index dafa71bf..909a1f28 100644 --- a/backend/lang/pt-br.json +++ b/backend/lang/pt-br.json @@ -245,5 +245,9 @@ "To accept the invitation, please click the link below:": "Para aceitar o convite, clique no link abaixo:", "Accept Invitation": "Aceitar convite", "All rights reserved.": "Todos os direitos reservados.", - "Congratulations 🎉": "Parabéns 🎉" -} \ No newline at end of file + "Congratulations 🎉": "Parabéns 🎉", + "Sent Date Oldest": "Data de Envio Mais Antiga", + "Sent Date Newest": "Data de Envio Mais Recente", + "Subject A-Z": "Assunto A-Z", + "Subject Z-A": "Assunto Z-A" +} diff --git a/backend/lang/pt.json b/backend/lang/pt.json index c5977169..09f56102 100644 --- a/backend/lang/pt.json +++ b/backend/lang/pt.json @@ -245,5 +245,9 @@ "To accept the invitation, please click the link below:": "Para aceitar o convite, clique na hiperligação abaixo:", "Accept Invitation": "Aceitar o convite", "All rights reserved.": "Todos os direitos reservados.", - "Congratulations 🎉": "Parabéns 🎉" -} \ No newline at end of file + "Congratulations 🎉": "Parabéns 🎉", + "Sent Date Oldest": "Data de Envio Mais Antiga", + "Sent Date Newest": "Data de Envio Mais Recente", + "Subject A-Z": "Assunto A-Z", + "Subject Z-A": "Assunto Z-A" +} diff --git a/backend/lang/ru.json b/backend/lang/ru.json index b0eb7d3f..a043a270 100644 --- a/backend/lang/ru.json +++ b/backend/lang/ru.json @@ -259,5 +259,10 @@ "Congratulations! You\\'ve received a new order for ": "", "What\\'s Next?": "", "Welcome to :appName! We\\'re excited to have you aboard!": "", - "You\\'ve been invited to join :appName.": "" + "You\\'ve been invited to join :appName.": "", + "Sent Date Oldest": "", + "Sent Date Newest": "", + "Subject A-Z": "", + "Subject Z-A": "", + "There are no tickets available. If you would like to assign this ticket to this attendee, please adjust the ticket\\'s available quantity.": "" } \ No newline at end of file diff --git a/backend/lang/zh-cn.json b/backend/lang/zh-cn.json index 928ca0c8..2feacde2 100644 --- a/backend/lang/zh-cn.json +++ b/backend/lang/zh-cn.json @@ -245,5 +245,9 @@ "To accept the invitation, please click the link below:": "要接受邀请,请点击下面的链接:", "Accept Invitation": "接受邀请", "All rights reserved.": "保留所有权利。", - "Congratulations 🎉": "恭喜 🎉" -} \ No newline at end of file + "Congratulations 🎉": "恭喜 🎉", + "Sent Date Oldest": "发送日期最早", + "Sent Date Newest": "发送日期最新", + "Subject A-Z": "主题 A-Z", + "Subject Z-A": "主题 Z-A" +} diff --git a/frontend/lingui.config.ts b/frontend/lingui.config.ts index 632c3707..f9b96ef0 100644 --- a/frontend/lingui.config.ts +++ b/frontend/lingui.config.ts @@ -28,6 +28,9 @@ const config: LinguiConfig = { ], sourceLocale: "en", format: "po", + fallbackLocales: { + "default": "en", + } }; export default config; diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index a6a52feb..e3df25b2 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -7,7 +7,7 @@ const BASE_URL = isSsr() ? getConfig('VITE_API_URL_SERVER') : getConfig('VITE_API_URL_CLIENT'); const LOGIN_PATH = "/auth/login"; -const PREVIOUS_URL_KEY = 'previous_url'; // Key for storing the previous URL +const PREVIOUS_URL_KEY = 'previous_url'; const ALLOWED_UNAUTHENTICATED_PATHS = [ 'auth/login', @@ -28,7 +28,6 @@ export const api = axios.create({ withCredentials: true, }); - const existingToken = typeof window !== "undefined" ? window.localStorage.getItem('token') : undefined; if (existingToken) { setAuthToken(existingToken); @@ -36,10 +35,7 @@ if (existingToken) { api.interceptors.response.use( (response) => { - // Securely update the token on each response - // eslint-disable-next-line lingui/no-unlocalized-strings const token = response?.data?.token || response?.headers["x-auth-token"]; - if (token) { window?.localStorage?.setItem('token', token); setAuthToken(token); @@ -48,20 +44,26 @@ api.interceptors.response.use( }, (error) => { const { status } = error.response; - if ((status === 401 || status === 403) && !ALLOWED_UNAUTHENTICATED_PATHS.some(path => window?.location.pathname.includes(path))) { + const currentPath = window?.location.pathname; + const isAllowedUnauthenticatedPath = ALLOWED_UNAUTHENTICATED_PATHS.some(path => currentPath.includes(path)); + const isManageEventPath = currentPath.startsWith('/manage/event/'); + const isAuthError = status === 401 || status === 403; + + if (isAuthError && (!isAllowedUnauthenticatedPath || isManageEventPath)) { // Store the current URL before redirecting to the login page window?.localStorage?.setItem(PREVIOUS_URL_KEY, window?.location.href); window?.location?.replace(LOGIN_PATH); } + return Promise.reject(error); } ); -axios.defaults.withCredentials = true +axios.defaults.withCredentials = true; export const redirectToPreviousUrl = () => { const previousUrl = window?.localStorage?.getItem(PREVIOUS_URL_KEY) || '/manage/events'; - window?.localStorage?.removeItem(PREVIOUS_URL_KEY); // Clean up after redirecting + window?.localStorage?.removeItem(PREVIOUS_URL_KEY); if (typeof window !== "undefined") { window.location.href = previousUrl; } diff --git a/frontend/src/components/common/LanguageSwitcher/index.tsx b/frontend/src/components/common/LanguageSwitcher/index.tsx index 5b0b2fea..fecf4d6d 100644 --- a/frontend/src/components/common/LanguageSwitcher/index.tsx +++ b/frontend/src/components/common/LanguageSwitcher/index.tsx @@ -1,15 +1,32 @@ import {Select} from "@mantine/core"; -import { - dynamicActivateLocale, - getClientLocale, - getLocaleName, - localeToNameMap, - SupportedLocales -} from "../../../locales.ts"; +import {dynamicActivateLocale, getClientLocale, localeToNameMap, SupportedLocales} from "../../../locales.ts"; import {t} from "@lingui/macro"; import {IconWorld} from "@tabler/icons-react"; +import {useLingui} from "@lingui/react"; export const LanguageSwitcher = () => { + useLingui(); + + // Ideally these would be in the locales.ts file, but when they're there they don't translate + const getLocaleName = (locale: SupportedLocales): string => { + switch (locale) { + case "de": + return t`German`; + case "en": + return t`English`; + case "es": + return t`Spanish`; + case "fr": + return t`French`; + case "pt": + return t`Portuguese`; + case "pt-br": + return t`Brazilian Portuguese`; + case "zh-cn": + return t`Chinese (Simplified)`; + } + }; + return ( <>