From bb178d71decf7954283d63ae75de090084ac9892 Mon Sep 17 00:00:00 2001 From: Stefan Schubert Date: Thu, 22 Feb 2024 22:50:04 +0100 Subject: [PATCH 1/5] fixes #sabi-113 (#152) fixes sabi-113 HTTP.500 after login (returned users) --- CHANGELOG.md | 5 ++ sabi-webclient/pom.xml | 40 ++----------- .../sabi/webclient/CDIBeans/UserSession.java | 24 +++++++- .../sabi/webclient/config/AppConfig.java | 2 +- .../webclient/config/WebSecurityConfig.java | 18 ++++-- .../controller/MeasurementListView.java | 7 ++- .../sabi/webclient/controller/MenuView.java | 8 ++- .../controller/MyErrorController.java | 45 ++++++++++++++ .../controller/PasswordForgottenView.java | 28 ++++----- .../sabi/webclient/controller/PlagueView.java | 7 ++- .../controller/RegistrationView.java | 21 ++++--- .../sabi/webclient/controller/ReportView.java | 11 ++-- .../webclient/controller/TankListView.java | 14 ++--- .../webclient/controller/UserProfileView.java | 9 +-- .../CustomExceptionHandlerFilter.java | 59 +++++++++++++++++++ .../sabi/webclient/utils/PageRegister.java | 32 ++++++++++ .../resources/META-INF/resources/login.xhtml | 39 ++++++------ .../resources/static/{ => error}/404.html | 7 ++- .../META-INF/resources/static/error/500.html | 49 +++++++++++++++ .../resources/static/{ => error}/error.html | 13 ++-- .../resources/template/masterLayout.xhtml | 14 +++-- .../src/main/resources/application.yml | 2 + .../src/main/resources/log4j2-spring.xml | 4 +- .../src/main/resources/static/error/404.html | 41 +++++++++++++ .../src/main/resources/static/error/500.html | 49 +++++++++++++++ .../main/resources/static/error/error.html | 46 +++++++++++++++ 26 files changed, 470 insertions(+), 124 deletions(-) create mode 100644 sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/MyErrorController.java create mode 100644 sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/security/CustomExceptionHandlerFilter.java create mode 100644 sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/utils/PageRegister.java rename sabi-webclient/src/main/resources/META-INF/resources/static/{ => error}/404.html (82%) create mode 100644 sabi-webclient/src/main/resources/META-INF/resources/static/error/500.html rename sabi-webclient/src/main/resources/META-INF/resources/static/{ => error}/error.html (69%) create mode 100644 sabi-webclient/src/main/resources/static/error/404.html create mode 100644 sabi-webclient/src/main/resources/static/error/500.html create mode 100644 sabi-webclient/src/main/resources/static/error/error.html diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fd25615..7f93c3c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # History of changes (since 5/2022) +## Release 1.2.5 + +### Bugfixes +* HTTP.500 in some cases for returing users with timedout session (sabi-113) + ## Release 1.2.4 ### Bugfixes diff --git a/sabi-webclient/pom.xml b/sabi-webclient/pom.xml index 1ba35b51..bc9e1d99 100644 --- a/sabi-webclient/pom.xml +++ b/sabi-webclient/pom.xml @@ -10,7 +10,7 @@ de.bluewhale sabi-webclient - 1.2.4 + 1.2.5 jar sabi-webclient A JSF based webclient for sabi. @@ -47,7 +47,7 @@ org.springframework.boot spring-boot-starter-parent - 3.1.7 + 3.2.2 @@ -57,8 +57,8 @@ 21 2.20.0 4.0.1 - 1.12.2 - 5.1.4 + 1.12.3 + 5.2.2 1.2.5 1.6.4 9.0.9 @@ -107,11 +107,6 @@ - - org.springframework.boot - spring-boot-starter-validation - - org.springframework.boot spring-boot-starter-log4j2 @@ -215,22 +210,6 @@ sabi-webclient - - - - org.joinfaces - joinfaces-maven-plugin - ${joinfaces.version} - - - - classpath-scan - - - - - - @@ -276,17 +255,6 @@ - - - org.joinfaces - joinfaces-maven-plugin - - @@ -13,7 +13,10 @@ xmlns:f="http://xmlns.jcp.org/jsf/core"> - + @@ -33,7 +36,7 @@ - @@ -7,14 +7,15 @@ Ups.. +

Ups...404 file not found

- +
- +
ClibanariusClibanarius crap

Do we have a broken file link? diff --git a/sabi-webclient/src/main/resources/META-INF/resources/static/error/500.html b/sabi-webclient/src/main/resources/META-INF/resources/static/error/500.html new file mode 100644 index 00000000..5179fc2a --- /dev/null +++ b/sabi-webclient/src/main/resources/META-INF/resources/static/error/500.html @@ -0,0 +1,49 @@ + + + + + + Ups.. + + + +

Ups...500 internal error

+ + + + + + + +
Clibanarius crap +

+ Sorry, there was an unplanned error. +

+

+ Currently there is one known issue with returning users + which was raised already here. + This is currently caused with a broken client side view state due to a server redeployment. +

+

Unfortunate this problem has nit been solved yet. + The workaround is to re-login by going into browsers URL field and remove everything after the last "/" and hit enter again. +

+ +

+ Just in case the problem has not been solved by the workaround: + YOU can still help! If you can reproduce the error please submit a trouble ticket with detail description what happened + and led to the problem at: projects Issues + tracker.
+ Before open an own ticket, have a look if some other already reported a problem and leave a comment + there instead. +

+

+ Thanks for supporting the project and sorry for any inconvenience caused. +

+
+ + + + \ No newline at end of file diff --git a/sabi-webclient/src/main/resources/META-INF/resources/static/error.html b/sabi-webclient/src/main/resources/META-INF/resources/static/error/error.html similarity index 69% rename from sabi-webclient/src/main/resources/META-INF/resources/static/error.html rename to sabi-webclient/src/main/resources/META-INF/resources/static/error/error.html index dd79e5ae..bd474116 100644 --- a/sabi-webclient/src/main/resources/META-INF/resources/static/error.html +++ b/sabi-webclient/src/main/resources/META-INF/resources/static/error/error.html @@ -1,5 +1,5 @@ @@ -7,18 +7,22 @@ Ups.. + -

Ups...something went wrong with Sabis Frontend

+

Ups...something went wrong with Sabis' Frontend

- +
- +
ClibanariusClibanarius crap

Sorry for that, but no reason to worry ;-)
+
Some exception in the frontend logic occurred I probably haven't considered yet. + Please try again: https://sabi-project.net/ and if that doesn't fix it + consider the suggested feedback in the next paragraph.

@@ -29,6 +33,7 @@

Ups...something went wrong with Sabis Frontend

Before open an own ticket, have a look if some other already reported a problem and leave a comment there instead.

+

Thanks for supporting the project and sorry for any inconvenience caused.

diff --git a/sabi-webclient/src/main/resources/META-INF/resources/template/masterLayout.xhtml b/sabi-webclient/src/main/resources/META-INF/resources/template/masterLayout.xhtml index f3abcb22..bf1f1d02 100644 --- a/sabi-webclient/src/main/resources/META-INF/resources/template/masterLayout.xhtml +++ b/sabi-webclient/src/main/resources/META-INF/resources/template/masterLayout.xhtml @@ -1,6 +1,6 @@ @@ -30,9 +30,15 @@ - -
Sorry content is missing. Report to site owner.
- + +
+ Sorry content is missing. Report to site owner. +
+
\ No newline at end of file diff --git a/sabi-webclient/src/main/resources/application.yml b/sabi-webclient/src/main/resources/application.yml index ef2a7d02..ad56b5de 100644 --- a/sabi-webclient/src/main/resources/application.yml +++ b/sabi-webclient/src/main/resources/application.yml @@ -41,6 +41,8 @@ server: error: whitelabel: enabled: false + # This will cause error occuring in DsipatcherServlet Context to be routed through the Controller listening on the /error Endpoint + path: /error servlet: session: # dev. setting for sessionExpired diff --git a/sabi-webclient/src/main/resources/log4j2-spring.xml b/sabi-webclient/src/main/resources/log4j2-spring.xml index 6c9e1f39..fef89177 100644 --- a/sabi-webclient/src/main/resources/log4j2-spring.xml +++ b/sabi-webclient/src/main/resources/log4j2-spring.xml @@ -1,7 +1,7 @@ @@ -36,7 +36,7 @@ - + \ No newline at end of file diff --git a/sabi-webclient/src/main/resources/static/error/404.html b/sabi-webclient/src/main/resources/static/error/404.html new file mode 100644 index 00000000..d4e6b5f7 --- /dev/null +++ b/sabi-webclient/src/main/resources/static/error/404.html @@ -0,0 +1,41 @@ + + + + + + Ups..🙈 + + + +

Ups...404 file not found

+ + + + + + + +
Clibanarius crap +

+ Do we have a broken file link? +

+ +

+ Good news is: YOU can help! First wait a while and try again. + If you can reproduce the error please submit a trouble ticket with detail description what happened + and led to the problem at: projects Issues + tracker.
+ Before open an own ticket, have a look if some other already reported a problem and leave a comment + there instead. +

+

+ Thanks for supporting the project and sorry for any inconvenience caused. +

+
+ + + + \ No newline at end of file diff --git a/sabi-webclient/src/main/resources/static/error/500.html b/sabi-webclient/src/main/resources/static/error/500.html new file mode 100644 index 00000000..21c5f936 --- /dev/null +++ b/sabi-webclient/src/main/resources/static/error/500.html @@ -0,0 +1,49 @@ + + + + + + Ups..🙈 + + + +

Ups...500 internal error

+ + + + + + + +
Clibanarius crap +

+ Sorry, there was an unplanned error. +

+

+ Currently there is one known issue with returning users + which was raised already here. + This is currently caused with a broken client side view state due to a server redeployment. +

+

Unfortunate this problem has nit been solved yet. + The workaround is to re-login by going into browsers URL field and remove everything after the last "/" and hit enter again. +

+ +

+ Just in case the problem has not been solved by the workaround: + YOU can still help! If you can reproduce the error please submit a trouble ticket with detail description what happened + and led to the problem at: projects Issues + tracker.
+ Before open an own ticket, have a look if some other already reported a problem and leave a comment + there instead. +

+

+ Thanks for supporting the project and sorry for any inconvenience caused. +

+
+ + + + \ No newline at end of file diff --git a/sabi-webclient/src/main/resources/static/error/error.html b/sabi-webclient/src/main/resources/static/error/error.html new file mode 100644 index 00000000..f98b77c2 --- /dev/null +++ b/sabi-webclient/src/main/resources/static/error/error.html @@ -0,0 +1,46 @@ + + + + + + Ups..🙈 + + + +

Ups...something went wrong with Sabis' Frontend

+ + + + + + + +
Clibanarius crap +

+ Sorry for that, but no reason to worry ;-)
+
+ Some exception in the frontend logic occurred I probably haven't considered yet. + Please try again: https://sabi-project.net/ and if that doesn't fix it + consider the suggested feedback in the next paragraph. +

+ +

+ Good news is: YOU can help! First wait a while and try again. + If you can reproduce the error please submit a trouble ticket with detail description what happened + and led to the problem at: projects Issues + tracker.
+ Before open an own ticket, have a look if some other already reported a problem and leave a comment + there instead. +

+ +

+ Thanks for supporting the project and sorry for any inconvenience caused. +

