From 950a51ff9cdf4d4a7cbd753061667294cd56924d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B9=E9=9B=AA?= <2b@yorha.xyz> Date: Thu, 11 Jun 2026 06:46:57 +0900 Subject: [PATCH] feat(ui): i18n for model select components --- .../components/ModelSelect/ModelSelect.tsx | 26 +++++++++++-------- .../PaginatedModelSelect.tsx | 14 +++++----- ui/litellm-dashboard/src/locales/en.json | 18 +++++++++++++ ui/litellm-dashboard/src/locales/zh-CN.json | 18 +++++++++++++ 4 files changed, 59 insertions(+), 17 deletions(-) diff --git a/ui/litellm-dashboard/src/components/ModelSelect/ModelSelect.tsx b/ui/litellm-dashboard/src/components/ModelSelect/ModelSelect.tsx index 898374d2a61..7865b368721 100644 --- a/ui/litellm-dashboard/src/components/ModelSelect/ModelSelect.tsx +++ b/ui/litellm-dashboard/src/components/ModelSelect/ModelSelect.tsx @@ -3,6 +3,7 @@ import { useOrganization } from "@/app/(dashboard)/hooks/organizations/useOrgani import { useTeam } from "@/app/(dashboard)/hooks/teams/useTeams"; import { useCurrentUser } from "@/app/(dashboard)/hooks/users/useCurrentUser"; import { Select, Skeleton, Tooltip, type SelectProps } from "antd"; +import { useTranslation } from "react-i18next"; import { Organization, Team } from "../networking"; import { splitWildcardModels } from "./modelUtils"; @@ -92,6 +93,7 @@ const filterModels = ( }; export const ModelSelect = (props: ModelSelectProps) => { + const { t } = useTranslation(); const { teamID, organizationID, options, context, dataTestId, value = [], onChange, style } = props; const { includeUserModels, showAllTeamModelsOption, showAllProxyModelsOverride, includeSpecialOptions } = options || {}; @@ -148,13 +150,13 @@ export const ModelSelect = (props: ModelSelectProps) => { ...(includeSpecialOptions ? [ { - label: Special Options, - title: "Special Options", + label: {t("modelSelect.modelSelect.specialOptions")}, + title: t("modelSelect.modelSelect.specialOptions"), options: [ ...(shouldShowAllProxyModels ? [ { - label: All Proxy Models, + label: {t("modelSelect.modelSelect.allProxyModels")}, value: MODEL_SELECT_ALL_PROXY_MODELS_SPECIAL_VALUE.value, disabled: value.length > 0 && @@ -166,7 +168,7 @@ export const ModelSelect = (props: ModelSelectProps) => { ] : []), { - label: No Default Models, + label: {t("modelSelect.modelSelect.noDefaultModels")}, value: MODEL_SELECT_NO_DEFAULT_MODELS_SPECIAL_VALUE.value, disabled: value.length > 0 && @@ -180,14 +182,16 @@ export const ModelSelect = (props: ModelSelectProps) => { ...(wildcard.length > 0 ? [ { - label: Wildcard Options, - title: "Wildcard Options", + label: {t("modelSelect.modelSelect.wildcardOptions")}, + title: t("modelSelect.modelSelect.wildcardOptions"), options: wildcard.map((model) => { const provider = model.replace("/*", ""); const capitalizedProvider = provider.charAt(0).toUpperCase() + provider.slice(1); return { - label: {`All ${capitalizedProvider} models`}, + label: ( + {t("modelSelect.modelSelect.allProviderModels", { provider: capitalizedProvider })} + ), value: model, disabled: hasSpecialOptionSelected, }; @@ -196,8 +200,8 @@ export const ModelSelect = (props: ModelSelectProps) => { ] : []), { - label: Models, - title: "Models", + label: {t("modelSelect.modelSelect.models")}, + title: t("modelSelect.modelSelect.models"), options: regular.map((model) => ({ label: {model}, value: model, @@ -206,7 +210,7 @@ export const ModelSelect = (props: ModelSelectProps) => { }, ]} mode="multiple" - placeholder="Select Models" + placeholder={t("modelSelect.modelSelect.selectModels")} allowClear maxTagCount="responsive" maxTagPlaceholder={(omittedValues) => ( @@ -214,7 +218,7 @@ export const ModelSelect = (props: ModelSelectProps) => { styles={{ root: { pointerEvents: "none" } }} title={omittedValues.map(({ value }) => value).join(", ")} > - +{omittedValues.length} more + {t("modelSelect.modelSelect.moreModels", { count: omittedValues.length })} )} /> diff --git a/ui/litellm-dashboard/src/components/ModelSelect/PaginatedModelSelect/PaginatedModelSelect.tsx b/ui/litellm-dashboard/src/components/ModelSelect/PaginatedModelSelect/PaginatedModelSelect.tsx index da3ecf77ded..4ac8c8341bc 100644 --- a/ui/litellm-dashboard/src/components/ModelSelect/PaginatedModelSelect/PaginatedModelSelect.tsx +++ b/ui/litellm-dashboard/src/components/ModelSelect/PaginatedModelSelect/PaginatedModelSelect.tsx @@ -3,6 +3,7 @@ import { LoadingOutlined } from "@ant-design/icons"; import { useDebouncedState } from "@tanstack/react-pacer/debouncer"; import { Select, Space, Typography } from "antd"; import { useMemo, useState, type UIEvent } from "react"; +import { useTranslation } from "react-i18next"; const { Text } = Typography; @@ -22,12 +23,13 @@ const DEBOUNCE_MS = 300; export const PaginatedModelSelect = ({ value, onChange, - placeholder = "Select a model", + placeholder, style, pageSize = 50, allowClear = true, disabled = false, }: PaginatedModelSelectProps) => { + const { t } = useTranslation(); const [searchInput, setSearchInput] = useState(""); const [debouncedSearch, setDebouncedSearch] = useDebouncedState("", { wait: DEBOUNCE_MS, @@ -73,16 +75,16 @@ export const PaginatedModelSelect = ({ {modelName ? ( - Model name: + {t("modelSelect.paginatedModelSelect.modelNameLabel")} {modelName} - Model ID: {modelId} + {t("modelSelect.paginatedModelSelect.modelIdLabel")} {modelId} ) : ( - Model ID: {modelId} + {t("modelSelect.paginatedModelSelect.modelIdLabel")} {modelId} )} @@ -112,7 +114,7 @@ export const PaginatedModelSelect = ({