-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(pages): add i18n configuration (#11)
- Loading branch information
Showing
13 changed files
with
225 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import type { Locale, LocaleLang } from "val-i18n"; | ||
import type { ReadonlyVal } from "value-enhancer"; | ||
|
||
import { useEffect } from "react"; | ||
import { detectLang, I18n } from "val-i18n"; | ||
import { joinDisposers } from "~/misc/utils"; | ||
import { useAsyncMemo } from "./use-async-memo"; | ||
|
||
const i18nLoader = (lang?: string): Promise<I18n> => { | ||
const localeModules = import.meta.glob<boolean, string, Locale>( | ||
"~/locales/*.json", | ||
{ | ||
import: "default", | ||
}, | ||
); | ||
|
||
const localeLoaders = Object.keys(localeModules).reduce( | ||
(loaders, path) => { | ||
if (localeModules[path]) { | ||
const langMatch = path.match(/\/([^/]+)\.json$/); | ||
if (langMatch) { | ||
loaders[langMatch[1]] = localeModules[path]; | ||
} | ||
} | ||
return loaders; | ||
}, | ||
{} as Record<LocaleLang, () => Promise<Locale>>, | ||
); | ||
|
||
const langs = Object.keys(localeLoaders); | ||
|
||
return I18n.preload( | ||
lang && localeLoaders[lang] | ||
? lang | ||
: detectLang(langs) || (localeLoaders.en ? "en" : langs[0]), | ||
lang => localeLoaders[lang](), | ||
); | ||
}; | ||
|
||
export const useI18nLoader = ( | ||
localeLang$: ReadonlyVal<string | undefined>, | ||
): I18n | undefined => { | ||
const maybeI18n = useAsyncMemo(() => i18nLoader(localeLang$.value), []); | ||
useEffect( | ||
() => | ||
joinDisposers( | ||
localeLang$.subscribe(lang => lang && void maybeI18n?.switchLang(lang)), | ||
maybeI18n?.lang$.subscribe((lang) => { | ||
document.documentElement.lang = lang; | ||
}), | ||
), | ||
[maybeI18n, localeLang$], | ||
); | ||
return maybeI18n; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
export * from "./i18n-loader"; | ||
export * from "./use-app-context"; | ||
export * from "./use-async-memo"; | ||
export * from "./use-isomorphic-layout-effect"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import type { DependencyList } from "react"; | ||
|
||
import { useState } from "react"; | ||
import { isPromise } from "~/misc/utils"; | ||
|
||
import { useIsomorphicLayoutEffect } from "./use-isomorphic-layout-effect"; | ||
|
||
export const useAsyncMemo = <T>( | ||
effect: (oldValue: T | undefined) => Promise<T> | T, | ||
deps: DependencyList = [], | ||
): T | undefined => { | ||
const [value, setValue] = useState<T | undefined>(); | ||
|
||
useIsomorphicLayoutEffect(() => { | ||
let isValid = true; | ||
|
||
const maybePromise = effect(value); | ||
|
||
if (isPromise(maybePromise)) { | ||
void maybePromise.then((value) => { | ||
if (isValid) { | ||
setValue(value); | ||
} | ||
}); | ||
} | ||
else { | ||
setValue(maybePromise); | ||
} | ||
|
||
return () => { | ||
isValid = false; | ||
}; | ||
}, deps); | ||
|
||
return value; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"settings": { | ||
"appearance": "Appearance", | ||
"chinese": "Chinese", | ||
"language": "Language", | ||
"theme-light": "Light", | ||
"theme-dark": "Dark", | ||
"theme-auto": "Auto" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { default as en } from "./en.json"; | ||
export { default as zhCN } from "./zh-CN.json"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"settings": { | ||
"appearance": "外观", | ||
"chinese": "中文", | ||
"language": "语言", | ||
"theme-light": "浅色", | ||
"theme-dark": "深色", | ||
"theme-auto": "自动" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
export const isPromise = <T>( | ||
value: T | PromiseLike<T>, | ||
): value is PromiseLike<T> => | ||
value && typeof (value as PromiseLike<T>).then === "function"; | ||
|
||
export const noop = () => {}; | ||
|
||
const invoke = (fn?: (() => unknown) | null): void => { | ||
try { | ||
fn?.(); | ||
} | ||
catch (e) { | ||
console.error(e); | ||
} | ||
}; | ||
|
||
export const joinDisposers | ||
= ( | ||
...disposers: ReadonlyArray<(() => void) | undefined | null> | ||
): (() => void) => | ||
() => | ||
disposers.forEach(invoke); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,55 +1,63 @@ | ||
import type { CheckboxChangeEvent } from "antd/es/checkbox"; | ||
import { Radio } from "antd"; | ||
import React from "react"; | ||
|
||
import { useVal } from "use-value-enhancer"; | ||
import { useLang, useTranslate } from "val-i18n-react"; | ||
import { AppearancePicker } from "~/components/AppearancePicker"; | ||
import type { OOMOLPrefersColorScheme } from "~/components/ThemeProvider"; | ||
import { useAppContext } from "~/hooks"; | ||
|
||
import styles from "./index.module.scss"; | ||
|
||
enum SelectLanguage { | ||
Chinese = "zh-CN", | ||
English = "en", | ||
} | ||
|
||
type Lang = "en" | "zh-CN"; | ||
|
||
export const Settings = () => { | ||
// const t = useTranslate(); | ||
// const language = useLang(); | ||
const t = useTranslate(); | ||
const language = useLang(); | ||
const { settingStore } = useAppContext(); | ||
|
||
const prefersColorScheme = useVal(settingStore.prefersColorScheme$); | ||
|
||
// const [selectLanguage, setSelectLanguage] = useState<Lang>(language as Lang); | ||
|
||
const changeAppearance = (event: CheckboxChangeEvent) => { | ||
const prefersColorScheme: OOMOLPrefersColorScheme = event.target.value; | ||
settingStore.updatePrefersColorScheme(prefersColorScheme); | ||
}; | ||
|
||
const changeLanguage = async (event: CheckboxChangeEvent) => { | ||
const lang: Lang = event.target.value; | ||
settingStore.updateLocalLanguage(lang); | ||
}; | ||
|
||
return ( | ||
<div className={styles.container}> | ||
{/* <p className={styles.label}>{t("setting.appearance")}</p> */} | ||
<p className={styles.label}>Appearance</p> | ||
<p className={styles.label}>{t("settings.appearance")}</p> | ||
<AppearancePicker | ||
defaultValue={prefersColorScheme} | ||
changeAppearance={changeAppearance} | ||
/> | ||
{/* <div className={styles.languageSetting}> */} | ||
{/* <span className={styles.label}>{t("setting.language")}</span> */} | ||
{/* <Radio.Group | ||
value={language} | ||
<div className={styles.languageSetting}> | ||
<span className={styles.label}>{t("settings.language")}</span> | ||
<Radio.Group | ||
defaultValue={ | ||
language === "zh-CN" | ||
? SelectLanguage.Chinese | ||
: SelectLanguage.English | ||
} | ||
onChange={openRestartModal} | ||
rootClassName={styles.radioGroup} | ||
onChange={changeLanguage} | ||
> | ||
<Radio value={SelectLanguage.Chinese}> | ||
<span>{t("setting.chinese")}</span> | ||
<span>{t("settings.chinese")}</span> | ||
</Radio> | ||
<Radio value={SelectLanguage.English}> | ||
<span>English</span> | ||
</Radio> | ||
</Radio.Group> */} | ||
{/* </div> */} | ||
</Radio.Group> | ||
</div> | ||
</div> | ||
); | ||
}; |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.