+
+ + + + \ No newline at end of file From 4f32126f71142c6fa443b231bf60d67325186b1f Mon Sep 17 00:00:00 2001 From: Stefan Schubert Date: Sun, 25 Feb 2024 00:00:09 +0100 Subject: [PATCH 2/5] fixes sabi-68 (#154) Adding Spanish resource bundles Patch-Management on Server Module Added French, Italian as well Added flags to the selection dialog DisplayLanguage is set in it's own Locale. --- CHANGELOG.md | 10 + sabi-boundary/pom.xml | 4 +- .../sabi/model/SupportedLocales.java | 7 +- sabi-server/pom.xml | 16 +- .../i18n/RegistrationMessages_es.properties | 15 ++ .../i18n/RegistrationMessages_fr.properties | 15 ++ .../i18n/RegistrationMessages_it.properties | 15 ++ sabi-webclient/pom.xml | 4 +- .../webclient/controller/UserProfileView.java | 10 + .../sabi/webclient/utils/I18nUtil.java | 4 +- .../META-INF/resources/images/LICENSE.md | 15 +- .../resources/images/icons8-flag-de-48.png | Bin 0 -> 1715 bytes .../resources/images/icons8-flag-en-48.png | Bin 0 -> 3667 bytes .../resources/images/icons8-flag-es-48.png | Bin 0 -> 1923 bytes .../resources/images/icons8-flag-fr-48.png | Bin 0 -> 1584 bytes .../resources/images/icons8-flag-it-48.png | Bin 0 -> 1679 bytes .../resources/secured/userProfile.xhtml | 16 +- .../resources/i18n/messages_es.properties | 206 +++++++++++++++++ .../resources/i18n/messages_fr.properties | 209 ++++++++++++++++++ .../resources/i18n/messages_it.properties | 209 ++++++++++++++++++ 20 files changed, 729 insertions(+), 26 deletions(-) create mode 100644 sabi-server/src/main/resources/i18n/RegistrationMessages_es.properties create mode 100644 sabi-server/src/main/resources/i18n/RegistrationMessages_fr.properties create mode 100644 sabi-server/src/main/resources/i18n/RegistrationMessages_it.properties create mode 100644 sabi-webclient/src/main/resources/META-INF/resources/images/icons8-flag-de-48.png create mode 100644 sabi-webclient/src/main/resources/META-INF/resources/images/icons8-flag-en-48.png create mode 100644 sabi-webclient/src/main/resources/META-INF/resources/images/icons8-flag-es-48.png create mode 100644 sabi-webclient/src/main/resources/META-INF/resources/images/icons8-flag-fr-48.png create mode 100644 sabi-webclient/src/main/resources/META-INF/resources/images/icons8-flag-it-48.png create mode 100644 sabi-webclient/src/main/resources/i18n/messages_es.properties create mode 100644 sabi-webclient/src/main/resources/i18n/messages_fr.properties create mode 100644 sabi-webclient/src/main/resources/i18n/messages_it.properties diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f93c3c9..18403d4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # History of changes (since 5/2022) +## Release 1.2.6 + +### Enhancements +* SABI-68: Spanish ressource bundles added +** THX to deepl I added French, Italian as well + +### Technical Maintenance + +* SABI-128 Additional TLS on Backend component (required by aquarium-IoT project) + ## Release 1.2.5 ### Bugfixes diff --git a/sabi-boundary/pom.xml b/sabi-boundary/pom.xml index b6fead80..674c990b 100644 --- a/sabi-boundary/pom.xml +++ b/sabi-boundary/pom.xml @@ -1,6 +1,6 @@ @@ -12,7 +12,7 @@ de.bluewhale sabi-boundary - 1.2.5 + 1.2.6 jar Contains the DTOs and Utility classes which will be used by the server and client module. diff --git a/sabi-boundary/src/main/java/de/bluewhale/sabi/model/SupportedLocales.java b/sabi-boundary/src/main/java/de/bluewhale/sabi/model/SupportedLocales.java index e1f90a10..43738b73 100644 --- a/sabi-boundary/src/main/java/de/bluewhale/sabi/model/SupportedLocales.java +++ b/sabi-boundary/src/main/java/de/bluewhale/sabi/model/SupportedLocales.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 by Stefan Schubert under the MIT License (MIT). + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). * See project LICENSE file for the detailed terms and conditions. */ @@ -16,7 +16,10 @@ */ public enum SupportedLocales { German(Locale.GERMAN), - English(Locale.ENGLISH); + English(Locale.ENGLISH), + French(Locale.FRENCH), + Italian(Locale.ITALIAN), + Spanish(new Locale("es")); private Locale locale; diff --git a/sabi-server/pom.xml b/sabi-server/pom.xml index 2993e47d..9ba0fc35 100644 --- a/sabi-server/pom.xml +++ b/sabi-server/pom.xml @@ -1,6 +1,6 @@ @@ -19,7 +19,7 @@ de.bluewhale sabi-server - 1.3.4 + 1.3.5 jar Backend consistent of internal CRUD services which will be used by the REST service orchestration @@ -40,7 +40,7 @@ - 1.2.5 + 1.2.6 UTF-8 UTF-8 21 @@ -48,12 +48,12 @@ 2.3.0 4.0.2 1.5.5.Final - 1.12.1 - 6.1.2 + 1.12.3 + 6.1.4 1.18.30 - 9.0.7 + 9.0.9 1.6.4 - 3.3.2 + 3.3.3 2.2.224 1.6 @@ -62,7 +62,7 @@ 4.0.1 24.1.0 2.16.2 - 3.2.3 + 3.2.5 diff --git a/sabi-server/src/main/resources/i18n/RegistrationMessages_es.properties b/sabi-server/src/main/resources/i18n/RegistrationMessages_es.properties new file mode 100644 index 00000000..fc452268 --- /dev/null +++ b/sabi-server/src/main/resources/i18n/RegistrationMessages_es.properties @@ -0,0 +1,15 @@ +# +# Copyright (c) 2022 por Stefan Schubert bajo la Licencia MIT (MIT). +# Ver el archivo LICENSE del proyecto para los t\u00E9rminos y condiciones detallados. +# + +email.verify.failed.response.headline=\u00A1Fall\u00F3 la validaci\u00F3n de la cuenta! +email.verify.failed.response.txt=Tu cuenta sigue bloqueada. \u00BFHa copiado el enlace de validaci\u00F3n completo en su navegador? Int\u00E9ntalo de nuevo. +email.verify.successful.response.headline=\u00A1Bienvenido al proyecto SABI-IP! +email.verify.successful.response.txt=Su correo electr\u00F3nico ha sido validado. Ahora puede iniciar sesi\u00F3n a trav\u00E9s de \ +https://sabi-project.net/login.html con su cuenta. \ +Gracias por apoyar la ciencia abierta con sabi. +email.verify.token.request.headline=\u00A1Bienvenido al proyecto SABI-IP! +email.verify.token.request.txt=Para activar tu cuenta y participar en el proyecto sabi \ +necesitamos verificar su direcci\u00F3n de correo electr\u00F3nico. Para ello, por favor \ +haga clic en el siguiente enlace o c\u00F3pielo y p\u00E9guelo en su navegador: \ No newline at end of file diff --git a/sabi-server/src/main/resources/i18n/RegistrationMessages_fr.properties b/sabi-server/src/main/resources/i18n/RegistrationMessages_fr.properties new file mode 100644 index 00000000..21a8aff6 --- /dev/null +++ b/sabi-server/src/main/resources/i18n/RegistrationMessages_fr.properties @@ -0,0 +1,15 @@ +# +# Copyright (c) 2022 par Stefan Schubert sous la licence MIT (MIT). +# Voir le fichier LICENSE du projet pour les termes et conditions d\u00E9taill\u00E9s. +# + +email.verify.failed.response.headline=La validation du compte a \u00E9chou\u00E9 ! +email.verify.failed.response.txt=Votre compte est toujours bloqu\u00E9. Avez-vous copi\u00E9 le lien de validation complet dans votre navigateur web ? Veuillez r\u00E9essayer. +email.verify.successful.response.headline=Bienvenue au projet SABI-IP ! +email.verify.successful.response.txt=Votre email a \u00E9t\u00E9 valid\u00E9. Vous pouvez maintenant vous connecter via \ +https://sabi-project.net/login.html avec votre compte. \ +Merci de soutenir la science ouverte avec sabi. +email.verify.token.request.headline=Bienvenue au projet SABI-IP ! +email.verify.token.request.txt=Pour activer votre compte et participer au projet sabi, nous avons besoin de v\u00E9rifier votre adresse \u00E9lectronique. \ +nous avons besoin de v\u00E9rifier votre adresse e-mail. Pour ce faire, veuillez cliquer sur le lien suivant ou copier-coller \ +cliquer sur le lien suivant ou le copier-coller dans votre navigateur : \ No newline at end of file diff --git a/sabi-server/src/main/resources/i18n/RegistrationMessages_it.properties b/sabi-server/src/main/resources/i18n/RegistrationMessages_it.properties new file mode 100644 index 00000000..c1f1c436 --- /dev/null +++ b/sabi-server/src/main/resources/i18n/RegistrationMessages_it.properties @@ -0,0 +1,15 @@ +# +# Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). +# See project LICENSE file for the detailed terms and conditions. +# + +email.verify.failed.response.headline=Convalida dell'account fallita! +email.verify.failed.response.txt=Il tuo account \u00E8 ancora bloccato. Avete copiato il link di convalida completo nel vostro browser? Riprova. +email.verify.successful.response.headline=Benvenuto nel progetto SABI-IP! +email.verify.successful.response.txt=La tua email \u00E8 stata convalidata. Ora puoi accedere tramite \ +https://sabi-project.net/login.html con il tuo account. \ +Grazie per aver sostenuto la scienza aperta con sabi. +email.verify.token.request.headline=Benvenuto nel progetto SABI-IP! +email.verify.token.request.txt=Per attivare il tuo account e partecipare al progetto sabi \ +abbiamo bisogno di verificare il tuo indirizzo e-mail. Per fare ci\u00F2, per favore \ +cliccare sul seguente link o copiarlo e incollarlo nel browser: \ No newline at end of file diff --git a/sabi-webclient/pom.xml b/sabi-webclient/pom.xml index bc9e1d99..ba6101dd 100644 --- a/sabi-webclient/pom.xml +++ b/sabi-webclient/pom.xml @@ -10,7 +10,7 @@ de.bluewhale sabi-webclient - 1.2.5 + 1.2.6 jar sabi-webclient A JSF based webclient for sabi. @@ -59,7 +59,7 @@ 4.0.1 1.12.3 5.2.2 - 1.2.5 + 1.2.6 1.6.4 9.0.9 1.18.30 diff --git a/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/UserProfileView.java b/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/UserProfileView.java index df00546f..e09afafc 100644 --- a/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/UserProfileView.java +++ b/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/UserProfileView.java @@ -81,6 +81,16 @@ public Boolean getHasMeasurementReminders() { return !measurementReminderTos.isEmpty(); } + /** + * Used as Workaround to create dynamic images resources + * @return + */ + public String getFlagResource(Locale c) { + return "images:icons8-flag-" + c.getLanguage() + "-48.png"; + } + + + public String save() { if (selectedLocale != null) { // Already stored diff --git a/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/utils/I18nUtil.java b/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/utils/I18nUtil.java index 16871785..313f86ea 100644 --- a/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/utils/I18nUtil.java +++ b/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/utils/I18nUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 by Stefan Schubert under the MIT License (MIT). + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). * See project LICENSE file for the detailed terms and conditions. */ @@ -45,7 +45,7 @@ public Locale getEnsuredSupportedLocale(String language) { /** - * Uses to distinguish users decimal seperator, depending on provided locale, which will be the sessions locale settings + * Uses to distinguish users decimal separator, depending on provided locale, which will be the sessions locale settings * in most cases. However you may request other punctuation than sessions locale through the locale parameter. * * @param forLocale diff --git a/sabi-webclient/src/main/resources/META-INF/resources/images/LICENSE.md b/sabi-webclient/src/main/resources/META-INF/resources/images/LICENSE.md index 9939c3b6..92f495a1 100644 --- a/sabi-webclient/src/main/resources/META-INF/resources/images/LICENSE.md +++ b/sabi-webclient/src/main/resources/META-INF/resources/images/LICENSE.md @@ -3,11 +3,12 @@ Every Picture used in Sabi needs to register here with the origin and license. So that we are able to give information on that in doubt of any copyright issue. -| Filename | Origin | License info | Remark | -|------------|----------|----------------|--------| -| RiffStefan2.png | Sabi Authors Private Stock | Free usage within Sabi | Used for the splash screen | -| icons8-crab-64.png | https://icons8.com/icon/9232/crab-filled/ | Creative Commons Attribution-NoDervis 3.0 Unported. | Got permission from Elena and confirmation about the credits link. | -| ByeBye.png | Sabi Authors Private Stock | Free usage within Sabi | Used in LogOff Page | -| Clibanarius.JPG | Sabi Authors Private Stock | Free usage within Sabi | Used as template for ByeBye.jpg and maybe in error pages. | -| pathfinder.jpg | Sabi Authors Private Stock | Free usage within Sabi | Used in Impressum page. | +| Filename | Origin | License info | Remark | +|--------------------|----------|-----------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| RiffStefan2.png | Sabi Authors Private Stock | Free usage within Sabi | Used for the splash screen | +| icons8-crab-64.png | https://icons8.com/icon/9232/crab-filled/ | Creative Commons Attribution-NoDervis 3.0 Unported. | Got permission from Elena and confirmation about the credits link. | +| icons8-flags-* | https://icons8.com/icon/set/flags/family-hand-drawn-2 | Free download version 48pt | Used in User Profile Page for language selection. Original filenames have been slightly modified to ease programmatic selection. Icons8 mentioned and linked from Apps credit page. | +| ByeBye.png | Sabi Authors Private Stock | Free usage within Sabi | Used in LogOff Page | +| Clibanarius.JPG | Sabi Authors Private Stock | Free usage within Sabi | Used as template for ByeBye.jpg and maybe in error pages. | +| pathfinder.jpg | Sabi Authors Private Stock | Free usage within Sabi | Used in Impressum page. | diff --git a/sabi-webclient/src/main/resources/META-INF/resources/images/icons8-flag-de-48.png b/sabi-webclient/src/main/resources/META-INF/resources/images/icons8-flag-de-48.png new file mode 100644 index 0000000000000000000000000000000000000000..b6ff90d8f40b2e16951dee99e0c63be668e89b14 GIT binary patch literal 1715 zcmV;k22A;hP)VKrL|}= z#Q+V(7R3UEhL(h!rfEu>C~asBjg?0c{b98-AIF@=L+TYNSa5|6l+Fz#By@8%N=NiVsU zbR-%QpEPv-0AsY1h*lGk^j>CCsw(b@gp`*JO+0C6!kdOBoSs3P(p7Ov*TgAV;@^=a zewyPrFvhiHiEpTi*f4cz+BTJG*U_eIrEIsjUii|u3b%*cSgb8{nFBx6=sPRJ{!08^spyy4EK%2J5z%@-fTr-L zGnou}i)r*1yU}0l!cZZK!F(7485?~`6TRIAs!1Ka2@UzEiegOhNjMUcA!%;eqZC)s zpVl!_urS&i!jh_sj}1gITyjw_yBI0h=ua8QMHEC$5sJtl@C>%XBW;POMr4d8RD3d{ zpYi+)vcQ_&%CTGsTZ=AsmczKKFM+*^(M>|Z!D z=HbODj4#jP@0aE=xw6m}S7*$oclPwJeG;0`Xm^01xh7+_&RrnV!ahfC25o4vO|G2@ zaDx|M@km(t$OTxRwY;;?tzLjyH6(xJ4xwA~ju&8?7oe0i#j`;hnrxG8B^Nx$?e+p> z!YY3zXhV~2vb#47TjL+}0>ll8y&bfn$u{v$$5B%_=m)T5{;dyVr+@rJ4o5FexF!l{au)o&jcZ$bsmt2>&5VzS+ zyZ|{vVhyjjW=qD~@cYAw^NQ=4dUCGJ=JV}Z+&6P~U(_$aE#(kyDLJ^lXyUT0hLO08 zlqEnF8Db`nYEs1Vs)ThPm$Ch`D)x=3_{MD-4(`9^q3N~FK z<8v!yti43?@s>AUF5`+(39iMCcmet>jlDCrO2NjJ3N~D-V9muc)+~{+a!AICK?zG2 zNEptEJ}auS&#Dm_Yc7(pZn=VumnpdA@|m6PxIx8zV=5lMUBe6a8W=xd;va`>G@f_R zI{d-$+&u;&HhaknP>DF~tq*eW4}+h5%?~i{U&~1%ceeRL@TOXA@Zv)z!Zw?^sn->D z>aR~&ftzZz!LJ@Q;hO9fKS0=K<3GL62;5Yw4UXJzAm*^+GXX4i=)iU@a8s=|cxJDG zc$mF7GqK6ht}k7uHiI_RYJ(^4(9so|=>bpIuU;md4%$?!4IbH|A#Cz~6MI^eOYm<5 zZL0M?dHGu=hKj-zWBzRS%+#W(v)^1$7T)~gI<fnp82H2E7ABsw-^Hs3 zE&q??HR#?=%9)!!CBMFGq3~)U$-m}W?BA}*CT59PY%&?;C#pUCKbP0Uf33YlI{Epl z<*7Y4tIhpeHGf~v-eus}Bc{)Z$1EKGriovC-N4gd(fv~V@&=`K@_-nwrAiwlsDsVzcA6 z&YtEtZXXeCId_x2gop~~o)gTcpNN*7dseW4h;HLJZm+3v-*GMWylb;#A%mTWIP4Wm zW3Sr=doAj)-^Uzw)V0`Cs?6Q(9qL3>ey`^O9d*=EM;-nD>AzLw+A^>2r@sII002ov JPDHLkV1f&ZRI~s9 literal 0 HcmV?d00001 diff --git a/sabi-webclient/src/main/resources/META-INF/resources/images/icons8-flag-en-48.png b/sabi-webclient/src/main/resources/META-INF/resources/images/icons8-flag-en-48.png new file mode 100644 index 0000000000000000000000000000000000000000..7d794a49eb01aaef9117fe3f1bcc99df537d050f GIT binary patch literal 3667 zcmV-Z4y^HsP)XyKmpM_q}J|_l?;%aDaL2&Hyt4 zf(RlbgHZy=CaVN}DiMjeBt}J1U!tgJSYl9w2t))06cv?h&%{cq-U}|w@6|a&ccz8Z z`y=&I^{VDnebrrkZ=du1zV-JVh8bSNYj_Q>;WfPe_hn-KZ;sD3vH!au^cv6aNf+${Jy8Wlg8?`8_2HMtkK>(BKEeGDKMYAx zp~kAq7Q;{A2mlXKTV~^WEkd} zq5AhaOh%k)2;s|-G3=}IBTIGS+9{K8?A$rLci{rwdhb1q9zPMhQ-xMME9GD@V+^`_ zucPm&vXb0~$OCyAIvVP!F$7V*Qt9SF@l`K`HXV{zS_IS>`s&ywmpobuV0)>gP2JRU4?(Sv{28pX7zimX@!yI+5uDo5mj zAO8eSS%VmDpcW&C6RTb`ZbA~k$squC6u8h@U4=uZPJy=zS12B6T!l!{XgDPqYc_Aj zug{#pjF~f_Ie2W%cj3^80BU_Qa?;~?{Q2jxXz6lrCJR`j^}QqjBWL>hM^8L~U9Y@C zUu^L!c&C0)iF@;1P#kvr;D^<57-12I(EK9GwKO)+Bz>{m zi=%ZxlzSx9RFq-wkt5jp$fIzGGQ?Oj^*Z^#-eCGe0syaP4PTR_QbNTDMdNtp<(Kiw z8*iYhv;-wC5eI7m_^c&@$zcWQ;ShelZ(q_I#B+8*L}p&mWe=z+0G=!JqBt{)K4V!H zp6rpZ3r?Ew$IhL@igoKQC#iK8g23NJ7Bdtq2x}wYQ^$a zFCrfJV*-GtXSuIPJtx&fOdCaGS`3!LU^KyMPi*>A_uDdh0ZdxfW~hz8iNx_#htMxigu#L=K-m zjjrx4c%61UUhKgeH31a4M2x5`$1e^ahRf|q0r2LC0Q{NrmDLz!gY?H=2h)dKm&)HP9j@Fq-+(2>^bFQ~H{0 z@b3BZc=_N#Ji2QaRsOp|x+78K$roP0?JHNpX0>8WSi|epek_Pd5UduMOeU&e0>ImK zL9lu~1hWa-^Ih0m}KPZhG!L+qYxgJ@;VR z%$blh&zS^(pwY-(N=wg#*<^x8l2G9HqAeE0$XFmLEol){g#9QD1(4%)Bi-XcSX1fy z9>Go(6f9<>Ndk@Q1b{!a$Ius(5auo5jfMoLqGB_fV7FL?h!u)M7~E5m;Fe{$Wd(lC zg}6UJB^C(6qiPVG>fr={2+wifkYu~i8c81fuaFC^5q#X7DrXwQI9?Y_5#q)D)&8X1 z9+zM?*Ge(WmsP!hH!N5!&iH*UxdVp3)pZRruzrbSQ|k0K`&M0zj?pQb?-B{-}W z7+Ds2oep0HE2->a4l?7C~WmLIDRBEYG;gV49R;ZMEG-N3vf=&UNorm3Q zra5EgI0(EQyp0EEwrx!S$kCH3;Sk{S1(2DYi}LCbXzLiH$a5DiME}yISh;Z{Hr;qe<(dx4aEmLdQCL=mSVlIY>Dh4mL*N|(EWGeo0zj_j@m?bJ^~PIn zLHn3-$jmE-sA%9g69`Ks?z32VtlsySpjrvp9W_b0$H} zp9-yL23#fA!(BcPp30lyjJLyJv_6vrU@&su%Hc8y(Wb$XujKkco}W8~(&bT|<0G0!r*f70k8jhSkO|3}6tvmL24-jQZZjdJV*sfhD%*jHLTf)!F z2j4kT8$_)~L|#T34N0=c&-U&`b$tUQ%@22R?-f)+Etn3LvmH$4fWhMYOA48*xfM=t zF2eCF8Y)Dx<5AT4WJ;|`Sk(Juo?@kH3p4qdpJlm5}JscJboybUt9De_OY}vLA zVV@VRL6uSs0&-japfRRRn@YV*_9C4>nwAMIln-xJUs6AJ*<3P_olOA9HkciM9UQ9H zK+YTk-XWrY*>ZZ=^xhu01v?%tbW^@ghHKew!;%$uP`4*Y9tl74y`gO+tzbg|xCH^P zz4aE_$BqMMvZ8C|4b-Dc*Q|yr3YZqvD4izZI3udSEjqDz>(=Dpv})5PI3*QYdL#Vx z%iyi-&jbEwoQ99k$+(h|5*__O; zV<%1qYcSFgll+#Iok!mt3P9$0s&GYZ1EkEcaQI7MGF#C#V-{XLbO>|j&!-dMq6`<# zw?rrf&sCimQBh90S%QjBp56;ykRfMufL!k+$()`wd`qUPJJzqq@sB>jthqPPq5A0( z4}RMk#SL*49$8GOLXSWHA5dIAh@o<-R9(x+!FfPYQ`jgG-fX7c%qc8RPFCLPTOb8X zVY3S~Z-~(*O`HJDZo`HgjVAe>St?}ShMW2p(uzp-C)7T-s5Ei4!qS1pWVT!)NJ;W! zrNzq!eW=87EBwwmB^WhmX1#9Zq8^-mdk{YBqo$O z6icIAK84#?E`&E;f2~HSRk`@#P7xUuuACzxf}>N?HF^-C`!XwgW*ylgmk16m%AlOCC)X6 zF(INMJsPH+FwtNd+dE)&sL%?pENfC`C&o^?b`XFq6#$_U1OV|)G%e!_4+Mu+zuF~m z$4cQ3g=tA8;XME51vH%hJL%7bb4*JN~ffmvuD#A0phCf ztyl#sFTfe8L!e>BRSy<3Mq^_4boxFSXo%HQ%Bb0lH&32KT2>B}ye^stWQ0|6Cqv2@ z3unBI3i(cqVN=s#Fc>j!(IPrX-L`TiM8Sb-uS6-!)UX2mkVeK>ES4MX7VAZl7@=6& zz{IJ&xbc>L1fyv*)@)ktfFoG*HzCsSjhNm+W1e`zU2zk=0C2`y>GcPxG>YoNLj^86 zeXY!pF+C{4Y%mPic*nO!j{Al+nm=PX{)BdEqEb3_ly~pm#8EqDM?96atVn>L^ct{ ziD)hnwGmMl5he31C8A|SG(tox^L&hm))a7O{@qPPw3vvxiKuF(3h;q-`N=tb`N^*% zqETIvJ|D8=?X|XYAmNh_SG(n7K7+lf%2HO7rL0F|=_;2zQD-X?O#yYHJ*cI6!umvS z*hnvln(6Cm%=`Srj(2H%Hu9Rcm8o zqaRzF%JFzx2nV~WaJat)#|GmVUsU_9^83CBK2qy}&t$I?k@uAL9#vZ1A9PN>l8n9U zN?Z&^6P`)Gi)}k)K#fO!bzeug=!%WckQe)F;L@bGiHHdUoQjnGe_8$UJe8K5;%m?K z4|p|}Ew)1A7szFPl^bw5H=w=Q)-tm>`O6Dpcxgclf9$Wp?|LJ6?y71$-CZ?}r#dUK zyFL70Y4EBUA{yWZj4Y|NCeJtFkp(fl&>O*l`IRE`e0N?DUz=No4Gn&*N!S>x_hNaS z8y|>UxF+gEZ?%rrkczlZMx|SZ?PT!i5*!W(B*`KE_L&S3pNx1w#@w)iwi*>}Q3Y+W z91EIMB%4(v=c!1xY1%6{0~TJ`=E7gT@5XDp z-1ygC4^BSm!Q|84i^eTO>YGHgf}FbJfuVL)D6xHw6MOD9@yvr3UVOxbf9&=kbMWF# zdNCPYti44`q3k6okdq@@&dWGOF2nIAEYv`^!$(Sv(7vCt)FO;?n-m2WcYQ4R-X=D zPLz8Xjy;hZv-*0yC5*Ms9VI$=whuX2I#6|f>%MLtB$wF_f5|bJa7%oAzbI3170*%%V@38aBaPXhDt9q zmEr!e0QP>_#Bh&V6ay65!PBTgn&Nopjs0h*xW)*>b6Z{5wZVkf$*^gz9}NKw8#iyp zx(ypJ&{>XOZL!cdPbrE4GIQ{QOcO42wy>1~BHx@-~2c9_g?A&?y|Sv{%I!Zp{T~$YxMwhoG@sMSD=g`#LoI^nQz< zh11e*&3AoR&z|{m%cl$^DjAmb=K}PL%XN`$#)frlniCLR z*@}e*Qa=+bAyVzjkGYEx#5%8qJ~Z5;o-7>jGklA)2Rmo=|B5H|Nur~?^@KwEK=yZ-xAM}bM?a&qr*`J>tcdiUJ+dH7EiX$~~ zVD^=m{2$?qCP^ZQ9ipZ5TGG+OJ1#7f@I#K59EBX;;}K=_6nrOt^R3hT^6Qq!UQ;}A zmx;&Lo7l0|iLIY@;+~bfL^rT{#K6i$I!3xRTs=ocbG3p>n?YA3n5qO#7X3g@LSE@v zw=Rh$gV+9N!utW9X$sM03AVw`!tZ2=+sY{#{0drwT8?rJ-60(Vl}3)R6HBU13`Z>7 z73L||*KuF4 zND0D5rY~e<_?W(m+_=_&mTvNE>G#-bD&kVo)s~#{YAoZ{SVoo{liW4k7RCt{2*?VkLRU8NK-#zEPdi#E?rCr;VZElRsJs1-=hGT<0 zjKrzH2;u`oCty%8lKtUA2#PU4*a)aRvWXc9(=3tTVu&D$F+m1I2Rh{yGna`*1{>>o z+l}p*+qGMxBHok8U;QQDbm`jee0J_R_ncFJc*QGT@rqZx{(Bh!z#J0|(3kRF1!*Zpf_?-Y#LvGd*C;YO(qVim_9$HsxU%G(`}b1;Od2tCi4ss~(cA=phogh| zJ#*S4bb!R{;Ep|er~qb34EZln8)-*POP1?h^7Agf?&6Mg?#f zbnrx9)mLCE}!5Dz9(=lV^J--jk%t#wh zc2{ZvSLgYN#G;`|04H6VQm~2+;L4I4_wAzs6zApix8zMx4Y*k5BU%;@#sYerv({1q zGUZ)OO;mu&;-db&*>=?cW&I?v$UnKKXN5l3?APdSWX_BL?P9LFs=U7;GeI>#S;1;B z3QPhpH{>pP{hsd!menjA+%nCo8qo9CL9CqlC`TkzfCOLQ;NinmfK{trl>Zj52 z@H9Fc13|2U`VqB&A4`*nmPP$B_W`LhA@>>TW0m8lPg4PQH#d_CyDq2}pd2q+cziDQXz^)Y z=NP0J2co1O{<^c13h+T&8!0eLvf9fh*C_fCz>3&|T?TPtn_x)vJ0E;S6@cS~+h;Cb zqyl_=>=;SYi?T8;c9tZOjyc}&LGF#J0#4@d#C>ws|F&a~9#Y7N7WaXMQ>$*+;5pmLgx7-mew zC}805bt8v+%^bdL6Y#fI9)D%w*iVc+ZqaeL5dbyP&z_rstKEx^0KgAu*$o6 zn^MMG3XT|aO_qT zWuqiXD-l8q5khlb~!erpDvD zx`?mX1hNw$Gz7g;R-#JVu*e6LHj$4bhIR`^jZOvM#K91oI}GCH4u=j)M?=D@v5>fK zB6Qs}1(J5of-V~;gQnYRPgPdJp)+Toq@n`$95?`*_w0f7+qS{i8#cffD_6q8Wy@gZ z{P~bQeL9TG&aNGwlT(+In;ZHLbKLWl@hPg*$qW#|&6)^*{r%h{I5T_dk zoJ)-cjmP)tztFSh035Mi|L$fy1G#hNz>HXXqfx-s0X|R&_ZV>)H_)+|8PKX_;D^#u zX2859OJHJ*t==f$W_l|yV=jQO$X7S#MW)Ai0)^$}%z!0%c`!Okt1$|wY61{he9$F- zGW(0n8xj2R&>?0(-rBX0>9GWi0_ZJHBAlO&(|>eY^9eJ+=5Ys$j~-ijwTUG|`G%08laJhdBCZ){rby0KZf=j@*lY%@DEw8)KL{tsA-{FH!eH7X3T^MHSc9*JS1)1isV?9P0>{w}xA^jg+Rky@Y~HFA z@fP{CU{}u(O{ydo`8u&kw}>R%r{OiZinq!)=r)7?h8KnV?udw^PM53PYPavV>-r8w zQMQPpxQedN=^FjTI(;TWXyS{ELRLTq;R;u{!u9{I ZzX7CTu_=S6tm^;(002ovPDHLkV1nOj7N-CJ literal 0 HcmV?d00001 diff --git a/sabi-webclient/src/main/resources/META-INF/resources/secured/userProfile.xhtml b/sabi-webclient/src/main/resources/META-INF/resources/secured/userProfile.xhtml index c8788021..091b84d7 100644 --- a/sabi-webclient/src/main/resources/META-INF/resources/secured/userProfile.xhtml +++ b/sabi-webclient/src/main/resources/META-INF/resources/secured/userProfile.xhtml @@ -1,6 +1,6 @@ + widgetVar="n" var="c"> + + + #{c.getLanguage()}-Lang Flag + + + + + ~
\ +

Aqu\u00ED puedes volver a unirte: +logout.header.h=Adi\u00F3s - hasta la pr\u00F3xima... +register.cancel.b=Cancelar +register.register.b=Crear cuenta de usuario +register.captcha.h=Protecci\u00F3n DoS para el registro de usuarios (tambi\u00E9n conocido como CAPTCHA). +register.captcha_missing.t=Necesita responder a la pregunta captcha. +register.gdpr.h=Exenci\u00F3n de responsabilidad GDPR (Ley Global de Protecci\u00F3n de Datos) +register.welcome.h=Sobre SABI +register.homepage.l=SABI en github +register.sabi_on_github.l=Puede encontrar m\u00E1s informaci\u00F3n en la p\u00E1gina de inicio del proyecto: +register.captcha.t=Aunque espero que los proyectos semi-cient\u00EDficos no sean el objetivo de los hackers, aqu\u00ED hay una peque\u00F1a protecci\u00F3n contra los algoritmos. \ +Por favor, resuelva este peque\u00F1o acertijo: +register.username.l=Nombre de usuario: +register.email.l=Correo electr\u00F3nico: +common.cookie.t=Este Sitio hace uso de cookies de sesi\u00F3n, para identificarle entre las siguientes peticiones de p\u00E1gina. Esto ocurre s\u00F3lo para \ +requisitos t\u00E9cnicos. +common.error.backend_unreachable.l=UPS - esto no deber\u00EDa ocurrir. No se ha podido acceder al servidor. Vuelva a intentarlo m\u00E1s tarde. +register.password.l=Contrase\u00F1a: +register.verifypassword.l=Verificar contrase\u00F1a: +register.language.l=Idioma +register.country.l=Pa\u00EDs +register.i18n.t=Estos par\u00E1metros (opcionales) ser\u00E1n utilizados por SABI para soportar la internacionalizaci\u00F3n (notaci\u00F3n decimal, idioma). \ +Desde el principio SABI viene con soporte para alem\u00E1n e ingl\u00E9s. Si m\u00E1s usuarios con un fondo diferente se observar\u00E1,\ +se buscar\u00E1 un traductor voluntario. SABI establecer\u00E1 estos par\u00E1metros en Ingl\u00E9s por defecto, puede adoptar estos par\u00E1metros despu\u00E9s en su perfil de usuario.\ +despu\u00E9s en su perfil de usuario. Si eres desarrollador y dominas otro idioma, echa un vistazo a sabi en github ;-) +register.gdpr.t=SABI almacena tus datos de registro con el prop\u00F3sito de identificar tu cuenta de usuario. Adicionalmente y asignados a tu cuenta de usuario, \ + se almacenar\u00E1n todos los datos de las mediciones y la informaci\u00F3n proporcionada sobre los habitantes de su tanque de agua de mar. La suma de todas las mediciones y datos del tanque proporcionados por todos los usuarios \ + ser\u00E1 evaluada bajo aspectos semi-cient\u00EDficos y los resultados estar\u00E1n disponibles para todos los usuarios de forma an\u00F3nima. Todos los datos se almacenar\u00E1n dentro de los l\u00EDmites de la UE y \ + no se compartir\u00E1n con terceros sin su permiso.\ +Para cumplir con el deber de solicitud de informaci\u00F3n de GDPR SABI ha integrado una funcionalidad de exportaci\u00F3n dentro de la p\u00E1gina del informe, desde donde se pueden descargar los datos de medici\u00F3n que usted proporcion\u00F3 en SABI. +register.welcome.t=\u00A1Gracias por apoyar el proyecto SABI y bienvenido! SABI no har\u00E1 la competencia a todos los valiosos foros de\ +y no pretende ofrecer funcionalidades de foro.\ +La atenci\u00F3n se centra en el enfoque cient\u00EDfico. Los participantes se benefician de una representaci\u00F3n gr\u00E1fica de sus datos de medici\u00F3n\ +Los participantes se benefician de una representaci\u00F3n gr\u00E1fica de sus datos de medici\u00F3n y de la informaci\u00F3n generada a partir del an\u00E1lisis de los datos. \ +Actualmente, el proyecto se encuentra en la fase I (recopilaci\u00F3n de datos). En cuanto un n\u00FAmero suficiente de participantes\ +suficientes datos de medici\u00F3n, iniciaremos la fase II (an\u00E1lisis). +preregistro.info.t=Casi perfecto. Su nombre de usuario y contrase\u00F1a han sido aceptados.\ +En los pr\u00F3ximos minutos recibir\u00E1 un correo electr\u00F3nico con un enlace de activaci\u00F3n para validar su direcci\u00F3n de correo electr\u00F3nico.\ +Una vez que el correo electr\u00F3nico ha sido validado, puede utilizar sus credenciales para iniciar sesi\u00F3n en sabi \ +a trav\u00E9s de https://sabi-project.net/login.html para\ +configurar tu tanque y a\u00F1adir medidas. +welcome.but.login=Iniciar sesi\u00F3n +welcome.but.register=Registrarse +welcome.lab.login=Bienvenido: +welcome.lab.register=\u00A1Genial, quiero formar parte de este proyecto! +welcome.t.introduction=SABI es un proyecto semicient\u00EDfico de ciencia abierta cuyo objetivo es obtener informaci\u00F3n de los aficionados a la acuariofilia sobre las medidas del agua de mar. El proyecto se encuentra actualmente en la fase 1 (recogida de datos). \ +Consulte las \u00FAltimas noticias y planificaci\u00F3n del proyecto en Github para m\u00E1s detalles. +register.email_invalid.t=Direcci\u00F3n de correo electr\u00F3nico no v\u00E1lida. +credits.sponsor_thx.h=Gracias especiales a todos los patrocinadores: +credits.sponsor_icon8.t=Por el uso gratuito del simp\u00E1tico cangrejo como favicon. +credits.sponsor_developer.t=En caso de que haya m\u00E1s que yo: Por dedicar su tiempo libre al proyecto. +credits.sponsor_developer.l=Todos los desarrolladores contribuyentes +register.conflict.t=Nombre de usuario y/o Email ya est\u00E1n registrados. +tankview.tanklist.h=Tus tanques +menu.tankView.l=Tanque +menu.home.l=Casa +menu.export.l=Exportar +menu.report.l=Medida-Informe +menu.userProfile.l=Perfil de usuario +menu.feedback.l=Retroalimentaci\u00F3n +menu.statistics.l=Estad\u00EDsticas del proyecto +common.delete.b=Borrar +common.add.b=A\u00F1adir +common.edit.b=Editar +common.save.b=Guardar +common.cancel.b=Cancelar +common.error.internal_server_problem.t=Problema interno del servidor. Por favor, int\u00E9ntelo de nuevo m\u00E1s tarde o cree un ticket de problema en la p\u00E1gina de github del proyecto. +tankview.description.l=Descripci\u00F3n: +tankview.volume.l=Tama\u00F1o: +tankview.volUnit.l=Unidad: +tankview.waterType.l=Tipo de tanque: +tankview.inceptionDate.l=Fecha de inicio: +login.username.l=NombreUsuario: +login.password.l=Contrase\u00F1a: +login.forgottenPW.l=\u00BFContrase\u00F1a olvidada? \u00BFError tipogr\u00E1fico? O el servidor backend no est\u00E1 disponible... +login.resetPW.b=restablecer contrase\u00F1a +login.panel.h=Por favor, inicie sesi\u00F3n: +projectstats.tankcount.l=Tanques registrados: +projecttats.usercount.l=Participantes del proyecto: +userportal.projecttate.l=Estado-actual-del-proyecto: +userportal.currentprojectstate.l=Etapa 1 - Recogida de datos +menu.measureView.l=Adquisici\u00F3n de datos de medici\u00F3n +common.tankchoice.l=Tanque: +measureview.measurekind.l=Tipo de registro: +measureview.value.l=Valor medido: +common.unitchoise.l=Unidad: +measureview.date.l=Registrado en: +common.new_record.b=Nuevo registro +credits.sponsor_wife.l=Mi esposa +credits.sponsor_wife.t=Por todas las horas extra mir\u00E1ndome delante del port\u00E1til despu\u00E9s del trabajo. +common.select.l=Seleccionar una... +measureview.listing.h=Grabado recientemente: +crowdfounding.title.h=\u00BFD\u00F3nde ha ido a parar todo el dinero? Informe sobre peque\u00F1as finanzas: +crowdfunding.introduction.t=

Hay varias maneras de apoyar este proyecto de ciencia abierta:

\ +

\ +

Como patrocinador y propietario del proyecto pas\u00E9 bastante de mi tiempo libre realizando trabajos de concepci\u00F3n, programaci\u00F3n y operaci\u00F3n. \ +Asumiendo los costes operativos iniciales del primer centro de datos de sabis (raspberry pis con base en casa)...\ +Sin embargo, espero que algunos de ustedes est\u00E9n dispuestos a dejar que la plataforma operativa de SABI crezca para que tenga una base s\u00F3lida.\ +Para que vuestras inversiones sean transparentes mostrar\u00E9 aqu\u00ED como se est\u00E1 invirtiendo el dinero.

