i18n
This commit is contained in:
parent
0d08b6cf51
commit
7c2ab21c9c
@ -1,12 +1,14 @@
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import type { TFunction } from 'i18next'
|
||||||
|
|
||||||
type Tag = {
|
type Tag = {
|
||||||
name: string
|
name: string
|
||||||
label: string
|
label: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useTags = () => {
|
export const useTags = (translateFromOut?: TFunction) => {
|
||||||
const { t } = useTranslation()
|
const { t: translation } = useTranslation()
|
||||||
|
const t = translateFromOut || translation
|
||||||
|
|
||||||
const tags = [
|
const tags = [
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
const Description = () => {
|
import { useTranslation as translate } from '@/i18n/server'
|
||||||
|
|
||||||
|
type DescriptionProps = {
|
||||||
|
locale?: string
|
||||||
|
}
|
||||||
|
const Description = async ({
|
||||||
|
locale = 'en-US',
|
||||||
|
}: DescriptionProps) => {
|
||||||
|
const { t } = await translate(locale, 'plugin')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h1 className='mb-2 text-center title-4xl-semi-bold text-text-primary'>
|
<h1 className='mb-2 text-center title-4xl-semi-bold text-text-primary'>
|
||||||
@ -7,19 +16,19 @@ const Description = () => {
|
|||||||
<h2 className='flex justify-center items-center text-center body-md-regular text-text-tertiary'>
|
<h2 className='flex justify-center items-center text-center body-md-regular text-text-tertiary'>
|
||||||
Discover
|
Discover
|
||||||
<span className="relative ml-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
|
<span className="relative ml-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
|
||||||
models
|
{t('category.models')}
|
||||||
</span>
|
</span>
|
||||||
,
|
,
|
||||||
<span className="relative ml-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
|
<span className="relative ml-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
|
||||||
tools
|
{t('category.tools')}
|
||||||
</span>
|
</span>
|
||||||
,
|
,
|
||||||
<span className="relative ml-1 mr-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
|
<span className="relative ml-1 mr-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
|
||||||
extensions
|
{t('category.extensions')}
|
||||||
</span>
|
</span>
|
||||||
and
|
and
|
||||||
<span className="relative ml-1 mr-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
|
<span className="relative ml-1 mr-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
|
||||||
bundles
|
{t('category.bundles')}
|
||||||
</span>
|
</span>
|
||||||
in Dify Marketplace
|
in Dify Marketplace
|
||||||
</h2>
|
</h2>
|
||||||
|
@ -2,6 +2,8 @@ import {
|
|||||||
useCallback,
|
useCallback,
|
||||||
useState,
|
useState,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
|
import i18n from 'i18next'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useDebounceFn } from 'ahooks'
|
import { useDebounceFn } from 'ahooks'
|
||||||
import type { Plugin } from '../types'
|
import type { Plugin } from '../types'
|
||||||
import type {
|
import type {
|
||||||
@ -63,3 +65,14 @@ export const useMarketplacePlugins = () => {
|
|||||||
setIsLoading,
|
setIsLoading,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const useMixedTranslation = (localeFromOuter?: string) => {
|
||||||
|
let t = useTranslation().t
|
||||||
|
|
||||||
|
if (localeFromOuter)
|
||||||
|
t = i18n.getFixedT(localeFromOuter)
|
||||||
|
|
||||||
|
return {
|
||||||
|
t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -7,20 +7,23 @@ import ListWrapper from './list/list-wrapper'
|
|||||||
import { getMarketplaceCollectionsAndPlugins } from './utils'
|
import { getMarketplaceCollectionsAndPlugins } from './utils'
|
||||||
|
|
||||||
type MarketplaceProps = {
|
type MarketplaceProps = {
|
||||||
|
locale?: string
|
||||||
showInstallButton?: boolean
|
showInstallButton?: boolean
|
||||||
}
|
}
|
||||||
const Marketplace = async ({
|
const Marketplace = async ({
|
||||||
|
locale,
|
||||||
showInstallButton = true,
|
showInstallButton = true,
|
||||||
}: MarketplaceProps) => {
|
}: MarketplaceProps) => {
|
||||||
const { marketplaceCollections, marketplaceCollectionPluginsMap } = await getMarketplaceCollectionsAndPlugins()
|
const { marketplaceCollections, marketplaceCollectionPluginsMap } = await getMarketplaceCollectionsAndPlugins()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MarketplaceContextProvider>
|
<MarketplaceContextProvider>
|
||||||
<Description />
|
<Description locale={locale} />
|
||||||
<IntersectionLine />
|
<IntersectionLine />
|
||||||
<SearchBoxWrapper />
|
<SearchBoxWrapper locale={locale} />
|
||||||
<PluginTypeSwitch />
|
<PluginTypeSwitch locale={locale} />
|
||||||
<ListWrapper
|
<ListWrapper
|
||||||
|
locale={locale}
|
||||||
marketplaceCollections={marketplaceCollections}
|
marketplaceCollections={marketplaceCollections}
|
||||||
marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMap}
|
marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMap}
|
||||||
showInstallButton={showInstallButton}
|
showInstallButton={showInstallButton}
|
||||||
|
@ -1,21 +1,23 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import { RiArrowRightUpLine } from '@remixicon/react'
|
import { RiArrowRightUpLine } from '@remixicon/react'
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import Card from '@/app/components/plugins/card'
|
import Card from '@/app/components/plugins/card'
|
||||||
import CardMoreInfo from '@/app/components/plugins/card/card-more-info'
|
import CardMoreInfo from '@/app/components/plugins/card/card-more-info'
|
||||||
import type { Plugin } from '@/app/components/plugins/types'
|
import type { Plugin } from '@/app/components/plugins/types'
|
||||||
import { MARKETPLACE_URL_PREFIX } from '@/config'
|
import { MARKETPLACE_URL_PREFIX } from '@/config'
|
||||||
import Button from '@/app/components/base/button'
|
import Button from '@/app/components/base/button'
|
||||||
|
import { useMixedTranslation } from '@/app/components/plugins/marketplace/hooks'
|
||||||
|
|
||||||
type CardWrapperProps = {
|
type CardWrapperProps = {
|
||||||
plugin: Plugin
|
plugin: Plugin
|
||||||
showInstallButton?: boolean
|
showInstallButton?: boolean
|
||||||
|
locale?: string
|
||||||
}
|
}
|
||||||
const CardWrapper = ({
|
const CardWrapper = ({
|
||||||
plugin,
|
plugin,
|
||||||
showInstallButton,
|
showInstallButton,
|
||||||
|
locale,
|
||||||
}: CardWrapperProps) => {
|
}: CardWrapperProps) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useMixedTranslation(locale)
|
||||||
return (
|
return (
|
||||||
<div className='group relative rounded-xl cursor-pointer'>
|
<div className='group relative rounded-xl cursor-pointer'>
|
||||||
<Card
|
<Card
|
||||||
|
@ -10,12 +10,14 @@ type ListProps = {
|
|||||||
marketplaceCollectionPluginsMap: Record<string, Plugin[]>
|
marketplaceCollectionPluginsMap: Record<string, Plugin[]>
|
||||||
plugins?: Plugin[]
|
plugins?: Plugin[]
|
||||||
showInstallButton?: boolean
|
showInstallButton?: boolean
|
||||||
|
locale?: string
|
||||||
}
|
}
|
||||||
const List = ({
|
const List = ({
|
||||||
marketplaceCollections,
|
marketplaceCollections,
|
||||||
marketplaceCollectionPluginsMap,
|
marketplaceCollectionPluginsMap,
|
||||||
plugins,
|
plugins,
|
||||||
showInstallButton,
|
showInstallButton,
|
||||||
|
locale,
|
||||||
}: ListProps) => {
|
}: ListProps) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -37,6 +39,7 @@ const List = ({
|
|||||||
key={plugin.name}
|
key={plugin.name}
|
||||||
plugin={plugin}
|
plugin={plugin}
|
||||||
showInstallButton={showInstallButton}
|
showInstallButton={showInstallButton}
|
||||||
|
locale={locale}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,13 @@ type ListWrapperProps = {
|
|||||||
marketplaceCollections: MarketplaceCollection[]
|
marketplaceCollections: MarketplaceCollection[]
|
||||||
marketplaceCollectionPluginsMap: Record<string, Plugin[]>
|
marketplaceCollectionPluginsMap: Record<string, Plugin[]>
|
||||||
showInstallButton?: boolean
|
showInstallButton?: boolean
|
||||||
|
locale?: string
|
||||||
}
|
}
|
||||||
const ListWrapper = ({
|
const ListWrapper = ({
|
||||||
marketplaceCollections,
|
marketplaceCollections,
|
||||||
marketplaceCollectionPluginsMap,
|
marketplaceCollectionPluginsMap,
|
||||||
showInstallButton,
|
showInstallButton,
|
||||||
|
locale,
|
||||||
}: ListWrapperProps) => {
|
}: ListWrapperProps) => {
|
||||||
const plugins = useMarketplaceContext(v => v.plugins)
|
const plugins = useMarketplaceContext(v => v.plugins)
|
||||||
const marketplaceCollectionsFromClient = useMarketplaceContext(v => v.marketplaceCollectionsFromClient)
|
const marketplaceCollectionsFromClient = useMarketplaceContext(v => v.marketplaceCollectionsFromClient)
|
||||||
@ -35,6 +37,7 @@ const ListWrapper = ({
|
|||||||
marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMapFromClient || marketplaceCollectionPluginsMap}
|
marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMapFromClient || marketplaceCollectionPluginsMap}
|
||||||
plugins={plugins}
|
plugins={plugins}
|
||||||
showInstallButton={showInstallButton}
|
showInstallButton={showInstallButton}
|
||||||
|
locale={locale}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
RiArchive2Line,
|
RiArchive2Line,
|
||||||
RiBrain2Line,
|
RiBrain2Line,
|
||||||
@ -8,6 +7,7 @@ import {
|
|||||||
} from '@remixicon/react'
|
} from '@remixicon/react'
|
||||||
import { PluginType } from '../types'
|
import { PluginType } from '../types'
|
||||||
import { useMarketplaceContext } from './context'
|
import { useMarketplaceContext } from './context'
|
||||||
|
import { useMixedTranslation } from './hooks'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
export const PLUGIN_TYPE_SEARCH_MAP = {
|
export const PLUGIN_TYPE_SEARCH_MAP = {
|
||||||
@ -17,6 +17,16 @@ export const PLUGIN_TYPE_SEARCH_MAP = {
|
|||||||
extension: PluginType.extension,
|
extension: PluginType.extension,
|
||||||
bundle: 'bundle',
|
bundle: 'bundle',
|
||||||
}
|
}
|
||||||
|
type PluginTypeSwitchProps = {
|
||||||
|
locale?: string
|
||||||
|
}
|
||||||
|
const PluginTypeSwitch = ({
|
||||||
|
locale,
|
||||||
|
}: PluginTypeSwitchProps) => {
|
||||||
|
const { t } = useMixedTranslation(locale)
|
||||||
|
const activePluginType = useMarketplaceContext(s => s.activePluginType)
|
||||||
|
const handleActivePluginTypeChange = useMarketplaceContext(s => s.handleActivePluginTypeChange)
|
||||||
|
|
||||||
const options = [
|
const options = [
|
||||||
{
|
{
|
||||||
value: PLUGIN_TYPE_SEARCH_MAP.all,
|
value: PLUGIN_TYPE_SEARCH_MAP.all,
|
||||||
@ -25,28 +35,25 @@ const options = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: PLUGIN_TYPE_SEARCH_MAP.model,
|
value: PLUGIN_TYPE_SEARCH_MAP.model,
|
||||||
text: 'Models',
|
text: t('plugin.category.models'),
|
||||||
icon: <RiBrain2Line className='mr-1.5 w-4 h-4' />,
|
icon: <RiBrain2Line className='mr-1.5 w-4 h-4' />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: PLUGIN_TYPE_SEARCH_MAP.tool,
|
value: PLUGIN_TYPE_SEARCH_MAP.tool,
|
||||||
text: 'Tools',
|
text: t('plugin.category.tools'),
|
||||||
icon: <RiHammerLine className='mr-1.5 w-4 h-4' />,
|
icon: <RiHammerLine className='mr-1.5 w-4 h-4' />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: PLUGIN_TYPE_SEARCH_MAP.extension,
|
value: PLUGIN_TYPE_SEARCH_MAP.extension,
|
||||||
text: 'Extensions',
|
text: t('plugin.category.extensions'),
|
||||||
icon: <RiPuzzle2Line className='mr-1.5 w-4 h-4' />,
|
icon: <RiPuzzle2Line className='mr-1.5 w-4 h-4' />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: PLUGIN_TYPE_SEARCH_MAP.bundle,
|
value: PLUGIN_TYPE_SEARCH_MAP.bundle,
|
||||||
text: 'Bundles',
|
text: t('plugin.category.bundles'),
|
||||||
icon: <RiArchive2Line className='mr-1.5 w-4 h-4' />,
|
icon: <RiArchive2Line className='mr-1.5 w-4 h-4' />,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
const PluginTypeSwitch = () => {
|
|
||||||
const activePluginType = useMarketplaceContext(s => s.activePluginType)
|
|
||||||
const handleActivePluginTypeChange = useMarketplaceContext(s => s.handleActivePluginTypeChange)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn(
|
<div className={cn(
|
||||||
|
@ -12,6 +12,7 @@ type SearchBoxProps = {
|
|||||||
onTagsChange: (tags: string[]) => void
|
onTagsChange: (tags: string[]) => void
|
||||||
size?: 'small' | 'large'
|
size?: 'small' | 'large'
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
|
locale?: string
|
||||||
}
|
}
|
||||||
const SearchBox = ({
|
const SearchBox = ({
|
||||||
search,
|
search,
|
||||||
@ -20,7 +21,8 @@ const SearchBox = ({
|
|||||||
tags,
|
tags,
|
||||||
onTagsChange,
|
onTagsChange,
|
||||||
size = 'small',
|
size = 'small',
|
||||||
placeholder = 'Search tools...',
|
placeholder = '',
|
||||||
|
locale,
|
||||||
}: SearchBoxProps) => {
|
}: SearchBoxProps) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -35,6 +37,7 @@ const SearchBox = ({
|
|||||||
tags={tags}
|
tags={tags}
|
||||||
onTagsChange={onTagsChange}
|
onTagsChange={onTagsChange}
|
||||||
size={size}
|
size={size}
|
||||||
|
locale={locale}
|
||||||
/>
|
/>
|
||||||
<div className='mx-1 w-[1px] h-3.5 bg-divider-regular'></div>
|
<div className='mx-1 w-[1px] h-3.5 bg-divider-regular'></div>
|
||||||
<div className='grow flex items-center p-1 pl-2'>
|
<div className='grow flex items-center p-1 pl-2'>
|
||||||
|
@ -1,9 +1,16 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import { useMarketplaceContext } from '../context'
|
import { useMarketplaceContext } from '../context'
|
||||||
|
import { useMixedTranslation } from '../hooks'
|
||||||
import SearchBox from './index'
|
import SearchBox from './index'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
const SearchBoxWrapper = () => {
|
type SearchBoxWrapperProps = {
|
||||||
|
locale?: string
|
||||||
|
}
|
||||||
|
const SearchBoxWrapper = ({
|
||||||
|
locale,
|
||||||
|
}: SearchBoxWrapperProps) => {
|
||||||
|
const { t } = useMixedTranslation(locale)
|
||||||
const intersected = useMarketplaceContext(v => v.intersected)
|
const intersected = useMarketplaceContext(v => v.intersected)
|
||||||
const searchPluginText = useMarketplaceContext(v => v.searchPluginText)
|
const searchPluginText = useMarketplaceContext(v => v.searchPluginText)
|
||||||
const handleSearchPluginTextChange = useMarketplaceContext(v => v.handleSearchPluginTextChange)
|
const handleSearchPluginTextChange = useMarketplaceContext(v => v.handleSearchPluginTextChange)
|
||||||
@ -21,6 +28,8 @@ const SearchBoxWrapper = () => {
|
|||||||
tags={filterPluginTags}
|
tags={filterPluginTags}
|
||||||
onTagsChange={handleFilterPluginTagsChange}
|
onTagsChange={handleFilterPluginTagsChange}
|
||||||
size='large'
|
size='large'
|
||||||
|
locale={locale}
|
||||||
|
placeholder={t('plugin.searchPlugins')}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import {
|
import {
|
||||||
RiArrowDownSLine,
|
RiArrowDownSLine,
|
||||||
RiCloseCircleFill,
|
RiCloseCircleFill,
|
||||||
@ -16,21 +15,24 @@ import Checkbox from '@/app/components/base/checkbox'
|
|||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import Input from '@/app/components/base/input'
|
import Input from '@/app/components/base/input'
|
||||||
import { useTags } from '@/app/components/plugins/hooks'
|
import { useTags } from '@/app/components/plugins/hooks'
|
||||||
|
import { useMixedTranslation } from '@/app/components/plugins/marketplace/hooks'
|
||||||
|
|
||||||
type TagsFilterProps = {
|
type TagsFilterProps = {
|
||||||
tags: string[]
|
tags: string[]
|
||||||
onTagsChange: (tags: string[]) => void
|
onTagsChange: (tags: string[]) => void
|
||||||
size: 'small' | 'large'
|
size: 'small' | 'large'
|
||||||
|
locale?: string
|
||||||
}
|
}
|
||||||
const TagsFilter = ({
|
const TagsFilter = ({
|
||||||
tags,
|
tags,
|
||||||
onTagsChange,
|
onTagsChange,
|
||||||
size,
|
size,
|
||||||
|
locale,
|
||||||
}: TagsFilterProps) => {
|
}: TagsFilterProps) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useMixedTranslation(locale)
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const [searchText, setSearchText] = useState('')
|
const [searchText, setSearchText] = useState('')
|
||||||
const { tags: options, tagsMap } = useTags()
|
const { tags: options, tagsMap } = useTags(t)
|
||||||
const filteredOptions = options.filter(option => option.label.toLowerCase().includes(searchText.toLowerCase()))
|
const filteredOptions = options.filter(option => option.label.toLowerCase().includes(searchText.toLowerCase()))
|
||||||
const handleCheck = (id: string) => {
|
const handleCheck = (id: string) => {
|
||||||
if (tags.includes(id))
|
if (tags.includes(id))
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import { RiArrowUpDoubleLine } from '@remixicon/react'
|
import { RiArrowUpDoubleLine } from '@remixicon/react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useMarketplace } from './hooks'
|
import { useMarketplace } from './hooks'
|
||||||
import List from '@/app/components/plugins/marketplace/list'
|
import List from '@/app/components/plugins/marketplace/list'
|
||||||
import Loading from '@/app/components/base/loading'
|
import Loading from '@/app/components/base/loading'
|
||||||
|
import { getLocaleOnClient } from '@/i18n'
|
||||||
|
|
||||||
type MarketplaceProps = {
|
type MarketplaceProps = {
|
||||||
searchPluginText: string
|
searchPluginText: string
|
||||||
@ -13,6 +15,8 @@ const Marketplace = ({
|
|||||||
filterPluginTags,
|
filterPluginTags,
|
||||||
onMarketplaceScroll,
|
onMarketplaceScroll,
|
||||||
}: MarketplaceProps) => {
|
}: MarketplaceProps) => {
|
||||||
|
const locale = getLocaleOnClient()
|
||||||
|
const { t } = useTranslation()
|
||||||
const {
|
const {
|
||||||
isLoading,
|
isLoading,
|
||||||
marketplaceCollections,
|
marketplaceCollections,
|
||||||
@ -31,19 +35,19 @@ const Marketplace = ({
|
|||||||
<div className='flex items-center text-center body-md-regular text-text-tertiary'>
|
<div className='flex items-center text-center body-md-regular text-text-tertiary'>
|
||||||
Discover
|
Discover
|
||||||
<span className="relative ml-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
|
<span className="relative ml-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
|
||||||
models
|
{t('plugin.category.models')}
|
||||||
</span>
|
</span>
|
||||||
,
|
,
|
||||||
<span className="relative ml-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
|
<span className="relative ml-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
|
||||||
tools
|
{t('plugin.category.tools')}
|
||||||
</span>
|
</span>
|
||||||
,
|
,
|
||||||
<span className="relative ml-1 mr-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
|
<span className="relative ml-1 mr-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
|
||||||
extensions
|
{t('plugin.category.extensions')}
|
||||||
</span>
|
</span>
|
||||||
and
|
and
|
||||||
<span className="relative ml-1 mr-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
|
<span className="relative ml-1 mr-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
|
||||||
bundles
|
{t('plugin.category.bundles')}
|
||||||
</span>
|
</span>
|
||||||
in Dify Marketplace
|
in Dify Marketplace
|
||||||
</div>
|
</div>
|
||||||
@ -62,6 +66,7 @@ const Marketplace = ({
|
|||||||
marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMap || {}}
|
marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMap || {}}
|
||||||
plugins={plugins}
|
plugins={plugins}
|
||||||
showInstallButton
|
showInstallButton
|
||||||
|
locale={locale}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
const translation = {
|
const translation = {
|
||||||
|
category: {
|
||||||
|
models: 'models',
|
||||||
|
tools: 'tools',
|
||||||
|
extensions: 'extensions',
|
||||||
|
bundles: 'bundles',
|
||||||
|
},
|
||||||
|
searchPlugins: 'Search plugins',
|
||||||
from: 'From',
|
from: 'From',
|
||||||
findMoreInMarketplace: 'Find more in Marketplace',
|
findMoreInMarketplace: 'Find more in Marketplace',
|
||||||
searchInMarketplace: 'Search in Marketplace',
|
searchInMarketplace: 'Search in Marketplace',
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
const translation = {
|
const translation = {
|
||||||
|
category: {
|
||||||
|
models: '模型',
|
||||||
|
tools: '工具',
|
||||||
|
extensions: '扩展',
|
||||||
|
bundles: '捆绑包',
|
||||||
|
},
|
||||||
|
searchPlugins: '搜索插件',
|
||||||
from: '来自',
|
from: '来自',
|
||||||
findMoreInMarketplace: '在 Marketplace 中查找更多',
|
findMoreInMarketplace: '在 Marketplace 中查找更多',
|
||||||
searchInMarketplace: '在 Marketplace 中搜索',
|
searchInMarketplace: '在 Marketplace 中搜索',
|
||||||
|
Loading…
Reference in New Issue
Block a user