mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-20 07:00:09 +08:00
fix(i18n): standardize i18n usage (#8525)
* fix(数据设置): 修复菜单项标题未使用翻译函数的问题 * refactor(i18n): 使用labelMap集中管理翻译键以提升维护性 将分散在各处的翻译键集中管理到labelMap中,统一通过映射获取翻译文本 替换直接使用i18n.t的调用为从labelMap获取,减少重复代码 修复部分未考虑Linux平台的翻译描述 * fix(NewApiPage): 将未知提供者的值设为undefined以保持一致 * refactor(i18n): 将labelMap替换为动态获取标签的函数 重构国际化标签的获取方式,从静态对象改为动态函数,以支持语言切换时实时更新标签内容 * feat(i18n): 添加文件字段标签的国际化支持 将文件字段的标签文本提取到i18n模块中统一管理,便于维护和翻译 * refactor(utils): 移除调试用的console.log语句
This commit is contained in:
parent
ff649b9d49
commit
36a22129a1
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -38,6 +38,7 @@
|
|||||||
// "i18n-ally.namespace": true, // 开启命名空间
|
// "i18n-ally.namespace": true, // 开启命名空间
|
||||||
"i18n-ally.sortKeys": true, // 排序
|
"i18n-ally.sortKeys": true, // 排序
|
||||||
"i18n-ally.sourceLanguage": "zh-cn", // 翻译源语言
|
"i18n-ally.sourceLanguage": "zh-cn", // 翻译源语言
|
||||||
|
"i18n-ally.usage.derivedKeyRules": ["{key}_one", "{key}_other"], // 标记单复数形式的键为已翻译
|
||||||
"search.exclude": {
|
"search.exclude": {
|
||||||
"**/dist/**": true,
|
"**/dist/**": true,
|
||||||
".yarn/releases/**": true
|
".yarn/releases/**": true
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import NewApiAddModelPopup from '@renderer/components/ModelList/NewApiAddModelPo
|
|||||||
import { PROVIDER_CONFIG } from '@renderer/config/providers'
|
import { PROVIDER_CONFIG } from '@renderer/config/providers'
|
||||||
import { useAssistants, useDefaultModel } from '@renderer/hooks/useAssistant'
|
import { useAssistants, useDefaultModel } from '@renderer/hooks/useAssistant'
|
||||||
import { useProvider } from '@renderer/hooks/useProvider'
|
import { useProvider } from '@renderer/hooks/useProvider'
|
||||||
|
import { getProviderLabel } from '@renderer/i18n/label'
|
||||||
import { SettingHelpLink, SettingHelpText, SettingHelpTextRow, SettingSubtitle } from '@renderer/pages/settings'
|
import { SettingHelpLink, SettingHelpText, SettingHelpTextRow, SettingSubtitle } from '@renderer/pages/settings'
|
||||||
import { useAppDispatch } from '@renderer/store'
|
import { useAppDispatch } from '@renderer/store'
|
||||||
import { setModel } from '@renderer/store/assistants'
|
import { setModel } from '@renderer/store/assistants'
|
||||||
@ -141,7 +142,7 @@ const ModelList: React.FC<ModelListProps> = ({ providerId }) => {
|
|||||||
<SettingHelpText>{t('settings.provider.docs_check')} </SettingHelpText>
|
<SettingHelpText>{t('settings.provider.docs_check')} </SettingHelpText>
|
||||||
{docsWebsite && (
|
{docsWebsite && (
|
||||||
<SettingHelpLink target="_blank" href={docsWebsite}>
|
<SettingHelpLink target="_blank" href={docsWebsite}>
|
||||||
{t(`provider.${provider.id}`) + ' '}
|
{getProviderLabel(provider.id) + ' '}
|
||||||
{t('common.docs')}
|
{t('common.docs')}
|
||||||
</SettingHelpLink>
|
</SettingHelpLink>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { getProviderLabel } from '@renderer/i18n/label'
|
||||||
import { Provider } from '@renderer/types'
|
import { Provider } from '@renderer/types'
|
||||||
import { oauthWithAihubmix, oauthWithPPIO, oauthWithSiliconFlow, oauthWithTokenFlux } from '@renderer/utils/oauth'
|
import { oauthWithAihubmix, oauthWithPPIO, oauthWithSiliconFlow, oauthWithTokenFlux } from '@renderer/utils/oauth'
|
||||||
import { Button, ButtonProps } from 'antd'
|
import { Button, ButtonProps } from 'antd'
|
||||||
@ -39,7 +40,7 @@ const OAuthButton: FC<Props> = ({ provider, onSuccess, ...buttonProps }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Button type="primary" onClick={onAuth} shape="round" {...buttonProps}>
|
<Button type="primary" onClick={onAuth} shape="round" {...buttonProps}>
|
||||||
{t('settings.provider.oauth.button', { provider: t(`provider.${provider.id}`) })}
|
{t('settings.provider.oauth.button', { provider: getProviderLabel(provider.id) })}
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { loggerService } from '@logger'
|
import { loggerService } from '@logger'
|
||||||
|
import { getProgressLabel } from '@renderer/i18n/label'
|
||||||
import { backup } from '@renderer/services/BackupService'
|
import { backup } from '@renderer/services/BackupService'
|
||||||
import store from '@renderer/store'
|
import store from '@renderer/store'
|
||||||
import { IpcChannel } from '@shared/IpcChannel'
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
@ -54,11 +55,11 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
|
|||||||
if (!progressData) return ''
|
if (!progressData) return ''
|
||||||
|
|
||||||
if (progressData.stage === 'copying_files') {
|
if (progressData.stage === 'copying_files') {
|
||||||
return t(`backup.progress.${progressData.stage}`, {
|
return t('backup.progress.copying_files', {
|
||||||
progress: Math.floor(progressData.progress)
|
progress: Math.floor(progressData.progress)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return t(`backup.progress.${progressData.stage}`)
|
return getProgressLabel(progressData.stage)
|
||||||
}
|
}
|
||||||
|
|
||||||
BackupPopup.hide = onCancel
|
BackupPopup.hide = onCancel
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { getProgressLabel } from '@renderer/i18n/label'
|
||||||
import { restore } from '@renderer/services/BackupService'
|
import { restore } from '@renderer/services/BackupService'
|
||||||
import { IpcChannel } from '@shared/IpcChannel'
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
import { Modal, Progress } from 'antd'
|
import { Modal, Progress } from 'antd'
|
||||||
@ -48,11 +49,11 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
|
|||||||
if (!progressData) return ''
|
if (!progressData) return ''
|
||||||
|
|
||||||
if (progressData.stage === 'copying_files') {
|
if (progressData.stage === 'copying_files') {
|
||||||
return t(`restore.progress.${progressData.stage}`, {
|
return t('backup.progress.copying_files', {
|
||||||
progress: Math.floor(progressData.progress)
|
progress: Math.floor(progressData.progress)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return t(`restore.progress.${progressData.stage}`)
|
return getProgressLabel(progressData.stage)
|
||||||
}
|
}
|
||||||
|
|
||||||
RestorePopup.hide = onCancel
|
RestorePopup.hide = onCancel
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { PlusOutlined } from '@ant-design/icons'
|
|||||||
import { isLinux, isMac, isWin } from '@renderer/config/constant'
|
import { isLinux, isMac, isWin } from '@renderer/config/constant'
|
||||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||||
import { useFullscreen } from '@renderer/hooks/useFullscreen'
|
import { useFullscreen } from '@renderer/hooks/useFullscreen'
|
||||||
|
import { getTitleLabel } from '@renderer/i18n/label'
|
||||||
import tabsService from '@renderer/services/TabsService'
|
import tabsService from '@renderer/services/TabsService'
|
||||||
import { useAppDispatch, useAppSelector } from '@renderer/store'
|
import { useAppDispatch, useAppSelector } from '@renderer/store'
|
||||||
import type { Tab } from '@renderer/store/tabs'
|
import type { Tab } from '@renderer/store/tabs'
|
||||||
@ -23,7 +24,6 @@ import {
|
|||||||
X
|
X
|
||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
import { useCallback, useEffect } from 'react'
|
import { useCallback, useEffect } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
@ -62,7 +62,6 @@ let lastSettingsPath = '/settings/provider'
|
|||||||
const specialTabs = ['launchpad', 'settings']
|
const specialTabs = ['launchpad', 'settings']
|
||||||
|
|
||||||
const TabsContainer: React.FC<TabsContainerProps> = ({ children }) => {
|
const TabsContainer: React.FC<TabsContainerProps> = ({ children }) => {
|
||||||
const { t } = useTranslation()
|
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
@ -134,7 +133,7 @@ const TabsContainer: React.FC<TabsContainerProps> = ({ children }) => {
|
|||||||
<Tab key={tab.id} active={tab.id === activeTabId} onClick={() => navigate(tab.path)}>
|
<Tab key={tab.id} active={tab.id === activeTabId} onClick={() => navigate(tab.path)}>
|
||||||
<TabHeader>
|
<TabHeader>
|
||||||
{tab.id && <TabIcon>{getTabIcon(tab.id)}</TabIcon>}
|
{tab.id && <TabIcon>{getTabIcon(tab.id)}</TabIcon>}
|
||||||
<TabTitle>{t(`title.${tab.id}`)}</TabTitle>
|
<TabTitle>{getTitleLabel(tab.id)}</TabTitle>
|
||||||
</TabHeader>
|
</TabHeader>
|
||||||
{tab.id !== 'home' && (
|
{tab.id !== 'home' && (
|
||||||
<CloseButton
|
<CloseButton
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import useNavBackgroundColor from '@renderer/hooks/useNavBackgroundColor'
|
|||||||
import { modelGenerating, useRuntime } from '@renderer/hooks/useRuntime'
|
import { modelGenerating, useRuntime } from '@renderer/hooks/useRuntime'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
import i18n from '@renderer/i18n'
|
import i18n from '@renderer/i18n'
|
||||||
|
import { getSidebarIconLabel, getThemeModeLabel } from '@renderer/i18n/label'
|
||||||
import { ThemeMode } from '@renderer/types'
|
import { ThemeMode } from '@renderer/types'
|
||||||
import { isEmoji } from '@renderer/utils'
|
import { isEmoji } from '@renderer/utils'
|
||||||
import { Avatar, Tooltip } from 'antd'
|
import { Avatar, Tooltip } from 'antd'
|
||||||
@ -104,7 +105,7 @@ const Sidebar: FC = () => {
|
|||||||
</Icon>
|
</Icon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={t('settings.theme.title') + ': ' + t(`settings.theme.${theme}`)}
|
title={t('settings.theme.title') + ': ' + getThemeModeLabel(theme)}
|
||||||
mouseEnterDelay={0.8}
|
mouseEnterDelay={0.8}
|
||||||
placement="right">
|
placement="right">
|
||||||
<Icon theme={theme} onClick={() => setTheme(theme === ThemeMode.dark ? ThemeMode.light : ThemeMode.dark)}>
|
<Icon theme={theme} onClick={() => setTheme(theme === ThemeMode.dark ? ThemeMode.light : ThemeMode.dark)}>
|
||||||
@ -129,7 +130,6 @@ const Sidebar: FC = () => {
|
|||||||
|
|
||||||
const MainMenus: FC = () => {
|
const MainMenus: FC = () => {
|
||||||
const { hideMinappPopup } = useMinappPopup()
|
const { hideMinappPopup } = useMinappPopup()
|
||||||
const { t } = useTranslation()
|
|
||||||
const { pathname } = useLocation()
|
const { pathname } = useLocation()
|
||||||
const { sidebarIcons, defaultPaintingProvider } = useSettings()
|
const { sidebarIcons, defaultPaintingProvider } = useSettings()
|
||||||
const { minappShow } = useRuntime()
|
const { minappShow } = useRuntime()
|
||||||
@ -164,7 +164,7 @@ const MainMenus: FC = () => {
|
|||||||
const isActive = path === '/' ? isRoute(path) : isRoutes(path)
|
const isActive = path === '/' ? isRoute(path) : isRoutes(path)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip key={icon} title={t(`${icon}.title`)} mouseEnterDelay={0.8} placement="right">
|
<Tooltip key={icon} title={getSidebarIconLabel(icon)} mouseEnterDelay={0.8} placement="right">
|
||||||
<StyledLink
|
<StyledLink
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
hideMinappPopup()
|
hideMinappPopup()
|
||||||
|
|||||||
245
src/renderer/src/i18n/label.ts
Normal file
245
src/renderer/src/i18n/label.ts
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
import i18n from './index'
|
||||||
|
|
||||||
|
const t = i18n.t
|
||||||
|
|
||||||
|
/** 使用函数形式是为了动态获取,如果使用静态对象的话,导出的对象将不会随语言切换而改变 */
|
||||||
|
|
||||||
|
export const getProviderLabel = (key: string): string => {
|
||||||
|
const labelMap = {
|
||||||
|
'302ai': t('provider.302ai'),
|
||||||
|
aihubmix: t('provider.aihubmix'),
|
||||||
|
alayanew: t('provider.alayanew'),
|
||||||
|
anthropic: t('provider.anthropic'),
|
||||||
|
'azure-openai': t('provider.azure-openai'),
|
||||||
|
baichuan: t('provider.baichuan'),
|
||||||
|
'baidu-cloud': t('provider.baidu-cloud'),
|
||||||
|
burncloud: t('provider.burncloud'),
|
||||||
|
cephalon: t('provider.cephalon'),
|
||||||
|
copilot: t('provider.copilot'),
|
||||||
|
dashscope: t('provider.dashscope'),
|
||||||
|
deepseek: t('provider.deepseek'),
|
||||||
|
dmxapi: t('provider.dmxapi'),
|
||||||
|
doubao: t('provider.doubao'),
|
||||||
|
fireworks: t('provider.fireworks'),
|
||||||
|
gemini: t('provider.gemini'),
|
||||||
|
'gitee-ai': t('provider.gitee-ai'),
|
||||||
|
github: t('provider.github'),
|
||||||
|
gpustack: t('provider.gpustack'),
|
||||||
|
grok: t('provider.grok'),
|
||||||
|
groq: t('provider.groq'),
|
||||||
|
hunyuan: t('provider.hunyuan'),
|
||||||
|
hyperbolic: t('provider.hyperbolic'),
|
||||||
|
infini: t('provider.infini'),
|
||||||
|
jina: t('provider.jina'),
|
||||||
|
lanyun: t('provider.lanyun'),
|
||||||
|
lmstudio: t('provider.lmstudio'),
|
||||||
|
minimax: t('provider.minimax'),
|
||||||
|
mistral: t('provider.mistral'),
|
||||||
|
modelscope: t('provider.modelscope'),
|
||||||
|
moonshot: t('provider.moonshot'),
|
||||||
|
'new-api': t('provider.new-api'),
|
||||||
|
nvidia: t('provider.nvidia'),
|
||||||
|
o3: t('provider.o3'),
|
||||||
|
ocoolai: t('provider.ocoolai'),
|
||||||
|
ollama: t('provider.ollama'),
|
||||||
|
openai: t('provider.openai'),
|
||||||
|
openrouter: t('provider.openrouter'),
|
||||||
|
perplexity: t('provider.perplexity'),
|
||||||
|
ph8: t('provider.ph8'),
|
||||||
|
ppio: t('provider.ppio'),
|
||||||
|
qiniu: t('provider.qiniu'),
|
||||||
|
qwenlm: t('provider.qwenlm'),
|
||||||
|
silicon: t('provider.silicon'),
|
||||||
|
stepfun: t('provider.stepfun'),
|
||||||
|
'tencent-cloud-ti': t('provider.tencent-cloud-ti'),
|
||||||
|
together: t('provider.together'),
|
||||||
|
tokenflux: t('provider.tokenflux'),
|
||||||
|
vertexai: t('provider.vertexai'),
|
||||||
|
voyageai: t('provider.voyageai'),
|
||||||
|
xirang: t('provider.xirang'),
|
||||||
|
yi: t('provider.yi'),
|
||||||
|
zhinao: t('provider.zhinao'),
|
||||||
|
zhipu: t('provider.zhipu')
|
||||||
|
} as const
|
||||||
|
return labelMap[key] ?? key
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getProgressLabel = (key: string): string => {
|
||||||
|
const labelMap = {
|
||||||
|
completed: t('backup.progress.completed'),
|
||||||
|
compressing: t('backup.progress.compressing'),
|
||||||
|
copying_files: t('backup.progress.copying_files'),
|
||||||
|
preparing: t('backup.progress.preparing'),
|
||||||
|
title: t('backup.progress.title'),
|
||||||
|
writing_data: t('backup.progress.writing_data')
|
||||||
|
} as const
|
||||||
|
return labelMap[key] ?? key
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getTitleLabel = (key: string): string => {
|
||||||
|
const labelMap = {
|
||||||
|
agents: t('title.agents'),
|
||||||
|
apps: t('title.apps'),
|
||||||
|
files: t('title.files'),
|
||||||
|
home: t('title.home'),
|
||||||
|
knowledge: t('title.knowledge'),
|
||||||
|
launchpad: t('title.launchpad'),
|
||||||
|
'mcp-servers': t('title.mcp-servers'),
|
||||||
|
memories: t('title.memories'),
|
||||||
|
paintings: t('title.paintings'),
|
||||||
|
settings: t('title.settings'),
|
||||||
|
translate: t('title.translate')
|
||||||
|
} as const
|
||||||
|
return labelMap[key] ?? key
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getThemeModeLabel = (key: string): string => {
|
||||||
|
const labelMap = {
|
||||||
|
dark: t('settings.theme.dark'),
|
||||||
|
light: t('settings.theme.light'),
|
||||||
|
system: t('settings.theme.system')
|
||||||
|
} as const
|
||||||
|
return labelMap[key] ?? key
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getSidebarIconLabel = (key: string): string => {
|
||||||
|
const labelMap = {
|
||||||
|
assistants: t('assistants.title'),
|
||||||
|
agents: t('agents.title'),
|
||||||
|
paintings: t('paintings.title'),
|
||||||
|
translate: t('translate.title'),
|
||||||
|
minapp: t('minapp.title'),
|
||||||
|
knowledge: t('knowledge.title'),
|
||||||
|
files: t('files.title')
|
||||||
|
} as const
|
||||||
|
return labelMap[key] ?? key
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getShortcutLabel = (key: string): string => {
|
||||||
|
const labelMap = {
|
||||||
|
action: t('settings.shortcuts.action'),
|
||||||
|
actions: t('settings.shortcuts.actions'),
|
||||||
|
clear_shortcut: t('settings.shortcuts.clear_shortcut'),
|
||||||
|
clear_topic: t('settings.shortcuts.clear_topic'),
|
||||||
|
copy_last_message: t('settings.shortcuts.copy_last_message'),
|
||||||
|
enabled: t('settings.shortcuts.enabled'),
|
||||||
|
exit_fullscreen: t('settings.shortcuts.exit_fullscreen'),
|
||||||
|
label: t('settings.shortcuts.label'),
|
||||||
|
mini_window: t('settings.shortcuts.mini_window'),
|
||||||
|
new_topic: t('settings.shortcuts.new_topic'),
|
||||||
|
press_shortcut: t('settings.shortcuts.press_shortcut'),
|
||||||
|
reset_defaults: t('settings.shortcuts.reset_defaults'),
|
||||||
|
reset_defaults_confirm: t('settings.shortcuts.reset_defaults_confirm'),
|
||||||
|
reset_to_default: t('settings.shortcuts.reset_to_default'),
|
||||||
|
search_message: t('settings.shortcuts.search_message'),
|
||||||
|
search_message_in_chat: t('settings.shortcuts.search_message_in_chat'),
|
||||||
|
selection_assistant_select_text: t('settings.shortcuts.selection_assistant_select_text'),
|
||||||
|
selection_assistant_toggle: t('settings.shortcuts.selection_assistant_toggle'),
|
||||||
|
show_app: t('settings.shortcuts.show_app'),
|
||||||
|
show_settings: t('settings.shortcuts.show_settings'),
|
||||||
|
title: t('settings.shortcuts.title'),
|
||||||
|
toggle_new_context: t('settings.shortcuts.toggle_new_context'),
|
||||||
|
toggle_show_assistants: t('settings.shortcuts.toggle_show_assistants'),
|
||||||
|
toggle_show_topics: t('settings.shortcuts.toggle_show_topics'),
|
||||||
|
zoom_in: t('settings.shortcuts.zoom_in'),
|
||||||
|
zoom_out: t('settings.shortcuts.zoom_out'),
|
||||||
|
zoom_reset: t('settings.shortcuts.zoom_reset')
|
||||||
|
} as const
|
||||||
|
return labelMap[key] ?? key
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getSelectionDescriptionLabel = (key: string): string => {
|
||||||
|
const labelMap = {
|
||||||
|
mac: t('selection.settings.toolbar.trigger_mode.description_note.mac'),
|
||||||
|
windows: t('selection.settings.toolbar.trigger_mode.description_note.windows')
|
||||||
|
} as const
|
||||||
|
return labelMap[key] ?? key
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getPaintingsImageSizeOptionsLabel = (key: string): string => {
|
||||||
|
const labelMap = {
|
||||||
|
auto: t('paintings.image_size_options.auto')
|
||||||
|
} as const
|
||||||
|
return labelMap[key] ?? key
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getPaintingsQualityOptionsLabel = (key: string): string => {
|
||||||
|
const labelMap = {
|
||||||
|
auto: t('paintings.quality_options.auto'),
|
||||||
|
high: t('paintings.quality_options.high'),
|
||||||
|
low: t('paintings.quality_options.low'),
|
||||||
|
medium: t('paintings.quality_options.medium')
|
||||||
|
} as const
|
||||||
|
return labelMap[key] ?? key
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getPaintingsModerationOptionsLabel = (key: string): string => {
|
||||||
|
const labelMap = {
|
||||||
|
auto: t('paintings.moderation_options.auto'),
|
||||||
|
low: t('paintings.moderation_options.low')
|
||||||
|
} as const
|
||||||
|
return labelMap[key] ?? key
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getPaintingsBackgroundOptionsLabel = (key: string): string => {
|
||||||
|
const labelMap = {
|
||||||
|
auto: t('paintings.background_options.auto'),
|
||||||
|
opaque: t('paintings.background_options.opaque'),
|
||||||
|
transparent: t('paintings.background_options.transparent')
|
||||||
|
} as const
|
||||||
|
return labelMap[key] ?? key
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getMcpTypeLabel = (key: string): string => {
|
||||||
|
const labelMap = {
|
||||||
|
inMemory: t('settings.mcp.types.inMemory'),
|
||||||
|
sse: t('settings.mcp.types.sse'),
|
||||||
|
stdio: t('settings.mcp.types.stdio'),
|
||||||
|
streamableHttp: t('settings.mcp.types.streamableHttp')
|
||||||
|
} as const
|
||||||
|
return labelMap[key] ?? key
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getMiniappsStatusLabel = (key: string): string => {
|
||||||
|
const labelMap = {
|
||||||
|
visible: t('settings.miniapps.visible'),
|
||||||
|
disabled: t('settings.miniapps.disabled')
|
||||||
|
} as const
|
||||||
|
return labelMap[key] ?? key
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getHttpMessageLabel = (key: string): string => {
|
||||||
|
const labelMap = {
|
||||||
|
'400': t('error.http.400'),
|
||||||
|
'401': t('error.http.401'),
|
||||||
|
'403': t('error.http.403'),
|
||||||
|
'404': t('error.http.404'),
|
||||||
|
'429': t('error.http.429'),
|
||||||
|
'500': t('error.http.500'),
|
||||||
|
'502': t('error.http.502'),
|
||||||
|
'503': t('error.http.503'),
|
||||||
|
'504': t('error.http.504')
|
||||||
|
} as const
|
||||||
|
return labelMap[key] ?? key
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getReasoningEffortOptionsLabel = (key: string): string => {
|
||||||
|
const labelMap = {
|
||||||
|
auto: t('assistants.settings.reasoning_effort.default'),
|
||||||
|
high: t('assistants.settings.reasoning_effort.high'),
|
||||||
|
label: t('assistants.settings.reasoning_effort.label'),
|
||||||
|
low: t('assistants.settings.reasoning_effort.low'),
|
||||||
|
medium: t('assistants.settings.reasoning_effort.medium'),
|
||||||
|
off: t('assistants.settings.reasoning_effort.off')
|
||||||
|
} as const
|
||||||
|
return labelMap[key] ?? key
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getFileFieldLabel = (key: string): string => {
|
||||||
|
const labelMap = {
|
||||||
|
created_at: t('files.created_at'),
|
||||||
|
size: t('files.size'),
|
||||||
|
name: t('files.name')
|
||||||
|
} as const
|
||||||
|
return labelMap[key] ?? key
|
||||||
|
}
|
||||||
@ -2536,7 +2536,7 @@
|
|||||||
"addServer": {
|
"addServer": {
|
||||||
"create": "快速创建",
|
"create": "快速创建",
|
||||||
"importFrom": {
|
"importFrom": {
|
||||||
"connectionFailed": "連接失敗",
|
"connectionFailed": "连接失败",
|
||||||
"dxt": "导入 DXT 包",
|
"dxt": "导入 DXT 包",
|
||||||
"dxtFile": "DXT 包文件",
|
"dxtFile": "DXT 包文件",
|
||||||
"dxtHelp": "选择包含 MCP 服务器的 .dxt 文件",
|
"dxtHelp": "选择包含 MCP 服务器的 .dxt 文件",
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import {
|
|||||||
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
|
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
|
||||||
import ListItem from '@renderer/components/ListItem'
|
import ListItem from '@renderer/components/ListItem'
|
||||||
import db from '@renderer/databases'
|
import db from '@renderer/databases'
|
||||||
|
import { getFileFieldLabel } from '@renderer/i18n/label'
|
||||||
import { handleDelete, handleRename, sortFiles, tempFilesSort } from '@renderer/services/FileAction'
|
import { handleDelete, handleRename, sortFiles, tempFilesSort } from '@renderer/services/FileAction'
|
||||||
import FileManager from '@renderer/services/FileManager'
|
import FileManager from '@renderer/services/FileManager'
|
||||||
import { FileMetadata, FileTypes } from '@renderer/types'
|
import { FileMetadata, FileTypes } from '@renderer/types'
|
||||||
@ -94,7 +95,7 @@ const FilesPage: FC = () => {
|
|||||||
</SideNav>
|
</SideNav>
|
||||||
<MainContent>
|
<MainContent>
|
||||||
<SortContainer>
|
<SortContainer>
|
||||||
{['created_at', 'size', 'name'].map((field) => (
|
{(['created_at', 'size', 'name'] as const).map((field) => (
|
||||||
<SortButton
|
<SortButton
|
||||||
key={field}
|
key={field}
|
||||||
active={sortField === field}
|
active={sortField === field}
|
||||||
@ -106,7 +107,7 @@ const FilesPage: FC = () => {
|
|||||||
setSortOrder('desc')
|
setSortOrder('desc')
|
||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
{t(`files.${field}`)}
|
{getFileFieldLabel(field)}
|
||||||
{sortField === field && (sortOrder === 'desc' ? <SortDescendingOutlined /> : <SortAscendingOutlined />)}
|
{sortField === field && (sortOrder === 'desc' ? <SortDescendingOutlined /> : <SortAscendingOutlined />)}
|
||||||
</SortButton>
|
</SortButton>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import {
|
|||||||
isSupportedThinkingTokenQwenModel
|
isSupportedThinkingTokenQwenModel
|
||||||
} from '@renderer/config/models'
|
} from '@renderer/config/models'
|
||||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||||
|
import { getReasoningEffortOptionsLabel } from '@renderer/i18n/label'
|
||||||
import { Assistant, Model, ReasoningEffortOptions } from '@renderer/types'
|
import { Assistant, Model, ReasoningEffortOptions } from '@renderer/types'
|
||||||
import { Tooltip } from 'antd'
|
import { Tooltip } from 'antd'
|
||||||
import { FC, ReactElement, useCallback, useEffect, useImperativeHandle, useMemo } from 'react'
|
import { FC, ReactElement, useCallback, useEffect, useImperativeHandle, useMemo } from 'react'
|
||||||
@ -153,13 +154,13 @@ const ThinkingButton: FC<Props> = ({ ref, model, assistant, ToolbarButton }): Re
|
|||||||
// 使用表中定义的选项创建UI选项
|
// 使用表中定义的选项创建UI选项
|
||||||
return supportedOptions.map((option) => ({
|
return supportedOptions.map((option) => ({
|
||||||
level: option,
|
level: option,
|
||||||
label: t(`assistants.settings.reasoning_effort.${option === 'auto' ? 'default' : option}`),
|
label: getReasoningEffortOptionsLabel(option),
|
||||||
description: '',
|
description: '',
|
||||||
icon: createThinkingIcon(option),
|
icon: createThinkingIcon(option),
|
||||||
isSelected: currentReasoningEffort === option,
|
isSelected: currentReasoningEffort === option,
|
||||||
action: () => onThinkingChange(option)
|
action: () => onThinkingChange(option)
|
||||||
}))
|
}))
|
||||||
}, [t, createThinkingIcon, currentReasoningEffort, supportedOptions, onThinkingChange])
|
}, [createThinkingIcon, currentReasoningEffort, supportedOptions, onThinkingChange])
|
||||||
|
|
||||||
const openQuickPanel = useCallback(() => {
|
const openQuickPanel = useCallback(() => {
|
||||||
quickPanel.open({
|
quickPanel.open({
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { getHttpMessageLabel } from '@renderer/i18n/label'
|
||||||
import type { ErrorMessageBlock } from '@renderer/types/newMessage'
|
import type { ErrorMessageBlock } from '@renderer/types/newMessage'
|
||||||
import { Alert as AntdAlert } from 'antd'
|
import { Alert as AntdAlert } from 'antd'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
@ -18,7 +19,7 @@ const MessageErrorInfo: React.FC<{ block: ErrorMessageBlock }> = ({ block }) =>
|
|||||||
const HTTP_ERROR_CODES = [400, 401, 403, 404, 429, 500, 502, 503, 504]
|
const HTTP_ERROR_CODES = [400, 401, 403, 404, 429, 500, 502, 503, 504]
|
||||||
|
|
||||||
if (block.error && HTTP_ERROR_CODES.includes(block.error?.status)) {
|
if (block.error && HTTP_ERROR_CODES.includes(block.error?.status)) {
|
||||||
return <Alert description={t(`error.http.${block.error.status}`)} message={block.error?.message} type="error" />
|
return <Alert description={getHttpMessageLabel(block.error.status)} message={block.error?.message} type="error" />
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block?.error?.message) {
|
if (block?.error?.message) {
|
||||||
|
|||||||
@ -72,7 +72,7 @@ const MessageGroupModelList: FC<MessageGroupModelListProps> = ({ messages, selec
|
|||||||
<Tooltip
|
<Tooltip
|
||||||
title={
|
title={
|
||||||
isCompact
|
isCompact
|
||||||
? t(`message.message.multi_model_style.fold.expand`)
|
? t('message.message.multi_model_style.fold.expand')
|
||||||
: t('message.message.multi_model_style.fold.compress')
|
: t('message.message.multi_model_style.fold.compress')
|
||||||
}
|
}
|
||||||
placement="top"
|
placement="top"
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import {
|
|||||||
} from '@hello-pangea/dnd'
|
} from '@hello-pangea/dnd'
|
||||||
import { DEFAULT_MIN_APPS } from '@renderer/config/minapps'
|
import { DEFAULT_MIN_APPS } from '@renderer/config/minapps'
|
||||||
import { useMinapps } from '@renderer/hooks/useMinapps'
|
import { useMinapps } from '@renderer/hooks/useMinapps'
|
||||||
|
import { getMiniappsStatusLabel } from '@renderer/i18n/label'
|
||||||
import { MinAppType } from '@renderer/types'
|
import { MinAppType } from '@renderer/types'
|
||||||
import { FC, useCallback } from 'react'
|
import { FC, useCallback } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
@ -115,7 +116,7 @@ const MiniAppIconsManager: FC<MiniAppManagerProps> = ({
|
|||||||
<ProgramSection style={{ background: 'transparent' }}>
|
<ProgramSection style={{ background: 'transparent' }}>
|
||||||
{(['visible', 'disabled'] as const).map((listType) => (
|
{(['visible', 'disabled'] as const).map((listType) => (
|
||||||
<ProgramColumn key={listType}>
|
<ProgramColumn key={listType}>
|
||||||
<h4>{t(`settings.miniapps.${listType}`)}</h4>
|
<h4>{getMiniappsStatusLabel(listType)}</h4>
|
||||||
<Droppable droppableId={listType}>
|
<Droppable droppableId={listType}>
|
||||||
{(provided: DroppableProvided) => (
|
{(provided: DroppableProvided) => (
|
||||||
<ProgramList ref={provided.innerRef} {...provided.droppableProps}>
|
<ProgramList ref={provided.innerRef} {...provided.droppableProps}>
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import { usePaintings } from '@renderer/hooks/usePaintings'
|
|||||||
import { useAllProviders } from '@renderer/hooks/useProvider'
|
import { useAllProviders } from '@renderer/hooks/useProvider'
|
||||||
import { useRuntime } from '@renderer/hooks/useRuntime'
|
import { useRuntime } from '@renderer/hooks/useRuntime'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
|
import { getProviderLabel } from '@renderer/i18n/label'
|
||||||
import FileManager from '@renderer/services/FileManager'
|
import FileManager from '@renderer/services/FileManager'
|
||||||
import { translateText } from '@renderer/services/TranslateService'
|
import { translateText } from '@renderer/services/TranslateService'
|
||||||
import { useAppDispatch } from '@renderer/store'
|
import { useAppDispatch } from '@renderer/store'
|
||||||
@ -58,9 +59,16 @@ const AihubmixPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
const providers = useAllProviders()
|
const providers = useAllProviders()
|
||||||
const providerOptions = Options.map((option) => {
|
const providerOptions = Options.map((option) => {
|
||||||
const provider = providers.find((p) => p.id === option)
|
const provider = providers.find((p) => p.id === option)
|
||||||
return {
|
if (provider) {
|
||||||
label: t(`provider.${provider?.id}`),
|
return {
|
||||||
value: provider?.id
|
label: getProviderLabel(provider.id),
|
||||||
|
value: provider.id
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
label: 'Unknown Provider',
|
||||||
|
value: undefined
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { useTheme } from '@renderer/context/ThemeProvider'
|
|||||||
import { usePaintings } from '@renderer/hooks/usePaintings'
|
import { usePaintings } from '@renderer/hooks/usePaintings'
|
||||||
import { useAllProviders } from '@renderer/hooks/useProvider'
|
import { useAllProviders } from '@renderer/hooks/useProvider'
|
||||||
import { useRuntime } from '@renderer/hooks/useRuntime'
|
import { useRuntime } from '@renderer/hooks/useRuntime'
|
||||||
|
import { getProviderLabel } from '@renderer/i18n/label'
|
||||||
import FileManager from '@renderer/services/FileManager'
|
import FileManager from '@renderer/services/FileManager'
|
||||||
import { useAppDispatch } from '@renderer/store'
|
import { useAppDispatch } from '@renderer/store'
|
||||||
import { setGenerating } from '@renderer/store/runtime'
|
import { setGenerating } from '@renderer/store/runtime'
|
||||||
@ -49,9 +50,16 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
const providers = useAllProviders()
|
const providers = useAllProviders()
|
||||||
const providerOptions = Options.map((option) => {
|
const providerOptions = Options.map((option) => {
|
||||||
const provider = providers.find((p) => p.id === option)
|
const provider = providers.find((p) => p.id === option)
|
||||||
return {
|
if (provider) {
|
||||||
label: t(`provider.${provider?.id}`),
|
return {
|
||||||
value: provider?.id
|
label: getProviderLabel(provider.id),
|
||||||
|
value: provider.id
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
label: 'Unknown Provider',
|
||||||
|
value: undefined
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,13 @@ import { usePaintings } from '@renderer/hooks/usePaintings'
|
|||||||
import { useAllProviders } from '@renderer/hooks/useProvider'
|
import { useAllProviders } from '@renderer/hooks/useProvider'
|
||||||
import { useRuntime } from '@renderer/hooks/useRuntime'
|
import { useRuntime } from '@renderer/hooks/useRuntime'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
|
import {
|
||||||
|
getPaintingsBackgroundOptionsLabel,
|
||||||
|
getPaintingsImageSizeOptionsLabel,
|
||||||
|
getPaintingsModerationOptionsLabel,
|
||||||
|
getPaintingsQualityOptionsLabel,
|
||||||
|
getProviderLabel
|
||||||
|
} from '@renderer/i18n/label'
|
||||||
import PaintingsList from '@renderer/pages/paintings/components/PaintingsList'
|
import PaintingsList from '@renderer/pages/paintings/components/PaintingsList'
|
||||||
import { DEFAULT_PAINTING, MODELS, SUPPORTED_MODELS } from '@renderer/pages/paintings/config/NewApiConfig'
|
import { DEFAULT_PAINTING, MODELS, SUPPORTED_MODELS } from '@renderer/pages/paintings/config/NewApiConfig'
|
||||||
import FileManager from '@renderer/services/FileManager'
|
import FileManager from '@renderer/services/FileManager'
|
||||||
@ -53,9 +60,16 @@ const NewApiPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
const providers = useAllProviders()
|
const providers = useAllProviders()
|
||||||
const providerOptions = Options.map((option) => {
|
const providerOptions = Options.map((option) => {
|
||||||
const provider = providers.find((p) => p.id === option)
|
const provider = providers.find((p) => p.id === option)
|
||||||
return {
|
if (provider) {
|
||||||
label: t(`provider.${provider?.id}`),
|
return {
|
||||||
value: provider?.id
|
label: getProviderLabel(provider.id),
|
||||||
|
value: provider.id
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
label: 'Unknown Provider',
|
||||||
|
value: undefined
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
@ -566,7 +580,7 @@ const NewApiPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
<Select value={painting.size} onChange={handleSizeChange} style={{ width: '100%', marginBottom: 15 }}>
|
<Select value={painting.size} onChange={handleSizeChange} style={{ width: '100%', marginBottom: 15 }}>
|
||||||
{selectedModelConfig.imageSizes.map((s) => (
|
{selectedModelConfig.imageSizes.map((s) => (
|
||||||
<Select.Option value={s.value} key={s.value}>
|
<Select.Option value={s.value} key={s.value}>
|
||||||
{t(`paintings.image_size_options.${s.value}`, { defaultValue: s.value })}
|
{getPaintingsImageSizeOptionsLabel(s.value) ?? s.value}
|
||||||
</Select.Option>
|
</Select.Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
@ -583,7 +597,7 @@ const NewApiPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
style={{ width: '100%', marginBottom: 15 }}>
|
style={{ width: '100%', marginBottom: 15 }}>
|
||||||
{selectedModelConfig.quality.map((q) => (
|
{selectedModelConfig.quality.map((q) => (
|
||||||
<Select.Option value={q.value} key={q.value}>
|
<Select.Option value={q.value} key={q.value}>
|
||||||
{t(`paintings.quality_options.${q.value}`, { defaultValue: q.value })}
|
{getPaintingsQualityOptionsLabel(q.value) ?? q.value}
|
||||||
</Select.Option>
|
</Select.Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
@ -602,7 +616,7 @@ const NewApiPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
style={{ width: '100%', marginBottom: 15 }}>
|
style={{ width: '100%', marginBottom: 15 }}>
|
||||||
{selectedModelConfig.moderation.map((m) => (
|
{selectedModelConfig.moderation.map((m) => (
|
||||||
<Select.Option value={m.value} key={m.value}>
|
<Select.Option value={m.value} key={m.value}>
|
||||||
{t(`paintings.moderation_options.${m.value}`, { defaultValue: m.value })}
|
{getPaintingsModerationOptionsLabel(m.value) ?? m.value}
|
||||||
</Select.Option>
|
</Select.Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
@ -621,7 +635,7 @@ const NewApiPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
style={{ width: '100%', marginBottom: 15 }}>
|
style={{ width: '100%', marginBottom: 15 }}>
|
||||||
{selectedModelConfig.background.map((b) => (
|
{selectedModelConfig.background.map((b) => (
|
||||||
<Select.Option value={b.value} key={b.value}>
|
<Select.Option value={b.value} key={b.value}>
|
||||||
{t(`paintings.background_options.${b.value}`, { defaultValue: b.value })}
|
{getPaintingsBackgroundOptionsLabel(b.value) ?? b.value}
|
||||||
</Select.Option>
|
</Select.Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import { usePaintings } from '@renderer/hooks/usePaintings'
|
|||||||
import { useAllProviders } from '@renderer/hooks/useProvider'
|
import { useAllProviders } from '@renderer/hooks/useProvider'
|
||||||
import { useRuntime } from '@renderer/hooks/useRuntime'
|
import { useRuntime } from '@renderer/hooks/useRuntime'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
|
import { getProviderLabel } from '@renderer/i18n/label'
|
||||||
import { getProviderByModel } from '@renderer/services/AssistantService'
|
import { getProviderByModel } from '@renderer/services/AssistantService'
|
||||||
import FileManager from '@renderer/services/FileManager'
|
import FileManager from '@renderer/services/FileManager'
|
||||||
import { translateText } from '@renderer/services/TranslateService'
|
import { translateText } from '@renderer/services/TranslateService'
|
||||||
@ -100,9 +101,16 @@ const SiliconPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
const providers = useAllProviders()
|
const providers = useAllProviders()
|
||||||
const providerOptions = Options.map((option) => {
|
const providerOptions = Options.map((option) => {
|
||||||
const provider = providers.find((p) => p.id === option)
|
const provider = providers.find((p) => p.id === option)
|
||||||
return {
|
if (provider) {
|
||||||
label: t(`provider.${provider?.id}`),
|
return {
|
||||||
value: provider?.id
|
label: getProviderLabel(provider.id),
|
||||||
|
value: provider.id
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
label: 'Unknown Provider',
|
||||||
|
value: undefined
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const [currentImageIndex, setCurrentImageIndex] = useState(0)
|
const [currentImageIndex, setCurrentImageIndex] = useState(0)
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import { usePaintings } from '@renderer/hooks/usePaintings'
|
|||||||
import { useAllProviders } from '@renderer/hooks/useProvider'
|
import { useAllProviders } from '@renderer/hooks/useProvider'
|
||||||
import { useRuntime } from '@renderer/hooks/useRuntime'
|
import { useRuntime } from '@renderer/hooks/useRuntime'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
|
import { getProviderLabel } from '@renderer/i18n/label'
|
||||||
import FileManager from '@renderer/services/FileManager'
|
import FileManager from '@renderer/services/FileManager'
|
||||||
import { translateText } from '@renderer/services/TranslateService'
|
import { translateText } from '@renderer/services/TranslateService'
|
||||||
import { useAppDispatch } from '@renderer/store'
|
import { useAppDispatch } from '@renderer/store'
|
||||||
@ -55,9 +56,16 @@ const TokenFluxPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
|
|
||||||
const providerOptions = Options.map((option) => {
|
const providerOptions = Options.map((option) => {
|
||||||
const provider = providers.find((p) => p.id === option)
|
const provider = providers.find((p) => p.id === option)
|
||||||
return {
|
if (provider) {
|
||||||
label: t(`provider.${provider?.id}`),
|
return {
|
||||||
value: provider?.id
|
label: getProviderLabel(provider.id),
|
||||||
|
value: provider.id
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
label: 'Unknown Provider',
|
||||||
|
value: undefined
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -87,49 +87,49 @@ const DataSettings: FC = () => {
|
|||||||
|
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
{ key: 'divider_0', isDivider: true, text: t('settings.data.divider.basic') },
|
{ key: 'divider_0', isDivider: true, text: t('settings.data.divider.basic') },
|
||||||
{ key: 'data', title: 'settings.data.data.title', icon: <FolderCog size={16} /> },
|
{ key: 'data', title: t('settings.data.data.title'), icon: <FolderCog size={16} /> },
|
||||||
{ key: 'divider_1', isDivider: true, text: t('settings.data.divider.cloud_storage') },
|
{ key: 'divider_1', isDivider: true, text: t('settings.data.divider.cloud_storage') },
|
||||||
{ key: 'local_backup', title: 'settings.data.local.title', icon: <FolderCog size={16} /> },
|
{ key: 'local_backup', title: t('settings.data.local.title'), icon: <FolderCog size={16} /> },
|
||||||
{ key: 'webdav', title: 'settings.data.webdav.title', icon: <CloudSyncOutlined style={{ fontSize: 16 }} /> },
|
{ key: 'webdav', title: t('settings.data.webdav.title'), icon: <CloudSyncOutlined style={{ fontSize: 16 }} /> },
|
||||||
{ key: 'nutstore', title: 'settings.data.nutstore.title', icon: <NutstoreIcon /> },
|
{ key: 'nutstore', title: t('settings.data.nutstore.title'), icon: <NutstoreIcon /> },
|
||||||
{ key: 's3', title: 'settings.data.s3.title', icon: <CloudServerOutlined style={{ fontSize: 16 }} /> },
|
{ key: 's3', title: t('settings.data.s3.title.label'), icon: <CloudServerOutlined style={{ fontSize: 16 }} /> },
|
||||||
{ key: 'divider_2', isDivider: true, text: t('settings.data.divider.export_settings') },
|
{ key: 'divider_2', isDivider: true, text: t('settings.data.divider.export_settings') },
|
||||||
{
|
{
|
||||||
key: 'export_menu',
|
key: 'export_menu',
|
||||||
title: 'settings.data.export_menu.title',
|
title: t('settings.data.export_menu.title'),
|
||||||
icon: <FolderInput size={16} />
|
icon: <FolderInput size={16} />
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'markdown_export',
|
key: 'markdown_export',
|
||||||
title: 'settings.data.markdown_export.title',
|
title: t('settings.data.markdown_export.title'),
|
||||||
icon: <FileText size={16} />
|
icon: <FileText size={16} />
|
||||||
},
|
},
|
||||||
|
|
||||||
{ key: 'divider_3', isDivider: true, text: t('settings.data.divider.third_party') },
|
{ key: 'divider_3', isDivider: true, text: t('settings.data.divider.third_party') },
|
||||||
{ key: 'notion', title: 'settings.data.notion.title', icon: <i className="iconfont icon-notion" /> },
|
{ key: 'notion', title: t('settings.data.notion.title'), icon: <i className="iconfont icon-notion" /> },
|
||||||
{
|
{
|
||||||
key: 'yuque',
|
key: 'yuque',
|
||||||
title: 'settings.data.yuque.title',
|
title: t('settings.data.yuque.title'),
|
||||||
icon: <YuqueOutlined style={{ fontSize: 16 }} />
|
icon: <YuqueOutlined style={{ fontSize: 16 }} />
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'joplin',
|
key: 'joplin',
|
||||||
title: 'settings.data.joplin.title',
|
title: t('settings.data.joplin.title'),
|
||||||
icon: <JoplinIcon />
|
icon: <JoplinIcon />
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'obsidian',
|
key: 'obsidian',
|
||||||
title: 'settings.data.obsidian.title',
|
title: t('settings.data.obsidian.title'),
|
||||||
icon: <i className="iconfont icon-obsidian" />
|
icon: <i className="iconfont icon-obsidian" />
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'siyuan',
|
key: 'siyuan',
|
||||||
title: 'settings.data.siyuan.title',
|
title: t('settings.data.siyuan.title'),
|
||||||
icon: <SiyuanIcon />
|
icon: <SiyuanIcon />
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'agentssubscribe_url',
|
key: 'agentssubscribe_url',
|
||||||
title: 'agents.settings.title',
|
title: t('agents.settings.title'),
|
||||||
icon: <Sparkle size={16} className="icon" />
|
icon: <Sparkle size={16} className="icon" />
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -568,7 +568,7 @@ const DataSettings: FC = () => {
|
|||||||
) : (
|
) : (
|
||||||
<ListItem
|
<ListItem
|
||||||
key={item.key}
|
key={item.key}
|
||||||
title={t(item.title || '')}
|
title={item.title}
|
||||||
active={menu === item.key}
|
active={menu === item.key}
|
||||||
onClick={() => setMenu(item.key)}
|
onClick={() => setMenu(item.key)}
|
||||||
titleStyle={{ fontWeight: 500 }}
|
titleStyle={{ fontWeight: 500 }}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
DroppableProvided,
|
DroppableProvided,
|
||||||
DropResult
|
DropResult
|
||||||
} from '@hello-pangea/dnd'
|
} from '@hello-pangea/dnd'
|
||||||
|
import { getSidebarIconLabel } from '@renderer/i18n/label'
|
||||||
import { useAppDispatch } from '@renderer/store'
|
import { useAppDispatch } from '@renderer/store'
|
||||||
import { setSidebarIcons } from '@renderer/store/settings'
|
import { setSidebarIcons } from '@renderer/store/settings'
|
||||||
import { message } from 'antd'
|
import { message } from 'antd'
|
||||||
@ -136,7 +137,7 @@ const SidebarIconsManager: FC<SidebarIconsManagerProps> = ({
|
|||||||
<IconItem ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
|
<IconItem ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
|
||||||
<IconContent>
|
<IconContent>
|
||||||
{renderIcon(icon)}
|
{renderIcon(icon)}
|
||||||
<span>{t(`${icon}.title`)}</span>
|
<span>{getSidebarIconLabel(icon)}</span>
|
||||||
</IconContent>
|
</IconContent>
|
||||||
{icon !== 'assistants' && (
|
{icon !== 'assistants' && (
|
||||||
<CloseButton onClick={() => onMoveIcon(icon, 'visible')}>
|
<CloseButton onClick={() => onMoveIcon(icon, 'visible')}>
|
||||||
@ -166,7 +167,7 @@ const SidebarIconsManager: FC<SidebarIconsManagerProps> = ({
|
|||||||
<IconItem ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
|
<IconItem ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
|
||||||
<IconContent>
|
<IconContent>
|
||||||
{renderIcon(icon)}
|
{renderIcon(icon)}
|
||||||
<span>{t(`${icon}.title`)}</span>
|
<span>{getSidebarIconLabel(icon)}</span>
|
||||||
</IconContent>
|
</IconContent>
|
||||||
<CloseButton onClick={() => onMoveIcon(icon, 'disabled')}>
|
<CloseButton onClick={() => onMoveIcon(icon, 'disabled')}>
|
||||||
<CloseOutlined />
|
<CloseOutlined />
|
||||||
|
|||||||
@ -236,7 +236,7 @@ const AddMcpServerModal: FC<AddMcpServerModalProps> = ({
|
|||||||
.catch((connError: any) => {
|
.catch((connError: any) => {
|
||||||
logger.error(`Connectivity check failed for ${newServer.name}:`, connError)
|
logger.error(`Connectivity check failed for ${newServer.name}:`, connError)
|
||||||
window.message.error({
|
window.message.error({
|
||||||
content: t(`${newServer.name} settings.mcp.addServer.importFrom.connectionFailed`),
|
content: newServer.name + t('settings.mcp.addServer.importFrom.connectionFailed'),
|
||||||
key: 'mcp-quick-add-failed'
|
key: 'mcp-quick-add-failed'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { CheckOutlined, PlusOutlined } from '@ant-design/icons'
|
import { CheckOutlined, PlusOutlined } from '@ant-design/icons'
|
||||||
import { useMCPServers } from '@renderer/hooks/useMCPServers'
|
import { useMCPServers } from '@renderer/hooks/useMCPServers'
|
||||||
|
import { getMcpTypeLabel } from '@renderer/i18n/label'
|
||||||
import { builtinMCPServers } from '@renderer/store/mcp'
|
import { builtinMCPServers } from '@renderer/store/mcp'
|
||||||
import { Button, Popover, Tag } from 'antd'
|
import { Button, Popover, Tag } from 'antd'
|
||||||
import { FC } from 'react'
|
import { FC } from 'react'
|
||||||
@ -55,7 +56,7 @@ const BuiltinMCPServersSection: FC = () => {
|
|||||||
</Popover>
|
</Popover>
|
||||||
<ServerFooter>
|
<ServerFooter>
|
||||||
<Tag color="processing" style={{ borderRadius: 20, margin: 0, fontWeight: 500 }}>
|
<Tag color="processing" style={{ borderRadius: 20, margin: 0, fontWeight: 500 }}>
|
||||||
{t(`settings.mcp.types.${server.type || 'stdio'}`)}
|
{getMcpTypeLabel(server.type ?? 'stdio')}
|
||||||
</Tag>
|
</Tag>
|
||||||
{server.env && Object.keys(server.env).length > 0 && (
|
{server.env && Object.keys(server.env).length > 0 && (
|
||||||
<Tag color="warning" style={{ borderRadius: 20, margin: 0, fontWeight: 500 }}>
|
<Tag color="warning" style={{ borderRadius: 20, margin: 0, fontWeight: 500 }}>
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { nanoid } from '@reduxjs/toolkit'
|
|||||||
import { DraggableList } from '@renderer/components/DraggableList'
|
import { DraggableList } from '@renderer/components/DraggableList'
|
||||||
import Scrollbar from '@renderer/components/Scrollbar'
|
import Scrollbar from '@renderer/components/Scrollbar'
|
||||||
import { useMCPServers } from '@renderer/hooks/useMCPServers'
|
import { useMCPServers } from '@renderer/hooks/useMCPServers'
|
||||||
|
import { getMcpTypeLabel } from '@renderer/i18n/label'
|
||||||
import { MCPServer } from '@renderer/types'
|
import { MCPServer } from '@renderer/types'
|
||||||
import { formatMcpError } from '@renderer/utils/error'
|
import { formatMcpError } from '@renderer/utils/error'
|
||||||
import { Badge, Button, Dropdown, Empty, Switch, Tag } from 'antd'
|
import { Badge, Button, Dropdown, Empty, Switch, Tag } from 'antd'
|
||||||
@ -221,7 +222,7 @@ const McpServersList: FC = () => {
|
|||||||
<ServerDescription>{server.description}</ServerDescription>
|
<ServerDescription>{server.description}</ServerDescription>
|
||||||
<ServerFooter>
|
<ServerFooter>
|
||||||
<Tag color="processing" style={{ borderRadius: 20, margin: 0, fontWeight: 500 }}>
|
<Tag color="processing" style={{ borderRadius: 20, margin: 0, fontWeight: 500 }}>
|
||||||
{t(`settings.mcp.types.${server.type || 'stdio'}`)}
|
{getMcpTypeLabel(server.type ?? 'stdio')}
|
||||||
</Tag>
|
</Tag>
|
||||||
{server.provider && (
|
{server.provider && (
|
||||||
<Tag color="success" style={{ borderRadius: 20, margin: 0, fontWeight: 500 }}>
|
<Tag color="success" style={{ borderRadius: 20, margin: 0, fontWeight: 500 }}>
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { HStack } from '@renderer/components/Layout'
|
|||||||
import OAuthButton from '@renderer/components/OAuth/OAuthButton'
|
import OAuthButton from '@renderer/components/OAuth/OAuthButton'
|
||||||
import { PROVIDER_CONFIG } from '@renderer/config/providers'
|
import { PROVIDER_CONFIG } from '@renderer/config/providers'
|
||||||
import { useProvider } from '@renderer/hooks/useProvider'
|
import { useProvider } from '@renderer/hooks/useProvider'
|
||||||
|
import { getProviderLabel } from '@renderer/i18n/label'
|
||||||
import { providerBills, providerCharge } from '@renderer/utils/oauth'
|
import { providerBills, providerCharge } from '@renderer/utils/oauth'
|
||||||
import { Button } from 'antd'
|
import { Button } from 'antd'
|
||||||
import { isEmpty } from 'lodash'
|
import { isEmpty } from 'lodash'
|
||||||
@ -44,7 +45,7 @@ const ProviderOAuth: FC<Props> = ({ providerId }) => {
|
|||||||
<ProviderLogo src={PROVIDER_LOGO_MAP[provider.id]} />
|
<ProviderLogo src={PROVIDER_LOGO_MAP[provider.id]} />
|
||||||
{isEmpty(provider.apiKey) ? (
|
{isEmpty(provider.apiKey) ? (
|
||||||
<OAuthButton provider={provider} onSuccess={setApiKey}>
|
<OAuthButton provider={provider} onSuccess={setApiKey}>
|
||||||
{t('settings.provider.oauth.button', { provider: t(`provider.${provider.id}`) })}
|
{t('settings.provider.oauth.button', { provider: getProviderLabel(provider.id) })}
|
||||||
</OAuthButton>
|
</OAuthButton>
|
||||||
) : (
|
) : (
|
||||||
<HStack gap={10}>
|
<HStack gap={10}>
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { loggerService } from '@logger'
|
|||||||
import Scrollbar from '@renderer/components/Scrollbar'
|
import Scrollbar from '@renderer/components/Scrollbar'
|
||||||
import { getProviderLogo } from '@renderer/config/providers'
|
import { getProviderLogo } from '@renderer/config/providers'
|
||||||
import { useAllProviders, useProviders } from '@renderer/hooks/useProvider'
|
import { useAllProviders, useProviders } from '@renderer/hooks/useProvider'
|
||||||
|
import { getProviderLabel } from '@renderer/i18n/label'
|
||||||
import ImageStorage from '@renderer/services/ImageStorage'
|
import ImageStorage from '@renderer/services/ImageStorage'
|
||||||
import { INITIAL_PROVIDERS } from '@renderer/store/llm'
|
import { INITIAL_PROVIDERS } from '@renderer/store/llm'
|
||||||
import { Provider, ProviderType } from '@renderer/types'
|
import { Provider, ProviderType } from '@renderer/types'
|
||||||
@ -101,7 +102,7 @@ const ProvidersList: FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const providerDisplayName = existingProvider.isSystem
|
const providerDisplayName = existingProvider.isSystem
|
||||||
? t(`provider.${existingProvider.id}`)
|
? getProviderLabel(existingProvider.id)
|
||||||
: existingProvider.name
|
: existingProvider.name
|
||||||
|
|
||||||
// 检查是否已有 API Key
|
// 检查是否已有 API Key
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { isMac, isWin } from '@renderer/config/constant'
|
import { isMac, isWin } from '@renderer/config/constant'
|
||||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||||
import { useSelectionAssistant } from '@renderer/hooks/useSelectionAssistant'
|
import { useSelectionAssistant } from '@renderer/hooks/useSelectionAssistant'
|
||||||
|
import { getSelectionDescriptionLabel } from '@renderer/i18n/label'
|
||||||
import { FilterMode, TriggerMode } from '@renderer/types/selectionTypes'
|
import { FilterMode, TriggerMode } from '@renderer/types/selectionTypes'
|
||||||
import SelectionToolbar from '@renderer/windows/selection/toolbar/SelectionToolbar'
|
import SelectionToolbar from '@renderer/windows/selection/toolbar/SelectionToolbar'
|
||||||
import { Button, Radio, Row, Slider, Switch, Tooltip } from 'antd'
|
import { Button, Radio, Row, Slider, Switch, Tooltip } from 'antd'
|
||||||
@ -132,10 +133,8 @@ const SelectionAssistantSettings: FC = () => {
|
|||||||
<SettingLabel>
|
<SettingLabel>
|
||||||
<SettingRowTitle>
|
<SettingRowTitle>
|
||||||
<div style={{ marginRight: '4px' }}>{t('selection.settings.toolbar.trigger_mode.title')}</div>
|
<div style={{ marginRight: '4px' }}>{t('selection.settings.toolbar.trigger_mode.title')}</div>
|
||||||
<Tooltip
|
{/* FIXME: 没有考虑Linux? */}
|
||||||
placement="top"
|
<Tooltip placement="top" title={getSelectionDescriptionLabel(isWin ? 'windows' : 'mac')} arrow>
|
||||||
title={t(`selection.settings.toolbar.trigger_mode.description_note.${isWin ? 'windows' : 'mac'}`)}
|
|
||||||
arrow>
|
|
||||||
<QuestionIcon size={14} />
|
<QuestionIcon size={14} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</SettingRowTitle>
|
</SettingRowTitle>
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { HStack } from '@renderer/components/Layout'
|
|||||||
import { isMac, isWin } from '@renderer/config/constant'
|
import { isMac, isWin } from '@renderer/config/constant'
|
||||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||||
import { useShortcuts } from '@renderer/hooks/useShortcuts'
|
import { useShortcuts } from '@renderer/hooks/useShortcuts'
|
||||||
|
import { getShortcutLabel } from '@renderer/i18n/label'
|
||||||
import { useAppDispatch } from '@renderer/store'
|
import { useAppDispatch } from '@renderer/store'
|
||||||
import { initialState, resetShortcuts, toggleShortcut, updateShortcut } from '@renderer/store/shortcuts'
|
import { initialState, resetShortcuts, toggleShortcut, updateShortcut } from '@renderer/store/shortcuts'
|
||||||
import { Shortcut } from '@renderer/types'
|
import { Shortcut } from '@renderer/types'
|
||||||
@ -400,7 +401,7 @@ const ShortcutSettings: FC = () => {
|
|||||||
<SettingDivider style={{ marginBottom: 0 }} />
|
<SettingDivider style={{ marginBottom: 0 }} />
|
||||||
<Table
|
<Table
|
||||||
columns={columns as ColumnsType<unknown>}
|
columns={columns as ColumnsType<unknown>}
|
||||||
dataSource={shortcuts.map((s) => ({ ...s, name: t(`settings.shortcuts.${s.key}`) }))}
|
dataSource={shortcuts.map((s) => ({ ...s, name: getShortcutLabel(s.key) }))}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
size="middle"
|
size="middle"
|
||||||
showHeader={false}
|
showHeader={false}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import i18n from '@renderer/i18n'
|
import { getProviderLabel } from '@renderer/i18n/label'
|
||||||
import store from '@renderer/store'
|
import store from '@renderer/store'
|
||||||
import { Provider } from '@renderer/types'
|
import { Provider } from '@renderer/types'
|
||||||
|
|
||||||
@ -9,7 +9,7 @@ export function getProviderName(id: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (provider.isSystem) {
|
if (provider.isSystem) {
|
||||||
return i18n.t(`provider.${provider.id}`, { defaultValue: provider.name })
|
return getProviderLabel(provider.id) ?? provider.name
|
||||||
}
|
}
|
||||||
|
|
||||||
return provider?.name
|
return provider?.name
|
||||||
|
|||||||
@ -202,13 +202,14 @@ const migrateConfig = {
|
|||||||
'8': (state: RootState) => {
|
'8': (state: RootState) => {
|
||||||
try {
|
try {
|
||||||
const fixAssistantName = (assistant: Assistant) => {
|
const fixAssistantName = (assistant: Assistant) => {
|
||||||
|
// 2025/07/25 这俩键早没了,从远古版本迁移包出错的
|
||||||
if (isEmpty(assistant.name)) {
|
if (isEmpty(assistant.name)) {
|
||||||
assistant.name = i18n.t(`assistant.${assistant.id}.name`)
|
assistant.name = i18n.t('chat.default.name')
|
||||||
}
|
}
|
||||||
|
|
||||||
assistant.topics = assistant.topics.map((topic) => {
|
assistant.topics = assistant.topics.map((topic) => {
|
||||||
if (isEmpty(topic.name)) {
|
if (isEmpty(topic.name)) {
|
||||||
topic.name = i18n.t(`assistant.${assistant.id}.topic.name`)
|
topic.name = i18n.t('chat.default.topic.name')
|
||||||
}
|
}
|
||||||
return topic
|
return topic
|
||||||
})
|
})
|
||||||
|
|||||||
@ -83,7 +83,7 @@ describe('match', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should match i18n name for system provider', () => {
|
it('should match i18n name for system provider', () => {
|
||||||
expect(matchKeywordsInProvider('i18n:provider.sys', sysProvider)).toBe(true)
|
expect(matchKeywordsInProvider('sys', sysProvider)).toBe(true)
|
||||||
expect(matchKeywordsInProvider('SystemProvider', sysProvider)).toBe(false)
|
expect(matchKeywordsInProvider('SystemProvider', sysProvider)).toBe(false)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -108,8 +108,8 @@ describe('match', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should match model name and i18n provider name for system provider', () => {
|
it('should match model name and i18n provider name for system provider', () => {
|
||||||
expect(matchKeywordsInModel('gpt-4.1 i18n:provider.sys', model, sysProvider)).toBe(true)
|
expect(matchKeywordsInModel('gpt-4.1 sys', model, sysProvider)).toBe(true)
|
||||||
expect(matchKeywordsInModel('i18n:provider.sys', model, sysProvider)).toBe(true)
|
expect(matchKeywordsInModel('sys', model, sysProvider)).toBe(true)
|
||||||
expect(matchKeywordsInModel('SystemProvider', model, sysProvider)).toBe(false)
|
expect(matchKeywordsInModel('SystemProvider', model, sysProvider)).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { loggerService } from '@logger'
|
import { loggerService } from '@logger'
|
||||||
import { Client } from '@notionhq/client'
|
import { Client } from '@notionhq/client'
|
||||||
import i18n from '@renderer/i18n'
|
import i18n from '@renderer/i18n'
|
||||||
|
import { getProviderLabel } from '@renderer/i18n/label'
|
||||||
import { getMessageTitle } from '@renderer/services/MessagesService'
|
import { getMessageTitle } from '@renderer/services/MessagesService'
|
||||||
import store from '@renderer/store'
|
import store from '@renderer/store'
|
||||||
import { setExportState } from '@renderer/store/runtime'
|
import { setExportState } from '@renderer/store/runtime'
|
||||||
@ -56,7 +57,7 @@ export function getTitleFromString(str: string, length: number = 80) {
|
|||||||
return title
|
return title
|
||||||
}
|
}
|
||||||
|
|
||||||
const getRoleText = (role: string, modelName?: string, modelProvider?: string) => {
|
const getRoleText = (role: string, modelName?: string, providerId?: string) => {
|
||||||
const { showModelNameInMarkdown, showModelProviderInMarkdown } = store.getState().settings
|
const { showModelNameInMarkdown, showModelProviderInMarkdown } = store.getState().settings
|
||||||
|
|
||||||
if (role === 'user') {
|
if (role === 'user') {
|
||||||
@ -67,14 +68,14 @@ const getRoleText = (role: string, modelName?: string, modelProvider?: string) =
|
|||||||
let assistantText = '🤖 '
|
let assistantText = '🤖 '
|
||||||
if (showModelNameInMarkdown && modelName) {
|
if (showModelNameInMarkdown && modelName) {
|
||||||
assistantText += `${modelName}`
|
assistantText += `${modelName}`
|
||||||
if (showModelProviderInMarkdown && modelProvider) {
|
if (showModelProviderInMarkdown && providerId) {
|
||||||
const providerDisplayName = i18n.t(`provider.${modelProvider}`, { defaultValue: modelProvider })
|
const providerDisplayName = getProviderLabel(providerId) ?? providerId
|
||||||
assistantText += ` | ${providerDisplayName}`
|
assistantText += ` | ${providerDisplayName}`
|
||||||
return assistantText
|
return assistantText
|
||||||
}
|
}
|
||||||
return assistantText
|
return assistantText
|
||||||
} else if (showModelProviderInMarkdown && modelProvider) {
|
} else if (showModelProviderInMarkdown && providerId) {
|
||||||
const providerDisplayName = i18n.t(`provider.${modelProvider}`, { defaultValue: modelProvider })
|
const providerDisplayName = getProviderLabel(providerId) ?? providerId
|
||||||
assistantText += `Assistant | ${providerDisplayName}`
|
assistantText += `Assistant | ${providerDisplayName}`
|
||||||
return assistantText
|
return assistantText
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import i18n from '@renderer/i18n'
|
import { getProviderLabel } from '@renderer/i18n/label'
|
||||||
import { Model, Provider } from '@renderer/types'
|
import { Model, Provider } from '@renderer/types'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,6 +43,8 @@ export function matchKeywordsInString(keywords: string | string[], value: string
|
|||||||
* @returns 匹配所有关键词则返回 true
|
* @returns 匹配所有关键词则返回 true
|
||||||
*/
|
*/
|
||||||
export function matchKeywordsInProvider(keywords: string | string[], provider: Provider): boolean {
|
export function matchKeywordsInProvider(keywords: string | string[], provider: Provider): boolean {
|
||||||
|
console.log(keywords, provider.id)
|
||||||
|
console.log(getProviderSearchString(provider))
|
||||||
return includeKeywords(getProviderSearchString(provider), keywords)
|
return includeKeywords(getProviderSearchString(provider), keywords)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +66,7 @@ export function matchKeywordsInModel(keywords: string | string[], model: Model,
|
|||||||
* @returns 搜索字符串
|
* @returns 搜索字符串
|
||||||
*/
|
*/
|
||||||
function getProviderSearchString(provider: Provider) {
|
function getProviderSearchString(provider: Provider) {
|
||||||
return provider.isSystem ? `${i18n.t(`provider.${provider.id}`)} ${provider.id}` : provider.name
|
return provider.isSystem ? `${getProviderLabel(provider.id)} ${provider.id}` : provider.name
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import i18n from '@renderer/i18n'
|
import { getProviderLabel } from '@renderer/i18n/label'
|
||||||
import { Provider } from '@renderer/types'
|
import { Provider } from '@renderer/types'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -82,7 +82,7 @@ export const getLowerBaseModelName = (id: string, delimiter: string = '/'): stri
|
|||||||
* @returns 描述性的名字
|
* @returns 描述性的名字
|
||||||
*/
|
*/
|
||||||
export const getFancyProviderName = (provider: Provider) => {
|
export const getFancyProviderName = (provider: Provider) => {
|
||||||
return provider.isSystem ? i18n.t(`provider.${provider.id}`) : provider.name
|
return provider.isSystem ? getProviderLabel(provider.id) : provider.name
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user