+common.incompleted_formdata.t=Por favor, rellene los campos que faltan. +common.save.confirmation.t=Datos guardados. THX :-) +common.token.expired.t=\u00BFEl backendtoken ha caducado? Por favor, vuelva a iniciar sesi\u00F3n. +userportal.greeting.l=SABI-Proyecto | +userportal.welcome.l=Bienvenido de nuevo +pw_forgotten.reset_request_accepted.t=Solicitud aceptada. Compruebe su correo electr\u00F3nico para un token de restablecimiento para continuar con el formulario. +pw_forgotten.request.step1.h=Paso 1 - Introduzca su direcci\u00F3n de correo electr\u00F3nico y demuestre que es humano :-) +pw_forgotten.request.b=Solicitar correo electr\u00F3nico con token de restablecimiento +pw_forgotten.request.h=\u00BFHa olvidado su contrase\u00F1a? Siga los pasos... +pw_forgotten.request.step2.h=Paso 2 - Comprueba tu Email, proporciona la nueva contrase\u00F1a junto con el token de cambio. +pw_forgotten.reset_token.l=Token de restablecimiento +pw_forgotten.reset.b=Confirmar +pw_forgotten.request.step3.h=Paso 3 - Lo ha conseguido, vuelva a iniciar sesi\u00F3n despu\u00E9s de recibir el correo de confirmaci\u00F3n. +pw_forgotten.login_link.l=Volver a la p\u00E1gina de inicio de sesi\u00F3n... +register.password.policy_failed.t=Contrase\u00F1as no id\u00E9nticas o demasiado d\u00E9biles. +register.pwreset_token_invalid.t=Reset-Token no coincide o ha caducado.. +reportview.headline.h=Informes de medici\u00F3n +reportview.introduction.t=Aqu\u00ED puede ver sus \u00FAltimos 14 registros de medici\u00F3n de una unidad mostrados como l\u00EDnea de tiempo.\ +M\u00E1s abajo tiene la posibilidad de exportar la serie completa de datos de la unidad seleccionada. +common.no_such_data.t=No se han encontrado estos datos. +reportview.chart.h=Medidas para %s +reportview.request_data.b=Solicitar informe +measureview.mode.editrecord.l=Modo: editar registro existente +measureview.mode.newrecord.l=Modo: a\u00F1adir nuevo registro +userprofile.h=Perfil de usuario para +common.additional.info.t=Debido al bajo presupuesto inicial del proyecto, el servicio est\u00E1 actualmente \ +s\u00F3lo est\u00E1 disponible en la "nueva" (desde hace m\u00E1s de 20 a\u00F1os) Internet basada en IPV6. \ +Si tu proveedor de internet te bloquea el universo IPV6, \ +prueba con tu tel\u00E9fono m\u00F3vil con la WLAN apagada. +impressum.role.t=Fundador y responsable del proyecto: +gdpr.menu.l=GDPR +userprofile.localechoice.l=Idioma: +userprofile.pwchange.l=Cambiar contrase\u00F1a +userprofile.updateconfirmation.t=Se ha actualizado la configuraci\u00F3n. +feedback.features.h=Aver\u00EDas, mejoras y peticiones de funciones +feedback.features.t=Si desea enviar un informe de error, una mejora o una solicitud de funci\u00F3n, visite la lista de foros de discusi\u00F3n de los proyectos en
SABIs Github Discussions
\ +THX :-) +feedback.common.h=Otros comentarios... +feedback.common.t=En caso de que s\u00F3lo desees dejarme una nota sobre sabi, puedes hacerlo simplemente por correo electr\u00F3nico.\ +Env\u00EDa tu correo a stefan@bluewhale.de Me alegro \ +sobre cualquier retroalimentaci\u00F3n pero por favor no se pregunte si me tomo mi tiempo para responder \ +(trabajo, familia, nanoreef-maintenance...) +sessionExpired.header.h=Oops - Sesi\u00F3n expirada +sessionExpired.message.t=Su sesi\u00F3n de usuario ha alcanzado un tiempo l\u00EDmite de inactividad y se ha detenido. Esto no estaba previsto.\ +

Aqu\u00ED puede iniciar sesi\u00F3n de nuevo: +projectstats.measurementcount.l=Cuento de mediciones: +menu.plagueView.l=Centro de plagas +credits.sponsor_magazin_article.t=Para poder anunciar este proyecto a trav\u00E9s de un art\u00EDculo en la revista KORALLE-Magazine (Edici\u00F3n 136). +login.register.l=\u00BFA\u00FAn no se ha registrado? --> +plague.center.introduction.h=Bienvenido al Centro de Plagas SABIs. \u00BFDe qu\u00E9 se trata? +plague.center.introduction.t=La visi\u00F3n central de SABI es identificar posibles correlaciones entre las mediciones de la calidad del agua y las plagas. \ +Para que esto sea posible, no s\u00F3lo deben registrarse regularmente los valores del agua, sino tambi\u00E9n la aparici\u00F3n y el curso de plagas espec\u00EDficas. +plagas espec\u00EDficas de forma estructurada. Si el proyecto tiene \u00E9xito, podremos \ +deducir la probabilidad de aparici\u00F3n de plagas en el acuario marino a partir de los valores del agua registrados \ +y actuar como una especie de sistema de alerta temprana con recomendaciones sobre contramedidas adecuadas. +plague.center.mystatus.h=Plagas reportadas actualmente en mis acuarios: +plague.center.mystatus.noplague.t=-- no listado -- +plague.center.addrecord.h=A\u00F1adir nueva plaga o registrar una actualizaci\u00F3n de estado: +plague.center.info.t=Los avisos de estado de una plaga en curso se combinar\u00E1n autom\u00E1ticamente.\ +siempre y cuando la plaga sea cerrada por el estado curado. +plague.center.history.h=Registro de plagas pasadas +plague.center.history.norecords.t=-- no hay registros todav\u00EDa -- +tankview.tempApiKey.l=ApiKey para env\u00EDo autom\u00E1tico de temperatura por dispositivos IoT: +tankview.tempApiKey.b=generar API-Key +projectstats.plagueObservationRecordCount.l=evoluci\u00F3n de la plaga observada: +plagueview.date.l=observado el: +plagueview.tank.l=Tanque: +plagueview.plague.l=Peste: +plagueview.laststatus.l=\u00DAltimo estado: +plagueview.curedate.l=Anunciado el: +plagueview.status.l=Estado: +plagueview.save.b=Guardar observaci\u00F3n +reportview.90d.chart.h=Puntos de medici\u00F3n en la revisi\u00F3n de 3 meses +reportview.365d.chart.h=Puntos de medici\u00F3n en la revisi\u00F3n anual +reportview.14mp.chart.h=Revisi\u00F3n reciente de los puntos de medici\u00F3n +plagueview.duration.l=Duraci\u00F3n en d\u00EDas: +userportal.meassurement.reminder.h=Recordatorio de sus mediciones: +userportal.meassurement.nosetting.t=Aqu\u00ED se le puede recordar si desea medir algo con regularidad. \ +Para ello, vaya a su perfil de usuario y guarde el intervalo de medici\u00F3n deseado.\ +userprofile.reminderinfo.t=Si desea que se le recuerde en la p\u00E1gina de inicio que debe medir un determinado valor de agua, \ +puede establecer aqu\u00ED un intervalo de medici\u00F3n para el valor correspondiente. La pr\u00F3xima vez que inicie sesi\u00F3n, \ +SABI comprobar\u00E1 cu\u00E1ndo ha medido el valor del agua por \u00FAltima vez y si el intervalo de medici\u00F3n previsto ha expirado. +userprofile.reminderinfo.h=Recordatorio de medici\u00F3n regular +userportal.meassurement.unit.l=Par\u00E1metro de medici\u00F3n +userportal.meassurement.duedate.l=Siguiente medici\u00F3n +userportal.meassurement.dayinterval.l=Intervalo de medici\u00F3n en d\u00EDas +userprofile.meassurement.active.l=Activo +userprofile.meassurement.dayinterval.l=Intervalo de medici\u00F3n en d\u00EDas +userprofile.meassurement.unit.l=Par\u00E1metro de medici\u00F3n +userprofile.meassurement.addreminder.l=Configurar recordatorio para: +common.update.b=Actualizar +register.password.policy.t=(Contrase\u00F1a: M\u00EDnimo 10 y m\u00E1ximo 20 caracteres. Mezcla de may\u00FAsculas/min\u00FAsculas con d\u00EDgitos y caracteres especiales) +enum.waterType.seawater.l=agua de mar +enum.waterType.freshwater.l=agua dulce \ No newline at end of file diff --git a/sabi-webclient/src/main/resources/i18n/messages_fr.properties b/sabi-webclient/src/main/resources/i18n/messages_fr.properties new file mode 100644 index 00000000..70c62000 --- /dev/null +++ b/sabi-webclient/src/main/resources/i18n/messages_fr.properties @@ -0,0 +1,209 @@ +# +# Copyright (c) 2023 par Stefan Schubert sous la licence MIT (MIT). +# See project LICENSE file for the detailed terms and conditions. +# +register.captcha_wrongAnswer.t=Mais... ce n'\u00E9tait pas la bonne r\u00E9ponse. Veuillez r\u00E9essayer. +login.welcome.h=Bienvenue au projet SABI - Seawater Aquarium Business Intelligence +logout.message.t=La session utilisateur a \u00E9t\u00E9 ferm\u00E9e. Nous vous remercions de votre participation au projet.
Nous vous remercions de votre participation au projet.\ +A la prochaine fois ! Ou simplement d\u00E9connect\u00E9 par erreur ?
\ +

Voici le retour : +logout.header.h=\u00C0 la prochaine fois... +register.cancel.b=Annuler +register.register.b=Cr\u00E9er un compte utilisateur +register.captcha.h=Protection DoS pour l'inscription des utilisateurs (aka CAPTCHA). +register.captcha_missing.t=La question captcha n'a pas encore re\u00E7u de r\u00E9ponse. +register.gdpr.h=D\u00E9claration du RGPD (R\u00E8glement g\u00E9n\u00E9ral sur la protection des donn\u00E9es) +register.welcome.h=A propos de SABI +register.homepage.l=SABI sur github +register.sabi_on_github.l=De plus amples informations se trouvent sur la page d'accueil du projet : +register.captcha.t=M\u00EAme si j'esp\u00E8re que les hackers ne s'int\u00E9ressent pas aux projets semi-scientifiques, \ +voici tout de m\u00EAme une petite d\u00E9fense contre les algorithmes. Veuillez r\u00E9soudre la mini-\u00E9nigme suivante : +register.username.l=Nom de connexion : +register.email.l=Email : +common.cookie.t=Ce service web utilise un cookie de session pour vous identifier entre les consultations de pages, \ +d\u00E8s qu'ils s'enregistrent ou se connectent. Celui-ci est utilis\u00E9 exclusivement pour la fonction techniquement n\u00E9cessaire de \ +fonction de la page. +common.error.backend_unreachable.l=UPS - cela n'aurait pas d\u00FB se produire. N'a pas pu atteindre le serveur backend. Veuillez r\u00E9essayer plus tard. +register.password.l=Mot de passe : +register.verifypassword.l=R\u00E9p\u00E9ter le mot de passe : +register.language.l=Langue +register.country.l=Pays +register.i18n.t=Ces informations (facultatives) sont utilis\u00E9es pour internationaliser SABI (point d\u00E9cimal, langue).\ +Au d\u00E9part, seules deux langues sont propos\u00E9es (Deutsch et English), si un nombre plus important d'utilisateurs d'un autre arri\u00E8re-plan\ + un traducteur volontaire est recherch\u00E9. Si les donn\u00E9es sont laiss\u00E9es en blanc, SABI met l'anglais \ + comme param\u00E8tre par d\u00E9faut. Il est possible de le modifier ult\u00E9rieurement via le profil d'utilisateur. \ + Si tu es d\u00E9veloppeur et que tu ma\u00EEtrises une autre langue, consulte SABI sur github ;-) +register.gdpr.t=SABI enregistre votre adresse e-mail dans le cadre de l'identification de l'utilisateur pour identifier le compte utilisateur. \ +En outre, et en lien avec votre compte d'utilisateur, les valeurs de mesure que vous avez communiqu\u00E9es et les informations sur la population de l'aquarium sont enregistr\u00E9es. \ +La somme de toutes les valeurs mesur\u00E9es et de toutes les informations sur la population de l'aquarium enregistr\u00E9es dans SABI par tous les utilisateurs est utilis\u00E9e dans le cadre d'une \ +questions semi-scientifiques. Les r\u00E9sultats de ces \u00E9valuations sont mis \u00E0 la disposition de tous les utilisateurs de mani\u00E8re anonyme. \ +Les donn\u00E9es sont stock\u00E9es au sein de l'UE et ne sont pas transmises \u00E0 des tiers sans votre autorisation. \ +Afin de satisfaire \u00E0 l'obligation d'information impos\u00E9e par le RGPD, l'application SABI comprend, sous le point Report, une fonction d'exportation automatique des donn\u00E9es.\ +Exportation des donn\u00E9es que vous avez saisies. +register.welcome.t=Merci de soutenir le projet SABI et bienvenue ! \ +SABI n'offrira pas de fonctionnalit\u00E9s de forum et n'entrera pas en concurrence avec les nombreuses et pr\u00E9cieuses communaut\u00E9s de forum. \ +L'approche scientifique est au premier plan. Les participants b\u00E9n\u00E9ficient d'une repr\u00E9sentation graphique des \ +des valeurs de mesure ainsi que des connaissances acquises au cours du projet. \ +Actuellement, le projet se trouve en phase I (collecte de donn\u00E9es). D\u00E8s que le nombre de \ +participants se sont r\u00E9unis et ont fourni une quantit\u00E9 suffisante de donn\u00E9es de mesure \ +le projet passera \u00E0 la phase II (analyse). + +preregistration.info.t=Presque termin\u00E9. Le nom d'utilisateur n'\u00E9tait pas encore attribu\u00E9 et a \u00E9t\u00E9 cr\u00E9\u00E9 avec succ\u00E8s. \ +Dans la minute qui suit, vous recevrez un e-mail avec un lien d'activation pour confirmer que votre adresse e-mail est valide. \ +D\u00E8s que votre adresse e-mail a \u00E9t\u00E9 v\u00E9rifi\u00E9e par ce biais, votre login est activ\u00E9 et vous pouvez vous connecter via \ +https://sabi-project.net/login.html pour vous connecter. +welcome.but.login=Connexion +welcome.but.register=Enregistrement +welcome.lab.login=Bienvenue \u00E0 nouveau : +welcome.lab.register=Cool, je veux y participer. +welcome.t.introduction=SABI est un projet semi-scientifique ouvert aux aquariophiles d'eau de mer. L'objectif est d'\u00E9tudier les questions relatives aux valeurs mesur\u00E9es afin d'en tirer des enseignements. Le projet en est actuellement \u00E0 la phase 1 (collecte de donn\u00E9es). \ +Vous trouverez plus d'informations sur la vision et la planification du projet sur Github. +register.email_invalid.t=Aucune adresse e-mail valide +credits.sponsor_thx.h=Merci de tout c\u0153ur pour votre soutien \u00E0 : +credits.sponsor_icon8.t=Pour l'utilisation gratuite du crabe mignon comme favicon. +credits.sponsor_developer.t=Si je ne suis pas rest\u00E9 le seul : Pour le temps libre sacrifi\u00E9. +credits.sponsor_developer.l=Tous les d\u00E9veloppeurs qui me soutiennent +register.conflict.t=Le nom d'utilisateur et/ou l'email sont d\u00E9j\u00E0 enregistr\u00E9s. +tankview.tanklist.h=vos aquariums +menu.tankView.l=Aquarium +menu.home.l=Page d'accueil +menu.export.l=Exporter +menu.report.l=Rapport des donn\u00E9es de mesure +menu.userProfile.l=Profil de l'utilisateur +menu.feedback.l=R\u00E9troaction +menu.statistics.l=Statistiques du projet +common.delete.b=Supprimer +common.add.b=ajouter +common.edit.b=Modifier +common.save.b=Enregistrer +common.cancel.b=Annuler +common.error.internal_server_problem.t=Ups - il y a eu une erreur de serveur interne. Merci de r\u00E9essayer plus tard ou de signaler un probl\u00E8me (de pr\u00E9f\u00E9rence via un ticket github sur le projet sabi). +tankview.description.l=Description : +tankview.volume.l=volume : +tankview.volUnit.l=Unit\u00E9 : +tankview.waterType.l=Type d'aquarium : +tankview.inceptionDate.l=date de mise en place : +login.username.l=Nom d'utilisateur : +login.password.l=Mot de passe : +login.forgottenPW.l=Mot de passe oubli\u00E9 ? Erreur de frappe ? Ou le serveur backend est actuellement indisponible ? +login.resetPW.b=R\u00E9initialiser le mot de passe +login.panel.h=Veuillez vous connecter : +projectstats.tankcount.l=Aquariums recens\u00E9s : +projectstats.usercount.l=Participants au projet : +userportal.projectstate.l=P\u00E9riode actuelle du projet : +userportal.currentprojectstate.l=Phase 1 - Collecte de donn\u00E9es +menu.measureView.l=Collecte des donn\u00E9es de mesure +common.tankchoice.l=Aquarium : +measureview.measurekind.l=Qu'est-ce qui a \u00E9t\u00E9 mesur\u00E9 : +measureview.value.l=valeur mesur\u00E9e : +common.unitchoise.l=Unit\u00E9 : +measureview.date.l=Mesur\u00E9 le : +common.new_record.b=Nouvelle entr\u00E9e +credits.sponsor_wife.l=Ma femme +credits.sponsor_wife.t=Pour le temps sacrifi\u00E9 pass\u00E9 ensemble devant l'ordinateur portable apr\u00E8s le travail. +common.select.l=Choisir... +measureview.listing.h=Mesures r\u00E9centes : +crowdfounding.title.h=Comment les dons ont-ils \u00E9t\u00E9 investis ? Petit aper\u00E7u financier : +crowdfunding.introduction.t=

Il existe plusieurs fa\u00E7ons de soutenir ce projet semi-scientifique :

\ +
    en tant que donateur\ +
  • En tant que d\u00E9veloppeur via github
  • .\ +
  • En tant que participant et donc donateur de donn\u00E9es
  • .\ +
  • En tant que sponsor pour amortir les d\u00E9penses mat\u00E9rielles
  • .\ +
.\ +\ +

En tant que sponsor du projet, j'investis mon temps libre dans le cadre de la prestation de d\u00E9veloppement et d'exploitation.\ +Mais il y a aussi des frais mat\u00E9riels et d'exploitation qui doivent \u00EAtre refinanc\u00E9s (si tout se passe bien \u00E0 un moment donn\u00E9) et que je ne veux pas supporter seul. Toutefois, je ne peux pas me permettre d'\u00EAtre seul.\ +Afin d'assurer la transparence, les co\u00FBts et les ressources sont publi\u00E9s ici. +common.incompleted_formdata.t=Veuillez indiquer tous les champs. +common.save.confirmation.t=Les donn\u00E9es ont \u00E9t\u00E9 enregistr\u00E9es. Merci :-) +common.token.expired.t=La session du serveur semble avoir expir\u00E9. Veuillez vous reconnecter. +userportal.greeting.l=Projet SABI | +userportal.welcome.l=Bienvenue \u00E0 nouveau +pw_forgotten.reset_request_accepted.t=Requ\u00EAte accept\u00E9e. Le token pour la r\u00E9initialisation a \u00E9t\u00E9 envoy\u00E9 par mail. Veuillez l'utiliser \u00E0 l'\u00E9tape suivante. +pw_forgotten.request.step1.h=Etape 1 - Veuillez indiquer votre adresse e-mail et r\u00E9pondre au captcha. +pw_forgotten.request.b=Demander un jeton par email +pw_forgotten.request.h=Mot de passe oubli\u00E9 !? Suis les instructions... +pw_forgotten.request.step2.h=Etape 2 - Entrer le jeton de l'email et le nouveau mot de passe. +pw_forgotten.reset_token.l=Token de r\u00E9initialisation +pw_forgotten.reset.b=Envoyer +pw_forgotten.request.step3.h=Etape 3 - C'est fait, connectez-vous \u00E0 nouveau apr\u00E8s avoir re\u00E7u l'e-mail de confirmation. +pw_forgotten.login_link.l=Retour \u00E0 la page d'inscription... +register.password.policy_failed.t=Mots de passe non identiques ou trop faibles. +register.pwreset_token_invalid.t=Le jeton de r\u00E9initialisation ne correspond pas ou est expir\u00E9. +reportview.headline.h=Rapports de donn\u00E9es de mesure +reportview.introduction.t=Les 14 derniers points de mesure sont repr\u00E9sent\u00E9s ici sous forme de graphique dans le temps. Plus bas, il est possible d'exporter toutes ses propres donn\u00E9es de mesure. +common.no_such_data.t=Aucune donn\u00E9e n'a \u00E9t\u00E9 trouv\u00E9e \u00E0 ce sujet. +reportview.chart.h=Donn\u00E9es de mesure pour %s +reportview.request_data.b=G\u00E9n\u00E9rer un rapport +measureview.mode.editrecord.l=Mode : \u00E9diter l'ensemble de donn\u00E9es existant +measureview.mode.newrecord.l=Mode : ajouter un enregistrement de donn\u00E9es +userprofile.h=Profil d'utilisateur pour +common.additional.info.t=En raison du budget volontairement r\u00E9duit au d\u00E9marrage du projet, ce service est actuellement \ +exclusivement dans le "nouveau" r\u00E9seau Internet bas\u00E9 sur IPv6 \ +est accessible. Si le fournisseur d'acc\u00E8s local ne met pas IPv6 \u00E0 disposition, \ +il est g\u00E9n\u00E9ralement possible d'y acc\u00E9der via le t\u00E9l\u00E9phone portable (avec le WLAN d\u00E9sactiv\u00E9). +impressum.role.t=Fondateur et responsable du projet : +gdpr.menu.l=R\u00E8glement g\u00E9n\u00E9ral sur la protection des donn\u00E9es (RGPD) +userprofile.localechoice.l=Langue : +userprofile.pwchange.l=Changer le mot de passe +userprofile.updateconfirmation.t=Les param\u00E8tres ont \u00E9t\u00E9 mis \u00E0 jour. +feedback.features.h=Rapports d'erreurs, am\u00E9liorations, souhaits +feedback.features.t=Les propositions d'am\u00E9lioration, les id\u00E9es ou les rapports de probl\u00E8mes peuvent \u00EAtre signal\u00E9s et consult\u00E9s publiquement ici \ +SSABIs Github Discussions
\ +Comme il s'agit d'un projet international, il est pr\u00E9f\u00E9rable de le faire en anglais. Mais l'allemand est tout aussi bienvenu. Merci beaucoup :-) +feedback.common.h=Autres r\u00E9actions... +feedback.common.t=Pour tout autre feedback, n'h\u00E9sitez pas \u00E0 m'envoyer un email \u00E0 stefan@bluewhale.de \ +Ne vous \u00E9tonnez pas si je ne r\u00E9ponds pas tout de suite (travail, famille, entretien du nano-r\u00E9cif...). +sessionExpired.header.h=Ups - Session d'utilisateur expir\u00E9e +sessionExpired.message.t=Votre session utilisateur a expir\u00E9 apr\u00E8s un d\u00E9lai d'attente. Si ce n'\u00E9tait pas intentionnel...
-'est pas un probl\u00E8me.\ +

Il suffit de se connecter \u00E0 nouveau : +projectstats.measurementcount.l=Nombre de donn\u00E9es de mesure : +menu.plagueView.l=Centre des plaintes +credits.sponsor_magazin_article.t=Pour faire conna\u00EEtre le projet dans le cadre d'un article paru dans le magazine KORALLE (num\u00E9ro 136). +login.register.l=Sans login ? --> +plague.center.introduction.h=Bienvenue au centre des plaies de SABI. De quoi s'agit-il ici ? +plague.center.introduction.t=La vision centrale de SABI est d'identifier les corr\u00E9lations possibles entre les mesures de la qualit\u00E9 de l'eau et les plaies. \ +Pour ce faire, il faut non seulement enregistrer r\u00E9guli\u00E8rement les valeurs de l'eau, mais aussi et surtout surveiller l'apparition de \ +et l'\u00E9volution de fl\u00E9aux sp\u00E9cifiques doivent \u00EAtre prot\u00E9g\u00E9es de mani\u00E8re structur\u00E9e. Si le projet est couronn\u00E9 de succ\u00E8s, nous pourrons \ +d\u00E9duire la probabilit\u00E9 d'apparition de pestes dans l'aquarium marin \u00E0 partir des valeurs de l'eau signal\u00E9es et les utiliser comme une sorte de \ +syst\u00E8me d'alerte pr\u00E9coce avec des recommandations sur les contre-mesures appropri\u00E9es. +plague.center.mystatus.h=Pestes actuellement signal\u00E9s dans mes aquariums : +plague.center.mystatus.noplague.t=-- aucune entr\u00E9e -- +plague.center.addrecord.h=D\u00E9clarer une nouvelle peste ou mettre \u00E0 jour le statut : +plague.center.info.t=Une plaie actuelle est automatiquement r\u00E9sum\u00E9e et n'est annonc\u00E9e que par le message \ +message de cl\u00F4ture. +plague.center.history.h=R\u00E9pertoire des plaies surmont\u00E9es +plague.center.history.norecords.t=-- aucune entr\u00E9e jusqu'\u00E0 pr\u00E9sent -- +tankview.tempApiKey.l=ApiKey pour les messages automatiques de temp\u00E9rature par les appareils IoT : +tankview.tempApiKey.b=g\u00E9n\u00E8re une cl\u00E9 API +projectstats.plagueObservationRecordCount.l=\u00E9volution des plaies observ\u00E9e : +plagueview.date.l=Observ\u00E9 le : +plagueview.tank.l=Aquarium : +plagueview.plague.l=Fl\u00E9au : +plagueview.laststatus.l=dernier \u00E9tat : +plagueview.curedate.l=Enregistr\u00E9 le : +plagueview.status.l=Statut : +plagueview.save.b=Sauvegarder l'observation +reportview.14mp.chart.h=R\u00E9trospective des points de mesure r\u00E9cemment relev\u00E9s +reportview.365d.chart.h=Points de mesure dans la r\u00E9trospective annuelle +reportview.90d.chart.h=Points de mesure dans la r\u00E9trospective 3 mois +plagueview.duration.l=dur\u00E9e en jours : +userportal.meassurement.reminder.h=Vos rappels de mesures : +userportal.meassurement.nosetting.t=Tu peux te faire rappeler ici si tu voulais mesurer quelque chose r\u00E9guli\u00E8rement. \ +Pour cela, va dans ton profil d'utilisateur et enregistre l'intervalle de mesure souhait\u00E9. +userprofile.reminderinfo.t=Si tu veux qu'on te rappelle sur la page d'accueil que tu dois mesurer une certaine valeur d'eau, \ +tu peux enregistrer ici un intervalle de mesure pour la valeur correspondante. La prochaine fois que tu te connecteras \ +SABI regardera quand tu as mesur\u00E9 la valeur de l'eau pour la derni\u00E8re fois et comparera si ton \ +l'intervalle que tu as enregistr\u00E9 est \u00E9coul\u00E9. +userprofile.reminderinfo.h=Rappel pour les mesures r\u00E9guli\u00E8res +userportal.meassurement.unit.l=Param\u00E8tres de mesure +userportal.meassurement.duedate.l=prochaine mesure +userportal.meassurement.dayinterval.l=intervalle de mesure en jours +userprofile.meassurement.active.l=Activ\u00E9 +userprofile.meassurement.dayinterval.l=Intervalle de mesure en jours +userprofile.meassurement.unit.l=Param\u00E8tres de mesure +userprofile.meassurement.addreminder.l=D\u00E9finir un rappel pour : +common.update.b=Mise \u00E0 jour +register.password.policy.t=(mot de passe : min 10 \u00E0 20 caract\u00E8res. Minuscules/majuscules, chiffre et caract\u00E8res sp\u00E9ciaux) +enum.waterType.seawater.l=Eau sal\u00E9e +enum.waterType.freshwater.l=Eau douce \ No newline at end of file diff --git a/sabi-webclient/src/main/resources/i18n/messages_it.properties b/sabi-webclient/src/main/resources/i18n/messages_it.properties new file mode 100644 index 00000000..d9e4c0c2 --- /dev/null +++ b/sabi-webclient/src/main/resources/i18n/messages_it.properties @@ -0,0 +1,209 @@ +# +# Copyright (c) 2023 by Stefan Schubert under the MIT Licence (MIT). +# Vedere il file LICENZA del progetto per i termini e le condizioni dettagliate. +# +register.captcha_wrongAnswer.t=Hm... questa era la risposta sbagliata. Si prega di riprovare. +login.welcome.h=Benvenuto nel progetto SABI - Seawater Aquarium Business Intelligence +logout.message.t=La sessione utente \u00E8 stata terminata. Grazie per aver partecipato al progetto. \ +Alla prossima volta! O ti sei disconnesso per errore?
\ +

