From fd14db9ed8b725d3162ffa784c82aa617d075180 Mon Sep 17 00:00:00 2001 From: yassinedorbozgithub Date: Tue, 1 Oct 2024 14:23:02 +0100 Subject: [PATCH 1/6] feat(frontend): typed react i18next --- .../attachment/AttachmentDialog.tsx | 4 +- .../attachment/AttachmentThumbnail.tsx | 5 +- .../attachment/AttachmentUploader.tsx | 5 +- frontend/src/app-components/auth/Login.tsx | 103 +++++++++--------- frontend/src/app-components/auth/Register.tsx | 5 +- .../src/app-components/auth/ResetPassword.tsx | 5 +- .../auth/resetPasswordRequest.tsx | 5 +- .../app-components/buttons/DialogButtons.tsx | 5 +- .../app-components/dialogs/DeleteDialog.tsx | 5 +- .../app-components/inputs/FilterTextfield.tsx | 5 +- .../app-components/inputs/MultipleInput.tsx | 5 +- frontend/src/app-components/menus/Sidebar.tsx | 19 +++- .../app-components/tables/NoDataOverlay.tsx | 5 +- .../tables/columns/getColumns.tsx | 43 +++++--- .../src/components/Menu/MenuAccordion.tsx | 5 +- frontend/src/components/Menu/MenuDialog.tsx | 11 +- frontend/src/components/Menu/index.tsx | 5 +- .../components/categories/CategoryDialog.tsx | 4 +- frontend/src/components/categories/index.tsx | 4 +- .../content-types/ContentTypeDialog.tsx | 5 +- .../EditContentTypeFieldsDialog.tsx | 5 +- .../content-types/components/FieldInput.tsx | 5 +- .../src/components/content-types/index.tsx | 5 +- .../src/components/contents/ContentDialog.tsx | 13 ++- frontend/src/components/contents/index.tsx | 5 +- .../context-vars/ContextVarDialog.tsx | 5 +- .../src/components/context-vars/index.tsx | 4 +- .../components/dashboard/AudienceChart.tsx | 5 +- .../dashboard/ConversationChart.tsx | 5 +- .../src/components/dashboard/MessageChart.tsx | 5 +- .../src/components/dashboard/NoDataChart.tsx | 4 +- .../src/components/dashboard/PopularChart.tsx | 5 +- frontend/src/components/dashboard/index.tsx | 4 +- .../inbox/components/AttachmentViewer.tsx | 5 +- .../src/components/inbox/components/Chat.tsx | 5 +- .../inbox/components/ChatActions.tsx | 5 +- .../inbox/components/ConversationsList.tsx | 4 +- frontend/src/components/inbox/index.tsx | 5 +- .../src/components/labels/LabelDialog.tsx | 5 +- frontend/src/components/labels/index.tsx | 5 +- .../components/languages/LanguageDialog.tsx | 5 +- frontend/src/components/languages/index.tsx | 4 +- .../src/components/media-library/index.tsx | 5 +- .../src/components/nlp/NlpEntityDialog.tsx | 5 +- .../src/components/nlp/NlpImportDialog.tsx | 4 +- .../src/components/nlp/NlpSampleDialog.tsx | 5 +- .../src/components/nlp/NlpValueDialog.tsx | 5 +- .../nlp/components/NlpDatasetCounter.tsx | 5 +- .../components/nlp/components/NlpEntity.tsx | 5 +- .../components/nlp/components/NlpSample.tsx | 9 +- .../nlp/components/NlpTrainForm.tsx | 6 +- .../components/nlp/components/NlpValues.tsx | 5 +- frontend/src/components/nlp/index.tsx | 5 +- frontend/src/components/profile/index.tsx | 4 +- frontend/src/components/profile/profile.tsx | 4 +- .../components/roles/PermissionsDialog.tsx | 5 +- frontend/src/components/roles/RoleDialog.tsx | 5 +- frontend/src/components/roles/index.tsx | 12 +- .../src/components/settings/SettingInput.tsx | 15 ++- frontend/src/components/settings/index.tsx | 23 ++-- .../subscribers/EditSubscriberDialog.tsx | 5 +- frontend/src/components/subscribers/index.tsx | 5 +- .../translations/EditTranslationDialog.tsx | 5 +- .../src/components/translations/index.tsx | 5 +- .../src/components/users/EditUserDialog.tsx | 5 +- .../src/components/users/InvitationDialog.tsx | 5 +- frontend/src/components/users/index.tsx | 5 +- .../src/components/visual-editor/Aside.tsx | 5 +- .../components/visual-editor/BlockDialog.tsx | 5 +- .../components/visual-editor/CustomBlocks.tsx | 5 +- .../form/AttachmentMessageForm.tsx | 5 +- .../visual-editor/form/ButtonsMessageForm.tsx | 5 +- .../visual-editor/form/ListMessageForm.tsx | 21 ++-- .../visual-editor/form/OptionsForm.tsx | 5 +- .../form/QuickRepliesMessageForm.tsx | 5 +- .../visual-editor/form/TextMessageForm.tsx | 5 +- .../visual-editor/form/TriggersForm.tsx | 5 +- .../form/inputs/ReplacementTokens.tsx | 7 +- .../form/inputs/message/ButtonInput.tsx | 5 +- .../form/inputs/message/ButtonsInput.tsx | 4 +- .../form/inputs/message/QuickRepliesInput.tsx | 4 +- .../form/inputs/message/QuickReplyInput.tsx | 5 +- .../form/inputs/options/ContextVarInput.tsx | 5 +- .../form/inputs/options/ContextVarsInput.tsx | 4 +- .../inputs/options/LocalFallbackInput.tsx | 5 +- .../inputs/triggers/ContentPostbackInput.tsx | 5 +- .../form/inputs/triggers/PatternInput.tsx | 5 +- .../form/inputs/triggers/PatternsInput.tsx | 4 +- .../form/inputs/triggers/PostbackInput.tsx | 5 +- .../components/visual-editor/v2/Diagrams.tsx | 5 +- frontend/src/contexts/auth.context.tsx | 4 +- frontend/src/hooks/useApiClient.ts | 4 +- frontend/src/hooks/useFormattedFileSize.tsx | 4 +- frontend/src/hooks/useTranslate.tsx | 42 +++++++ frontend/src/hooks/useValidationRules.tsx | 4 +- frontend/src/i18n/en/translation.json | 13 ++- frontend/src/i18n/fr/translation.json | 11 +- frontend/src/i18n/i18n.types.ts | 22 ++++ frontend/src/i18n/index.ts | 4 + frontend/src/layout/Header.tsx | 5 +- frontend/src/layout/VerticalMenu.tsx | 4 +- frontend/src/pages/visual-editor.tsx | 5 +- frontend/src/types/common/object.types.ts | 20 ++++ 103 files changed, 503 insertions(+), 296 deletions(-) create mode 100644 frontend/src/hooks/useTranslate.tsx create mode 100644 frontend/src/i18n/i18n.types.ts create mode 100644 frontend/src/i18n/index.ts create mode 100644 frontend/src/types/common/object.types.ts diff --git a/frontend/src/app-components/attachment/AttachmentDialog.tsx b/frontend/src/app-components/attachment/AttachmentDialog.tsx index 139b7629..0ddc30ec 100644 --- a/frontend/src/app-components/attachment/AttachmentDialog.tsx +++ b/frontend/src/app-components/attachment/AttachmentDialog.tsx @@ -9,11 +9,11 @@ import { Button, Dialog, DialogActions, DialogContent } from "@mui/material"; import { GridEventListener } from "@mui/x-data-grid"; import { FC, useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; import { DialogTitle } from "@/app-components/dialogs/DialogTitle"; import { MediaLibrary } from "@/components/media-library"; import { DialogControlProps } from "@/hooks/useDialog"; +import { useTranslate } from "@/hooks/useTranslate"; import { IAttachment } from "@/types/attachment.types"; export type AttachmentDialogProps = DialogControlProps< @@ -28,7 +28,7 @@ export const AttachmentDialog: FC = ({ accept, ...rest }) => { - const { t } = useTranslation(); + const { t } = useTranslate(); const [selected, setSelected] = useState(null); const handleSelection: GridEventListener<"rowClick"> = (data) => { setSelected(data.row); diff --git a/frontend/src/app-components/attachment/AttachmentThumbnail.tsx b/frontend/src/app-components/attachment/AttachmentThumbnail.tsx index c211d080..c0e61ff4 100644 --- a/frontend/src/app-components/attachment/AttachmentThumbnail.tsx +++ b/frontend/src/app-components/attachment/AttachmentThumbnail.tsx @@ -20,7 +20,7 @@ import { Typography, } from "@mui/material"; import { FC } from "react"; -import { useTranslation } from "react-i18next"; + import { useDelete } from "@/hooks/crud/useDelete"; import { useGet } from "@/hooks/crud/useGet"; @@ -28,6 +28,7 @@ import { useDialog } from "@/hooks/useDialog"; import useFormattedFileSize from "@/hooks/useFormattedFileSize"; import { useHasPermission } from "@/hooks/useHasPermission"; import { useToast } from "@/hooks/useToast"; +import { useTranslate } from "@/hooks/useTranslate"; import { EntityType } from "@/services/types"; import { IAttachment } from "@/types/attachment.types"; import { PermissionAction } from "@/types/permission.types"; @@ -84,7 +85,7 @@ const AttachmentThumbnail: FC = ({ entity: EntityType.ATTACHMENT, }); const { toast } = useToast(); - const { t } = useTranslation(); + const { t } = useTranslate(); const deleteDialogCtl = useDialog(false); const { mutateAsync: deleteAttachment } = useDelete(EntityType.ATTACHMENT, { onError: () => { diff --git a/frontend/src/app-components/attachment/AttachmentUploader.tsx b/frontend/src/app-components/attachment/AttachmentUploader.tsx index 498474a1..5323aff1 100644 --- a/frontend/src/app-components/attachment/AttachmentUploader.tsx +++ b/frontend/src/app-components/attachment/AttachmentUploader.tsx @@ -10,11 +10,12 @@ import CloudUploadIcon from "@mui/icons-material/CloudUpload"; import FolderCopyIcon from "@mui/icons-material/FolderCopy"; import { Box, Button, Divider, Grid, styled, Typography } from "@mui/material"; import { ChangeEvent, DragEvent, FC, useState } from "react"; -import { useTranslation } from "react-i18next"; + import { useUpload } from "@/hooks/crud/useUpload"; import { getDisplayDialogs, useDialog } from "@/hooks/useDialog"; import { useToast } from "@/hooks/useToast"; +import { useTranslate } from "@/hooks/useTranslate"; import { EntityType } from "@/services/types"; import { IAttachment } from "@/types/attachment.types"; @@ -76,7 +77,7 @@ const AttachmentUploader: FC = ({ const [attachment, setAttachment] = useState( undefined, ); - const { t } = useTranslation(); + const { t } = useTranslate(); const [isDragOver, setIsDragOver] = useState(false); const { toast } = useToast(); const { mutateAsync: uploadAttachment } = useUpload(EntityType.ATTACHMENT, { diff --git a/frontend/src/app-components/auth/Login.tsx b/frontend/src/app-components/auth/Login.tsx index 8c22aca6..d84ca0f5 100755 --- a/frontend/src/app-components/auth/Login.tsx +++ b/frontend/src/app-components/auth/Login.tsx @@ -14,11 +14,12 @@ import Link from "next/link"; import { useRouter } from "next/router"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; -import { useTranslation } from "react-i18next"; + import { useConfirmAccount, useLogin } from "@/hooks/entities/auth-hooks"; import { useAuth } from "@/hooks/useAuth"; import { useToast } from "@/hooks/useToast"; +import { useTranslate } from "@/hooks/useTranslate"; import { useValidationRules } from "@/hooks/useValidationRules"; import { ILoginAttributes } from "@/types/auth/login.types"; @@ -33,7 +34,7 @@ const DEFAULT_VALUES: ILoginAttributes = { }; export const Login = () => { - const { t } = useTranslation(); + const { t } = useTranslate(); const { toast } = useToast(); const router = useRouter(); const { authenticate } = useAuth(); @@ -91,59 +92,57 @@ export const Login = () => { return ( -
- - - {t("title.login")} - - , - }} - helperText={ - errors.identifier ? errors.identifier.message : null - } - {...register("identifier", validationRules.email)} - /> + + + + {t("title.login")} + + , + }} + helperText={errors.identifier ? errors.identifier.message : null} + {...register("identifier", validationRules.email)} + /> - , - }} - helperText={errors.password ? errors.password.message : null} - {...register("password", validationRules.password)} - /> - - - - - - - - - + - - -
+ + + +
+ + + ); }; diff --git a/frontend/src/app-components/auth/Register.tsx b/frontend/src/app-components/auth/Register.tsx index e8eadb10..6c55f805 100644 --- a/frontend/src/app-components/auth/Register.tsx +++ b/frontend/src/app-components/auth/Register.tsx @@ -22,10 +22,11 @@ import { import { useRouter } from "next/router"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; -import { useTranslation } from "react-i18next"; + import { useAcceptInvite } from "@/hooks/entities/auth-hooks"; import { useToast } from "@/hooks/useToast"; +import { useTranslate } from "@/hooks/useTranslate"; import { useValidationRules } from "@/hooks/useValidationRules"; import { IRegisterAttributes } from "@/types/auth/register.types"; import { JWT } from "@/utils/Jwt"; @@ -49,7 +50,7 @@ const DEFAULT_VALUES: IRegisterAttributes = { type TRegisterExtendedPayload = IRegisterAttributes & { password2: string }; export const Register = () => { - const { t } = useTranslation(); + const { t } = useTranslate(); const router = useRouter(); const { toast } = useToast(); const { mutateAsync: acceptInvite, isLoading } = useAcceptInvite({ diff --git a/frontend/src/app-components/auth/ResetPassword.tsx b/frontend/src/app-components/auth/ResetPassword.tsx index 2eb284be..5337ec75 100644 --- a/frontend/src/app-components/auth/ResetPassword.tsx +++ b/frontend/src/app-components/auth/ResetPassword.tsx @@ -11,10 +11,11 @@ import { Button, Grid, Paper, Typography } from "@mui/material"; import Link from "next/link"; import { useRouter } from "next/router"; import { useForm } from "react-hook-form"; -import { useTranslation } from "react-i18next"; + import { useResetPassword } from "@/hooks/entities/reset-hooks"; import { useToast } from "@/hooks/useToast"; +import { useTranslate } from "@/hooks/useTranslate"; import { useValidationRules } from "@/hooks/useValidationRules"; import { ContentContainer } from "../dialogs"; @@ -22,7 +23,7 @@ import { Adornment } from "../inputs/Adornment"; import { PasswordInput } from "../inputs/PasswordInput"; export const ResetPassword = () => { - const { t } = useTranslation(); + const { t } = useTranslate(); const { toast } = useToast(); const rules = useValidationRules(); const validationRules = { diff --git a/frontend/src/app-components/auth/resetPasswordRequest.tsx b/frontend/src/app-components/auth/resetPasswordRequest.tsx index 704b9b20..563457f7 100644 --- a/frontend/src/app-components/auth/resetPasswordRequest.tsx +++ b/frontend/src/app-components/auth/resetPasswordRequest.tsx @@ -9,16 +9,17 @@ import { Button, Grid, Paper, Typography } from "@mui/material"; import Link from "next/link"; import { useForm } from "react-hook-form"; -import { useTranslation } from "react-i18next"; + import { useRequestResetPassword } from "@/hooks/entities/reset-hooks"; import { useToast } from "@/hooks/useToast"; +import { useTranslate } from "@/hooks/useTranslate"; import { ContentContainer } from "../dialogs"; import { Input } from "../inputs/Input"; export const ResetPasswordRequest = () => { - const { t } = useTranslation(); + const { t } = useTranslate(); const { toast } = useToast(); const { register, diff --git a/frontend/src/app-components/buttons/DialogButtons.tsx b/frontend/src/app-components/buttons/DialogButtons.tsx index 2ff94a61..36fbe909 100644 --- a/frontend/src/app-components/buttons/DialogButtons.tsx +++ b/frontend/src/app-components/buttons/DialogButtons.tsx @@ -9,7 +9,8 @@ import CheckIcon from "@mui/icons-material/Check"; import CloseIcon from "@mui/icons-material/Close"; import { Button } from "@mui/material"; -import { useTranslation } from "react-i18next"; + +import { useTranslate } from "@/hooks/useTranslate"; interface DialogButtonsProps { closeDialog?: () => void; @@ -20,7 +21,7 @@ const DialogButtons: React.FC = ({ closeDialog, handleSubmit, }) => { - const { t } = useTranslation(); + const { t } = useTranslate(); return ( <> diff --git a/frontend/src/app-components/dialogs/DeleteDialog.tsx b/frontend/src/app-components/dialogs/DeleteDialog.tsx index 6fc9dcd1..70701050 100644 --- a/frontend/src/app-components/dialogs/DeleteDialog.tsx +++ b/frontend/src/app-components/dialogs/DeleteDialog.tsx @@ -16,10 +16,11 @@ import { Button, } from "@mui/material"; import { FC } from "react"; -import { useTranslation } from "react-i18next"; + import { DialogTitle } from "@/app-components/dialogs/DialogTitle"; import { DialogControl } from "@/hooks/useDialog"; +import { useTranslate } from "@/hooks/useTranslate"; export type DeleteDialogProps = DialogControl; export const DeleteDialog: FC = ({ @@ -27,7 +28,7 @@ export const DeleteDialog: FC = ({ callback, closeDialog: closeFunction, }: DeleteDialogProps) => { - const { t } = useTranslation(); + const { t } = useTranslate(); return ( diff --git a/frontend/src/app-components/inputs/FilterTextfield.tsx b/frontend/src/app-components/inputs/FilterTextfield.tsx index ef77e43d..cd58df06 100644 --- a/frontend/src/app-components/inputs/FilterTextfield.tsx +++ b/frontend/src/app-components/inputs/FilterTextfield.tsx @@ -8,13 +8,14 @@ import SearchIcon from "@mui/icons-material/Search"; import { TextFieldProps } from "@mui/material"; -import { useTranslation } from "react-i18next"; + +import { useTranslate } from "@/hooks/useTranslate"; import { Adornment } from "./Adornment"; import { Input } from "./Input"; export const FilterTextfield = (props: TextFieldProps) => { - const { t } = useTranslation(); + const { t } = useTranslate(); //TODO: replace the native delete text button by a styled custom button return ( diff --git a/frontend/src/app-components/inputs/MultipleInput.tsx b/frontend/src/app-components/inputs/MultipleInput.tsx index 62751e72..17c73a38 100644 --- a/frontend/src/app-components/inputs/MultipleInput.tsx +++ b/frontend/src/app-components/inputs/MultipleInput.tsx @@ -24,7 +24,8 @@ import { useEffect, useState, } from "react"; -import { useTranslation } from "react-i18next"; + +import { useTranslate } from "@/hooks/useTranslate"; import { Input } from "./Input"; @@ -54,7 +55,7 @@ const MultipleInput = forwardRef( }, ref, ) => { - const { t } = useTranslation(); + const { t } = useTranslate(); const [inputs, setInputs] = useState>( value ? value.length >= minInput diff --git a/frontend/src/app-components/menus/Sidebar.tsx b/frontend/src/app-components/menus/Sidebar.tsx index 59c77730..ca621817 100644 --- a/frontend/src/app-components/menus/Sidebar.tsx +++ b/frontend/src/app-components/menus/Sidebar.tsx @@ -26,8 +26,9 @@ import { import { OverridableComponent } from "@mui/material/OverridableComponent"; import Link from "next/link"; import { useState, useEffect } from "react"; -import { useTranslation } from "react-i18next"; +import { useTranslate } from "@/hooks/useTranslate"; +import { TTranslationKeys } from "@/i18n/i18n.types"; import { theme } from "@/layout/themes/theme"; import { SXStyleOptions } from "@/utils/SXStyleOptions"; @@ -160,7 +161,7 @@ const VerticalMenuItem = ({ isNested?: boolean; isToggled?: boolean; }) => { - const { t } = useTranslation(); + const { t } = useTranslate(); const linkProps = { href, onClick, @@ -173,7 +174,11 @@ const VerticalMenuItem = ({ : theme.palette.text.secondary; return ( - + @@ -221,7 +226,7 @@ export const Sidebar = ({ isToggled, toggleFunction, }: TSidebarProps) => { - const { t } = useTranslation(); + const { t } = useTranslate(); const [openItems, setOpenItems] = useState([]); const toggleCollapse = (menuItem: string) => () => { if (isToggled || !openItems.includes(menuItem)) @@ -301,7 +306,9 @@ export const Sidebar = ({ return ( {isToggled && text ? ( - {t(text)} + + {String(t(text as TTranslationKeys))} + ) : null} ); diff --git a/frontend/src/app-components/tables/NoDataOverlay.tsx b/frontend/src/app-components/tables/NoDataOverlay.tsx index 5d0b7b0f..78b15dbc 100644 --- a/frontend/src/app-components/tables/NoDataOverlay.tsx +++ b/frontend/src/app-components/tables/NoDataOverlay.tsx @@ -7,12 +7,13 @@ */ import { Grid, Typography } from "@mui/material"; -import { useTranslation } from "react-i18next"; + +import { useTranslate } from "@/hooks/useTranslate"; import NoDataIcon from "../svg/NoDataIcon"; export const NoDataOverlay = () => { - const { t } = useTranslation(); + const { t } = useTranslate(); return ( = { + [ActionColumnLabel.Edit]: "button.edit", + [ActionColumnLabel.Delete]: "button.delete", + [ActionColumnLabel.Values]: "button.values", + [ActionColumnLabel.Manage_Roles]: "button.manage_roles", + [ActionColumnLabel.Permissions]: "button.permissions", + [ActionColumnLabel.Content]: "button.content", + [ActionColumnLabel.Fields]: "button.fields", + [ActionColumnLabel.Manage_Labels]: "title.manage_labels", + [ActionColumnLabel.Toggle]: "button.toggle", +} as const; + export interface ActionColumn { label: ActionColumnLabel; action?: (row: T) => void; @@ -99,7 +112,7 @@ function StackComponent({ actions: ActionColumn[]; params: GridRenderCellParams; }) { - const { t } = useTranslation(); + const { t } = useTranslate(); return ( @@ -116,9 +129,13 @@ function StackComponent({ key={label} className="actionButton" icon={ - {getIcon(label)} + + {getIcon(label)} + } - label={helperText || t(label)} + label={helperText || t(ACTION_COLUMN_LABEL_MAP[label])} showInMenu={false} sx={{ color: diff --git a/frontend/src/components/Menu/MenuAccordion.tsx b/frontend/src/components/Menu/MenuAccordion.tsx index 962e380b..c103cabc 100644 --- a/frontend/src/components/Menu/MenuAccordion.tsx +++ b/frontend/src/components/Menu/MenuAccordion.tsx @@ -25,13 +25,14 @@ import { styled, } from "@mui/material"; import React, { FC, useState } from "react"; -import { useTranslation } from "react-i18next"; + import { AnimatedChevron } from "@/app-components/icons/AnimatedChevron"; import { UnifiedIcon } from "@/app-components/icons/UnifiedIcon"; import { TMenuItem } from "@/app-components/menus/Sidebar"; import { useGetFromCache } from "@/hooks/crud/useGet"; import { useHasPermission } from "@/hooks/useHasPermission"; +import { useTranslate } from "@/hooks/useTranslate"; import { theme } from "@/layout/themes/theme"; import { EntityType } from "@/services/types"; import { IMenuNode } from "@/types/menu-tree.types"; @@ -103,7 +104,7 @@ const MenuItem: FC = ({ onUpdate, onDelete, }) => { - const { t } = useTranslation(); + const { t } = useTranslate(); const hasPermission = useHasPermission(); return ( diff --git a/frontend/src/components/Menu/MenuDialog.tsx b/frontend/src/components/Menu/MenuDialog.tsx index 0483c0a1..1a417d68 100644 --- a/frontend/src/components/Menu/MenuDialog.tsx +++ b/frontend/src/components/Menu/MenuDialog.tsx @@ -15,7 +15,6 @@ import { } from "@mui/material"; import { useEffect, FC } from "react"; import { useForm, Controller } from "react-hook-form"; -import { useTranslation } from "react-i18next"; import DialogButtons from "@/app-components/buttons/DialogButtons"; import { DialogTitle } from "@/app-components/dialogs/DialogTitle"; @@ -23,6 +22,8 @@ import { ContentContainer } from "@/app-components/dialogs/layouts/ContentContai import { ContentItem } from "@/app-components/dialogs/layouts/ContentItem"; import { Input } from "@/app-components/inputs/Input"; import { ToggleableInput } from "@/app-components/inputs/ToggleableInput"; +import { useTranslate } from "@/hooks/useTranslate"; +import { TNestedTranslation } from "@/i18n/i18n.types"; import { IMenuItem, IMenuItemAttributes, MenuType } from "@/types/menu.types"; import { isAbsoluteUrl } from "@/utils/URL"; @@ -45,7 +46,7 @@ export const MenuDialog: FC = ({ parentId, ...rest }) => { - const { t } = useTranslation(); + const { t } = useTranslate(); const { reset, resetField, @@ -123,9 +124,11 @@ export const MenuDialog: FC = ({ helperText={errors.type ? errors.type.message : null} {...rest} > - {Object.keys(MenuType).map((value, key) => ( + {( + Object.keys(MenuType) as TNestedTranslation<"label">[] + ).map((value, key) => ( - {t(`label.${value}`)} + {t("label", value)} ))} diff --git a/frontend/src/components/Menu/index.tsx b/frontend/src/components/Menu/index.tsx index ead52812..ee7716c0 100644 --- a/frontend/src/components/Menu/index.tsx +++ b/frontend/src/components/Menu/index.tsx @@ -10,7 +10,7 @@ import { faBars } from "@fortawesome/free-solid-svg-icons"; import AddIcon from "@mui/icons-material/Add"; import { Grid, Paper, Button, Box, debounce } from "@mui/material"; import React, { useRef, useState } from "react"; -import { useTranslation } from "react-i18next"; + import { DeleteDialog } from "@/app-components/dialogs/DeleteDialog"; import { NoDataOverlay } from "@/app-components/tables/NoDataOverlay"; @@ -19,6 +19,7 @@ import { useDelete } from "@/hooks/crud/useDelete"; import { useFind } from "@/hooks/crud/useFind"; import { useUpdate } from "@/hooks/crud/useUpdate"; import { useHasPermission } from "@/hooks/useHasPermission"; +import { useTranslate } from "@/hooks/useTranslate"; import { PageHeader } from "@/layout/content/PageHeader"; import { EntityType } from "@/services/types"; import { IMenuItem } from "@/types/menu.types"; @@ -28,7 +29,7 @@ import MenuAccordion from "./MenuAccordion"; import { MenuDialog } from "./MenuDialog"; export const Menu = () => { - const { t } = useTranslation(); + const { t } = useTranslate(); const [addDialogOpened, setAddDialogOpened] = useState(false); const [editDialogOpened, setEditDialogOpened] = useState(false); const [selectedMenuId, setSelectedMenuId] = useState( diff --git a/frontend/src/components/categories/CategoryDialog.tsx b/frontend/src/components/categories/CategoryDialog.tsx index af27e349..f6baa5e9 100644 --- a/frontend/src/components/categories/CategoryDialog.tsx +++ b/frontend/src/components/categories/CategoryDialog.tsx @@ -9,7 +9,6 @@ import { Dialog, DialogActions, DialogContent } from "@mui/material"; import { FC, useEffect } from "react"; import { useForm } from "react-hook-form"; -import { useTranslation } from "react-i18next"; import DialogButtons from "@/app-components/buttons/DialogButtons"; import { DialogTitle } from "@/app-components/dialogs/DialogTitle"; @@ -20,6 +19,7 @@ import { useCreate } from "@/hooks/crud/useCreate"; import { useUpdate } from "@/hooks/crud/useUpdate"; import { DialogControlProps } from "@/hooks/useDialog"; import { useToast } from "@/hooks/useToast"; +import { useTranslate } from "@/hooks/useTranslate"; import { EntityType } from "@/services/types"; import { ICategory, ICategoryAttributes } from "@/types/category.types"; @@ -31,7 +31,7 @@ export const CategoryDialog: FC = ({ closeDialog, ...rest }) => { - const { t } = useTranslation(); + const { t } = useTranslate(); const { toast } = useToast(); const { mutateAsync: createCategory } = useCreate(EntityType.CATEGORY, { onError: () => { diff --git a/frontend/src/components/categories/index.tsx b/frontend/src/components/categories/index.tsx index b3c152f1..93b5d5af 100644 --- a/frontend/src/components/categories/index.tsx +++ b/frontend/src/components/categories/index.tsx @@ -10,7 +10,6 @@ import AddIcon from "@mui/icons-material/Add"; import FolderIcon from "@mui/icons-material/Folder"; import { Button, Grid, Paper } from "@mui/material"; import { GridColDef } from "@mui/x-data-grid"; -import { useTranslation } from "react-i18next"; import { DeleteDialog } from "@/app-components/dialogs/DeleteDialog"; import { FilterTextfield } from "@/app-components/inputs/FilterTextfield"; @@ -26,6 +25,7 @@ import { getDisplayDialogs, useDialog } from "@/hooks/useDialog"; import { useHasPermission } from "@/hooks/useHasPermission"; import { useSearch } from "@/hooks/useSearch"; import { useToast } from "@/hooks/useToast"; +import { useTranslate } from "@/hooks/useTranslate"; import { PageHeader } from "@/layout/content/PageHeader"; import { EntityType } from "@/services/types"; import { PermissionAction } from "@/types/permission.types"; @@ -35,7 +35,7 @@ import { CategoryDialog } from "./CategoryDialog"; import { ICategory } from "../../types/category.types"; export const Categories = () => { - const { t } = useTranslation(); + const { t } = useTranslate(); const { toast } = useToast(); const addDialogCtl = useDialog(false); const editDialogCtl = useDialog(false); diff --git a/frontend/src/components/content-types/ContentTypeDialog.tsx b/frontend/src/components/content-types/ContentTypeDialog.tsx index a278662e..6846c15b 100644 --- a/frontend/src/components/content-types/ContentTypeDialog.tsx +++ b/frontend/src/components/content-types/ContentTypeDialog.tsx @@ -9,7 +9,7 @@ import { Dialog, DialogActions, DialogContent } from "@mui/material"; import { FC, useEffect } from "react"; import { useForm } from "react-hook-form"; -import { useTranslation } from "react-i18next"; + import DialogButtons from "@/app-components/buttons/DialogButtons"; import { DialogTitle } from "@/app-components/dialogs/DialogTitle"; @@ -20,6 +20,7 @@ import { useCreate } from "@/hooks/crud/useCreate"; import { useUpdate } from "@/hooks/crud/useUpdate"; import { DialogControlProps } from "@/hooks/useDialog"; import { useToast } from "@/hooks/useToast"; +import { useTranslate } from "@/hooks/useTranslate"; import { EntityType } from "@/services/types"; import { IContentType, @@ -33,7 +34,7 @@ export const ContentTypeDialog: FC = ({ closeDialog, }) => { const { toast } = useToast(); - const { t } = useTranslation(); + const { t } = useTranslate(); const { handleSubmit, register, diff --git a/frontend/src/components/content-types/EditContentTypeFieldsDialog.tsx b/frontend/src/components/content-types/EditContentTypeFieldsDialog.tsx index af9186aa..89cde847 100644 --- a/frontend/src/components/content-types/EditContentTypeFieldsDialog.tsx +++ b/frontend/src/components/content-types/EditContentTypeFieldsDialog.tsx @@ -17,7 +17,7 @@ import { } from "@mui/material"; import { useEffect } from "react"; import { useFieldArray, useForm } from "react-hook-form"; -import { useTranslation } from "react-i18next"; + import DialogButtons from "@/app-components/buttons/DialogButtons"; import { @@ -30,6 +30,7 @@ import { useGet } from "@/hooks/crud/useGet"; import { useUpdate } from "@/hooks/crud/useUpdate"; import { DialogControlProps } from "@/hooks/useDialog"; import { useToast } from "@/hooks/useToast"; +import { useTranslate } from "@/hooks/useTranslate"; import { EntityType } from "@/services/types"; import { ContentFieldType, IContentType } from "@/types/content-type.types"; @@ -43,7 +44,7 @@ export const EditContentTypeFieldsDialog = ({ closeDialog, open, }: EditContentTypeDialogFieldsProps) => { - const { t } = useTranslation(); + const { t } = useTranslate(); const { isLoading, data, refetch } = useGet(contentType?.id || "", { entity: EntityType.CONTENT_TYPE, }); diff --git a/frontend/src/components/content-types/components/FieldInput.tsx b/frontend/src/components/content-types/components/FieldInput.tsx index c8c1c1c3..236ab728 100644 --- a/frontend/src/components/content-types/components/FieldInput.tsx +++ b/frontend/src/components/content-types/components/FieldInput.tsx @@ -16,10 +16,11 @@ import { UseFormSetValue, useWatch, } from "react-hook-form"; -import { useTranslation } from "react-i18next"; + import { IconButton } from "@/app-components/buttons/IconButton"; import { Input } from "@/app-components/inputs/Input"; +import { useTranslate } from "@/hooks/useTranslate"; import { ContentFieldType, IContentType } from "@/types/content-type.types"; import { slugify } from "@/utils/string"; @@ -34,7 +35,7 @@ export const FieldInput = ({ control: Control>; setValue: UseFormSetValue>; }) => { - const { t } = useTranslation(); + const { t } = useTranslate(); const label = useWatch({ control: props.control, name: `fields.${index}.label`, diff --git a/frontend/src/components/content-types/index.tsx b/frontend/src/components/content-types/index.tsx index 79f0a9e7..53243909 100644 --- a/frontend/src/components/content-types/index.tsx +++ b/frontend/src/components/content-types/index.tsx @@ -10,7 +10,7 @@ import { faAlignLeft } from "@fortawesome/free-solid-svg-icons"; import AddIcon from "@mui/icons-material/Add"; import { Button, Grid, Paper } from "@mui/material"; import { useRouter } from "next/router"; -import { useTranslation } from "react-i18next"; + import { DeleteDialog } from "@/app-components/dialogs"; import { FilterTextfield } from "@/app-components/inputs/FilterTextfield"; @@ -26,6 +26,7 @@ import { getDisplayDialogs, useDialog } from "@/hooks/useDialog"; import { useHasPermission } from "@/hooks/useHasPermission"; import { useSearch } from "@/hooks/useSearch"; import { useToast } from "@/hooks/useToast"; +import { useTranslate } from "@/hooks/useTranslate"; import { PageHeader } from "@/layout/content/PageHeader"; import { EntityType } from "@/services/types"; import { IContentType } from "@/types/content-type.types"; @@ -36,7 +37,7 @@ import { ContentTypeDialog } from "./ContentTypeDialog"; import { EditContentTypeFieldsDialog } from "./EditContentTypeFieldsDialog"; export const ContentTypes = () => { - const { t } = useTranslation(); + const { t } = useTranslate(); const { toast } = useToast(); const router = useRouter(); // Dialog Controls diff --git a/frontend/src/components/contents/ContentDialog.tsx b/frontend/src/components/contents/ContentDialog.tsx index 1c845762..4d1b27d1 100644 --- a/frontend/src/components/contents/ContentDialog.tsx +++ b/frontend/src/components/contents/ContentDialog.tsx @@ -23,7 +23,6 @@ import { FieldErrors, useForm, } from "react-hook-form"; -import { useTranslation } from "react-i18next"; import AttachmentInput from "@/app-components/attachment/AttachmentInput"; import DialogButtons from "@/app-components/buttons/DialogButtons"; @@ -36,6 +35,8 @@ import { useCreate } from "@/hooks/crud/useCreate"; import { useUpdate } from "@/hooks/crud/useUpdate"; import { DialogControlProps } from "@/hooks/useDialog"; import { useToast } from "@/hooks/useToast"; +import { useTranslate } from "@/hooks/useTranslate"; +import { TNestedTranslation } from "@/i18n/i18n.types"; import { EntityType } from "@/services/types"; import { ContentField, @@ -60,7 +61,7 @@ const ContentFieldInput: React.FC = ({ field, errors, }) => { - const { t } = useTranslation(); + const { t } = useTranslate(); switch (contentField.type) { case ContentFieldType.TEXT: @@ -70,7 +71,7 @@ const ContentFieldInput: React.FC = ({ , { defaultValue: contentField.label, })} InputProps={ @@ -92,7 +93,7 @@ const ContentFieldInput: React.FC = ({ case ContentFieldType.CHECKBOX: return ( , { defaultValue: contentField.label, })} {...field} @@ -102,7 +103,7 @@ const ContentFieldInput: React.FC = ({ case ContentFieldType.FILE: return ( , { defaultValue: contentField.label, })} {...field} @@ -133,7 +134,7 @@ export const ContentDialog: FC = ({ content: undefined, contentType: undefined, }; - const { t } = useTranslation(); + const { t } = useTranslate(); const { toast } = useToast(); const { reset, diff --git a/frontend/src/components/contents/index.tsx b/frontend/src/components/contents/index.tsx index 0634b5a1..5cfaace6 100644 --- a/frontend/src/components/contents/index.tsx +++ b/frontend/src/components/contents/index.tsx @@ -12,7 +12,7 @@ import ArrowBackIcon from "@mui/icons-material/ArrowBack"; import { Button, Chip, Grid, Paper, Switch, Typography } from "@mui/material"; import Link from "next/link"; import { useRouter } from "next/router"; -import { useTranslation } from "react-i18next"; + import { DeleteDialog } from "@/app-components/dialogs"; import { FilterTextfield } from "@/app-components/inputs/FilterTextfield"; @@ -30,6 +30,7 @@ import { getDisplayDialogs, useDialog } from "@/hooks/useDialog"; import { useHasPermission } from "@/hooks/useHasPermission"; import { useSearch } from "@/hooks/useSearch"; import { useToast } from "@/hooks/useToast"; +import { useTranslate } from "@/hooks/useTranslate"; import { PageHeader } from "@/layout/content/PageHeader"; import { EntityType, Format } from "@/services/types"; import { IContentType } from "@/types/content-type.types"; @@ -40,7 +41,7 @@ import { getDateTimeFormatter } from "@/utils/date"; import { ContentDialog } from "./ContentDialog"; export const Contents = () => { - const { t } = useTranslation(); + const { t } = useTranslate(); const { toast } = useToast(); const { query } = useRouter(); // Dialog Controls diff --git a/frontend/src/components/context-vars/ContextVarDialog.tsx b/frontend/src/components/context-vars/ContextVarDialog.tsx index e19c8903..bd33ebb0 100644 --- a/frontend/src/components/context-vars/ContextVarDialog.tsx +++ b/frontend/src/components/context-vars/ContextVarDialog.tsx @@ -16,7 +16,7 @@ import { } from "@mui/material"; import { FC, useEffect } from "react"; import { Controller, useForm } from "react-hook-form"; -import { useTranslation } from "react-i18next"; + import DialogButtons from "@/app-components/buttons/DialogButtons"; import { DialogTitle } from "@/app-components/dialogs/DialogTitle"; @@ -27,6 +27,7 @@ import { useCreate } from "@/hooks/crud/useCreate"; import { useUpdate } from "@/hooks/crud/useUpdate"; import { DialogControlProps } from "@/hooks/useDialog"; import { useToast } from "@/hooks/useToast"; +import { useTranslate } from "@/hooks/useTranslate"; import { EntityType } from "@/services/types"; import { IContextVar, IContextVarAttributes } from "@/types/context-var.types"; import { slugify } from "@/utils/string"; @@ -38,7 +39,7 @@ export const ContextVarDialog: FC = ({ closeDialog, ...rest }) => { - const { t } = useTranslation(); + const { t } = useTranslate(); const { toast } = useToast(); const { mutateAsync: createContextVar } = useCreate(EntityType.CONTEXT_VAR, { onError: () => { diff --git a/frontend/src/components/context-vars/index.tsx b/frontend/src/components/context-vars/index.tsx index 8037c466..3cb5e1c5 100644 --- a/frontend/src/components/context-vars/index.tsx +++ b/frontend/src/components/context-vars/index.tsx @@ -11,7 +11,6 @@ import AddIcon from "@mui/icons-material/Add"; import { Button, Grid, Paper, Switch } from "@mui/material"; import { GridColDef } from "@mui/x-data-grid"; import React from "react"; -import { useTranslation } from "react-i18next"; import { DeleteDialog } from "@/app-components/dialogs/DeleteDialog"; import { FilterTextfield } from "@/app-components/inputs/FilterTextfield"; @@ -28,6 +27,7 @@ import { getDisplayDialogs, useDialog } from "@/hooks/useDialog"; import { useHasPermission } from "@/hooks/useHasPermission"; import { useSearch } from "@/hooks/useSearch"; import { useToast } from "@/hooks/useToast"; +import { useTranslate } from "@/hooks/useTranslate"; import { PageHeader } from "@/layout/content/PageHeader"; import { EntityType } from "@/services/types"; import { IContextVar } from "@/types/context-var.types"; @@ -37,7 +37,7 @@ import { getDateTimeFormatter } from "@/utils/date"; import { ContextVarDialog } from "./ContextVarDialog"; export const ContextVars = () => { - const { t } = useTranslation(); + const { t } = useTranslate(); const { toast } = useToast(); const addDialogCtl = useDialog(false); const editDialogCtl = useDialog(false); diff --git a/frontend/src/components/dashboard/AudienceChart.tsx b/frontend/src/components/dashboard/AudienceChart.tsx index 67042ed2..d0ed3559 100644 --- a/frontend/src/components/dashboard/AudienceChart.tsx +++ b/frontend/src/components/dashboard/AudienceChart.tsx @@ -8,17 +8,18 @@ import { Card, CardContent, Divider } from "@mui/material"; import { MultiLineChart, ResponsiveChartContainer } from "eazychart-react"; -import { useTranslation } from "react-i18next"; + import { StyledCardHeader } from "@/app-components/card/StyledCardHeader"; import { useFindStats } from "@/hooks/entities/bot-stat-hooks"; +import { useTranslate } from "@/hooks/useTranslate"; import { LineChartStats } from "@/types/bot-stat.types"; import { buildMultiLineChartConfig, transformToLine } from "@/utils/chart"; import { NoDataChart } from "./NoDataChart"; const AudienceChart = () => { - const { t, i18n } = useTranslation(); + const { t, i18n } = useTranslate(); const { data: stats } = useFindStats("audiance"); const { data, domainKeys } = transformToLine(stats); diff --git a/frontend/src/components/dashboard/ConversationChart.tsx b/frontend/src/components/dashboard/ConversationChart.tsx index 8a7940b4..11f2d277 100644 --- a/frontend/src/components/dashboard/ConversationChart.tsx +++ b/frontend/src/components/dashboard/ConversationChart.tsx @@ -8,17 +8,18 @@ import { Card, CardContent, Divider } from "@mui/material"; import { MultiLineChart, ResponsiveChartContainer } from "eazychart-react"; -import { useTranslation } from "react-i18next"; + import { StyledCardHeader } from "@/app-components/card/StyledCardHeader"; import { useFindStats } from "@/hooks/entities/bot-stat-hooks"; +import { useTranslate } from "@/hooks/useTranslate"; import { LineChartStats } from "@/types/bot-stat.types"; import { buildMultiLineChartConfig, transformToLine } from "@/utils/chart"; import { NoDataChart } from "./NoDataChart"; const ConversationChart = () => { - const { t, i18n } = useTranslation(); + const { t, i18n } = useTranslate(); const { data: conversations } = useFindStats("conversation"); const { data: conversationData, domainKeys: conversationDomains } = transformToLine(conversations); diff --git a/frontend/src/components/dashboard/MessageChart.tsx b/frontend/src/components/dashboard/MessageChart.tsx index fc70cde0..f6dd8450 100644 --- a/frontend/src/components/dashboard/MessageChart.tsx +++ b/frontend/src/components/dashboard/MessageChart.tsx @@ -8,17 +8,18 @@ import { Card, CardContent, Divider } from "@mui/material"; import { MultiLineChart, ResponsiveChartContainer } from "eazychart-react"; -import { useTranslation } from "react-i18next"; + import { StyledCardHeader } from "@/app-components/card/StyledCardHeader"; import { useFindStats } from "@/hooks/entities/bot-stat-hooks"; +import { useTranslate } from "@/hooks/useTranslate"; import { LineChartStats } from "@/types/bot-stat.types"; import { buildMultiLineChartConfig, transformToLine } from "@/utils/chart"; import { NoDataChart } from "./NoDataChart"; const MessageChart = () => { - const { t, i18n } = useTranslation(); + const { t, i18n } = useTranslate(); const { data: stats } = useFindStats("messages"); const { data, domainKeys: domains } = transformToLine(stats); diff --git a/frontend/src/components/dashboard/NoDataChart.tsx b/frontend/src/components/dashboard/NoDataChart.tsx index 28dba0a3..e4728709 100644 --- a/frontend/src/components/dashboard/NoDataChart.tsx +++ b/frontend/src/components/dashboard/NoDataChart.tsx @@ -9,8 +9,8 @@ import { faChartLine } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { styled, Typography } from "@mui/material"; -import { useTranslation } from "react-i18next"; +import { useTranslate } from "@/hooks/useTranslate"; import { SXStyleOptions } from "@/utils/SXStyleOptions"; export const StyledMessage = styled(Typography)( @@ -24,7 +24,7 @@ export const StyledMessage = styled(Typography)( ); export const NoDataChart = () => { - const { t } = useTranslation(); + const { t } = useTranslate(); return ( diff --git a/frontend/src/components/dashboard/PopularChart.tsx b/frontend/src/components/dashboard/PopularChart.tsx index c3568cc1..e244ac27 100644 --- a/frontend/src/components/dashboard/PopularChart.tsx +++ b/frontend/src/components/dashboard/PopularChart.tsx @@ -8,17 +8,18 @@ import { Card, CardContent, Divider } from "@mui/material"; import { ColumnChart, ResponsiveChartContainer } from "eazychart-react"; -import { useTranslation } from "react-i18next"; + import { StyledCardHeader } from "@/app-components/card/StyledCardHeader"; import { useFindStats } from "@/hooks/entities/bot-stat-hooks"; +import { useTranslate } from "@/hooks/useTranslate"; import { ColumnChartStats } from "@/types/bot-stat.types"; import { buildColumnChartConfig } from "@/utils/chart"; import { NoDataChart } from "./NoDataChart"; const PopularChart = () => { - const { t } = useTranslation(); + const { t } = useTranslate(); const { data } = useFindStats("popularBlocks"); return ( diff --git a/frontend/src/components/dashboard/index.tsx b/frontend/src/components/dashboard/index.tsx index 7cc6fd10..bd69b8fc 100644 --- a/frontend/src/components/dashboard/index.tsx +++ b/frontend/src/components/dashboard/index.tsx @@ -9,8 +9,8 @@ import Home from "@mui/icons-material/Home"; import { Grid, GridProps } from "@mui/material"; import { PropsWithChildren } from "react"; -import { useTranslation } from "react-i18next"; +import { useTranslate } from "@/hooks/useTranslate"; import { PageHeader } from "@/layout/content/PageHeader"; import AudienceChart from "./AudienceChart"; @@ -23,7 +23,7 @@ const DashboardContent = (props: PropsWithChildren) => ( ); export const Dashboard = () => { - const { t } = useTranslation(); + const { t } = useTranslate(); return ( diff --git a/frontend/src/components/inbox/components/AttachmentViewer.tsx b/frontend/src/components/inbox/components/AttachmentViewer.tsx index 76da28a4..26da61bc 100644 --- a/frontend/src/components/inbox/components/AttachmentViewer.tsx +++ b/frontend/src/components/inbox/components/AttachmentViewer.tsx @@ -9,10 +9,11 @@ import DownloadIcon from "@mui/icons-material/Download"; import { Button, Dialog, DialogContent } from "@mui/material"; import { FC } from "react"; -import { useTranslation } from "react-i18next"; + import { DialogTitle } from "@/app-components/dialogs"; import { useDialog } from "@/hooks/useDialog"; +import { useTranslate } from "@/hooks/useTranslate"; import { AttachmentAttrs, FileType, @@ -68,7 +69,7 @@ const componentMap: { [key in FileType]: FC } = { return