From 0b60405c010de95c8269d9bb1888ca5b3b57db4f Mon Sep 17 00:00:00 2001 From: Baozier Date: Sun, 11 Aug 2024 18:47:17 -0400 Subject: [PATCH] Support locale switch in admin panel (#96) --- admin-panel/app/Setup.tsx | 23 +++++- admin-panel/i18n.ts | 2 +- admin-panel/middleware.ts | 2 +- admin-panel/package-lock.json | 62 +++++++------- admin-panel/package.json | 2 +- admin-panel/translations/fr.json | 96 ++++++++++++++++++++++ server/migrations/0001_creae_app_table.sql | 2 +- server/src/views/components/Field.tsx | 2 +- server/src/views/components/Layout.tsx | 2 +- 9 files changed, 154 insertions(+), 39 deletions(-) create mode 100644 admin-panel/translations/fr.json diff --git a/admin-panel/app/Setup.tsx b/admin-panel/app/Setup.tsx index 76e0b200..76ace8d4 100644 --- a/admin-panel/app/Setup.tsx +++ b/admin-panel/app/Setup.tsx @@ -22,6 +22,8 @@ import { routeTool, typeTool, } from 'tools' +const locale = localStorage.getItem('Locale') + const AuthSetup = ({ children }: PropsWithChildren) => { const t = useTranslations() @@ -71,7 +73,7 @@ const AuthSetup = ({ children }: PropsWithChildren) => { } if (!isAuthenticated) { - loginRedirect() + loginRedirect({ locale: locale ?? undefined }) return } @@ -99,6 +101,16 @@ const LayoutSetup = ({ children } : PropsWithChildren) => { const locale = useCurrentLocale() const { logoutRedirect } = useAuth() + useEffect( + () => { + localStorage.setItem( + 'Locale', + locale, + ) + }, + [locale], + ) + const handleLogout = () => { logoutRedirect({ postLogoutRedirectUri: process.env.NEXT_PUBLIC_CLIENT_URI }) } @@ -155,6 +167,13 @@ const LayoutSetup = ({ children } : PropsWithChildren) => { > {t('layout.scopes')} + + {locale === 'en' ? 'FR' : 'EN'} + { return ( diff --git a/admin-panel/i18n.ts b/admin-panel/i18n.ts index 8c847b68..67eea239 100644 --- a/admin-panel/i18n.ts +++ b/admin-panel/i18n.ts @@ -1,7 +1,7 @@ import { notFound } from 'next/navigation' import { getRequestConfig } from 'next-intl/server' -const locales = ['en'] +const locales = ['en', 'fr'] export default getRequestConfig(async ({ locale }: { locale:string}) => { if (!locales.includes(locale)) notFound() diff --git a/admin-panel/middleware.ts b/admin-panel/middleware.ts index fdac9a22..6a27053d 100644 --- a/admin-panel/middleware.ts +++ b/admin-panel/middleware.ts @@ -1,7 +1,7 @@ import createMiddleware from 'next-intl/middleware' export default createMiddleware({ - locales: ['en'], + locales: ['en', 'fr'], defaultLocale: 'en', }) diff --git a/admin-panel/package-lock.json b/admin-panel/package-lock.json index dbf02dda..bd694b37 100644 --- a/admin-panel/package-lock.json +++ b/admin-panel/package-lock.json @@ -7,7 +7,7 @@ "name": "admin-panel", "dependencies": { "@heroicons/react": "^2.1.4", - "@melody-auth/react": "*", + "@melody-auth/react": "^0.0.6", "@preact/signals-react": "^2.1.0", "classnames": "^2.5.1", "flowbite-react": "^0.10.1", @@ -58,12 +58,12 @@ } }, "node_modules/@floating-ui/dom": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.8.tgz", - "integrity": "sha512-kx62rP19VZ767Q653wsP1XZCGIirkE09E0QUGNYTM/ttbbQHqcGPdSfWFxUyyNLc/W6aoJRBajOSXhP6GXjC0Q==", + "version": "1.6.10", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.10.tgz", + "integrity": "sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==", "dependencies": { "@floating-ui/core": "^1.6.0", - "@floating-ui/utils": "^0.2.5" + "@floating-ui/utils": "^0.2.7" } }, "node_modules/@floating-ui/react": { @@ -93,9 +93,9 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.5.tgz", - "integrity": "sha512-sTcG+QZ6fdEUObICavU+aB3Mp8HY4n14wYHdxK4fXjPmv3PXZZeY5RaguJmGyeH/CJQhX3fqKUtS4qc1LoHwhQ==" + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.7.tgz", + "integrity": "sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==" }, "node_modules/@formatjs/ecma402-abstract": { "version": "2.0.0", @@ -218,8 +218,8 @@ }, "node_modules/@melody-auth/react": { "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@melody-auth/react/-/react-0.0.2.tgz", - "integrity": "sha512-oPXu8LofPeiKcLU8Bh/PJEZPcox2OnB6N9XGUnHK6Wfo7a0v5JNk3ueE2VNFgrItGdlPwhZ6bXgHt9MEdr1xUA==", + "resolved": "https://registry.npmjs.org/@melody-auth/react/-/react-0.0.6.tgz", + "integrity": "sha512-JpcIOWA5Uj9jfXOXVVREtrteQLRvMQeoG2wkkQQgRWEzn4fYvGs4bYmwVJeDXQWNY40dxnmQ7mF8XzqKdySbfw==", "peerDependencies": { "react": "^16.11.0 || ^17 || ^18" } @@ -415,18 +415,18 @@ } }, "node_modules/@preact/signals-core": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.7.0.tgz", - "integrity": "sha512-bEZLgmJGSBVP5PUPDowhPW3bVdMmp9Tr5OEl+SQK+8Tv9T7UsIfyN905cfkmmeqw8z4xp8T6zrl4M1uj9+HAfg==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.8.0.tgz", + "integrity": "sha512-OBvUsRZqNmjzCZXWLxkZfhcgT+Fk8DDcT/8vD6a1xhDemodyy87UJRJfASMuSD8FaAIeGgGm85ydXhm7lr4fyA==", "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" } }, "node_modules/@preact/signals-react": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@preact/signals-react/-/signals-react-2.1.0.tgz", - "integrity": "sha512-jWq2ldDWXdbKpg+aMGuOZfj9tS5JkVlGJ5hGNzNe1Zfe7RLFfvldBEfNe6ZT7KZddecAxKhyoxSsEypgbfx/Gw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@preact/signals-react/-/signals-react-2.2.0.tgz", + "integrity": "sha512-EPYlhXqqcOUxz2gTQGt4rtK6X7Jr04517DcJVZ4I5a7Gxy39haK24uFeVWtiU/tnEReRFcxpQN6poYra1jf68A==", "dependencies": { "@preact/signals-core": "^1.7.0", "use-sync-external-store": "^1.2.0" @@ -511,9 +511,9 @@ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==" }, "node_modules/@types/node": { - "version": "20.14.14", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.14.tgz", - "integrity": "sha512-d64f00982fS9YoOgJkAMolK7MN8Iq3TDdVjchbYHdEmjth/DHowx82GnoA+tVUAN+7vxfYUgAzi+JXbKNd2SDQ==", + "version": "20.14.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.15.tgz", + "integrity": "sha512-Fz1xDMCF/B00/tYSVMlmK7hVeLh7jE5f3B7X1/hmV0MJBwE27KlS7EvD/Yp+z1lm8mVhwV5w+n8jOZG8AfTlKw==", "dependencies": { "undici-types": "~5.26.4" } @@ -676,9 +676,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001646", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001646.tgz", - "integrity": "sha512-dRg00gudiBDDTmUhClSdv3hqRfpbOnU28IpI1T6PBTLWa+kOj0681C8uML3PifYfREuBrVjDGhL3adYpBT6spw==", + "version": "1.0.30001651", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", + "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==", "funding": [ { "type": "opencollective", @@ -926,9 +926,9 @@ } }, "node_modules/foreground-child": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", - "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -1544,9 +1544,9 @@ } }, "node_modules/postcss": { - "version": "8.4.40", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.40.tgz", - "integrity": "sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==", + "version": "8.4.41", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", + "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", "funding": [ { "type": "opencollective", @@ -2055,9 +2055,9 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.7.tgz", - "integrity": "sha512-rxWZbe87YJb4OcSopb7up2Ba4U82BoiSGUdoDr3Ydrg9ckxFS/YWsvhN323GMcddgU65QRy7JndC7ahhInhvlQ==", + "version": "3.4.9", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.9.tgz", + "integrity": "sha512-1SEOvRr6sSdV5IDf9iC+NU4dhwdqzF4zKKq3sAbasUWHEM6lsMhX+eNN5gkPx1BvLFEnZQEUFbXnGj8Qlp83Pg==", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", diff --git a/admin-panel/package.json b/admin-panel/package.json index 07b98fcc..c9ff3665 100644 --- a/admin-panel/package.json +++ b/admin-panel/package.json @@ -9,7 +9,7 @@ }, "dependencies": { "@heroicons/react": "^2.1.4", - "@melody-auth/react": "*", + "@melody-auth/react": "^0.0.6", "@preact/signals-react": "^2.1.0", "classnames": "^2.5.1", "flowbite-react": "^0.10.1", diff --git a/admin-panel/translations/fr.json b/admin-panel/translations/fr.json new file mode 100644 index 00000000..ec7431fc --- /dev/null +++ b/admin-panel/translations/fr.json @@ -0,0 +1,96 @@ +{ + "layout": { + "blocked": "Seul le super administrateur peut accéder à cette application.", + "brand": "Melody Auth", + "logout": "Déconnexion", + "users": "Gérer les utilisateurs", + "roles": "Gérer les rôles", + "apps": "Gérer les applications", + "scopes": "Gérer les portées", + "dashboard": "Tableau de bord" + }, + "common": { + "enable": "Activer", + "disable": "Désactiver", + "disabled": "Désactivé", + "active": "Actif", + "property": "Propriété", + "value": "Valeur", + "createdAt": "Créé le", + "updatedAt": "Mis à jour le", + "create": "Créer", + "options": "Options :", + "save": "Enregistrer", + "delete": "Supprimer", + "system": "Système", + "note": "Remarque", + "previous": "Précédent", + "next": "Suivant", + "status": "Statut", + "fieldIsRequired": "Ce champ est requis.", + "deleteConfirm": "Êtes-vous sûr de vouloir supprimer {item} ?", + "deleteConfirmBtn": "Supprimer" + }, + "dashboard": { + "configs": "Configurations système", + "configName": "Nom", + "configValue": "Valeur", + "configSeconds": "secondes", + "links": "Liens système", + "apiSwagger": "Swagger API S2S", + "systemInfo": "Informations système" + }, + "apps": { + "title": "Applications", + "app": "Application", + "new": "Créer une application", + "clientId": "ID Client", + "clientSecret": "Secret Client", + "name": "Nom", + "status": "Statut", + "type": "Type", + "scopes": "Portées", + "redirectUris": "URIs de redirection" + }, + "users": { + "title": "Utilisateurs", + "user": "Utilisateur", + "authId": "ID Auth", + "email": "Email", + "name": "Nom", + "locale": "Langue", + "status": "Statut", + "loginCount": "Nombre de connexions", + "emailVerified": "Email vérifié", + "firstName": "Prénom", + "lastName": "Nom", + "roles": "Rôles", + "resend": "Renvoyer l'email", + "sent": "Email envoyé", + "you": "Vous", + "consented": "Applications consenties", + "revokeConsent": "Révoquer", + "confirmRevoke": "Êtes-vous sûr de vouloir révoquer le consentement à {item} pour l'utilisateur actuel ?", + "noConsented": "Aucune application consentie pour l'instant.", + "noIP": "Pas d'IP", + "lockedIPs": "IPs verrouillées", + "unlock": "Déverrouiller tout" + }, + "roles": { + "title": "Rôles", + "role": "Rôle", + "name": "Nom", + "status": "Statut", + "new": "Créer un rôle" + }, + "scopes": { + "title": "Portées", + "scope": "Portée", + "name": "Nom", + "status": "Statut", + "type": "Type de client", + "new": "Créer une portée", + "locales": "Langues", + "localeNote": "Ceci sera affiché sur la page de consentement de l'application utilisateur." + } +} \ No newline at end of file diff --git a/server/migrations/0001_creae_app_table.sql b/server/migrations/0001_creae_app_table.sql index cf16ede8..4ff90ec9 100644 --- a/server/migrations/0001_creae_app_table.sql +++ b/server/migrations/0001_creae_app_table.sql @@ -110,5 +110,5 @@ CREATE TABLE [app] ( "isActive" integer DEFAULT 1 ); CREATE UNIQUE INDEX idx_unique_app_clientId ON app (clientId) WHERE deletedAt IS NULL; -INSERT INTO app ("name", "type", "redirectUris") values ("Admin Panel (SPA)", "spa", "http://localhost:3000/en/dashboard"); +INSERT INTO app ("name", "type", "redirectUris") values ("Admin Panel (SPA)", "spa", "http://localhost:3000/en/dashboard,http://localhost:3000/fr/dashboard"); INSERT INTO app ("name", "type") values ("Admin Panel (S2S)", "s2s"); diff --git a/server/src/views/components/Field.tsx b/server/src/views/components/Field.tsx index eb845c9a..52141924 100644 --- a/server/src/views/components/Field.tsx +++ b/server/src/views/components/Field.tsx @@ -33,7 +33,7 @@ const Field = ({ /> ) diff --git a/server/src/views/components/Layout.tsx b/server/src/views/components/Layout.tsx index 980a6ff7..e63339bf 100644 --- a/server/src/views/components/Layout.tsx +++ b/server/src/views/components/Layout.tsx @@ -62,7 +62,7 @@ const Layout = ({ .rounded-lg { border-radius: 16px; } .rounded-md { border-radius: 8px; } .w-full { width: 100%; } - .w-text { width: 300px } + .w-text { width: 240px; } .main { background-color: lightgray; height: 100vh;