Ecco che torna indietro: +logout.header.h=Fino alla prossima volta... +register.cancel.b=Annulla +register.register.b=Crea account utente +register.captcha.h=Protezione DoS per il login degli utenti (aka CAPTCHA). +register.captcha_missing.t=La domanda CAPTCHA non ha ancora ricevuto risposta. +register.gdpr.h=Dichiarazione dell'ADGVO (Regolamento generale sulla protezione dei dati) +register.welcome.h=Sulla SABI +register.homepage.l=SABI su github +register.sabi_on_github.l=Altre informazioni sono disponibili sulla homepage del progetto: +register.captcha.t=Anche se spero che gli hacker non abbiano interesse in progetti semi-scientifici, \ +tuttavia ecco un piccolo algoritmo di difesa. Risolvete il seguente mini-rompicapo: +register.username.l=nome di login: +register.email.l=Email: +common.cookie.t=Questo servizio web utilizza un cookie di sessione per identificare l'utente tra una visualizzazione e l'altra della pagina. \ +non appena ci si registra o si effettua il login. Questo viene utilizzato esclusivamente per le funzioni tecnicamente necessarie. \ +che \u00E8 tecnicamente necessario. +common.error.backend_unreachable.l=UPS - questo non sarebbe dovuto accadere. Impossibile raggiungere il server di backend. Riprovare pi\u00F9 tardi. +register.password.l=Password: +register.verifypassword.l=Di nuovo la password: +register.language.l=lingua +register.country.l=paese +register.i18n.t=Questi dati (volontari) sono utilizzati per internazionalizzare SABI (punto decimale, lingua). \ +All'inizio vengono offerte solo due lingue (tedesco e inglese), ma se ci sono pi\u00F9 utenti con un background diverso si cerca un traduttore volontario. \ +si cerca un traduttore volontario. Se l'informazione viene lasciata vuota, SABI imposta l'inglese \ + come impostazione predefinita. Questa impostazione pu\u00F2 essere modificata in seguito tramite il profilo utente. \ + Se sei uno sviluppatore e conosci un'altra lingua, visita SABI su github ;-) +register.gdpr.t=SABI salva il vostro indirizzo e-mail per identificare l'account utente come parte del processo di identificazione dell'utente. \ +Inoltre, collegati all'account utente, vengono memorizzati i valori misurati e le informazioni sul popolamento dell'acquario segnalati dall'utente. \ +Il totale di tutti i valori misurati e dei dati relativi al popolamento dell'acquario memorizzati in SABI da tutti gli utenti viene analizzato in base a \ +analizzati in base a domande semi-scientifiche. I risultati di queste analisi sono resi anonimi e disponibili a tutti gli utenti. \ +I dati sono conservati all'interno dell'UE e non vengono trasmessi a terzi senza il vostro consenso. \ +Per adempiere all'obbligo di informazione previsto dal GDPR, l'applicazione SABI contiene una funzione per l'esportazione automatica dei dati inseriti. \ +automatica dei dati inseriti. +register.welcome.t=Grazie per aver sostenuto il progetto SABI e benvenuto! \ +SABI non offre alcuna funzionalit\u00E0 di forum e non entra in concorrenza con le numerose e valide comunit\u00E0 di forum. \ +L'attenzione \u00E8 rivolta all'approccio scientifico. I partecipanti beneficiano di una rappresentazione grafica dei valori misurati e delle conoscenze acquisite nel corso del progetto. \ +valori misurati e delle conoscenze acquisite nel corso del progetto. \ +Il progetto \u00E8 attualmente nella Fase I (raccolta dati). Non appena un numero sufficiente di \ +partecipanti che hanno fornito un numero sufficientemente elevato di dati di misurazione, il progetto passer\u00E0 alla fase I (raccolta dati). \ +dati, il progetto passer\u00E0 alla fase II (analisi). + +preregistrazione.info.t=Quasi finito. Il nome utente non era ancora stato assegnato ed \u00E8 stato creato con successo. \ +Entro un minuto riceverete un'e-mail con un link di attivazione per confermare la validit\u00E0 del vostro indirizzo e-mail. \ +Non appena l'indirizzo e-mail \u00E8 stato verificato, il login sar\u00E0 attivato e sar\u00E0 possibile accedere tramite \ +https://sabi-project.net/login.html per accedere. +welcome.but.login=login +welcome.but.register=Registrazione +welcome.lab.login=Benvenuto: +welcome.lab.register=Fico, voglio iscrivermi. +welcome.t.introduction=SABI \u00E8 un progetto aperto e semi-scientifico per gli acquariofili marini. L'obiettivo \u00E8 indagare su questioni relative ai valori misurati per ottenere approfondimenti. Il progetto \u00E8 attualmente nella fase 1 (raccolta dati). \ +Ulteriori informazioni sulla visione e sulla pianificazione del progetto sono disponibili su Github. +register.email_invalid.t=Nessun indirizzo e-mail valido +credits.sponsor_thx.h=Grazie per il vostro supporto: +credits.sponsor_icon8.t=Per l'uso gratuito del simpatico granchio come favicon. +credits.sponsor_developer.t=Nel caso in cui non sia l'unico: Per il tempo libero sacrificato. +credits.sponsor_developer.l=Tutti gli sviluppatori che supportano il progetto. +register.conflict.t=Il nome utente e/o l'e-mail sono gi\u00E0 registrati. +tankview.tanklist.h=I tuoi acquari +menu.tankView.l=Acquario +menu.home.l=Pagina iniziale +menu.export.l=Esportazione +menu.report.l=Rapporto dati misurati +menu.userProfile.l=Profilo utente +menu.feedback.l=Feedback +menu.statistics.l=Statistiche del progetto +common.delete.b=Elimina +common.add.b=Aggiungi +common.edit.b=Modifica +common.save.b=Salva +common.cancel.b=Annulla +common.error.internal_server_problem.t=Ups - si \u00E8 verificato un errore interno del server. Riprovare pi\u00F9 tardi o segnalare l'errore (preferibilmente tramite un ticket github per il progetto sabi). +tankview.description.l=Descrizione: +tankview.volume.l=Volume: +tankview.volUnit.l=Unit\u00E0: +tankview.waterType.l=tipo di acquario: +tankview.inceptionDate.l=Data di inizio: +login.username.l=Nome utente: +login.password.l=Password: +login.forgottenPW.l=Ha dimenticato la password? Errore di digitazione? Oppure il server di backend non \u00E8 attualmente disponibile... +login.resetPW.b=Ripristina password +login.panel.h=Per favore, accedi: +projectstats.tankcount.l=Aquari registrati: +projectstats.usercount.l=Partecipanti al progetto: +userportal.projectstate.l=Fase attuale del progetto: +userportal.currentprojectstate.l=Fase 1 - raccolta dati +menu.measureView.l=Raccolta dati di misurazione +common.tankchoice.l=Aquario: +measureview.measurekind.l=Cosa \u00E8 stato misurato: +measureview.value.l=Valore misurato: +common.unitchoise.l=Unit\u00E0: +measureview.date.l=Misurato il giorno: +common.new_record.b=Nuovo inserimento +crediti.sponsor_moglie.l=moglie +credits.sponsor_wife.t=Per il tempo sacrificato trascorso insieme davanti al computer dopo il lavoro. +common.select.l=Selezione... +measureview.listing.h=Le ultime misurazioni: +crowdfounding.title.h=Come sono state investite le donazioni? Piccola panoramica finanziaria: +crowdfunding.introduction.t=

Ci sono diversi modi per supportare questo progetto semi-scientifico:

\ +
    \ +
  • Come sviluppatore tramite github
  • \ +
  • Come partecipante e quindi donatore di dati
  • \ +
  • Come sponsor per rimborsare le spese materiali
  • \ +
\ +\ +

Come sponsor del progetto, investo il mio tempo libero come parte dei servizi di sviluppo e operativi.\ +Ma ci sono anche costi materiali e operativi che (se le cose vanno bene a un certo punto) dovrebbero essere rifinanziati e che non voglio sostenere da solo.\ +Tuttavia, per creare trasparenza, i costi e i fondi ricevuti sono resi noti qui.

+common.incompleted_formdata.t=Per favore inserisci tutti i campi. +common.save.confirmation.t=I dati sono stati salvati. Grazie :-) +common.token.expired.t=La sessione del server sembra essere scaduta. Si prega di effettuare nuovamente il login. +userportal.greeting.l=Progetto SABI | +userportal.welcome.l=Bentornato +pw_forgotten.reset_request_accepted.t=Richiesta accettata. Il token per la reimpostazione \u00E8 stato inviato via e-mail. Utilizzarlo nella fase successiva. +pw_forgotten.request.step1.h=Fase 1 - Inserisci il tuo indirizzo e-mail e rispondi al captcha. +pw_forgotten.request.b=Richiesta del token via e-mail +pw_forgotten.request.h=Hai dimenticato la password! Seguire le istruzioni... +pw_forgotten.request.step2.h=Fase 2 - Inserire il token dall'e-mail e la nuova password. +pw_forgotten.reset_token.l=Ripristina il token +pw_forgotten.reset.b=Invio +pw_forgotten.request.step3.h=Passo 3 - Fatto, effettuare nuovamente il login dopo aver ricevuto l'e-mail di conferma. +pw_forgotten.login_link.l=Torna alla pagina di login... +register.password.policy_failed.t=Password non identiche o troppo deboli. +register.pwreset_token_invalid.t=Il token di ripristino non corrisponde o \u00E8 scaduto. +reportview.headline.h=Rapporti dei dati di misurazione +reportview.introduction.t=Qui vengono visualizzati graficamente gli ultimi 14 punti di misurazione nel tempo. Di seguito \u00E8 possibile esportare tutti i propri dati di misurazione. +common.no_such_data.t=Non sono stati trovati dati per questo. +reportview.chart.h=Dati di misurazione per %s +reportview.request_data.b=generare report +measureview.mode.editrecord.l=Modalit\u00E0: modifica set di dati esistenti +measureview.mode.newrecord.l=Modalit\u00E0: aggiungere un record di dati +userprofile.h=Profilo utente per +common.additional.info.t=A causa del budget volutamente ridotto all'inizio del progetto, questo servizio \u00E8 attualmente \ +esclusivamente nel "nuovo" Internet basato su IPv6. +accessibile. Se il provider Internet locale non fornisce l'IPv6, \code(0144)\. +c'\u00E8 di solito la possibilit\u00E0 di accedervi tramite telefono cellulare (con WLAN disattivata). +impressum.role.t=Fondatore e responsabile del progetto: +gdpr.menu.l=GDPR +userprofile.localechoice.l=lingua: +userprofile.pwchange.l=Cambia password +userprofile.updateconfirmation.t=Le impostazioni sono state aggiornate. +feedback.features.h=Messaggi di errore, miglioramenti, richieste +feedback.features.t=Suggerimenti di miglioramento, idee o segnalazioni di problemi possono essere segnalati pubblicamente e visualizzati qui.\ +
Discussioni su Github di SABI
\ +Trattandosi di un progetto internazionale, si prega di utilizzare l'inglese. Anche il tedesco \u00E8 benvenuto. Grazie mille :-) +feedback.common.h=Altri feedback... +feedback.common.t=Per qualsiasi altro feedback, si prega di inviare un'email a stefan@bluewhale.de \ +Non sorprendetevi se non rispondo immediatamente (lavoro, famiglia, manutenzione del nano reef...). +sessionExpired.header.h=Ups - sessione utente scaduta +sessionExpired.message.t=La sessione utente \u00E8 scaduta dopo un timeout. Se questo non era previsto...
\ +

