From 14f3b92962d43a07f36190cb64d242fd1244dfb8 Mon Sep 17 00:00:00 2001 From: GZTime Date: Wed, 24 Jan 2024 04:13:25 +0800 Subject: [PATCH] feat: language switch --- .../ClientApp/src/components/AppNavbar.tsx | 24 ++++++++++ .../ClientApp/src/locales/zh_CN/common.json | 6 +-- src/GZCTF/ClientApp/src/main.tsx | 18 -------- src/GZCTF/ClientApp/src/utils/I18n.tsx | 46 +++++++++++++++++++ 4 files changed, 73 insertions(+), 21 deletions(-) create mode 100644 src/GZCTF/ClientApp/src/utils/I18n.tsx diff --git a/src/GZCTF/ClientApp/src/components/AppNavbar.tsx b/src/GZCTF/ClientApp/src/components/AppNavbar.tsx index c8f1321b5..8bc182169 100644 --- a/src/GZCTF/ClientApp/src/components/AppNavbar.tsx +++ b/src/GZCTF/ClientApp/src/components/AppNavbar.tsx @@ -19,6 +19,7 @@ import { mdiInformationOutline, mdiLogout, mdiNoteTextOutline, + mdiSignLanguage, mdiWeatherNight, mdiWeatherSunny, mdiWrenchOutline, @@ -28,6 +29,7 @@ import React, { FC, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import { Link, useLocation, useNavigate } from 'react-router-dom' import MainIcon from '@Components/icon/MainIcon' +import { useLanguage } from '@Utils/I18n' import { useLocalStorageCache } from '@Utils/useConfig' import { useLoginOut, useUser } from '@Utils/useUser' import { Role } from '@Api' @@ -123,6 +125,7 @@ const AppNavbar: FC = () => { const { clearLocalCache } = useLocalStorageCache() const { user, error } = useUser() const { t } = useTranslation() + const { language, setLanguage, supportedLanguages } = useLanguage() const items: NavbarItem[] = [ { icon: mdiHomeVariantOutline, label: t('common.tab.home'), link: '/' }, @@ -199,6 +202,27 @@ const AppNavbar: FC = () => { + {/* Language */} + + + + + + + + + {supportedLanguages.map((lang) => ( + setLanguage(lang)} + icon={} + > + {lang} + + ))} + + + {/* User Info */} {user && !error ? ( diff --git a/src/GZCTF/ClientApp/src/locales/zh_CN/common.json b/src/GZCTF/ClientApp/src/locales/zh_CN/common.json index 15a3d0e1e..fe481826f 100644 --- a/src/GZCTF/ClientApp/src/locales/zh_CN/common.json +++ b/src/GZCTF/ClientApp/src/locales/zh_CN/common.json @@ -18,9 +18,9 @@ "clean_cache": "清除缓存" }, "language": { - "en": "English", - "zh": "中文", - "switch_to": "切换到{{language}}" + "zh-CN": "中文", + "en-US": "English", + "ja-JP": "日本語" } }, "title": { diff --git a/src/GZCTF/ClientApp/src/main.tsx b/src/GZCTF/ClientApp/src/main.tsx index a71363276..e4fab4687 100644 --- a/src/GZCTF/ClientApp/src/main.tsx +++ b/src/GZCTF/ClientApp/src/main.tsx @@ -1,25 +1,7 @@ import { App } from '@App' -import i18n from 'i18next' -import LanguageDetector from 'i18next-browser-languagedetector' import { StrictMode } from 'react' import ReactDOM from 'react-dom/client' -import { initReactI18next } from 'react-i18next' import { BrowserRouter as Router } from 'react-router-dom' -import resources from 'virtual:i18next-loader' - -i18n - .use(LanguageDetector) - .use(initReactI18next) - .init({ - resources, - fallbackLng: 'zh_CN', - interpolation: { - escapeValue: false, - }, - detection: { - convertDetectedLanguage: 'Iso15897', - }, - }) ReactDOM.createRoot(document.getElementById('root')!).render( diff --git a/src/GZCTF/ClientApp/src/utils/I18n.tsx b/src/GZCTF/ClientApp/src/utils/I18n.tsx new file mode 100644 index 000000000..f87b7662c --- /dev/null +++ b/src/GZCTF/ClientApp/src/utils/I18n.tsx @@ -0,0 +1,46 @@ +import { useLocalStorage } from '@mantine/hooks' +import i18n from 'i18next' +import LanguageDetector from 'i18next-browser-languagedetector' +import { useEffect } from 'react' +import { initReactI18next } from 'react-i18next' +import resources from 'virtual:i18next-loader' + +i18n + .use(LanguageDetector) + .use(initReactI18next) + .init({ + resources, + fallbackLng: 'zh_CN', + interpolation: { + escapeValue: false, + }, + detection: { + convertDetectedLanguage: 'Iso15897', + }, + }) + +export const useLanguage = () => { + const [language, setLanguageInner] = useLocalStorage({ + key: 'language', + defaultValue: 'zh_CN', + }) + + useEffect(() => { + i18n.changeLanguage(language) + }, [language]) + + const supportedLanguages = Object.keys(resources) + + const setLanguage = (lang: string) => { + // check if language is supported + if (supportedLanguages.includes(lang)) { + setLanguageInner(lang) + } else { + setLanguageInner('zh_CN') + } + } + + return { language, setLanguage, supportedLanguages } +} + +export default i18n