From 7c2ab21c9c37eff3fd21057188b5196038b80986 Mon Sep 17 00:00:00 2001 From: StyleZhang Date: Wed, 6 Nov 2024 11:55:19 +0800 Subject: [PATCH] i18n --- web/app/components/plugins/hooks.ts | 6 +- .../plugins/marketplace/description/index.tsx | 19 ++++-- .../components/plugins/marketplace/hooks.ts | 13 ++++ .../components/plugins/marketplace/index.tsx | 9 ++- .../plugins/marketplace/list/card-wrapper.tsx | 6 +- .../plugins/marketplace/list/index.tsx | 3 + .../plugins/marketplace/list/list-wrapper.tsx | 3 + .../marketplace/plugin-type-switch.tsx | 65 ++++++++++--------- .../plugins/marketplace/search-box/index.tsx | 5 +- .../search-box/search-box-wrapper.tsx | 11 +++- .../marketplace/search-box/tags-filter.tsx | 8 ++- .../components/tools/marketplace/index.tsx | 13 ++-- web/i18n/en-US/plugin.ts | 7 ++ web/i18n/zh-Hans/plugin.ts | 7 ++ 14 files changed, 125 insertions(+), 50 deletions(-) diff --git a/web/app/components/plugins/hooks.ts b/web/app/components/plugins/hooks.ts index 0abadd7a90..484a7fbb5a 100644 --- a/web/app/components/plugins/hooks.ts +++ b/web/app/components/plugins/hooks.ts @@ -1,12 +1,14 @@ import { useTranslation } from 'react-i18next' +import type { TFunction } from 'i18next' type Tag = { name: string label: string } -export const useTags = () => { - const { t } = useTranslation() +export const useTags = (translateFromOut?: TFunction) => { + const { t: translation } = useTranslation() + const t = translateFromOut || translation const tags = [ { diff --git a/web/app/components/plugins/marketplace/description/index.tsx b/web/app/components/plugins/marketplace/description/index.tsx index 754a4b12a9..41888d3dbe 100644 --- a/web/app/components/plugins/marketplace/description/index.tsx +++ b/web/app/components/plugins/marketplace/description/index.tsx @@ -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 ( <>

@@ -7,19 +16,19 @@ const Description = () => {

Discover - models + {t('category.models')} , - tools + {t('category.tools')} , - extensions + {t('category.extensions')} and - bundles + {t('category.bundles')} in Dify Marketplace

diff --git a/web/app/components/plugins/marketplace/hooks.ts b/web/app/components/plugins/marketplace/hooks.ts index 83b7ee5435..254e506912 100644 --- a/web/app/components/plugins/marketplace/hooks.ts +++ b/web/app/components/plugins/marketplace/hooks.ts @@ -2,6 +2,8 @@ import { useCallback, useState, } from 'react' +import i18n from 'i18next' +import { useTranslation } from 'react-i18next' import { useDebounceFn } from 'ahooks' import type { Plugin } from '../types' import type { @@ -63,3 +65,14 @@ export const useMarketplacePlugins = () => { setIsLoading, } } + +export const useMixedTranslation = (localeFromOuter?: string) => { + let t = useTranslation().t + + if (localeFromOuter) + t = i18n.getFixedT(localeFromOuter) + + return { + t, + } +} diff --git a/web/app/components/plugins/marketplace/index.tsx b/web/app/components/plugins/marketplace/index.tsx index 0c87cce924..742df86ea0 100644 --- a/web/app/components/plugins/marketplace/index.tsx +++ b/web/app/components/plugins/marketplace/index.tsx @@ -7,20 +7,23 @@ import ListWrapper from './list/list-wrapper' import { getMarketplaceCollectionsAndPlugins } from './utils' type MarketplaceProps = { + locale?: string showInstallButton?: boolean } const Marketplace = async ({ + locale, showInstallButton = true, }: MarketplaceProps) => { const { marketplaceCollections, marketplaceCollectionPluginsMap } = await getMarketplaceCollectionsAndPlugins() return ( - + - - + + { - const { t } = useTranslation() + const { t } = useMixedTranslation(locale) return (
plugins?: Plugin[] showInstallButton?: boolean + locale?: string } const List = ({ marketplaceCollections, marketplaceCollectionPluginsMap, plugins, showInstallButton, + locale, }: ListProps) => { return ( <> @@ -37,6 +39,7 @@ const List = ({ key={plugin.name} plugin={plugin} showInstallButton={showInstallButton} + locale={locale} /> )) } diff --git a/web/app/components/plugins/marketplace/list/list-wrapper.tsx b/web/app/components/plugins/marketplace/list/list-wrapper.tsx index bcb929ca2f..443b9ef516 100644 --- a/web/app/components/plugins/marketplace/list/list-wrapper.tsx +++ b/web/app/components/plugins/marketplace/list/list-wrapper.tsx @@ -9,11 +9,13 @@ type ListWrapperProps = { marketplaceCollections: MarketplaceCollection[] marketplaceCollectionPluginsMap: Record showInstallButton?: boolean + locale?: string } const ListWrapper = ({ marketplaceCollections, marketplaceCollectionPluginsMap, showInstallButton, + locale, }: ListWrapperProps) => { const plugins = useMarketplaceContext(v => v.plugins) const marketplaceCollectionsFromClient = useMarketplaceContext(v => v.marketplaceCollectionsFromClient) @@ -35,6 +37,7 @@ const ListWrapper = ({ marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMapFromClient || marketplaceCollectionPluginsMap} plugins={plugins} showInstallButton={showInstallButton} + locale={locale} />
) diff --git a/web/app/components/plugins/marketplace/plugin-type-switch.tsx b/web/app/components/plugins/marketplace/plugin-type-switch.tsx index 35f5349343..c1469cf6bf 100644 --- a/web/app/components/plugins/marketplace/plugin-type-switch.tsx +++ b/web/app/components/plugins/marketplace/plugin-type-switch.tsx @@ -1,5 +1,4 @@ 'use client' - import { RiArchive2Line, RiBrain2Line, @@ -8,6 +7,7 @@ import { } from '@remixicon/react' import { PluginType } from '../types' import { useMarketplaceContext } from './context' +import { useMixedTranslation } from './hooks' import cn from '@/utils/classnames' export const PLUGIN_TYPE_SEARCH_MAP = { @@ -17,37 +17,44 @@ export const PLUGIN_TYPE_SEARCH_MAP = { extension: PluginType.extension, bundle: 'bundle', } -const options = [ - { - value: PLUGIN_TYPE_SEARCH_MAP.all, - text: 'All', - icon: null, - }, - { - value: PLUGIN_TYPE_SEARCH_MAP.model, - text: 'Models', - icon: , - }, - { - value: PLUGIN_TYPE_SEARCH_MAP.tool, - text: 'Tools', - icon: , - }, - { - value: PLUGIN_TYPE_SEARCH_MAP.extension, - text: 'Extensions', - icon: , - }, - { - value: PLUGIN_TYPE_SEARCH_MAP.bundle, - text: 'Bundles', - icon: , - }, -] -const PluginTypeSwitch = () => { +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 = [ + { + value: PLUGIN_TYPE_SEARCH_MAP.all, + text: 'All', + icon: null, + }, + { + value: PLUGIN_TYPE_SEARCH_MAP.model, + text: t('plugin.category.models'), + icon: , + }, + { + value: PLUGIN_TYPE_SEARCH_MAP.tool, + text: t('plugin.category.tools'), + icon: , + }, + { + value: PLUGIN_TYPE_SEARCH_MAP.extension, + text: t('plugin.category.extensions'), + icon: , + }, + { + value: PLUGIN_TYPE_SEARCH_MAP.bundle, + text: t('plugin.category.bundles'), + icon: , + }, + ] + return (
void size?: 'small' | 'large' placeholder?: string + locale?: string } const SearchBox = ({ search, @@ -20,7 +21,8 @@ const SearchBox = ({ tags, onTagsChange, size = 'small', - placeholder = 'Search tools...', + placeholder = '', + locale, }: SearchBoxProps) => { return (
diff --git a/web/app/components/plugins/marketplace/search-box/search-box-wrapper.tsx b/web/app/components/plugins/marketplace/search-box/search-box-wrapper.tsx index a124d93eb4..dfdc699958 100644 --- a/web/app/components/plugins/marketplace/search-box/search-box-wrapper.tsx +++ b/web/app/components/plugins/marketplace/search-box/search-box-wrapper.tsx @@ -1,9 +1,16 @@ 'use client' import { useMarketplaceContext } from '../context' +import { useMixedTranslation } from '../hooks' import SearchBox from './index' 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 searchPluginText = useMarketplaceContext(v => v.searchPluginText) const handleSearchPluginTextChange = useMarketplaceContext(v => v.handleSearchPluginTextChange) @@ -21,6 +28,8 @@ const SearchBoxWrapper = () => { tags={filterPluginTags} onTagsChange={handleFilterPluginTagsChange} size='large' + locale={locale} + placeholder={t('plugin.searchPlugins')} /> ) } 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 670d7af6ed..416cc99b91 100644 --- a/web/app/components/plugins/marketplace/search-box/tags-filter.tsx +++ b/web/app/components/plugins/marketplace/search-box/tags-filter.tsx @@ -1,7 +1,6 @@ 'use client' import { useState } from 'react' -import { useTranslation } from 'react-i18next' import { RiArrowDownSLine, RiCloseCircleFill, @@ -16,21 +15,24 @@ import Checkbox from '@/app/components/base/checkbox' import cn from '@/utils/classnames' import Input from '@/app/components/base/input' import { useTags } from '@/app/components/plugins/hooks' +import { useMixedTranslation } from '@/app/components/plugins/marketplace/hooks' type TagsFilterProps = { tags: string[] onTagsChange: (tags: string[]) => void size: 'small' | 'large' + locale?: string } const TagsFilter = ({ tags, onTagsChange, size, + locale, }: TagsFilterProps) => { - const { t } = useTranslation() + const { t } = useMixedTranslation(locale) const [open, setOpen] = useState(false) 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 handleCheck = (id: string) => { if (tags.includes(id)) diff --git a/web/app/components/tools/marketplace/index.tsx b/web/app/components/tools/marketplace/index.tsx index fff22fedc5..f2092227a0 100644 --- a/web/app/components/tools/marketplace/index.tsx +++ b/web/app/components/tools/marketplace/index.tsx @@ -1,7 +1,9 @@ import { RiArrowUpDoubleLine } from '@remixicon/react' +import { useTranslation } from 'react-i18next' import { useMarketplace } from './hooks' import List from '@/app/components/plugins/marketplace/list' import Loading from '@/app/components/base/loading' +import { getLocaleOnClient } from '@/i18n' type MarketplaceProps = { searchPluginText: string @@ -13,6 +15,8 @@ const Marketplace = ({ filterPluginTags, onMarketplaceScroll, }: MarketplaceProps) => { + const locale = getLocaleOnClient() + const { t } = useTranslation() const { isLoading, marketplaceCollections, @@ -31,19 +35,19 @@ const Marketplace = ({
Discover - models + {t('plugin.category.models')} , - tools + {t('plugin.category.tools')} , - extensions + {t('plugin.category.extensions')} and - bundles + {t('plugin.category.bundles')} in Dify Marketplace
@@ -62,6 +66,7 @@ const Marketplace = ({ marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMap || {}} plugins={plugins} showInstallButton + locale={locale} /> ) } diff --git a/web/i18n/en-US/plugin.ts b/web/i18n/en-US/plugin.ts index 5ee95468b9..6fbe49a5b7 100644 --- a/web/i18n/en-US/plugin.ts +++ b/web/i18n/en-US/plugin.ts @@ -1,4 +1,11 @@ const translation = { + category: { + models: 'models', + tools: 'tools', + extensions: 'extensions', + bundles: 'bundles', + }, + searchPlugins: 'Search plugins', from: 'From', findMoreInMarketplace: 'Find more in Marketplace', searchInMarketplace: 'Search in Marketplace', diff --git a/web/i18n/zh-Hans/plugin.ts b/web/i18n/zh-Hans/plugin.ts index a9acc1e0e3..a7d146181b 100644 --- a/web/i18n/zh-Hans/plugin.ts +++ b/web/i18n/zh-Hans/plugin.ts @@ -1,4 +1,11 @@ const translation = { + category: { + models: '模型', + tools: '工具', + extensions: '扩展', + bundles: '捆绑包', + }, + searchPlugins: '搜索插件', from: '来自', findMoreInMarketplace: '在 Marketplace 中查找更多', searchInMarketplace: '在 Marketplace 中搜索',