Eseguire nuovamente il login: +projectstats.measurementcount.l=Numero di dati di misurazione: +menu.plagueView.l=Centro della peste +credits.sponsor_magazine_article.t=Per aver pubblicizzato il progetto in un articolo della rivista KORALLE (numero 136). +login.register.l=Senza login? --> +plague.centre.introduction.h=Benvenuto nel centro peste della SABI. Di cosa si tratta? +plague.centre.introduction.t=La visione centrale della SABI \u00E8 quella di identificare possibili correlazioni tra le misurazioni della qualit\u00E0 dell'acqua e le pestilenze. \ +Per rendere possibile questo, non solo i valori dell'acqua devono essere registrati regolarmente, ma soprattutto l'insorgenza e il decorso di specifiche pestilenze. \ +e il decorso di specifiche epidemie devono essere registrati in modo strutturato. Se il progetto avr\u00E0 successo, potremo \u00B4\u00B4 ricavare la probabilit\u00E0 di insorgenza delle piaghe. \ +ricavare la probabilit\u00E0 di insorgenza di parassiti nell'acquario marino sulla base dei valori dell'acqua riportati e utilizzarla come una sorta di sistema di \u25A0 allarme precoce con raccomandazioni per le opportune contromisure. \ +come una sorta di sistema di allerta precoce con raccomandazioni di contromisure adeguate. +plague.centre.mystatus.h=Peste attualmente segnalate nei miei acquari: +plague.centre.mystatus.noplague.t=-- nessuna voce -- +plague.centre.addrecord.h=Segnala una nuova piaga o aggiorna lo stato: +plague.centre.info.t=La storia della peste attuale viene riassunta automaticamente e termina solo con il messaggio di terminazione. +messaggio di terminazione. +plague.centre.history.h=Direttore delle piaghe sopravvissute +plague.centre.history.norecords.t=-- nessuna voce fino ad ora -- +tankview.tempApiKey.l=ApiKey per i messaggi automatici di temperatura dai dispositivi IoT: +tankview.tempApiKey.b=generazione chiave API +projectstats.plagueObservationRecordCount.l=evoluzioni osservate della peste: +plagueview.date.l=osservato il giorno: +plagueview.tank.l=acquario: +plagueview.plague.l=peste: +plagueview.laststatus.l=ultimo stato: +plagueview.curedate.l=registrato su: +plagueview.status.l=stato: +plagueview.save.b=Salva l'osservazione +reportview.14mp.chart.h=Punti di misura registrati di recente in retrospettiva +reportview.365d.chart.h=Punti di misura nella revisione annuale +reportview.90d.chart.h=Punti di misurazione nella revisione di 3 mesi +plagueview.duration.l=durata in giorni: +userportal.meassurement.reminder.h=Il vostro promemoria di misurazione: +userportal.meassurement.nosetting.t=Si pu\u00F2 impostare qui un promemoria se si vuole misurare qualcosa regolarmente. \ +Andare al proprio profilo utente e inserire l'intervallo di misurazione desiderato. +userprofile.reminderinfo.t=Se si desidera che nella pagina iniziale venga ricordato che \u00E8 necessario misurare un determinato valore dell'acqua, \ +\u00E8 possibile inserire qui un intervallo di misurazione per il valore corrispondente. Al successivo accesso \ +al successivo accesso, SABI controlla quando \u00E8 stata effettuata l'ultima misurazione del valore dell'acqua e confronta se l'intervallo \ +memorizzato \u00E8 scaduto. +userprofile.reminderinfo.h=Ricordo per le misurazioni regolari +userportal.meassurement.unit.l=Parametro di misurazione +userportal.meassurement.duedate.l=Prossima misurazione +userportal.meassurement.dayinterval.l=Intervallo di misurazione in giorni +userprofile.meassurement.active.l=Attivato +userprofile.meassurement.dayinterval.l=Intervallo di misurazione in giorni +userprofile.meassurement.unit.l=Parametro di misurazione +userprofile.meassurement.addreminder.l=Impostare un promemoria per: +common.update.b=Aggiornamento +register.password.policy.t=(Password: minimo 10-20 caratteri. Maiuscole/minuscole, numeri e caratteri speciali). +enum.waterType.seawater.l=acqua salata +enum.waterType.freshwater.l=acqua dolce \ No newline at end of file From 5ea54c20b4a59ffcb96c316f6f5e186f9cdb02b3 Mon Sep 17 00:00:00 2001 From: Stefan Schubert Date: Sun, 25 Feb 2024 12:03:19 +0100 Subject: [PATCH 3/5] Added same more locales to captcha, too. Some PatcheManagement --- DEVELOPERS_MANUAL.md | 2 + captcha/pom.xml | 10 +- .../captcha/rest/CaptchaController.java | 2 +- .../captcha/service/QAGenerator.java | 135 +++++++----------- .../i18n/ChallengeSamples.properties | 21 +++ .../i18n/ChallengeSamples_de.properties | 21 +++ .../i18n/ChallengeSamples_en.properties | 21 +++ .../i18n/ChallengeSamples_es.properties | 21 +++ .../i18n/ChallengeSamples_fr.properties | 21 +++ .../i18n/ChallengeSamples_it.properties | 21 +++ .../resources/secured/userProfile.xhtml | 7 +- 11 files changed, 193 insertions(+), 89 deletions(-) create mode 100644 captcha/src/main/resources/i18n/ChallengeSamples.properties create mode 100644 captcha/src/main/resources/i18n/ChallengeSamples_de.properties create mode 100644 captcha/src/main/resources/i18n/ChallengeSamples_en.properties create mode 100644 captcha/src/main/resources/i18n/ChallengeSamples_es.properties create mode 100644 captcha/src/main/resources/i18n/ChallengeSamples_fr.properties create mode 100644 captcha/src/main/resources/i18n/ChallengeSamples_it.properties diff --git a/DEVELOPERS_MANUAL.md b/DEVELOPERS_MANUAL.md index 476d5f4a..89bf5a55 100644 --- a/DEVELOPERS_MANUAL.md +++ b/DEVELOPERS_MANUAL.md @@ -62,6 +62,8 @@ With a look at [Building-Block View](https://github.com/StefanSchubert/sabi/wiki YOUR_API_KEY +* If you work with IntelliJ: Install the "Jakarta Server Faces (JSF)" Plugin + #### Prepare your local docker environment Do some maven builds in the following order: diff --git a/captcha/pom.xml b/captcha/pom.xml index 7246197f..c53c2704 100644 --- a/captcha/pom.xml +++ b/captcha/pom.xml @@ -11,14 +11,14 @@ org.springframework.boot spring-boot-starter-parent - 3.2.1 + 3.2.2 4.0.0 de.bluewhale captcha-light - 1.2.4 + 1.2.5 jar A REST-full microservice service for CAPTCHA running as spring boot application @@ -46,9 +46,9 @@ UTF-8 UTF-8 2.3.0 - 1.12.1 - 9.0.7 - 3.2.3 + 1.12.3 + 9.0.9 + 3.2.5 2.16.2 diff --git a/captcha/src/main/java/de/bluewhale/captcha/rest/CaptchaController.java b/captcha/src/main/java/de/bluewhale/captcha/rest/CaptchaController.java index a22be542..5bf1e8f6 100644 --- a/captcha/src/main/java/de/bluewhale/captcha/rest/CaptchaController.java +++ b/captcha/src/main/java/de/bluewhale/captcha/rest/CaptchaController.java @@ -44,7 +44,7 @@ public class CaptchaController { @ResponseStatus(HttpStatus.OK) public ResponseEntity getNewCaptchaChallenge( @PathVariable(value = "language", required = true) - @Parameter(name = "language", description = "ISO-639-1 language code - used for i18n in communication.") String language) { + @Parameter(name = "language", description = "ISO-639-1 language code - used for i18n in communication. English will be used as fallback, if language is not available.") String language) { ResponseEntity response; diff --git a/captcha/src/main/java/de/bluewhale/captcha/service/QAGenerator.java b/captcha/src/main/java/de/bluewhale/captcha/service/QAGenerator.java index 565c1a55..a144fcb3 100644 --- a/captcha/src/main/java/de/bluewhale/captcha/service/QAGenerator.java +++ b/captcha/src/main/java/de/bluewhale/captcha/service/QAGenerator.java @@ -38,174 +38,131 @@ public class QAGenerator { // -------------------------- STATIC METHODS -------------------------- - // FIXME: 30.09.18 These data shuld be json config, which is loaded as runtime. - static { - // This pattern challenge1 could be dynamically generated on the fly - // as this is nonsense as the source is open...but for the start it's fine - ChallengeData challenge1 = new ChallengeData(); - challenge1.questionMap.put(Locale.GERMAN, "Welches passt nicht zum Muster?"); - challenge1.questionMap.put(Locale.ENGLISH, "Which one does not fit to the pattern?"); + // The questions from the ressource bundle will be combined with the possible answers in this step. + // The criteria for new questions is, that the possible answers are as language agnostic as possible. + + ChallengeData challenge1 = new ChallengeData(1); challenge1.answerMap.put("A1-B2-C2D", FALSE); challenge1.answerMap.put("K8-V4-W7H", FALSE); challenge1.answerMap.put("J6-N8-9T9", TRUE); challenge1.answerMap.put("V1-J3-Q2P", FALSE); - ChallengeData challenge2 = new ChallengeData(); - challenge2.questionMap.put(Locale.GERMAN, "Was passt nicht?"); - challenge2.questionMap.put(Locale.ENGLISH, "Which option does not fit?"); + ChallengeData challenge2 = new ChallengeData(2); challenge2.answerMap.put("Saturn", FALSE); challenge2.answerMap.put("Jupiter", FALSE); challenge2.answerMap.put("Moon", TRUE); challenge2.answerMap.put("Venus", FALSE); - ChallengeData challenge3 = new ChallengeData(); - challenge3.questionMap.put(Locale.GERMAN, "Welcher Wert muss gering gehalten werden?"); - challenge3.questionMap.put(Locale.ENGLISH, "Which value is to be minimized?"); + ChallengeData challenge3 = new ChallengeData(3); challenge3.answerMap.put("PO4", TRUE); challenge3.answerMap.put("Ca", FALSE); challenge3.answerMap.put("Mg", FALSE); challenge3.answerMap.put("NO3", FALSE); - ChallengeData challenge4 = new ChallengeData(); - challenge4.questionMap.put(Locale.GERMAN, "Was gibt es davon sprachlich?"); - challenge4.questionMap.put(Locale.ENGLISH, "Which one exists likely as spoken words?"); + ChallengeData challenge4 = new ChallengeData(4); challenge4.answerMap.put("+-0", TRUE); challenge4.answerMap.put("#-#", FALSE); challenge4.answerMap.put("+##", FALSE); challenge4.answerMap.put("##0", FALSE); - ChallengeData challenge5 = new ChallengeData(); - challenge5.questionMap.put(Locale.GERMAN, "Wen wĂŒrdest du aufmuntern?"); - challenge5.questionMap.put(Locale.ENGLISH, "Who needs a little support?"); + ChallengeData challenge5 = new ChallengeData(5); challenge5.answerMap.put(":-)", FALSE); challenge5.answerMap.put(";-)", FALSE); challenge5.answerMap.put(":-(", TRUE); challenge5.answerMap.put(":-x", FALSE); - ChallengeData challenge6 = new ChallengeData(); - challenge6.questionMap.put(Locale.GERMAN, "Platform 9 3/4 was passt dazu am besten?"); - challenge6.questionMap.put(Locale.ENGLISH, "Platform 9 3/4 which association fits best?"); + ChallengeData challenge6 = new ChallengeData(6); challenge6.answerMap.put("@@@@@", FALSE); challenge6.answerMap.put("#####", FALSE); challenge6.answerMap.put("+++++", FALSE); challenge6.answerMap.put("=====", TRUE); - ChallengeData challenge7 = new ChallengeData(); - challenge7.questionMap.put(Locale.GERMAN, "Was wĂŒrdest du vermehren?"); - challenge7.questionMap.put(Locale.ENGLISH, "Which one would you increase?"); + ChallengeData challenge7 = new ChallengeData(7); challenge7.answerMap.put("@@@", FALSE); challenge7.answerMap.put("§§§", FALSE); challenge7.answerMap.put("%%%", FALSE); challenge7.answerMap.put("$$$", TRUE); - ChallengeData challenge8 = new ChallengeData(); - challenge8.questionMap.put(Locale.GERMAN, "Was nimmt mehr FlĂ€che ein?"); - challenge8.questionMap.put(Locale.ENGLISH, "Which one occupies the bigger space?"); + ChallengeData challenge8 = new ChallengeData(8); challenge8.answerMap.put("C", FALSE); challenge8.answerMap.put("W", TRUE); challenge8.answerMap.put("I", FALSE); challenge8.answerMap.put("L", FALSE); - ChallengeData challenge9 = new ChallengeData(); - challenge9.questionMap.put(Locale.GERMAN, "Wenn jeder Strich ein Bleistift wĂ€re und du diese nun in eine Linie setzt, was gibt die lĂ€ngere Strecke?"); - challenge9.questionMap.put(Locale.ENGLISH, "If each line is a pencil and you set them in a line, which one would result in the max line?"); + ChallengeData challenge9 = new ChallengeData(9); challenge9.answerMap.put("=====", FALSE); challenge9.answerMap.put("#####", TRUE); challenge9.answerMap.put("NNNNN", FALSE); challenge9.answerMap.put("XXXXX", FALSE); - ChallengeData challenge10 = new ChallengeData(); - challenge10.questionMap.put(Locale.GERMAN, "Was wird immer besser erreichbar?"); - challenge10.questionMap.put(Locale.ENGLISH, "Which one gets more and more reachable?"); + ChallengeData challenge10 = new ChallengeData(10); challenge10.answerMap.put("Jupiter", FALSE); challenge10.answerMap.put("Mars", TRUE); challenge10.answerMap.put("Venus", FALSE); challenge10.answerMap.put("Saturn", FALSE); - ChallengeData challenge11 = new ChallengeData(); - challenge11.questionMap.put(Locale.GERMAN, "Welche Box passt 27 mal in eine 15x15x15 Box?"); - challenge11.questionMap.put(Locale.ENGLISH, "Which box fits 27 times in a 15x15x15 box?"); + ChallengeData challenge11 = new ChallengeData(11); challenge11.answerMap.put("10x10x10 Box", FALSE); challenge11.answerMap.put("5x5x5 Box", TRUE); challenge11.answerMap.put("4x8x12 Box", FALSE); challenge11.answerMap.put("20x20x20 Box", FALSE); - ChallengeData challenge12 = new ChallengeData(); - challenge12.questionMap.put(Locale.GERMAN, "Welcher Ball rollt am ehesten durch ein MĂ€useloch?"); - challenge12.questionMap.put(Locale.ENGLISH, "Which ball is likely to be rolling through a mouse hole?"); + ChallengeData challenge12 = new ChallengeData(12); challenge12.answerMap.put("5cm Ball", TRUE); challenge12.answerMap.put("10cm Ball", FALSE); challenge12.answerMap.put("15cm Ball", FALSE); challenge12.answerMap.put("20cm Ball", FALSE); - ChallengeData challenge13 = new ChallengeData(); - challenge13.questionMap.put(Locale.GERMAN, "Hinter dir kollidieren zwei schnelle Objekte, wo wirst du es am geringsten bemerken?"); - challenge13.questionMap.put(Locale.ENGLISH, "Two fast objects are colliding behind you, where will you hardly recognize it?"); + ChallengeData challenge13 = new ChallengeData(13); challenge13.answerMap.put("500km NN", TRUE); challenge13.answerMap.put("10km NN", FALSE); challenge13.answerMap.put("-50m NN (sea)", FALSE); challenge13.answerMap.put("5m NN", FALSE); - ChallengeData challenge14 = new ChallengeData(); - challenge14.questionMap.put(Locale.GERMAN, "Welches davon kippen manche in ihr Riff-Aquarium?"); - challenge14.questionMap.put(Locale.ENGLISH, "Which one of these will be added by some of us to the reef-tank?"); + ChallengeData challenge14 = new ChallengeData(14); challenge14.answerMap.put("Blue Curaçao", FALSE); challenge14.answerMap.put("Vodka", TRUE); challenge14.answerMap.put("Campari", FALSE); challenge14.answerMap.put("Ginger Ale", FALSE); - ChallengeData challenge15 = new ChallengeData(); - challenge15.questionMap.put(Locale.GERMAN, "Wer fĂ€llt aus der Reihe?"); - challenge15.questionMap.put(Locale.ENGLISH, "Who does not fit here?"); + ChallengeData challenge15 = new ChallengeData(15); challenge15.answerMap.put("Wall-E", FALSE); challenge15.answerMap.put("E.T.", TRUE); challenge15.answerMap.put("R2D2", FALSE); challenge15.answerMap.put("No.5", FALSE); - ChallengeData challenge16 = new ChallengeData(); - challenge16.questionMap.put(Locale.GERMAN, "Welche Eigenschaften von Seegraswiesen können uns zukĂŒnftig helfen?"); - challenge16.questionMap.put(Locale.ENGLISH, "What are the best capabilities of Seaweed-Cultures for our furture?"); + ChallengeData challenge16 = new ChallengeData(16); challenge16.answerMap.put("\\|/\\|/", FALSE); challenge16.answerMap.put("Superfood", FALSE); challenge16.answerMap.put("C02-Storage", TRUE); challenge16.answerMap.put("=~=~=~~", FALSE); - ChallengeData challenge17 = new ChallengeData(); - challenge17.questionMap.put(Locale.GERMAN, "Welche Zahl ist nur durch eins und sich selbst teilbar, so dass das Ergebnis wieder eine Ganze Zahl ergibt?"); - challenge17.questionMap.put(Locale.ENGLISH, "If the result must be a whole number, which one of those can be divided only by 1 and itself?"); + ChallengeData challenge17 = new ChallengeData(17); challenge17.answerMap.put("9", FALSE); challenge17.answerMap.put("4", FALSE); challenge17.answerMap.put("22", FALSE); challenge17.answerMap.put("5", TRUE); - ChallengeData challenge18 = new ChallengeData(); - challenge18.questionMap.put(Locale.GERMAN, "Was geschieht mit Korallen bei einer durchschnittlichen Wassertemperatur vom 30°C"); - challenge18.questionMap.put(Locale.ENGLISH, "What happens to corals if the average water temperature is around 86°F?"); + ChallengeData challenge18 = new ChallengeData(18); challenge18.answerMap.put("☠", TRUE); challenge18.answerMap.put("🩐", FALSE); challenge18.answerMap.put("🐡", FALSE); challenge18.answerMap.put("đŸ§œđŸœâ€", FALSE); - ChallengeData challenge19 = new ChallengeData(); - challenge19.questionMap.put(Locale.GERMAN, "Was geschieht wahrscheinlich mit den nĂŒtzlichen Bakterien in deinem Riff, wenn der KH-Wert sinkt?"); - challenge19.questionMap.put(Locale.ENGLISH, "What is likely to happen to the useful bacteria in your reef if the carbonate level decreases?"); + ChallengeData challenge19 = new ChallengeData(19); challenge19.answerMap.put("🩐", FALSE); challenge19.answerMap.put("🐡", FALSE); challenge19.answerMap.put("đŸ§œđŸœâ€", FALSE); challenge19.answerMap.put("☠", TRUE); - ChallengeData challenge20 = new ChallengeData(); - challenge20.questionMap.put(Locale.GERMAN, "Wer von den gezeigten hat die Chance Ă€lter als die anderen zu werden?"); - challenge20.questionMap.put(Locale.ENGLISH, "Who among those shown has the chance to become older than the others?"); + ChallengeData challenge20 = new ChallengeData(20); challenge20.answerMap.put("🐬", FALSE); challenge20.answerMap.put("🐒", FALSE); challenge20.answerMap.put("🐱", TRUE); challenge20.answerMap.put("🩉", FALSE); - ChallengeData challenge21 = new ChallengeData(); - challenge21.questionMap.put(Locale.GERMAN, "Emotie RĂ€tsel: Welche Kombination reprĂ€sentiert den Song Titel 'Walking this way'?"); - challenge21.questionMap.put(Locale.ENGLISH, "Emotie quiz: Which combination represents the song 'Walking this way'?"); + ChallengeData challenge21 = new ChallengeData(21); challenge21.answerMap.put("đŸȘąđŸ‘€", FALSE); challenge21.answerMap.put("đŸš¶â€âžĄïž", TRUE); challenge21.answerMap.put("🏄‍💹", FALSE); @@ -245,24 +202,42 @@ public class QAGenerator { */ public ChallengeTo provideChallengeFor(final String pLanguage) { - int questionIndex = random.nextInt(dataSet.size()); - - Object[] challenges = dataSet.toArray(); - ChallengeData challengeData = (ChallengeData) challenges[questionIndex]; - - ChallengeTo challengeTo = new ChallengeTo(); - - Map questionMap = challengeData.questionMap; Locale locale; try { - locale = new Locale(pLanguage); + + // check for supported locales and set "en" as fallback + switch (pLanguage) { + case "de": + case "en": + case "fr": + case "es": + case "it": + locale = new Locale(pLanguage); + break; + default: locale = Locale.ENGLISH; + } + locale.getISO3Language(); // semantic check + } catch (MissingResourceException pE) { locale = Locale.ENGLISH; } + + ResourceBundle bundle = ResourceBundle.getBundle("i18n/ChallengeSamples", locale); + + int questionIndex = random.nextInt(dataSet.size()); + + Object[] challenges = dataSet.toArray(); + ChallengeData challengeData = (ChallengeData) challenges[questionIndex]; + + ChallengeTo challengeTo = new ChallengeTo(); + challengeTo.setLanguage(locale.getLanguage()); - challengeTo.setQuestion(questionMap.get(locale)); + + String localedQuestion = bundle.getString(challengeData.questionKey); + + challengeTo.setQuestion(localedQuestion); // As for the answer map, we generate answer tokens and for the right one // we register it with the ValidationCache. @@ -293,11 +268,11 @@ private String createToken(int pTOKEN_SIZE) { // -------------------------- INNER CLASSES -------------------------- private static class ChallengeData { - protected Map questionMap; + protected String questionKey; protected Map answerMap; // the one marked with true is the right answer. - public ChallengeData() { - this.questionMap = new HashMap(); + public ChallengeData(int challengeNumber) { + this.questionKey = "challenge."+challengeNumber+".question"; this.answerMap = new HashMap(); } } diff --git a/captcha/src/main/resources/i18n/ChallengeSamples.properties b/captcha/src/main/resources/i18n/ChallengeSamples.properties new file mode 100644 index 00000000..03934deb --- /dev/null +++ b/captcha/src/main/resources/i18n/ChallengeSamples.properties @@ -0,0 +1,21 @@ +challenge.1.question="Which one does not match the pattern?" +challenge.2.question="What does not fit?" +challenge.3.question="Which value must be kept low?" +challenge.4.question="What is there linguistically?" +challenge.5.question="Who would you cheer up?" +challenge.6.question="Platform 9 3/4 what fits best?" +challenge.7.question="What would you increase?" +challenge.8.question="What takes up more space?" +challenge.9.question="If each line were a pencil and you now put them in a line, what gives the longer distance?" +challenge.10.question="What is becoming more accessible?" +challenge.11.question="Which box fits 27 times into a 15x15x15 box?" +challenge.12.question="Which ball is most likely to roll through a mouse hole?" +challenge.13.question="Two fast objects collide behind you, where will you notice it the least?" +challenge.14.question="Which of these do some people tip into their reef aquarium?" +challenge.15.question="Who falls out of line?" +challenge.16.question="Which characteristics of seagrass meadows can help us in the future?" +challenge.17.question="Which number can only be divided by one and itself, so that the result is a whole number again?" +challenge.18.question="What happens to corals at an average water temperature of 30\u00B0C" +challenge.19.question="What is likely to happen to the beneficial bacteria in your reef when the KH value drops?" +challenge.20.question="Which of those shown has the chance to grow older than the others?" +challenge.21.question="Emotie riddle: Which combination represents the song title 'Walking this way'?" \ No newline at end of file diff --git a/captcha/src/main/resources/i18n/ChallengeSamples_de.properties b/captcha/src/main/resources/i18n/ChallengeSamples_de.properties new file mode 100644 index 00000000..6beebbd6 --- /dev/null +++ b/captcha/src/main/resources/i18n/ChallengeSamples_de.properties @@ -0,0 +1,21 @@ +challenge.1.question="Welches passt nicht zum Muster?" +challenge.2.question="Was passt nicht?" +challenge.3.question="Welcher Wert muss gering gehalten werden?" +challenge.4.question="Was gibt es davon sprachlich?" +challenge.5.question="Wen w\u00FCrdest du aufmuntern?" +challenge.6.question="Platform 9 3/4 was passt dazu am besten?" +challenge.7.question="Was w\u00FCrdest du vermehren?" +challenge.8.question="Was nimmt mehr Fl\u00E4che ein?" +challenge.9.question="Wenn jeder Strich ein Bleistift w\u00E4re und du diese nun in eine Linie setzt, was gibt die l\u00E4ngere Strecke?" +challenge.10.question="Was wird immer besser erreichbar?" +challenge.11.question="Welche Box passt 27 mal in eine 15x15x15 Box?" +challenge.12.question="Welcher Ball rollt am ehesten durch ein M\u00E4useloch?" +challenge.13.question="Hinter dir kollidieren zwei schnelle Objekte, wo wirst du es am geringsten bemerken?" +challenge.14.question="Welches davon kippen manche in ihr Riff-Aquarium?" +challenge.15.question="Wer f\u00E4llt aus der Reihe?" +challenge.16.question="Welche Eigenschaften von Seegraswiesen k\u00F6nnen uns zuk\u00FCnftig helfen?" +challenge.17.question="Welche Zahl ist nur durch eins und sich selbst teilbar, so dass das Ergebnis wieder eine Ganze Zahl ergibt?" +challenge.18.question="Was geschieht mit Korallen bei einer durchschnittlichen Wassertemperatur vom 30\u00B0C" +challenge.19.question="Was geschieht wahrscheinlich mit den n\u00FCtzlichen Bakterien in deinem Riff, wenn der KH-Wert sinkt?" +challenge.20.question="Wer von den gezeigten hat die Chance \u00E4lter als die anderen zu werden?" +challenge.21.question="Emotie R\u00E4tsel: Welche Kombination repr\u00E4sentiert den Song Titel 'Walking this way'?" \ No newline at end of file diff --git a/captcha/src/main/resources/i18n/ChallengeSamples_en.properties b/captcha/src/main/resources/i18n/ChallengeSamples_en.properties new file mode 100644 index 00000000..03934deb --- /dev/null +++ b/captcha/src/main/resources/i18n/ChallengeSamples_en.properties @@ -0,0 +1,21 @@ +challenge.1.question="Which one does not match the pattern?" +challenge.2.question="What does not fit?" +challenge.3.question="Which value must be kept low?" +challenge.4.question="What is there linguistically?" +challenge.5.question="Who would you cheer up?" +challenge.6.question="Platform 9 3/4 what fits best?" +challenge.7.question="What would you increase?" +challenge.8.question="What takes up more space?" +challenge.9.question="If each line were a pencil and you now put them in a line, what gives the longer distance?" +challenge.10.question="What is becoming more accessible?" +challenge.11.question="Which box fits 27 times into a 15x15x15 box?" +challenge.12.question="Which ball is most likely to roll through a mouse hole?" +challenge.13.question="Two fast objects collide behind you, where will you notice it the least?" +challenge.14.question="Which of these do some people tip into their reef aquarium?" +challenge.15.question="Who falls out of line?" +challenge.16.question="Which characteristics of seagrass meadows can help us in the future?" +challenge.17.question="Which number can only be divided by one and itself, so that the result is a whole number again?" +challenge.18.question="What happens to corals at an average water temperature of 30\u00B0C" +challenge.19.question="What is likely to happen to the beneficial bacteria in your reef when the KH value drops?" +challenge.20.question="Which of those shown has the chance to grow older than the others?" +challenge.21.question="Emotie riddle: Which combination represents the song title 'Walking this way'?" \ No newline at end of file diff --git a/captcha/src/main/resources/i18n/ChallengeSamples_es.properties b/captcha/src/main/resources/i18n/ChallengeSamples_es.properties new file mode 100644 index 00000000..d574fd0a --- /dev/null +++ b/captcha/src/main/resources/i18n/ChallengeSamples_es.properties @@ -0,0 +1,21 @@ +challenge.1.question="\u00BFCu\u00E1l no encaja en el patr\u00F3n?" +challenge.2.question="\u00BFCu\u00E1l no encaja?" +challenge.3.question="\u00BFQu\u00E9 valor debe mantenerse bajo?" +challenge.4.question="\u00BFQu\u00E9 hay ling\u00FC\u00EDsticamente?" +challenge.5.question="\u00BFA qui\u00E9n animar\u00EDas?" +challenge.6.question="Plataforma 9 3/4 \u00BFqu\u00E9 encaja mejor?" +challenge.7.question="\u00BFQu\u00E9 aumentar\u00EDas?" +challenge.8.question="\u00BFQu\u00E9 ocupa m\u00E1s espacio?" +challenge.9.question="Si cada l\u00EDnea fuera un l\u00E1piz y ahora los pusieras en fila, \u00BFqu\u00E9 da m\u00E1s distancia?" +challenge.10.question="\u00BFQu\u00E9 es cada vez m\u00E1s accesible?" +challenge.11.question="\u00BFQu\u00E9 caja cabe 27 veces en una caja de 15x15x15?" +challenge.12.question="\u00BFQu\u00E9 bola tiene m\u00E1s probabilidades de pasar por el agujero de un rat\u00F3n?" +challenge.13.question="Dos objetos r\u00E1pidos chocan detr\u00E1s de ti, \u00BFd\u00F3nde lo notar\u00E1s menos?" +challenge.14.question="\u00BFCu\u00E1l de estos objetos vuelcan algunas personas en su acuario de arrecife?" +challenge.15.question="\u00BFQui\u00E9n se cae de la fila?" +challenge.16.question="\u00BFQu\u00E9 caracter\u00EDsticas de las praderas marinas pueden ayudarnos en el futuro?" +challenge.17.question="\u00BFQu\u00E9 n\u00FAmero s\u00F3lo se puede dividir por uno y por s\u00ED mismo, de modo que el resultado vuelva a ser un n\u00FAmero entero?" +challenge.18.question="\u00BFQu\u00E9 les ocurre a los corales cuando la temperatura media del agua es de 30\u00BAC? +challenge.19.question="\u00BFQu\u00E9 les puede pasar a las bacterias beneficiosas de tu arrecife cuando baja el valor de KH?" +challenge.20.question="\u00BFCu\u00E1l de los que se muestran tiene m\u00E1s posibilidades de envejecer que los dem\u00E1s?" +challenge.21.question="Adivinanza Emotie: \u00BFQu\u00E9 combinaci\u00F3n representa el t\u00EDtulo de la canci\u00F3n 'Walking this way'?" \ No newline at end of file diff --git a/captcha/src/main/resources/i18n/ChallengeSamples_fr.properties b/captcha/src/main/resources/i18n/ChallengeSamples_fr.properties new file mode 100644 index 00000000..f5dabf02 --- /dev/null +++ b/captcha/src/main/resources/i18n/ChallengeSamples_fr.properties @@ -0,0 +1,21 @@ +challenge.1.question="Lequel ne correspond pas au mod\u00E8le ?" +challenge.2.question="Qu'est-ce qui ne correspond pas ?" +challenge.3.question="Quelle valeur doit \u00EAtre maintenue \u00E0 un niveau bas ?" +challenge.4.question="Qu'est-ce qui existe au niveau linguistique ?" +challenge.5.question="Qui encouragerais-tu ?" +challenge.6.question="Plateforme 9 3/4 qu'est-ce qui convient le mieux ?" +challenge.7.question="Que multiplierais-tu ?" +challenge.8.question="Qu'est-ce qui prend le plus de place ?" +challenge.9.question="Si chaque trait \u00E9tait un crayon et que tu les pla\u00E7ais maintenant sur une ligne, qu'est-ce qui donnerait la plus longue distance ?" +challenge.10.question="Qu'est-ce qui devient de plus en plus accessible ?" +challenge.11.question="Quelle bo\u00EEte tient 27 fois dans une bo\u00EEte de 15x15x15 ?" +challenge.12.question="Quelle balle a le plus de chances de rouler dans un trou de souris ?" +challenge.13.question="Derri\u00E8re toi, deux objets rapides entrent en collision, o\u00F9 le remarqueras-tu le moins ?" +challenge.14.question="Lequel des deux renverse-t-on dans son aquarium r\u00E9cifal ?" +challenge.15.question="Qui sort du lot ?" +challenge.16.question="Quelles sont les caract\u00E9ristiques des herbiers marins qui peuvent nous aider \u00E0 l'avenir ?" +challenge.17.question="Quel nombre n'est divisible que par un et par lui-m\u00EAme, de sorte que le r\u00E9sultat soit \u00E0 nouveau un nombre entier ?" +challenge.18.question="Que se passe-t-il pour les coraux lorsque la temp\u00E9rature moyenne de l'eau est de 30\u00B0C ?" +challenge.19.question="Qu'arrive-t-il probablement aux bact\u00E9ries utiles dans ton r\u00E9cif lorsque le KH diminue ?" +challenge.20.question="Qui, parmi ceux pr\u00E9sent\u00E9s, a une chance de devenir plus vieux que les autres ?" +challenge.21.question="Enigme d'\u00E9motivit\u00E9 : quelle combinaison repr\u00E9sente le titre de la chanson 'Walking this way' ?" \ No newline at end of file diff --git a/captcha/src/main/resources/i18n/ChallengeSamples_it.properties b/captcha/src/main/resources/i18n/ChallengeSamples_it.properties new file mode 100644 index 00000000..24852e5f --- /dev/null +++ b/captcha/src/main/resources/i18n/ChallengeSamples_it.properties @@ -0,0 +1,21 @@ +challenge.1.question="Quale non corrisponde al modello?". +challenge.2.question="Cosa non corrisponde?". +challenge.3.question="Quale valore deve essere mantenuto basso?". +challenge.4.question="Cosa c'\u00E8 a livello linguistico?". +challenge.5.question="Chi vuoi tirar su di morale?". +challenge.6.question="Piattaforma 9 3/4 cosa si adatta meglio?" +challenge.7.question="Cosa aumenteresti?" +challenge.8.question="Cosa occupa pi\u00F9 spazio?" +challenge.9.question="Se ogni linea fosse una matita e le metteste in fila, quale sarebbe la distanza maggiore?". +challenge.10.question="Che cosa sta diventando pi\u00F9 accessibile?". +challenge.11.question="Quale scatola entra 27 volte in una scatola 15x15x15?". +challenge.12.question="Qual \u00E8 la palla che ha pi\u00F9 probabilit\u00E0 di rotolare attraverso il buco di un topo?". +challenge.13.question="Due oggetti veloci si scontrano dietro di te, dove lo noterai di meno?". +challenge.14.question="Quale di questi oggetti alcune persone rovesciano nel loro acquario di barriera?". +challenge.15.question="Chi cade fuori dalle righe?". +challenge.16.question="Quali caratteristiche delle praterie di fanerogame possono aiutarci in futuro?". +challenge.17.question="Quale numero pu\u00F2 essere diviso solo per uno e per se stesso, in modo che il risultato sia di nuovo un numero intero?". +challenge.18.question="Cosa succede ai coralli a una temperatura media dell'acqua di 30\u00B0C". +challenge.19.question="Cosa pu\u00F2 succedere ai batteri benefici della barriera corallina quando il valore del KH si abbassa?" +challenge.20.question="Quale di quelli mostrati ha la possibilit\u00E0 di invecchiare rispetto agli altri?" +challenge.21.question="Indovinello di Emotie: quale combinazione rappresenta il titolo della canzone 'Walking this way'?". \ No newline at end of file diff --git a/sabi-webclient/src/main/resources/META-INF/resources/secured/userProfile.xhtml b/sabi-webclient/src/main/resources/META-INF/resources/secured/userProfile.xhtml index 091b84d7..c59595b8 100644 --- a/sabi-webclient/src/main/resources/META-INF/resources/secured/userProfile.xhtml +++ b/sabi-webclient/src/main/resources/META-INF/resources/secured/userProfile.xhtml @@ -104,8 +104,9 @@ /> - + @@ -133,7 +134,7 @@ + action="#{userProfileView.save}"/> From 35443f8211349c3a34604f2047b2c4ea460f0250 Mon Sep 17 00:00:00 2001 From: Stefan Schubert Date: Sun, 25 Feb 2024 17:13:15 +0100 Subject: [PATCH 4/5] Fixes i18n Bundle - broken key issue Tuned logging --- captcha/pom.xml | 9 +++++++ .../captcha/rest/CaptchaController.java | 4 +++ .../captcha/service/QAGenerator.java | 2 ++ captcha/src/main/resources/application.yml | 10 ------- captcha/src/main/resources/log4j2-spring.xml | 5 ++-- .../resources/i18n/messages_es.properties | 17 ++++++------ .../resources/i18n/messages_fr.properties | 3 +-- .../resources/i18n/messages_it.properties | 27 +++++++++---------- 8 files changed, 40 insertions(+), 37 deletions(-) diff --git a/captcha/pom.xml b/captcha/pom.xml index c53c2704..e4657869 100644 --- a/captcha/pom.xml +++ b/captcha/pom.xml @@ -47,6 +47,7 @@ UTF-8 2.3.0 1.12.3 + 1.18.30 9.0.9 3.2.5 2.16.2 @@ -106,6 +107,14 @@ ${springdoc.openapiv2.version} + + + org.projectlombok + lombok + ${lombok.version} + provided + + org.springframework.boot diff --git a/captcha/src/main/java/de/bluewhale/captcha/rest/CaptchaController.java b/captcha/src/main/java/de/bluewhale/captcha/rest/CaptchaController.java index 5bf1e8f6..d8abb103 100644 --- a/captcha/src/main/java/de/bluewhale/captcha/rest/CaptchaController.java +++ b/captcha/src/main/java/de/bluewhale/captcha/rest/CaptchaController.java @@ -13,6 +13,7 @@ import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -26,6 +27,7 @@ */ @RestController @RequestMapping(value = "api/") +@Slf4j public class CaptchaController { @Autowired @@ -46,9 +48,11 @@ public ResponseEntity getNewCaptchaChallenge( @PathVariable(value = "language", required = true) @Parameter(name = "language", description = "ISO-639-1 language code - used for i18n in communication. English will be used as fallback, if language is not available.") String language) { + log.debug("Received new challenge request for langcode {}", language); ResponseEntity response; if (ChallengeRequestThrottle.requestAllowed()) { + log.debug("Request passed throttle barrier"); ChallengeTo challengeTo = generator.provideChallengeFor(language); response = new ResponseEntity<>(challengeTo, HttpStatus.OK); } else { diff --git a/captcha/src/main/java/de/bluewhale/captcha/service/QAGenerator.java b/captcha/src/main/java/de/bluewhale/captcha/service/QAGenerator.java index a144fcb3..f73d379d 100644 --- a/captcha/src/main/java/de/bluewhale/captcha/service/QAGenerator.java +++ b/captcha/src/main/java/de/bluewhale/captcha/service/QAGenerator.java @@ -6,6 +6,7 @@ package de.bluewhale.captcha.service; import de.bluewhale.captcha.model.ChallengeTo; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.*; @@ -27,6 +28,7 @@ * @author Stefan Schubert */ @Service +@Slf4j public class QAGenerator { private static final int TOKEN_SIZE = 5; // ------------------------------ FIELDS ------------------------------ diff --git a/captcha/src/main/resources/application.yml b/captcha/src/main/resources/application.yml index a5203cca..b3b09499 100644 --- a/captcha/src/main/resources/application.yml +++ b/captcha/src/main/resources/application.yml @@ -35,13 +35,3 @@ spring: token: # Time in milliseconds before a cached answer token expires. TTL: 120000 - -logging: - level: - de: - bluewhale: - sabi: INFO - org: - springframework: ERROR - pattern: - console: '%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n' diff --git a/captcha/src/main/resources/log4j2-spring.xml b/captcha/src/main/resources/log4j2-spring.xml index 2dbf6c9b..7a3a2d26 100644 --- a/captcha/src/main/resources/log4j2-spring.xml +++ b/captcha/src/main/resources/log4j2-spring.xml @@ -14,8 +14,7 @@ %d %p %C{1.} [%t] %m%n - + @@ -32,7 +31,7 @@ - + \ No newline at end of file diff --git a/sabi-webclient/src/main/resources/i18n/messages_es.properties b/sabi-webclient/src/main/resources/i18n/messages_es.properties index b0fe4907..e3640566 100644 --- a/sabi-webclient/src/main/resources/i18n/messages_es.properties +++ b/sabi-webclient/src/main/resources/i18n/messages_es.properties @@ -5,7 +5,7 @@ register.captcha_wrongAnswer.t=Lo sentimos - Respuesta incorrecta. Por favor, int\u00E9ntelo de nuevo. login.welcome.h=Bienvenido al proyecto SABI - Seawater Aquarium Business Intelligence logout.message.t=Su sesi\u00F3n de usuario ha finalizado. Gracias por participar en este proyecto.\ -Nos vemos \u00BFO ha cerrado la sesi\u00F3n por accidente?
~
\ +Nos vemos \u00BFO ha cerrado la sesi\u00F3n por accidente?
\

