From 88acf8c6ba049f71a10ae854d7430a3d32ac544d Mon Sep 17 00:00:00 2001 From: alex Date: Wed, 28 Jun 2023 23:42:04 +0200 Subject: [PATCH] added i18next --- package-lock.json | 131 +++++++++++- package.json | 4 + public/locales/de/translation.json | 156 ++++++++++++++ public/locales/en/translation.json | 156 ++++++++++++++ src/Components/LogCard/index.js | 26 +-- src/Components/SideMenu/index.js | 28 +-- src/Pages/AdminArea/Roles/index.js | 61 ++++-- src/Pages/AllUsers/CreateUserModal.js | 23 +- src/Pages/AllUsers/index.js | 65 ++++-- .../Overview/GroupTasksTableList.js | 178 +++++++++------- .../Overview/GroupTasksViewModal.js | 78 ++++--- .../Overview/GroupTypeSelectionModal.js | 45 ++-- src/Pages/GroupTasks/Overview/index.js | 8 +- src/Pages/PageNotFound/index.js | 7 +- src/Pages/Scanners/index.js | 51 ++--- src/Pages/UserProfile/index.js | 199 ++++++++++-------- src/i18n.js | 22 ++ src/index.js | 9 +- 18 files changed, 929 insertions(+), 318 deletions(-) create mode 100644 public/locales/de/translation.json create mode 100644 public/locales/en/translation.json create mode 100644 src/i18n.js diff --git a/package-lock.json b/package-lock.json index 5eb9003..2c9b142 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,8 +14,12 @@ "@testing-library/user-event": "^13.5.0", "antd": "^5.4.2", "buffer": "^6.0.3", + "i18next": "^23.2.3", + "i18next-browser-languagedetector": "^7.1.0", + "i18next-http-backend": "^2.2.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-i18next": "^13.0.1", "react-qr-scanner": "^1.0.0-alpha.11", "react-router-dom": "^6.10.0", "react-scripts": "5.0.1", @@ -1860,9 +1864,9 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "node_modules/@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.5.tgz", + "integrity": "sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==", "dependencies": { "regenerator-runtime": "^0.13.11" }, @@ -6413,6 +6417,14 @@ "node": ">=10" } }, + "node_modules/cross-fetch": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", + "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", + "dependencies": { + "node-fetch": "^2.6.11" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -9202,6 +9214,14 @@ "node": ">=12" } }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "dependencies": { + "void-elements": "3.1.0" + } + }, "node_modules/html-webpack-plugin": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", @@ -9336,6 +9356,44 @@ "node": ">=10.17.0" } }, + "node_modules/i18next": { + "version": "23.2.3", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.2.3.tgz", + "integrity": "sha512-5spO7L0rNmW0jFuNhz+gfirlFt1anle4mTy4+gFkgsH0+T3R5++4oncBrzeKa7v8pweRyGBoGmOpboqlxovg6A==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "dependencies": { + "@babel/runtime": "^7.22.5" + } + }, + "node_modules/i18next-browser-languagedetector": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.1.0.tgz", + "integrity": "sha512-cr2k7u1XJJ4HTOjM9GyOMtbOA47RtUoWRAtt52z43r3AoMs2StYKyjS3URPhzHaf+mn10hY9dZWamga5WPQjhA==", + "dependencies": { + "@babel/runtime": "^7.19.4" + } + }, + "node_modules/i18next-http-backend": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.2.1.tgz", + "integrity": "sha512-ZXIdn/8NJIBJ0X4hzXfc3STYxKrCKh1fYjji9HPyIpEJfvTvy8/ZlTl8RuTizzCPj2ZcWrfaecyOMKs6bQ7u5A==", + "dependencies": { + "cross-fetch": "3.1.6" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -12650,6 +12708,44 @@ "tslib": "^2.0.3" } }, + "node_modules/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -15435,6 +15531,27 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, + "node_modules/react-i18next": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-13.0.1.tgz", + "integrity": "sha512-gMO6N2GfSfuH7xlHSsZ/mZf+Py9bLm/+EDKIn5fNTuDTjcCcwmMU5UEuGCDk5mdfivbo7ySyYXBN7B9tbGUxiA==", + "dependencies": { + "@babel/runtime": "^7.22.5", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 23.2.3", + "react": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -17683,6 +17800,14 @@ "node": ">= 0.8" } }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", diff --git a/package.json b/package.json index 08d52ff..0d829cf 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,12 @@ "@testing-library/user-event": "^13.5.0", "antd": "^5.4.2", "buffer": "^6.0.3", + "i18next": "^23.2.3", + "i18next-browser-languagedetector": "^7.1.0", + "i18next-http-backend": "^2.2.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-i18next": "^13.0.1", "react-qr-scanner": "^1.0.0-alpha.11", "react-router-dom": "^6.10.0", "react-scripts": "5.0.1", diff --git a/public/locales/de/translation.json b/public/locales/de/translation.json new file mode 100644 index 0000000..1f79f88 --- /dev/null +++ b/public/locales/de/translation.json @@ -0,0 +1,156 @@ +{ + "contactAdmin": "Bitte kontaktieren Sie einen Administrator", + "buttonCancel": "Abbrechen", + "buttonClose": "Schließen", + "buttonSave": "Speichern", + "sideMenu.dashboard": "Dashboard", + "sideMenu.groupTasks": "Gruppenaufgaben", + "sideMenu.groupTasks.overview": "Übersicht", + "sideMenu.groupTasks.history": "Verlauf", + "sideMenu.adminArea": "Adminbereich", + "sideMenu.adminArea.roles": "Rollen", + "sideMenu.adminArea.logs": "Logs", + "sideMenu.adminArea.noScannerSelected": "Kein Scanner ausgewählt", + "sideMenu.usersCount": "Benutzer online", + "sideMenu.usersCount.multiple": "Benutzer online", + "sideMenu.logout": "Abmelden", + "groupTasks.categoryGroups.length0": "Keine Gruppenaufgaben gefunden", + "groupTasks.categoryGroups.assignedToNoTask.title": "Sie wurden keiner Gruppenaufgabe zugewiesen", + "groupTasks.groupTypeSelectionModal.notification.globalInputsCannotBeEmpty.message": "Globale Eingaben können nicht leer sein", + "groupTasks.groupTypeSelectionModal.notification.globalInputsCannotBeEmpty.description": "Bitte füllen Sie alle globalen Eingaben aus", + "groupTasks.groupTypeSelectionModal.title": "Wählen Sie einen Gruppentyp", + "groupTasks.groupTypeSelectionModal.button.startTask": "Aufgabe starten", + "groupTasks.groupTypeSelectionModal.select.placeholder": "Wählen Sie einen Gruppentyp", + "groupTasks.groupTypeSelectionModal.form.item.groupTypeDescription.label": "Beschreibung", + "groupTasks.groupTypeSelectionModal.form.item.groupTypeDescription.tooltip.title": "Diese Beschreibung hilft, im Nachhinein zu verstehen, worum es bei dieser Aufgabe ging", + "groupTasks.tag.global": "Global", + "groupTasks.groupTypeSelectionModal.notification.globalInputTypeNotImplemented.message": "Typ {{globalInputType}} nicht implementiert", + "groupTasks.groupTypeSelectionModal.notification.globalInputTypeNotImplemented.description": "Wurde festgelegt in: {{globalInputDisplayName}}", + "groupTasks.groupTypeSelectionModal.h3": "Füllen Sie die globalen Werte aus", + "groupTasks.groupTasksViewModal.groupTaskNotFound": "Gruppenaufgabe nicht gefunden", + "groupTasks.groupTasksViewModal.notification.inputsCannotBeEmpty.message": "Eingaben können nicht leer sein", + "groupTasks.groupTasksViewModal.notification.inputsCannotBeEmpty.description": "Bitte füllen Sie alle Felder aus", + "groupTasks.groupTasksViewModal.button.tryAgain": "Erneut versuchen", + "groupTasks.groupTasksViewModal.button.continue": "Weiter", + "groupTasks.groupTasksViewModal.popover.specifiedTaskInputs": "Spezifizierte Aufgaben-Eingaben", + "groupTasks.groupTasksViewModal.startedAt": "Gestartet am", + "groupTasks.groupTasksViewModal.endedAt": "Beendet am", + "groupTasks.groupTasksViewModal.duration": "Laufzeit", + "groupTasks.groupTasksViewModal.category": "Kategorie", + "groupTasks.groupTasksViewModal.popover.details": "Einzelheiten", + "groupTasks.groupTasksViewModal.popover.specifiedGlobalInputs": "Spezifizierte globale Eingaben", + "groupTasks.groupTasksViewModal.notification.groupTaskParameterNotImplemented.message": "Typ {{groupTaskParameterType}} nicht implementiert", + "groupTasks.groupTasksViewModal.notification.groupTaskParameterNotImplemented.description": "Wurde festgelegt in: {{groupTaskParameterDisplayName}}", + "groupTasks.groupTasksViewModal.alertMessage.successful": "Erfolgreich", + "groupTasks.groupTasksViewModal.alertMessage.taskIsRunning": "Aufgabe wird ausgeführt", + "groupTasks.groupTasksViewModal.alertMessage.taskCanceled": "Aufgabe abgebrochen", + "groupTasks.groupTasksViewModal.alertMessage.taskFailed": "Aufgabe fehlgeschlagen", + "groupTasks.groupTasksViewModal.alertMessage.taskInputRequired": "Eingabe erforderlich", + "groupTasks.groupTasksTableList.column.creator": "Ersteller", + "groupTasks.groupTasksTableList.column.groupName": "Gruppenname", + "groupTasks.groupTasksTableList.column.description": "Beschreibung", + "groupTasks.groupTasksTableList.column.step": "Schritt", + "groupTasks.groupTasksTableList.column.status": "Status", + "groupTasks.groupTasksTableList.column.startedAt": "Gestartet am", + "groupTasks.groupTasksTableList.column.endedAt": "Beendet am", + "groupTasks.groupTasksTableList.column.duration": "Laufzeit", + "groupTasks.groupTasksTableList.column.action": "Maßnahme", + "groupTasks.groupTasksTableList.column.action.view": "Ansehen", + "groupTasks.groupTasksTableList.statusBadge.finished": "Abgeschlossen", + "groupTasks.groupTasksTableList.statusBadge.running": "Laufend", + "groupTasks.groupTasksTableList.statusBadge.canceled": "Abgebrochen", + "groupTasks.groupTasksTableList.statusBadge.failed": "Fehlgeschlagen", + "groupTasks.groupTasksTableList.statusBadge.inputRequired": "Eingabe erforderlich", + "groupTasks.groupTasksTableList.button.newTask": "Neue Aufgabe", + "groupTasks.groupTasksTableList.button.reload": "Neu laden", + "groupTasks.groupTasksTableList.popover.title": "Sind Sie sicher, dass Sie die Gruppenkonfigurationen neu laden wollen?", + "groupTasks.groupTasksTableList.popover.buttonOk": "Ja", + "logCard.popover.groupTaskId.title": "Gruppenaufgabe", + "logCard.popover.groupTaskStep.title": "Gruppenaufgabe Schritt", + "logCard.popover.role.title": "Rolle", + "logCard.card.checkbox.info": "INFO", + "logCard.card.checkbox.error": "FEHLER", + "logCard.tooltip.previous": "Vorige", + "logCard.tooltip.next": "Nächste", + "logCard.tooltip.reload": "Neu laden", + "pageNotFound.subTitle": "Die Seite, die Sie besucht haben, existiert leider nicht.", + "pageNotFound.buttonBackHome": "Zurück zur Startseite", + "allUsers.column.avatar": "Avatar", + "allUsers.column.username": "Benutzername", + "allUsers.column.role": "Rolle", + "allUsers.column.connectionStatus": "Verbindungsstatus", + "allUsers.column.lastOnline": "Zuletzt online", + "allUsers.column.action": "Maßnahme", + "allUsers.column.action.roleChange.popconfirm.title": "Rolle ändern in", + "allUsers.column.action.roleChange.popconfirm.okText": "Ändern", + "allUsers.column.action.changeRole": "Rolle ändern", + "allUsers.column.action.delete.popconfirm.okText": "User löschen", + "allUsers.column.action.delete.popconfirm.title": "Sind Sie sicher, dass Sie den Benutzer löschen wollen?", + "allUsers.column.action.delete": "Löschen", + "allUsers.column.action.deactivate.popconfirm.okText": "Benutzer deaktivieren", + "allUsers.column.action.deactivate.popconfirm.title": "Sind Sie sicher, dass Sie den Benutzer deaktivieren wollen?", + "allUsers.column.action.deactivate": "Deaktivieren", + "allUsers.column.action.activate.popconfirm.okText": "Benutzer aktivieren", + "allUsers.column.action.activate.popconfirm.title": "Sind Sie sicher, dass Sie den Benutzer aktivieren wollen?", + "allUsers.column.action.activate": "Aktivieren", + "allUsers.roleChangeError.notification.message": "Benutzerrolle konnte nicht geändert werden", + "allUsers.roleChangeError.notification.description": "Die Rolle existiert nicht mehr", + "allUsers.header.allUsers": "Alle Benutzer", + "allUsers.button.createNewUser": "Neuen Benutzer anlegen", + "allUsers.header.deactivatedUsers": "Deaktivierte Benutzer", + "allUsers.createUserModal.title": "Einen neuen Benutzer anlegen", + "allUsers.createUserModal.okText": "Benutzer anlegen", + "allUsers.createUserModal.form.username": "Benutzername", + "allUsers.createUserModal.form.email": "E-Mail", + "allUsers.createUserModal.form.password": "Passwort", + "allUsers.createUserModal.form.role": "Rolle", + "allUsers.createUserModal.form.role.placeholder": "Wählen Sie eine Rolle", + "adminArea.createNewRole.popconfirm.okText": "Erstellen", + "adminArea.createNewRole.popconfirm.title": "Sind Sie sicher, dass Sie eine neue Rolle anlegen wollen?", + "adminArea.createNewRole.button": "Neue Rolle erstellen", + "adminArea.roleUpdate.errorDisplayNameToShort.notification.message": "Der angezeigte Name muss größer sein als {{MIN_ROLE_DISPLAY_NAME}} sein", + "adminArea.roleUpdate.errorDisplayNameToShort.notification.description": "Bitte geben Sie einen längeren Anzeigenamen ein", + "adminArea.roleUpdate.errorDisplayNameToLong.notification.message": "Der Anzeigename muss kleiner sein als {{MAX_ROLE_DISPLAY_NAME}} sein", + "adminArea.roleUpdate.errorDisplayNameToLong.notification.description": "Bitte geben Sie einen kürzeren Anzeigenamen ein", + "adminArea.roleUpdate.errorDescriptionToLong.notification.message": "Die Beschreibung muss kleiner sein als {{MAX_ROLE_DESCRIPTION}} sein", + "adminArea.roleUpdate.errorDescriptionToLong.notification.description": "Bitte geben Sie eine kürzere Beschreibung ein", + "adminArea.deleteRole.popconfirm.title": "Rolle löschen", + "adminArea.deleteRole.popconfirm.description": "Sind Sie sicher, dass Sie diese Rolle löschen wollen?", + "adminArea.deleteRole.tooltip.title": "Löschen", + "adminArea.moveRoleUp.tooltip.title": "Rolle nach oben verschieben", + "adminArea.moveRoleDown.tooltip.title": "Rolle nach unten verschieben", + "adminArea.save.tooltip.title": "Speichern", + "adminArea.close.tooltip.title": "Schließen", + "adminArea.edit.tooltip.title": "Bearbeiten", + "adminArea.masterRoleRightsMessage": "Rechte können nicht bearbeitet werden, da diese Rolle der Master ist und alle Rechte besitzt.", + "userProfile.header.yourProfile": "Ihr Profil", + "userProfile.column.userAgent": "User-Agent", + "userProfile.column.connectionStatus": "Verbindungsstatus", + "userProfile.column.lastUsed": "Zuletzt verwendet", + "userProfile.column.expiresAt": "Läuft ab am", + "userProfile.column.action": "Maßnahme", + "userProfile.column.action.signOut": "Abmelden", + "userProfile.changeAvatarError.notification.message": "Ihr Avatar konnte nicht geändert werden", + "userProfile.changeAvatarError.notification.description": "Avatar muss kleiner sein als {{MAX_AVATAR_SIZE}} MB sein", + "userProfile.form.username": "Benutzername", + "userProfile.form.email": "E-Mail", + "userProfile.form.oldPassword": "Altes passwort", + "userProfile.form.newPassword": "Neues passwort", + "userProfile.form.repeatNewPassword": "Neues Passwort wiederholen", + "userProfile.form.language": "Sprache", + "userProfile.header.yourSessions": "Ihre Sitzungen", + "scanners.column.name": "Name", + "scanners.column.usedBy": "Verwendet von", + "scanners.column.lastUsed": "Zuletzt verwendet", + "scanners.column.registeredAt": "Registriert am", + "scanners.column.userAgent": "User-Agent", + "scanners.column.action": "Maßnahme", + "scanners.column.action.disconnect.popconfirm.title": "Sind Sie sicher, dass Sie die Verbindung zu diesem Scanner trennen wollen?", + "scanners.column.action.disconnect.popconfirm.okText": "Verbindung trennen", + "scanners.column.action.disconnect": "Verbindung trennen", + "scanners.column.action.use.popconfirm.title": "Sind Sie sicher, dass Sie diesen Scanner verwenden möchten?", + "scanners.column.action.use.popconfirm.description": "Benutzer, die mit diesem Scanner verbunden sind, werden von der Verbindung getrennt.", + "scanners.column.action.use.popconfirm.okText": "Verwenden", + "scanners.column.action.use": "Scanner verwenden", + "scanners.header.scanners": "Scanner" +} diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json new file mode 100644 index 0000000..eb0a57c --- /dev/null +++ b/public/locales/en/translation.json @@ -0,0 +1,156 @@ +{ + "contactAdmin": "Please contact an administrator", + "buttonCancel": "Cancel", + "buttonClose": "Close", + "buttonSave": "Save", + "sideMenu.dashboard": "Dashboard", + "sideMenu.groupTasks": "Group Tasks", + "sideMenu.groupTasks.overview": "Overview", + "sideMenu.groupTasks.history": "History", + "sideMenu.adminArea": "Admin Area", + "sideMenu.adminArea.roles": "Roles", + "sideMenu.adminArea.logs": "Logs", + "sideMenu.adminArea.noScannerSelected": "No scanner selected", + "sideMenu.usersCount": "user connected", + "sideMenu.usersCount.multiple": "users connected", + "sideMenu.logout": "Logout", + "groupTasks.categoryGroups.length0": "No group tasks found", + "groupTasks.categoryGroups.assignedToNoTask.title": "You were not assigned to any group tasks", + "groupTasks.groupTypeSelectionModal.notification.globalInputsCannotBeEmpty.message": "Global inputs cannot be empty", + "groupTasks.groupTypeSelectionModal.notification.globalInputsCannotBeEmpty.description": "Please fill in all global inputs", + "groupTasks.groupTypeSelectionModal.title": "Select a group type", + "groupTasks.groupTypeSelectionModal.button.startTask": "Start task", + "groupTasks.groupTypeSelectionModal.select.placeholder": "Choose a group type", + "groupTasks.groupTypeSelectionModal.form.item.groupTypeDescription.label": "Description", + "groupTasks.groupTypeSelectionModal.form.item.groupTypeDescription.tooltip.title": "This description helps to understand afterwards what this task was about", + "groupTasks.tag.global": "Global", + "groupTasks.groupTypeSelectionModal.notification.globalInputTypeNotImplemented.message": "Type {{globalInputType}} not implemented", + "groupTasks.groupTypeSelectionModal.notification.globalInputTypeNotImplemented.description": "Was specified in: {{globalInputDisplayName}}", + "groupTasks.groupTypeSelectionModal.h3": "Fill in the global values", + "groupTasks.groupTasksViewModal.groupTaskNotFound": "Group Task not found", + "groupTasks.groupTasksViewModal.notification.inputsCannotBeEmpty.message": "Inputs cannot be empty", + "groupTasks.groupTasksViewModal.notification.inputsCannotBeEmpty.description": "Please fill in all inputs", + "groupTasks.groupTasksViewModal.button.tryAgain": "Try again", + "groupTasks.groupTasksViewModal.button.continue": "Continue", + "groupTasks.groupTasksViewModal.popover.specifiedTaskInputs": "Specified Task Inputs", + "groupTasks.groupTasksViewModal.startedAt": "Started at", + "groupTasks.groupTasksViewModal.endedAt": "Ended at", + "groupTasks.groupTasksViewModal.duration": "Duration", + "groupTasks.groupTasksViewModal.category": "Category", + "groupTasks.groupTasksViewModal.popover.details": "Details", + "groupTasks.groupTasksViewModal.popover.specifiedGlobalInputs": "Specified Global Inputs", + "groupTasks.groupTasksViewModal.notification.groupTaskParameterNotImplemented.message": "Type {{groupTaskParameterType}} not implemented", + "groupTasks.groupTasksViewModal.notification.groupTaskParameterNotImplemented.description": "Was specified in: {{groupTaskParameterDisplayName}}", + "groupTasks.groupTasksViewModal.alertMessage.successful": "Successful", + "groupTasks.groupTasksViewModal.alertMessage.taskIsRunning": "Task is running", + "groupTasks.groupTasksViewModal.alertMessage.taskCanceled": "Task canceled", + "groupTasks.groupTasksViewModal.alertMessage.taskFailed": "Task failed", + "groupTasks.groupTasksViewModal.alertMessage.taskInputRequired": "Input required", + "groupTasks.groupTasksTableList.column.creator": "Creator", + "groupTasks.groupTasksTableList.column.groupName": "Group Name", + "groupTasks.groupTasksTableList.column.description": "Description", + "groupTasks.groupTasksTableList.column.step": "Step", + "groupTasks.groupTasksTableList.column.status": "Status", + "groupTasks.groupTasksTableList.column.startedAt": "Started At", + "groupTasks.groupTasksTableList.column.endedAt": "Ended At", + "groupTasks.groupTasksTableList.column.duration": "Duration", + "groupTasks.groupTasksTableList.column.action": "Action", + "groupTasks.groupTasksTableList.column.action.view": "View", + "groupTasks.groupTasksTableList.statusBadge.finished": "Finished", + "groupTasks.groupTasksTableList.statusBadge.running": "Running", + "groupTasks.groupTasksTableList.statusBadge.canceled": "Canceled", + "groupTasks.groupTasksTableList.statusBadge.failed": "Failed", + "groupTasks.groupTasksTableList.statusBadge.inputRequired": "Input required", + "groupTasks.groupTasksTableList.button.newTask": "New task", + "groupTasks.groupTasksTableList.button.reload": "Reload", + "groupTasks.groupTasksTableList.popover.title": "Are you sure you want to reload the group configs?", + "groupTasks.groupTasksTableList.popover.buttonOk": "Yes", + "logCard.popover.groupTaskId.title": "Group Task", + "logCard.popover.groupTaskStep.title": "Group Task Step", + "logCard.popover.role.title": "Role", + "logCard.card.checkbox.info": "INFO", + "logCard.card.checkbox.error": "ERROR", + "logCard.tooltip.previous": "Previous", + "logCard.tooltip.next": "Next", + "logCard.tooltip.reload": "Reload", + "pageNotFound.subTitle": "Sorry, the page you visited does not exist.", + "pageNotFound.buttonBackHome": "Back Home", + "allUsers.column.avatar": "Avatar", + "allUsers.column.username": "Username", + "allUsers.column.role": "Role", + "allUsers.column.connectionStatus": "Connection status", + "allUsers.column.lastOnline": "Last online", + "allUsers.column.action": "Action", + "allUsers.column.action.roleChange.popconfirm.title": "Change role to", + "allUsers.column.action.roleChange.popconfirm.okText": "Change", + "allUsers.column.action.changeRole": "Change role", + "allUsers.column.action.delete.popconfirm.okText": "Delete user", + "allUsers.column.action.delete.popconfirm.title": "Are you sure you want to delete the user?", + "allUsers.column.action.delete": "Delete", + "allUsers.column.action.deactivate.popconfirm.okText": "Deactivate user", + "allUsers.column.action.deactivate.popconfirm.title": "Are you sure you want to deactivate the user?", + "allUsers.column.action.deactivate": "Deactivate", + "allUsers.column.action.activate.popconfirm.okText": "Activate user", + "allUsers.column.action.activate.popconfirm.title": "Are you sure you want to activate the user?", + "allUsers.column.action.activate": "Activate", + "allUsers.roleChangeError.notification.message": "User role could not be changed", + "allUsers.roleChangeError.notification.description": "The role does not exist anymore", + "allUsers.header.allUsers": "All users", + "allUsers.button.createNewUser": "Create new user", + "allUsers.header.deactivatedUsers": "Deactivated users", + "allUsers.createUserModal.title": "Create a new user", + "allUsers.createUserModal.okText": "Create user", + "allUsers.createUserModal.form.username": "Username", + "allUsers.createUserModal.form.email": "E-Mail", + "allUsers.createUserModal.form.password": "Password", + "allUsers.createUserModal.form.role": "Role", + "allUsers.createUserModal.form.role.placeholder": "Select a role", + "adminArea.createNewRole.popconfirm.okText": "Create", + "adminArea.createNewRole.popconfirm.title": "Are you sure you want to create a new role?", + "adminArea.createNewRole.button": "Create new role", + "adminArea.roleUpdate.errorDisplayNameToShort.notification.message": "Display name must be greater than {{MIN_ROLE_DISPLAY_NAME}}", + "adminArea.roleUpdate.errorDisplayNameToShort.notification.description": "Please enter a longer display name", + "adminArea.roleUpdate.errorDisplayNameToLong.notification.message": "Display name must be less than {{MIN_ROLE_DISPLAY_NAME}}", + "adminArea.roleUpdate.errorDisplayNameToLong.notification.description": "Please enter a shorter display name", + "adminArea.roleUpdate.errorDescriptionToLong.notification.message": "Description must be less than {{MAX_ROLE_DESCRIPTION}}", + "adminArea.roleUpdate.errorDescriptionToLong.notification.description": "Please enter a shorter description", + "adminArea.deleteRole.popconfirm.title": "Delete role", + "adminArea.deleteRole.popconfirm.description": "Are you sure to delete this role?", + "adminArea.deleteRole.tooltip.title": "Delete", + "adminArea.moveRoleUp.tooltip.title": "Move role up", + "adminArea.moveRoleDown.tooltip.title": "Move role down", + "adminArea.save.tooltip.title": "Save", + "adminArea.close.tooltip.title": "Close", + "adminArea.edit.tooltip.title": "Edit", + "adminArea.masterRoleRightsMessage": "Rights cannot be edited, because this role is the master and has all rights.", + "userProfile.header.yourProfile": "Your profile", + "userProfile.column.userAgent": "User-Agent", + "userProfile.column.connectionStatus": "Connection status", + "userProfile.column.lastUsed": "Last used", + "userProfile.column.expiresAt": "Expires at", + "userProfile.column.action": "Action", + "userProfile.column.action.signOut": "Sign out", + "userProfile.changeAvatarError.notification.message": "Your avatar could not be changed", + "userProfile.changeAvatarError.notification.description": "Avatar must be smaller than {{MAX_AVATAR_SIZE}} MB", + "userProfile.form.username": "Username", + "userProfile.form.email": "E-Mail", + "userProfile.form.oldPassword": "Old password", + "userProfile.form.newPassword": "New password", + "userProfile.form.repeatNewPassword": "Repeat new password", + "userProfile.form.language": "Language", + "userProfile.header.yourSessions": "Your sessions", + "scanners.column.name": "Name", + "scanners.column.usedBy": "Used by", + "scanners.column.lastUsed": "Last used", + "scanners.column.registeredAt": "Registered at", + "scanners.column.userAgent": "User-Agent", + "scanners.column.action": "Action", + "scanners.column.action.disconnect.popconfirm.title": "Are you sure you want to disconnect from this scanner?", + "scanners.column.action.disconnect.popconfirm.okText": "Disconnect", + "scanners.column.action.disconnect": "Disconnect", + "scanners.column.action.use.popconfirm.title": "Are you sure you want to use this scanner?", + "scanners.column.action.use.popconfirm.description": "Users connected to this scanner will be disconnected", + "scanners.column.action.use.popconfirm.okText": "Use", + "scanners.column.action.use": "Use scanner", + "scanners.header.scanners": "Scanners" +} diff --git a/src/Components/LogCard/index.js b/src/Components/LogCard/index.js index 1ffad6a..303ca6a 100644 --- a/src/Components/LogCard/index.js +++ b/src/Components/LogCard/index.js @@ -13,9 +13,11 @@ import { handleUnauthorizedStatus, } from "../../utils"; import { Link } from "react-router-dom"; +import { useTranslation } from "react-i18next"; export default function LogCard({ type }) { const webSocketContext = useContext(WebSocketContext); + const { t } = useTranslation(); const [checkboxInfoChecked, setCheckboxInfoChecked] = useState(true); const [checkboxErrorChecked, setCheckboxErrorChecked] = useState(true); @@ -38,14 +40,6 @@ export default function LogCard({ type }) { const colorIndex = index % colorCodes.length; return colorCodes[colorIndex]; }; - /* - const getLogDataValue = (logData, splittedMessage) => { - const logDataIndex = logData.findIndex( - (data) => data.Type === splittedMessage.replace(new RegExp("%", "g"), "") - ); - - return logData[logDataIndex].Value; - };*/ const ColoredSpanItem = ({ dataLogs, splittedMessage, children }) => { const logDataIndex = dataLogs.LogData.findIndex( @@ -187,7 +181,7 @@ export default function LogCard({ type }) { } - title="Group Task" + title={t("logCard.popover.groupTaskId.title")} trigger="click" > @@ -236,7 +230,7 @@ export default function LogCard({ type }) { } - title="Group Task Step" + title={t("logCard.popover.groupTaskStep.title")} trigger="click" > {" "} @@ -281,7 +275,7 @@ export default function LogCard({ type }) { {foundData.Value} } - title="Role" + title={t("logCard.popover.role.title")} trigger="click" > {" "} @@ -358,17 +352,17 @@ export default function LogCard({ type }) { checked={checkboxInfoChecked} onChange={(e) => setCheckboxInfoChecked(e.target.checked)} > - INFO + {t("logCard.card.checkbox.info")} setCheckboxErrorChecked(e.target.checked)} > - ERROR + {t("logCard.card.checkbox.error")} {logData.Dates.findIndex((date) => date === selectedDate) > 0 ? ( - + setSelectedDate( @@ -391,7 +385,7 @@ export default function LogCard({ type }) { {logData.Dates.findIndex((date) => date === selectedDate) + 1 < logData.Dates.length ? ( - + setSelectedDate( @@ -412,7 +406,7 @@ export default function LogCard({ type }) { /> )} - + loadLogs(selectedDate)} /> diff --git a/src/Components/SideMenu/index.js b/src/Components/SideMenu/index.js index cdf86d6..74156af 100644 --- a/src/Components/SideMenu/index.js +++ b/src/Components/SideMenu/index.js @@ -21,11 +21,13 @@ import { hasOnePermission, hasPermission, } from "../../utils"; +import { useTranslation } from "react-i18next"; export default function SideMenu({ userSession, setUserSession }) { const location = useLocation(); const [selectedKeys, setSelectedKeys] = useState("/"); const webSocketContext = useContext(WebSocketContext); + const { t } = useTranslation(); useEffect(() => { const pathName = location.pathname; @@ -39,24 +41,26 @@ export default function SideMenu({ userSession, setUserSession }) { (scanner) => scanner.UsedByUserId === getUserId() )?.Name; - return scannerName === undefined ? "No scanner selected" : scannerName; + return scannerName === undefined + ? t("sideMenu.adminArea.noScannerSelected") + : scannerName; }; const getFirstMenuItems = () => { let items = [ { - label: "Dashboard", + label: t("sideMenu.dashboard"), icon: , key: "/", }, ]; let groupTasks = { - label: "Group Tasks", + label: t("sideMenu.groupTasks"), type: "group", children: [ { - label: "Overview", + label: t("sideMenu.groupTasks.overview"), icon: , key: "/group-tasks", }, @@ -70,7 +74,7 @@ export default function SideMenu({ userSession, setUserSession }) { ) ) { groupTasks.children.push({ - label: "History", + label: t("sideMenu.groupTasks.history"), icon: , key: "/group-tasks-history", }); @@ -93,7 +97,7 @@ export default function SideMenu({ userSession, setUserSession }) { ) ) { let adminArea = { - label: "Admin Area", + label: t("sideMenu.adminArea"), icon: , key: "/admin-area", children: [], @@ -109,7 +113,7 @@ export default function SideMenu({ userSession, setUserSession }) { ) ) { adminArea.children.push({ - label: "Roles", + label: t("sideMenu.adminArea.roles"), icon: , key: "/admin-area/roles", }); @@ -122,7 +126,7 @@ export default function SideMenu({ userSession, setUserSession }) { ) ) { adminArea.children.push({ - label: "Logs", + label: t("sideMenu.adminArea.logs"), icon: , key: "/admin-area/logs", }); @@ -157,9 +161,9 @@ export default function SideMenu({ userSession, setUserSession }) { status={webSocketContext.ConnectionBadgeStatus} text={`${webSocketContext.ConnectedWebSocketUsersCount} ${ webSocketContext.ConnectedWebSocketUsersCount === 1 - ? "user" - : "users" - } connected`} + ? t("sideMenu.usersCount") + : t("sideMenu.usersCount.multiple") + }`} /> ), key: "/users", @@ -175,7 +179,7 @@ export default function SideMenu({ userSession, setUserSession }) { key: "/user-profile", }, { - label: "Logout", + label: t("sideMenu.logout"), icon: , onClick: () => { setUserSession(); diff --git a/src/Pages/AdminArea/Roles/index.js b/src/Pages/AdminArea/Roles/index.js index c08698a..3872d23 100644 --- a/src/Pages/AdminArea/Roles/index.js +++ b/src/Pages/AdminArea/Roles/index.js @@ -28,8 +28,10 @@ import { SaveOutlined, } from "@ant-design/icons"; import { useContext, useState } from "react"; +import { useTranslation } from "react-i18next"; export default function AdminAreaRoles() { + const { t } = useTranslation(); const webSocketContext = useContext(WebSocketContext); const [notificationApi, notificationContextHolder] = notification.useNotification(); @@ -133,12 +135,13 @@ export default function AdminAreaRoles() { > onCreateNewRoleClick()} > @@ -148,6 +151,7 @@ export default function AdminAreaRoles() { } function Role({ treeData, role, webSocketContext, notificationApi }) { + const { t } = useTranslation(); const [editMode, setEditMode] = useState(false); const [roleDisplayName, setRoleDisplayName] = useState(""); const [roleDescription, setRoleDescription] = useState(""); @@ -169,7 +173,7 @@ function Role({ treeData, role, webSocketContext, notificationApi }) { const [checkedTreeKeyPermissions, setCheckedTreeKeyPermissions] = useState(rolePermissions); - const onTreeCheck = (checkedKeys, info) => + const onTreeCheck = (checkedKeys) => setCheckedTreeKeyPermissions(checkedKeys); const getMasterPermissions = () => { @@ -245,8 +249,13 @@ function Role({ treeData, role, webSocketContext, notificationApi }) { changes.DisplayName.length < Constants.GLOBALS.MIN_ROLE_DISPLAY_NAME ) { notificationApi["error"]({ - message: `Display name must be greater than ${Constants.GLOBALS.MIN_ROLE_DISPLAY_NAME}`, - description: `Please enter a longer display name`, + message: t( + "adminArea.roleUpdate.errorDisplayNameToShort.notification.message", + { MIN_ROLE_DISPLAY_NAME: Constants.GLOBALS.MIN_ROLE_DISPLAY_NAME } + ), + description: t( + "adminArea.roleUpdate.errorDisplayNameToShort.notification.description" + ), }); return; } @@ -254,8 +263,13 @@ function Role({ treeData, role, webSocketContext, notificationApi }) { changes.DisplayName.length > Constants.GLOBALS.MAX_ROLE_DISPLAY_NAME ) { notificationApi["error"]({ - message: `Display name must be less than ${Constants.GLOBALS.MAX_ROLE_DISPLAY_NAME}`, - description: `Please enter a shorter display name`, + message: t( + "adminArea.roleUpdate.errorDisplayNameToLong.notification.message", + { MAX_ROLE_DISPLAY_NAME: Constants.GLOBALS.MAX_ROLE_DISPLAY_NAME } + ), + description: t( + "adminArea.roleUpdate.errorDisplayNameToLong.notification.description" + ), }); return; } @@ -266,8 +280,13 @@ function Role({ treeData, role, webSocketContext, notificationApi }) { changes.Description.length > Constants.GLOBALS.MAX_ROLE_DESCRIPTION ) { notificationApi["error"]({ - message: `Description must be less than ${Constants.GLOBALS.MAX_ROLE_DESCRIPTION}`, - description: `Please enter a shorter description`, + message: t( + "adminArea.roleUpdate.errorDescriptionToLong.notification.message", + { MAX_ROLE_DESCRIPTION: Constants.GLOBALS.MAX_ROLE_DESCRIPTION } + ), + description: t( + "adminArea.roleUpdate.errorDescriptionToLong.notification.description" + ), }); return; } @@ -381,12 +400,15 @@ function Role({ treeData, role, webSocketContext, notificationApi }) { /> ) : ( } + cancelText={t("buttonCancel")} onConfirm={() => onDeleteClick()} > - + @@ -407,7 +429,7 @@ function Role({ treeData, role, webSocketContext, notificationApi }) { }} /> ) : ( - + onMoveUpClick()} /> )} @@ -419,7 +441,7 @@ function Role({ treeData, role, webSocketContext, notificationApi }) { }} /> ) : ( - + onMoveDownClick()} /> )} @@ -430,12 +452,12 @@ function Role({ treeData, role, webSocketContext, notificationApi }) { webSocketContext.User.Permissions, Constants.PERMISSIONS.ADMIN_AREA.ROLES.UPDATE_ROLE ) && ( - + onSaveClick()} /> )} - + onCloseClick()} /> @@ -443,7 +465,7 @@ function Role({ treeData, role, webSocketContext, notificationApi }) { - + onEditClick()} /> @@ -491,8 +513,7 @@ function Role({ treeData, role, webSocketContext, notificationApi }) { <> {role.Master && editMode && (

- Rights cannot be edited, because this role is the master and - has all rights. + {t("adminArea.masterRoleRightsMessage")}

)} diff --git a/src/Pages/AllUsers/CreateUserModal.js b/src/Pages/AllUsers/CreateUserModal.js index e74d4cc..4418107 100644 --- a/src/Pages/AllUsers/CreateUserModal.js +++ b/src/Pages/AllUsers/CreateUserModal.js @@ -8,9 +8,11 @@ import { isEmailValid, } from "../../utils"; import { useContext, useState } from "react"; +import { useTranslation } from "react-i18next"; export default function CreateUserModal({ isModalOpen, setIsModalOpen }) { const webSocketContext = useContext(WebSocketContext); + const { t } = useTranslation(); const [username, setUsername] = useState(""); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); @@ -55,18 +57,19 @@ export default function CreateUserModal({ isModalOpen, setIsModalOpen }) { return ( setIsModalOpen(false)} onOk={() => onConfirmUserCreation()} >
setUsername(e.target.value)} minLength={Constants.GLOBALS.MIN_USERNAME_LENGTH} @@ -83,19 +86,19 @@ export default function CreateUserModal({ isModalOpen, setIsModalOpen }) { /> setEmail(e.target.value)} type="email" /> setPassword(e.target.value)} minLength={Constants.GLOBALS.MIN_PASSWORD_LENGTH} maxLength={Constants.GLOBALS.MAX_PASSWORD_LENGTH} /> - + setCurrentSelectedModalGroupType(value)} @@ -188,10 +194,13 @@ export default function GroupTypeSelectionModal({
, }} required @@ -215,12 +224,14 @@ function GroupGlobalInputs({ currentSelectedModalGroupType, notificationApi, }) { + const { t } = useTranslation(); + const getLabel = (displayName) => { return ( <> {displayName} - Global + {t("groupTasks.tag.global")} ); @@ -275,8 +286,14 @@ function GroupGlobalInputs({ break; default: notificationApi["error"]({ - message: `Type ${globalInput.type} not implemented`, - description: `Was specified in: ${globalInput.displayName}`, + message: t( + "groupTasks.groupTypeSelectionModal.notification.globalInputTypeNotImplemented.message", + { globalInputType: globalInput.type } + ), + description: t( + "groupTasks.groupTypeSelectionModal.notification.globalInputTypeNotImplemented.description", + { globalInputDisplayName: globalInput.displayName } + ), }); break; } @@ -291,7 +308,9 @@ function GroupGlobalInputs({ {elements.length > 0 ? (
-

Fill in the global values

+

+ {t("groupTasks.groupTypeSelectionModal.h3")} +

{ setCurrentCategoryGroup(categoryGroup); @@ -31,7 +33,7 @@ export default function GroupTasks({ isGroupTasksViewModalOpen }) { return ( <> {webSocketContext.CategoryGroups.length === 0 ? ( - + ) : ( <> {filteredCategoryGroups.length > 0 ? ( @@ -51,8 +53,8 @@ export default function GroupTasks({ isGroupTasksViewModalOpen }) { )} diff --git a/src/Pages/PageNotFound/index.js b/src/Pages/PageNotFound/index.js index ff0ca97..3770868 100644 --- a/src/Pages/PageNotFound/index.js +++ b/src/Pages/PageNotFound/index.js @@ -1,15 +1,18 @@ import { Button, Result } from "antd"; +import { useTranslation } from "react-i18next"; import { Link } from "react-router-dom"; export default function PageNotFound() { + const { t } = useTranslation(); + return ( - + } /> diff --git a/src/Pages/Scanners/index.js b/src/Pages/Scanners/index.js index 4a53e0c..b52d21a 100644 --- a/src/Pages/Scanners/index.js +++ b/src/Pages/Scanners/index.js @@ -9,39 +9,41 @@ import { import { useContext } from "react"; import { Link } from "react-router-dom"; import { Constants } from "../../utils"; +import { useTranslation } from "react-i18next"; export default function Scanners() { const webSocketContext = useContext(WebSocketContext); + const { t } = useTranslation(); const getTableColumns = () => { return [ { - title: "Name", + title: t("scanners.column.name"), dataIndex: "name", key: "name", }, { - title: "Used by", + title: t("scanners.column.usedBy"), dataIndex: "usedByUserId", key: "usedByUserId", }, { - title: "Last used", + title: t("scanners.column.lastUsed"), dataIndex: "lastUsed", key: "lastUsed", }, { - title: "Registered at", + title: t("scanners.column.registeredAt"), dataIndex: "registeredAt", key: "registeredAt", }, { - title: "User-Agent", + title: t("scanners.column.userAgent"), dataIndex: "userAgent", key: "userAgent", }, { - title: "Action", + title: t("scanners.column.action"), dataIndex: "action", key: "action", render: (_, record) => ( @@ -49,8 +51,11 @@ export default function Scanners() { {record._usedByUserId === getUserId() ? ( { webSocketContext.SendSocketMessage( SentMessagesCommands.ScannersDisconnectScanner, @@ -60,14 +65,17 @@ export default function Scanners() { ); }} > - Disconnect + {t("scanners.column.action.disconnect")} ) : ( { webSocketContext.SendSocketMessage( SentMessagesCommands.ScannersUseScanners, @@ -77,7 +85,7 @@ export default function Scanners() { ); }} > - Use scanner + {t("scanners.column.action.use")} )} @@ -121,7 +129,7 @@ export default function Scanners() { return ( <>

- Scanners ( + {t("scanners.header.scanners")} ( {webSocketContext.Scanners === null ? "0" : webSocketContext.Scanners.length} @@ -132,18 +140,3 @@ export default function Scanners() { ); } - -/* -} -> - - -*/ diff --git a/src/Pages/UserProfile/index.js b/src/Pages/UserProfile/index.js index cbe43ed..fa2ffb6 100644 --- a/src/Pages/UserProfile/index.js +++ b/src/Pages/UserProfile/index.js @@ -1,8 +1,11 @@ import { Button, Card, + Col, Form, Input, + Row, + Select, Space, Table, Upload, @@ -22,68 +25,72 @@ import { isEmailValid, } from "../../utils"; import { Link } from "react-router-dom"; - -const columns = [ - { - title: "User-Agent", - dataIndex: "userAgent", - key: "userAgent", - }, - { - title: "Connection status", - dataIndex: "connectionStatus", - key: "connectionStatus", - }, - { - title: "Last used", - dataIndex: "lastUsed", - key: "lastUsed", - }, - { - title: "Expires at", - dataIndex: "expiresAt", - key: "expiresAt", - }, - { - title: "Action", - dataIndex: "action", - key: "action", - render: (_, record) => { - return ( - - { - fetch(`${Constants.API_ADDRESS}/user/session/${record.key}`, { - method: "DELETE", - headers: { - "Content-Type": "application/json", - "X-Authorization": getUserSessionFromLocalStorage(), - }, - }) - .then((res) => handleUnauthorizedStatus(res.status)) - .catch((err) => { - console.error(err); - }); - }} - > - Sign out - - - ); - }, - }, -]; +import { useTranslation } from "react-i18next"; export default function UserProfile() { const webSocketContext = useContext(WebSocketContext); const [notificationApi, notificationContextHolder] = notification.useNotification(); + const { t, i18n } = useTranslation(); const [oldPassword, setOldPassword] = useState(""); const [newPassword, setNewPassword] = useState(""); const [repeatedNewPassword, setRepeatedNewPassword] = useState(""); + const getTableColumns = () => { + return [ + { + title: t("userProfile.column.userAgent"), + dataIndex: "userAgent", + key: "userAgent", + }, + { + title: t("userProfile.column.connectionStatus"), + dataIndex: "connectionStatus", + key: "connectionStatus", + }, + { + title: t("userProfile.column.lastUsed"), + dataIndex: "lastUsed", + key: "lastUsed", + }, + { + title: t("userProfile.column.expiresAt"), + dataIndex: "expiresAt", + key: "expiresAt", + }, + { + title: t("userProfile.column.action"), + dataIndex: "action", + key: "action", + render: (_, record) => { + return ( + + { + fetch(`${Constants.API_ADDRESS}/user/session/${record.key}`, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + "X-Authorization": getUserSessionFromLocalStorage(), + }, + }) + .then((res) => handleUnauthorizedStatus(res.status)) + .catch((err) => { + console.error(err); + }); + }} + > + {t("userProfile.column.action.signOut")} + + + ); + }, + }, + ]; + }; + const getTableItems = () => { let items = []; @@ -107,10 +114,11 @@ export default function UserProfile() { const beforeUpload = (file) => { if (file.size > Constants.MAX_AVATAR_SIZE) { notificationApi["error"]({ - message: `Your profile could not be changed`, - description: `Avatar must be smaller than ${ - Constants.MAX_AVATAR_SIZE / 1024 / 1024 - } MB`, + message: t("userProfile.changeAvatarError.notification.message"), + description: t( + "userProfile.changeAvatarError.notification.description", + { MAX_AVATAR_SIZE: Constants.MAX_AVATAR_SIZE / 1024 / 1024 } + ), }); return false; } @@ -174,29 +182,55 @@ export default function UserProfile() { <> {notificationContextHolder} -

Your Profile

+

+ {t("userProfile.header.yourProfile")} +

- - - - + + + + + + + + + +