diff --git a/gui/rpk-gui/public/locales/DE/common.json b/gui/rpk-gui/public/locales/DE/common.json new file mode 100644 index 0000000..dc4cb0f --- /dev/null +++ b/gui/rpk-gui/public/locales/DE/common.json @@ -0,0 +1,164 @@ +{ + "pages": { + "login": { + "title": "Melden Sie sich bei Ihrem Konto an", + "signin": "Einloggen", + "signup": "Anmelden", + "divider": "oder", + "fields": { + "email": "Email", + "password": "Passwort" + }, + "oauth": { + "google": "Einloggen mit Google", + "discord": "Einloggen mit Discord" + }, + "errors": { + "validEmail": "Ungültige E-Mail-Adresse", + "requiredEmail": "E-Mail ist erforderlich", + "requiredPassword": "Passwort wird benötigt" + }, + "buttons": { + "submit": "Anmeldung", + "forgotPassword": "Passwort vergessen?", + "noAccount": "Sie haben kein Konto?", + "rememberMe": "Erinnere dich an mich" + } + }, + "forgotPassword": { + "title": "Haben Sie Ihr Passwort vergessen?", + "fields": { + "email": "Email" + }, + "errors": { + "validEmail": "Ungültige E-Mail-Adresse", + "requiredEmail": "E-Mail ist erforderlich" + }, + "buttons": { + "submit": "Anweisungen zum Zurücksetzen senden" + } + }, + "register": { + "title": "Registrieren Sie sich für Ihr Konto", + "fields": { + "email": "Email", + "password": "Passwort" + }, + "errors": { + "validEmail": "Ungültige E-Mail-Adresse", + "requiredEmail": "E-Mail ist erforderlich", + "requiredPassword": "Passwort wird benötigt" + }, + "buttons": { + "submit": "Registrieren", + "haveAccount": "Ein Konto haben?" + } + }, + "updatePassword": { + "title": "Kennwort aktualisieren", + "fields": { + "password": "Neues Passwort", + "confirmPassword": "Bestätige neues Passwort" + }, + "errors": { + "confirmPasswordNotMatch": "Passwörter stimmen nicht überein", + "requiredPassword": "Passwort wird benötigt", + "requiredConfirmPassword": "Das Feld „Passwort bestätigen“ ist erforderlich" + }, + "buttons": { + "submit": "Aktualisieren" + } + }, + "error": { + "info": "Sie haben vergessen, {{action}} component zu {{resource}} hinzufügen.", + "404": "Leider existiert diese Seite nicht.", + "resource404": "Haben Sie die {{resource}} resource erstellt?", + "backHome": "Zurück" + } + }, + "actions": { + "list": "Aufführen", + "create": "Erstellen", + "edit": "Bearbeiten", + "show": "Zeigen" + }, + "buttons": { + "create": "Erstellen", + "save": "Speichern", + "logout": "Abmelden", + "delete": "Löschen", + "edit": "Bearbeiten", + "cancel": "Abbrechen", + "confirm": "Sicher?", + "filter": "Filter", + "clear": "Löschen", + "refresh": "Erneuern", + "show": "Zeigen", + "undo": "Undo", + "import": "Importieren", + "clone": "Klon", + "notAccessTitle": "Sie haben keine zugriffsberechtigung" + }, + "warnWhenUnsavedChanges": "Nicht gespeicherte Änderungen werden nicht übernommen.", + "notifications": { + "success": "Erfolg", + "error": "Fehler (status code: {{statusCode}})", + "undoable": "Sie haben {{seconds}} Sekunden Zeit für Undo.", + "createSuccess": "{{resource}} erfolgreich erstellt.", + "createError": "Fehler beim Erstellen {{resource}} (status code: {{statusCode}})", + "deleteSuccess": "{{resource}} erfolgreich gelöscht.", + "deleteError": "Fehler beim Löschen {{resource}} (status code: {{statusCode}})", + "editSuccess": "{{resource}} erfolgreich bearbeitet.", + "editError": "Fehler beim Bearbeiten {{resource}} (status code: {{statusCode}})", + "importProgress": "{{processed}}/{{total}} importiert" + }, + "loading": "Wird geladen", + "tags": { + "clone": "Klon" + }, + "dashboard": { + "title": "Dashboard" + }, + "posts": { + "posts": "Einträge", + "fields": { + "id": "Id", + "title": "Titel", + "category": "Kategorie", + "status": { + "title": "Status", + "published": "Veröffentlicht", + "draft": "Draft", + "rejected": "Abgelehnt" + }, + "content": "Inhalh", + "createdAt": "Erstellt am" + }, + "titles": { + "create": "Erstellen", + "edit": "Bearbeiten", + "list": "Einträge", + "show": "Eintrag zeigen" + } + }, + "table": { + "actions": "Aktionen" + }, + "documentTitle": { + "default": "refine", + "suffix": " | Refine", + "post": { + "list": "Beiträge | Refine", + "show": "#{{id}} Beitrag anzeigen | Refine", + "edit": "#{{id}} Beitrag bearbeiten | Refine", + "create": "Neuen Beitrag erstellen | Refine", + "clone": "#{{id}} Beitrag klonen | Refine" + } + }, + "autoSave": { + "success": "gespeichert", + "error": "fehler beim automatischen speichern", + "loading": "speichern...", + "idle": "warten auf anderungen" + } +} diff --git a/gui/rpk-gui/public/locales/EN/common.json b/gui/rpk-gui/public/locales/EN/common.json new file mode 100644 index 0000000..6ad95a6 --- /dev/null +++ b/gui/rpk-gui/public/locales/EN/common.json @@ -0,0 +1,164 @@ +{ + "pages": { + "login": { + "title": "Sign in to your account", + "signin": "Sign in", + "signup": "Sign up", + "divider": "or", + "fields": { + "email": "Email", + "password": "Password" + }, + "oauth": { + "google": "Sign in with Google", + "discord": "Sign in with Discord" + }, + "errors": { + "validEmail": "Invalid email address", + "requiredEmail": "Email is required", + "requiredPassword": "Password is required" + }, + "buttons": { + "submit": "Login", + "forgotPassword": "Forgot password?", + "noAccount": "Don’t have an account?", + "rememberMe": "Remember me" + } + }, + "forgotPassword": { + "title": "Forgot your password?", + "fields": { + "email": "Email" + }, + "errors": { + "validEmail": "Invalid email address", + "requiredEmail": "Email is required" + }, + "buttons": { + "submit": "Send reset instructions" + } + }, + "register": { + "title": "Sign up for your account", + "fields": { + "email": "Email", + "password": "Password" + }, + "errors": { + "validEmail": "Invalid email address", + "requiredEmail": "Email is required", + "requiredPassword": "Password is required" + }, + "buttons": { + "submit": "Register", + "haveAccount": "Have an account?" + } + }, + "updatePassword": { + "title": "Update password", + "fields": { + "password": "New Password", + "confirmPassword": "Confirm new password" + }, + "errors": { + "confirmPasswordNotMatch": "Passwords do not match", + "requiredPassword": "Password required", + "requiredConfirmPassword": "Confirm password is required" + }, + "buttons": { + "submit": "Update" + } + }, + "error": { + "info": "You may have forgotten to add the {{action}} component to {{resource}} resource.", + "404": "Sorry, the page you visited does not exist.", + "resource404": "Are you sure you have created the {{resource}} resource.", + "backHome": "Back Home" + } + }, + "actions": { + "list": "List", + "create": "Create", + "edit": "Edit", + "show": "Show" + }, + "buttons": { + "create": "Create", + "save": "Save", + "logout": "Logout", + "delete": "Delete", + "edit": "Edit", + "cancel": "Cancel", + "confirm": "Are you sure?", + "filter": "Filter", + "clear": "Clear", + "refresh": "Refresh", + "show": "Show", + "undo": "Undo", + "import": "Import", + "clone": "Clone", + "notAccessTitle": "You don't have permission to access" + }, + "warnWhenUnsavedChanges": "Are you sure you want to leave? You have unsaved changes.", + "notifications": { + "success": "Successful", + "error": "Error (status code: {{statusCode}})", + "undoable": "You have {{seconds}} seconds to undo", + "createSuccess": "Successfully created {{resource}}", + "createError": "There was an error creating {{resource}} (status code: {{statusCode}})", + "deleteSuccess": "Successfully deleted {{resource}}", + "deleteError": "Error when deleting {{resource}} (status code: {{statusCode}})", + "editSuccess": "Successfully edited {{resource}}", + "editError": "Error when editing {{resource}} (status code: {{statusCode}})", + "importProgress": "Importing: {{processed}}/{{total}}" + }, + "loading": "Loading", + "tags": { + "clone": "Clone" + }, + "dashboard": { + "title": "Dashboard" + }, + "posts": { + "posts": "Posts", + "fields": { + "id": "Id", + "title": "Title", + "category": "Category", + "status": { + "title": "Status", + "published": "Published", + "draft": "Draft", + "rejected": "Rejected" + }, + "content": "Content", + "createdAt": "Created At" + }, + "titles": { + "create": "Create Post", + "edit": "Edit Post", + "list": "Posts", + "show": "Show Post" + } + }, + "table": { + "actions": "Actions" + }, + "documentTitle": { + "default": "refine", + "suffix": " | Refine", + "post": { + "list": "Posts | Refine", + "show": "#{{id}} Show Post | Refine", + "edit": "#{{id}} Edit Post | Refine", + "create": "Create new Post | Refine", + "clone": "#{{id}} Clone Post | Refine" + } + }, + "autoSave": { + "success": "saved", + "error": "auto save failure", + "loading": "saving...", + "idle": "waiting for changes" + } +} diff --git a/gui/rpk-gui/public/locales/FR/common.json b/gui/rpk-gui/public/locales/FR/common.json new file mode 100644 index 0000000..4897684 --- /dev/null +++ b/gui/rpk-gui/public/locales/FR/common.json @@ -0,0 +1,164 @@ +{ + "pages": { + "login": { + "title": "Authentification", + "signin": "S'authentifier", + "signup": "Créer un compte", + "divider": "ou", + "fields": { + "email": "Email", + "password": "Mot de passe" + }, + "oauth": { + "google": "S'authentifier avec Google", + "discord": "S'authentifier avec Discord" + }, + "errors": { + "validEmail": "Email invalide", + "requiredEmail": "l'Email est obligatoire", + "requiredPassword": "Le mot de passe est obligatoire" + }, + "buttons": { + "submit": "S'authentifier", + "forgotPassword": "Mot de passe oublié?", + "noAccount": "Vous n'avec pas de compte?", + "rememberMe": "Se souvenir de moi" + } + }, + "forgotPassword": { + "title": "Mot de passe oublié?", + "fields": { + "email": "Email" + }, + "errors": { + "validEmail": "mail invalide", + "requiredEmail": "l'Email est obligatoire" + }, + "buttons": { + "submit": "Envoyer les instructions de récupération" + } + }, + "register": { + "title": "Création de compte", + "fields": { + "email": "Email", + "password": "Mot de passe" + }, + "errors": { + "validEmail": "Email invalide", + "requiredEmail": "l'Email est obligatoire", + "requiredPassword": "Le mot de passe est obligatoire" + }, + "buttons": { + "submit": "Créer un compte", + "haveAccount": "Vous avez déjà un compte?" + } + }, + "updatePassword": { + "title": "Mise à jour du mot de passe", + "fields": { + "password": "Nouveau mot de passe", + "confirmPassword": "Confirmation" + }, + "errors": { + "confirmPasswordNotMatch": "Les mots de passe ne correspondent pas", + "requiredPassword": "Le mot de passe est obligatoire", + "requiredConfirmPassword": "Vous devez confirmer votre mot de passe" + }, + "buttons": { + "submit": "Mettre à jour" + } + }, + "error": { + "info": "Il manque l'action {{action}} component à la ressource {{resource}} .", + "404": "Cette page n'existe pas.", + "resource404": "Cette page n'existe pas.", + "backHome": "Retour à l'accueil" + } + }, + "actions": { + "list": "Liste", + "create": "Création", + "edit": "Édtion", + "show": "Voir" + }, + "buttons": { + "create": "Créer", + "save": "Sauvegarder", + "logout": "Se déconnecter", + "delete": "Supprimer", + "edit": "Modifier", + "cancel": "Annuler", + "confirm": "Êtes vous sur?", + "filter": "Filtrer", + "clear": "Effacer", + "refresh": "Rafraîchir", + "show": "Voir", + "undo": "Annuler", + "import": "Importer", + "clone": "Cloner", + "notAccessTitle": "Vous n'avez pas la permission d'accéder à cette ressource" + }, + "warnWhenUnsavedChanges": "Êtes vous sur de vouloir quitter la page? Vous avez des modification non sauvegardées.", + "notifications": { + "success": "Succès", + "error": "Erreur (Code de statut: {{statusCode}})", + "undoable": "Vous avez {{seconds}} secondes à annuler", + "createSuccess": "Création de {{resource}} réussie", + "createError": "Erreur pendant la création de {{resource}} (Code de statut: {{statusCode}})", + "deleteSuccess": "Suppression de {{resource}} réussie", + "deleteError": "Erreur pendant la suppression de {{resource}} (Code de statut: {{statusCode}})", + "editSuccess": "Modification de {{resource}} réussie", + "editError": "Erreur pendant la modification de {{resource}} (Code de statut: {{statusCode}})", + "importProgress": "Importation de: {{processed}}/{{total}}" + }, + "loading": "Chargement", + "tags": { + "clone": "Clone" + }, + "dashboard": { + "title": "Tableau de bord" + }, + "posts": { + "posts": "Posts", + "fields": { + "id": "Id", + "title": "Title", + "category": "Category", + "status": { + "title": "Status", + "published": "Published", + "draft": "Draft", + "rejected": "Rejected" + }, + "content": "Content", + "createdAt": "Created At" + }, + "titles": { + "create": "Create Post", + "edit": "Edit Post", + "list": "Posts", + "show": "Show Post" + } + }, + "table": { + "actions": "Actions" + }, + "documentTitle": { + "default": "refine", + "suffix": " | Refine", + "post": { + "list": "Posts | Refine", + "show": "#{{id}} Show Post | Refine", + "edit": "#{{id}} Edit Post | Refine", + "create": "Create new Post | Refine", + "clone": "#{{id}} Clone Post | Refine" + } + }, + "autoSave": { + "success": "Sauvegardé", + "error": "Sauvegarde automatique ratée", + "loading": "Sauvegarde...", + "idle": "En attente de modification" + } +} diff --git a/gui/rpk-gui/public/locales/en/common.json b/gui/rpk-gui/public/locales/en/common.json deleted file mode 100644 index 1e19716..0000000 --- a/gui/rpk-gui/public/locales/en/common.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "pages": { - "login": { - "title": "Sign in to your account" - } - } -} diff --git a/gui/rpk-gui/public/locales/fr/common.json b/gui/rpk-gui/public/locales/fr/common.json deleted file mode 100644 index 5756149..0000000 --- a/gui/rpk-gui/public/locales/fr/common.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "pages": { - "login": { - "title": "S'authentifier" - } - } -} diff --git a/gui/rpk-gui/src/components/auth/Login.tsx b/gui/rpk-gui/src/components/auth/Login.tsx index a3942d2..0b9dbab 100644 --- a/gui/rpk-gui/src/components/auth/Login.tsx +++ b/gui/rpk-gui/src/components/auth/Login.tsx @@ -8,8 +8,10 @@ import * as React from "react"; import Typography from "@mui/material/Typography"; import Box from "@mui/material/Box"; import Stack from "@mui/material/Stack"; +import { useTranslation } from "@refinedev/core"; export const Login = () => { + const { translate } = useTranslation(); const [searchParams] = useSearchParams(); if (searchParams.get("oauth") == "success") { const redirect_to = localStorage.getItem("redirect_after_login") @@ -24,12 +26,12 @@ export const Login = () => { rememberMe={false} providers={[{ name: "google", - label: "Sign in with Google", + label: translate("pages.login.oauth.google"), icon: (), }, { name: "discord", - label: "Sign in with Discord", + label: translate("pages.login.oauth.discord"), icon: (), }, ]} @@ -50,7 +52,7 @@ export const Login = () => { underline="none" to="/auth/forgot-password" > - Forgot password? + {translate("pages.login.buttons.forgotPassword")} } @@ -69,7 +71,7 @@ export const Login = () => { component="span" fontSize="12px" > - Don’t have an account? + {translate("pages.login.buttons.noAccount")} { to="/auth/register" fontWeight="bold" > - Sign up + {translate("pages.login.signup")} } diff --git a/gui/rpk-gui/src/components/auth/Register.tsx b/gui/rpk-gui/src/components/auth/Register.tsx index cb022c7..a979d96 100644 --- a/gui/rpk-gui/src/components/auth/Register.tsx +++ b/gui/rpk-gui/src/components/auth/Register.tsx @@ -1,5 +1,51 @@ import { AuthPage } from "@refinedev/mui"; +import Box from "@mui/material/Box"; +import Typography from "@mui/material/Typography"; +import MuiLink from "@mui/material/Link"; +import * as React from "react"; +import { useTranslation } from "@refinedev/core"; +import { Link } from "react-router"; export const Register = () => { - return ; + const { translate } = useTranslation(); + const loginLink = ( + + + {translate( + "pages.register.buttons.haveAccount", + translate( + "pages.login.buttons.haveAccount", + "Have an account?", + ), + )} + + + {translate( + "pages.register.signin", + translate("pages.login.signin", "Sign in"), + )} + + + ) + + return ; }; diff --git a/gui/rpk-gui/src/components/header/I18nPicker.tsx b/gui/rpk-gui/src/components/header/I18nPicker.tsx new file mode 100644 index 0000000..39f5f2c --- /dev/null +++ b/gui/rpk-gui/src/components/header/I18nPicker.tsx @@ -0,0 +1,41 @@ +import Autocomplete from "@mui/material/Autocomplete"; +import TextField from "@mui/material/TextField"; +import Box from "@mui/material/Box"; +import React from "react"; +import { useTranslation } from "react-i18next"; +import { useTranslation as useRefineTranslation } from "@refinedev/core"; + +const I18nPicker = () => { + const { i18n } = useTranslation(); + const { getLocale, changeLocale } = useRefineTranslation(); + const currentLocale = getLocale(); + + return ( + { + return + }} + renderOption={(props, option) => { + const { key, ...optionProps } = props; + return ( + img': { mr: 2, flexShrink: 0 } }} + {...optionProps} + > + { option } + + ); + }} + onChange={(event, value) => { + changeLocale(value); + }} + /> + ) +} + +export default I18nPicker; diff --git a/gui/rpk-gui/src/components/header/index.tsx b/gui/rpk-gui/src/components/header/index.tsx index bf0e285..aa9125a 100644 --- a/gui/rpk-gui/src/components/header/index.tsx +++ b/gui/rpk-gui/src/components/header/index.tsx @@ -18,17 +18,11 @@ import { FirmContext } from "../../contexts/FirmContext"; import { Logout } from "../auth/Logout"; import { IUser } from "../../interfaces"; import MuiLink from "@mui/material/Link"; -import { useTranslation } from "react-i18next"; -import { useTranslation as useTranslationR } from "@refinedev/core"; -import { useSetLocale } from "@refinedev/core"; +import I18nPicker from "./I18nPicker"; export const Header: React.FC = ({ sticky = true, }) => { - const { i18n } = useTranslation(); - const { getLocale, changeLocale } = useTranslationR(); - const currentLocale = getLocale(); - const collapsed = false; const { mode, setMode } = useContext(ColorModeContext); const { currentFirm } = useContext(FirmContext); @@ -44,16 +38,6 @@ export const Header: React.FC = ({ setAnchorEl(null); }; - const [anchorIn, setAnchorIn] = React.useState(null); - const openI18nMenu = Boolean(anchorEl); - const handleOpenI18nMenu = (event: React.MouseEvent) => { - setAnchorIn(event.currentTarget); - } - const handleCloseI18nMenu = () => { - setAnchorIn(null); - }; - - return ( @@ -149,43 +133,7 @@ export const Header: React.FC = ({ {!user && ( )} - - - {[...(i18n.languages || [])].sort().map((lang: string) => ( - changeLocale(lang)} - > - - - - {lang === "en" ? "English" : "Français"} - - ))} - + diff --git a/gui/rpk-gui/src/i18n.tsx b/gui/rpk-gui/src/i18n.tsx index e6f6b51..5e280bb 100644 --- a/gui/rpk-gui/src/i18n.tsx +++ b/gui/rpk-gui/src/i18n.tsx @@ -8,13 +8,13 @@ i18n .use(detector) .use(initReactI18next) .init({ - supportedLngs: ["en", "fr"], + supportedLngs: ["EN", "FR"], backend: { loadPath: "/locales/{{lng}}/{{ns}}.json", // locale files path }, ns: ["common"], defaultNS: "common", - fallbackLng: ["en", "fr"], + fallbackLng: ["EN", "FR"], }); export default i18n;