Aqu\u00ED puedes volver a unirte: logout.header.h=Adi\u00F3s - hasta la pr\u00F3xima... register.cancel.b=Cancelar @@ -42,7 +42,7 @@ La atenci\u00F3n se centra en el enfoque cient\u00EDfico. Los participantes se b Los participantes se benefician de una representaci\u00F3n gr\u00E1fica de sus datos de medici\u00F3n y de la informaci\u00F3n generada a partir del an\u00E1lisis de los datos. \ Actualmente, el proyecto se encuentra en la fase I (recopilaci\u00F3n de datos). En cuanto un n\u00FAmero suficiente de participantes\ suficientes datos de medici\u00F3n, iniciaremos la fase II (an\u00E1lisis). -preregistro.info.t=Casi perfecto. Su nombre de usuario y contrase\u00F1a han sido aceptados.\ +preregistration.info.t=Casi perfecto. Su nombre de usuario y contrase\u00F1a han sido aceptados.\ En los pr\u00F3ximos minutos recibir\u00E1 un correo electr\u00F3nico con un enlace de activaci\u00F3n para validar su direcci\u00F3n de correo electr\u00F3nico.\ Una vez que el correo electr\u00F3nico ha sido validado, puede utilizar sus credenciales para iniciar sesi\u00F3n en sabi \ a trav\u00E9s de https://sabi-project.net/login.html para\ @@ -84,8 +84,8 @@ login.forgottenPW.l=\u00BFContrase\u00F1a olvidada? \u00BFError tipogr\u00E1fico login.resetPW.b=restablecer contrase\u00F1a login.panel.h=Por favor, inicie sesi\u00F3n: projectstats.tankcount.l=Tanques registrados: -projecttats.usercount.l=Participantes del proyecto: -userportal.projecttate.l=Estado-actual-del-proyecto: +projectstats.usercount.l=Participantes del proyecto: +userportal.projectstate.l=Estado-actual-del-proyecto: userportal.currentprojectstate.l=Etapa 1 - Recogida de datos menu.measureView.l=Adquisici\u00F3n de datos de medici\u00F3n common.tankchoice.l=Tanque: @@ -99,12 +99,13 @@ credits.sponsor_wife.t=Por todas las horas extra mir\u00E1ndome delante del port common.select.l=Seleccionar una... measureview.listing.h=Grabado recientemente: crowdfounding.title.h=\u00BFD\u00F3nde ha ido a parar todo el dinero? Informe sobre peque\u00F1as finanzas: -crowdfunding.introduction.t=

Hay varias maneras de apoyar este proyecto de ciencia abierta:

\ +crowdfunding.introduction.t=

Hay varias maneras de apoyar este proyecto de ciencia abierta:

\
    \
  • Como desarrollador a trav\u00E9s de github
  • \
  • Como Participante para compartir sus datos m\u00E9tricos
  • \
  • Como Patrocinador para hacerse cargo de los costes materiales y operativos
  • \
\ + \

Como patrocinador y propietario del proyecto pas\u00E9 bastante de mi tiempo libre realizando trabajos de concepci\u00F3n, programaci\u00F3n y operaci\u00F3n. \ Asumiendo los costes operativos iniciales del primer centro de datos de sabis (raspberry pis con base en casa)...\ Sin embargo, espero que algunos de ustedes est\u00E9n dispuestos a dejar que la plataforma operativa de SABI crezca para que tenga una base s\u00F3lida.\ @@ -158,10 +159,10 @@ sessionExpired.message.t=Su sesi\u00F3n de usuario ha alcanzado un tiempo l\u00E projectstats.measurementcount.l=Cuento de mediciones: menu.plagueView.l=Centro de plagas credits.sponsor_magazin_article.t=Para poder anunciar este proyecto a trav\u00E9s de un art\u00EDculo en la revista KORALLE-Magazine (Edici\u00F3n 136). -login.register.l=\u00BFA\u00FAn no se ha registrado? --> +login.register.l=\u00BFA\u00FAn no se ha registrado? plague.center.introduction.h=Bienvenido al Centro de Plagas SABIs. \u00BFDe qu\u00E9 se trata? plague.center.introduction.t=La visi\u00F3n central de SABI es identificar posibles correlaciones entre las mediciones de la calidad del agua y las plagas. \ -Para que esto sea posible, no s\u00F3lo deben registrarse regularmente los valores del agua, sino tambi\u00E9n la aparici\u00F3n y el curso de plagas espec\u00EDficas. +Para que esto sea posible, no s\u00F3lo deben registrarse regularmente los valores del agua, sino tambi\u00E9n la aparici\u00F3n y el curso de plagas espec\u00EDficas. \ plagas espec\u00EDficas de forma estructurada. Si el proyecto tiene \u00E9xito, podremos \ deducir la probabilidad de aparici\u00F3n de plagas en el acuario marino a partir de los valores del agua registrados \ y actuar como una especie de sistema de alerta temprana con recomendaciones sobre contramedidas adecuadas. @@ -188,7 +189,7 @@ reportview.14mp.chart.h=Revisi\u00F3n reciente de los puntos de medici\u00F3n plagueview.duration.l=Duraci\u00F3n en d\u00EDas: userportal.meassurement.reminder.h=Recordatorio de sus mediciones: userportal.meassurement.nosetting.t=Aqu\u00ED se le puede recordar si desea medir algo con regularidad. \ -Para ello, vaya a su perfil de usuario y guarde el intervalo de medici\u00F3n deseado.\ +Para ello, vaya a su perfil de usuario y guarde el intervalo de medici\u00F3n deseado. userprofile.reminderinfo.t=Si desea que se le recuerde en la p\u00E1gina de inicio que debe medir un determinado valor de agua, \ puede establecer aqu\u00ED un intervalo de medici\u00F3n para el valor correspondiente. La pr\u00F3xima vez que inicie sesi\u00F3n, \ SABI comprobar\u00E1 cu\u00E1ndo ha medido el valor del agua por \u00FAltima vez y si el intervalo de medici\u00F3n previsto ha expirado. diff --git a/sabi-webclient/src/main/resources/i18n/messages_fr.properties b/sabi-webclient/src/main/resources/i18n/messages_fr.properties index 70c62000..754b31ac 100644 --- a/sabi-webclient/src/main/resources/i18n/messages_fr.properties +++ b/sabi-webclient/src/main/resources/i18n/messages_fr.properties @@ -6,7 +6,7 @@ register.captcha_wrongAnswer.t=Mais... ce n'\u00E9tait pas la bonne r\u00E9ponse login.welcome.h=Bienvenue au projet SABI - Seawater Aquarium Business Intelligence logout.message.t=La session utilisateur a \u00E9t\u00E9 ferm\u00E9e. Nous vous remercions de votre participation au projet.
Nous vous remercions de votre participation au projet.\ A la prochaine fois ! Ou simplement d\u00E9connect\u00E9 par erreur ?
\ -

Voici le retour : +

Voici le retour: logout.header.h=\u00C0 la prochaine fois... register.cancel.b=Annuler register.register.b=Cr\u00E9er un compte utilisateur @@ -47,7 +47,6 @@ des valeurs de mesure ainsi que des connaissances acquises au cours du projet. \ Actuellement, le projet se trouve en phase I (collecte de donn\u00E9es). D\u00E8s que le nombre de \ participants se sont r\u00E9unis et ont fourni une quantit\u00E9 suffisante de donn\u00E9es de mesure \ le projet passera \u00E0 la phase II (analyse). - preregistration.info.t=Presque termin\u00E9. Le nom d'utilisateur n'\u00E9tait pas encore attribu\u00E9 et a \u00E9t\u00E9 cr\u00E9\u00E9 avec succ\u00E8s. \ Dans la minute qui suit, vous recevrez un e-mail avec un lien d'activation pour confirmer que votre adresse e-mail est valide. \ D\u00E8s que votre adresse e-mail a \u00E9t\u00E9 v\u00E9rifi\u00E9e par ce biais, votre login est activ\u00E9 et vous pouvez vous connecter via \ diff --git a/sabi-webclient/src/main/resources/i18n/messages_it.properties b/sabi-webclient/src/main/resources/i18n/messages_it.properties index d9e4c0c2..6eadca75 100644 --- a/sabi-webclient/src/main/resources/i18n/messages_it.properties +++ b/sabi-webclient/src/main/resources/i18n/messages_it.properties @@ -47,8 +47,7 @@ valori misurati e delle conoscenze acquisite nel corso del progetto. \ Il progetto \u00E8 attualmente nella Fase I (raccolta dati). Non appena un numero sufficiente di \ partecipanti che hanno fornito un numero sufficientemente elevato di dati di misurazione, il progetto passer\u00E0 alla fase I (raccolta dati). \ dati, il progetto passer\u00E0 alla fase II (analisi). - -preregistrazione.info.t=Quasi finito. Il nome utente non era ancora stato assegnato ed \u00E8 stato creato con successo. \ +preregistration.info.t=Quasi finito. Il nome utente non era ancora stato assegnato ed \u00E8 stato creato con successo. \ Entro un minuto riceverete un'e-mail con un link di attivazione per confermare la validit\u00E0 del vostro indirizzo e-mail. \ Non appena l'indirizzo e-mail \u00E8 stato verificato, il login sar\u00E0 attivato e sar\u00E0 possibile accedere tramite \ https://sabi-project.net/login.html per accedere. @@ -99,7 +98,7 @@ measureview.value.l=Valore misurato: common.unitchoise.l=Unit\u00E0: measureview.date.l=Misurato il giorno: common.new_record.b=Nuovo inserimento -crediti.sponsor_moglie.l=moglie +credits.sponsor_wife.l=moglie credits.sponsor_wife.t=Per il tempo sacrificato trascorso insieme davanti al computer dopo il lavoro. common.select.l=Selezione... measureview.listing.h=Le ultime misurazioni: @@ -139,8 +138,8 @@ measureview.mode.editrecord.l=Modalit\u00E0: modifica set di dati esistenti measureview.mode.newrecord.l=Modalit\u00E0: aggiungere un record di dati userprofile.h=Profilo utente per common.additional.info.t=A causa del budget volutamente ridotto all'inizio del progetto, questo servizio \u00E8 attualmente \ -esclusivamente nel "nuovo" Internet basato su IPv6. -accessibile. Se il provider Internet locale non fornisce l'IPv6, \code(0144)\. +esclusivamente nel "nuovo" Internet basato su IPv6. \ +accessibile. Se il provider Internet locale non fornisce l'IPv6, \ c'\u00E8 di solito la possibilit\u00E0 di accedervi tramite telefono cellulare (con WLAN disattivata). impressum.role.t=Fondatore e responsabile del progetto: gdpr.menu.l=GDPR @@ -159,21 +158,21 @@ sessionExpired.message.t=La sessione utente \u00E8 scaduta dopo un timeout. Se q

