Skip to content

Commit

Permalink
Improves internationalization loading.
Browse files Browse the repository at this point in the history
  • Loading branch information
mntone committed Jun 20, 2024
1 parent 8ba86c7 commit f2bcc66
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 31 deletions.
30 changes: 2 additions & 28 deletions src/app/App.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<IntlProvider defaultLocale='en' locale={lang} messages={messages as any}>
<>
<OverlayHost />

<NotificationController />
Expand All @@ -49,7 +23,7 @@ const App = () => {
ShakeStreamKit. Copyright © 2024 mntone. Licensed under the GPLv3 license.
</footer>
</div>
</IntlProvider>
</>
)
}

Expand Down
11 changes: 11 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 4 additions & 1 deletion src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -24,7 +25,9 @@ if (element) {
>
<EnvironmentProvider>
<WebSocketProvider>
<App />
<IntlLoader>
<App />
</IntlLoader>
</WebSocketProvider>
</EnvironmentProvider>
</PersistGate>
Expand Down
62 changes: 62 additions & 0 deletions src/modules/core/components/IntlLoader/index.tsx
Original file line number Diff line number Diff line change
@@ -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<any>(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 (
<div className='Message'>
Loading…
</div>
)
}

return (
<IntlProvider
defaultLocale='en'
locale={language}
messages={messages}
>
{children}
</IntlProvider>
)
}

export default IntlLoader
10 changes: 8 additions & 2 deletions src/modules/core/utils/language.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

0 comments on commit f2bcc66

Please sign in to comment.