diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index 20447bb..654a794 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -40,7 +40,6 @@ "close": "Close", "configureWaysToSignIn": "Configure ways to sign in", "confirm": "Confirm", - "confirmProfileDelete": "Confirm profile delete", "copied": "Copied", "copy": "Copy", "createATxtRecordInYourDnsConfigurationForTheFollowingHostname": "Create a txt record in your dns configuration for the following hostname", @@ -51,7 +50,6 @@ "currentRegisteredDomains": "Current registered domains", "currentSession": "Current session", "dark": "Dark", - "deleteYourProfile": "Delete your profile", "description": "Description", "device-activity": "Device activity", "deviceActivity": "Device activity", @@ -62,6 +60,9 @@ "doDeny": "Deny", "domainName": "Domain name", "domains": "Domains", + "domains-add-placeholder": "www.your-domain.com", + "domains-add-success": "{{domain}} has been added to organization. Please verify domain.", + "domains-verify": "Verify domain", "done": "Done", "doSave": "Save", "doSignOut": "Sign out", @@ -70,6 +71,8 @@ "editTheResource": "Share the resource - {{0}}", "email": "Email", "enterAVerificationCodeFromAuthenticatorApplication": "Enter a verification code from authenticator application", + "error-domain-invalid": "Domain is not valid", + "error-domain-already-present": "${domain} is already present for this org.", "error-empty": "Please specify value of '{{0}}'.", "error-invalid-blank": "Please specify value of '{{0}}'.", "error-invalid-date": "'{{0}}' is invalid date.", @@ -105,8 +108,14 @@ "insufficientPermissionsToViewOrganization": "Insufficient permissions to view organization", "internalApp": "Internal", "inUse": "In use", - "invitationInstructionsDescription": "Add a new member to the organization by entering their email and assigning them a role within the organization. An email will be sent to them with instructions on how to join.", - "invitationTitle": "Invite new member to {{0}}", + "insufficient-permissions": "Insufficient permissions to perform action.", + "invitation-email-placeholder": "for example, Thomas, thomas@domain.com", + "invitation-instructions-description": "Add a new member to the organization by entering their email and assigning them a role within the organization. An email will be sent to them with instructions on how to join.", + "invitation-missing-permission-title": "You lack the 'manage-invitations' role.", + "invitation-missing-permission-body": "Speak to an admin in order to be granted this role.", + "invitation-title": "Invite new member to {{0}}", + "invitation-toast-submit": "{{data.email}} is being sent an invitation.", + "invitation-toast-submit-success": "{{data.email}} has been sent an invitation.", "inviteNewMembers": "Invite new members", "inviteNewMembersOrRemoveMembersFromTheOrganization": "Invite new members or remove members from the organization", "ipAddress": "IP address", @@ -128,9 +137,12 @@ "localization": "Localization", "logo": "Logo", "logOut": "Log out", + "manage": "manage", "manageAccount": "Manage account", "manageLoginsThroughThirdPartyAccounts": "Manage logins through third party accounts", "manageYourUserProfileInformation": "Manage your user profile information", + "member-roles-missing-permission-title": "You lack the 'manage-roles' role.", + "member-roles-missing-permission-body": "Speak to an admin in order to be granted this role.", "members": "Members", "myResources": "My Resources", "name": "Name", @@ -141,6 +153,7 @@ "notSetUp": "{{0}} is not set up.", "offlineAccess": "Offline access", "options": "Options", + "org-details-stat-sso-active": "active SSO connections", "organization": "Organization", "organizations": "Organizations", "otp-display-name": "Authenticator application", @@ -151,6 +164,7 @@ "password": "My password", "passwordless": "no password", "path": "Path", + "pending": "pending", "permanentlyRemoveYourProfileAndAllOfItsContentsThisActionIsNotReversibleSoPleaseContinueWithCaution": "Permanently remove your profile and all of its contents this action is not reversible so please continue with caution", "permissionRequest": "Permission requests - {{0}}", "permissionRequests": "Permission requests", @@ -160,6 +174,13 @@ "personalInformation": "Personal information", "privacyPolicy": "Privacy policy", "profile": "Profile", + "profile-delete-title": "Delete your profile", + "profile-delete-confirm": "Confirm profile delete", + "profile-delete-write-to-confirm": "Write 'delete' to confirm.", + "profile-email-placeholder": "your@email.com", + "profile-localization-description": "Manage your localization (language).", + "profile-toast-success": "Profile updated successfully.", + "profile-toast-error": "Error during Profile update.", "provider": "Provider", "refreshPage": "Refresh the page", "remove": "Remove", @@ -186,8 +207,20 @@ "resourceSharedWith_other": "Resource is shared with <0>{{username}} and <1>{{other}} other users", "resourceSharedWith_zero": "This resource is not shared.", "returnToHomepage": "Return to homepage", + "role-toast-granted": "Granted {{roleName}} role to user.", + "role-toast-granted-error": "Error granting role {{roleName}} to user. Please try again.", + "role-toast-granted-all": "Granted all roles to user.", + "role-toast-granted-all-error": "Error granting all roles to user. Please try again.", + "role-toast-revoked": "Revoked {{roleName}} role from user.", + "role-toast-revoked-error": "Error revoking {{roleName}} role from user. Please try again.", + "role-toast-revoked-all": "Revoked all roles for user.", + "role-toast-revoked-all-error": "Error revoking all roles for user. Please try again.", + "role-toast-granted-filter": "Granted roles to user:", + "role-set": "Set roles:", + "role-section-header-title": "Edit roles of", "save": "Save", "searchMembers": "Search members", + "searchOrganizations": "Search Organizations", "securityKey": "Security key", "selectLocale": "Select Locale", "selectOne": "Select an option", @@ -267,11 +300,10 @@ "verificationPending": "Verification pending", "verified": "Verified", "verify": "Verify", - "verifyDomain": "Verify domain", + "view": "view", "viewLinkedDomainsAndVerifyDnsEntries": "View linked domains and verify dns entries", "viewOrganizationInformationChangeDisplayName": "View organization information change display name", "welcomeMessage": "Welcome to keycloak account management", - "writeDeleteToConfirm": "Write delete to confirm", "youAreTheSameUserAsThisUser": "This is your account! This is you!", "youLackTheManageRolesRole": "You lack the manage roles role" } diff --git a/public/locales/fr/translation.json b/public/locales/fr/translation.json new file mode 100644 index 0000000..c6779c3 --- /dev/null +++ b/public/locales/fr/translation.json @@ -0,0 +1,308 @@ +{ + "accept": "Accepter", + "accessGrantedOn": "Accès accordé le", + "accountSecurity": "Sécurité du compte", + "accountUpdatedError": "Impossible de mettre à jour le compte en raison d'erreurs de validation", + "accountUpdatedMessage": "Votre compte a été mis à jour.", + "add": "Ajouter", + "addANewDomainToThisOrganization": "Ajouter un nouveau domaine à l'organisation", + "addAnSsoProvider": "Gestion des fournisseurs SSO.", + "addDomain": "Ajouter un domaine", + "addNewDomain": "Ajouter un nouveau domaine", + "admin": "Admin", + "all": "Tout", + "allApplication": "Toutes les applications", + "allManage": "Tout gérer", + "allView": "Tout voir", + "anyChangesYouMakeWillHaveImmediateEffect": "Tout changement que vous effectuez aura un effet immédiat", + "application": "Application", + "applicationDetails": "Détails de l'application", + "applications": "Applications", + "applicationsIntroMessage": "Suivez et gérez les permissions de votre application pour accéder à votre compte", + "applicationType": "Type d'application", + "authenticatorApplication": "Application d'authentification", + "avatar": "Avatar", + "backToOrg": "Retour à l'organisation", + "backToSettings": "Retour aux paramètres", + "basic-authentication": "Authentification basique", + "basicAuthentication": "Authentification basique", + "cancel": "Annuler", + "choose": "Choisir...", + "client": "Client", + "clientNotFoundMessage": "*Client non trouvé.", + "client_account": "*Compte", + "client_account-console": "*Console du compte", + "client_admin-cli": "*CLI d'administration", + "client_broker": "*Broker", + "client_realm-management": "*Gestion du domaine", + "client_security-admin-console": "*Console d'administration", + "clients": "Clients", + "close": "Fermer", + "configureWaysToSignIn": "Configurer les méthodes de connexion", + "confirm": "Confirmer", + "copied": "Copié", + "copy": "Copier", + "createATxtRecordInYourDnsConfigurationForTheFollowingHostname": "Créez un enregistrement TXT dans votre configuration DNS avec le nom d'hôte suivant", + "created": "Créé", + "credentialCreatedAt": "<0>Créé {{date}}.", + "credentialsRemovingError": "Erreur lors de la suppression de {{0}}. Veuillez réessayer.", + "credentialsSuccessfullyRemoved": "{{0}} supprimé", + "currentRegisteredDomains": "Domaines actuellement enregistrés", + "currentSession": "Session actuelle", + "dark": "Sombre", + "description": "Description", + "device-activity": "Activité de l'appareil", + "deviceActivity": "Activité de l'appareil", + "directMembership": "Membre direct", + "displayName": "Nom affiché", + "doCancel": "Annuler", + "doDeny": "Refuser", + "domainName": "Nom du domaine", + "domains": "Domaines", + "domains-add-placeholder": "www.mon-domaine.com", + "domains-add-success": "{{domain}} a été ajouté à l'organization. Vous devez vérifier le domaine.", + "domains-verify": "Vérifier le domaine", + "done": "Fait", + "doSave": "Sauvegarder", + "doSignOut": "Se déconnecter", + "edit": "Modifier", + "editRoles": "Modifier les rôles", + "editTheResource": "Partager la ressource - {{0}}", + "email": "Email", + "enterAVerificationCodeFromAuthenticatorApplication": "Entrez un code de vérification de l'application d'authentification.", + "error-domain-invalid": "Domaine invalide.", + "error-domain-already-present": "existe déjà pour l'organisation.", + "error-empty": "Veuillez spécifier la valeur de '{{0}}'.", + "error-invalid-blank": "Veuillez spécifier la valeur de '{{0}}'.", + "error-invalid-date": "'{{0}}' est une date invalide.", + "error-invalid-email": "Adresse e-mail invalide.", + "error-invalid-length-too-long": "'{{0}}' doit avoir une longueur maximale de {{2}}.", + "error-invalid-length-too-short": "'{{0}}' doit avoir une longueur minimale de {{1}}.", + "error-invalid-length": "'{{0}}' doit avoir une longueur entre {{1}} et {{2}}.", + "error-invalid-number": "'{{0}}' est un nombre invalide", + "error-invalid-uri-fragment": "'{{0}}' est un fragment d'URL invalide.", + "error-invalid-uri-scheme": "'{{0}}' a un schéma d'URL invalide.", + "error-invalid-uri": "'{{0}}' est une URL invalide.", + "error-invalid-value": "'{{0}}' a une valeur invalide.", + "error-number-out-of-range-too-big": "'{{0}}' doit avoir une valeur maximale de {{2}}.", + "error-number-out-of-range-too-small": "'{{0}}' doit avoir une valeur minimale de {{1}}.", + "error-number-out-of-range": "'{{0}}' mdoit être un nombre entre {{1}} et {{2}}.", + "error-pattern-no-match": "'{{0}}' ne correspond pas au format requis.", + "error-person-name-invalid-character": "'{{0}}' contient un caractère invalide.", + "error-user-attribute-required": "Veuillez spécifier '{{0}}'.", + "error-username-invalid-character": "'{{0}}' contains invalid character.", + "errorRemovedMessage": "Impossible de supprimer {{userLabel}} en raison de : {{error}}", + "errorSignOutMessage": "Impossible de se déconnecter : {{error}}", + "expires": "Expiration", + "failedToCopy": "Échec de la copie", + "filterByName": "Filtrer par nom...", + "firstName": "Prénom", + "fullName": "{{givenName}} {{familyName}}", + "general": "Général", + "groupDescriptionLabel": "Voir les groupes auxquels vous êtes associé", + "groupLabel": "Groupes", + "groups": "Groupes", + "id": "ID", + "infoMessage": "En cliquant sur Retirer l'accès, vous retirerez les permissions accordées à cette application. Cette application n'utilisera plus vos informations.", + "insufficientPermissionsToViewOrganization": "Permissions insuffisantes pour voir l'organisation", + "internalApp": "Interne", + "inUse": "En cours d'utilisation", + "insufficient-permissions": "Permissions insuffisante pour réaliser cette action.", + "invitation-email-placeholder": "par exemple, Thomas, thomas@domaine.com", + "invitation-instructions-description": "Ajoutez un nouveau membre à l'organisation en entrant son email et en lui attribuant un rôle au sein de l'organisation. Un email leur sera envoyé avec des instructions pour rejoindre.", + "invitation-missing-permission-title": "Vous ne pouvez pas gérer les invitations.", + "invitation-missing-permission-body": "Contactez un administrateur pour obtenir les droits nécessaires.", + "invitation-title": "Inviter un nouveau membre à {{0}}", + "invitation-toast-submit": "Une invitation est envoyée à {{data.email}}.", + "invitation-toast-submit-success": "Une invitation a été envoyée à {{data.email}}.", + "inviteNewMembers": "Inviter des nouveaux membres", + "inviteNewMembersOrRemoveMembersFromTheOrganization": "Inviter de nouveaux membres ou retirer des membres de l'organisation.", + "ipAddress": "Adresse IP", + "label": "Étiquette", + "lastAccessed": "Dernier accès", + "lastAccessedOn": "Dernièrement accédé", + "lastName": "Nom", + "light": "Clair", + "link": "Lier le compte", + "linkAccount": "Lier le compte", + "linkedAccounts": "Comptes tiers liés", + "linkedAccountsIntroMessage": "Gérer les connexions via des comptes tiers.", + "linkedAccountsTitle": "Comptes liés", + "linkedEmpty": "Aucun compte lié", + "linkedLoginProviders": "Comptes liés", + "linkError": "Impossible de lier en raison de : {{error}}", + "localeUpdatedSuccessfully": "Localisation mise à jour avec succès", + "localeUpdateFailed": "Erreur lors de la mise à jour de la localisation.", + "localization": "Localisation", + "logo": "Logo", + "logOut": "Se déconnecter", + "manage": "gestion", + "manageAccount": "Gérer le compte", + "manageLoginsThroughThirdPartyAccounts": "Gérer les connexions via des comptes tiers", + "manageYourUserProfileInformation": "Gérer vos informations personnelles.", + "member-roles-missing-permission-title": "Vous ne pouvez pas gérer les roles.", + "member-roles-missing-permission-body": "Contactez un administrateur pour obtenir les droits nécessaires.", + "members": "Membres", + "myResources": "Mes Ressources", + "name": "Nom", + "noGroups": "Aucun groupe", + "noGroupsText": "Vous n'êtes inscrit dans aucun groupe", + "none": "Aucun", + "notInUse": "Pas en utilisation", + "notSetUp": "{{0}} n'est pas configuré.", + "offlineAccess": "Accès hors ligne", + "options": "Options", + "org-details-stat-sso-active": "SSO actifs", + "organization": "Organisation", + "organizations": "Organisations", + "otp-display-name": "Application d'authentification", + "otp-help-text": "Saisissze le code de vérification de l'application d'authentification.", + "password-display-name": "Mot de passe", + "password-help-text": "Connectez-vous en saisissant votre mot de passe.", + "password-less-title": "Connexion avec clé de sécurité", + "password": "Mon mot de passe", + "passwordless": "Sans mot de passe", + "path": "Chemin", + "pending": "En attente", + "permanentlyRemoveYourProfileAndAllOfItsContentsThisActionIsNotReversibleSoPleaseContinueWithCaution": "Supprimez définitivement votre compte et tout son contenu, cette action est irréversible, veuillez donc continuer avec prudence.", + "permissionRequest": "Demandes de permission - {{0}}", + "permissionRequests": "Demandes de permission", + "permissions": "Permissions", + "personalInfo": "Informations personnelles", + "personalInfoDescription": "Gérez vos informations", + "personalInformation": "Informations personnelles", + "privacyPolicy": "Politique de confidentialité", + "profile": "Profil", + "profile-email-placeholder": "votre@email.com", + "profile-localization-description": "Gérer votre localisation (langue).", + "profile-toast-success": "Compte modifié avec succès.", + "profile-toast-error": "Un problème est survenu.", + "profile-delete-title": "Supprimer votre compte", + "profile-delete-confirm": "Confirmer la suppression du compte", + "profile-delete-write-to-confirm": "Écrivez 'supprimer' pour confirmer.", + "provider": "Fournisseur", + "refreshPage": "Rafraîchir la page", + "remove": "Retirer", + "removeButton": "Retirer l'accès", + "removeConsentError": "Impossible de retirer le consentement en raison de: {{error}}", + "removeConsentSuccess": "Consentement retiré avec succès", + "removeCred": "Retirer {{0}}", + "removeCredAriaLabel": "Retirer les informations d'identification", + "removeDomain": "Retirer", + "removeDomainError": "{{0}} n'a pas été retiré de l'organisation. ({{1}})", + "removeDomainQuestion": "Retirer ce domaine de l'organisation est irréversible et nécessitera de l'ajouter à nouveau manuellement.", + "removeDomainSuccess": "{{0}} a été retiré avec succès de l'organisation.", + "removeDomainTitle": "Retirer {{0}} de l'organisation.", + "removeModalMessage": "Cela retirera la permission d'accès actuellement accordée pour {{0}}. Vous devrez accorder à nouveau l'accès si vous souhaitez utiliser cette application.", + "removeModalTitle": "Retirer l'accès", + "requestor": "Demandeur", + "required": "Requis", + "reset": "Réinitialiser", + "resourceAlreadyShared": "La ressource est déjà partagée avec cet utilisateur.", + "resourceIntroMessage": "Partagez vos ressources parmi les membres de l'équipe", + "resourceName": "Nom de la ressource", + "resources": "Ressources", + "resourceSharedWith_one": "La ressource est partagée avec <0>{{username}}", + "resourceSharedWith_other": "La ressource est partagée avec <0>{{username}} et <1>{{other}} autres utilisateurs", + "resourceSharedWith_zero": "Cette ressource n'est pas partagée.", + "returnToHomepage": "Retourner à la page d'accueil", + "role-toast-granted": "Rôle {{roleName}} accordé à l'utilisateur.", + "role-toast-granted-error": "Une erreur est survenue lors de l'assignation du rôle {{roleName}}, Veuillez réessayer.", + "role-toast-granted-all": "Tous les rôles ont été assignés à l'utilisateur.", + "role-toast-granted-all-error": "Une erreur est survenue lors de l'assignation de tous les rôles. Veuillez réessayer.", + "role-toast-revoked": "Rôle {{roleName}} retiré à l'utilisateur.", + "role-toast-revoked-error": "Une erreur est survenue lors de la dissociation du rôle {{roleName}}, Veuillez réessayer.", + "role-toast-revoked-all": "Tous les rôles ont été retirés à l'utilisateur.", + "role-toast-revoked-all-error": "Une erreur est survenue lors de la dissociation de tous les rôles, Veuillez réessayer.", + "role-toast-granted-filter": "Roles assignés à l'utilisateur:", + "role-set": "Assigner les rôles:", + "role-section-header-title": "Modifier les rôles de", + "save": "Sauvegarder", + "searchMembers": "Chercher des membres", + "searchOrganizations": "Chercher des Organisations", + "securityKey": "Clé de sécurité", + "selectLocale": "Sélectionner la langue", + "selectOne": "Sélectionner une option", + "sendInvitation": "Envoyer une invitation", + "settings": "Paramètres", + "setupAssociatedDomainsAndVerifyThemToEnsureFullSecurity": "Configurer et vérifier les domaines associés pour assurer une sécurité complète.", + "setUpAuthenticator": "Configurer l'authentificateur", + "setupDomains": "Configurer des domaines", + "setUpNew": "Configurer {{0}}", + "setUpSecurityKey": "Configurer la clé de sécurité", + "setupSso": "Configurer un fournisseur SSO", + "setupSsoConnectionsAsNecessaryForThisOrganization": "Configurer les fournisseurs SSO de l'organisation.", + "share": "Partager", + "sharedWithMe": "Partagé avec moi", + "shareError": "Impossible de partager la ressource en raison de : {{error}}", + "shareSuccess": "Ressource partagée avec succès.", + "shareTheResource": "Partager la ressource - {{0}}", + "shareUser": "Ajoutez des utilisateurs pour partager votre ressource", + "shareWith": "Partager avec ", + "signedInDevices": "Appareils connectés", + "signedInDevicesExplanation": "Déconnectez-vous de tout appareil inconnu.", + "signedOutSession": "Déconnecté {{0}}/{{1}}", + "signInByEnteringYourPassword": "Connexion avec un mot de passe", + "signingIn": "Connexion", + "signingInDescription": "Configurer les méthodes de connexion.", + "signOut": "Se déconnecter", + "signOutAllDevices": "Déconnecter tous les appareils", + "signOutAllDevicesWarning": "Cette action déconnectera tous les appareils qui se sont connectés à votre compte, y compris l'appareil que vous utilisez actuellement.", + "signOutOfAnyUnfamiliarDevices": "Déconnectez-vous de tout appareil inconnu", + "signOutSession": "Déconnecter la session", + "signOutThisSessionQuestion": "Veuillez confirmer que vous souhaitez vous déconnecter de la session sur l'autre appareil.", + "signOutWarning": "Déconnecter la session ?", + "socialLogin": "Social login", + "somethingWentWrong": "Quelque chose s'est mal passé", + "somethingWentWrongDescription": "Désolé, une erreur inattendue s'est produite.", + "speakToAnAdminInOrderToBeGrantedThisRole": "Contactez un administrateur pour obtenir ce rôle.", + "sso": "SSO", + "started": "Commencé", + "status": "Statut", + "stopUsingCred": "Arrêter d'utiliser {{0}}?", + "successRemovedMessage": "{{userLabel}} a été retiré.", + "system": "Système", + "systemDefined": "Défini par le système", + "termsOfService": "Conditions de service", + "theme": "Thème", + "thirdPartyApp": "Tiers", + "thisActionWillSignOutAllTheDevicesThatHaveSignedInToYourAccountIncludingTheCurrentDeviceYouAreUsing": "Cette action déconnectera tous les appareils qui se sont connectés à votre compte, y compris l'appareil que vous utilisez actuellement.", + "tryAgain": "Réessayer", + "two-factor": "Authentification à deux facteurs", + "twoFactorAuthentication": "Authentification à deux facteurs", + "unknownOperatingSystem": "Système d'exploitation inconnu", + "unknownUser": "Anonyme", + "unLink": "Dissocier le compte", + "unlinkAccount": "Dissocier le compte", + "unlinkedEmpty": "Pas de compte dissocié", + "unlinkedLoginProviders": "Comptes dissociés", + "unLinkError": "Impossible de dissocier en raison de : {{error}}", + "unLinkSuccess": "Compte dissocié avec succès", + "unShare": "Ne plus partager l'ensemble", + "unShareError": "Impossible de ne plus partager la ressource en raison de : {{error}}", + "unShareSuccess": "Partage supprimé avec succès.", + "update": "Mettre à jour", + "updateCredAriaLabel": "Mettre à jour les informations d'identification", + "updateError": "Impossible de mettre à jour la ressource en raison de : {{error}}", + "updateLocale": "Modifier", + "updateOrganization": "Modifier l'organisation", + "updateSuccess": "Ressource mise à jour avec succès.", + "user": "Utilisateur", + "username": "Nom d'utilisateur", + "usernamePlaceholder": "Nom d'utilisateur ou mail.", + "usernameEmailSame": "Le nom d'utilisateur est identique à l'email.", + "useTheFollowingDetailsToVerifyYourDomain": "Utilisez les informations suivantes pour vérifier votre domaine.", + "useThisCodeForTheValueOfTheTxtRecord": "Utilisez ce code pour la valeur de l'enregistrement TXT", + "useYourSecurityKeyForPasswordlessSignIn": "Utilisez votre clé de sécurité pour une connexion sans mot de passe.", + "useYourSecurityKeyToSignIn": "UUtilisez votre clé de sécurité pour vous connecter", + "validated": "Validé", + "verificationPending": "Vérification en attente", + "verified": "Vérifié", + "verify": "Vérifier", + "view": "lecture", + "viewLinkedDomainsAndVerifyDnsEntries": "Domaines liés et entrées DNS.", + "viewOrganizationInformationChangeDisplayName": "Détails de l'organisation.", + "welcomeMessage": "Bienvenue dans la gestion de compte keycloak", + "youAreTheSameUserAsThisUser": "C'est votre compte ! C'est vous !", + "youLackTheManageRolesRole": "Vous manquez le rôle de gestion des rôles" +} diff --git a/src/App.tsx b/src/App.tsx index 2a8b430..c3f465b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,7 +1,29 @@ import Layout from "components/layouts/layout"; +import { setLanguage } from "i18n"; import { Outlet } from "react-router-dom"; +import { useGetAccountQuery } from "store/apis/profile"; +import { config } from "config"; +import { useEffect } from "react"; + +const { supportedLocales, realm } = config.env; function App() { + const hasLocale = (locale: string): boolean => locale in supportedLocales; + + const { data: account } = useGetAccountQuery({ + userProfileMetadata: true, + realm, + }); + useEffect(() => { + // load language (after login) + if ( + account?.attributes?.locale && + hasLocale(account?.attributes?.locale[0]) + ) { + setLanguage(account?.attributes?.locale[0]); + } + }, [account]); + return ( diff --git a/src/i18n.ts b/src/i18n.ts index 1f8009c..0eec725 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -3,16 +3,24 @@ import HttpBackend from "i18next-http-backend"; import { initReactI18next } from "react-i18next"; import { joinPath } from "services/join-path"; -const DEFAULT_LOCALE = "en"; +const ENGLISH_LOCALE = "en"; +const FRENCH_LOCAL = "fr"; const DEFAULT_NAMESPACE = "translation"; +// use localStorage to avoid losing language on page reload +const locale = localStorage.getItem("locale"); +if (!locale) { + localStorage.setItem("locale", ENGLISH_LOCALE); +} + i18n .use(HttpBackend) .use(initReactI18next) .init({ + lng: locale || ENGLISH_LOCALE, returnNull: false, defaultNS: DEFAULT_NAMESPACE, - fallbackLng: DEFAULT_LOCALE, + fallbackLng: [ENGLISH_LOCALE, FRENCH_LOCAL], ns: [DEFAULT_NAMESPACE], interpolation: { escapeValue: false, @@ -22,4 +30,11 @@ i18n }, }); +export const setLanguage = (lang: string) => { + i18n.changeLanguage(lang).then(() => { + i18n.options.lng = lang; + }); + localStorage.setItem("locale", lang); +}; + export default i18n; diff --git a/src/pages/invitation/new.tsx b/src/pages/invitation/new.tsx index b01fdae..d6d0636 100644 --- a/src/pages/invitation/new.tsx +++ b/src/pages/invitation/new.tsx @@ -57,7 +57,7 @@ const NewInvitation = () => { const onSubmit = async (data) => { if (data.email) { P2Toast({ - title: `${data.email} is being sent an invitation.`, + title: t("invitation-toast-submit", { data }), information: true, }); await addOrganizationInvitation({ @@ -74,7 +74,7 @@ const NewInvitation = () => { .then(() => { P2Toast({ success: true, - title: `${data.email} has been sent an invitation.`, + title: t("invitation-toast-submit-success", { data }), }); reset(); return navigate(`/organizations/${orgId}/details`); @@ -84,7 +84,7 @@ const NewInvitation = () => { error: true, title: e.status === 401 - ? "Insufficient roles to perform action." + ? t("insufficient-permissions") : e.data.error, }); }); @@ -98,8 +98,8 @@ const NewInvitation = () => { return (
{ {!hasManageInvitationsRole && (
@@ -133,7 +133,7 @@ const NewInvitation = () => { error={errors.email} inputArgs={{ type: "email", - placeholder: "you@email.com", + placeholder: t("invitation-email-placeholder"), required: true, disabled: !hasManageInvitationsRole, }} diff --git a/src/pages/member/roles.tsx b/src/pages/member/roles.tsx index 8ea3980..d4d927c 100644 --- a/src/pages/member/roles.tsx +++ b/src/pages/member/roles.tsx @@ -85,13 +85,13 @@ const Roles = () => { refetchRoles(); P2Toast({ success: true, - title: `Granted ${roleName} role to user.`, + title: t("role-toast-granted", { roleName }), }); }) .catch(() => P2Toast({ error: true, - title: `Error granting ${roleName} role to user. Please try again.`, + title: t("role-toast-granted-error", { roleName }), }) ) .finally(() => { @@ -109,13 +109,13 @@ const Roles = () => { refetchRoles(); P2Toast({ success: true, - title: `Revoked ${roleName} role user.`, + title: t("role-toast-revoked", { roleName }), }); }) .catch(() => P2Toast({ error: true, - title: `Error revoking ${roleName} role to user. Please try again.`, + title: t("role-toast-revoked-error", { roleName }), }) ) .finally(() => { @@ -140,13 +140,13 @@ const Roles = () => { .then(() => { P2Toast({ success: true, - title: `Granted all roles to user.`, + title: t("role-toast-granted-all"), }); }) .catch(() => { P2Toast({ error: true, - title: `Error granting all roles to user. Please try again.`, + title: t("role-toast-granted-all-error"), }); }) .finally(() => { @@ -171,13 +171,13 @@ const Roles = () => { .then(() => { P2Toast({ success: true, - title: `Revoked all roles for user.`, + title: t("role-toast-revoked-all"), }); }) .catch(() => { P2Toast({ error: true, - title: `Error revoking all roles for user. Please try again.`, + title: t("role-toast-revoked-all-error"), }); }) .finally(() => { @@ -205,13 +205,13 @@ const Roles = () => { .then(() => { P2Toast({ success: true, - title: `Granted ${filter} roles to user.`, + title: `${t("role-toast-granted-filter")} ${t(filter)}.`, }); }) .catch(() => { P2Toast({ error: true, - title: `Error granting ${filter} roles to user. Please try again.`, + title: t("role-toast-granted-error"), }); }) .finally(() => { @@ -228,7 +228,7 @@ const Roles = () => { return (
{ {!hasManageRolesRole && (
)}
-
Set roles:
+
{t("role-set")}
+ ); const removeDomainBtn = ( diff --git a/src/pages/profile-delete/index.tsx b/src/pages/profile-delete/index.tsx index 034bfb5..b773ed4 100644 --- a/src/pages/profile-delete/index.tsx +++ b/src/pages/profile-delete/index.tsx @@ -27,7 +27,7 @@ const ProfileDelete = () => { const { t } = useTranslation(); const { register, watch, handleSubmit } = useForm(); const watchConfirmDelete = watch("delete"); - const confirmDelete = toLower(watchConfirmDelete) !== "delete"; + const confirmDelete = ["delete", "supprimer"].includes(toLower(watchConfirmDelete)); const onSubmit = () => { if (confirmDelete) { @@ -39,7 +39,7 @@ const ProfileDelete = () => {
{
-
diff --git a/src/pages/profile/components/delete.tsx b/src/pages/profile/components/delete.tsx index 3247199..14b36cf 100644 --- a/src/pages/profile/components/delete.tsx +++ b/src/pages/profile/components/delete.tsx @@ -11,14 +11,14 @@ const DeleteProfile = () => {
- +
diff --git a/src/pages/profile/components/internationalization.tsx b/src/pages/profile/components/internationalization.tsx index c924948..5030705 100644 --- a/src/pages/profile/components/internationalization.tsx +++ b/src/pages/profile/components/internationalization.tsx @@ -10,6 +10,7 @@ import { useTranslation } from "react-i18next"; import P2Toast from "components/utils/toast"; import Dropdown from "components/elements/forms/dropdown/hui-dropdown"; import { first } from "lodash"; +import { setLanguage } from "../../../i18n"; const { realm, supportedLocales } = config.env; @@ -29,6 +30,7 @@ const Internationalization = () => { id: string; name: string; }>(localeOptions[0]); + const { data: account, isLoading: isLoadingAccount } = useGetAccountQuery({ userProfileMetadata: true, realm, @@ -39,13 +41,15 @@ const Internationalization = () => { (l) => l.id === first(account?.attributes?.locale) ); if (hasLocale) { - setSelectedLocale( + const locale = localeOptions[ localeOptions.findIndex( (l) => l.id === first(account?.attributes?.locale) ) - ] - ); + ]; + + setSelectedLocale(locale); + setLanguage(locale.id); } }, [account]); @@ -93,7 +97,7 @@ const Internationalization = () => {
diff --git a/src/pages/profile/components/profile.tsx b/src/pages/profile/components/profile.tsx index 8824de6..0e6ca63 100644 --- a/src/pages/profile/components/profile.tsx +++ b/src/pages/profile/components/profile.tsx @@ -59,13 +59,13 @@ const ProfileData = () => { .then(() => { P2Toast({ success: true, - title: `Profile updated successfully.`, + title: t("profile-toast-success"), }); }) .catch((err) => { return P2Toast({ error: true, - title: `Error during Profile update. ${err.data.error}`, + title: `${t("profile-toast-error")} ${err.data.error}`, }); }); }; @@ -74,8 +74,8 @@ const ProfileData = () => { <>
@@ -92,9 +92,9 @@ const ProfileData = () => { }} inputArgs={{ disabled: isLoadingAccount || !featureFlags.editUsernameAllowed, - placeholder: "your@email.com", + placeholder: t("profile-email-placeholder"), type: "email", - title: "Username is the same as email.", + title: t("usernameEmailSame"), }} error={errors.username} helpText={t("usernameEmailSame")} @@ -128,7 +128,7 @@ const ProfileData = () => { inputArgs={{ disabled: isLoadingAccount || !featureFlags.updateEmailFeatureEnabled, - placeholder: "your@email.com", + placeholder: t("profile-email-placeholder"), type: "email", }} error={errors.email}