Eseguire nuovamente il login: projectstats.measurementcount.l=Numero di dati di misurazione: menu.plagueView.l=Centro della peste -credits.sponsor_magazine_article.t=Per aver pubblicizzato il progetto in un articolo della rivista KORALLE (numero 136). +credits.sponsor_magazin_article.t=Per aver pubblicizzato il progetto in un articolo della rivista KORALLE (numero 136). login.register.l=Senza login? --> -plague.centre.introduction.h=Benvenuto nel centro peste della SABI. Di cosa si tratta? -plague.centre.introduction.t=La visione centrale della SABI \u00E8 quella di identificare possibili correlazioni tra le misurazioni della qualit\u00E0 dell'acqua e le pestilenze. \ +plague.center.introduction.h=Benvenuto nel centro peste della SABI. Di cosa si tratta? +plague.center.introduction.t=La visione centrale della SABI \u00E8 quella di identificare possibili correlazioni tra le misurazioni della qualit\u00E0 dell'acqua e le pestilenze. \ Per rendere possibile questo, non solo i valori dell'acqua devono essere registrati regolarmente, ma soprattutto l'insorgenza e il decorso di specifiche pestilenze. \ e il decorso di specifiche epidemie devono essere registrati in modo strutturato. Se il progetto avr\u00E0 successo, potremo \u00B4\u00B4 ricavare la probabilit\u00E0 di insorgenza delle piaghe. \ ricavare la probabilit\u00E0 di insorgenza di parassiti nell'acquario marino sulla base dei valori dell'acqua riportati e utilizzarla come una sorta di sistema di \u25A0 allarme precoce con raccomandazioni per le opportune contromisure. \ come una sorta di sistema di allerta precoce con raccomandazioni di contromisure adeguate. -plague.centre.mystatus.h=Peste attualmente segnalate nei miei acquari: -plague.centre.mystatus.noplague.t=-- nessuna voce -- -plague.centre.addrecord.h=Segnala una nuova piaga o aggiorna lo stato: -plague.centre.info.t=La storia della peste attuale viene riassunta automaticamente e termina solo con il messaggio di terminazione. +plague.center.mystatus.h=Peste attualmente segnalate nei miei acquari: +plague.center.mystatus.noplague.t=-- nessuna voce -- +plague.center.addrecord.h=Segnala una nuova piaga o aggiorna lo stato: +plague.center.info.t=La storia della peste attuale viene riassunta automaticamente e termina solo con il messaggio di terminazione. \ messaggio di terminazione. -plague.centre.history.h=Direttore delle piaghe sopravvissute -plague.centre.history.norecords.t=-- nessuna voce fino ad ora -- +plague.center.history.h=Direttore delle piaghe sopravvissute +plague.center.history.norecords.t=-- nessuna voce fino ad ora -- tankview.tempApiKey.l=ApiKey per i messaggi automatici di temperatura dai dispositivi IoT: tankview.tempApiKey.b=generazione chiave API projectstats.plagueObservationRecordCount.l=evoluzioni osservate della peste: From 44a46f9bc7c7162decfae98f1629509a3da871ef Mon Sep 17 00:00:00 2001 From: Stefan Schubert Date: Sun, 3 Mar 2024 12:30:04 +0100 Subject: [PATCH 5/5] Enhanced i18n sabi-17 (#158) * sabi-17 i18n of measurement, unit, parameters name and description - plagues - parameters - unit --- CHANGELOG.md | 5 + devops/sabi_docker_sdk/docker-compose-arm.yml | 4 +- devops/sabi_docker_sdk/docker-compose.yml | 2 +- .../version1_3_0/V1_3_0_2__i18nPlague.sql | 99 ++++++++++ .../version1_3_0/V1_3_0_3__i18nParameter.sql | 124 ++++++++++++ .../version1_3_0/V1_3_0_4__i18nUnit.sql | 185 ++++++++++++++++++ sabi-server/pom.xml | 2 +- .../de/bluewhale/sabi/mapper/UnitMapper.java | 4 +- .../model/LocalizedParameterEntity.java | 38 ++++ .../model/LocalizedUnitEntity.java | 38 ++++ .../persistence/model/MeasurementEntity.java | 4 +- .../sabi/persistence/model/MotdEntity.java | 4 +- .../persistence/model/ParameterEntity.java | 16 +- .../sabi/persistence/model/PlagueEntity.java | 6 +- .../persistence/model/PlagueRecordEntity.java | 4 +- .../sabi/persistence/model/UnitEntity.java | 13 +- .../sabi/persistence/model/UserEntity.java | 4 +- .../repositories/LocalizedUnitRepository.java | 28 +++ .../controller/MeasurementController.java | 8 +- .../sabi/rest/controller/UnitController.java | 15 +- .../sabi/services/MeasurementService.java | 12 +- .../sabi/services/MeasurementServiceImpl.java | 32 ++- .../sabi/services/TankServiceImpl.java | 4 +- .../src/main/resources/application.yml | 4 + .../de/bluewhale/sabi/BasicDataFactory.java | 42 +++- .../sabi/services/MeasurementServiceTest.java | 8 +- .../services/rest/UnitControllerTest.java | 17 +- sabi-webclient/pom.xml | 2 +- .../apigateway/MeasurementService.java | 13 +- .../apigateway/MeasurementServiceImpl.java | 23 ++- .../controller/AbstractControllerTools.java | 6 +- .../controller/MeasurementListView.java | 8 +- .../sabi/webclient/controller/ReportView.java | 8 +- .../webclient/controller/TankListView.java | 4 +- .../webclient/controller/UserProfileView.java | 6 +- .../META-INF/resources/template/header.xhtml | 4 +- .../main/resources/i18n/messages.properties | 3 +- .../resources/i18n/messages_de.properties | 5 +- .../resources/i18n/messages_en.properties | 5 +- .../resources/i18n/messages_es.properties | 3 +- .../resources/i18n/messages_fr.properties | 3 +- .../resources/i18n/messages_it.properties | 3 +- 42 files changed, 708 insertions(+), 110 deletions(-) create mode 100644 sabi-database/src/main/resources/db/migration/version1_3_0/V1_3_0_2__i18nPlague.sql create mode 100644 sabi-database/src/main/resources/db/migration/version1_3_0/V1_3_0_3__i18nParameter.sql create mode 100644 sabi-database/src/main/resources/db/migration/version1_3_0/V1_3_0_4__i18nUnit.sql create mode 100644 sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/LocalizedParameterEntity.java create mode 100644 sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/LocalizedUnitEntity.java create mode 100644 sabi-server/src/main/java/de/bluewhale/sabi/persistence/repositories/LocalizedUnitRepository.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 18403d4c..c0f76a8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # History of changes (since 5/2022) +## Release 1.2.7 + +### Feature +* SABI-17: i18n of measurement units, parameter and plagues. + ## Release 1.2.6 ### Enhancements diff --git a/devops/sabi_docker_sdk/docker-compose-arm.yml b/devops/sabi_docker_sdk/docker-compose-arm.yml index c2ab61d6..ba622698 100644 --- a/devops/sabi_docker_sdk/docker-compose-arm.yml +++ b/devops/sabi_docker_sdk/docker-compose-arm.yml @@ -40,7 +40,7 @@ services: depends_on: - db db: - image: mariadb:11.1 + image: mariadb:11.3.2 platform: linux/arm64/v8 environment: - MYSQL_ROOT_PASSWORD=SuperDooper @@ -93,6 +93,6 @@ networks: sabinet: driver: bridge -# TODO: application.properties files contains "localhost" this does not matches the hosts, +# Notice: application.properties files contains "localhost" this does not matches the hosts, # db, fakeSMTP etc.. so the application.properties need to be externalized as in production # through the assets. \ No newline at end of file diff --git a/devops/sabi_docker_sdk/docker-compose.yml b/devops/sabi_docker_sdk/docker-compose.yml index b1f93ffd..b4543f0c 100644 --- a/devops/sabi_docker_sdk/docker-compose.yml +++ b/devops/sabi_docker_sdk/docker-compose.yml @@ -36,7 +36,7 @@ services: depends_on: - db db: - image: mariadb:11.1 + image: mariadb:11.3.2 platform: linux/amd64 environment: - MYSQL_ROOT_PASSWORD=SuperDooper diff --git a/sabi-database/src/main/resources/db/migration/version1_3_0/V1_3_0_2__i18nPlague.sql b/sabi-database/src/main/resources/db/migration/version1_3_0/V1_3_0_2__i18nPlague.sql new file mode 100644 index 00000000..cf401837 --- /dev/null +++ b/sabi-database/src/main/resources/db/migration/version1_3_0/V1_3_0_2__i18nPlague.sql @@ -0,0 +1,99 @@ +INSERT INTO localized_plague (plague_id, common_name, language, created_on, lastmod_on, optlock) +VALUES (6, 'Stella marina Asterina', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague (plague_id, common_name, language, created_on, lastmod_on, optlock) +VALUES (5, 'Alghe filamentose', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague (plague_id, common_name, language, created_on, lastmod_on, optlock) +VALUES (4, 'Dinoflagellate', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague (plague_id, common_name, language, created_on, lastmod_on, optlock) +VALUES (3, 'Vermi piatti', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague (plague_id, common_name, language, created_on, lastmod_on, optlock) +VALUES (2, 'Alghe a bolla', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague (plague_id, common_name, language, created_on, lastmod_on, optlock) +VALUES (1, 'Cianobatteri', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague (plague_id, common_name, language, created_on, lastmod_on, optlock) +VALUES (6, 'Étoile de mer Asterina', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague (plague_id, common_name, language, created_on, lastmod_on, optlock) +VALUES (5, 'Algues filamenteuses', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague (plague_id, common_name, language, created_on, lastmod_on, optlock) +VALUES (4, 'DinoflagellĂ©', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague (plague_id, common_name, language, created_on, lastmod_on, optlock) +VALUES (3, 'Vers plats', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague (plague_id, common_name, language, created_on, lastmod_on, optlock) +VALUES (2, 'Algues-bulles', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague (plague_id, common_name, language, created_on, lastmod_on, optlock) +VALUES (1, 'CyanobactĂ©ries', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague (plague_id, common_name, language, created_on, lastmod_on, optlock) +VALUES (6, 'Estrella de mar Asterina', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague (plague_id, common_name, language, created_on, lastmod_on, optlock) +VALUES (5, 'Algas filamentosas', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague (plague_id, common_name, language, created_on, lastmod_on, optlock) +VALUES (4, 'Dinoflagelados', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague (plague_id, common_name, language, created_on, lastmod_on, optlock) +VALUES (3, 'Gusanos planos', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague (plague_id, common_name, language, created_on, lastmod_on, optlock) +VALUES (2, 'Algas burbuja', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague (plague_id, common_name, language, created_on, lastmod_on, optlock) +VALUES (1, 'Cianobacterias', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague_status (plague_status_id, description, language, created_on, lastmod_on, optlock) +VALUES (1, 'Primera apariciĂłn', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague_status (plague_status_id, description, language, created_on, lastmod_on, optlock) +VALUES (2, 'Se extiende', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague_status (plague_status_id, description, language, created_on, lastmod_on, optlock) +VALUES (3, 'La expansiĂłn se estanca', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague_status (plague_status_id, description, language, created_on, lastmod_on, optlock) +VALUES (4, 'Lento declive', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague_status (plague_status_id, description, language, created_on, lastmod_on, optlock) +VALUES (5, 'DesapariciĂłn (fin de la plaga)', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague_status (plague_status_id, description, language, created_on, lastmod_on, optlock) +VALUES (1, 'PremiĂšre apparition', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague_status (plague_status_id, description, language, created_on, lastmod_on, optlock) +VALUES (2, 'Se propage', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague_status (plague_status_id, description, language, created_on, lastmod_on, optlock) +VALUES (3, 'Extension stagnante', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague_status (plague_status_id, description, language, created_on, lastmod_on, optlock) +VALUES (4, 'Recule lentement', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague_status (plague_status_id, description, language, created_on, lastmod_on, optlock) +VALUES (5, 'DisparaĂźt (fin du flĂ©au)', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague_status (plague_status_id, description, language, created_on, lastmod_on, optlock) +VALUES (1, 'Prima comparsa', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague_status (plague_status_id, description, language, created_on, lastmod_on, optlock) +VALUES (2, 'Si diffonde', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague_status (plague_status_id, description, language, created_on, lastmod_on, optlock) +VALUES (3, 'L\'espansione ristagna', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague_status (plague_status_id, description, language, created_on, lastmod_on, optlock) +VALUES (4, 'Lentamente diminuisce', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_plague_status (plague_status_id, description, language, created_on, lastmod_on, optlock) +VALUES (5, 'Scomparsa (fine della peste)', 'it', DEFAULT, DEFAULT, DEFAULT); + diff --git a/sabi-database/src/main/resources/db/migration/version1_3_0/V1_3_0_3__i18nParameter.sql b/sabi-database/src/main/resources/db/migration/version1_3_0/V1_3_0_3__i18nParameter.sql new file mode 100644 index 00000000..396b62dc --- /dev/null +++ b/sabi-database/src/main/resources/db/migration/version1_3_0/V1_3_0_3__i18nParameter.sql @@ -0,0 +1,124 @@ +CREATE TABLE `localized_parameter` +( + `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, + `parameter_id` INT UNSIGNED NOT NULL, + `description` VARCHAR(80) NOT NULL, + `language` VARCHAR(3) NOT NULL, + `created_on` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `lastmod_on` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `optlock` INT UNSIGNED NOT NULL DEFAULT 0, + PRIMARY KEY (`id`), + UNIQUE KEY `business_key` (`parameter_id`, `language`), + foreign key (parameter_id) references parameter(id) +) + ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8; + +ALTER TABLE parameter drop column description; + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (1, 'KarbonathĂ€rte', 'de', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (2, 'Temperatur', 'de', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (3, 'Magnesium', 'de', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (4, 'Calcium', 'de', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (5, 'PH', 'de', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (6, 'Phosphat', 'de', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (7, 'Salzgehalt', 'de', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (1, 'Carbonate hardness', 'en', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (2, 'temperature', 'en', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (3, 'magnesium', 'en', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (4, 'calcium', 'en', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (5, 'PH', 'en', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (6, 'phosphate', 'en', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (7, 'Salinity', 'en', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (2, 'temperatura', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (3, 'magnesio', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (4, 'calcio', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (5, 'PH', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (6, 'fosfato', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (7, 'Salinidad', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (1, 'Dureza del carbonato', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (1, 'Durezza del carbonato', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (2, 'temperatura', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (3, 'magnesio', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (4, 'calcio', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (5, 'PH', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (6, 'fosfato', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (7, 'SalinitĂ ', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (1, 'DuretĂ© carbonatĂ©e', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (2, 'TempĂ©rature', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (3, 'MagnĂ©sium', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (4, 'Calcium', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (5, 'PH', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (6, 'Phosphate', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO localized_parameter (parameter_id, description, language, created_on, lastmod_on, optlock) +VALUES (7, 'Teneur en sel', 'fr', DEFAULT, DEFAULT, DEFAULT); + diff --git a/sabi-database/src/main/resources/db/migration/version1_3_0/V1_3_0_4__i18nUnit.sql b/sabi-database/src/main/resources/db/migration/version1_3_0/V1_3_0_4__i18nUnit.sql new file mode 100644 index 00000000..7f5f09be --- /dev/null +++ b/sabi-database/src/main/resources/db/migration/version1_3_0/V1_3_0_4__i18nUnit.sql @@ -0,0 +1,185 @@ +CREATE TABLE `localized_unit` +( + `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, + `unit_id` INT UNSIGNED NOT NULL, + `description` VARCHAR(80) NOT NULL, + `language` VARCHAR(3) NOT NULL, + `created_on` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `lastmod_on` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `optlock` INT UNSIGNED NOT NULL DEFAULT 0, + PRIMARY KEY (`id`), + UNIQUE KEY `business_key` (`unit_id`, `language`), + foreign key (unit_id) references unit(id) +) + ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8; + +ALTER TABLE unit drop column description; + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (1, 'KarbonathĂ€rte (1 °DH = 0,178 mmol/l CAO3)', 'de', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (2, 'Temperatur in Celsius', 'de', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (3, 'Calcium-Konzentration in ppm (1 ppm = 1.023 mg/L)', 'de', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (4, 'Magnesium-Konzentration in ppm (1 ppm = 1.023 mg/L)', 'de', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (5, 'PH Wert', 'de', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (6, 'Ammonium', 'de', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (7, 'Ammoniak', 'de', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (8, 'Nitrit', 'de', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (9, 'Nitrat', 'de', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (10, 'Phosphat', 'de', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (11, 'SalinitĂ€t', 'de', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (1, 'Carbonate hardness (1 °DH = 0.178 mmol/l CAO3)', 'en', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (2, 'Temperature in Celsius', 'en', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (3, 'Calcium concentration in ppm (1 ppm = 1,023 mg/L)', 'en', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (4, 'Magnesium concentration in ppm (1 ppm = 1,023 mg/L)', 'en', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (5, 'PH value', 'en', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (6, 'Ammonium', 'en', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (7, 'Ammonia', 'en', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (8, 'nitrite', 'en', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (9, 'nitrate', 'en', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (10, 'phosphate', 'en', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (11, 'Salinity', 'en', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (1, 'Dureza carbonatada (1 °DH = 0,178 mmol/l CAO3)', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (2, 'Temperatura', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (3, 'ConcentraciĂłn de calcio en ppm (1 ppm = 1,023 mg/L)', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (4, 'ConcentraciĂłn de magnesio en ppm (1 ppm = 1,023 mg/L)', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (5, 'Valor PH', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (6, 'Amonio', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (7, 'AmonĂ­aco', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (8, 'nitrito', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (9, 'nitrato', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (10, 'fosfato', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (11, 'Salinidad', 'es', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (1, 'DuretĂ© carbonatĂ©e (1 °DH = 0,178 mmol/l CAO3)', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (2, 'TempĂ©rature', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (3, 'Concentration de calcium en ppm (1 ppm = 1.023 mg/L)', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (4, 'Concentration en magnĂ©sium en ppm (1 ppm = 1.023 mg/L)', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (5, 'Valeur du PH', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (6, 'Ammonium', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (7, 'Ammoniaque', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (8, 'Nitrite', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (9, 'Nitrate', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (10, 'Phosphate', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (11, 'SalinitĂ©', 'fr', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (1, 'Durezza carbonatica (1 °DH = 0,178 mmol/l CAO3)', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (2, 'Temperatura', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (3, 'Concentrazione di calcio in ppm (1 ppm = 1,023 mg/L)', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (4, 'Concentrazione di magnesio in ppm (1 ppm = 1,023 mg/L)', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (5, 'Valore PH', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (6, 'Ammonio', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (7, 'Ammoniaca', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (8, 'nitrito', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (9, 'nitrato', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (10, 'fosfato', 'it', DEFAULT, DEFAULT, DEFAULT); + +INSERT INTO sabi.localized_unit (unit_id, description, language, created_on, lastmod_on, optlock) +VALUES (11, 'SalinitĂ ', 'it', DEFAULT, DEFAULT, DEFAULT); + + diff --git a/sabi-server/pom.xml b/sabi-server/pom.xml index 9ba0fc35..8310aacd 100644 --- a/sabi-server/pom.xml +++ b/sabi-server/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 3.2.1 + 3.2.2 diff --git a/sabi-server/src/main/java/de/bluewhale/sabi/mapper/UnitMapper.java b/sabi-server/src/main/java/de/bluewhale/sabi/mapper/UnitMapper.java index 77e0c67e..0abed8de 100644 --- a/sabi-server/src/main/java/de/bluewhale/sabi/mapper/UnitMapper.java +++ b/sabi-server/src/main/java/de/bluewhale/sabi/mapper/UnitMapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 by Stefan Schubert under the MIT License (MIT). + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). * See project LICENSE file for the detailed terms and conditions. */ @@ -25,7 +25,6 @@ public interface UnitMapper { @Mappings({ @Mapping(target ="id", source="id"), @Mapping(target ="unitSign", source="name"), - @Mapping(target ="description", source="description"), }) UnitTo mapUnitEntity2To(@NotNull final UnitEntity pUnitEntity); @@ -33,7 +32,6 @@ public interface UnitMapper { @Mappings({ @Mapping(target ="id", source="id"), @Mapping(target ="name", source="unitSign"), - @Mapping(target ="description", source="description"), }) UnitEntity mapUnitToEntity(@NotNull final UnitTo pUnitTo); diff --git a/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/LocalizedParameterEntity.java b/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/LocalizedParameterEntity.java new file mode 100644 index 00000000..9f527b81 --- /dev/null +++ b/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/LocalizedParameterEntity.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). + * See project LICENSE file for the detailed terms and conditions. + */ + +package de.bluewhale.sabi.persistence.model; + +import jakarta.persistence.*; +import lombok.Data; + +/** + * Table which contains the translated parameter descriptions. + */ +@Table(name = "localized_parameter", schema = "sabi") +@Entity +@Data +public class LocalizedParameterEntity extends Auditable { +// ------------------------------ FIELDS ------------------------------ + + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Id + @Column(name = "id", nullable = false, insertable = true, updatable = true, length = 20) + @Basic + private Long id; + + @Column(name = "parameter_id", nullable = false, insertable = true, updatable = true) + @Basic + private Integer parameter_id; + + @Column(name = "description", nullable = true, insertable = true, updatable = true, length = 80) + @Basic + private String description; + + @Column(name = "language", nullable = true, insertable = true, updatable = true, length = 3) + @Basic + private String language; + +} diff --git a/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/LocalizedUnitEntity.java b/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/LocalizedUnitEntity.java new file mode 100644 index 00000000..dc727cf2 --- /dev/null +++ b/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/LocalizedUnitEntity.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). + * See project LICENSE file for the detailed terms and conditions. + */ + +package de.bluewhale.sabi.persistence.model; + +import jakarta.persistence.*; +import lombok.Data; + +/** + * Table which contains the translated parameter descriptions. + */ +@Table(name = "localized_unit", schema = "sabi") +@Entity +@Data +public class LocalizedUnitEntity extends Auditable { +// ------------------------------ FIELDS ------------------------------ + + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Id + @Column(name = "id", nullable = false, insertable = true, updatable = true, length = 20) + @Basic + private Long id; + + @Column(name = "unit_id", nullable = false, insertable = true, updatable = true) + @Basic + private Integer unitId; + + @Column(name = "description", nullable = true, insertable = true, updatable = true, length = 80) + @Basic + private String description; + + @Column(name = "language", nullable = true, insertable = true, updatable = true, length = 3) + @Basic + private String language; + +} diff --git a/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/MeasurementEntity.java b/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/MeasurementEntity.java index 274a3ffa..a8df7836 100644 --- a/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/MeasurementEntity.java +++ b/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/MeasurementEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 by Stefan Schubert under the MIT License (MIT). + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). * See project LICENSE file for the detailed terms and conditions. */ @@ -26,7 +26,7 @@ @Table(name = "measurement", schema = "sabi") @Entity @Data -@EqualsAndHashCode(exclude = {"user", "aquarium"}) +@EqualsAndHashCode(exclude = {"user", "aquarium"},callSuper = false) public class MeasurementEntity extends Auditable { // ------------------------------ FIELDS ------------------------------ diff --git a/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/MotdEntity.java b/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/MotdEntity.java index baf4d514..eddf6dc6 100644 --- a/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/MotdEntity.java +++ b/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/MotdEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 by Stefan Schubert under the MIT License (MIT). + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). * See project LICENSE file for the detailed terms and conditions. */ @@ -22,7 +22,7 @@ @Table(name = "motd", schema = "sabi") @Entity @Data -@EqualsAndHashCode(exclude = "localizedMotdEntities") +@EqualsAndHashCode(exclude = "localizedMotdEntities",callSuper = false) public class MotdEntity extends Auditable { // ------------------------------ FIELDS ------------------------------ diff --git a/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/ParameterEntity.java b/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/ParameterEntity.java index 9bb413d7..30b96d4b 100644 --- a/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/ParameterEntity.java +++ b/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/ParameterEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 by Stefan Schubert under the MIT License (MIT). + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). * See project LICENSE file for the detailed terms and conditions. */ @@ -7,10 +7,15 @@ import jakarta.persistence.*; import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.ArrayList; +import java.util.List; @Table(name = "parameter", schema = "sabi") @Entity @Data +@EqualsAndHashCode(exclude = "localizedParameterEntities") public class ParameterEntity extends Auditable { // ------------------------------ FIELDS ------------------------------ @@ -20,10 +25,6 @@ public class ParameterEntity extends Auditable { @Basic private Integer id; - @jakarta.persistence.Column(name = "description", nullable = false, insertable = true, updatable = true, length = 255, precision = 0) - @Basic - private String description; - @jakarta.persistence.Column(name = "belonging_unit_id", nullable = false, insertable = true, updatable = true, length = 10, precision = 0) @Basic private int belongingUnitId; @@ -36,4 +37,9 @@ public class ParameterEntity extends Auditable { @Basic private Float maxThreshold; + // Unidirectional for now - as this contains more static data, we won't provide an admin gui for it. + @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) + @JoinColumn(name="parameter_id") + private List localizedParameterEntities = new ArrayList(); + } diff --git a/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/PlagueEntity.java b/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/PlagueEntity.java index 0cc7e889..bb9d7468 100644 --- a/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/PlagueEntity.java +++ b/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/PlagueEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 by Stefan Schubert under the MIT License (MIT). + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). * See project LICENSE file for the detailed terms and conditions. */ @@ -18,7 +18,7 @@ @Table(name = "plague", schema = "sabi") @Entity @Data -@EqualsAndHashCode(exclude = "localizedPlagueEntities") +@EqualsAndHashCode(exclude = "localizedPlagueEntities",callSuper = false) public class PlagueEntity extends Auditable { // ------------------------------ FIELDS ------------------------------ @@ -31,7 +31,7 @@ public class PlagueEntity extends Auditable { @Basic private String scientificName; - // Unidirectional for now - as this contains more static data, we we won't provide a admin gui for it. + // Unidirectional for now - as this contains more static data, we won't provide an admin gui for it. @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name="plague_id") private List localizedPlagueEntities = new ArrayList(); diff --git a/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/PlagueRecordEntity.java b/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/PlagueRecordEntity.java index 73eea962..608a4fb1 100644 --- a/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/PlagueRecordEntity.java +++ b/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/PlagueRecordEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 by Stefan Schubert under the MIT License (MIT). + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). * See project LICENSE file for the detailed terms and conditions. */ @@ -26,7 +26,7 @@ @Table(name = "plague_record", schema = "sabi") @Entity @Data -@EqualsAndHashCode(exclude = {"user", "aquarium"}) +@EqualsAndHashCode(exclude = {"user", "aquarium"}, callSuper = false) public class PlagueRecordEntity extends Auditable { // ------------------------------ FIELDS ------------------------------ diff --git a/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/UnitEntity.java b/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/UnitEntity.java index bea88729..72bd015d 100644 --- a/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/UnitEntity.java +++ b/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/UnitEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 by Stefan Schubert under the MIT License (MIT). + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). * See project LICENSE file for the detailed terms and conditions. */ @@ -8,6 +8,9 @@ import jakarta.persistence.*; import lombok.Data; +import java.util.ArrayList; +import java.util.List; + @Table(name = "unit", schema = "sabi") @Entity @Data @@ -24,8 +27,10 @@ public class UnitEntity extends Auditable { @Basic private String name; - @jakarta.persistence.Column(name = "description", nullable = false, insertable = true, updatable = true, length = 255, precision = 0) - @Basic - private String description; + // Unidirectional for now - as this contains more static data, we won't provide an admin gui for it. + @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) + @JoinColumn(name="unit_id") + private List localizedUnitEntities = new ArrayList(); + } diff --git a/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/UserEntity.java b/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/UserEntity.java index 8599e9ef..c54ca9ab 100644 --- a/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/UserEntity.java +++ b/sabi-server/src/main/java/de/bluewhale/sabi/persistence/model/UserEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 by Stefan Schubert under the MIT License (MIT). + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). * See project LICENSE file for the detailed terms and conditions. */ @@ -19,7 +19,7 @@ @Table(name = "users", schema = "sabi") @Entity @Data -@EqualsAndHashCode(exclude = {"aquariums","corals","fishes","measurements","treatments"}) +@EqualsAndHashCode(exclude = {"aquariums","corals","fishes","measurements","treatments"},callSuper = false) public class UserEntity extends Auditable { // ------------------------------ FIELDS ------------------------------ diff --git a/sabi-server/src/main/java/de/bluewhale/sabi/persistence/repositories/LocalizedUnitRepository.java b/sabi-server/src/main/java/de/bluewhale/sabi/persistence/repositories/LocalizedUnitRepository.java new file mode 100644 index 00000000..77b6e1f1 --- /dev/null +++ b/sabi-server/src/main/java/de/bluewhale/sabi/persistence/repositories/LocalizedUnitRepository.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). + * See project LICENSE file for the detailed terms and conditions. + */ + +package de.bluewhale.sabi.persistence.repositories; + +import de.bluewhale.sabi.persistence.model.LocalizedUnitEntity; +import jakarta.validation.constraints.NotNull; +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * SpringDataRepository + * + * @author Stefan Schubert + */ +public interface LocalizedUnitRepository extends JpaRepository { + + /** + * Used to get the language specific fields. + * @param pLanguage + * @param pUnitId + * @return LocalizedUnitEntity suitable for requested language + */ + LocalizedUnitEntity findByLanguageAndUnitId(@NotNull String pLanguage, @NotNull Integer pUnitId); + + +} diff --git a/sabi-server/src/main/java/de/bluewhale/sabi/rest/controller/MeasurementController.java b/sabi-server/src/main/java/de/bluewhale/sabi/rest/controller/MeasurementController.java index c603bbeb..d6fce527 100644 --- a/sabi-server/src/main/java/de/bluewhale/sabi/rest/controller/MeasurementController.java +++ b/sabi-server/src/main/java/de/bluewhale/sabi/rest/controller/MeasurementController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 by Stefan Schubert under the MIT License (MIT). + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). * See project LICENSE file for the detailed terms and conditions. */ @@ -329,16 +329,18 @@ public ResponseEntity> listUsersTankMeasurementsOfSpecificUn description = "Success - list of measurement reminders for authed user returned."), @ApiResponse(responseCode = "401", description = "Unauthorized-request did not contained a valid user token.") }) - @RequestMapping(value = "/reminder/list", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + @RequestMapping(value = "/reminder/list/{language}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody @ResponseStatus(HttpStatus.OK) public ResponseEntity> listUsersMeasurementReminders(@RequestHeader(name = AUTH_TOKEN, required = true) String token, + @PathVariable(value="language", required = true) + @Parameter(name = "language", description = "ISO-639-1 language code - used for i18n in communication. ") String language, Principal principal) { // If we come so far, the JWTAuthenticationFilter has already validated the token, // and we can be sure that spring has injected a valid Principal object. // list may be empty but not null - List measurementReminderTos = measurementService.fetchUsersNextMeasurements(principal.getName()); + List measurementReminderTos = measurementService.fetchUsersNextMeasurements(principal.getName(), language); return new ResponseEntity<>(measurementReminderTos, HttpStatus.ACCEPTED); } diff --git a/sabi-server/src/main/java/de/bluewhale/sabi/rest/controller/UnitController.java b/sabi-server/src/main/java/de/bluewhale/sabi/rest/controller/UnitController.java index b435fbfc..ab9ca7f6 100644 --- a/sabi-server/src/main/java/de/bluewhale/sabi/rest/controller/UnitController.java +++ b/sabi-server/src/main/java/de/bluewhale/sabi/rest/controller/UnitController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 by Stefan Schubert under the MIT License (MIT). + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). * See project LICENSE file for the detailed terms and conditions. */ @@ -45,13 +45,15 @@ public class UnitController { description = "Success - list of all supported measurement units returned."), @ApiResponse(responseCode = "401", description = "Unauthorized - request did not contained a valid user token.") }) - @RequestMapping(value = {"/list"}, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + @RequestMapping(value = {"/list/{language}"}, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody @ResponseStatus(HttpStatus.ACCEPTED) - public ResponseEntity> listAllMeasurementUnits(@RequestHeader(name = AUTH_TOKEN, required = true) String token, Principal principal) { + public ResponseEntity> listAllMeasurementUnits(@RequestHeader(name = AUTH_TOKEN, required = true) String token, + @PathVariable(value="language", required = false) + @Parameter(name = "language", description = "ISO-639-1 language code - used for i18n in communication. ") String language, Principal principal) { // If we come so far, the JWTAuthenticationFilter has already validated the token, // and we can be sure that spring has injected a valid Principal object. - List unitToList = measurementService.listAllMeasurementUnits(); + List unitToList = measurementService.listAllMeasurementUnits(language); return new ResponseEntity<>(unitToList, HttpStatus.ACCEPTED); } @@ -64,16 +66,17 @@ public ResponseEntity> listAllMeasurementUnits(@RequestHeader(name description = "Not detail parameter available for requested unit."), @ApiResponse(responseCode = "401", description = "Unauthorized - request did not contained a valid user token.") }) - @RequestMapping(value = {"/parameter/{unitID}"}, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + @RequestMapping(value = {"/parameter/{unitID}/{language}"}, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody @ResponseStatus(HttpStatus.ACCEPTED) public ResponseEntity readDetailParameterOfUnit(@RequestHeader(name = AUTH_TOKEN, required = true) String token, @PathVariable(value = "unitID", required = true) @Parameter(name = "unitID", description = "id of the unit you query details for...") Integer unitID, + @PathVariable(value = "language", required = true) @Parameter(name = "language", description = "ISO-639-1 language code - used for i18n in communication.") String language, Principal principal) { // If we come so far, the JWTAuthenticationFilter has already validated the token, // and we can be sure that spring has injected a valid Principal object. - ParameterTo parameterTo = measurementService.fetchParameterInfoFor(unitID); + ParameterTo parameterTo = measurementService.fetchParameterInfoFor(unitID,language); if (parameterTo == null) { return new ResponseEntity<>(null, HttpStatus.NOT_FOUND); } else { diff --git a/sabi-server/src/main/java/de/bluewhale/sabi/services/MeasurementService.java b/sabi-server/src/main/java/de/bluewhale/sabi/services/MeasurementService.java index ef084d62..baeb0c71 100644 --- a/sabi-server/src/main/java/de/bluewhale/sabi/services/MeasurementService.java +++ b/sabi-server/src/main/java/de/bluewhale/sabi/services/MeasurementService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 by Stefan Schubert under the MIT License (MIT). + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). * See project LICENSE file for the detailed terms and conditions. */ @@ -33,10 +33,11 @@ public interface MeasurementService { * Measurement units are not hard coded via enums, they can dynamically added through the database if required. * Use this function to retrieve the list of known ones. * + * @param pUsersLanguage ISO-639-1 language code - used for i18n in communication (localized parameter description) * @return List of supported measurement units */ @NotNull - List listAllMeasurementUnits(); + List listAllMeasurementUnits(String pUsersLanguage); /** * Lists all measurements of a specific user. @@ -118,9 +119,10 @@ public interface MeasurementService { * Required because of the loose coupling. * * @param pUnitID identifies the unit for which we are interested on additional parameter infos. - * @return ParameterTo with details or null if they do not exists. + * @param pUsersLanguage ISO-639-1 language code - used for i18n in communication (localized parameter description) + * @return ParameterTo with details or null if they do not exist. */ - ParameterTo fetchParameterInfoFor(Integer pUnitID); + ParameterTo fetchParameterInfoFor(Integer pUnitID, String pUsersLanguage); /** * Used to display some project stats. @@ -149,7 +151,7 @@ public interface MeasurementService { * @param pUserEmail preAuthed UserID * @return List of measurement reminders, might be empty. */ - @NotNull List fetchUsersNextMeasurements(@NotNull String pUserEmail); + @NotNull List fetchUsersNextMeasurements(@NotNull String pUserEmail, @NotNull String pUserLanguage); /** * Adds provided MeasurementReminderTo if it is consistent with requesting user. diff --git a/sabi-server/src/main/java/de/bluewhale/sabi/services/MeasurementServiceImpl.java b/sabi-server/src/main/java/de/bluewhale/sabi/services/MeasurementServiceImpl.java index af3feff4..3264d580 100644 --- a/sabi-server/src/main/java/de/bluewhale/sabi/services/MeasurementServiceImpl.java +++ b/sabi-server/src/main/java/de/bluewhale/sabi/services/MeasurementServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 by Stefan Schubert under the MIT License (MIT). + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). * See project LICENSE file for the detailed terms and conditions. */ @@ -58,6 +58,9 @@ public class MeasurementServiceImpl implements MeasurementService { @Autowired UnitRepository unitRepository; + @Autowired + LocalizedUnitRepository localizedUnitRepository; + @Autowired UnitMapper unitMapper; @@ -93,12 +96,15 @@ public List listMeasurementsFilteredBy(Long pTankID, Integer pUni @Override @Cacheable("unitsCache") - public @NotNull List listAllMeasurementUnits() { + public @NotNull List listAllMeasurementUnits(String pUsersLanguage) { List unitToList = Collections.emptyList(); List unitEntityList = unitRepository.findAll(); if (unitEntityList != null && !unitEntityList.isEmpty()) { unitToList = unitMapper.mapUnitEntities2TOs(unitEntityList); - + for (UnitTo unitTo : unitToList) { + LocalizedUnitEntity localizedUnit = localizedUnitRepository.findByLanguageAndUnitId(pUsersLanguage, unitTo.getId()); + unitTo.setDescription((localizedUnit == null) ? null : localizedUnit.getDescription()); + } } return unitToList; } @@ -209,13 +215,18 @@ public ResultTo updateMeasurement(MeasurementTo pMeasurementTo, S } @Override - public ParameterTo fetchParameterInfoFor(Integer pUnitID) { + public ParameterTo fetchParameterInfoFor(Integer pUnitID, String pUsersLanguage) { if (pUnitID == null) { log.warn("Tried to fetch Parameter Info for null unit. This smells after a logic flaw."); return null; } + if (pUsersLanguage == null) { + log.warn("Called fetch parameter Info without language param. Using english as default."); + pUsersLanguage = "en"; + } + ParameterEntity parameterEntity = parameterRepository.findByBelongingUnitIdEquals(pUnitID); if (parameterEntity == null) { @@ -225,7 +236,14 @@ public ParameterTo fetchParameterInfoFor(Integer pUnitID) { ParameterTo parameterTo = parameterMapper.mapParameterEntity2To(parameterEntity); - return parameterTo; + List localizedParameterEntities = parameterEntity.getLocalizedParameterEntities(); + String finalPUsersLanguage = pUsersLanguage; + Optional localizedParameterEntity = localizedParameterEntities.stream().filter(item -> finalPUsersLanguage.equalsIgnoreCase(item.getLanguage())).findFirst(); + if (localizedParameterEntity.isPresent()) { + parameterTo.setDescription(localizedParameterEntity.get().getDescription()); + } + + return parameterTo; } @Override @@ -275,10 +293,10 @@ public ResultTo addIotAuthorizedMeasurement(MeasurementTo pMeasur } @Override - public List fetchUsersNextMeasurements(String pUserEmail) { + public List fetchUsersNextMeasurements(String pUserEmail, String pUserLanguage) { List measurementReminderTos = new ArrayList<>(); - List allMeasurementUnits = listAllMeasurementUnits(); + List allMeasurementUnits = listAllMeasurementUnits(pUserLanguage); UserEntity user = userRepository.getByEmail(pUserEmail); List userMeasurementReminders = user.getUserMeasurementReminders(); diff --git a/sabi-server/src/main/java/de/bluewhale/sabi/services/TankServiceImpl.java b/sabi-server/src/main/java/de/bluewhale/sabi/services/TankServiceImpl.java index 3f6b7688..3c2e0701 100644 --- a/sabi-server/src/main/java/de/bluewhale/sabi/services/TankServiceImpl.java +++ b/sabi-server/src/main/java/de/bluewhale/sabi/services/TankServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 by Stefan Schubert under the MIT License (MIT). + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). * See project LICENSE file for the detailed terms and conditions. */ @@ -136,7 +136,7 @@ public ResultTo updateTank(AquariumTo updatedAquariumTo, String pUse AquariumEntity aquariumEntity = aquariumRepository.getAquariumEntityByIdAndUser_IdIs(updatedAquariumTo.getId(), requestingUser.getId()); if (aquariumEntity != null) { - // FIXME STS (04.09.23): The Mapping here will provide a completley new entity + // FIXME STS (04.09.23): The Mapping here will provide a completely new entity // however we have the aquarium before. Isn't there a merge mapping // between entities available by mapstruts? aquariumEntity = aquariumMapper.mapAquariumTo2Entity(updatedAquariumTo); diff --git a/sabi-server/src/main/resources/application.yml b/sabi-server/src/main/resources/application.yml index c1f03b23..e66d1440 100644 --- a/sabi-server/src/main/resources/application.yml +++ b/sabi-server/src/main/resources/application.yml @@ -64,6 +64,10 @@ spring: application: name: sabi-service # JPA Database configuration + threads: + virtual: + # No need to configure Http Threadpool size, we use virtual Threads + enabled: true datasource: driver-class-name: org.mariadb.jdbc.Driver # Hikari Connection Pool diff --git a/sabi-server/src/test/java/de/bluewhale/sabi/BasicDataFactory.java b/sabi-server/src/test/java/de/bluewhale/sabi/BasicDataFactory.java index 847856ba..e6312bc0 100644 --- a/sabi-server/src/test/java/de/bluewhale/sabi/BasicDataFactory.java +++ b/sabi-server/src/test/java/de/bluewhale/sabi/BasicDataFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 by Stefan Schubert under the MIT License (MIT). + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). * See project LICENSE file for the detailed terms and conditions. */ @@ -14,6 +14,7 @@ import org.springframework.jdbc.core.JdbcTemplate; import java.time.LocalDateTime; +import java.util.List; /** * Derive your tests from this class to inject required minimum required basic data into H2. @@ -31,6 +32,9 @@ public class BasicDataFactory { @Autowired UnitRepository unitRepository; + @Autowired + LocalizedUnitRepository localizedUnitRepository; + @Autowired RemedyRepository remedyRepository; @@ -88,31 +92,51 @@ public void populateBasicData() { UnitEntity unitEntity = new UnitEntity(); unitEntity.setName("KH"); - unitEntity.setDescription("KarbonathĂ€rte / AlkanitĂ€t"); unitEntity.setId(1); UnitEntity unitEntity2 = new UnitEntity(); unitEntity2.setName("°C"); - unitEntity2.setDescription("Grad Celsius"); unitEntity2.setId(2); - unitRepository.saveAndFlush(unitEntity); - unitRepository.saveAndFlush(unitEntity2); + UnitEntity savedUnitEntity = unitRepository.saveAndFlush(unitEntity); + + LocalizedUnitEntity localizedUnitEntity = new LocalizedUnitEntity(); + localizedUnitEntity.setDescription("KarbonathĂ€rte / AlkanitĂ€t"); + localizedUnitEntity.setUnitId(savedUnitEntity.getId()); + localizedUnitRepository.saveAndFlush(localizedUnitEntity); + unitEntity.setLocalizedUnitEntities(List.of(localizedUnitEntity)); + + UnitEntity savedUnitEntity2 = unitRepository.saveAndFlush(unitEntity2); + + LocalizedUnitEntity localizedUnitEntity2 = new LocalizedUnitEntity(); + localizedUnitEntity2.setDescription("Grad Celsius"); + localizedUnitEntity2.setUnitId(savedUnitEntity2.getId()); + localizedUnitRepository.saveAndFlush(localizedUnitEntity2); + unitEntity2.setLocalizedUnitEntities(List.of(localizedUnitEntity2)); ParameterEntity parameterEntity = new ParameterEntity(); - parameterEntity.setDescription("KarbonathĂ€rte"); parameterEntity.setBelongingUnitId(1); parameterEntity.setMinThreshold(6.5f); parameterEntity.setMaxThreshold(10f); ParameterEntity parameterEntity2 = new ParameterEntity(); - parameterEntity2.setDescription("Temperatur"); parameterEntity2.setBelongingUnitId(2); parameterEntity2.setMinThreshold(24f); parameterEntity2.setMaxThreshold(27f); - parameterRepository.saveAndFlush(parameterEntity); - parameterRepository.saveAndFlush(parameterEntity2); + ParameterEntity savedParameterEntity1 = parameterRepository.saveAndFlush(parameterEntity); + LocalizedParameterEntity localizedParameterEntity = new LocalizedParameterEntity(); + localizedParameterEntity.setDescription("KarbonathĂ€rte"); + localizedParameterEntity.setLanguage("de"); + localizedParameterEntity.setParameter_id(savedParameterEntity1.getId()); + savedParameterEntity1.setLocalizedParameterEntities(List.of(localizedParameterEntity)); + + ParameterEntity savedParameterEntity2 = parameterRepository.saveAndFlush(parameterEntity2); + LocalizedParameterEntity localizedParameterEntity2 = new LocalizedParameterEntity(); + localizedParameterEntity2.setDescription("Temperatur"); + localizedParameterEntity2.setLanguage("de"); + localizedParameterEntity2.setParameter_id(savedParameterEntity2.getId()); + savedParameterEntity2.setLocalizedParameterEntities(List.of(localizedParameterEntity2)); RemedyEntity remedyEntity = new RemedyEntity(); remedyEntity.setProductname("KH+"); diff --git a/sabi-server/src/test/java/de/bluewhale/sabi/services/MeasurementServiceTest.java b/sabi-server/src/test/java/de/bluewhale/sabi/services/MeasurementServiceTest.java index 19cc27f1..1748ae79 100644 --- a/sabi-server/src/test/java/de/bluewhale/sabi/services/MeasurementServiceTest.java +++ b/sabi-server/src/test/java/de/bluewhale/sabi/services/MeasurementServiceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 by Stefan Schubert under the MIT License (MIT). + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). * See project LICENSE file for the detailed terms and conditions. */ @@ -103,7 +103,7 @@ public void testFindMeasurementParameter() throws Exception { // Given already stored testdata for measurements // When - ParameterTo parameterTo = measurementService.fetchParameterInfoFor(1); + ParameterTo parameterTo = measurementService.fetchParameterInfoFor(1, "de"); // Then assertNotNull("Should not happen!",parameterTo); @@ -116,7 +116,7 @@ public void testFindInvalidMeasurementParameter() throws Exception { Integer nonExistingUnit = Integer.MAX_VALUE; // When - ParameterTo parameterTo = measurementService.fetchParameterInfoFor(nonExistingUnit); + ParameterTo parameterTo = measurementService.fetchParameterInfoFor(nonExistingUnit,"de"); // Then assertNull(parameterTo); @@ -143,7 +143,7 @@ public void testListMeasurementUnits() throws Exception { // Given already stored testdata for measurements // When - List measurementUnits = measurementService.listAllMeasurementUnits(); + List measurementUnits = measurementService.listAllMeasurementUnits("de"); // Then assertNotNull("Should not happen!",measurementUnits); diff --git a/sabi-server/src/test/java/de/bluewhale/sabi/services/rest/UnitControllerTest.java b/sabi-server/src/test/java/de/bluewhale/sabi/services/rest/UnitControllerTest.java index 5e8696ec..9f2fd1d9 100644 --- a/sabi-server/src/test/java/de/bluewhale/sabi/services/rest/UnitControllerTest.java +++ b/sabi-server/src/test/java/de/bluewhale/sabi/services/rest/UnitControllerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 by Stefan Schubert under the MIT License (MIT). + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). * See project LICENSE file for the detailed terms and conditions. */ @@ -14,9 +14,11 @@ import de.bluewhale.sabi.model.ParameterTo; import de.bluewhale.sabi.model.UnitTo; import de.bluewhale.sabi.model.UserTo; +import de.bluewhale.sabi.persistence.model.LocalizedUnitEntity; import de.bluewhale.sabi.persistence.model.ParameterEntity; import de.bluewhale.sabi.persistence.model.UnitEntity; import de.bluewhale.sabi.persistence.model.UserEntity; +import de.bluewhale.sabi.persistence.repositories.LocalizedUnitRepository; import de.bluewhale.sabi.persistence.repositories.ParameterRepository; import de.bluewhale.sabi.persistence.repositories.UnitRepository; import de.bluewhale.sabi.persistence.repositories.UserRepository; @@ -62,6 +64,8 @@ public class UnitControllerTest { @MockBean UnitRepository unitRepository; @MockBean + LocalizedUnitRepository localizedUnitRepository; + @MockBean ParameterRepository parameterRepository; @MockBean UserRepository userRepository; @@ -98,11 +102,18 @@ public void testListAvailableUnits() throws Exception { UnitTo unitTo = testDataFactory.getTestUnitTo(); UnitEntity unitEntity = unitMapper.mapUnitToEntity(unitTo); + LocalizedUnitEntity localizedUnitEntity = new LocalizedUnitEntity(); + localizedUnitEntity.setUnitId(unitEntity.getId()); + localizedUnitEntity.setDescription(unitTo.getDescription()); + localizedUnitEntity.setLanguage("en"); + unitEntity.setLocalizedUnitEntities(List.of(localizedUnitEntity)); List unitEntityList = new ArrayList(); unitEntityList.add(unitEntity); given(this.unitRepository.findAll()).willReturn(unitEntityList); + given(this.localizedUnitRepository.findByLanguageAndUnitId("en", unitEntity.getId())).willReturn(localizedUnitEntity); + // and we need a valid authentication token for our mocked user String authToken = TokenAuthenticationService.createAuthorizationTokenFor(MOCKED_USER); @@ -112,7 +123,7 @@ public void testListAvailableUnits() throws Exception { HttpEntity requestEntity = new HttpEntity<>(headers); // Notice the that the controller defines a list, the rest-template will get it as array. - ResponseEntity responseEntity = restTemplate.exchange("/api/units/list", HttpMethod.GET, requestEntity, String.class); + ResponseEntity responseEntity = restTemplate.exchange("/api/units/list/en", HttpMethod.GET, requestEntity, String.class); // then we should get a 202 as result. assertThat(responseEntity.getStatusCode(), equalTo(HttpStatus.ACCEPTED)); @@ -149,7 +160,7 @@ public void testFetchUnitParameterInfo() throws Exception { HttpEntity requestEntity = new HttpEntity<>(headers); // Notice the that the controller defines a list, the rest-template will get it as array. - ResponseEntity responseEntity = restTemplate.exchange(Endpoint.UNITS + "/parameter/" + parameterEntity.getBelongingUnitId(), HttpMethod.GET, requestEntity, String.class); + ResponseEntity responseEntity = restTemplate.exchange(Endpoint.UNITS + "/parameter/" + parameterEntity.getBelongingUnitId() + "/en", HttpMethod.GET, requestEntity, String.class); // Then // then we should get a 202 as result. diff --git a/sabi-webclient/pom.xml b/sabi-webclient/pom.xml index ba6101dd..801eecd1 100644 --- a/sabi-webclient/pom.xml +++ b/sabi-webclient/pom.xml @@ -10,7 +10,7 @@ de.bluewhale sabi-webclient - 1.2.6 + 1.2.7 jar sabi-webclient A JSF based webclient for sabi. diff --git a/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/apigateway/MeasurementService.java b/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/apigateway/MeasurementService.java index 485b431f..0928782c 100644 --- a/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/apigateway/MeasurementService.java +++ b/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/apigateway/MeasurementService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 by Stefan Schubert under the MIT License (MIT). + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). * See project LICENSE file for the detailed terms and conditions. */ @@ -44,10 +44,11 @@ public interface MeasurementService extends Serializable { * Concrete user will be derived by the calling context (JWT Token Auth) * * @param pJWTBackendAuthtoken Bearer Auth string, which identifies the user against the backend. + * @param pLanguage ISO-639-1 language code for which the translation is being requested. * @return List of MeasurementReminderTo that belong to current user. List may be empty but never NULL. * @throws BusinessException in case of backend auth failures. */ - @NotNull List getMeasurementRemindersForUser(@NotNull String pJWTBackendAuthtoken) throws BusinessException; + @NotNull List getMeasurementRemindersForUser(@NotNull String pJWTBackendAuthtoken, @NotNull String pLanguage) throws BusinessException; /** @@ -58,11 +59,12 @@ public interface MeasurementService extends Serializable { * the backend introduces more units. * * @param pJWTBackendAuthtoken Bearer Auth string, which identifies the user against the backend. + * @param pLanguage ISO-639-1 language code for which the translation is being requested. * @return List of units known by the backend. * @throws BusinessException in case of backend auth failures. */ @Cacheable - @NotNull List getAvailableMeasurementUnits(@NotNull String pJWTBackendAuthtoken) throws BusinessException; + @NotNull List getAvailableMeasurementUnits(@NotNull String pJWTBackendAuthtoken, @NotNull String pLanguage) throws BusinessException; /** * List Users Measurements for a specific tank. Concrete user will be derived by the calling context @@ -105,13 +107,14 @@ public interface MeasurementService extends Serializable { void save(MeasurementTo measurement, @NotNull String pJWTBackendAuthtoken) throws BusinessException; /** - * Fetches detailed Parameterinfos for requested measurement unti + * Fetches detailed Parameterinfos for requested measurement unit * * @param selectedUnitId ID of measurement unit + * @param language ISO-639-1 language code for which the translation is being requested. * @param pJWTBackendAuthtoken Bearer Auth string, which identifies the user against the backend. * @return detailed info if available or null if it does not exists */ - @Null ParameterTo getParameterFor(@NotNull Integer selectedUnitId, @NotNull String pJWTBackendAuthtoken) throws BusinessException; + @Null ParameterTo getParameterFor(@NotNull Integer selectedUnitId, @NotNull String language, @NotNull String pJWTBackendAuthtoken) throws BusinessException; /** * Push a new Measurement reminder to the backend. diff --git a/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/apigateway/MeasurementServiceImpl.java b/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/apigateway/MeasurementServiceImpl.java index 810d6451..9b589ba7 100644 --- a/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/apigateway/MeasurementServiceImpl.java +++ b/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/apigateway/MeasurementServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 by Stefan Schubert under the MIT License (MIT). + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). * See project LICENSE file for the detailed terms and conditions. */ @@ -40,14 +40,13 @@ @Slf4j public class MeasurementServiceImpl extends APIServiceImpl implements MeasurementService { - static List cachedAvailableMeasurementUnits = Collections.emptyList(); - // TODO STS (04.05.21): Revisit and check after i18n of ParameterTo... + static Map> cachedAvailableMeasurementUnits = new HashMap<>(); static Map cachedUnitParameterMap = new HashMap<>(); @Override - public List getMeasurementRemindersForUser(String pJWTBackendAuthtoken) throws BusinessException { + public List getMeasurementRemindersForUser(String pJWTBackendAuthtoken, String pLanguage) throws BusinessException { - String listMeasurementReminderUri = sabiBackendUrl + Endpoint.MEASUREMENTS + "/reminder/list"; + String listMeasurementReminderUri = sabiBackendUrl + Endpoint.MEASUREMENTS + "/reminder/list/"+pLanguage; ResponseEntity responseEntity = getAPIResponseFor(listMeasurementReminderUri, pJWTBackendAuthtoken, HttpMethod.GET); MeasurementReminderTo[] measurementReminderTos; try { @@ -102,18 +101,18 @@ public void addMeasurementReminder(MeasurementReminderTo measurementReminderTo, @Override - public @NotNull List getAvailableMeasurementUnits (@NotNull String pJWTBackendAuthtoken) throws + public @NotNull List getAvailableMeasurementUnits (@NotNull String pJWTBackendAuthtoken, @NotNull String pLanguage) throws BusinessException { - String listMeasurementUnitsUri = sabiBackendUrl + Endpoint.UNITS + "/list"; + String listMeasurementUnitsUri = sabiBackendUrl + Endpoint.UNITS + "/list" + "/" +pLanguage; - if (cachedAvailableMeasurementUnits.isEmpty()) { + if (cachedAvailableMeasurementUnits.containsKey(pLanguage) == false) { ResponseEntity responseEntity = getAPIResponseFor(listMeasurementUnitsUri, pJWTBackendAuthtoken, HttpMethod.GET); try { UnitTo[] myObjects = objectMapper.readValue(responseEntity.getBody(), UnitTo[].class); - cachedAvailableMeasurementUnits = Arrays.asList(myObjects); + cachedAvailableMeasurementUnits.put(pLanguage, Arrays.asList(myObjects)); } catch (JsonProcessingException e) { log.error(String.format("Didn't understand response from %s got parsing exception %s", listMeasurementUnitsUri, e.getMessage()), e.getMessage()); e.printStackTrace(); @@ -121,11 +120,11 @@ public void addMeasurementReminder(MeasurementReminderTo measurementReminderTo, } } - return cachedAvailableMeasurementUnits; + return cachedAvailableMeasurementUnits.get(pLanguage); } @Override - public ParameterTo getParameterFor (Integer selectedUnitId, String pJWTBackendAuthtoken) throws + public ParameterTo getParameterFor (Integer selectedUnitId, String pLanguage, String pJWTBackendAuthtoken) throws BusinessException { if (selectedUnitId != null && cachedUnitParameterMap.containsKey(selectedUnitId)) { @@ -133,7 +132,7 @@ public ParameterTo getParameterFor (Integer selectedUnitId, String pJWTBackendAu return cachedUnitParameterMap.get(selectedUnitId); } else { - String listUnitsParameterUri = sabiBackendUrl + Endpoint.UNITS + "/parameter/" + selectedUnitId; + String listUnitsParameterUri = sabiBackendUrl + Endpoint.UNITS + "/parameter/" + selectedUnitId + "/"+pLanguage; ResponseEntity responseEntity = getAPIResponseFor(listUnitsParameterUri, pJWTBackendAuthtoken, HttpMethod.GET); diff --git a/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/AbstractControllerTools.java b/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/AbstractControllerTools.java index 61f595ed..f0d13f57 100644 --- a/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/AbstractControllerTools.java +++ b/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/AbstractControllerTools.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 by Stefan Schubert under the MIT License (MIT). + * Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). * See project LICENSE file for the detailed terms and conditions. */ @@ -53,8 +53,8 @@ public String getUnitSignForId(Integer unitId, List fromUnitList) { */ @NotNull public String getUnitDescriptionForId(Integer unitId, List fromUnitList) { - // TODO STS (13.04.21): Improvment: instead of providing the list of known units those should be fetched here - // wee need to change the auth scope on the api for this + // TODO STS (13.04.21): Improvement: instead of providing the list of known units those should be fetched here + // we need to change the auth scope on the api for this String result = ""; if (unitId != null) { for (UnitTo unitTo : fromUnitList) { diff --git a/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/MeasurementListView.java b/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/MeasurementListView.java index 446b772b..fd555af6 100644 --- a/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/MeasurementListView.java +++ b/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/MeasurementListView.java @@ -21,7 +21,7 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.context.annotation.SessionScope; +import org.springframework.web.context.annotation.RequestScope; import java.io.Serializable; import java.util.Collections; @@ -36,7 +36,7 @@ * @author Stefan Schubert */ @Named -@SessionScope +@RequestScope @Slf4j @Getter public class MeasurementListView extends AbstractControllerTools implements Serializable { @@ -74,7 +74,7 @@ public void init() { } try { - knownUnits = measurementService.getAvailableMeasurementUnits(userSession.getSabiBackendToken()); + knownUnits = measurementService.getAvailableMeasurementUnits(userSession.getSabiBackendToken(),userSession.getLanguage()); } catch (BusinessException e) { knownUnits = Collections.emptyList(); log.error(e.getLocalizedMessage()); @@ -160,7 +160,7 @@ public String getGetThresholdInfoFor(Integer unitId) { String result = ""; if (unitId != null && unitId != 0) { try { - ParameterTo parameterTo = measurementService.getParameterFor(unitId, userSession.getSabiBackendToken()); + ParameterTo parameterTo = measurementService.getParameterFor(unitId, userSession.getLanguage(), userSession.getSabiBackendToken()); Locale usersLocale = userSession.getLocale(); if (parameterTo != null && usersLocale != null) { result = String.format(usersLocale, "min = %.03f / max = %.03f", parameterTo.getMinThreshold(), parameterTo.getMaxThreshold()); diff --git a/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/ReportView.java b/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/ReportView.java index 881e70db..73022b77 100644 --- a/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/ReportView.java +++ b/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/ReportView.java @@ -28,7 +28,7 @@ import org.primefaces.model.charts.line.LineChartOptions; import org.primefaces.model.charts.optionconfig.title.Title; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.context.annotation.SessionScope; +import org.springframework.web.context.annotation.RequestScope; import java.io.Serializable; import java.time.LocalDate; @@ -46,7 +46,7 @@ * @author Stefan Schubert */ @Named -@SessionScope +@RequestScope @Slf4j @Getter @Setter @@ -246,7 +246,7 @@ private void applyThresholdLineToLineChartModell(@NotNull ChartData chartData, @ ParameterTo parameterTo = null; try { - parameterTo = measurementService.getParameterFor(selectedUnitId, userSession.getSabiBackendToken()); + parameterTo = measurementService.getParameterFor(selectedUnitId, userSession.getLanguage(),userSession.getSabiBackendToken()); } catch (Exception e) { log.error("Could not Reach Backend to access detail parameter infos for unit {}", selectedUnitId); e.printStackTrace(); @@ -302,7 +302,7 @@ public void init() { // TODO STS (12.04.21): Refactor this. To make use of the request scope here, this should went into // users session, it does not make sense that we to this in measureview and in report view again. tanks = tankService.getUsersTanks(userSession.getSabiBackendToken()); - knownUnits = measurementService.getAvailableMeasurementUnits(userSession.getSabiBackendToken()); + knownUnits = measurementService.getAvailableMeasurementUnits(userSession.getSabiBackendToken(), userSession.getLanguage()); if (tanks.size() == 1) { // default selection if user has only one tank this.selectedTankId = (tanks.get(0).getId()); diff --git a/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/TankListView.java b/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/TankListView.java index 2eae401a..93d777b4 100644 --- a/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/TankListView.java +++ b/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/TankListView.java @@ -18,7 +18,7 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.context.annotation.SessionScope; +import org.springframework.web.context.annotation.RequestScope; import java.io.Serializable; import java.util.ArrayList; @@ -35,7 +35,7 @@ * @author Stefan Schubert */ @Named -@SessionScope +@RequestScope @Slf4j @Getter public class TankListView implements Serializable { diff --git a/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/UserProfileView.java b/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/UserProfileView.java index e09afafc..48dd827b 100644 --- a/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/UserProfileView.java +++ b/sabi-webclient/src/main/java/de/bluewhale/sabi/webclient/controller/UserProfileView.java @@ -67,8 +67,8 @@ public void init() { selectedLocale = userSession.getLocale(); try { - measurementReminderTos = measurementService.getMeasurementRemindersForUser(userSession.getSabiBackendToken()); - knownMeasurementUnits = measurementService.getAvailableMeasurementUnits(userSession.getSabiBackendToken()); + measurementReminderTos = measurementService.getMeasurementRemindersForUser(userSession.getSabiBackendToken(),selectedLocale.getLanguage()); + knownMeasurementUnits = measurementService.getAvailableMeasurementUnits(userSession.getSabiBackendToken(), userSession.getLanguage()); } catch (BusinessException e) { measurementReminderTos = new ArrayList<>(); knownMeasurementUnits = new ArrayList<>(); @@ -125,7 +125,7 @@ public String addReminderForMeasurementUnit() { try { measurementService.addMeasurementReminder(measurementReminderTo, userSession.getSabiBackendToken()); - measurementReminderTos = measurementService.getMeasurementRemindersForUser(userSession.getSabiBackendToken()); + measurementReminderTos = measurementService.getMeasurementRemindersForUser(userSession.getSabiBackendToken(), userSession.getLanguage()); } catch (BusinessException e) { log.error("Could not add new Measurement Reminder.", e); MessageUtil.warn("messages", "common.error.internal_server_problem.t", userSession.getLocale()); diff --git a/sabi-webclient/src/main/resources/META-INF/resources/template/header.xhtml b/sabi-webclient/src/main/resources/META-INF/resources/template/header.xhtml index df1383f6..756e8aef 100644 --- a/sabi-webclient/src/main/resources/META-INF/resources/template/header.xhtml +++ b/sabi-webclient/src/main/resources/META-INF/resources/template/header.xhtml @@ -1,5 +1,5 @@ @@ -12,7 +12,7 @@ - + diff --git a/sabi-webclient/src/main/resources/i18n/messages.properties b/sabi-webclient/src/main/resources/i18n/messages.properties index ece29b9f..00356523 100644 --- a/sabi-webclient/src/main/resources/i18n/messages.properties +++ b/sabi-webclient/src/main/resources/i18n/messages.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2023 by Stefan Schubert under the MIT License (MIT). +# Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). # See project LICENSE file for the detailed terms and conditions. # login.welcome.h=Welcome at the SABI-Project - Seawater Aquarium Business Intelligence @@ -205,3 +205,4 @@ common.update.b=Update register.password.policy.t=(Password: Min 10 to max 20 chars. Mixture of Upper/LowerCase with Digit and Special-Character) enum.waterType.seawater.l=seawater enum.waterType.freshwater.l=freshwater +menu.b=Menu diff --git a/sabi-webclient/src/main/resources/i18n/messages_de.properties b/sabi-webclient/src/main/resources/i18n/messages_de.properties index 6200cb60..cbb08804 100644 --- a/sabi-webclient/src/main/resources/i18n/messages_de.properties +++ b/sabi-webclient/src/main/resources/i18n/messages_de.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2023 by Stefan Schubert under the MIT License (MIT). +# Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). # See project LICENSE file for the detailed terms and conditions. # register.captcha_wrongAnswer.t=Hm...das war die falsche Antwort. Bitte erneut versuchen. @@ -206,4 +206,5 @@ userprofile.meassurement.addreminder.l=Erinnerung setzen f\u00FCr: common.update.b=Aktualisieren register.password.policy.t=(Passwort: Min 10 bis 20 Zeichen. Klein/Gro\u00DFschreibung, Zahl und Sonderzeichen) enum.waterType.seawater.l=Salzwasser -enum.waterType.freshwater.l=S\u00FC\u00DFwasser \ No newline at end of file +enum.waterType.freshwater.l=S\u00FC\u00DFwasser +menu.b=Men\u00FC \ No newline at end of file diff --git a/sabi-webclient/src/main/resources/i18n/messages_en.properties b/sabi-webclient/src/main/resources/i18n/messages_en.properties index 739d963e..9ec7bd5a 100644 --- a/sabi-webclient/src/main/resources/i18n/messages_en.properties +++ b/sabi-webclient/src/main/resources/i18n/messages_en.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2023 by Stefan Schubert under the MIT License (MIT). +# Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT). # See project LICENSE file for the detailed terms and conditions. # register.captcha_wrongAnswer.t=Sorry - wrong Answer. Please try again. @@ -204,4 +204,5 @@ userprofile.meassurement.addreminder.l=Set reminder for: common.update.b=Update register.password.policy.t=(Password: Min 10 to max 20 chars. Mixture of Upper/LowerCase with Digit and Special-Character) enum.waterType.seawater.l=seawater -enum.waterType.freshwater.l=freshwater \ No newline at end of file +enum.waterType.freshwater.l=freshwater +menu.b=Menu \ No newline at end of file diff --git a/sabi-webclient/src/main/resources/i18n/messages_es.properties b/sabi-webclient/src/main/resources/i18n/messages_es.properties index e3640566..5527c78d 100644 --- a/sabi-webclient/src/main/resources/i18n/messages_es.properties +++ b/sabi-webclient/src/main/resources/i18n/messages_es.properties @@ -204,4 +204,5 @@ userprofile.meassurement.addreminder.l=Configurar recordatorio para: common.update.b=Actualizar register.password.policy.t=(Contrase\u00F1a: M\u00EDnimo 10 y m\u00E1ximo 20 caracteres. Mezcla de may\u00FAsculas/min\u00FAsculas con d\u00EDgitos y caracteres especiales) enum.waterType.seawater.l=agua de mar -enum.waterType.freshwater.l=agua dulce \ No newline at end of file +enum.waterType.freshwater.l=agua dulce +menu.b=Men\u00FA \ No newline at end of file diff --git a/sabi-webclient/src/main/resources/i18n/messages_fr.properties b/sabi-webclient/src/main/resources/i18n/messages_fr.properties index 754b31ac..53bc9bb4 100644 --- a/sabi-webclient/src/main/resources/i18n/messages_fr.properties +++ b/sabi-webclient/src/main/resources/i18n/messages_fr.properties @@ -205,4 +205,5 @@ userprofile.meassurement.addreminder.l=D\u00E9finir un rappel pour : common.update.b=Mise \u00E0 jour register.password.policy.t=(mot de passe : min 10 \u00E0 20 caract\u00E8res. Minuscules/majuscules, chiffre et caract\u00E8res sp\u00E9ciaux) enum.waterType.seawater.l=Eau sal\u00E9e -enum.waterType.freshwater.l=Eau douce \ No newline at end of file +enum.waterType.freshwater.l=Eau douce +menu.b=Menu \ No newline at end of file diff --git a/sabi-webclient/src/main/resources/i18n/messages_it.properties b/sabi-webclient/src/main/resources/i18n/messages_it.properties index 6eadca75..8a9db776 100644 --- a/sabi-webclient/src/main/resources/i18n/messages_it.properties +++ b/sabi-webclient/src/main/resources/i18n/messages_it.properties @@ -205,4 +205,5 @@ userprofile.meassurement.addreminder.l=Impostare un promemoria per: common.update.b=Aggiornamento register.password.policy.t=(Password: minimo 10-20 caratteri. Maiuscole/minuscole, numeri e caratteri speciali). enum.waterType.seawater.l=acqua salata -enum.waterType.freshwater.l=acqua dolce \ No newline at end of file +enum.waterType.freshwater.l=acqua dolce +menu.b=Menu \ No newline at end of file