From 521c145817c63029a98c4f81007a30c25bc2402b Mon Sep 17 00:00:00 2001 From: Hanqing Zhao Date: Wed, 29 Apr 2026 14:19:57 +0800 Subject: [PATCH] feat: modify translation for Collection and keep filtering settings (#35676) --- web/app/components/plugins/marketplace/atoms.ts | 10 ++++++++-- .../plugins/marketplace/list/collection-list.tsx | 16 +++++++++------- .../plugins/marketplace/list/template-card.tsx | 15 +++++++-------- web/i18n-config/language.ts | 2 +- 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/web/app/components/plugins/marketplace/atoms.ts b/web/app/components/plugins/marketplace/atoms.ts index 9f8ebbd43f..b9da495eb8 100644 --- a/web/app/components/plugins/marketplace/atoms.ts +++ b/web/app/components/plugins/marketplace/atoms.ts @@ -46,7 +46,10 @@ export function useActivePluginCategory() { const validatedCategory = getValidatedPluginCategory(categoryFromPath) const handleChange = useCallback( (newCategory: string) => { - router.push(`/plugins/${newCategory}`) + // Preserve the current query string (e.g. ?languages=en) so manual + // filters survive a category change. + const search = typeof window !== 'undefined' ? window.location.search : '' + router.push(`/plugins/${newCategory}${search}`) }, [router], ) @@ -69,7 +72,10 @@ export function useActiveTemplateCategory() { const validatedCategory = getValidatedTemplateCategory(categoryFromPath) const handleChange = useCallback( (newCategory: string) => { - router.push(`/${CREATION_TYPE.templates}/${newCategory}`) + // Preserve the current query string (e.g. ?languages=en) so manual + // filters survive a category change. + const search = typeof window !== 'undefined' ? window.location.search : '' + router.push(`/${CREATION_TYPE.templates}/${newCategory}${search}`) }, [router], ) diff --git a/web/app/components/plugins/marketplace/list/collection-list.tsx b/web/app/components/plugins/marketplace/list/collection-list.tsx index 5c2a3480bf..16abc1f37e 100644 --- a/web/app/components/plugins/marketplace/list/collection-list.tsx +++ b/web/app/components/plugins/marketplace/list/collection-list.tsx @@ -7,6 +7,7 @@ import type { Locale } from '@/i18n-config/language' import { useLocale, useTranslation } from '#i18n' import { RiArrowRightSLine } from '@remixicon/react' import { useEffect, useMemo, useState } from 'react' +import { renderI18nObject } from '@/i18n-config' import { getLanguage } from '@/i18n-config/language' import { cn } from '@/utils/classnames' import { useMarketplaceMoreClick } from '../atoms' @@ -72,14 +73,15 @@ export function CollectionHeader({ && !!collection.search_params && itemsLength > GRID_DISPLAY_LIMIT - // The API only ships translations for a subset of locales (typically en_US - // and zh_Hans). For any other locale (e.g. ja_JP, pt_BR) the keyed lookup - // returns undefined and the title/description render as empty divs. Fall - // back to the en_US translation, then to whatever value is available, so - // the header always shows something meaningful. + // The API only ships translations for a subset of locales (e.g. en_US and + // zh_Hans). For any other locale (e.g. ja_JP, pt_BR, zh_Hant before fix) + // the keyed lookup returns undefined and the title/description render as + // empty divs. `renderI18nObject` from `@/i18n-config` handles the fallback + // chain (locale → en_US → first available value) consistently across the + // codebase. const lang = getLanguage(locale) - const label = collection.label[lang] || collection.label.en_US || Object.values(collection.label)[0] || '' - const description = collection.description[lang] || collection.description.en_US || Object.values(collection.description)[0] || '' + const label = renderI18nObject(collection.label, lang) + const description = renderI18nObject(collection.description, lang) return (
diff --git a/web/app/components/plugins/marketplace/list/template-card.tsx b/web/app/components/plugins/marketplace/list/template-card.tsx index 414293062c..a8eaf63ac0 100644 --- a/web/app/components/plugins/marketplace/list/template-card.tsx +++ b/web/app/components/plugins/marketplace/list/template-card.tsx @@ -6,7 +6,6 @@ import Link from 'next/link' import * as React from 'react' import { useMemo } from 'react' import AppIcon from '@/app/components/base/app-icon' -import CornerMark from '@/app/components/plugins/card/base/corner-mark' import { MARKETPLACE_URL_PREFIX } from '@/config' import useTheme from '@/hooks/use-theme' import { cn } from '@/utils/classnames' @@ -32,8 +31,8 @@ const TemplateCardComponent = ({ const locale = useLocale() const { t } = useTranslation() const { theme } = useTheme() - const { id, template_name, overview, icon, publisher_handle, publisher_type, usage_count, icon_background, deps_plugins, kind } = template - const isSandbox = kind === 'sandboxed' + const { id, template_name, overview, icon, publisher_handle, publisher_type, usage_count, icon_background, deps_plugins } = template + // const isSandbox = kind === 'sandboxed' const iconUrl = getTemplateIconUrl(template) const href = useMemo(() => { @@ -63,7 +62,7 @@ const TemplateCardComponent = ({ className, )} > - {isSandbox && } + {/* {isSandbox && } */} {/* Header */}
{/* Avatar */} @@ -78,11 +77,11 @@ const TemplateCardComponent = ({
{template_name} -
+
{t('marketplace.templateCard.by', { ns: 'plugin' })}

{overview} @@ -131,7 +130,7 @@ const TemplateCardComponent = ({ ))} {remainingDepsPluginsCount > 0 && (

- + + {remainingDepsPluginsCount} diff --git a/web/i18n-config/language.ts b/web/i18n-config/language.ts index cdfd285442..4f5eddc3b8 100644 --- a/web/i18n-config/language.ts +++ b/web/i18n-config/language.ts @@ -17,7 +17,7 @@ export type Locale = 'ja_JP' | 'zh_Hans' | 'en_US' | (typeof languages[number])[ export const LanguagesSupported: Locale[] = languages.filter(item => item.supported).map(item => item.value) export const getLanguage = (locale: Locale): Locale => { - if (['zh-Hans', 'ja-JP'].includes(locale)) + if (['zh-Hans', 'zh-Hant', 'ja-JP'].includes(locale)) return locale.replace('-', '_') as Locale return LanguagesSupported[0].replace('-', '_') as Locale