Merge branch 'dev/i18n' into dev/main

This commit is contained in:
LittleBoy 2025-01-24 13:02:04 +08:00
commit 71e90e7edd
13 changed files with 93 additions and 18 deletions

View File

@ -4,7 +4,7 @@
<meta charset="UTF-8"/>
<link rel="icon" type="image/png" href="/logo.svg"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>数字人直播</title>
<title></title>
<style>
.app-loading-text{font-family:"PingFang SC","Microsoft YaHei",sans-serif;position:fixed;left:0;right:0;text-align:center;top:50%;transform:translateY(-50%);font-size:20px}
</style>

View File

@ -26,10 +26,12 @@
"dayjs": "^1.11.11",
"file-saver": "^2.0.5",
"flv.js": "^1.6.2",
"i18next": "^24.2.1",
"jszip": "^3.10.1",
"qs": "^6.12.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-i18next": "^15.4.0",
"react-player": "^2.16.0",
"react-router-dom": "^6.28.0",
"sass": "^1.81.0",

View File

@ -6,6 +6,7 @@ import {showErrorToast, showToast} from "@/components/message.ts";
import {BizError} from "@/service/types.ts";
import {IconWarningCircle} from "@/components/icons";
import {LoadingOutlined} from "@ant-design/icons";
import {useTranslation} from "react-i18next";
type Props = {
selected: any[],
@ -29,6 +30,7 @@ export default function ButtonBatch(
selected, emptyMessage, successMessage, children, icon,
title, confirmMessage, onProcess, onSuccess, className
}: Props) {
const {t} = useTranslation()
const [loading, setLoading] = useState(false)
const {modal} = App.useApp()
const onBatchProcess = async () => {
@ -54,7 +56,7 @@ export default function ButtonBatch(
if(confirmMessage){
modal.confirm({
wrapClassName: 'root-modal-confirm',
title: title || '操作提示',
title: title || t('notice.title'),
centered: true,
icon: <span className="anticon anticon-exclamation-circle"><IconWarningCircle/></span>,
content: confirmMessage,

View File

@ -2,12 +2,12 @@ import React, {useEffect} from "react";
type DocumentTitleProps = {
children?: string;
text?: string;
title?: string;
}
export const DocumentTitle: React.FC<DocumentTitleProps> = ({children, text}) => {
export const DocumentTitle: React.FC<DocumentTitleProps> = ({children, title}) => {
useEffect(() => {
if (text || children) {
document.title = text || children || '';
if (title || children) {
document.title = title || children || '';
}
}, []);
return <></>

View File

@ -1,5 +1,5 @@
import useLocalStorage from "@/hooks/useLocalStorage";
import {createContext} from "react";
import React, {createContext} from "react";
const config: ConfigProps = {
fontFamily: `'Public Sans', sans-serif`,
@ -21,7 +21,7 @@ const initialState: CustomizationProps = {
const ConfigContext = createContext(initialState);
export const ConfigProvider = ({children}: { children: React.ReactNode }) => {
const [config, setConfig] = useLocalStorage('app-payment-config', initialState);
const [config, setConfig] = useLocalStorage('app-video-admin-config', initialState);
// 改变语言
const onChangeLocalization = (lang: I18n) => {
setConfig({

14
src/i18n/config.ts Normal file
View File

@ -0,0 +1,14 @@
import i18next from 'i18next';
import {initReactI18next} from 'react-i18next';
import LangEN from './translations/en-US.json';
import LangCN from './translations/zh-CN.json';
console.log('AppConfig',AppMode)
i18next.use(initReactI18next).init({
debug: true,
fallbackLng: 'en-US',
resources: {
'en-US': {translation:LangEN},
'zh-CN': {translation:LangCN},
},
});

0
src/i18n/index.ts Normal file
View File

View File

@ -0,0 +1,10 @@
{
"AppTitle": "Digital Human Live",
"Hello": "Hello",
"login": {
"text": "Login"
},
"notice": {
"title": "操作提示"
}
}

View File

@ -0,0 +1,10 @@
{
"AppTitle": "数字人直播",
"Hello": "你好",
"login": {
"text": "登录"
},
"notice": {
"title": "Notice"
}
}

View File

@ -1,6 +1,6 @@
import {createBrowserRouter, RouterProvider,} from "react-router-dom";
import {Suspense,} from "react";
import {ConfigProvider,App} from "antd";
import {Suspense, useEffect,} from "react";
import {ConfigProvider, App} from "antd";
import zhCN from 'antd/locale/zh_CN';
// for date-picker i18n
import dayjs from "dayjs";
@ -8,10 +8,11 @@ import 'dayjs/locale/zh-cn';
import ErrorBoundary from "./error.tsx";
import Loader from "@/components/loader.tsx";
import routes from "@/routes/routes.tsx";
import {DocumentTitle} from "@/components/document.tsx";
import useConfig from "@/hooks/useConfig.ts";
import {useTranslation} from "react-i18next";
dayjs.locale('zh-cn');
const router = createBrowserRouter([
...routes,
{path: '*', element: <ErrorBoundary/>}
@ -28,16 +29,23 @@ const router = createBrowserRouter([
// future={{v7_startTransition: true,v7_relativeSplatPath: true}}
const AppRouter = () => {
const {t} = useTranslation();
const {i18n} = useConfig();
useEffect(() => {
if (i18n && i18n == 'zh-CN') {
dayjs.locale('zh-cn');
}
}, [i18n])
return (<ConfigProvider
locale={zhCN}
locale={i18n == 'zh-CN' ? zhCN : undefined}
theme={{
token: {
borderRadius: 4,
},
}}
>
<DocumentTitle title={t('AppTitle')}/>
<App>
<Suspense fallback={<Loader/>}>
<RouterProvider future={{v7_startTransition: true}} router={router}/>

View File

@ -12,6 +12,7 @@ import useAuth from "@/hooks/useAuth.ts";
import {hidePhone} from "@/util/strings.ts";
import {defaultCache} from "@/hooks/useCache.ts";
import {IconVideo} from "@/components/icons";
import {useTranslation} from "react-i18next";
type LayoutProps = {
@ -19,6 +20,7 @@ type LayoutProps = {
}
const NavigationUserContainer = () => {
const {t } = useTranslation()
const {logout, user} = useAuth()
const navigate = useNavigate()
const handleLogout = ()=>{
@ -41,7 +43,7 @@ const NavigationUserContainer = () => {
className={`flex items-center rounded-3xl ${user ? 'bg-[#e3eeff]' : 'bg-primary-blue'} p-1 pr-2 cursor-pointer rounded`}>
<UserAvatar className="user-avatar size-7"/>
{user ? <span className={"username ml-2 text-sm"}>{hidePhone(user.nickname)}</span> : (
<span className="text-sm mx-2 text-white"></span>
<span className="text-sm mx-2 text-white">{t('login.text')}</span>
)}
</div>)
return (<div className={"flex items-center justify-between gap-2 ml-10"}>

View File

@ -1,4 +1,4 @@
type I18n = 'en-US' | 'zh-CN' | 'zh-HK';
type I18n = 'en-US' | 'zh-CN' | 'zh-HK' | string;
type ConfigProps = {
fontFamily: string;

View File

@ -201,7 +201,7 @@
dependencies:
"@babel/helper-plugin-utils" "^7.25.9"
"@babel/runtime@^7.10.1", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.16.7", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.6", "@babel/runtime@^7.23.9", "@babel/runtime@^7.24.4", "@babel/runtime@^7.24.7", "@babel/runtime@^7.24.8", "@babel/runtime@^7.25.7":
"@babel/runtime@^7.10.1", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.16.7", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.6", "@babel/runtime@^7.23.9", "@babel/runtime@^7.24.4", "@babel/runtime@^7.24.7", "@babel/runtime@^7.24.8", "@babel/runtime@^7.25.0", "@babel/runtime@^7.25.7":
version "7.26.0"
resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1"
integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==
@ -1870,6 +1870,20 @@ hasown@^2.0.0, hasown@^2.0.2:
dependencies:
function-bind "^1.1.2"
html-parse-stringify@^3.0.1:
version "3.0.1"
resolved "https://registry.npmmirror.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2"
integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==
dependencies:
void-elements "3.1.0"
i18next@^24.2.1:
version "24.2.1"
resolved "https://registry.npmmirror.com/i18next/-/i18next-24.2.1.tgz#91e8f11fc9bd7042ec0bd36bed2dd0457aaa35fa"
integrity sha512-Q2wC1TjWcSikn1VAJg13UGIjc+okpFxQTxjVAymOnSA3RpttBQNMPf2ovcgoFVsV4QNxTfNZMAxorXZXsk4fBA==
dependencies:
"@babel/runtime" "^7.23.2"
ignore@^5.2.0, ignore@^5.3.1:
version "5.3.2"
resolved "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5"
@ -2905,6 +2919,14 @@ react-fast-compare@^3.0.1, react-fast-compare@^3.2.2:
resolved "https://registry.npmmirror.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49"
integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==
react-i18next@^15.4.0:
version "15.4.0"
resolved "https://registry.npmmirror.com/react-i18next/-/react-i18next-15.4.0.tgz#87c755fb6d7a567eec134e4759b022a0baacb19e"
integrity sha512-Py6UkX3zV08RTvL6ZANRoBh9sL/ne6rQq79XlkHEdd82cZr2H9usbWpUNVadJntIZP2pu3M2rL1CN+5rQYfYFw==
dependencies:
"@babel/runtime" "^7.25.0"
html-parse-stringify "^3.0.1"
react-is@^16.13.1:
version "16.13.1"
resolved "https://registry.npmmirror.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
@ -3444,6 +3466,11 @@ vite@^5.2.0:
optionalDependencies:
fsevents "~2.3.3"
void-elements@3.1.0:
version "3.1.0"
resolved "https://registry.npmmirror.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09"
integrity sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==
webworkify-webpack@^2.1.5:
version "2.1.5"
resolved "https://registry.npmmirror.com/webworkify-webpack/-/webworkify-webpack-2.1.5.tgz#bf4336624c0626cbe85cf1ffde157f7aa90b1d1c"