From f06851fa378cecd6a4ccdf1265e1f539e1808653 Mon Sep 17 00:00:00 2001 From: chamikaJ Date: Tue, 8 Jul 2025 15:26:55 +0530 Subject: [PATCH] feat(localization): add and update translations for multiple languages - Introduced new localization files for Albanian, German, Spanish, Portuguese, and Chinese, enhancing the application's multilingual support. - Added new keys and updated existing translations in project-view, task-list-table, and settings files to improve user experience across different languages. - Enhanced error handling and empty state messages in task management components to provide clearer feedback to users. - Updated tooltip texts and button labels for better clarity and consistency in the user interface. --- .../public/locales/alb/project-view.json | 14 +++ .../alb/project-view/project-view-header.json | 20 ++++- .../public/locales/alb/settings/profile.json | 3 +- .../locales/alb/settings/team-members.json | 5 +- .../public/locales/alb/settings/teams.json | 16 ++++ .../public/locales/alb/task-list-table.json | 7 ++ .../public/locales/de/project-view.json | 14 +++ .../de/project-view/project-view-header.json | 16 +++- .../public/locales/de/settings/profile.json | 3 +- .../locales/de/settings/team-members.json | 5 +- .../public/locales/de/settings/teams.json | 16 ++++ .../public/locales/de/task-list-table.json | 7 ++ .../public/locales/en/project-view.json | 14 +++ .../en/project-view/project-view-header.json | 14 ++- .../public/locales/en/settings/profile.json | 3 +- .../locales/en/settings/team-members.json | 5 +- .../public/locales/en/settings/teams.json | 16 ++++ .../public/locales/en/task-list-table.json | 7 ++ .../public/locales/es/project-view.json | 14 +++ .../es/project-view/project-view-header.json | 20 ++++- .../public/locales/es/settings/profile.json | 3 +- .../locales/es/settings/team-members.json | 5 +- .../public/locales/es/settings/teams.json | 16 ++++ .../public/locales/es/task-list-table.json | 7 ++ .../public/locales/pt/project-view.json | 14 +++ .../pt/project-view/project-view-header.json | 18 +++- .../public/locales/pt/settings/profile.json | 3 +- .../locales/pt/settings/team-members.json | 5 +- .../public/locales/pt/settings/teams.json | 16 ++++ .../public/locales/pt/task-list-table.json | 7 ++ .../public/locales/zh/project-view.json | 14 +++ .../zh/project-view/project-view-header.json | 38 +++++--- .../public/locales/zh/settings/profile.json | 3 +- .../public/locales/zh/settings/sidebar.json | 1 + .../locales/zh/settings/team-members.json | 5 +- .../public/locales/zh/settings/teams.json | 16 ++++ .../public/locales/zh/task-list-filters.json | 14 ++- .../public/locales/zh/task-list-table.json | 70 +++++++++++++++ .../public/locales/zh/task-management.json | 35 ++++++++ .../src/components/PinRouteToNavbarButton.tsx | 11 ++- .../settings/edit-team-name-modal.tsx | 14 +-- .../settings/update-member-drawer.tsx | 2 +- .../components/task-drawer/task-drawer.tsx | 2 +- .../components/task-list-v2/TaskListV2.tsx | 8 +- .../task-management/improved-task-filters.tsx | 33 ++++++- .../src/lib/project/project-view-constants.ts | 44 ++++++++-- .../projectView/project-view-header.tsx | 88 +++++++++++-------- .../projects/projectView/project-view.tsx | 14 ++- .../settings/sidebar/settings-sidebar.tsx | 4 +- .../team-members/team-members-settings.tsx | 3 + .../pages/settings/teams/teams-settings.tsx | 19 ++-- .../src/utils/current-date-string.ts | 53 ++++++++++- worklenz-frontend/src/utils/greetingString.ts | 13 ++- 53 files changed, 700 insertions(+), 117 deletions(-) create mode 100644 worklenz-frontend/public/locales/alb/project-view.json create mode 100644 worklenz-frontend/public/locales/alb/settings/teams.json create mode 100644 worklenz-frontend/public/locales/de/project-view.json create mode 100644 worklenz-frontend/public/locales/de/settings/teams.json create mode 100644 worklenz-frontend/public/locales/en/project-view.json create mode 100644 worklenz-frontend/public/locales/en/settings/teams.json create mode 100644 worklenz-frontend/public/locales/es/project-view.json create mode 100644 worklenz-frontend/public/locales/es/settings/teams.json create mode 100644 worklenz-frontend/public/locales/pt/project-view.json create mode 100644 worklenz-frontend/public/locales/pt/settings/teams.json create mode 100644 worklenz-frontend/public/locales/zh/project-view.json create mode 100644 worklenz-frontend/public/locales/zh/settings/teams.json create mode 100644 worklenz-frontend/public/locales/zh/task-management.json diff --git a/worklenz-frontend/public/locales/alb/project-view.json b/worklenz-frontend/public/locales/alb/project-view.json new file mode 100644 index 00000000..2bc256fe --- /dev/null +++ b/worklenz-frontend/public/locales/alb/project-view.json @@ -0,0 +1,14 @@ +{ + "taskList": "Lista e Detyrave", + "board": "Tabela Kanban", + "insights": "Analiza", + "files": "Skedarë", + "members": "Anëtarë", + "updates": "Përditësime", + "projectView": "Pamja e Projektit", + "loading": "Duke ngarkuar projektin...", + "error": "Gabim në ngarkimin e projektit", + "pinnedTab": "E fiksuar si tab i parazgjedhur", + "pinTab": "Fikso si tab i parazgjedhur", + "unpinTab": "Hiqe fiksimin e tab-it të parazgjedhur" +} \ No newline at end of file diff --git a/worklenz-frontend/public/locales/alb/project-view/project-view-header.json b/worklenz-frontend/public/locales/alb/project-view/project-view-header.json index 3335738f..f12bdd8d 100644 --- a/worklenz-frontend/public/locales/alb/project-view/project-view-header.json +++ b/worklenz-frontend/public/locales/alb/project-view/project-view-header.json @@ -4,14 +4,26 @@ "createTask": "Krijo detyrë", "settings": "Cilësimet", "subscribe": "Abonohu", - "unsubscribe": "Ç'abonohu", + "unsubscribe": "Çabonohu", "deleteProject": "Fshi projektin", "startDate": "Data e fillimit", - "endDate": "Data e përfundimit", + "endDate": "Data e mbarimit", "projectSettings": "Cilësimet e projektit", "projectSummary": "Përmbledhja e projektit", "receiveProjectSummary": "Merrni një përmbledhje të projektit çdo mbrëmje.", "refreshProject": "Rifresko projektin", - "saveAsTemplate": "Ruaje si shabllon", - "invite": "Fto" + "saveAsTemplate": "Ruaj si model", + "invite": "Fto", + "subscribeTooltip": "Abonohu tek njoftimet e projektit", + "unsubscribeTooltip": "Çabonohu nga njoftimet e projektit", + "refreshTooltip": "Rifresko të dhënat e projektit", + "settingsTooltip": "Hap cilësimet e projektit", + "saveAsTemplateTooltip": "Ruaj këtë projekt si model", + "inviteTooltip": "Fto anëtarë të ekipit në këtë projekt", + "createTaskTooltip": "Krijo një detyrë të re", + "importTaskTooltip": "Importo detyrë nga modeli", + "navigateBackTooltip": "Kthehu tek lista e projekteve", + "projectStatusTooltip": "Statusi i projektit", + "projectDatesInfo": "Informacion për kohëzgjatjen e projektit", + "projectCategoryTooltip": "Kategoria e projektit" } diff --git a/worklenz-frontend/public/locales/alb/settings/profile.json b/worklenz-frontend/public/locales/alb/settings/profile.json index c3ad210d..dcce50d5 100644 --- a/worklenz-frontend/public/locales/alb/settings/profile.json +++ b/worklenz-frontend/public/locales/alb/settings/profile.json @@ -9,5 +9,6 @@ "saveChanges": "Ruaj Ndryshimet", "profileJoinedText": "U bashkua një muaj më parë", "profileLastUpdatedText": "Përditësuar një muaj më parë", - "avatarTooltip": "Klikoni për të ngarkuar një avatar" + "avatarTooltip": "Klikoni për të ngarkuar një avatar", + "title": "Cilësimet e Profilit" } diff --git a/worklenz-frontend/public/locales/alb/settings/team-members.json b/worklenz-frontend/public/locales/alb/settings/team-members.json index 0ebdb3b5..955954dc 100644 --- a/worklenz-frontend/public/locales/alb/settings/team-members.json +++ b/worklenz-frontend/public/locales/alb/settings/team-members.json @@ -1,4 +1,5 @@ { + "title": "Anëtarët e Ekipit", "nameColumn": "Emri", "projectsColumn": "Projektet", "emailColumn": "Email", @@ -40,5 +41,7 @@ "ownerText": "Pronar i Ekipit", "addedText": "Shtuar", "updatedText": "Përditësuar", - "noResultFound": "Shkruani një adresë email dhe shtypni Enter..." + "noResultFound": "Shkruani një adresë email dhe shtypni Enter...", + "jobTitlesFetchError": "Dështoi marrja e titujve të punës", + "invitationResent": "Ftesa u dërgua sërish me sukses!" } diff --git a/worklenz-frontend/public/locales/alb/settings/teams.json b/worklenz-frontend/public/locales/alb/settings/teams.json new file mode 100644 index 00000000..30f87d79 --- /dev/null +++ b/worklenz-frontend/public/locales/alb/settings/teams.json @@ -0,0 +1,16 @@ +{ + "title": "Ekipet", + "team": "Ekip", + "teams": "Ekipet", + "name": "Emri", + "created": "Krijuar", + "ownsBy": "I përket", + "edit": "Ndrysho", + "editTeam": "Ndrysho Ekipin", + "pinTooltip": "Kliko për ta fiksuar në menunë kryesore", + "editTeamName": "Ndrysho Emrin e Ekipit", + "updateName": "Përditëso Emrin", + "namePlaceholder": "Emri", + "nameRequired": "Ju lutem shkruani një Emër", + "updateFailed": "Ndryshimi i emrit të ekipit dështoi!" +} \ No newline at end of file diff --git a/worklenz-frontend/public/locales/alb/task-list-table.json b/worklenz-frontend/public/locales/alb/task-list-table.json index 067d1088..c6e1dc44 100644 --- a/worklenz-frontend/public/locales/alb/task-list-table.json +++ b/worklenz-frontend/public/locales/alb/task-list-table.json @@ -68,6 +68,13 @@ "dueDatePlaceholder": "Data e afatit", "startDatePlaceholder": "Data e fillimit", + "emptyStates": { + "noTaskGroups": "Nuk u gjetën grupe detyrash", + "noTaskGroupsDescription": "Detyrat do të shfaqen këtu kur krijohen ose kur aplikohen filtra.", + "errorPrefix": "Gabim:", + "dragTaskFallback": "Detyrë" + }, + "customColumns": { "addCustomColumn": "Shto një kolonë të personalizuar", "customColumnHeader": "Kolona e Personalizuar", diff --git a/worklenz-frontend/public/locales/de/project-view.json b/worklenz-frontend/public/locales/de/project-view.json new file mode 100644 index 00000000..448a7249 --- /dev/null +++ b/worklenz-frontend/public/locales/de/project-view.json @@ -0,0 +1,14 @@ +{ + "taskList": "Aufgabenliste", + "board": "Kanban-Board", + "insights": "Insights", + "files": "Dateien", + "members": "Mitglieder", + "updates": "Aktualisierungen", + "projectView": "Projektansicht", + "loading": "Projekt wird geladen...", + "error": "Fehler beim Laden des Projekts", + "pinnedTab": "Als Standard-Registerkarte festgesetzt", + "pinTab": "Als Standard-Registerkarte festsetzen", + "unpinTab": "Standard-Registerkarte lösen" +} \ No newline at end of file diff --git a/worklenz-frontend/public/locales/de/project-view/project-view-header.json b/worklenz-frontend/public/locales/de/project-view/project-view-header.json index e2810462..dae5f67a 100644 --- a/worklenz-frontend/public/locales/de/project-view/project-view-header.json +++ b/worklenz-frontend/public/locales/de/project-view/project-view-header.json @@ -4,7 +4,7 @@ "createTask": "Aufgabe erstellen", "settings": "Einstellungen", "subscribe": "Abonnieren", - "unsubscribe": "Abbestellen", + "unsubscribe": "Abonnement beenden", "deleteProject": "Projekt löschen", "startDate": "Startdatum", "endDate": "Enddatum", @@ -13,5 +13,17 @@ "receiveProjectSummary": "Erhalten Sie jeden Abend eine Projektzusammenfassung.", "refreshProject": "Projekt aktualisieren", "saveAsTemplate": "Als Vorlage speichern", - "invite": "Einladen" + "invite": "Einladen", + "subscribeTooltip": "Projektbenachrichtigungen abonnieren", + "unsubscribeTooltip": "Projektbenachrichtigungen beenden", + "refreshTooltip": "Projektdaten aktualisieren", + "settingsTooltip": "Projekteinstellungen öffnen", + "saveAsTemplateTooltip": "Dieses Projekt als Vorlage speichern", + "inviteTooltip": "Teammitglieder zu diesem Projekt einladen", + "createTaskTooltip": "Neue Aufgabe erstellen", + "importTaskTooltip": "Aufgabe aus Vorlage importieren", + "navigateBackTooltip": "Zurück zur Projektliste", + "projectStatusTooltip": "Projektstatus", + "projectDatesInfo": "Informationen zum Projektzeitraum", + "projectCategoryTooltip": "Projektkategorie" } diff --git a/worklenz-frontend/public/locales/de/settings/profile.json b/worklenz-frontend/public/locales/de/settings/profile.json index f896e1f8..4d7fc4cd 100644 --- a/worklenz-frontend/public/locales/de/settings/profile.json +++ b/worklenz-frontend/public/locales/de/settings/profile.json @@ -9,5 +9,6 @@ "saveChanges": "Änderungen speichern", "profileJoinedText": "Vor einem Monat beigetreten", "profileLastUpdatedText": "Vor einem Monat aktualisiert", - "avatarTooltip": "Klicken Sie zum Hochladen eines Avatars" + "avatarTooltip": "Klicken Sie zum Hochladen eines Avatars", + "title": "Profil-Einstellungen" } diff --git a/worklenz-frontend/public/locales/de/settings/team-members.json b/worklenz-frontend/public/locales/de/settings/team-members.json index 6f2add12..d223f08e 100644 --- a/worklenz-frontend/public/locales/de/settings/team-members.json +++ b/worklenz-frontend/public/locales/de/settings/team-members.json @@ -1,4 +1,5 @@ { + "title": "Teammitglieder", "nameColumn": "Name", "projectsColumn": "Projekte", "emailColumn": "E-Mail", @@ -40,5 +41,7 @@ "ownerText": "Team-Besitzer", "addedText": "Hinzugefügt", "updatedText": "Aktualisiert", - "noResultFound": "Geben Sie eine E-Mail-Adresse ein und drücken Sie Enter..." + "noResultFound": "Geben Sie eine E-Mail-Adresse ein und drücken Sie Enter...", + "jobTitlesFetchError": "Fehler beim Abrufen der Jobtitel", + "invitationResent": "Einladung erfolgreich erneut gesendet!" } diff --git a/worklenz-frontend/public/locales/de/settings/teams.json b/worklenz-frontend/public/locales/de/settings/teams.json new file mode 100644 index 00000000..bf39215d --- /dev/null +++ b/worklenz-frontend/public/locales/de/settings/teams.json @@ -0,0 +1,16 @@ +{ + "title": "Teams", + "team": "Team", + "teams": "Teams", + "name": "Name", + "created": "Erstellt", + "ownsBy": "Gehört zu", + "edit": "Bearbeiten", + "editTeam": "Team bearbeiten", + "pinTooltip": "Klicken Sie hier, um dies im Hauptmenü zu fixieren", + "editTeamName": "Team-Name bearbeiten", + "updateName": "Name aktualisieren", + "namePlaceholder": "Name", + "nameRequired": "Bitte geben Sie einen Namen ein", + "updateFailed": "Änderung des Team-Namens fehlgeschlagen!" +} \ No newline at end of file diff --git a/worklenz-frontend/public/locales/de/task-list-table.json b/worklenz-frontend/public/locales/de/task-list-table.json index fa8e7623..2caa8e5c 100644 --- a/worklenz-frontend/public/locales/de/task-list-table.json +++ b/worklenz-frontend/public/locales/de/task-list-table.json @@ -68,6 +68,13 @@ "dueDatePlaceholder": "Fälligkeitsdatum", "startDatePlaceholder": "Startdatum", + "emptyStates": { + "noTaskGroups": "Keine Aufgabengruppen gefunden", + "noTaskGroupsDescription": "Aufgaben werden hier angezeigt, wenn sie erstellt oder Filter angewendet werden.", + "errorPrefix": "Fehler:", + "dragTaskFallback": "Aufgabe" + }, + "customColumns": { "addCustomColumn": "Benutzerdefinierte Spalte hinzufügen", "customColumnHeader": "Benutzerdefinierte Spalte", diff --git a/worklenz-frontend/public/locales/en/project-view.json b/worklenz-frontend/public/locales/en/project-view.json new file mode 100644 index 00000000..16d2a0bc --- /dev/null +++ b/worklenz-frontend/public/locales/en/project-view.json @@ -0,0 +1,14 @@ +{ + "taskList": "Task List", + "board": "Kanban Board", + "insights": "Insights", + "files": "Files", + "members": "Members", + "updates": "Updates", + "projectView": "Project View", + "loading": "Loading project...", + "error": "Error loading project", + "pinnedTab": "Pinned as default tab", + "pinTab": "Pin as default tab", + "unpinTab": "Unpin default tab" +} \ No newline at end of file diff --git a/worklenz-frontend/public/locales/en/project-view/project-view-header.json b/worklenz-frontend/public/locales/en/project-view/project-view-header.json index c8467288..536ccad4 100644 --- a/worklenz-frontend/public/locales/en/project-view/project-view-header.json +++ b/worklenz-frontend/public/locales/en/project-view/project-view-header.json @@ -13,5 +13,17 @@ "receiveProjectSummary": "Receive a project summary every evening.", "refreshProject": "Refresh project", "saveAsTemplate": "Save as template", - "invite": "Invite" + "invite": "Invite", + "subscribeTooltip": "Subscribe to project notifications", + "unsubscribeTooltip": "Unsubscribe from project notifications", + "refreshTooltip": "Refresh project data", + "settingsTooltip": "Open project settings", + "saveAsTemplateTooltip": "Save this project as a template", + "inviteTooltip": "Invite team members to this project", + "createTaskTooltip": "Create a new task", + "importTaskTooltip": "Import task from template", + "navigateBackTooltip": "Go back to projects list", + "projectStatusTooltip": "Project status", + "projectDatesInfo": "Project timeline information", + "projectCategoryTooltip": "Project category" } diff --git a/worklenz-frontend/public/locales/en/settings/profile.json b/worklenz-frontend/public/locales/en/settings/profile.json index 5dd49095..43ce2f41 100644 --- a/worklenz-frontend/public/locales/en/settings/profile.json +++ b/worklenz-frontend/public/locales/en/settings/profile.json @@ -9,5 +9,6 @@ "saveChanges": "Save Changes", "profileJoinedText": "Joined a month ago", "profileLastUpdatedText": "Last updated a month ago", - "avatarTooltip": "Click to upload an avatar" + "avatarTooltip": "Click to upload an avatar", + "title": "Profile Settings" } diff --git a/worklenz-frontend/public/locales/en/settings/team-members.json b/worklenz-frontend/public/locales/en/settings/team-members.json index 35e77f6e..36918b90 100644 --- a/worklenz-frontend/public/locales/en/settings/team-members.json +++ b/worklenz-frontend/public/locales/en/settings/team-members.json @@ -1,4 +1,5 @@ { + "title": "Team Members", "nameColumn": "Name", "projectsColumn": "Projects", "emailColumn": "Email", @@ -40,5 +41,7 @@ "ownerText": "Team Owner", "addedText": "Added", "updatedText": "Updated", - "noResultFound": "Type an email address and hit enter..." + "noResultFound": "Type an email address and hit enter...", + "jobTitlesFetchError": "Failed to fetch job titles", + "invitationResent": "Invitation resent successfully!" } diff --git a/worklenz-frontend/public/locales/en/settings/teams.json b/worklenz-frontend/public/locales/en/settings/teams.json new file mode 100644 index 00000000..57a1df51 --- /dev/null +++ b/worklenz-frontend/public/locales/en/settings/teams.json @@ -0,0 +1,16 @@ +{ + "title": "Teams", + "team": "Team", + "teams": "Teams", + "name": "Name", + "created": "Created", + "ownsBy": "Owns By", + "edit": "Edit", + "editTeam": "Edit Team", + "pinTooltip": "Click to pin this into the main menu", + "editTeamName": "Edit Team Name", + "updateName": "Update Name", + "namePlaceholder": "Name", + "nameRequired": "Please enter a Name", + "updateFailed": "Team name change failed!" +} \ No newline at end of file diff --git a/worklenz-frontend/public/locales/en/task-list-table.json b/worklenz-frontend/public/locales/en/task-list-table.json index 674f12d0..adea199f 100644 --- a/worklenz-frontend/public/locales/en/task-list-table.json +++ b/worklenz-frontend/public/locales/en/task-list-table.json @@ -68,6 +68,13 @@ "dueDatePlaceholder": "Due Date", "startDatePlaceholder": "Start Date", + "emptyStates": { + "noTaskGroups": "No task groups found", + "noTaskGroupsDescription": "Tasks will appear here when they are created or when filters are applied.", + "errorPrefix": "Error:", + "dragTaskFallback": "Task" + }, + "customColumns": { "addCustomColumn": "Add a custom column", "customColumnHeader": "Custom Column", diff --git a/worklenz-frontend/public/locales/es/project-view.json b/worklenz-frontend/public/locales/es/project-view.json new file mode 100644 index 00000000..a4c12d9f --- /dev/null +++ b/worklenz-frontend/public/locales/es/project-view.json @@ -0,0 +1,14 @@ +{ + "taskList": "Lista de Tareas", + "board": "Tablero Kanban", + "insights": "Análisis", + "files": "Archivos", + "members": "Miembros", + "updates": "Actualizaciones", + "projectView": "Vista del Proyecto", + "loading": "Cargando proyecto...", + "error": "Error al cargar el proyecto", + "pinnedTab": "Fijado como pestaña predeterminada", + "pinTab": "Fijar como pestaña predeterminada", + "unpinTab": "Desfijar pestaña predeterminada" +} \ No newline at end of file diff --git a/worklenz-frontend/public/locales/es/project-view/project-view-header.json b/worklenz-frontend/public/locales/es/project-view/project-view-header.json index 0d9bdf26..c6fb854b 100644 --- a/worklenz-frontend/public/locales/es/project-view/project-view-header.json +++ b/worklenz-frontend/public/locales/es/project-view/project-view-header.json @@ -2,16 +2,28 @@ "importTasks": "Importar tareas", "importTask": "Importar tarea", "createTask": "Crear tarea", - "settings": "Ajustes", + "settings": "Configuración", "subscribe": "Suscribirse", "unsubscribe": "Cancelar suscripción", "deleteProject": "Eliminar proyecto", "startDate": "Fecha de inicio", "endDate": "Fecha de finalización", - "projectSettings": "Ajustes del proyecto", + "projectSettings": "Configuración del proyecto", "projectSummary": "Resumen del proyecto", - "receiveProjectSummary": "Recibir un resumen del proyecto todas las noches.", + "receiveProjectSummary": "Recibe un resumen del proyecto cada noche.", "refreshProject": "Actualizar proyecto", "saveAsTemplate": "Guardar como plantilla", - "invite": "Invitar" + "invite": "Invitar", + "subscribeTooltip": "Suscribirse a notificaciones del proyecto", + "unsubscribeTooltip": "Cancelar suscripción a notificaciones del proyecto", + "refreshTooltip": "Actualizar datos del proyecto", + "settingsTooltip": "Abrir configuración del proyecto", + "saveAsTemplateTooltip": "Guardar este proyecto como plantilla", + "inviteTooltip": "Invitar miembros del equipo a este proyecto", + "createTaskTooltip": "Crear una nueva tarea", + "importTaskTooltip": "Importar tarea desde plantilla", + "navigateBackTooltip": "Volver a la lista de proyectos", + "projectStatusTooltip": "Estado del proyecto", + "projectDatesInfo": "Información de cronograma del proyecto", + "projectCategoryTooltip": "Categoría del proyecto" } diff --git a/worklenz-frontend/public/locales/es/settings/profile.json b/worklenz-frontend/public/locales/es/settings/profile.json index 9c43a470..1a1698c8 100644 --- a/worklenz-frontend/public/locales/es/settings/profile.json +++ b/worklenz-frontend/public/locales/es/settings/profile.json @@ -9,5 +9,6 @@ "saveChanges": "Guardar cambios", "profileJoinedText": "Se unió hace un mes", "profileLastUpdatedText": "Última actualización hace un mes", - "avatarTooltip": "Haz clic para subir un avatar" + "avatarTooltip": "Haz clic para subir un avatar", + "title": "Configuración del Perfil" } diff --git a/worklenz-frontend/public/locales/es/settings/team-members.json b/worklenz-frontend/public/locales/es/settings/team-members.json index 8de73b84..1000bf98 100644 --- a/worklenz-frontend/public/locales/es/settings/team-members.json +++ b/worklenz-frontend/public/locales/es/settings/team-members.json @@ -1,4 +1,5 @@ { + "title": "Miembros del Equipo", "nameColumn": "Nombre", "projectsColumn": "Proyectos", "emailColumn": "Correo electrónico", @@ -40,5 +41,7 @@ "ownerText": "Propietario del equipo", "addedText": "Agregado", "updatedText": "Actualizado", - "noResultFound": "Escriba una dirección de correo electrónico y presione enter..." + "noResultFound": "Escriba una dirección de correo electrónico y presione enter...", + "jobTitlesFetchError": "Error al obtener los cargos", + "invitationResent": "¡Invitación reenviada exitosamente!" } diff --git a/worklenz-frontend/public/locales/es/settings/teams.json b/worklenz-frontend/public/locales/es/settings/teams.json new file mode 100644 index 00000000..808c1b78 --- /dev/null +++ b/worklenz-frontend/public/locales/es/settings/teams.json @@ -0,0 +1,16 @@ +{ + "title": "Equipos", + "team": "Equipo", + "teams": "Equipos", + "name": "Nombre", + "created": "Creado", + "ownsBy": "Pertenece a", + "edit": "Editar", + "editTeam": "Editar Equipo", + "pinTooltip": "Haz clic para fijar esto en el menú principal", + "editTeamName": "Editar Nombre del Equipo", + "updateName": "Actualizar Nombre", + "namePlaceholder": "Nombre", + "nameRequired": "Por favor ingresa un Nombre", + "updateFailed": "¡Falló el cambio de nombre del equipo!" +} \ No newline at end of file diff --git a/worklenz-frontend/public/locales/es/task-list-table.json b/worklenz-frontend/public/locales/es/task-list-table.json index 006a2763..c67225de 100644 --- a/worklenz-frontend/public/locales/es/task-list-table.json +++ b/worklenz-frontend/public/locales/es/task-list-table.json @@ -68,6 +68,13 @@ "dueDatePlaceholder": "Fecha de vencimiento", "startDatePlaceholder": "Fecha de inicio", + "emptyStates": { + "noTaskGroups": "No se encontraron grupos de tareas", + "noTaskGroupsDescription": "Las tareas aparecerán aquí cuando se creen o cuando se apliquen filtros.", + "errorPrefix": "Error:", + "dragTaskFallback": "Tarea" + }, + "customColumns": { "addCustomColumn": "Agregar una columna personalizada", "customColumnHeader": "Columna Personalizada", diff --git a/worklenz-frontend/public/locales/pt/project-view.json b/worklenz-frontend/public/locales/pt/project-view.json new file mode 100644 index 00000000..c58337da --- /dev/null +++ b/worklenz-frontend/public/locales/pt/project-view.json @@ -0,0 +1,14 @@ +{ + "taskList": "Lista de Tarefas", + "board": "Quadro Kanban", + "insights": "Insights", + "files": "Arquivos", + "members": "Membros", + "updates": "Atualizações", + "projectView": "Visualização do Projeto", + "loading": "Carregando projeto...", + "error": "Erro ao carregar projeto", + "pinnedTab": "Fixada como aba padrão", + "pinTab": "Fixar como aba padrão", + "unpinTab": "Desfixar aba padrão" +} \ No newline at end of file diff --git a/worklenz-frontend/public/locales/pt/project-view/project-view-header.json b/worklenz-frontend/public/locales/pt/project-view/project-view-header.json index e776c67d..6e295e38 100644 --- a/worklenz-frontend/public/locales/pt/project-view/project-view-header.json +++ b/worklenz-frontend/public/locales/pt/project-view/project-view-header.json @@ -7,11 +7,23 @@ "unsubscribe": "Cancelar inscrição", "deleteProject": "Excluir projeto", "startDate": "Data de início", - "endDate": "Data de fim", + "endDate": "Data de término", "projectSettings": "Configurações do projeto", "projectSummary": "Resumo do projeto", - "receiveProjectSummary": "Receber um resumo do projeto todas as noites.", + "receiveProjectSummary": "Receba um resumo do projeto todas as noites.", "refreshProject": "Atualizar projeto", "saveAsTemplate": "Salvar como modelo", - "invite": "Convidar" + "invite": "Convidar", + "subscribeTooltip": "Inscrever-se nas notificações do projeto", + "unsubscribeTooltip": "Cancelar inscrição nas notificações do projeto", + "refreshTooltip": "Atualizar dados do projeto", + "settingsTooltip": "Abrir configurações do projeto", + "saveAsTemplateTooltip": "Salvar este projeto como modelo", + "inviteTooltip": "Convidar membros da equipe para este projeto", + "createTaskTooltip": "Criar uma nova tarefa", + "importTaskTooltip": "Importar tarefa de modelo", + "navigateBackTooltip": "Voltar para lista de projetos", + "projectStatusTooltip": "Status do projeto", + "projectDatesInfo": "Informações do cronograma do projeto", + "projectCategoryTooltip": "Categoria do projeto" } diff --git a/worklenz-frontend/public/locales/pt/settings/profile.json b/worklenz-frontend/public/locales/pt/settings/profile.json index 61e94e8b..3a4a8447 100644 --- a/worklenz-frontend/public/locales/pt/settings/profile.json +++ b/worklenz-frontend/public/locales/pt/settings/profile.json @@ -9,5 +9,6 @@ "saveChanges": "Salvar Alterações", "profileJoinedText": "Entrou há um mês", "profileLastUpdatedText": "Última atualização há um mês", - "avatarTooltip": "Clique para carregar um avatar" + "avatarTooltip": "Clique para carregar um avatar", + "title": "Configurações do Perfil" } diff --git a/worklenz-frontend/public/locales/pt/settings/team-members.json b/worklenz-frontend/public/locales/pt/settings/team-members.json index 9c6d80b6..9ace1764 100644 --- a/worklenz-frontend/public/locales/pt/settings/team-members.json +++ b/worklenz-frontend/public/locales/pt/settings/team-members.json @@ -1,4 +1,5 @@ { + "title": "Membros da Equipe", "nameColumn": "Nome", "projectsColumn": "Projetos", "emailColumn": "Email", @@ -40,5 +41,7 @@ "ownerText": "Dono da Equipe", "addedText": "Adicionado", "updatedText": "Atualizado", - "noResultFound": "Digite um endereço de email e pressione enter..." + "noResultFound": "Digite um endereço de email e pressione enter...", + "jobTitlesFetchError": "Falha ao buscar cargos", + "invitationResent": "Convite reenviado com sucesso!" } diff --git a/worklenz-frontend/public/locales/pt/settings/teams.json b/worklenz-frontend/public/locales/pt/settings/teams.json new file mode 100644 index 00000000..e460318f --- /dev/null +++ b/worklenz-frontend/public/locales/pt/settings/teams.json @@ -0,0 +1,16 @@ +{ + "title": "Equipes", + "team": "Equipe", + "teams": "Equipes", + "name": "Nome", + "created": "Criado", + "ownsBy": "Pertence a", + "edit": "Editar", + "editTeam": "Editar Equipe", + "pinTooltip": "Clique para fixar isso no menu principal", + "editTeamName": "Editar Nome da Equipe", + "updateName": "Atualizar Nome", + "namePlaceholder": "Nome", + "nameRequired": "Por favor digite um Nome", + "updateFailed": "Falha na alteração do nome da equipe!" +} \ No newline at end of file diff --git a/worklenz-frontend/public/locales/pt/task-list-table.json b/worklenz-frontend/public/locales/pt/task-list-table.json index a493fcf0..b7f90398 100644 --- a/worklenz-frontend/public/locales/pt/task-list-table.json +++ b/worklenz-frontend/public/locales/pt/task-list-table.json @@ -68,6 +68,13 @@ "dueDatePlaceholder": "Data de vencimento", "startDatePlaceholder": "Data de início", + "emptyStates": { + "noTaskGroups": "Nenhum grupo de tarefas encontrado", + "noTaskGroupsDescription": "As tarefas aparecerão aqui quando forem criadas ou quando filtros forem aplicados.", + "errorPrefix": "Erro:", + "dragTaskFallback": "Tarefa" + }, + "customColumns": { "addCustomColumn": "Adicionar uma coluna personalizada", "customColumnHeader": "Coluna Personalizada", diff --git a/worklenz-frontend/public/locales/zh/project-view.json b/worklenz-frontend/public/locales/zh/project-view.json new file mode 100644 index 00000000..ff756ea5 --- /dev/null +++ b/worklenz-frontend/public/locales/zh/project-view.json @@ -0,0 +1,14 @@ +{ + "taskList": "任务列表", + "board": "看板", + "insights": "数据洞察", + "files": "文件", + "members": "成员", + "updates": "动态更新", + "projectView": "项目视图", + "loading": "正在加载项目...", + "error": "加载项目时出错", + "pinnedTab": "已固定为默认标签页", + "pinTab": "固定为默认标签页", + "unpinTab": "取消固定默认标签页" +} \ No newline at end of file diff --git a/worklenz-frontend/public/locales/zh/project-view/project-view-header.json b/worklenz-frontend/public/locales/zh/project-view/project-view-header.json index 7ce20f0b..ca0ead5c 100644 --- a/worklenz-frontend/public/locales/zh/project-view/project-view-header.json +++ b/worklenz-frontend/public/locales/zh/project-view/project-view-header.json @@ -1,13 +1,29 @@ { - "importTasks": "导入任务", - "createTask": "创建任务", - "settings": "设置", - "subscribe": "订阅", - "unsubscribe": "取消订阅", - "deleteProject": "删除项目", - "startDate": "开始日期", - "endDate": "结束日期", - "projectSettings": "项目设置", - "projectSummary": "项目摘要", - "receiveProjectSummary": "每晚接收项目摘要。" + "importTasks": "导入任务", + "importTask": "导入任务", + "createTask": "创建任务", + "settings": "设置", + "subscribe": "订阅", + "unsubscribe": "取消订阅", + "deleteProject": "删除项目", + "startDate": "开始日期", + "endDate": "结束日期", + "projectSettings": "项目设置", + "projectSummary": "项目摘要", + "receiveProjectSummary": "每晚接收项目摘要。", + "refreshProject": "刷新项目", + "saveAsTemplate": "保存为模板", + "invite": "邀请", + "subscribeTooltip": "订阅项目通知", + "unsubscribeTooltip": "取消订阅项目通知", + "refreshTooltip": "刷新项目数据", + "settingsTooltip": "打开项目设置", + "saveAsTemplateTooltip": "将此项目保存为模板", + "inviteTooltip": "邀请团队成员加入此项目", + "createTaskTooltip": "创建新任务", + "importTaskTooltip": "从模板导入任务", + "navigateBackTooltip": "返回项目列表", + "projectStatusTooltip": "项目状态", + "projectDatesInfo": "项目时间安排信息", + "projectCategoryTooltip": "项目类别" } \ No newline at end of file diff --git a/worklenz-frontend/public/locales/zh/settings/profile.json b/worklenz-frontend/public/locales/zh/settings/profile.json index 79e670c6..cfafeb12 100644 --- a/worklenz-frontend/public/locales/zh/settings/profile.json +++ b/worklenz-frontend/public/locales/zh/settings/profile.json @@ -9,5 +9,6 @@ "saveChanges": "保存更改", "profileJoinedText": "一个月前加入", "profileLastUpdatedText": "一个月前更新", - "avatarTooltip": "点击上传头像" + "avatarTooltip": "点击上传头像", + "title": "个人资料设置" } \ No newline at end of file diff --git a/worklenz-frontend/public/locales/zh/settings/sidebar.json b/worklenz-frontend/public/locales/zh/settings/sidebar.json index ad5e9a7d..b9f74709 100644 --- a/worklenz-frontend/public/locales/zh/settings/sidebar.json +++ b/worklenz-frontend/public/locales/zh/settings/sidebar.json @@ -1,5 +1,6 @@ { "profile": "个人资料", + "appearance": "外观", "notifications": "通知", "clients": "客户", "job-titles": "职位", diff --git a/worklenz-frontend/public/locales/zh/settings/team-members.json b/worklenz-frontend/public/locales/zh/settings/team-members.json index 5826c6ec..8b39483c 100644 --- a/worklenz-frontend/public/locales/zh/settings/team-members.json +++ b/worklenz-frontend/public/locales/zh/settings/team-members.json @@ -1,4 +1,5 @@ { + "title": "团队成员", "nameColumn": "名称", "projectsColumn": "项目", "emailColumn": "电子邮件", @@ -40,5 +41,7 @@ "ownerText": "团队所有者", "addedText": "已添加", "updatedText": "已更新", - "noResultFound": "输入电子邮件地址并按回车键..." + "noResultFound": "输入电子邮件地址并按回车键...", + "jobTitlesFetchError": "获取职位失败", + "invitationResent": "邀请重新发送成功!" } \ No newline at end of file diff --git a/worklenz-frontend/public/locales/zh/settings/teams.json b/worklenz-frontend/public/locales/zh/settings/teams.json new file mode 100644 index 00000000..af2064ae --- /dev/null +++ b/worklenz-frontend/public/locales/zh/settings/teams.json @@ -0,0 +1,16 @@ +{ + "title": "团队", + "team": "团队", + "teams": "团队", + "name": "名称", + "created": "创建时间", + "ownsBy": "所有者", + "edit": "编辑", + "editTeam": "编辑团队", + "pinTooltip": "点击将此项固定到主菜单", + "editTeamName": "编辑团队名称", + "updateName": "更新名称", + "namePlaceholder": "名称", + "nameRequired": "请输入名称", + "updateFailed": "团队名称更改失败!" +} \ No newline at end of file diff --git a/worklenz-frontend/public/locales/zh/task-list-filters.json b/worklenz-frontend/public/locales/zh/task-list-filters.json index 300c8eb0..a3354305 100644 --- a/worklenz-frontend/public/locales/zh/task-list-filters.json +++ b/worklenz-frontend/public/locales/zh/task-list-filters.json @@ -50,5 +50,17 @@ "selectCategory": "选择类别", "pleaseEnterAName": "请输入名称", "pleaseSelectACategory": "请选择类别", - "create": "创建" + "create": "创建", + "searchTasks": "搜索任务...", + "searchPlaceholder": "搜索...", + "fieldsText": "字段", + "loadingFilters": "加载筛选器...", + "noOptionsFound": "未找到选项", + "filtersActive": "个筛选器已激活", + "filterActive": "个筛选器已激活", + "clearAll": "清除全部", + "clearing": "清除中...", + "cancel": "取消", + "search": "搜索", + "groupedBy": "分组依据" } \ No newline at end of file diff --git a/worklenz-frontend/public/locales/zh/task-list-table.json b/worklenz-frontend/public/locales/zh/task-list-table.json index c380963e..d2f9634c 100644 --- a/worklenz-frontend/public/locales/zh/task-list-table.json +++ b/worklenz-frontend/public/locales/zh/task-list-table.json @@ -36,6 +36,7 @@ "addTaskText": "+ 添加任务", "addSubTaskText": "+ 添加子任务", "addTaskInputPlaceholder": "输入任务并按回车键", + "noTasksInGroup": "此组中没有任务", "openButton": "打开", "okButton": "确定", "noLabelsFound": "未找到标签", @@ -52,5 +53,74 @@ "convertToTask": "转换为任务", "delete": "删除", "searchByNameInputPlaceholder": "按名称搜索" + }, + "setDueDate": "设置截止日期", + "setStartDate": "设置开始日期", + "clearDueDate": "清除截止日期", + "clearStartDate": "清除开始日期", + "dueDatePlaceholder": "截止日期", + "startDatePlaceholder": "开始日期", + + "emptyStates": { + "noTaskGroups": "未找到任务组", + "noTaskGroupsDescription": "创建任务或应用筛选器后,任务将显示在此处。", + "errorPrefix": "错误:", + "dragTaskFallback": "任务" + }, + + "customColumns": { + "addCustomColumn": "添加自定义列", + "customColumnHeader": "自定义列", + "customColumnSettings": "自定义列设置", + "noCustomValue": "无值", + "peopleField": "人员字段", + "noDate": "无日期", + "unsupportedField": "不支持的字段类型", + + "modal": { + "addFieldTitle": "添加字段", + "editFieldTitle": "编辑字段", + "fieldTitle": "字段标题", + "fieldTitleRequired": "字段标题为必填项", + "columnTitlePlaceholder": "列标题", + "type": "类型", + "deleteConfirmTitle": "确定要删除此自定义列吗?", + "deleteConfirmDescription": "此操作无法撤销。与此列关联的所有数据将被永久删除。", + "deleteButton": "删除", + "cancelButton": "取消", + "createButton": "创建", + "updateButton": "更新", + "createSuccessMessage": "自定义列创建成功", + "updateSuccessMessage": "自定义列更新成功", + "deleteSuccessMessage": "自定义列删除成功", + "deleteErrorMessage": "删除自定义列失败", + "createErrorMessage": "创建自定义列失败", + "updateErrorMessage": "更新自定义列失败" + }, + + "fieldTypes": { + "people": "人员", + "number": "数字", + "date": "日期", + "selection": "选择", + "checkbox": "复选框", + "labels": "标签", + "key": "键", + "formula": "公式" + } + }, + + "indicators": { + "tooltips": { + "subtasks": "{{count}} 个子任务", + "subtasks_plural": "{{count}} 个子任务", + "comments": "{{count}} 条评论", + "comments_plural": "{{count}} 条评论", + "attachments": "{{count}} 个附件", + "attachments_plural": "{{count}} 个附件", + "subscribers": "任务有订阅者", + "dependencies": "任务有依赖项", + "recurring": "重复任务" + } } } \ No newline at end of file diff --git a/worklenz-frontend/public/locales/zh/task-management.json b/worklenz-frontend/public/locales/zh/task-management.json new file mode 100644 index 00000000..341ecc64 --- /dev/null +++ b/worklenz-frontend/public/locales/zh/task-management.json @@ -0,0 +1,35 @@ +{ + "noTasksInGroup": "此组中没有任务", + "noTasksInGroupDescription": "添加任务开始使用", + "addFirstTask": "添加你的第一个任务", + "openTask": "打开", + "subtask": "子任务", + "subtasks": "子任务", + "comment": "评论", + "comments": "评论", + "attachment": "附件", + "attachments": "附件", + "enterSubtaskName": "输入子任务名称...", + "add": "添加", + "cancel": "取消", + "renameGroup": "重命名组", + "renameStatus": "重命名状态", + "renamePhase": "重命名阶段", + "changeCategory": "更改类别", + "clickToEditGroupName": "点击编辑组名称", + "enterGroupName": "输入组名称", + + "indicators": { + "tooltips": { + "subtasks": "{{count}} 个子任务", + "subtasks_plural": "{{count}} 个子任务", + "comments": "{{count}} 条评论", + "comments_plural": "{{count}} 条评论", + "attachments": "{{count}} 个附件", + "attachments_plural": "{{count}} 个附件", + "subscribers": "任务有订阅者", + "dependencies": "任务有依赖项", + "recurring": "重复任务" + } + } +} \ No newline at end of file diff --git a/worklenz-frontend/src/components/PinRouteToNavbarButton.tsx b/worklenz-frontend/src/components/PinRouteToNavbarButton.tsx index c7e99c1d..c2e415a9 100644 --- a/worklenz-frontend/src/components/PinRouteToNavbarButton.tsx +++ b/worklenz-frontend/src/components/PinRouteToNavbarButton.tsx @@ -5,8 +5,15 @@ import { PushpinFilled, PushpinOutlined } from '@ant-design/icons'; import { colors } from '../styles/colors'; import { navRoutes, NavRoutesType } from '../features/navbar/navRoutes'; +// Props type for the component +type PinRouteToNavbarButtonProps = { + name: string; + path: string; + adminOnly?: boolean; +}; + // this component pin the given path to navbar -const PinRouteToNavbarButton = ({ name, path }: NavRoutesType) => { +const PinRouteToNavbarButton = ({ name, path, adminOnly = false }: PinRouteToNavbarButtonProps) => { const navRoutesList: NavRoutesType[] = getJSONFromLocalStorage('navRoutes') || navRoutes; const [isPinned, setIsPinned] = useState( @@ -18,7 +25,7 @@ const PinRouteToNavbarButton = ({ name, path }: NavRoutesType) => { const handlePinToNavbar = (name: string, path: string) => { let newNavRoutesList; - const route: NavRoutesType = { name, path }; + const route: NavRoutesType = { name, path, adminOnly }; if (isPinned) { newNavRoutesList = navRoutesList.filter(item => item.name !== route.name); diff --git a/worklenz-frontend/src/components/settings/edit-team-name-modal.tsx b/worklenz-frontend/src/components/settings/edit-team-name-modal.tsx index 90a29abe..243a6146 100644 --- a/worklenz-frontend/src/components/settings/edit-team-name-modal.tsx +++ b/worklenz-frontend/src/components/settings/edit-team-name-modal.tsx @@ -1,5 +1,6 @@ import { Divider, Form, Input, message, Modal, Typography } from 'antd'; import { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { useAppDispatch } from '@/hooks/useAppDispatch'; import { editTeamName, fetchTeams } from '@/features/teams/teamSlice'; import { ITeamGetResponse } from '@/types/teams/team.type'; @@ -11,6 +12,7 @@ interface EditTeamNameModalProps { } const EditTeamNameModal = ({ team, isModalOpen, onCancel }: EditTeamNameModalProps) => { + const { t } = useTranslation('settings/teams'); const dispatch = useAppDispatch(); const [form] = Form.useForm(); const [updating, setUpdating] = useState(false); @@ -33,7 +35,7 @@ const EditTeamNameModal = ({ team, isModalOpen, onCancel }: EditTeamNameModalPro } setUpdating(false); } catch (error) { - message.error('Team name change failed!'); + message.error(t('updateFailed')); } finally { setUpdating(false); } @@ -49,13 +51,13 @@ const EditTeamNameModal = ({ team, isModalOpen, onCancel }: EditTeamNameModalPro width: '100%', }} > - Edit Team Name + {t('editTeamName')} } open={isModalOpen} onOk={form.submit} - okText="Update Name" + okText={t('updateName')} onCancel={() => { onCancel(); setUpdating(false); @@ -67,15 +69,15 @@ const EditTeamNameModal = ({ team, isModalOpen, onCancel }: EditTeamNameModalPro
- +
diff --git a/worklenz-frontend/src/components/settings/update-member-drawer.tsx b/worklenz-frontend/src/components/settings/update-member-drawer.tsx index a7da0075..1af06fcc 100644 --- a/worklenz-frontend/src/components/settings/update-member-drawer.tsx +++ b/worklenz-frontend/src/components/settings/update-member-drawer.tsx @@ -65,7 +65,7 @@ const UpdateMemberDrawer = ({ selectedMemberId, onRoleUpdate }: UpdateMemberDraw setJobTitles(res.body.data || []); } } catch (error) { - console.error('Error fetching job titles:', error); + logger.error('Error fetching job titles:', error); message.error(t('jobTitlesFetchError')); } finally { setLoading(false); diff --git a/worklenz-frontend/src/components/task-drawer/task-drawer.tsx b/worklenz-frontend/src/components/task-drawer/task-drawer.tsx index bbec5479..527988f1 100644 --- a/worklenz-frontend/src/components/task-drawer/task-drawer.tsx +++ b/worklenz-frontend/src/components/task-drawer/task-drawer.tsx @@ -154,7 +154,7 @@ const TaskDrawer = () => { onClick={handleAddTimeLog} style={{ width: '100%' }} > - Add new time log + {t('taskTimeLogTab.addTimeLog')} ); diff --git a/worklenz-frontend/src/components/task-list-v2/TaskListV2.tsx b/worklenz-frontend/src/components/task-list-v2/TaskListV2.tsx index 37af547a..28d415ae 100644 --- a/worklenz-frontend/src/components/task-list-v2/TaskListV2.tsx +++ b/worklenz-frontend/src/components/task-list-v2/TaskListV2.tsx @@ -519,7 +519,7 @@ const TaskListV2: React.FC = () => { // Loading and error states if (loading || loadingColumns) return ; - if (error) return
Error: {error}
; + if (error) return
{t('emptyStates.errorPrefix')} {error}
; // Show message when no data if (groups.length === 0 && !loading) { @@ -531,10 +531,10 @@ const TaskListV2: React.FC = () => {
- No task groups found + {t('emptyStates.noTaskGroups')}
- Tasks will appear here when they are created or when filters are applied. + {t('emptyStates.noTaskGroupsDescription')}
@@ -623,7 +623,7 @@ const TaskListV2: React.FC = () => {
{allTasks.find(task => task.id === activeId)?.name || allTasks.find(task => task.id === activeId)?.title || - 'Task'} + t('emptyStates.dragTaskFallback')}
{allTasks.find(task => task.id === activeId)?.task_key} diff --git a/worklenz-frontend/src/components/task-management/improved-task-filters.tsx b/worklenz-frontend/src/components/task-management/improved-task-filters.tsx index e3239f42..35de7b88 100644 --- a/worklenz-frontend/src/components/task-management/improved-task-filters.tsx +++ b/worklenz-frontend/src/components/task-management/improved-task-filters.tsx @@ -213,7 +213,7 @@ const useFilterData = (position: 'board' | 'list'): FilterSection[] => { return [ { id: 'priority', - label: 'Priority', + label: t('priorityText'), options: filterData.priorities.map((p: any) => ({ value: p.id, label: p.name, @@ -288,7 +288,7 @@ const useFilterData = (position: 'board' | 'list'): FilterSection[] => { return [ { id: 'priority', - label: 'Priority', + label: t('priorityText'), options: filterData.priorities.map((p: any) => ({ value: p.id, label: p.name, @@ -719,7 +719,34 @@ const FieldsDropdown: React.FC<{ themeClasses: any; isDarkMode: boolean }> = ({ isDarkMode, }) => { const { t } = useTranslation('task-list-filters'); + const { t: tTable } = useTranslation('task-list-table'); const dispatch = useAppDispatch(); + + // Helper function to get translated field label using existing task-list-table translations + const getFieldLabel = useCallback((fieldKey: string) => { + const keyMappings: Record = { + 'KEY': 'keyColumn', + 'DESCRIPTION': 'descriptionColumn', + 'PROGRESS': 'progressColumn', + 'ASSIGNEES': 'assigneesColumn', + 'LABELS': 'labelsColumn', + 'PHASE': 'phaseColumn', + 'STATUS': 'statusColumn', + 'PRIORITY': 'priorityColumn', + 'TIME_TRACKING': 'timeTrackingColumn', + 'ESTIMATION': 'estimationColumn', + 'START_DATE': 'startDateColumn', + 'DUE_DATE': 'dueDateColumn', + 'DUE_TIME': 'dueTimeColumn', + 'COMPLETED_DATE': 'completedDateColumn', + 'CREATED_DATE': 'createdDateColumn', + 'LAST_UPDATED': 'lastUpdatedColumn', + 'REPORTER': 'reporterColumn', + }; + + const translationKey = keyMappings[fieldKey]; + return translationKey ? tTable(translationKey) : fieldKey; + }, [tTable]); const fieldsRaw = useSelector((state: RootState) => state.taskManagementFields); const columns = useSelector(selectColumns); const projectId = useAppSelector(state => state.projectReducer.projectId); @@ -857,7 +884,7 @@ const FieldsDropdown: React.FC<{ themeClasses: any; isDarkMode: boolean }> = ({ {/* Label and Count */}
- {field.label} + {getFieldLabel(field.key)}
); diff --git a/worklenz-frontend/src/lib/project/project-view-constants.ts b/worklenz-frontend/src/lib/project/project-view-constants.ts index 5edf1814..289b98c5 100644 --- a/worklenz-frontend/src/lib/project/project-view-constants.ts +++ b/worklenz-frontend/src/lib/project/project-view-constants.ts @@ -1,5 +1,6 @@ import React, { ReactNode, Suspense } from 'react'; import { InlineSuspenseFallback } from '@/components/suspense-fallback/suspense-fallback'; +import i18n from '@/i18n'; // Import core components synchronously to avoid suspense in main tabs import ProjectViewEnhancedBoard from '@/pages/projects/projectView/enhancedBoard/project-view-enhanced-board'; @@ -28,26 +29,31 @@ type TabItems = { element: ReactNode; }; +// Function to get translated labels +const getTabLabel = (key: string): string => { + return i18n.t(`project-view:${key}`); +}; + // settings all element items use for tabs export const tabItems: TabItems[] = [ { index: 0, key: 'tasks-list', - label: 'Task List', + label: getTabLabel('taskList'), isPinned: true, element: React.createElement(TaskListV2), }, { index: 1, key: 'board', - label: 'Board', + label: getTabLabel('board'), isPinned: true, element: React.createElement(ProjectViewEnhancedBoard), }, { index: 2, key: 'project-insights-member-overview', - label: 'Insights', + label: getTabLabel('insights'), element: React.createElement( Suspense, { fallback: React.createElement(InlineSuspenseFallback) }, @@ -57,7 +63,7 @@ export const tabItems: TabItems[] = [ { index: 3, key: 'all-attachments', - label: 'Files', + label: getTabLabel('files'), element: React.createElement( Suspense, { fallback: React.createElement(InlineSuspenseFallback) }, @@ -67,7 +73,7 @@ export const tabItems: TabItems[] = [ { index: 4, key: 'members', - label: 'Members', + label: getTabLabel('members'), element: React.createElement( Suspense, { fallback: React.createElement(InlineSuspenseFallback) }, @@ -77,7 +83,7 @@ export const tabItems: TabItems[] = [ { index: 5, key: 'updates', - label: 'Updates', + label: getTabLabel('updates'), element: React.createElement( Suspense, { fallback: React.createElement(InlineSuspenseFallback) }, @@ -85,3 +91,29 @@ export const tabItems: TabItems[] = [ ), }, ]; + +// Function to update tab labels when language changes +export const updateTabLabels = () => { + tabItems.forEach(item => { + switch (item.key) { + case 'tasks-list': + item.label = getTabLabel('taskList'); + break; + case 'board': + item.label = getTabLabel('board'); + break; + case 'project-insights-member-overview': + item.label = getTabLabel('insights'); + break; + case 'all-attachments': + item.label = getTabLabel('files'); + break; + case 'members': + item.label = getTabLabel('members'); + break; + case 'updates': + item.label = getTabLabel('updates'); + break; + } + }); +}; diff --git a/worklenz-frontend/src/pages/projects/projectView/project-view-header.tsx b/worklenz-frontend/src/pages/projects/projectView/project-view-header.tsx index 62db71fe..c77c149d 100644 --- a/worklenz-frontend/src/pages/projects/projectView/project-view-header.tsx +++ b/worklenz-frontend/src/pages/projects/projectView/project-view-header.tsx @@ -268,7 +268,7 @@ const ProjectViewHeader = memo(() => { { key: 'import', label: ( -
+
{t('importTask')}
), @@ -285,19 +285,21 @@ const ProjectViewHeader = memo(() => { if (selectedProject.category_id) { elements.push( - - {selectedProject.category_name} - + + + {selectedProject.category_name} + + ); } if (selectedProject.status) { elements.push( - + { if (selectedProject.start_date || selectedProject.end_date) { const tooltipContent = ( + {t('projectDatesInfo')} +
{selectedProject.start_date && `${t('startDate')}: ${formatDate(new Date(selectedProject.start_date))}`} {selectedProject.end_date && ( @@ -348,7 +352,7 @@ const ProjectViewHeader = memo(() => { // Refresh button actions.push( - + + + + ); } // Create task button if (isOwnerOrAdmin) { actions.push( - } - menu={{ items: dropdownItems }} - trigger={['click']} - onClick={handleCreateTask} - > - {t('createTask')} - + + } + menu={{ items: dropdownItems }} + trigger={['click']} + onClick={handleCreateTask} + > + {t('createTask')} + + ); } else { actions.push( - + + + ); } @@ -451,14 +461,16 @@ const ProjectViewHeader = memo(() => { const pageHeaderTitle = useMemo( () => ( - + + + {selectedProject?.name} {projectAttributes} ), - [handleNavigateToProjects, selectedProject?.name, projectAttributes] + [handleNavigateToProjects, selectedProject?.name, projectAttributes, t] ); // Memoized page header styles diff --git a/worklenz-frontend/src/pages/projects/projectView/project-view.tsx b/worklenz-frontend/src/pages/projects/projectView/project-view.tsx index 32b53f08..a18023f8 100644 --- a/worklenz-frontend/src/pages/projects/projectView/project-view.tsx +++ b/worklenz-frontend/src/pages/projects/projectView/project-view.tsx @@ -32,7 +32,7 @@ import { resetSelection } from '@/features/task-management/selection.slice'; import { resetFields } from '@/features/task-management/taskListFields.slice'; import { fetchLabels } from '@/features/taskAttributes/taskLabelSlice'; import { deselectAll } from '@/features/projects/bulkActions/bulkActionSlice'; -import { tabItems } from '@/lib/project/project-view-constants'; +import { tabItems, updateTabLabels } from '@/lib/project/project-view-constants'; import { setSelectedTaskId, setShowTaskDrawer, @@ -41,6 +41,7 @@ import { import { resetState as resetEnhancedKanbanState } from '@/features/enhanced-kanban/enhanced-kanban.slice'; import { setProjectId as setInsightsProjectId } from '@/features/projects/insights/project-insights.slice'; import { SuspenseFallback } from '@/components/suspense-fallback/suspense-fallback'; +import { useTranslation } from 'react-i18next'; // Import critical components synchronously to avoid suspense interruptions import TaskDrawer from '@components/task-drawer/task-drawer'; @@ -63,13 +64,14 @@ const ProjectView = React.memo(() => { const dispatch = useAppDispatch(); const [searchParams] = useSearchParams(); const { projectId } = useParams(); + const { t } = useTranslation('project-view'); // Memoized selectors to prevent unnecessary re-renders const selectedProject = useAppSelector(state => state.projectReducer.project); const projectLoading = useAppSelector(state => state.projectReducer.projectLoading); // Optimize document title updates - useDocumentTitle(selectedProject?.name || 'Project View'); + useDocumentTitle(selectedProject?.name || t('projectView')); // Memoize URL params to prevent unnecessary state updates const urlParams = useMemo( @@ -174,6 +176,11 @@ const ProjectView = React.memo(() => { setIsInitialized(false); }, [projectId]); + // Update tab labels when language changes + useEffect(() => { + updateTabLabels(); + }, [t]); + // Effect for handling task drawer opening from URL params useEffect(() => { if (taskid && isInitialized) { @@ -287,6 +294,7 @@ const ProjectView = React.memo(() => { e.stopPropagation(); pinToDefaultTab(item.key); }} + title={item.key === pinnedTab ? t('unpinTab') : t('pinTab')} /> )} @@ -296,7 +304,7 @@ const ProjectView = React.memo(() => { })); return menuItems; - }, [pinnedTab, pinToDefaultTab]); + }, [pinnedTab, pinToDefaultTab, t]); // Optimized secondary components loading with better UX const [shouldLoadSecondaryComponents, setShouldLoadSecondaryComponents] = useState(false); diff --git a/worklenz-frontend/src/pages/settings/sidebar/settings-sidebar.tsx b/worklenz-frontend/src/pages/settings/sidebar/settings-sidebar.tsx index b233018a..61f67a94 100644 --- a/worklenz-frontend/src/pages/settings/sidebar/settings-sidebar.tsx +++ b/worklenz-frontend/src/pages/settings/sidebar/settings-sidebar.tsx @@ -24,7 +24,7 @@ const SettingSidebar: React.FC = () => { const items: Required['items'] = accessibleSettings .map(item => { if (currentSession?.is_google && item.key === 'change-password') { - return undefined; + return null; } return { key: item.key, @@ -39,7 +39,7 @@ const SettingSidebar: React.FC = () => { ), }; }) - .filter(Boolean); + .filter((item): item is NonNullable => item !== null); return ( { const { socket } = useSocket(); const refreshTeamMembers = useAppSelector(state => state.memberReducer.refreshTeamMembers); // Listen to refresh flag + useDocumentTitle(t('title') || 'Team Members'); + const [model, setModel] = useState({ total: 0, data: [] }); const [searchQuery, setSearchQuery] = useState(''); const [isLoading, setIsLoading] = useState(false); diff --git a/worklenz-frontend/src/pages/settings/teams/teams-settings.tsx b/worklenz-frontend/src/pages/settings/teams/teams-settings.tsx index a46a10b4..5c21fb0c 100644 --- a/worklenz-frontend/src/pages/settings/teams/teams-settings.tsx +++ b/worklenz-frontend/src/pages/settings/teams/teams-settings.tsx @@ -5,6 +5,7 @@ import { durationDateFormat } from '@utils/durationDateFormat'; import { EditOutlined } from '@ant-design/icons'; import { useEffect, useState } from 'react'; import EditTeamModal from '@/components/settings/edit-team-name-modal'; +import { useTranslation } from 'react-i18next'; import { fetchTeams } from '@features/teams/teamSlice'; import { useAppDispatch } from '@/hooks/useAppDispatch'; @@ -12,7 +13,8 @@ import { useDocumentTitle } from '@/hooks/useDoumentTItle'; import { ITeamGetResponse } from '@/types/teams/team.type'; const TeamsSettings = () => { - useDocumentTitle('Teams'); + const { t } = useTranslation('settings/teams'); + useDocumentTitle(t('title')); const [selectedTeam, setSelectedTeam] = useState(null); const [isModalOpen, setIsModalOpen] = useState(false); @@ -26,27 +28,27 @@ const TeamsSettings = () => { const columns: TableProps['columns'] = [ { key: 'name', - title: 'Name', + title: t('name'), render: (record: ITeamGetResponse) => {record.name}, }, { key: 'created', - title: 'Created', + title: t('created'), render: (record: ITeamGetResponse) => ( {durationDateFormat(record.created_at)} ), }, { key: 'ownsBy', - title: 'Owns By', + title: t('ownsBy'), render: (record: ITeamGetResponse) => {record.owns_by}, }, { key: 'actionBtns', width: 60, render: (record: ITeamGetResponse) => ( - +