From 9170157dbb2f7766fc8e7b810f58ce87d4d52918 Mon Sep 17 00:00:00 2001 From: Thibaut Valentin Date: Tue, 13 Jan 2026 21:31:05 +0100 Subject: [PATCH] feat: init translation --- src/main/webapp/package-lock.json | 160 ++++++- src/main/webapp/package.json | 4 + src/main/webapp/public/locales/en/common.json | 419 ++++++++++++++++++ src/main/webapp/public/locales/fr/common.json | 419 ++++++++++++++++++ src/main/webapp/src/App.jsx | 18 +- .../src/components/Club/ContactEditor.jsx | 15 +- .../src/components/Club/HoraireEditor.jsx | 22 +- .../src/components/Club/LocationEditor.jsx | 15 +- src/main/webapp/src/components/ClubSelect.jsx | 14 +- .../webapp/src/components/ColoredCircle.jsx | 5 +- .../webapp/src/components/ConfirmDialog.jsx | 8 +- src/main/webapp/src/components/Input.jsx | 11 - src/main/webapp/src/components/ListEditor.jsx | 83 ---- .../src/components/MemberCustomFiels.jsx | 26 +- src/main/webapp/src/components/Nav.jsx | 44 +- src/main/webapp/src/components/SearchBar.jsx | 6 +- src/main/webapp/src/config/i18n.js | 33 ++ src/main/webapp/src/main.jsx | 3 + src/main/webapp/src/pages/DemandeAff.jsx | 183 +++----- src/main/webapp/src/pages/Homepage.jsx | 27 +- src/main/webapp/src/pages/MePage.jsx | 59 +-- src/main/webapp/src/pages/MemberList.jsx | 146 +++--- .../webapp/src/pages/PayAndValidateList.jsx | 125 ++---- src/main/webapp/src/pages/admin/AdminRoot.jsx | 4 +- src/main/webapp/src/pages/admin/StatsLazy.jsx | 16 +- src/main/webapp/src/pages/admin/StatsPage.jsx | 6 +- .../admin/affiliation/AffiliationReqList.jsx | 15 +- .../admin/affiliation/AffiliationReqPage.jsx | 138 +++--- .../src/pages/admin/club/AffiliationCard.jsx | 51 +-- .../webapp/src/pages/admin/club/ClubList.jsx | 41 +- .../webapp/src/pages/admin/club/ClubPage.jsx | 74 ++-- .../src/pages/admin/club/NewClubPage.jsx | 40 +- .../src/pages/admin/member/CompteInfo.jsx | 54 +-- .../pages/admin/member/InformationForm.jsx | 51 ++- .../src/pages/admin/member/LicenceCard.jsx | 53 +-- .../src/pages/admin/member/MemberPage.jsx | 29 +- .../src/pages/admin/member/NewMemberPage.jsx | 50 +-- .../src/pages/admin/member/PremForm.jsx | 37 +- .../src/pages/admin/member/SelectCard.jsx | 62 +-- src/main/webapp/src/pages/club/ClubRoot.jsx | 5 +- .../webapp/src/pages/club/PaymentError.jsx | 13 +- .../webapp/src/pages/club/PaymentReturn.jsx | 8 +- .../src/pages/club/club/AffiliationCard.jsx | 33 +- .../webapp/src/pages/club/club/MyClubPage.jsx | 38 +- .../src/pages/club/member/CompteInfo.jsx | 17 +- .../src/pages/club/member/InformationForm.jsx | 49 +- .../src/pages/club/member/LicenceCard.jsx | 61 +-- .../src/pages/club/member/MemberPage.jsx | 29 +- .../src/pages/club/member/NewMemberPage.jsx | 46 +- .../src/pages/club/member/SelectCard.jsx | 6 +- src/main/webapp/src/utils/Tools.js | 37 +- 51 files changed, 1818 insertions(+), 1090 deletions(-) create mode 100644 src/main/webapp/public/locales/en/common.json create mode 100644 src/main/webapp/public/locales/fr/common.json delete mode 100644 src/main/webapp/src/components/Input.jsx delete mode 100644 src/main/webapp/src/components/ListEditor.jsx create mode 100644 src/main/webapp/src/config/i18n.js diff --git a/src/main/webapp/package-lock.json b/src/main/webapp/package-lock.json index c8d23ff..43a9829 100644 --- a/src/main/webapp/package-lock.json +++ b/src/main/webapp/package-lock.json @@ -18,12 +18,16 @@ "@fortawesome/react-fontawesome": "^0.2.0", "axios": "^1.6.5", "browser-image-compression": "^2.0.2", + "i18next": "^25.7.4", + "i18next-browser-languagedetector": "^8.2.0", + "i18next-http-backend": "^3.0.2", "jszip": "^3.10.1", "leaflet": "^1.9.4", "obs-websocket-js": "^5.0.7", "proj4": "^2.11.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-i18next": "^16.5.2", "react-is": "^19.0.0", "react-leaflet": "^4.2.1", "react-loader-spinner": "^6.1.6", @@ -345,12 +349,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.7.tgz", - "integrity": "sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", "engines": { "node": ">=6.9.0" } @@ -1871,6 +1872,14 @@ "node": ">=0.8" } }, + "node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -2990,6 +2999,60 @@ "node": ">= 0.4" } }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "dependencies": { + "void-elements": "3.1.0" + } + }, + "node_modules/i18next": { + "version": "25.7.4", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.7.4.tgz", + "integrity": "sha512-hRkpEblXXcXSNbw8mBNq9042OEetgyB/ahc/X17uV/khPwzV+uB8RHceHh3qavyrkPJvmXFKXME2Sy1E0KjAfw==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "dependencies": { + "@babel/runtime": "^7.28.4" + }, + "peerDependencies": { + "typescript": "^5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/i18next-browser-languagedetector": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.2.0.tgz", + "integrity": "sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g==", + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, + "node_modules/i18next-http-backend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-3.0.2.tgz", + "integrity": "sha512-PdlvPnvIp4E1sYi46Ik4tBYh/v/NbYfFFgTjkwFl0is8A18s7/bx9aXqsrOax9WUbeNS6mD2oix7Z0yGGf6m5g==", + "dependencies": { + "cross-fetch": "4.0.0" + } + }, "node_modules/ignore": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", @@ -3634,6 +3697,25 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", @@ -4028,6 +4110,32 @@ "react": "^18.2.0" } }, + "node_modules/react-i18next": { + "version": "16.5.2", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-16.5.2.tgz", + "integrity": "sha512-GG/SBVxx9dvrO1uCs8VYdKfOP8NEBUhNP+2VDQLCifRJ8DL1qPq296k2ACNGyZMDe7iyIlz/LMJTQOs8HXSRvw==", + "dependencies": { + "@babel/runtime": "^7.28.4", + "html-parse-stringify": "^3.0.1", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "i18next": ">= 25.6.2", + "react": ">= 16.8.0", + "typescript": "^5" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, "node_modules/react-is": { "version": "19.0.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.0.0.tgz", @@ -4221,11 +4329,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, "node_modules/regexp.prototype.flags": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", @@ -4704,6 +4807,11 @@ "node": ">=4" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/tslib": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", @@ -4852,6 +4960,14 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -4938,6 +5054,28 @@ } } }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/src/main/webapp/package.json b/src/main/webapp/package.json index 418755f..469cbf3 100644 --- a/src/main/webapp/package.json +++ b/src/main/webapp/package.json @@ -20,12 +20,16 @@ "@fortawesome/react-fontawesome": "^0.2.0", "axios": "^1.6.5", "browser-image-compression": "^2.0.2", + "i18next": "^25.7.4", + "i18next-browser-languagedetector": "^8.2.0", + "i18next-http-backend": "^3.0.2", "jszip": "^3.10.1", "leaflet": "^1.9.4", "obs-websocket-js": "^5.0.7", "proj4": "^2.11.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-i18next": "^16.5.2", "react-is": "^19.0.0", "react-leaflet": "^4.2.1", "react-loader-spinner": "^6.1.6", diff --git a/src/main/webapp/public/locales/en/common.json b/src/main/webapp/public/locales/en/common.json new file mode 100644 index 0000000..6066739 --- /dev/null +++ b/src/main/webapp/public/locales/en/common.json @@ -0,0 +1,419 @@ +{ + "(optionnelle)": "(optional)", + "---SansClub---": "--- no club ---", + "---ToutLesClubs---": "--- all clubs ---", + "---ToutLesPays---": "--- all countries ---", + "---TouteLesCatégories---": "--- all categories ---", + "--NonLicencier--": "-- Unlicensed --", + "activer": "Activate", + "admin": "Administration", + "adresse": "Address", + "adresseAdministrative": "Administrative address", + "aff.ancienNom": "Former name: {{name}}", + "aff.byMembreSim": "By similar member", + "aff.byNewMenbre": "By new member", + "aff.byNoLicence": "By licence number", + "aff.info1": "This club has already been affiliated (affiliation no. {{no}})", + "aff.membreNo": "Member no. {{no}}", + "aff.nomDuClub": "Club name", + "aff.raisonDuRefus": "Reason for refusal", + "aff.raisonDuRefus.msg": "Please indicate the reason for refusal", + "aff.refusConfirm": "Are you sure you want to refuse this request?", + "aff.refuserLaDemande": "Refuse the request", + "aff.refuserLaDemande.detail": "Are you sure you want to refuse this request?", + "aff.submit.error1": "Please enter a valid licence number for member {{id}}", + "aff.submit.error2": "Please enter a valid licence number for member {{id}}", + "aff.submit.error3": "Please enter a valid email for member {{id}}", + "aff.toast.accept.error": "Failed to accept affiliation", + "aff.toast.accept.pending": "Accepting affiliation in progress", + "aff.toast.accept.success": "Affiliation accepted successfully 🎉", + "aff.toast.del.error": "Failed to delete affiliation request", + "aff.toast.del.pending": "Deleting affiliation request in progress", + "aff.toast.del.success": "Affiliation request deleted successfully 🎉", + "aff.toast.del2.error": "Failed to delete affiliation", + "aff.toast.del2.pending": "Deleting affiliation in progress", + "aff.toast.del2.success": "Affiliation deleted successfully 🎉", + "aff.toast.save.error": "Failed to save affiliation request", + "aff.toast.save.pending": "Saving affiliation request in progress", + "aff.toast.save.success": "Affiliation request saved successfully 🎉", + "aff.toast.save2.error": "Failed to save affiliation", + "aff.toast.save2.pending": "Saving affiliation in progress", + "aff.toast.save2.success": "Affiliation saved successfully 🎉", + "aff_req.appuyerSurRechercher": "Press search to complete", + "aff_req.association": "The association", + "aff_req.button.cancel": "Cancel my request", + "aff_req.button.confirm": "Confirm my affiliation request", + "aff_req.button.save": "Save changes", + "aff_req.denomination": "Denomination", + "aff_req.disposeLicence": "Already has a licence", + "aff_req.error1": "The role of member {{i}} is required", + "aff_req.error2": "The SIRET/RNA format is invalid", + "aff_req.nomDeLassociation": "Association name", + "aff_req.text1": "Affiliation is annual and valid for one sports season: from September 1st to August 31st of the following year.", + "aff_req.text2": "To affiliate, a sports association must meet the following conditions:", + "aff_req.text2.li": [ + "Have its headquarters in France or the Principality of Monaco", + "Be constituted in accordance with Chapter 1 of Title II of Book 1 of the Sports Code", + "Pursue a social purpose that falls within the definition of Article 1 of the Federation's statutes", + "Have statutes compatible with the principles of organization and operation of the Federation", + "Ensure freedom of opinion and respect for the rights of the defense within it, and prohibit any discrimination", + "Comply with the rules of supervision, hygiene, and safety established by the Federation's regulations" + ], + "aff_req.text3": "After your request is validated, you will receive a temporary ID and password to access your FFSAF space", + "aff_req.text4": "Note that to finalize your affiliation, you will need to:", + "aff_req.text4.li1": "Have at least three licensed members, including the president", + "aff_req.text4.li2": "Have paid the fees provided for by the federal regulations", + "aff_req.text5": "You can later add publicly visible addresses for your training locations", + "aff_req.text6": "Leave blank to make no changes. (If a coat of arms has already been sent with this request, it will be used; otherwise, we will use the one from the previous affiliation)", + "aff_req.text7": "Affiliation request sent successfully", + "aff_req.text8": "Once your request is validated, you will receive a temporary ID and password to access your FFSAF space", + "aff_req.toast.undo.error": "Failed to cancel affiliation request", + "aff_req.toast.undo.pending": "Cancelling affiliation request in progress", + "aff_req.toast.undo.success": "Affiliation request cancelled successfully 🎉", + "afficherLétatDesAffiliation": "Display affiliation status", + "affiliation": "Affiliation", + "affiliationNo": "Affiliation no. {{no}}", + "ajouterUnClub": "Add a club", + "ajouterUnMembre": "Add a member", + "all_season": "--- all seasons ---", + "aucunMembreSélectionné": "No member selected", + "back": "« back", + "blason": "Coat of arms", + "bureau": "Board", + "button.accepter": "Accept", + "button.ajouter": "Add", + "button.annuler": "Cancel", + "button.appliquer": "Apply", + "button.confirmer": "Confirm", + "button.créer": "Create", + "button.enregistrer": "Save", + "button.fermer": "Close", + "button.refuser": "Refuse", + "button.suivant": "Next", + "button.supprimer": "Delete", + "cat.benjamin": "Benjamin", + "cat.cadet": "Cadet", + "cat.catégorieInconnue": "Unknown category", + "cat.junior": "Junior", + "cat.miniPoussin": "Mini Chick", + "cat.minime": "Minime", + "cat.poussin": "Chick", + "cat.senior1": "Senior 1", + "cat.senior2": "Senior 2", + "cat.superMini": "Super Mini", + "cat.vétéran1": "Veteran 1", + "cat.vétéran2": "Veteran 2", + "catégorie": "Category", + "certificatMédical": "Medical certificate", + "chargement...": "Loading...", + "chargerLexcel": "Upload Excel", + "chargerLexcel.msg": "Please use the file above as a base; do not rename the columns or modify the licence numbers.", + "choisir...": "Choose...", + "club.aff_renew.msg": "Please select 0 to 3 board members to fill out the pre-request. (If a non-board member will become one next year, you can enter them in the next step)", + "club.change.status": "To modify the above information, please contact FFSAF by email.", + "club.contact.tt": { + "AUTRE": "Other club contact", + "COURRIEL": "Club email address
Example: contact@ffsaf.fr", + "FACEBOOK": "Club Facebook page starting with 'https://www.facebook.com/'
Example: https://www.facebook.com/ffmsf", + "INSTAGRAM": "Club Instagram account starting with 'https://www.instagram.com/'
Example: https://www.instagram.com/ff_msf", + "SITE": "Club website with or without 'https://'
Example: ffsaf.fr
Or https://ffsaf.fr", + "TELEPHONE": "Club phone number
Example: 06 12 13 78 55" + }, + "club.toast.aff.error": "Failed to load affiliations", + "club.toast.aff.pending": "Loading affiliations in progress", + "club.toast.aff.success": "Affiliations loaded successfully 🎉", + "club.toast.del.error": "Failed to delete club", + "club.toast.del.pending": "Deleting club in progress", + "club.toast.del.success": "Club deleted successfully 🎉", + "club.toast.new.error": "Failed to create club", + "club.toast.new.pending": "Creating club in progress", + "club.toast.new.success": "Club created successfully 🎉", + "club.toast.save.error": "Failed to save club", + "club.toast.save.pending": "Saving club in progress", + "club.toast.save.success": "Club saved successfully 🎉", + "clubExterne": "External club", + "club_one": "Club", + "club_other": "Clubs", + "club_zero": "No club", + "comp_manage": "Competitions Manager", + "competition_one": "Competition", + "competition_other": "Competitions", + "compte": "Account", + "conserverLancienEmail": "Keep the old email", + "contactAdministratif": "Administrative contact", + "contactInterne": "Internal contact", + "contact_one": "Contact", + "contact_other": "Contacts", + "dateDeNaissance": "Date of birth", + "days": [ + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + "Sunday" + ], + "de": "of", + "demandeDaffiliationEnCours": "Affiliation request in progress", + "demandeDeLicence": "Licence request", + "demander": "Request", + "dlAff": "Download affiliation certificate", + "donnéesAdministratives": "Administrative data", + "définirLidDuCompte": "Set account ID", + "editionDeL'affiliation": "Editing affiliation", + "editionDeLaDemande": "Editing request", + "editionDeLaLicence": "Editing licence", + "editionDeLaSéléction": "Editing selection", + "editionDeLadresse": "Editing address", + "email": "Email", + "en": "in", + "enAttente": "Pending", + "erreurDePaiement": "Payment error😕", + "erreurDePaiement.detail": "Error message:", + "erreurDePaiement.msg": "An error occurred while processing your payment. Please try again later.", + "espaceAdministration": "Administration space", + "faitPar": "Done by", + "femme": "Female", + "filtre": "Filter", + "genre": "Gender", + "gestionGroupée": "Group management", + "gradeDarbitrage": "Referee grade", + "home": { + "header1": "For licensed members", + "header2": "For clubs", + "text1": "Here you will find all your information as well as the status of your registration with the federation. You can also download your registration certificate, sign up for competitions, and view your results, provided that the organizing club has entered them.

During your first registration, you will receive an email containing your login details; this email will be sent once your licence is validated by the secretariat.", + "text2": "This is where you can take out federal licences for your members, request or renew your affiliation, enter your schedules, training locations, and social networks, which will then be displayed on the ffsaf.fr website.
You will also have the possibility to publish registration forms for your competitions and record the results.

Not yet affiliated with the federation? Click <1>here to make your first request.", + "welcome_message": "Welcome to the intranet of the Fédération France Soft Armored Fighting" + }, + "homme": "Male", + "horairesD'entraînements": "Training schedules", + "information": "Information", + "keepEmpty": "Leave blank to make no changes.", + "le": "the", + "licence": "Licence", + "licenceNo": "Licence no. {{no}}", + "lieuxDentraînements": "Training locations", + "loading": "Loading...", + "me": { + "result": { + "PRIVATE": "Private (visible only to me)", + "PUBLIC": "Public (visible to all)", + "REGISTERED_ONLY": "Logged-in members (visible to federation members)", + "REGISTERED_ONLY_NO_DETAILS": "Logged-in members - hide details (visible to federation members)" + }, + "toast.settings.error": "Failed to update settings 😕", + "toast.settings.pending": "Updating settings in progress...", + "toast.settings.success": "Settings updated successfully 🎉" + }, + "me.changerMonMotDePasse": "Change my password", + "me.formationDarbitrage": "Referee training", + "me.paramètresDuCompte": "Account settings", + "me.rôleAuSienDuClub": "Role within the club", + "me.visibilitéDesRésultats": "Results visibility", + "member_one": "Member", + "member_other": "Members", + "membre.emailVideàLaLigne": "Empty email on line {{no}}", + "membre.emailVérifié": "Verified email", + "membre.filtre.inactif": "Show inactive fighters", + "membre.filtre.licence": "Show licence status", + "membre.filtre.licences": [ + "No request or valid licence", + "With request or valid licence", + "Request in progress", + "Licence validated", + "All licence statuses", + "Complete request", + "Incomplete request" + ], + "membre.filtre.payement": [ + "No payment", + "With payment", + "All payment statuses" + ], + "membre.identifiant": "Identifier", + "membre.import.err1": "Invalid certificate date format on line {{no}}", + "membre.import.err2": "Invalid certificate date format on line {{no}}", + "membre.import.err3": "Empty date of birth on line {{no}}", + "membre.import.err4": "Invalid date of birth format on line {{no}}", + "membre.import.err5": "Invalid email on line {{no}}", + "membre.import.errTT_one": "{{count}} error in the file, operation cancelled", + "membre.import.errTT_other": "{{count}} errors in the file, operation cancelled", + "membre.import.warn_one": "{{count}} medical certificate not filled", + "membre.import.warn_other": "{{count}} medical certificates not filled", + "membre.info.emailInfo": "The email is used to create an account to log in to the site and must be unique.
For minors, the parents' email can be used multiple times using the following syntax: {'email.parent+@example.com'}.
Examples: mail.parent+1@example.com, mail.parent+titouan@example.com, mail.parent+cedrique@example.com", + "membre.info.error1": "Please select a valid country 😕", + "membre.info.error2": "Please select a valid club 😕", + "membre.initaccount": "Initialize account", + "membre.initaccount.text1": "Enter the account UUID", + "membre.initaccount.text2": "Warning: only change a member's ID if you are sure of what you are doing...", + "membre.noAccount": "This member does not have an account...", + "membre.noAccount.clubMsg": "An account will be created by the federation when their first licence is validated", + "membre.nomVideàLaLigne": "Empty name on line {{no}}", + "membre.prénomVideàLaLigne": "Empty first name on line {{no}}", + "membre.toast.compte.created": "Account created successfully 🎉", + "membre.toast.compte.error": "Failed to create account", + "membre.toast.compte.pending": "Creating account in progress", + "membre.toast.del.error": "Failed to delete account", + "membre.toast.del.pending": "Deleting account in progress", + "membre.toast.del.success": "Account deleted successfully 🎉", + "membre.toast.id.error": "Failed to set identifier", + "membre.toast.id.pending": "Setting identifier in progress", + "membre.toast.id.success": "Identifier set successfully 🎉", + "membre.toast.licence.ask.del.error": "Failed to delete licence request", + "membre.toast.licence.ask.del.pending": "Deleting licence request in progress", + "membre.toast.licence.ask.del.success": "Licence request deleted successfully 🎉", + "membre.toast.licence.ask.error": "Failed to request licence", + "membre.toast.licence.ask.pending": "Recording licence request in progress", + "membre.toast.licence.ask.success": "Licence request recorded successfully 🎉", + "membre.toast.licence.del.error": "Failed to delete licence", + "membre.toast.licence.del.pending": "Deleting licence in progress", + "membre.toast.licence.del.success": "Licence deleted successfully 🎉", + "membre.toast.licence.save.error": "Failed to save licence", + "membre.toast.licence.save.pending": "Saving licence in progress", + "membre.toast.licence.save.success": "Licence saved successfully 🎉", + "membre.toast.licences.export.error": "Failed to export licences", + "membre.toast.licences.export.pending": "Exporting licences in progress", + "membre.toast.licences.export.success": "Licences exported successfully 🎉", + "membre.toast.licences.import.error": "Failed to send changes", + "membre.toast.licences.import.pending": "Sending changes in progress", + "membre.toast.licences.import.success": "Changes sent successfully 🎉", + "membre.toast.licences.load.error": "Failed to load licences", + "membre.toast.licences.load.pending": "Loading licences in progress", + "membre.toast.licences.load.success": "Licences loaded successfully 🎉", + "membre.toast.perm.error": "Failed to update permissions 😕", + "membre.toast.perm.pending": "Updating permissions in progress...", + "membre.toast.perm.success": "Permissions updated successfully 🎉", + "membre.toast.save.error": "Failed to update profile 😕", + "membre.toast.save.pending": "Updating profile in progress...", + "membre.toast.save.success": "Profile updated successfully 🎉", + "membre.toast.select.del.error": "Failed to delete selection", + "membre.toast.select.del.pending": "Deleting selection in progress", + "membre.toast.select.del.success": "Selection deleted successfully 🎉", + "membre.toast.select.save.error": "Failed to save selection", + "membre.toast.select.save.pending": "Saving selection in progress", + "membre.toast.select.save.success": "Selection saved successfully 🎉", + "mettreàJours": "Update", + "nationalité": "Nationality", + "nav": { + "account": "My account", + "aff_request": "Affiliation request", + "club": { + "my": "My club" + }, + "competitions": { + "results": "My results" + }, + "home": "Home", + "login": "Login", + "logout": "Logout", + "space": "My space", + "title": "FFSAF Intranet" + }, + "noLicence": "Licence no.", + "noSiretOuRna": "SIRET or RNA no.", + "nom": "Last name", + "nombreDeLicences": "Number of licences", + "nombreDeLicencesParCatégorie": "Number of licences by category for {{saison}}", + "non": "No", + "nonDéfinie": "Not defined", + "nonValidée": "Not validated", + "nouveauClub": "New club", + "nouveauMembre": "New member", + "nouvelEmail": "New email", + "oui": "Yes", + "outdated_session": { + "login_button": "Log in again", + "message": "Your session has expired. Please log in again to continue using the application.", + "title": "Session expired" + }, + "pageClub": "Club page", + "pageMembre": "Member page", + "pageNouveauClub": "New club page", + "page_info_full": "Line {{line}} to {{tt_line}} (page {{page}} of {{tt_page}})", + "page_info_ligne": "{{show}} line(s) displayed out of {{total}}", + "paiementDeLaLicence": "Licence payment", + "paiementDesLicences": "Licence payments", + "pasDeLicence": "No licence", + "payment.ha.info": "HelloAsso's solidarity model guarantees that 100% of your payment will be transferred to the chosen association. You can support the help they provide to associations by leaving a voluntary contribution to HelloAsso at the time of your payment.", + "payment.info": "About HelloAsso", + "payment.paiementSécurisé": "Secure payment", + "payment.payerAvec": "Pay with", + "payment.recap": "{{count}} licence(s) selected
Total to pay: {{total}} €", + "paymentDesLicences": "Licence payments", + "paymentDesLicences.msg_one": "Are you sure you want to mark the licence as paid?", + "paymentDesLicences.msg_other": "Are you sure you want to mark the {{count}} licences as paid?", + "paymentDesLicences.msg_zero": "$t(paymentDesLicences.msg_other)", + "paymentOk": "🎉 Your payment has been processed successfully. 🎉", + "paymentOk.msg": "Thank you for your payment. The licences should be activated within the next hour, provided the medical certificate is completed.", + "pays": "Country", + "perm.administrateurDeLaFédération": "Federation administrator", + "perm.créerDesCompétion": "Create competitions", + "perm.ffsafIntra": "FFSAF intra", + "permission": "Permission", + "photos": "Photos", + "prenom": "First name", + "rechercher": "Search", + "rechercher...": "Search...", + "registration_one": "Registration", + "registration_other": "Registrations", + "renouveler": "Renew", + "renouvellementDeLaffiliation": "Affiliation renewal", + "result_one": "Result", + "result_other": "Results", + "retouràLaListeDeMembres": "Back to member list", + "role": "Role", + "role.membre": "Member", + "role.membreDuBureau": "Board member", + "role.président": "President", + "role.secrétaire": "Secretary", + "role.trésorier": "Treasurer", + "role.vise-président": "Vice-President", + "role.vise-secrétaire": "Vice-Secretary", + "role.vise-trésorier": "Vice-Treasurer", + "saison": "Season", + "selectionner...": "Select...", + "siretOuRna": "SIRET or RNA", + "stats": "Statistics", + "statue": "Statue", + "status": "Status", + "statuts": "Statutes", + "supprimerLeClub": "Delete club", + "supprimerLeClub.msg": "Are you sure you want to delete this club?", + "supprimerLeCompte": "Delete account", + "supprimerLeCompte.msg": "Are you sure you want to delete this account?", + "sélectionEnéquipeDeFrance": "Selection in the French team", + "sélectionner...": "Select...", + "toast.edit.error": "Failed to save changes", + "toast.edit.pending": "Saving changes in progress", + "toast.edit.success": "Changes saved successfully 🎉", + "toast.licence.bulk.pay.error": "Failed to mark licences as paid", + "toast.licence.bulk.pay.pending": "Marking licences as paid in progress", + "toast.licence.bulk.pay.success": "Licences marked as paid successfully 🎉", + "toast.licence.bulk.valid.error": "Failed to validate licences", + "toast.licence.bulk.valid.pending": "Validating licences in progress", + "toast.licence.bulk.valid.success": "Licences validated successfully 🎉", + "toast.licence.order.error": "Failed to create order", + "toast.licence.order.pending": "Creating order in progress", + "toast.licence.order.success": "Order created successfully 🎉", + "trie": "Sort", + "téléchargerLexcelDesMembres": "Download members' Excel", + "téléchargerLexcelDesMembres.info": "Use as a template to update information", + "téléchargéeLaLicence": "Download licence", + "validationDeLaLicence": "Licence validation", + "validationDesLicences": "Licence validations", + "validerDesLicences": "Validate licences", + "validerLePayement_one": "Validate payment for the selected licence", + "validerLePayement_other": "Validate payment for the {{count}} selected licences", + "validerLePayement_zero": "$t(validerLePayement_other)", + "validerLicence.msg_one": "Are you sure you want to validate the licence?", + "validerLicence.msg_other": "Are you sure you want to validate the {{count}} licences?", + "validerLicence.msg_zero": "$t(validerLicence.msg_other)", + "validerLicence_one": "Validate the selected licence", + "validerLicence_other": "Validate the {{count}} selected licences", + "validerLicence_zero": "$t(validerLicence_other)", + "validée": "Validated", + "voirLesStatues": "View statues", + "à": "at", + "étatDeLaDemande": "Request status" +} diff --git a/src/main/webapp/public/locales/fr/common.json b/src/main/webapp/public/locales/fr/common.json new file mode 100644 index 0000000..ed7bb93 --- /dev/null +++ b/src/main/webapp/public/locales/fr/common.json @@ -0,0 +1,419 @@ +{ + "(optionnelle)": "(optionnelle)", + "---SansClub---": "--- sans club ---", + "---ToutLesClubs---": "--- tout les clubs ---", + "---ToutLesPays---": "--- tout les pays ---", + "---TouteLesCatégories---": "--- toute les catégories ---", + "--NonLicencier--": "-- Non licencier --", + "activer": "Activer", + "admin": "Administration", + "adresse": "Adresse", + "adresseAdministrative": "Adresse administrative", + "aff.ancienNom": "Ancien nom: {{name}}", + "aff.byMembreSim": "Par Membre similaire", + "aff.byNewMenbre": "Par Nouveau membre", + "aff.byNoLicence": "Par n° de licence", + "aff.info1": "Ce club a déjà été affilié (affiliation n°{{no}})", + "aff.membreNo": "Membre n°{{no}}", + "aff.nomDuClub": "Nom du club", + "aff.raisonDuRefus": "Raison du refus", + "aff.raisonDuRefus.msg": "Veuillez indiquer la raison du refus", + "aff.refusConfirm": "Êtes-vous sûr de vouloir refuser cette demande ?", + "aff.refuserLaDemande": "Refuser la demande", + "aff.refuserLaDemande.detail": "Êtes-vous sûr de vouloir refuser cette demande ?", + "aff.submit.error1": "Veuillez saisir un numéro de licence valide pour le membre {{id}}", + "aff.submit.error2": "Veuillez saisir un numéro de licence valide pour le membre {{id}}", + "aff.submit.error3": "Veuillez saisir un email valide pour le membre {{id}}", + "aff.toast.accept.error": "Échec de l'acceptation de l'affiliation", + "aff.toast.accept.pending": "Acceptation de l'affiliation en cours", + "aff.toast.accept.success": "Affiliation acceptée avec succès 🎉", + "aff.toast.del.error": "Échec de la suppression de la demande d'affiliation", + "aff.toast.del.pending": "Suppression de la demande d'affiliation en cours", + "aff.toast.del.success": "Demande d'affiliation supprimée avec succès 🎉", + "aff.toast.del2.error": "Échec de la suppression de l'affiliation", + "aff.toast.del2.pending": "Suppression de l'affiliation en cours", + "aff.toast.del2.success": "Affiliation supprimée avec succès 🎉", + "aff.toast.save.error": "Échec de l'enregistrement de la demande d'affiliation", + "aff.toast.save.pending": "Enregistrement de la demande d'affiliation en cours", + "aff.toast.save.success": "Demande d'affiliation enregistrée avec succès 🎉", + "aff.toast.save2.error": "Échec de l'enregistrement de l'affiliation", + "aff.toast.save2.pending": "Enregistrement de l'affiliation en cours", + "aff.toast.save2.success": "Affiliation enregistrée avec succès 🎉", + "aff_req.appuyerSurRechercher": "Appuyer sur rechercher pour compléter", + "aff_req.association": "L'association", + "aff_req.button.cancel": "Annuler ma demande", + "aff_req.button.confirm": "Confirmer ma demande d'affiliation", + "aff_req.button.save": "Enregistrer les modifications", + "aff_req.denomination": "Dénomination", + "aff_req.disposeLicence": "Dispose déjà d'une licence", + "aff_req.error1": "Le rôle du membre {{i}} est obligatoire", + "aff_req.error2": "Le format du SIRET/RNA est invalide", + "aff_req.nomDeLassociation": "Nom de l'association", + "aff_req.text1": "L'affiliation est annuelle et valable pour une saison sportive : du 1er septembre au 31 août de l’année suivante.", + "aff_req.text2": "Pour s’affilier, une association sportive doit réunir les conditions suivantes :", + "aff_req.text2.li": [ + "Avoir son siège social en France ou Principauté de Monaco", + "Être constituée conformément au chapitre 1er du titre II du livre 1er du Code du Sport", + "Poursuivre un objet social entrant dans la définition de l’article 1 des statuts de la Fédération", + "Disposer de statuts compatibles avec les principes d’organisation et de fonctionnement de la Fédération", + "Assurer en son sein la liberté d’opinion et le respect des droits de la défense, et s’interdire toute discrimination", + "Respecter les règles d’encadrement, d’hygiène et de sécurité établies par les règlements de la Fédération" + ], + "aff_req.text3": "Après validation de votre demande, vous recevrez un identifiant et mot de passe provisoire pour accéder à votre espace FFSAF", + "aff_req.text4": "Notez que pour finaliser votre affiliation, il vous faudra :", + "aff_req.text4.li1": "Disposer d’au moins trois membres licenciés, dont le président", + "aff_req.text4.li2": "S'être acquitté des cotisations prévues par les règlements fédéraux", + "aff_req.text5": "Vous pourrez par la suite, ajouter des adresses visibles publiquement pour vos lieux d'entrainement", + "aff_req.text6": "Laissez vide pour ne rien changer. (Si un blason a déjà été envoyé lors de cette demande, il sera utilisé, sinon nous utiliserons celui de la précédant affiliation)", + "aff_req.text7": "Demande d'affiliation envoyée avec succès", + "aff_req.text8": "Une fois votre demande validée, vous recevrez un identifiant et mot de passe provisoire pour accéder à votre espace FFSAF", + "aff_req.toast.undo.error": "Échec de l'annulation de la demande d'affiliation", + "aff_req.toast.undo.pending": "Annulation de la demande d'affiliation en cours", + "aff_req.toast.undo.success": "Demande d'affiliation annulée avec succès 🎉", + "afficherLétatDesAffiliation": "Afficher l'état des affiliation", + "affiliation": "Affiliation", + "affiliationNo": "Affiliation n°{{no}}", + "ajouterUnClub": "Ajouter un club", + "ajouterUnMembre": "Ajouter un membre", + "all_season": "--- tout les saisons ---", + "aucunMembreSélectionné": "Aucun membre sélectionné", + "back": "« retour", + "blason": "Blason", + "bureau": "Bureau", + "button.accepter": "Accepter", + "button.ajouter": "Ajouter", + "button.annuler": "Annuler", + "button.appliquer": "Appliquer", + "button.confirmer": "Confirmer", + "button.créer": "Créer", + "button.enregistrer": "Enregistrer", + "button.fermer": "Fermer", + "button.refuser": "Refuser", + "button.suivant": "Suivant", + "button.supprimer": "Supprimer", + "cat.benjamin": "Benjamin", + "cat.cadet": "Cadet", + "cat.catégorieInconnue": "Catégorie inconnue", + "cat.junior": "Junior", + "cat.miniPoussin": "Mini Poussin", + "cat.minime": "Minime", + "cat.poussin": "Poussin", + "cat.senior1": "Senior 1", + "cat.senior2": "Senior 2", + "cat.superMini": "Super Mini", + "cat.vétéran1": "Vétéran 1", + "cat.vétéran2": "Vétéran 2", + "catégorie": "Catégorie", + "certificatMédical": "Certificat médical", + "chargement...": "Chargement...", + "chargerLexcel": "Charger l'Excel", + "chargerLexcel.msg": "Merci d'utiliser le fichier ci-dessus comme base, ne pas renommer les colonnes ni modifier les n° de licences.", + "choisir...": "Choisir...", + "club.aff_renew.msg": "Veuillez sélectionner 0 à 3 membres du bureau pour remplir la pré-demande. (Si un membre non-bureau va le devenir l'an prochain, vous pourrez les renseigner à la prochaine étape)", + "club.change.status": "Pour modifier les informations ci-dessus, merci de contacter la FFSAF par mail.", + "club.contact.tt": { + "AUTRE": "Autre contact du club", + "COURRIEL": "Adresse e-mail du club
Exemple: contact@ffsaf.fr", + "FACEBOOK": "Page Facebook du club débutant par 'https://www.facebook.com/'
Exemple: https://www.facebook.com/ffmsf", + "INSTAGRAM": "Compte Instagram du club débutant par 'https://www.instagram.com/'
Exemple: https://www.instagram.com/ff_msf", + "SITE": "Site web du club avec ou sans le 'https://'
Exemple: ffsaf.fr
Ou https://ffsaf.fr", + "TELEPHONE": "Numéro de téléphone du club
Exemple: 06 12 13 78 55" + }, + "club.toast.aff.error": "Impossible de charger les affiliations", + "club.toast.aff.pending": "Chargement des affiliations en cours", + "club.toast.aff.success": "Affiliations chargées avec succès 🎉", + "club.toast.del.error": "Échec de la suppression du club", + "club.toast.del.pending": "Suppression du club en cours", + "club.toast.del.success": "Club supprimé avec succès 🎉", + "club.toast.new.error": "Échec de la création du club", + "club.toast.new.pending": "Création du club en cours", + "club.toast.new.success": "Club créé avec succès 🎉", + "club.toast.save.error": "Échec de l'enregistrement du club", + "club.toast.save.pending": "Enregistrement du club en cours", + "club.toast.save.success": "Club enregistré avec succès 🎉", + "clubExterne": "Club externe", + "club_one": "Club", + "club_other": "Clubs", + "club_zero": "Sans club", + "comp_manage": "Compétitions Manager", + "competition_one": "Compétition", + "competition_other": "Compétitions", + "compte": "Compte", + "conserverLancienEmail": "Conserver l'ancien email", + "contactAdministratif": "Contact administratif", + "contactInterne": "Contact interne", + "contact_one": "Contact", + "contact_other": "Contacts", + "dateDeNaissance": "Date de naissance", + "days": [ + "Lundi", + "Mardi", + "Mercredi", + "Jeudi", + "Vendredi", + "Samedi", + "Dimanche" + ], + "de": "de", + "demandeDaffiliationEnCours": "Demande d'affiliation en cours", + "demandeDeLicence": "Demande de licence ", + "demander": "Demander", + "dlAff": "Téléchargée l'attestation d'affiliation", + "donnéesAdministratives": "Données administratives", + "définirLidDuCompte": "Définir l'id du compte", + "editionDeL'affiliation": "Edition de l'affiliation", + "editionDeLaDemande": "Edition de la demande ", + "editionDeLaLicence": "Edition de la licence", + "editionDeLaSéléction": "Edition de la séléction", + "editionDeLadresse": "Edition de l'adresse", + "email": "Email", + "en": "en", + "enAttente": "En attente", + "erreurDePaiement": "Erreur de paiement😕", + "erreurDePaiement.detail": "Message d'erreur :", + "erreurDePaiement.msg": "Une erreur est survenue lors du traitement de votre paiement. Veuillez réessayer plus tard.", + "espaceAdministration": "Espace administration", + "faitPar": "Fait par", + "femme": "Femme", + "filtre": "Filtre", + "genre": "Genre", + "gestionGroupée": "Gestion groupée", + "gradeDarbitrage": "Grade d'arbitrage", + "home": { + "header1": "Pour les licenciés", + "header2": "Pour les clubs", + "text1": "Vous y retrouverez toutes vos informations ainsi que l'état de votre inscription à la fédération. Vous pouvez également télécharger votre attestation d'inscription, vous inscrire aux compétitions ainsi que consulter vos résultats sous réserve que le club organisateur les ait renseignés.

Lors de votre première inscription, vous recevrez un email contenant vos informations d'identification, ce mail sera envoyé une fois votre licence validée par le secrétariat.", + "text2": "C'est ici que vous pouvez prendre les licences fédérales pour vos adhérents, que vous pouvez demander ou renouveler votre affiliation, renseigner vos horaires, lieux d'entraînement et réseaux sociaux qui seront par la suite affichés sur le site ffsaf.fr.
Vous aurez par ailleurs la possibilité de publier des formulaires d'inscriptions pour vos compétitions ainsi que d'enregistrer les résultats.

Vous n'êtes pas encore affilié à la fédération ? Cliquez <1>içi pour faire votre première demande.", + "welcome_message": "Bienvenue sur l’intranet de la Fédération France Soft Armored Fighting" + }, + "homme": "Homme", + "horairesD'entraînements": "Horaires d'entraînements", + "information": "Information", + "keepEmpty": "Laissez vide pour ne rien changer.", + "le": "le", + "licence": "Licence", + "licenceNo": "Licence n°{{no}}", + "lieuxDentraînements": "Lieux d'entraînements", + "loading": "Chargement...", + "me": { + "result": { + "PRIVATE": "Privé (visible uniquement par moi)", + "PUBLIC": "Public (visible par tous)", + "REGISTERED_ONLY": "Membres connectés (visibles par les membres de la fédération)", + "REGISTERED_ONLY_NO_DETAILS": "Membres connectés - masquer les détails (visibles par les membres de la fédération)" + }, + "toast.settings.error": "Échec de la mise à jours des paramètres 😕", + "toast.settings.pending": "Mise à jours des paramètres en cours...", + "toast.settings.success": "Paramètres mis à jours avec succès 🎉" + }, + "me.changerMonMotDePasse": "Changer mon mot de passe", + "me.formationDarbitrage": "Formation d'arbitrage", + "me.paramètresDuCompte": "Paramètres du compte", + "me.rôleAuSienDuClub": "Rôle au sien du club", + "me.visibilitéDesRésultats": "Visibilité des résultats", + "member_one": "Membre", + "member_other": "Membres", + "membre.emailVideàLaLigne": "Email vide à la ligne {{no}}", + "membre.emailVérifié": "Email vérifié", + "membre.filtre.inactif": "Afficher les combattants inactifs", + "membre.filtre.licence": "Afficher l'état des licences", + "membre.filtre.licences": [ + "Sans demande ni licence validée", + "Avec demande ou licence validée", + "Demande en cours", + "Licence validée", + "Tout les états de licences", + "Demande complet", + "Demande incomplet" + ], + "membre.filtre.payement": [ + "Sans paiement", + "Avec paiement", + "Tout les états de paiement" + ], + "membre.identifiant": "Identifiant", + "membre.import.err1": "Format de la date de certificat invalide à la ligne {{no}}", + "membre.import.err2": "Format de la date de certificat invalide à la ligne {{no}}", + "membre.import.err3": "Date de naissance vide à la ligne {{no}}", + "membre.import.err4": "Format de la date de naissance invalide à la ligne {{no}}", + "membre.import.err5": "Email invalide à la ligne {{no}}", + "membre.import.errTT_one": "{{count}} erreur dans le fichier, opération annulée", + "membre.import.errTT_other": "{{count}} erreurs dans le fichier, opération annulée", + "membre.import.warn_one": "{{count}} certificat médical non rempli", + "membre.import.warn_other": "{{count}} certificats médicaux non remplis", + "membre.info.emailInfo": "L'email sert à la création de compte pour se connecter au site et doit être unique.
Pour les mineurs, l'email des parents peut être utilisé plusieurs fois grâce à la syntaxe suivante : {'email.parent+@exemple.com'}.
Exemples : mail.parent+1@exemple.com, mail.parent+titouan@exemple.com, mail.parent+cedrique@exemple.com", + "membre.info.error1": "Veuillez sélectionner un pays valide 😕", + "membre.info.error2": "Veuillez sélectionner un club valide 😕", + "membre.initaccount": "Initialiser le compte", + "membre.initaccount.text1": "Entré l'UUID du compte", + "membre.initaccount.text2": "Attention ne changée l'id d'un membre que si vous êtes sûr de ce que vos faites...", + "membre.noAccount": "Ce membre ne dispose pas de compte...", + "membre.noAccount.clubMsg": "Un compte sera créé par la fédération lors de la validation de sa première licence", + "membre.nomVideàLaLigne": "Nom vide à la ligne {{no}}", + "membre.prénomVideàLaLigne": "Prénom vide à la ligne {{no}}", + "membre.toast.compte.created": "Compte créé avec succès 🎉", + "membre.toast.compte.error": "Échec de la création du compte", + "membre.toast.compte.pending": "Création du compte en cours", + "membre.toast.del.error": "Échec de la suppression du compte", + "membre.toast.del.pending": "Suppression du compte en cours", + "membre.toast.del.success": "Compte supprimé avec succès 🎉", + "membre.toast.id.error": "Échec de la définition de l'identifient", + "membre.toast.id.pending": "Définition de l'identifient en cours", + "membre.toast.id.success": "Identifient défini avec succès 🎉", + "membre.toast.licence.ask.del.error": "Échec de la suppression de la demande de licence", + "membre.toast.licence.ask.del.pending": "Suppression de la demande de licence en cours", + "membre.toast.licence.ask.del.success": "Demande de licence supprimée avec succès 🎉", + "membre.toast.licence.ask.error": "Échec de la demande de licence", + "membre.toast.licence.ask.pending": "Enregistrement de la demande de licence en cours", + "membre.toast.licence.ask.success": "Demande de licence enregistrée avec succès 🎉", + "membre.toast.licence.del.error": "Échec de la suppression de la licence", + "membre.toast.licence.del.pending": "Suppression de la licence en cours", + "membre.toast.licence.del.success": "Licence supprimée avec succès 🎉", + "membre.toast.licence.save.error": "Échec de l'enregistrement de la licence", + "membre.toast.licence.save.pending": "Enregistrement de la licence en cours", + "membre.toast.licence.save.success": "Licence enregistrée avec succès 🎉", + "membre.toast.licences.export.error": "Échec de l'export des licences", + "membre.toast.licences.export.pending": "Export des licences en cours", + "membre.toast.licences.export.success": "Licences exportées avec succès 🎉", + "membre.toast.licences.import.error": "Échec de l'envoie des changements", + "membre.toast.licences.import.pending": "Envoie des changements en cours", + "membre.toast.licences.import.success": "Changements envoyés avec succès 🎉", + "membre.toast.licences.load.error": "Impossible de charger les licences", + "membre.toast.licences.load.pending": "Chargement des licences en cours", + "membre.toast.licences.load.success": "Licences chargées avec succès 🎉", + "membre.toast.perm.error": "Échec de la mise à jours des permissions 😕", + "membre.toast.perm.pending": "Mise à jours des permissions en cours...", + "membre.toast.perm.success": "Permission mise à jours avec succès 🎉", + "membre.toast.save.error": "Échec de la mise à jours du profil 😕", + "membre.toast.save.pending": "Mise à jours du profil en cours...", + "membre.toast.save.success": "Profil mis à jours avec succès 🎉", + "membre.toast.select.del.error": "Échec de la suppression de la séléction", + "membre.toast.select.del.pending": "Suppression de la séléction en cours", + "membre.toast.select.del.success": "Séléction supprimée avec succès 🎉", + "membre.toast.select.save.error": "Échec de l'enregistrement de la séléction", + "membre.toast.select.save.pending": "Enregistrement de la séléction en cours", + "membre.toast.select.save.success": "Séléction enregistrée avec succès 🎉", + "mettreàJours": "Mettre à jours", + "nationalité": "Nationalité", + "nav": { + "account": "Mon compte", + "aff_request": "Demande d'affiliation", + "club": { + "my": "Mon club" + }, + "competitions": { + "results": "Mes résultats" + }, + "home": "Accueil", + "login": "Connexion", + "logout": "Déconnexion", + "space": "Mon espace", + "title": "FFSAF Intranet" + }, + "noLicence": "N° Licence", + "noSiretOuRna": "N° $t(siretOuRna)", + "nom": "Nom", + "nombreDeLicences": "Nombre de licences", + "nombreDeLicencesParCatégorie": "Nombre de licences par catégorie pour {{saison}}", + "non": "Non", + "nonDéfinie": "Non définie", + "nonValidée": "Non validée", + "nouveauClub": "Nouveau club", + "nouveauMembre": "Nouveau membre", + "nouvelEmail": "Nouvel email", + "oui": "Oui", + "outdated_session": { + "login_button": "Se reconnecter", + "message": "Votre session a expirée, veuillez vous reconnecter pour continuer à utiliser l'application.", + "title": "Session expirée" + }, + "pageClub": "Page club", + "pageMembre": "Page membre", + "pageNouveauClub": "Page nouveau club", + "page_info_full": "Ligne {{line}} à {{tt_line}} (page {{page}} sur {{tt_page}})", + "page_info_ligne": "{{show}} ligne(s) affichée(s) sur {{total}}", + "paiementDeLaLicence": "Paiement de la licence", + "paiementDesLicences": "Paiement des licences", + "pasDeLicence": "Pas de licence", + "payment.ha.info": "Le modèle solidaire de HelloAsso garantit que 100% de votre paiement sera versé à l’association choisie. Vous pouvez soutenir l’aide qu’ils apportent aux associations en laissant une contribution volontaire à HelloAsso au moment de votre paiement.", + "payment.info": "A propos de HelloAsso", + "payment.paiementSécurisé": "Paiement sécurisé", + "payment.payerAvec": "Payer avec", + "payment.recap": "{{count}} licence(s) sélectionnée
Total à régler : {{total}} €", + "paymentDesLicences": "Payment des licences", + "paymentDesLicences.msg_one": "Êtes-vous sûr de vouloir marquer comme payées la licence ?", + "paymentDesLicences.msg_other": "Êtes-vous sûr de vouloir marquer comme payées les {{count}} licences ?", + "paymentDesLicences.msg_zero": "$t(paymentDesLicences.msg_other)", + "paymentOk": "🎉Votre paiement a été traité avec succès.🎉", + "paymentOk.msg": "Merci pour votre paiement. Les licences devraient être activées dans l'heure qui vient, à condition que le certificat médical soit rempli.", + "pays": "Pays", + "perm.administrateurDeLaFédération": "Administrateur de la fédération", + "perm.créerDesCompétion": "Créer des compétion", + "perm.ffsafIntra": "FFSAF intra", + "permission": "Permission", + "photos": "Photos", + "prenom": "Prénom", + "rechercher": "Rechercher", + "rechercher...": "Rechercher...", + "registration_one": "Inscription", + "registration_other": "Inscriptions", + "renouveler": "Renouveler", + "renouvellementDeLaffiliation": "Renouvellement de l'affiliation", + "result_one": "Résultat", + "result_other": "Résultats", + "retouràLaListeDeMembres": "Retour à la liste de membres", + "role": "Rôle", + "role.membre": "Membre", + "role.membreDuBureau": "Membre du bureau", + "role.président": "Président", + "role.secrétaire": "Secrétaire", + "role.trésorier": "Trésorier", + "role.vise-président": "Vise-Président", + "role.vise-secrétaire": "Vise-Secrétaire", + "role.vise-trésorier": "Vise-Trésorier", + "saison": "Saison", + "selectionner...": "Sélectionner...", + "siretOuRna": "SIRET ou RNA", + "stats": "Statistiques", + "statue": "Statue", + "status": "Status", + "statuts": "Statuts", + "supprimerLeClub": "Supprimer le club", + "supprimerLeClub.msg": "Êtes-vous sûr de vouloir supprimer ce club ?", + "supprimerLeCompte": "Supprimer le compte", + "supprimerLeCompte.msg": "Êtes-vous sûr de vouloir supprimer ce compte ?", + "sélectionEnéquipeDeFrance": "Sélection en équipe de France", + "sélectionner...": "Sélectionner...", + "toast.edit.error": "Échec de l'enregistrement des modifications", + "toast.edit.pending": "Enregistrement des modifications en cours", + "toast.edit.success": "Modifications enregistrées avec succès 🎉", + "toast.licence.bulk.pay.error": "Échec du marquage des licences comme payées", + "toast.licence.bulk.pay.pending": "Marquage des licences comme payées en cours", + "toast.licence.bulk.pay.success": "Licences marquées comme payées avec succès 🎉", + "toast.licence.bulk.valid.error": "Échec de la validation des licences", + "toast.licence.bulk.valid.pending": "Validation des licences en cours", + "toast.licence.bulk.valid.success": "Licences validées avec succès 🎉", + "toast.licence.order.error": "Échec de le création de la commande", + "toast.licence.order.pending": "Création de la commande en cours", + "toast.licence.order.success": "Commande créée avec succès 🎉", + "trie": "Trie", + "téléchargerLexcelDesMembres": "Télécharger l'Excel des membres", + "téléchargerLexcelDesMembres.info": "À utiliser comme template pour mettre à jour les informations", + "téléchargéeLaLicence": "Téléchargée la licence", + "validationDeLaLicence": "Validation de la licence", + "validationDesLicences": "Validation des licences", + "validerDesLicences": "Valider des licences", + "validerLePayement_one": "Valider le payement de la licence sélectionnée", + "validerLePayement_other": "Valider le payement des {{count}} licences sélectionnées", + "validerLePayement_zero": "$t(validerLePayement_other)", + "validerLicence.msg_one": "Êtes-vous sûr de vouloir valider la licence ?", + "validerLicence.msg_other": "Êtes-vous sûr de vouloir valider les {{count}} licences ?", + "validerLicence.msg_zero": "$t(validerLicence.msg_other)", + "validerLicence_one": "Valider la licence sélectionnée", + "validerLicence_other": "Valider les {{count}} licences sélectionnées", + "validerLicence_zero": "$t(validerLicence_other)", + "validée": "Validée", + "voirLesStatues": "Voir les statues", + "à": "à", + "étatDeLaDemande": "État de la demande" +} diff --git a/src/main/webapp/src/App.jsx b/src/main/webapp/src/App.jsx index 6d89acc..f3e4930 100644 --- a/src/main/webapp/src/App.jsx +++ b/src/main/webapp/src/App.jsx @@ -14,8 +14,8 @@ import {ClubRoot, getClubChildren} from "./pages/club/ClubRoot.jsx"; import {DemandeAff, DemandeAffOk} from "./pages/DemandeAff.jsx"; import {MePage} from "./pages/MePage.jsx"; import {CompetitionRoot, getCompetitionChildren} from "./pages/competition/CompetitionRoot.jsx"; -import {FallingLines} from "react-loader-spinner"; import {getResultChildren, ResultRoot} from "./pages/result/ResultRoot.jsx"; +import {useTranslation} from "react-i18next"; const router = createBrowserRouter([ { @@ -79,10 +79,12 @@ const router = createBrowserRouter([ function GetCompetitionMangerLazy() { const CMLazy = lazy(() => import('./pages/competition/editor/CompetitionManagerRoot.jsx')) + const {t} = useTranslation(); + return -

Compétition manager

-

Chargement...

+

{t("comp_manage")}

+

{t("loading")}

}>
@@ -144,6 +146,7 @@ function Root() { function ReAuthMsg() { const {is_authenticated} = useAuth() const location = useLocation() + const {t} = useTranslation(); const notAuthPaths = [ /^\/$/s, @@ -161,15 +164,14 @@ function ReAuthMsg() { }}>
-
Session expirée
+
{t("outdated_session.title")}
-

Votre session a expirée, veuillez vous reconnecter pour continuer à - utiliser l'application.

+

{t("outdated_session.message")}

- - Accueil + + {t("nav.home")}
diff --git a/src/main/webapp/src/components/Club/ContactEditor.jsx b/src/main/webapp/src/components/Club/ContactEditor.jsx index 77c13df..2eda025 100644 --- a/src/main/webapp/src/components/Club/ContactEditor.jsx +++ b/src/main/webapp/src/components/Club/ContactEditor.jsx @@ -2,19 +2,12 @@ import {useEffect, useReducer, useState} from "react"; import {SimpleReducer} from "../../utils/SimpleReducer.jsx"; import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; import {faAdd, faCircleQuestion, faTrashCan} from "@fortawesome/free-solid-svg-icons"; +import {useTranslation} from "react-i18next"; export function ContactEditor({data}) { const [state, dispatch] = useReducer(SimpleReducer, []) const [out_data, setOutData] = useState({}) - - const tooltipText = { - SITE: "Site web du club avec ou sans le 'https://'
Exemple: ffsaf.fr
Ou https://ffsaf.fr", - FACEBOOK: "Page Facebook du club débutant par 'https://www.facebook.com/'
Exemple: https://www.facebook.com/ffmsf", - TELEPHONE: "Numéro de téléphone du club
Exemple: 06 12 13 78 55", - INSTAGRAM: "Compte Instagram du club débutant par 'https://www.instagram.com/'
Exemple: https://www.instagram.com/ff_msf", - COURRIEL: "Adresse e-mail du club
Exemple: contact@ffsaf.fr", - AUTRE: "Autre contact du club", - } + const {t} = useTranslation(); useEffect(() => { let i = 0; @@ -38,7 +31,7 @@ export function ContactEditor({data}) { return
- Contacts + {t('contact', {count : 2})}
    {state.map((d, index) => { if (d.data === undefined || d.data.value === undefined) @@ -62,7 +55,7 @@ export function ContactEditor({data}) { dispatch({type: 'UPDATE_OR_ADD', payload: {id: d.id, data: {type: d.data.type, value: e.target.value}}}) }}/>
@@ -147,7 +150,7 @@ export function LocationEditorModal({modal, sendData}) {
- + setLocation(e.target.value)}/> @@ -174,9 +177,9 @@ export function LocationEditorModal({modal, sendData}) {
- +
diff --git a/src/main/webapp/src/components/ClubSelect.jsx b/src/main/webapp/src/components/ClubSelect.jsx index 844f781..8e460f7 100644 --- a/src/main/webapp/src/components/ClubSelect.jsx +++ b/src/main/webapp/src/components/ClubSelect.jsx @@ -1,6 +1,7 @@ import {LoadingProvider, useLoadingSwitcher} from "../hooks/useLoading.jsx"; import {useFetch} from "../hooks/useFetch.js"; import {AxiosError} from "./AxiosError.jsx"; +import {useTranslation} from "react-i18next"; export function ClubSelect({defaultValue, name, na = false, disabled = false}) { return @@ -11,6 +12,7 @@ export function ClubSelect({defaultValue, name, na = false, disabled = false}) { function ClubSelect_({defaultValue, name, na, disabled}) { const setLoading = useLoadingSwitcher() const {data, error} = useFetch(`/club/no_detail`, setLoading, 1) + const {t} = useTranslation(); return <> {data @@ -18,8 +20,8 @@ function ClubSelect_({defaultValue, name, na, disabled}) { @@ -31,11 +33,13 @@ function ClubSelect_({defaultValue, name, na, disabled}) { } function Def() { + const {t} = useTranslation(); + return
- +
; } diff --git a/src/main/webapp/src/components/ColoredCircle.jsx b/src/main/webapp/src/components/ColoredCircle.jsx index 55fab61..e709071 100644 --- a/src/main/webapp/src/components/ColoredCircle.jsx +++ b/src/main/webapp/src/components/ColoredCircle.jsx @@ -1,5 +1,6 @@ import {Fragment} from "react"; import './ColoredCircle.css' +import i18n from "i18next"; export const ColoredCircle = ({color, boolean}) => { const styles = {backgroundColor: '#F00'}; @@ -15,7 +16,7 @@ export const ColoredCircle = ({color, boolean}) => { }; -export const ColoredText = ({boolean, text={true: "Oui", false: "Non"}}) => { +export const ColoredText = ({boolean, text={true: i18n.t('oui'), false: i18n.t('non')}}) => { const styles = {color: '#F00'}; if (boolean !== undefined) { @@ -25,4 +26,4 @@ export const ColoredText = ({boolean, text={true: "Oui", false: "Non"}}) => { return {text[boolean]} -}; \ No newline at end of file +}; diff --git a/src/main/webapp/src/components/ConfirmDialog.jsx b/src/main/webapp/src/components/ConfirmDialog.jsx index b3719ad..702f34f 100644 --- a/src/main/webapp/src/components/ConfirmDialog.jsx +++ b/src/main/webapp/src/components/ConfirmDialog.jsx @@ -1,5 +1,7 @@ +import {useTranslation} from "react-i18next"; export function ConfirmDialog({title, message, onConfirm = () => {}, onCancel = () => {}, id = "confirm-delete"}) { + const {t} = useTranslation(); return -} \ No newline at end of file +} diff --git a/src/main/webapp/src/components/Input.jsx b/src/main/webapp/src/components/Input.jsx deleted file mode 100644 index cbadc22..0000000 --- a/src/main/webapp/src/components/Input.jsx +++ /dev/null @@ -1,11 +0,0 @@ -export function Input({placeholder, value, onChange}) { - return
- onChange(e.target.value)} - /> -
-} \ No newline at end of file diff --git a/src/main/webapp/src/components/ListEditor.jsx b/src/main/webapp/src/components/ListEditor.jsx deleted file mode 100644 index 52edec4..0000000 --- a/src/main/webapp/src/components/ListEditor.jsx +++ /dev/null @@ -1,83 +0,0 @@ -import {useEffect, useReducer, useState} from "react"; -import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; -import {faPen, faTrashCan} from "@fortawesome/free-solid-svg-icons"; -import {AxiosError} from "./AxiosError.jsx"; - -function SimpleReducer(datas, action) { - switch (action.type) { - case 'ADD': - return [ - ...datas, - action.payload - ] - case 'REMOVE': - return datas.filter(data => data.id !== action.payload) - case 'UPDATE_OR_ADD': - const index = datas.findIndex(data => data.id === action.payload.id) - if (index === -1) { - return [ - ...datas, - action.payload - ] - } else { - datas[index] = action.payload - return [...datas] - } - default: - throw new Error() - } -} - -export function ListEditorTest() { - const [html, dispatch] = ListEditor(ListHTML) - - useEffect(() => { - dispatch({type: 'UPDATE_OR_ADD', payload: {id: 1, content: "data in"}}) - }, []); - - return html -} - -export function ListEditor(ListItem) { - const [modal, setModal] = useState({id: -1}) - const [state, dispatch] = useReducer(SimpleReducer, []) - - const sendAffiliation = (e) => { - - dispatch({type: 'UPDATE_OR_ADD', payload: e}) - } - - return [<> -
    - {state.map((d, index) => { - return
    - - - -
    - })} -
- - -, dispatch] -} - -function ListHTML({ - data -}) { - return
{data.content}
-} \ No newline at end of file diff --git a/src/main/webapp/src/components/MemberCustomFiels.jsx b/src/main/webapp/src/components/MemberCustomFiels.jsx index a922f33..deb4f24 100644 --- a/src/main/webapp/src/components/MemberCustomFiels.jsx +++ b/src/main/webapp/src/components/MemberCustomFiels.jsx @@ -1,11 +1,15 @@ import {useEffect, useState} from "react"; import {getCategoryFormBirthDate, getCatName} from "../utils/Tools.js"; import {useCountries} from "../hooks/useCountries.jsx"; +import i18n from "../config/i18n.js"; +import {useTranslation} from "react-i18next"; export function BirthDayField({inti_date, inti_category, required = true}) { const [date, setDate] = useState(inti_date) const [category, setCategory] = useState(inti_category) const [canUpdate, setCanUpdate] = useState(false) + const {t} = useTranslation(); + useEffect(() => { const b = category !== getCategoryFormBirthDate(new Date(date)) if (b !== canUpdate) @@ -18,19 +22,19 @@ export function BirthDayField({inti_date, inti_category, required = true}) { return <>
- Date de naissance + {t('dateDeNaissance')} setDate(e.target.value)}/>
- Catégorie + {t('catégorie')} {canUpdate && } + onClick={updateCat}>{t('mettreàJours')}}
@@ -52,14 +56,14 @@ export function OptionField({name, text, values, value, disabled = false}) { export function RoleList({name, text, value, disabled = false}) { return } diff --git a/src/main/webapp/src/components/Nav.jsx b/src/main/webapp/src/components/Nav.jsx index f3693f2..5c37075 100644 --- a/src/main/webapp/src/components/Nav.jsx +++ b/src/main/webapp/src/components/Nav.jsx @@ -3,14 +3,16 @@ import {NavLink} from "react-router-dom"; import {useAuth} from "../hooks/useAuth.jsx"; import {login, logout} from "../utils/auth.js"; import {isClubAdmin} from "../utils/Tools.js"; +import {useTranslation} from "react-i18next"; export function Nav() { + const {t} = useTranslation(); return