diff --git a/src/app/App.tsx b/src/app/App.tsx index 1c125d2..5416d0a 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -1,42 +1,16 @@ import './App.css' -import { useEffect, useState } from 'react' -import { IntlProvider } from 'react-intl' - -import { useEnvironment } from '@/core/components/EnvironmentProvider' import { useBodyClass } from '@/core/hooks/bodyclass' -import { loadLocale } from '@/core/utils/language' import NotificationController from '@/notification/components/NotificationController' import OverlayController from '@/overlay/components/OverlayController' import OverlayHost from '@/overlay/components/OverlayHost' import SettingsWindow from '@/settings' -import { useAppSelector } from './hooks' - const App = () => { - const [messages, setMessages] = useState(null) - useBodyClass() - const environment = useEnvironment() - const userLanguage = environment?.lang ?? 'en' - const lang = useAppSelector(state => state.config.language) ?? userLanguage - useEffect(() => { - const fetchMessages = async () => { - const messages = await loadLocale(lang) - document.documentElement.setAttribute('lang', lang) - setMessages(messages) - } - if (lang === 'en') { - document.documentElement.setAttribute('lang', 'en') - setMessages(null) - } else { - fetchMessages() - } - }, [lang]) - return ( - + <> @@ -49,7 +23,7 @@ const App = () => { ShakeStreamKit. Copyright © 2024 mntone. Licensed under the GPLv3 license. - + ) } diff --git a/src/index.css b/src/index.css index 58760c0..49bd232 100644 --- a/src/index.css +++ b/src/index.css @@ -58,6 +58,17 @@ html:lang(zh-TW) body, span:lang(zh-TW) { font-family: Oswald, 'PingFang TC', STHeitiTC, 'Heiti TC', '黒体-繁', 'Microsoft JhengHei', sans-serif, 'Apple Color Emoji', 'Segoe UI Symbol'; } +.Message { + display: flex; + align-items: center; + justify-content: center; + height: 100vh; + color: var(--fg-tertiary); + background-color: #000; + font-size: 200%; + user-select: none; +} + input, input::-webkit-file-upload-button, input::-webkit-slider-thumb, diff --git a/src/index.tsx b/src/index.tsx index a1ca8a7..8558662 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -7,6 +7,7 @@ import { createRoot } from 'react-dom/client' import { PersistGate } from 'redux-persist/integration/react' import EnvironmentProvider from '@/core/components/EnvironmentProvider' +import IntlLoader from '@/core/components/IntlLoader' import WebSocketProvider from '@/telemetry/components/WebSocketProvider' import App from 'app/App' @@ -24,7 +25,9 @@ if (element) { > - + + + diff --git a/src/modules/core/components/IntlLoader/index.tsx b/src/modules/core/components/IntlLoader/index.tsx new file mode 100644 index 0000000..96ab73a --- /dev/null +++ b/src/modules/core/components/IntlLoader/index.tsx @@ -0,0 +1,62 @@ +import { type PropsWithChildren, useState, useLayoutEffect } from 'react' +import { IntlProvider } from 'react-intl' + +import { useAppSelector } from 'app/hooks' + +import { loadLocale } from '../../utils/language' +import { useEnvironment } from '../EnvironmentProvider' + +const IntlLoader = ({ children }: PropsWithChildren) => { + const [messages, setMessages] = useState(null) + + const userLanguage = useEnvironment()?.lang ?? 'en' + const language = useAppSelector(state => state.config.language) ?? userLanguage + useLayoutEffect(() => { + const controller = new AbortController() + const fetchMessages = async () => { + try { + const messages = await loadLocale(language, controller.signal) + document.documentElement.setAttribute('lang', language) + setMessages(messages) + } catch (err) { + if (err instanceof DOMException) { + if (err.name !== 'AbortError') { + console.log(err) + } + } else { + console.log(err) + } + } + } + if (language === 'en') { + document.documentElement.setAttribute('lang', 'en') + setMessages(null) + } else { + fetchMessages() + } + + return () => { + controller.abort() + } + }, [language]) + + if (language !== 'en' && messages === null) { + return ( +
+ Loading… +
+ ) + } + + return ( + + {children} + + ) +} + +export default IntlLoader diff --git a/src/modules/core/utils/language.ts b/src/modules/core/utils/language.ts index c0b1333..baece60 100644 --- a/src/modules/core/utils/language.ts +++ b/src/modules/core/utils/language.ts @@ -27,8 +27,14 @@ export const detectLanguage = () => { return language } -export const loadLocale = async (locale: string) => { - const res = await fetch(`locales/${locale}.json`) +export const loadLocale = async (locale: string, signal?: AbortSignal) => { + const res = await fetch(`locales/${locale}.json`, { + signal, + }) + if (!res.ok) { + throw Error('Response is not OK') + } + const json = await res.json() return json }