refactor(language): move language constants to common module and improve language handling
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Menu, MenuItem } from '@mui/material';
|
||||
import { LanguageAbbreviation } from '../locales';
|
||||
import type { LanguageAbbreviationType } from '../locales';
|
||||
import { useLanguageSetting } from '@/hooks/setting-hooks';
|
||||
import logger from '@/utils/logger';
|
||||
import { LanguageAbbreviation, LanguageAbbreviationMap } from '@/constants/common';
|
||||
|
||||
interface LanguageSwitcherProps {
|
||||
textColor?: string;
|
||||
@@ -12,6 +13,7 @@ const LanguageSwitcher: React.FC<LanguageSwitcherProps> = ({ textColor = '#fff'
|
||||
const { t, i18n } = useTranslation();
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
const open = Boolean(anchorEl);
|
||||
const { changeLanguage } = useLanguageSetting();
|
||||
|
||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
@@ -21,13 +23,23 @@ const LanguageSwitcher: React.FC<LanguageSwitcherProps> = ({ textColor = '#fff'
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const handleLanguageChange = (language: LanguageAbbreviationType) => {
|
||||
i18n.changeLanguage(language);
|
||||
handleClose();
|
||||
const handleLanguageChange = async (language: LanguageAbbreviation) => {
|
||||
try {
|
||||
await changeLanguage(language);
|
||||
i18n.changeLanguage(language);
|
||||
handleClose();
|
||||
} catch (error) {
|
||||
logger.error('更新语言设置失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const supportedLangs: LanguageAbbreviation[] = [LanguageAbbreviation.Zh, LanguageAbbreviation.En];
|
||||
|
||||
const getCurrentLanguageLabel = () => {
|
||||
return i18n.language === LanguageAbbreviation.Zh ? '中文' : 'English';
|
||||
const curLang = supportedLangs.includes(i18n.language as LanguageAbbreviation)
|
||||
? (i18n.language as LanguageAbbreviation)
|
||||
: LanguageAbbreviation.En;
|
||||
return LanguageAbbreviationMap[curLang] || 'English';
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -42,23 +54,16 @@ const LanguageSwitcher: React.FC<LanguageSwitcherProps> = ({ textColor = '#fff'
|
||||
>
|
||||
{getCurrentLanguageLabel()}
|
||||
</Button>
|
||||
<Menu
|
||||
anchorEl={anchorEl}
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<MenuItem
|
||||
onClick={() => handleLanguageChange(LanguageAbbreviation.Zh)}
|
||||
selected={i18n.language === LanguageAbbreviation.Zh}
|
||||
>
|
||||
中文
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={() => handleLanguageChange(LanguageAbbreviation.En)}
|
||||
selected={i18n.language === LanguageAbbreviation.En}
|
||||
>
|
||||
English
|
||||
</MenuItem>
|
||||
<Menu anchorEl={anchorEl} open={open} onClose={handleClose}>
|
||||
{supportedLangs.map((lang) => (
|
||||
<MenuItem
|
||||
key={lang}
|
||||
onClick={() => handleLanguageChange(lang)}
|
||||
selected={i18n.language === lang}
|
||||
>
|
||||
{LanguageAbbreviationMap[lang]}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Menu>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -42,60 +42,76 @@ export const fileIconMap = {
|
||||
export const LanguageList = [
|
||||
'English',
|
||||
'Chinese',
|
||||
'Traditional Chinese',
|
||||
'Indonesia',
|
||||
'Spanish',
|
||||
'Vietnamese',
|
||||
'Japanese',
|
||||
'Portuguese BR',
|
||||
'German',
|
||||
'French',
|
||||
// 'Traditional Chinese',
|
||||
// 'Indonesia',
|
||||
// 'Spanish',
|
||||
// 'Vietnamese',
|
||||
// 'Japanese',
|
||||
// 'Portuguese BR',
|
||||
// 'German',
|
||||
// 'French',
|
||||
];
|
||||
export const LanguageMap = {
|
||||
|
||||
export const LanguageMap: Record<string, string> = {
|
||||
English: 'English',
|
||||
Chinese: '简体中文',
|
||||
'Traditional Chinese': '繁體中文',
|
||||
Indonesia: 'Indonesia',
|
||||
Spanish: 'Español',
|
||||
Vietnamese: 'Tiếng việt',
|
||||
Japanese: '日本語',
|
||||
'Portuguese BR': 'Português BR',
|
||||
German: 'German',
|
||||
French: 'Français',
|
||||
// 'Traditional Chinese': '繁體中文',
|
||||
// Indonesia: 'Indonesia',
|
||||
// Spanish: 'Español',
|
||||
// Vietnamese: 'Tiếng việt',
|
||||
// Japanese: '日本語',
|
||||
// 'Portuguese BR': 'Português BR',
|
||||
// German: 'German',
|
||||
// French: 'Français',
|
||||
};
|
||||
|
||||
export const LANUGAGE_ABBREVIATION_TYPE = Object.freeze({
|
||||
En: 'en',
|
||||
Zh: 'zh',
|
||||
ZhTraditional: 'zh-TRADITIONAL',
|
||||
Id: 'id',
|
||||
Ja: 'ja',
|
||||
Es: 'es',
|
||||
Vi: 'vi',
|
||||
PtBr: 'pt-BR',
|
||||
De: 'de',
|
||||
Fr: 'fr',
|
||||
} as const)
|
||||
|
||||
export type LanguageAbbreviation = (typeof LANUGAGE_ABBREVIATION_TYPE)[keyof typeof LANUGAGE_ABBREVIATION_TYPE]
|
||||
export enum LanguageAbbreviation {
|
||||
En = 'en',
|
||||
Zh = 'zh',
|
||||
ZhTraditional = 'zh-TRADITIONAL',
|
||||
Ru = 'ru',
|
||||
Id = 'id',
|
||||
Ja = 'ja',
|
||||
Es = 'es',
|
||||
Vi = 'vi',
|
||||
PtBr = 'pt-BR',
|
||||
De = 'de',
|
||||
Fr = 'fr',
|
||||
}
|
||||
|
||||
export const LanguageAbbreviationMap = {
|
||||
[LANUGAGE_ABBREVIATION_TYPE.En]: 'English',
|
||||
[LANUGAGE_ABBREVIATION_TYPE.Zh]: '简体中文',
|
||||
[LANUGAGE_ABBREVIATION_TYPE.ZhTraditional]: '繁體中文',
|
||||
[LANUGAGE_ABBREVIATION_TYPE.Id]: 'Indonesia',
|
||||
[LANUGAGE_ABBREVIATION_TYPE.Es]: 'Español',
|
||||
[LANUGAGE_ABBREVIATION_TYPE.Vi]: 'Tiếng việt',
|
||||
[LANUGAGE_ABBREVIATION_TYPE.Ja]: '日本語',
|
||||
[LANUGAGE_ABBREVIATION_TYPE.PtBr]: 'Português BR',
|
||||
[LANUGAGE_ABBREVIATION_TYPE.De]: 'Deutsch',
|
||||
[LANUGAGE_ABBREVIATION_TYPE.Fr]: 'Français',
|
||||
[LanguageAbbreviation.En]: 'English',
|
||||
[LanguageAbbreviation.Zh]: '简体中文',
|
||||
[LanguageAbbreviation.ZhTraditional]: '繁體中文',
|
||||
[LanguageAbbreviation.Ru]: 'Русский',
|
||||
[LanguageAbbreviation.Id]: 'Indonesia',
|
||||
[LanguageAbbreviation.Es]: 'Español',
|
||||
[LanguageAbbreviation.Vi]: 'Tiếng việt',
|
||||
[LanguageAbbreviation.Ja]: '日本語',
|
||||
[LanguageAbbreviation.PtBr]: 'Português BR',
|
||||
[LanguageAbbreviation.De]: 'Deutsch',
|
||||
[LanguageAbbreviation.Fr]: 'Français',
|
||||
};
|
||||
|
||||
export const LanguageTranslationMap = {
|
||||
export const LanguageAbbreviationKeysMap: Record<string, string> = {
|
||||
[LanguageAbbreviation.En]: 'English',
|
||||
[LanguageAbbreviation.Zh]: 'Chinese',
|
||||
[LanguageAbbreviation.ZhTraditional]: 'Traditional Chinese',
|
||||
[LanguageAbbreviation.Ru]: 'Russian',
|
||||
[LanguageAbbreviation.Id]: 'Indonesia',
|
||||
[LanguageAbbreviation.Es]: 'Spanish',
|
||||
[LanguageAbbreviation.Vi]: 'Vietnamese',
|
||||
[LanguageAbbreviation.Ja]: 'Japanese',
|
||||
[LanguageAbbreviation.PtBr]: 'Portuguese BR',
|
||||
[LanguageAbbreviation.De]: 'German',
|
||||
[LanguageAbbreviation.Fr]: 'French',
|
||||
};
|
||||
|
||||
export const LanguageTranslationMap: Record<string, string> = {
|
||||
English: 'en',
|
||||
Chinese: 'zh',
|
||||
'Traditional Chinese': 'zh-TRADITIONAL',
|
||||
Russian: 'ru',
|
||||
Indonesia: 'id',
|
||||
Spanish: 'es',
|
||||
Vietnamese: 'vi',
|
||||
|
||||
@@ -9,6 +9,7 @@ import type { LLMFactory } from "@/constants/llm";
|
||||
import type { IMcpServer, IMcpServerListResponse } from "@/interfaces/database/mcp";
|
||||
import type { IImportMcpServersRequestBody, ITestMcpRequestBody, ICreateMcpServerRequestBody } from "@/interfaces/request/mcp";
|
||||
import type { IPaginationBody } from "@/interfaces/request/base";
|
||||
import { LanguageAbbreviation, LanguageAbbreviationKeysMap, LanguageTranslationMap } from "@/constants/common";
|
||||
|
||||
/**
|
||||
* 个人中心设置
|
||||
@@ -49,6 +50,28 @@ export function useProfileSetting() {
|
||||
};
|
||||
}
|
||||
|
||||
export function useLanguageSetting() {
|
||||
const { userInfo, updateUserInfo } = useProfileSetting();
|
||||
const [language, setLanguage] = useState(userInfo?.language || 'English');
|
||||
|
||||
const changeLanguage = async (language: LanguageAbbreviation) => {
|
||||
try {
|
||||
// LanguageAbbreviation to language
|
||||
const translatedLanguage = LanguageAbbreviationKeysMap[language];
|
||||
await updateUserInfo({ language: translatedLanguage });
|
||||
setLanguage(translatedLanguage);
|
||||
} catch (error) {
|
||||
logger.error('更新语言设置失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
language,
|
||||
changeLanguage,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* LLM 模型设置
|
||||
*/
|
||||
|
||||
@@ -2,6 +2,8 @@ import { useEffect, useCallback } from 'react';
|
||||
import { useUserStore } from '@/stores/userStore';
|
||||
import userService from '@/services/user_service';
|
||||
import type { IUserInfo } from '@/interfaces/database/user-setting';
|
||||
import i18n from '@/locales';
|
||||
import { LanguageTranslationMap } from '@/constants/common';
|
||||
|
||||
/**
|
||||
* 用户数据管理Hook
|
||||
@@ -31,6 +33,9 @@ export const useUserData = () => {
|
||||
if (response.data.code === 0) {
|
||||
const userInfoData: IUserInfo | null = response.data.data || null;
|
||||
setUserInfo(userInfoData);
|
||||
i18n.changeLanguage(
|
||||
LanguageTranslationMap[userInfoData?.language as keyof typeof LanguageTranslationMap],
|
||||
);
|
||||
return userInfoData;
|
||||
} else {
|
||||
throw new Error(response.data.message || '获取用户信息失败');
|
||||
|
||||
@@ -2,19 +2,13 @@ import i18n from 'i18next';
|
||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
import dayjs from 'dayjs';
|
||||
import {LanguageAbbreviation} from '@/constants/common';
|
||||
import 'dayjs/locale/zh-cn';
|
||||
import 'dayjs/locale/en';
|
||||
|
||||
import en from './en';
|
||||
import zh from './zh';
|
||||
|
||||
export const LanguageAbbreviation = Object.freeze({
|
||||
En: 'en',
|
||||
Zh: 'zh',
|
||||
} as const)
|
||||
|
||||
export type LanguageAbbreviationType = (typeof LanguageAbbreviation)[keyof typeof LanguageAbbreviation]
|
||||
|
||||
const resources = {
|
||||
[LanguageAbbreviation.En]: en,
|
||||
[LanguageAbbreviation.Zh]: zh,
|
||||
|
||||
@@ -53,9 +53,9 @@ import { zhCN, enUS } from '@mui/x-data-grid/locales';
|
||||
import type { IKnowledgeFile } from '@/interfaces/database/knowledge';
|
||||
import type { IDocumentInfoFilter } from '@/interfaces/database/document';
|
||||
import { RunningStatus } from '@/constants/knowledge';
|
||||
import { LanguageAbbreviation } from '@/locales';
|
||||
import dayjs from 'dayjs';
|
||||
import logger from '@/utils/logger';
|
||||
import { LanguageAbbreviation } from '@/constants/common';
|
||||
|
||||
|
||||
interface DocumentListComponentProps {
|
||||
|
||||
@@ -9,9 +9,10 @@ import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { useKnowledgeOverview, useKnowledgeDetail } from '@/hooks/knowledge-hooks';
|
||||
import logger from '@/utils/logger';
|
||||
import i18n, { LanguageAbbreviation } from '@/locales';
|
||||
import i18n from '@/locales';
|
||||
import { enUS, zhCN } from '@mui/x-data-grid/locales';
|
||||
import KnowledgeBreadcrumbs from './components/KnowledgeBreadcrumbs';
|
||||
import { LanguageAbbreviation } from '@/constants/common';
|
||||
|
||||
|
||||
const PROCESSING_TYPES = {
|
||||
|
||||
@@ -20,18 +20,10 @@ import { useProfileSetting } from '@/hooks/setting-hooks';
|
||||
import { useMessage } from '@/hooks/useSnackbar';
|
||||
import type { IUserInfo } from '@/interfaces/database/user-setting';
|
||||
import { TimezoneList } from '@/constants/setting';
|
||||
import { LanguageList, LanguageMap } from '@/constants/common';
|
||||
|
||||
// 语言选项
|
||||
const languageOptions = [
|
||||
{ value: 'Chinese', label: '简体中文' },
|
||||
{ value: 'English', label: 'English' },
|
||||
{ value: 'Spanish', label: 'Español' },
|
||||
{ value: 'French', label: 'Français' },
|
||||
{ value: 'German', label: 'Deutsch' },
|
||||
{ value: 'Japanese', label: '日本語' },
|
||||
{ value: 'Korean', label: '한국어' },
|
||||
{ value: 'Vietnamese', label: 'Tiếng Việt' }
|
||||
];
|
||||
const languageOptions = LanguageList.map(x => ({ value: x, label: LanguageMap[x as keyof typeof LanguageMap] }));
|
||||
|
||||
// 时区选项
|
||||
const timezoneOptions = TimezoneList.map(x => ({ value: x, label: x }));
|
||||
|
||||
Reference in New Issue
Block a user