diff --git a/web/app/components/header/account-setting/model-provider-page/index.tsx b/web/app/components/header/account-setting/model-provider-page/index.tsx index 6d508f0de1..7faf3f3de7 100644 --- a/web/app/components/header/account-setting/model-provider-page/index.tsx +++ b/web/app/components/header/account-setting/model-provider-page/index.tsx @@ -123,7 +123,7 @@ const ModelProviderPage = ({ searchText }: Props) => { const [collapse, setCollapse] = useState(false) const { - plugins, + plugins = [], queryPlugins, queryPluginsWithDebounced, isLoading: isPluginsLoading, diff --git a/web/app/components/plugins/hooks.ts b/web/app/components/plugins/hooks.ts index ef69cf5f23..0abadd7a90 100644 --- a/web/app/components/plugins/hooks.ts +++ b/web/app/components/plugins/hooks.ts @@ -1,72 +1,87 @@ import { useTranslation } from 'react-i18next' +type Tag = { + name: string + label: string +} + export const useTags = () => { const { t } = useTranslation() - return [ + const tags = [ { name: 'search', - label: t('pluginTags.search'), + label: t('pluginTags.tags.search'), }, { name: 'image', - label: t('pluginTags.image'), + label: t('pluginTags.tags.image'), }, { name: 'videos', - label: t('pluginTags.videos'), + label: t('pluginTags.tags.videos'), }, { name: 'weather', - label: t('pluginTags.weather'), + label: t('pluginTags.tags.weather'), }, { name: 'finance', - label: t('pluginTags.finance'), + label: t('pluginTags.tags.finance'), }, { name: 'design', - label: t('pluginTags.design'), + label: t('pluginTags.tags.design'), }, { name: 'travel', - label: t('pluginTags.travel'), + label: t('pluginTags.tags.travel'), }, { name: 'social', - label: t('pluginTags.social'), + label: t('pluginTags.tags.social'), }, { name: 'news', - label: t('pluginTags.news'), + label: t('pluginTags.tags.news'), }, { name: 'medical', - label: t('pluginTags.medical'), + label: t('pluginTags.tags.medical'), }, { name: 'productivity', - label: t('pluginTags.productivity'), + label: t('pluginTags.tags.productivity'), }, { name: 'education', - label: t('pluginTags.education'), + label: t('pluginTags.tags.education'), }, { name: 'business', - label: t('pluginTags.business'), + label: t('pluginTags.tags.business'), }, { name: 'entertainment', - label: t('pluginTags.entertainment'), + label: t('pluginTags.tags.entertainment'), }, { name: 'utilities', - label: t('pluginTags.utilities'), + label: t('pluginTags.tags.utilities'), }, { name: 'other', - label: t('pluginTags.other'), + label: t('pluginTags.tags.other'), }, ] + + const tagsMap = tags.reduce((acc, tag) => { + acc[tag.name] = tag + return acc + }, {} as Record) + + return { + tags, + tagsMap, + } } diff --git a/web/app/components/plugins/marketplace/search-box/tags-filter.tsx b/web/app/components/plugins/marketplace/search-box/tags-filter.tsx index c7a1a4e57e..670d7af6ed 100644 --- a/web/app/components/plugins/marketplace/search-box/tags-filter.tsx +++ b/web/app/components/plugins/marketplace/search-box/tags-filter.tsx @@ -1,6 +1,7 @@ 'use client' import { useState } from 'react' +import { useTranslation } from 'react-i18next' import { RiArrowDownSLine, RiCloseCircleFill, @@ -26,9 +27,10 @@ const TagsFilter = ({ onTagsChange, size, }: TagsFilterProps) => { + const { t } = useTranslation() const [open, setOpen] = useState(false) const [searchText, setSearchText] = useState('') - const options = useTags() + const { tags: options, tagsMap } = useTags() const filteredOptions = options.filter(option => option.label.toLowerCase().includes(searchText.toLowerCase())) const handleCheck = (id: string) => { if (tags.includes(id)) @@ -65,10 +67,10 @@ const TagsFilter = ({ size === 'small' && 'px-0.5 py-1', )}> { - !selectedTagsLength && 'All Tags' + !selectedTagsLength && t('pluginTags.allTags') } { - !!selectedTagsLength && tags.slice(0, 2).join(',') + !!selectedTagsLength && tags.map(tag => tagsMap[tag].label).slice(0, 2).join(',') } { selectedTagsLength > 2 && ( @@ -100,7 +102,7 @@ const TagsFilter = ({ showLeftIcon value={searchText} onChange={e => setSearchText(e.target.value)} - placeholder='Search tags' + placeholder={t('pluginTags.searchTags') || ''} />
diff --git a/web/app/components/tools/labels/filter.tsx b/web/app/components/tools/labels/filter.tsx index f33a63f480..8f6e954b92 100644 --- a/web/app/components/tools/labels/filter.tsx +++ b/web/app/components/tools/labels/filter.tsx @@ -27,7 +27,7 @@ const LabelFilter: FC = ({ const { t } = useTranslation() const [open, setOpen] = useState(false) - const labelList = useTags() + const { tags: labelList } = useTags() const [keywords, setKeywords] = useState('') const [searchKeywords, setSearchKeywords] = useState('') diff --git a/web/app/components/tools/labels/selector.tsx b/web/app/components/tools/labels/selector.tsx index 0c64ebb142..88b910e87c 100644 --- a/web/app/components/tools/labels/selector.tsx +++ b/web/app/components/tools/labels/selector.tsx @@ -26,7 +26,7 @@ const LabelSelector: FC = ({ const { t } = useTranslation() const [open, setOpen] = useState(false) - const labelList = useTags() + const { tags: labelList } = useTags() const [keywords, setKeywords] = useState('') const [searchKeywords, setSearchKeywords] = useState('') diff --git a/web/app/components/workflow/block-selector/all-tools.tsx b/web/app/components/workflow/block-selector/all-tools.tsx index c7bd877775..43d887a4d5 100644 --- a/web/app/components/workflow/block-selector/all-tools.tsx +++ b/web/app/components/workflow/block-selector/all-tools.tsx @@ -66,7 +66,7 @@ const AllTools = ({ const { queryPluginsWithDebounced: fetchPlugins, - plugins: notInstalledPlugins, + plugins: notInstalledPlugins = [], } = useMarketplacePlugins() useEffect(() => { diff --git a/web/i18n/en-US/plugin-tags.ts b/web/i18n/en-US/plugin-tags.ts index 6eca3ac8a2..e96f415053 100644 --- a/web/i18n/en-US/plugin-tags.ts +++ b/web/i18n/en-US/plugin-tags.ts @@ -1,20 +1,24 @@ const translation = { - search: 'Search', - image: 'Image', - videos: 'Videos', - weather: 'Weather', - finance: 'Finance', - design: 'Design', - travel: 'Travel', - social: 'Social', - news: 'News', - medical: 'Medical', - productivity: 'Productivity', - education: 'Education', - business: 'Business', - entertainment: 'Entertainment', - utilities: 'Utilities', - other: 'Other', + allTags: 'All Tags', + searchTags: 'Search Tags', + tags: { + search: 'Search', + image: 'Image', + videos: 'Videos', + weather: 'Weather', + finance: 'Finance', + design: 'Design', + travel: 'Travel', + social: 'Social', + news: 'News', + medical: 'Medical', + productivity: 'Productivity', + education: 'Education', + business: 'Business', + entertainment: 'Entertainment', + utilities: 'Utilities', + other: 'Other', + }, } export default translation diff --git a/web/i18n/zh-Hans/plugin-tags.ts b/web/i18n/zh-Hans/plugin-tags.ts index f8251d339d..4c9b2c6370 100644 --- a/web/i18n/zh-Hans/plugin-tags.ts +++ b/web/i18n/zh-Hans/plugin-tags.ts @@ -1,20 +1,24 @@ const translation = { - search: '搜索', - image: '图片', - videos: '视频', - weather: '天气', - finance: '金融', - design: '设计', - travel: '旅行', - social: '社交', - news: '新闻', - medical: '医疗', - productivity: '生产力', - education: '教育', - business: '商业', - entertainment: '娱乐', - utilities: '工具', - other: '其他', + allTags: '所有标签', + searchTags: '搜索标签', + tags: { + search: '搜索', + image: '图片', + videos: '视频', + weather: '天气', + finance: '金融', + design: '设计', + travel: '旅行', + social: '社交', + news: '新闻', + medical: '医疗', + productivity: '生产力', + education: '教育', + business: '商业', + entertainment: '娱乐', + utilities: '工具', + other: '其他', + }, } export default translation