diff --git a/offline_node_modules/cross-fetch-npm-4.0.0-9c67668db4-386727dc4c.zip b/offline_node_modules/cross-fetch-npm-4.0.0-9c67668db4-386727dc4c.zip
new file mode 100644
index 0000000..ce69d2d
Binary files /dev/null and b/offline_node_modules/cross-fetch-npm-4.0.0-9c67668db4-386727dc4c.zip differ
diff --git a/offline_node_modules/html-parse-stringify-npm-3.0.1-5762cd4b01-159292753d.zip b/offline_node_modules/html-parse-stringify-npm-3.0.1-5762cd4b01-159292753d.zip
new file mode 100644
index 0000000..8209aea
Binary files /dev/null and b/offline_node_modules/html-parse-stringify-npm-3.0.1-5762cd4b01-159292753d.zip differ
diff --git a/offline_node_modules/i18next-browser-languagedetector-npm-8.0.0-fcff5207d7-08a7c747ec.zip b/offline_node_modules/i18next-browser-languagedetector-npm-8.0.0-fcff5207d7-08a7c747ec.zip
new file mode 100644
index 0000000..1fc7616
Binary files /dev/null and b/offline_node_modules/i18next-browser-languagedetector-npm-8.0.0-fcff5207d7-08a7c747ec.zip differ
diff --git a/offline_node_modules/i18next-http-backend-npm-2.5.2-6cbbe5e7c3-57cfbeeea4.zip b/offline_node_modules/i18next-http-backend-npm-2.5.2-6cbbe5e7c3-57cfbeeea4.zip
new file mode 100644
index 0000000..1d004dd
Binary files /dev/null and b/offline_node_modules/i18next-http-backend-npm-2.5.2-6cbbe5e7c3-57cfbeeea4.zip differ
diff --git a/offline_node_modules/i18next-npm-23.11.5-27df1f473c-b0bec64250.zip b/offline_node_modules/i18next-npm-23.11.5-27df1f473c-b0bec64250.zip
new file mode 100644
index 0000000..b6e08f2
Binary files /dev/null and b/offline_node_modules/i18next-npm-23.11.5-27df1f473c-b0bec64250.zip differ
diff --git a/offline_node_modules/node-fetch-npm-2.7.0-587d57004e-b55786b602.zip b/offline_node_modules/node-fetch-npm-2.7.0-587d57004e-b55786b602.zip
new file mode 100644
index 0000000..43a929c
Binary files /dev/null and b/offline_node_modules/node-fetch-npm-2.7.0-587d57004e-b55786b602.zip differ
diff --git a/offline_node_modules/react-i18next-npm-14.1.2-9873475bd7-cb8a83b369.zip b/offline_node_modules/react-i18next-npm-14.1.2-9873475bd7-cb8a83b369.zip
new file mode 100644
index 0000000..a21ea6f
Binary files /dev/null and b/offline_node_modules/react-i18next-npm-14.1.2-9873475bd7-cb8a83b369.zip differ
diff --git a/offline_node_modules/tr46-npm-0.0.3-de53018915-047cb209a6.zip b/offline_node_modules/tr46-npm-0.0.3-de53018915-047cb209a6.zip
new file mode 100644
index 0000000..6928ef0
Binary files /dev/null and b/offline_node_modules/tr46-npm-0.0.3-de53018915-047cb209a6.zip differ
diff --git a/offline_node_modules/void-elements-npm-3.1.0-4f43780839-0b8686f9f9.zip b/offline_node_modules/void-elements-npm-3.1.0-4f43780839-0b8686f9f9.zip
new file mode 100644
index 0000000..b05b8d8
Binary files /dev/null and b/offline_node_modules/void-elements-npm-3.1.0-4f43780839-0b8686f9f9.zip differ
diff --git a/offline_node_modules/webidl-conversions-npm-3.0.1-60310f6a2b-5612d5f3e5.zip b/offline_node_modules/webidl-conversions-npm-3.0.1-60310f6a2b-5612d5f3e5.zip
new file mode 100644
index 0000000..dda75f1
Binary files /dev/null and b/offline_node_modules/webidl-conversions-npm-3.0.1-60310f6a2b-5612d5f3e5.zip differ
diff --git a/offline_node_modules/whatwg-url-npm-5.0.0-374fb45e60-1588bed84d.zip b/offline_node_modules/whatwg-url-npm-5.0.0-374fb45e60-1588bed84d.zip
new file mode 100644
index 0000000..7c03e0b
Binary files /dev/null and b/offline_node_modules/whatwg-url-npm-5.0.0-374fb45e60-1588bed84d.zip differ
diff --git a/package.json b/package.json
index a55b35e..4eb8def 100644
--- a/package.json
+++ b/package.json
@@ -38,12 +38,16 @@
"@mui/material": "5.15.19",
"@react-spring/web": "9.7.3",
"classnames": "2.5.1",
+ "i18next": "23.11.5",
+ "i18next-browser-languagedetector": "8.0.0",
+ "i18next-http-backend": "2.5.2",
"notistack": "3.0.1",
"prop-types": "15.8.1",
"react": "18.3.1",
"react-dnd": "16.0.1",
"react-dnd-html5-backend": "16.0.1",
"react-dom": "18.3.1",
+ "react-i18next": "14.1.2",
"react-router-dom": "6.23.1",
"workbox-core": "7.1.0",
"workbox-precaching": "7.1.0",
diff --git a/public/locales/en/analyze-page.json b/public/locales/en/analyze-page.json
new file mode 100644
index 0000000..56146e7
--- /dev/null
+++ b/public/locales/en/analyze-page.json
@@ -0,0 +1,4 @@
+{
+ "title": "Analyze Page",
+ "toolbar": "Analyze Page Toolbar"
+}
diff --git a/public/locales/en/error-page.json b/public/locales/en/error-page.json
new file mode 100644
index 0000000..152f171
--- /dev/null
+++ b/public/locales/en/error-page.json
@@ -0,0 +1,5 @@
+{
+ "title": "Something goes wrong",
+ "toolbar": "Unhandled error",
+ "404-toolbar": "Page does not exist"
+}
diff --git a/public/locales/en/payments-page.json b/public/locales/en/payments-page.json
new file mode 100644
index 0000000..660f4e4
--- /dev/null
+++ b/public/locales/en/payments-page.json
@@ -0,0 +1,4 @@
+{
+ "title": "Payments Page",
+ "toolbar": "Payments Page Toolbar"
+}
diff --git a/public/locales/en/schedule-page.json b/public/locales/en/schedule-page.json
new file mode 100644
index 0000000..725796b
--- /dev/null
+++ b/public/locales/en/schedule-page.json
@@ -0,0 +1,4 @@
+{
+ "title": "Schedule Page",
+ "toolbar": "Schedule Page Toolbar"
+}
diff --git a/public/locales/en/sidebar.json b/public/locales/en/sidebar.json
new file mode 100644
index 0000000..ef6d9f5
--- /dev/null
+++ b/public/locales/en/sidebar.json
@@ -0,0 +1,5 @@
+{
+ "analyze-page-link": "Analyze",
+ "payments-page-link": "Payments list",
+ "schedule-page-link": "Schedule"
+}
diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json
new file mode 100644
index 0000000..0e2341f
--- /dev/null
+++ b/public/locales/en/translation.json
@@ -0,0 +1,3 @@
+{
+ "language": "English"
+}
diff --git a/public/locales/ru/analyze-page.json b/public/locales/ru/analyze-page.json
new file mode 100644
index 0000000..9f9b429
--- /dev/null
+++ b/public/locales/ru/analyze-page.json
@@ -0,0 +1,4 @@
+{
+ "title": "Аналитика",
+ "toolbar": "Доска аналитики"
+}
diff --git a/public/locales/ru/error-page.json b/public/locales/ru/error-page.json
new file mode 100644
index 0000000..1b5a8cd
--- /dev/null
+++ b/public/locales/ru/error-page.json
@@ -0,0 +1,5 @@
+{
+ "title": "Что-то пошло не так",
+ "toolbar": "Произошла непредвиденная ошибка",
+ "404-toolbar": "Такой страницы не существует"
+}
diff --git a/public/locales/ru/payments-page.json b/public/locales/ru/payments-page.json
new file mode 100644
index 0000000..f5a3a68
--- /dev/null
+++ b/public/locales/ru/payments-page.json
@@ -0,0 +1,4 @@
+{
+ "title": "Платежи",
+ "toolbar": "Доска платежей"
+}
diff --git a/public/locales/ru/schedule-page.json b/public/locales/ru/schedule-page.json
new file mode 100644
index 0000000..3246bc4
--- /dev/null
+++ b/public/locales/ru/schedule-page.json
@@ -0,0 +1,4 @@
+{
+ "title": "График платежей",
+ "toolbar": "Доска графика платежей"
+}
diff --git a/public/locales/ru/sidebar.json b/public/locales/ru/sidebar.json
new file mode 100644
index 0000000..37b2a7f
--- /dev/null
+++ b/public/locales/ru/sidebar.json
@@ -0,0 +1,5 @@
+{
+ "analyze-page-link": "Аналитика",
+ "payments-page-link": "Список платежей",
+ "schedule-page-link": "График платежей"
+}
diff --git a/public/locales/ru/translation.json b/public/locales/ru/translation.json
new file mode 100644
index 0000000..0bb9424
--- /dev/null
+++ b/public/locales/ru/translation.json
@@ -0,0 +1,3 @@
+{
+ "language": "Русский"
+}
diff --git a/src/apps/MoneyControllApp/model/providers/RouterProvider/index.tsx b/src/apps/MoneyControllApp/model/providers/RouterProvider/index.tsx
index 5798b35..7407b88 100644
--- a/src/apps/MoneyControllApp/model/providers/RouterProvider/index.tsx
+++ b/src/apps/MoneyControllApp/model/providers/RouterProvider/index.tsx
@@ -1,8 +1,8 @@
import CalendarMonthIcon from '@mui/icons-material/CalendarMonth';
import FormatListBulletedIcon from '@mui/icons-material/FormatListBulleted';
import PieChartIcon from '@mui/icons-material/PieChart';
-import CircularProgress from '@mui/material/CircularProgress';
import { Suspense } from 'react';
+import { useTranslation } from 'react-i18next';
import { createBrowserRouter, Navigate, RouterProvider as RRDRouterProvider } from 'react-router-dom';
import { AnalyzePage, AnalyzePageToolbar } from 'pages/AnalyzePage';
@@ -11,6 +11,7 @@ import { PaymentsPage, PaymentsPageToolbar } from 'pages/PaymentsPage';
import { SchedulePage, SchedulePageToolbar } from 'pages/SchedulePage';
import { AsideMenuLayout } from 'widgets/AsideMenuLayout';
+import { PageLoader } from 'widgets/PageLoader';
import type { ReactNode } from 'react';
import type { RouteObject } from 'react-router-dom';
@@ -23,76 +24,78 @@ type PageListItem = {
Toolbar?: ReactNode;
};
-const pages: PageListItem[] = [
- {
- icon: ,
- title: 'Аналитика',
- path: '/analyze',
- Content: (
- }>
-
-
- ),
- Toolbar: ,
- },
- {
- icon: ,
- title: 'График платежей',
- path: '/schedule',
- Content: (
- }>
-
-
- ),
- Toolbar: ,
- },
- {
- icon: ,
- title: 'Список платежей',
- path: '/payments',
- Content: (
- }>
-
-
- ),
- Toolbar: ,
- },
-];
+const RouterProvider = () => {
+ const { t } = useTranslation('sidebar');
-const routes: RouteObject[] = pages.map((page) => ({
- path: page.path,
- element: (
+ const pages: PageListItem[] = [
+ {
+ icon: ,
+ title: t('analyze-page-link'),
+ path: '/analyze',
+ Content: ,
+ Toolbar: ,
+ },
+ {
+ icon: ,
+ title: t('schedule-page-link'),
+ path: '/schedule',
+ Content: ,
+ Toolbar: ,
+ },
+ {
+ icon: ,
+ title: t('payments-page-link'),
+ path: '/payments',
+ Content: ,
+ Toolbar: ,
+ },
+ ];
+ const Fallback = (
}
pages={pages}
- Toolbar={page.Toolbar}
/>
- ),
- errorElement: (
- }
- pages={pages}
- Toolbar={}
- />
- ),
-}));
-const router = createBrowserRouter([
- ...routes,
- {
- path: '/',
- element: ,
+ );
+ const routes: RouteObject[] = pages.map((page) => ({
+ path: page.path,
+ element: (
+
+
+
+ ),
errorElement: (
- }
- pages={pages}
- Toolbar={}
- />
+
+ }
+ pages={pages}
+ Toolbar={}
+ />
+
),
- },
-]);
+ }));
-const RouterProvider = () => (
-
-);
+ const router = createBrowserRouter([
+ ...routes,
+ {
+ path: '/',
+ element: ,
+ errorElement: (
+ }
+ pages={pages}
+ Toolbar={}
+ />
+ ),
+ },
+ ]);
+
+ return (
+
+ );
+};
export default RouterProvider;
diff --git a/src/features/LangSwitcher/index.ts b/src/features/LangSwitcher/index.ts
new file mode 100644
index 0000000..57ad91e
--- /dev/null
+++ b/src/features/LangSwitcher/index.ts
@@ -0,0 +1 @@
+export { default as LangSwitcher } from './ui/LangSwitcher.ui';
diff --git a/src/features/LangSwitcher/ui/LangSwitcher.ui.tsx b/src/features/LangSwitcher/ui/LangSwitcher.ui.tsx
new file mode 100644
index 0000000..9bea81a
--- /dev/null
+++ b/src/features/LangSwitcher/ui/LangSwitcher.ui.tsx
@@ -0,0 +1,30 @@
+import { useCallback } from 'react';
+import { useTranslation } from 'react-i18next';
+
+import i18next from 'i18n';
+
+import { LANGUAGE } from 'shared/constants';
+
+import type { FC, ChangeEventHandler } from 'react';
+
+const LangSwitcher: FC = () => {
+ const { i18n } = useTranslation();
+
+ const onChangedHandler = useCallback>(async (e) => {
+ await i18next.changeLanguage(e.target.value);
+ }, []);
+
+ return (
+
+ );
+};
+
+export default LangSwitcher;
diff --git a/src/i18n.ts b/src/i18n.ts
new file mode 100644
index 0000000..46125c8
--- /dev/null
+++ b/src/i18n.ts
@@ -0,0 +1,22 @@
+import i18n from 'i18next';
+import LanguageDetector from 'i18next-browser-languagedetector';
+import Backend from 'i18next-http-backend';
+import { initReactI18next } from 'react-i18next';
+
+import type { HttpBackendOptions } from 'i18next-http-backend';
+
+// eslint-disable-next-line @typescript-eslint/no-floating-promises
+i18n
+ .use(Backend)
+ .use(LanguageDetector)
+ .use(initReactI18next)
+ .init({
+ fallbackLng: 'en',
+ debug: process.env.NODE_ENV === 'development',
+ load: 'currentOnly',
+ backend: {
+ loadPath: 'locales/{{lng}}/{{ns}}.json',
+ },
+ });
+
+export default i18n;
diff --git a/src/index.tsx b/src/index.tsx
index 0c08c2e..a12cf2f 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,3 +1,4 @@
+import './i18n';
import 'shared/styles/fonts/fonts.css';
import React from 'react';
import { createRoot } from 'react-dom/client';
diff --git a/src/pages/AnalyzePage/ui/AnalyzePage.ui.tsx b/src/pages/AnalyzePage/ui/AnalyzePage.ui.tsx
index 410145c..8d5b83d 100644
--- a/src/pages/AnalyzePage/ui/AnalyzePage.ui.tsx
+++ b/src/pages/AnalyzePage/ui/AnalyzePage.ui.tsx
@@ -1,10 +1,16 @@
+import { useTranslation } from 'react-i18next';
+
import type { DetailedHTMLProps, FC, HTMLAttributes } from 'react';
type AnalyzePageProps = DetailedHTMLProps, HTMLDivElement>;
-const AnalyzePage: FC = (props) => (
-
- Analyze page
-
-);
+const AnalyzePage: FC = (props) => {
+ const { t } = useTranslation('analyze-page');
+
+ return (
+
+ {t('title')}
+
+ );
+};
export default AnalyzePage;
diff --git a/src/pages/AnalyzePage/ui/AnalyzePageToolbar.ui.tsx b/src/pages/AnalyzePage/ui/AnalyzePageToolbar.ui.tsx
index 8fbac9c..c219ea6 100644
--- a/src/pages/AnalyzePage/ui/AnalyzePageToolbar.ui.tsx
+++ b/src/pages/AnalyzePage/ui/AnalyzePageToolbar.ui.tsx
@@ -1,15 +1,20 @@
import Toolbar from '@mui/material/Toolbar';
import Typography from '@mui/material/Typography';
+import { useTranslation } from 'react-i18next';
import type { ToolbarProps } from '@mui/material/Toolbar/Toolbar';
import type { FC } from 'react';
type AnalyzePageToolbarProps = ToolbarProps;
-const AnalyzePageToolbar: FC = (props) => (
-
-
- Analyze Page Toolbar
-
-
-);
+const AnalyzePageToolbar: FC = (props) => {
+ const { t } = useTranslation('analyze-page');
+
+ return (
+
+
+ {t('toolbar')}
+
+
+ );
+};
export default AnalyzePageToolbar;
diff --git a/src/pages/ErrorPage/ui/ErrorPage.ui.tsx b/src/pages/ErrorPage/ui/ErrorPage.ui.tsx
index 398fe9e..8fc1cdf 100644
--- a/src/pages/ErrorPage/ui/ErrorPage.ui.tsx
+++ b/src/pages/ErrorPage/ui/ErrorPage.ui.tsx
@@ -1,5 +1,6 @@
import { Grid } from '@mui/material';
import Typography from '@mui/material/Typography';
+import { useTranslation } from 'react-i18next';
import _404Image from 'public/assets/images/404.png';
import OopsImage from 'public/assets/images/oops.png';
@@ -16,6 +17,8 @@ const ErrorPage: FC = (props) => {
...restProps
} = props;
+ const { t } = useTranslation('error-page');
+
if (type === 'ErrorBoundary') {
return (
= (props) => {
>
- Что-то пошло не так
+ {t('title')}
diff --git a/src/pages/ErrorPage/ui/ErrorPageToolbar.ui.tsx b/src/pages/ErrorPage/ui/ErrorPageToolbar.ui.tsx
index a92fca7..17c42c1 100644
--- a/src/pages/ErrorPage/ui/ErrorPageToolbar.ui.tsx
+++ b/src/pages/ErrorPage/ui/ErrorPageToolbar.ui.tsx
@@ -1,5 +1,6 @@
import Toolbar from '@mui/material/Toolbar';
import Typography from '@mui/material/Typography';
+import { useTranslation } from 'react-i18next';
import type { ToolbarProps } from '@mui/material/Toolbar/Toolbar';
import type { FC } from 'react';
@@ -8,17 +9,19 @@ export type ErrorPageToolbarProps = ToolbarProps & {
type?: '404' | 'ErrorBoundary';
};
-const TITLE: Record, string> = {
- 404: 'Страницы не существует',
- ErrorBoundary: 'Непредвиденная ошибка',
-};
-
const ErrorPageToolbar: FC = (props) => {
const {
type = 'ErrorBoundary',
...restProps
} = props;
+ const { t } = useTranslation('error-page');
+
+ const TITLE: Record, string> = {
+ 404: t('404-toolbar'),
+ ErrorBoundary: t('toolbar'),
+ };
+
return (
diff --git a/src/pages/PaymentsPage/ui/PaymentsPage.ui.tsx b/src/pages/PaymentsPage/ui/PaymentsPage.ui.tsx
index d15c64b..4661b2b 100644
--- a/src/pages/PaymentsPage/ui/PaymentsPage.ui.tsx
+++ b/src/pages/PaymentsPage/ui/PaymentsPage.ui.tsx
@@ -1,10 +1,16 @@
+import { useTranslation } from 'react-i18next';
+
import type { DetailedHTMLProps, FC, HTMLAttributes } from 'react';
export type PaymentsPageProps = DetailedHTMLProps, HTMLDivElement>;
-const PaymentsPage: FC = (props) => (
-
- Payments Page
-
-);
+const PaymentsPage: FC = (props) => {
+ const { t } = useTranslation('payments-page');
+
+ return (
+
+ {t('title')}
+
+ );
+};
export default PaymentsPage;
diff --git a/src/pages/PaymentsPage/ui/PaymentsPageToolbar.ui.tsx b/src/pages/PaymentsPage/ui/PaymentsPageToolbar.ui.tsx
index 472229f..6e93b5f 100644
--- a/src/pages/PaymentsPage/ui/PaymentsPageToolbar.ui.tsx
+++ b/src/pages/PaymentsPage/ui/PaymentsPageToolbar.ui.tsx
@@ -1,16 +1,21 @@
import Toolbar from '@mui/material/Toolbar';
import Typography from '@mui/material/Typography';
+import { useTranslation } from 'react-i18next';
import type { ToolbarProps } from '@mui/material/Toolbar/Toolbar';
import type { FC } from 'react';
export type PaymentsPageToolbarProps = ToolbarProps;
-const PaymentsPageToolbar: FC = (props) => (
-
-
- Payments Page Toolbar
-
-
-);
+const PaymentsPageToolbar: FC = (props) => {
+ const { t } = useTranslation('payments-page');
+
+ return (
+
+
+ {t('toolbar')}
+
+
+ );
+};
export default PaymentsPageToolbar;
diff --git a/src/pages/SchedulePage/ui/SchedulePage.ui.tsx b/src/pages/SchedulePage/ui/SchedulePage.ui.tsx
index 31a5d2f..ebd3dd8 100644
--- a/src/pages/SchedulePage/ui/SchedulePage.ui.tsx
+++ b/src/pages/SchedulePage/ui/SchedulePage.ui.tsx
@@ -1,10 +1,16 @@
+import { useTranslation } from 'react-i18next';
+
import type { DetailedHTMLProps, FC, HTMLAttributes } from 'react';
export type SchedulePageProps = DetailedHTMLProps, HTMLDivElement>;
-const SchedulePage: FC = (props) => (
-
- Schedule Page
-
-);
+const SchedulePage: FC = (props) => {
+ const { t } = useTranslation('schedule-page');
+
+ return (
+
+ {t('title')}
+
+ );
+};
export default SchedulePage;
diff --git a/src/pages/SchedulePage/ui/SchedulePageToolbar.ui.tsx b/src/pages/SchedulePage/ui/SchedulePageToolbar.ui.tsx
index 38f5013..36b7d18 100644
--- a/src/pages/SchedulePage/ui/SchedulePageToolbar.ui.tsx
+++ b/src/pages/SchedulePage/ui/SchedulePageToolbar.ui.tsx
@@ -1,16 +1,21 @@
import Toolbar from '@mui/material/Toolbar';
import Typography from '@mui/material/Typography';
+import { useTranslation } from 'react-i18next';
import type { ToolbarProps } from '@mui/material/Toolbar/Toolbar';
import type { FC } from 'react';
type SchedulePageToolbarProps = ToolbarProps;
-const SchedulePageToolbar: FC = (props) => (
-
-
- Schedule Page Toolbar
-
-
-);
+const SchedulePageToolbar: FC = (props) => {
+ const { t } = useTranslation('schedule-page');
+
+ return (
+
+
+ {t('toolbar')}
+
+
+ );
+};
export default SchedulePageToolbar;
diff --git a/src/shared/constants/index.ts b/src/shared/constants/index.ts
index 44822ee..591e37f 100644
--- a/src/shared/constants/index.ts
+++ b/src/shared/constants/index.ts
@@ -1,5 +1,5 @@
export { DAYS_IN_WEEK, MONTHS, WEEK_DAYS } from './date';
-export { MONTHS_LABEL, WEEK_DAYS_LABEL } from './locale';
+export { MONTHS_LABEL, WEEK_DAYS_LABEL, LANGUAGE } from './locale';
export type {
MonthsKeys,
MonthsValues,
diff --git a/src/shared/constants/locale.ts b/src/shared/constants/locale.ts
index 5c799e9..f4a1ed4 100644
--- a/src/shared/constants/locale.ts
+++ b/src/shared/constants/locale.ts
@@ -136,3 +136,14 @@ export const WEEK_DAYS_LABEL: Record = {
},
},
};
+
+export const LANGUAGE = {
+ ru: {
+ name: 'Русский',
+ emoji: '🇷🇺',
+ },
+ en: {
+ name: 'English',
+ emoji: '🇬🇧',
+ },
+};
diff --git a/src/widgets/AsideMenuLayout/ui/AsideMenuLayout.ui.tsx b/src/widgets/AsideMenuLayout/ui/AsideMenuLayout.ui.tsx
index f2fdb6a..92674d7 100644
--- a/src/widgets/AsideMenuLayout/ui/AsideMenuLayout.ui.tsx
+++ b/src/widgets/AsideMenuLayout/ui/AsideMenuLayout.ui.tsx
@@ -7,6 +7,8 @@ import { animated, useTransition } from '@react-spring/web';
import { useContext } from 'react';
import { useLocation } from 'react-router-dom';
+import { LangSwitcher } from 'features/LangSwitcher';
+
import { DesktopAppBar, MobileAppBar } from './components/AppBar';
import { AsideMenuContext, AsideMenuProvider } from './components/AsideMenuProvider';
import { DesktopDrawer } from './components/DesktopDrawer';
@@ -15,6 +17,7 @@ import { MobileDrawer } from './components/MobileDrawer';
import type { MenuItemProps } from './components/MenuItem/ui/MenuItem.ui';
import type { BoxProps } from '@mui/material/Box/Box';
+// eslint-disable-next-line import/max-dependencies
import type { FC, ReactNode } from 'react';
export const DESKTOP_DRAWER_WIDTH = 250;
@@ -32,7 +35,6 @@ const AsideMenuLayout: FC = (props) => {
Toolbar,
...restProps
} = props;
-
const { desktopDrawerOpen, setMobileDrawerOpen } = useContext(AsideMenuContext);
const theme = useTheme();
const isMobileView = useMediaQuery(theme.breakpoints.down('sm'));
@@ -49,7 +51,7 @@ const AsideMenuLayout: FC = (props) => {
const AnimatedContent = (
<>
{transitions((styles) => (
-
+
{Content}
))}
@@ -85,6 +87,8 @@ const AsideMenuLayout: FC = (props) => {
{AnimatedToolBar}
+
+
)
}
@@ -113,14 +117,16 @@ const AsideMenuLayout: FC = (props) => {
-
+
{ Boolean(Toolbar) && (
{AnimatedToolBar}
+
+
)}
-
+
{AnimatedContent}
diff --git a/src/widgets/PageLoader/index.ts b/src/widgets/PageLoader/index.ts
new file mode 100644
index 0000000..d658126
--- /dev/null
+++ b/src/widgets/PageLoader/index.ts
@@ -0,0 +1 @@
+export { default as PageLoader } from './ui/PageLoader.ui';
diff --git a/src/widgets/PageLoader/ui/PageLoader.ui.tsx b/src/widgets/PageLoader/ui/PageLoader.ui.tsx
new file mode 100644
index 0000000..bc3a384
--- /dev/null
+++ b/src/widgets/PageLoader/ui/PageLoader.ui.tsx
@@ -0,0 +1,20 @@
+import CircularProgress from '@mui/material/CircularProgress';
+import { styled } from '@mui/material/styles';
+
+const CenteredDiv = styled('div')(
+ () => ({
+ width: '100%',
+ height: '100%',
+ display: 'flex',
+ justifyContent: 'center',
+ alignItems: 'center',
+ }),
+);
+
+const PageLoader = () => (
+
+
+
+);
+
+export default PageLoader;
diff --git a/yarn.lock b/yarn.lock
index d0789be..0a9ebbf 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2671,7 +2671,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/runtime@npm:^7.11.2":
+"@babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.23.2":
version: 7.24.7
resolution: "@babel/runtime@npm:7.24.7"
dependencies:
@@ -7769,6 +7769,15 @@ __metadata:
languageName: node
linkType: hard
+"cross-fetch@npm:4.0.0":
+ version: 4.0.0
+ resolution: "cross-fetch@npm:4.0.0"
+ dependencies:
+ node-fetch: "npm:^2.6.12"
+ checksum: 10c0/386727dc4c6b044746086aced959ff21101abb85c43df5e1d151547ccb6f338f86dec3f28b9dbddfa8ff5b9ec8662ed2263ad4607a93b2dc354fb7fe3bbb898a
+ languageName: node
+ linkType: hard
+
"cross-spawn@npm:7.0.3, cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3":
version: 7.0.3
resolution: "cross-spawn@npm:7.0.3"
@@ -10579,6 +10588,15 @@ __metadata:
languageName: node
linkType: hard
+"html-parse-stringify@npm:^3.0.1":
+ version: 3.0.1
+ resolution: "html-parse-stringify@npm:3.0.1"
+ dependencies:
+ void-elements: "npm:3.1.0"
+ checksum: 10c0/159292753d48b84d216d61121054ae5a33466b3db5b446e2ffc093ac077a411a99ce6cbe0d18e55b87cf25fa3c5a86c4d8b130b9719ec9b66623259000c72c15
+ languageName: node
+ linkType: hard
+
"html-webpack-plugin@npm:5.6.0":
version: 5.6.0
resolution: "html-webpack-plugin@npm:5.6.0"
@@ -10751,6 +10769,33 @@ __metadata:
languageName: node
linkType: hard
+"i18next-browser-languagedetector@npm:8.0.0":
+ version: 8.0.0
+ resolution: "i18next-browser-languagedetector@npm:8.0.0"
+ dependencies:
+ "@babel/runtime": "npm:^7.23.2"
+ checksum: 10c0/08a7c747ec18a0743b54390a0b42836d814b15fb49c92b90c259298e6a6e7e001ff9df99d0fd308283a34fceea53b4d9053aa1695a37f696bc04160017bbb524
+ languageName: node
+ linkType: hard
+
+"i18next-http-backend@npm:2.5.2":
+ version: 2.5.2
+ resolution: "i18next-http-backend@npm:2.5.2"
+ dependencies:
+ cross-fetch: "npm:4.0.0"
+ checksum: 10c0/57cfbeeea40a751134e1521fac89b14b780c9ad87b74a4f7d7168a88a8b603efed9f5df455dddbb408f7e268eae5aa0a6888e47b9f10cb9482d812d4d6997ffa
+ languageName: node
+ linkType: hard
+
+"i18next@npm:23.11.5":
+ version: 23.11.5
+ resolution: "i18next@npm:23.11.5"
+ dependencies:
+ "@babel/runtime": "npm:^7.23.2"
+ checksum: 10c0/b0bec64250a3e529d4c51e2fc511406a85c5dde3d005d3aabe919551ca31dfc0a8f5490bf6e44649822e895a1fa91a58092d112367669cd11b2eb89e6ba90d1a
+ languageName: node
+ linkType: hard
+
"iconv-lite@npm:0.4.24":
version: 0.4.24
resolution: "iconv-lite@npm:0.4.24"
@@ -13039,6 +13084,9 @@ __metadata:
eslint-config-ksv741: "npm:0.0.3"
eslint-import-resolver-webpack: "npm:0.13.8"
husky: "npm:9.0.11"
+ i18next: "npm:23.11.5"
+ i18next-browser-languagedetector: "npm:8.0.0"
+ i18next-http-backend: "npm:2.5.2"
identity-obj-proxy: "npm:3.0.0"
jest: "npm:29.7.0"
jest-environment-jsdom: "npm:29.7.0"
@@ -13050,6 +13098,7 @@ __metadata:
react-dnd: "npm:16.0.1"
react-dnd-html5-backend: "npm:16.0.1"
react-dom: "npm:18.3.1"
+ react-i18next: "npm:14.1.2"
react-router-dom: "npm:6.23.1"
standard-version: "npm:9.5.0"
ts-jest: "npm:29.1.4"
@@ -13156,6 +13205,20 @@ __metadata:
languageName: node
linkType: hard
+"node-fetch@npm:^2.6.12":
+ version: 2.7.0
+ resolution: "node-fetch@npm:2.7.0"
+ dependencies:
+ whatwg-url: "npm:^5.0.0"
+ peerDependencies:
+ encoding: ^0.1.0
+ peerDependenciesMeta:
+ encoding:
+ optional: true
+ checksum: 10c0/b55786b6028208e6fbe594ccccc213cab67a72899c9234eb59dba51062a299ea853210fcf526998eaa2867b0963ad72338824450905679ff0fa304b8c5093ae8
+ languageName: node
+ linkType: hard
+
"node-forge@npm:^1":
version: 1.3.1
resolution: "node-forge@npm:1.3.1"
@@ -14857,6 +14920,24 @@ __metadata:
languageName: node
linkType: hard
+"react-i18next@npm:14.1.2":
+ version: 14.1.2
+ resolution: "react-i18next@npm:14.1.2"
+ dependencies:
+ "@babel/runtime": "npm:^7.23.9"
+ html-parse-stringify: "npm:^3.0.1"
+ peerDependencies:
+ i18next: ">= 23.2.3"
+ react: ">= 16.8.0"
+ peerDependenciesMeta:
+ react-dom:
+ optional: true
+ react-native:
+ optional: true
+ checksum: 10c0/cb8a83b3696639f083dc9f770d9d9e0681c0fe56f6b5fe24cd6facce08d363c37bd3440078e9d63abacabd7037b783e6b4e4d0c935de9c8dda7820bd4ef7e329
+ languageName: node
+ linkType: hard
+
"react-is@npm:^16.13.1, react-is@npm:^16.7.0":
version: 16.13.1
resolution: "react-is@npm:16.13.1"
@@ -16587,6 +16668,13 @@ __metadata:
languageName: node
linkType: hard
+"tr46@npm:~0.0.3":
+ version: 0.0.3
+ resolution: "tr46@npm:0.0.3"
+ checksum: 10c0/047cb209a6b60c742f05c9d3ace8fa510bff609995c129a37ace03476a9b12db4dbf975e74600830ef0796e18882b2381fb5fb1f6b4f96b832c374de3ab91a11
+ languageName: node
+ linkType: hard
+
"trim-newlines@npm:^3.0.0":
version: 3.0.1
resolution: "trim-newlines@npm:3.0.1"
@@ -17134,6 +17222,13 @@ __metadata:
languageName: node
linkType: hard
+"void-elements@npm:3.1.0":
+ version: 3.1.0
+ resolution: "void-elements@npm:3.1.0"
+ checksum: 10c0/0b8686f9f9aa44012e9bd5eabf287ae0cde409b9a2854c5a2335cb83920c957668ac5876e3f0d158dd424744ac411a7270e64128556b451ed3bec875ef18534d
+ languageName: node
+ linkType: hard
+
"w3c-xmlserializer@npm:^4.0.0":
version: 4.0.0
resolution: "w3c-xmlserializer@npm:4.0.0"
@@ -17171,6 +17266,13 @@ __metadata:
languageName: node
linkType: hard
+"webidl-conversions@npm:^3.0.0":
+ version: 3.0.1
+ resolution: "webidl-conversions@npm:3.0.1"
+ checksum: 10c0/5612d5f3e54760a797052eb4927f0ddc01383550f542ccd33d5238cfd65aeed392a45ad38364970d0a0f4fea32e1f4d231b3d8dac4a3bdd385e5cf802ae097db
+ languageName: node
+ linkType: hard
+
"webidl-conversions@npm:^4.0.2":
version: 4.0.2
resolution: "webidl-conversions@npm:4.0.2"
@@ -17415,6 +17517,16 @@ __metadata:
languageName: node
linkType: hard
+"whatwg-url@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "whatwg-url@npm:5.0.0"
+ dependencies:
+ tr46: "npm:~0.0.3"
+ webidl-conversions: "npm:^3.0.0"
+ checksum: 10c0/1588bed84d10b72d5eec1d0faa0722ba1962f1821e7539c535558fb5398d223b0c50d8acab950b8c488b4ba69043fd833cc2697056b167d8ad46fac3995a55d5
+ languageName: node
+ linkType: hard
+
"whatwg-url@npm:^7.0.0":
version: 7.1.0
resolution: "whatwg-url@npm:7.1.0"