From afb430b9819265d6f81b4d6fbb4614d842bd8257 Mon Sep 17 00:00:00 2001 From: "jason.lam" Date: Tue, 2 Jan 2024 17:39:26 +0800 Subject: [PATCH] i18n: apply l10n selector --- package.json | 1 + src/components/I18nProvider.js | 47 ++++++ src/index.js | 7 +- .../Header/HeaderContent/LocaleSelector.js | 142 ++++++++++++++++++ .../MainLayout/Header/HeaderContent/index.js | 3 +- src/layout/MainLayout/Header/index.js | 3 + .../auth-forms/AuthLoginCustom.js | 7 +- src/translations/en.json | 10 ++ src/translations/zh-CN.json | 10 ++ src/translations/zh-HK.json | 10 ++ 10 files changed, 236 insertions(+), 4 deletions(-) create mode 100644 src/components/I18nProvider.js create mode 100644 src/layout/MainLayout/Header/HeaderContent/LocaleSelector.js create mode 100644 src/translations/en.json create mode 100644 src/translations/zh-CN.json create mode 100644 src/translations/zh-HK.json diff --git a/package.json b/package.json index 6f512ac..da7ce49 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "react-to-print": "^2.14.13", "react-toastify": "^9.1.3", "react-window": "^1.8.7", + "react-intl": "^6.4.7", "redux": "^4.2.0", "simplebar": "^5.3.8", "simplebar-react": "^2.4.1", diff --git a/src/components/I18nProvider.js b/src/components/I18nProvider.js new file mode 100644 index 0000000..3185ff5 --- /dev/null +++ b/src/components/I18nProvider.js @@ -0,0 +1,47 @@ +import React, {useState, useEffect, createContext} from 'react'; +import { IntlProvider } from 'react-intl'; +import enMessages from '../translations/en.json'; +import cnMessages from '../translations/zh-CN.json'; +import hkMessages from '../translations/zh-HK.json'; + +const LocaleContext = createContext(); + +export const I18nProvider = ({ children }) => { + const systemMessages = { + "en": enMessages, + "zh": hkMessages, + "zh-HK": hkMessages, + "zh-CN": cnMessages + }; + + const [locale, setLocale] = useState('en'); // Default locale, you can change this as per your requirement + const [messages, setMessages] = useState(systemMessages[locale]); + + useEffect(() => { + if(localStorage.getItem('locale') === null){ + //no locale case + localStorage.setItem('locale','en'); + } + else{ + setLocale(localStorage.getItem('locale')); + } + }, []); + useEffect(() => { + // Load the messages for the selected locale + const fetchMessages = async () => { + setMessages(systemMessages[locale]); + }; + + fetchMessages(); + }, [locale]); + + return ( + + + {children} + + + ); +} + +export default LocaleContext; \ No newline at end of file diff --git a/src/index.js b/src/index.js index 5efaa37..b612d1b 100644 --- a/src/index.js +++ b/src/index.js @@ -16,6 +16,7 @@ import 'assets/third-party/apex-chart.css'; import App from './App'; import { store } from 'store'; import reportWebVitals from './reportWebVitals'; +import {I18nProvider} from "./components/I18nProvider"; // ==============================|| MAIN - REACT DOM RENDER ||============================== // @@ -26,9 +27,11 @@ const root = createRoot(container); // createRoot(container!) if you use TypeScr root.render( - + + - + + ); diff --git a/src/layout/MainLayout/Header/HeaderContent/LocaleSelector.js b/src/layout/MainLayout/Header/HeaderContent/LocaleSelector.js new file mode 100644 index 0000000..3d276ee --- /dev/null +++ b/src/layout/MainLayout/Header/HeaderContent/LocaleSelector.js @@ -0,0 +1,142 @@ +import {useContext, useRef, useState} from 'react'; +import ListItem from '@mui/material/ListItem'; +// material-ui +import { useTheme } from '@mui/material/styles'; +import { + Box, + ClickAwayListener, + IconButton, + List, + ListItemButton, + ListItemText, + Paper, + Popper, + useMediaQuery +} from '@mui/material'; + +import Transitions from 'components/@extended/Transitions'; +import LanguageIcon from '@mui/icons-material/Language'; +import {FormattedMessage} from "react-intl"; +import * as React from "react"; +import LocaleContext from "../../../../components/I18nProvider"; + +// ==============================|| HEADER CONTENT - NOTIFICATION ||============================== // + +const LocaleSelector = () => { + const theme = useTheme(); + const matchesXs = useMediaQuery(theme.breakpoints.down('md')); + const { setLocale } = useContext(LocaleContext); + + const anchorRef = useRef(null); + const [open, setOpen] = useState(false); + const handleToggle = () => { + setOpen((prevOpen) => !prevOpen); + }; + + + const handleClose = (event) => { + if (anchorRef.current && anchorRef.current.contains(event.target)) { + return; + } + setOpen(false); + }; + + const iconBackColorOpen = 'grey.300'; + const iconBackColor = 'grey.100'; + + return ( + + + + + + {({ TransitionProps }) => ( + + + + + + { + setLocale("en") + localStorage.setItem('locale','en'); + }} + > + + /> + + + + { + setLocale("zh-HK") + localStorage.setItem('locale','zh-HK'); + }} + > + + /> + + + + { + setLocale("zh-CN") + localStorage.setItem('locale','zh-CN'); + }} + > + + /> + + + + + + + )} + + + ); +}; + +export default LocaleSelector; diff --git a/src/layout/MainLayout/Header/HeaderContent/index.js b/src/layout/MainLayout/Header/HeaderContent/index.js index 7d2e59a..a4cf253 100644 --- a/src/layout/MainLayout/Header/HeaderContent/index.js +++ b/src/layout/MainLayout/Header/HeaderContent/index.js @@ -7,6 +7,7 @@ import { Button ,Box } from '@mui/material'; // project import // import Search from './Search'; import Profile from './Profile'; +import LocaleSelector from "./LocaleSelector"; // import Notification from './Notification'; // import MobileSection from './MobileSection'; @@ -34,7 +35,7 @@ const HeaderContent = () => { > */} - + {/* */} {/* */} diff --git a/src/layout/MainLayout/Header/index.js b/src/layout/MainLayout/Header/index.js index 1edb078..93cb15e 100644 --- a/src/layout/MainLayout/Header/index.js +++ b/src/layout/MainLayout/Header/index.js @@ -50,6 +50,7 @@ import * as UrlUtils from "utils/ApiPathConst" // import { MenuFoldOutlined,MenuOutlined } from '@ant-design/icons'; // import { AppBar } from '../../../../node_modules/@mui/material/index'; import { Link } from "react-router-dom"; +import LocaleSelector from "./HeaderContent/LocaleSelector"; const drawerWidth = 240; @@ -383,6 +384,8 @@ function Header(props) { + + {/* */} diff --git a/src/pages/authentication/auth-forms/AuthLoginCustom.js b/src/pages/authentication/auth-forms/AuthLoginCustom.js index 7358440..03d5a1b 100644 --- a/src/pages/authentication/auth-forms/AuthLoginCustom.js +++ b/src/pages/authentication/auth-forms/AuthLoginCustom.js @@ -43,6 +43,7 @@ import { useDispatch } from "react-redux"; import { handleLogin } from "auth/index"; import useJwt from "../../../auth/jwt/useJwt"; import { handleLogoutFunction } from 'auth/index'; +import {FormattedMessage} from "react-intl"; // ============================|| FIREBASE - LOGIN ||============================ // const AuthLoginCustom = () => { @@ -214,7 +215,11 @@ const AuthLoginCustom = () => { - 用戶登入名稱 + + + + +