diff --git a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/RedactableField.tsx b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/RedactableField.tsx index 44fef5cc7f8..fc184333fe2 100644 --- a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/RedactableField.tsx +++ b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/RedactableField.tsx @@ -1,6 +1,7 @@ import { useState } from "react"; import { Button } from "antd"; import { Eye, EyeOff } from "lucide-react"; +import { useTranslation } from "react-i18next"; export default function RedactableField({ defaultHidden = true, @@ -9,6 +10,7 @@ export default function RedactableField({ defaultHidden?: boolean; value: string | null; }) { + const { t } = useTranslation(); const [isHidden, setIsHidden] = useState(defaultHidden); return ( @@ -21,7 +23,7 @@ export default function RedactableField({ value ) ) : ( - Not configured + {t("settingsPages.redactableField.notConfigured")} )} {value && ( diff --git a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/RoleMappings.tsx b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/RoleMappings.tsx index 3750ee88183..9de5440d870 100644 --- a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/RoleMappings.tsx +++ b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/RoleMappings.tsx @@ -1,23 +1,26 @@ import type { RoleMappings as RoleMappingsType } from "@/app/(dashboard)/hooks/sso/useSSOSettings"; import { Card, Divider, Table, Tag, Typography } from "antd"; import { Users } from "lucide-react"; +import { useTranslation } from "react-i18next"; import { defaultRoleDisplayNames } from "./constants"; const { Title, Text } = Typography; export default function RoleMappings({ roleMappings }: { roleMappings: RoleMappingsType | undefined }) { + const { t } = useTranslation(); + if (!roleMappings) { return null; } const roleMappingsColumns = [ { - title: "Role", + title: t("settingsPages.roleMappings.roleColumn"), dataIndex: "role", key: "role", render: (text: string) => {defaultRoleDisplayNames[text]}, }, { - title: "Mapped Groups", + title: t("settingsPages.roleMappings.mappedGroupsColumn"), dataIndex: "groups", key: "groups", render: (groups: string[]) => ( @@ -29,7 +32,7 @@ export default function RoleMappings({ roleMappings }: { roleMappings: RoleMappi )) ) : ( - No groups mapped + {t("settingsPages.roleMappings.noGroupsMapped")} )} ), @@ -39,18 +42,18 @@ export default function RoleMappings({ roleMappings }: { roleMappings: RoleMappi
- Role Mappings + {t("settingsPages.roleMappings.title")}
- Group Claim + {t("settingsPages.roleMappings.groupClaim")}
{roleMappings.group_claim}
- Default Role + {t("settingsPages.roleMappings.defaultRole")}
{defaultRoleDisplayNames[roleMappings.default_role]}
diff --git a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/SSOSettings.tsx b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/SSOSettings.tsx index 053da380103..afc644bb663 100644 --- a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/SSOSettings.tsx +++ b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/SSOSettings.tsx @@ -4,6 +4,7 @@ import { useSSOSettings, type SSOSettingsValues } from "@/app/(dashboard)/hooks/ import { Button, Card, Descriptions, Space, Tag, Typography } from "antd"; import { Edit, Shield, Trash2 } from "lucide-react"; import { useState } from "react"; +import { useTranslation } from "react-i18next"; import { ssoProviderDisplayNames, ssoProviderLogoMap } from "./constants"; import AddSSOSettingsModal from "./Modals/AddSSOSettingsModal"; import DeleteSSOSettingsModal from "./Modals/DeleteSSOSettingsModal"; @@ -17,6 +18,7 @@ import { detectSSOProvider } from "./utils"; const { Title, Text } = Typography; export default function SSOSettings() { + const { t } = useTranslation(); const { data: ssoSettings, refetch, isLoading } = useSSOSettings(); const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false); const [isAddModalVisible, setIsAddModalVisible] = useState(false); @@ -37,11 +39,11 @@ export default function SSOSettings() { ); const renderSimpleValue = (value?: string | null) => - value ? value : Not configured; + value ? value : {t("settingsPages.sSOSettings.notConfigured")}; const renderTeamMappingsField = (values: SSOSettingsValues) => { if (!values.team_mappings?.team_ids_jwt_field) { - return Not configured; + return {t("settingsPages.sSOSettings.notConfigured")}; } return {values.team_mappings.team_ids_jwt_field}; }; @@ -62,58 +64,70 @@ export default function SSOSettings() { providerText: ssoProviderDisplayNames.google, fields: [ { - label: "Client ID", + label: t("settingsPages.sSOSettings.clientId"), render: (values: SSOSettingsValues) => , }, { - label: "Client Secret", + label: t("settingsPages.sSOSettings.clientSecret"), render: (values: SSOSettingsValues) => , }, - { label: "Proxy Base URL", render: (values: SSOSettingsValues) => renderSimpleValue(values.proxy_base_url) }, + { + label: t("settingsPages.sSOSettings.proxyBaseUrl"), + render: (values: SSOSettingsValues) => renderSimpleValue(values.proxy_base_url), + }, ], }, microsoft: { providerText: ssoProviderDisplayNames.microsoft, fields: [ { - label: "Client ID", + label: t("settingsPages.sSOSettings.clientId"), render: (values: SSOSettingsValues) => , }, { - label: "Client Secret", + label: t("settingsPages.sSOSettings.clientSecret"), render: (values: SSOSettingsValues) => , }, - { label: "Tenant", render: (values: any) => renderSimpleValue(values.microsoft_tenant) }, - { label: "Proxy Base URL", render: (values: SSOSettingsValues) => renderSimpleValue(values.proxy_base_url) }, + { + label: t("settingsPages.sSOSettings.tenant"), + render: (values: any) => renderSimpleValue(values.microsoft_tenant), + }, + { + label: t("settingsPages.sSOSettings.proxyBaseUrl"), + render: (values: SSOSettingsValues) => renderSimpleValue(values.proxy_base_url), + }, ], }, okta: { providerText: ssoProviderDisplayNames.okta, fields: [ { - label: "Client ID", + label: t("settingsPages.sSOSettings.clientId"), render: (values: SSOSettingsValues) => , }, { - label: "Client Secret", + label: t("settingsPages.sSOSettings.clientSecret"), render: (values: SSOSettingsValues) => , }, { - label: "Authorization Endpoint", + label: t("settingsPages.sSOSettings.authorizationEndpoint"), render: (values: SSOSettingsValues) => renderEndpointValue(values.generic_authorization_endpoint), }, { - label: "Token Endpoint", + label: t("settingsPages.sSOSettings.tokenEndpoint"), render: (values: SSOSettingsValues) => renderEndpointValue(values.generic_token_endpoint), }, { - label: "User Info Endpoint", + label: t("settingsPages.sSOSettings.userInfoEndpoint"), render: (values: SSOSettingsValues) => renderEndpointValue(values.generic_userinfo_endpoint), }, - { label: "Proxy Base URL", render: (values: SSOSettingsValues) => renderSimpleValue(values.proxy_base_url) }, + { + label: t("settingsPages.sSOSettings.proxyBaseUrl"), + render: (values: SSOSettingsValues) => renderSimpleValue(values.proxy_base_url), + }, isTeamMappingsEnabled ? { - label: "Team IDs JWT Field", + label: t("settingsPages.sSOSettings.teamIdsJwtField"), render: (values: SSOSettingsValues) => renderTeamMappingsField(values), } : null, @@ -123,29 +137,32 @@ export default function SSOSettings() { providerText: ssoProviderDisplayNames.generic, fields: [ { - label: "Client ID", + label: t("settingsPages.sSOSettings.clientId"), render: (values: SSOSettingsValues) => , }, { - label: "Client Secret", + label: t("settingsPages.sSOSettings.clientSecret"), render: (values: SSOSettingsValues) => , }, { - label: "Authorization Endpoint", + label: t("settingsPages.sSOSettings.authorizationEndpoint"), render: (values: SSOSettingsValues) => renderEndpointValue(values.generic_authorization_endpoint), }, { - label: "Token Endpoint", + label: t("settingsPages.sSOSettings.tokenEndpoint"), render: (values: SSOSettingsValues) => renderEndpointValue(values.generic_token_endpoint), }, { - label: "User Info Endpoint", + label: t("settingsPages.sSOSettings.userInfoEndpoint"), render: (values: SSOSettingsValues) => renderEndpointValue(values.generic_userinfo_endpoint), }, - { label: "Proxy Base URL", render: (values: SSOSettingsValues) => renderSimpleValue(values.proxy_base_url) }, + { + label: t("settingsPages.sSOSettings.proxyBaseUrl"), + render: (values: SSOSettingsValues) => renderSimpleValue(values.proxy_base_url), + }, isTeamMappingsEnabled ? { - label: "Team IDs JWT Field", + label: t("settingsPages.sSOSettings.teamIdsJwtField"), render: (values: SSOSettingsValues) => renderTeamMappingsField(values), } : null, @@ -163,7 +180,7 @@ export default function SSOSettings() { return ( - +
{ssoProviderLogoMap[selectedProvider] && (
- SSO Configuration - Manage Single Sign-On authentication settings + {t("settingsPages.sSOSettings.title")} + {t("settingsPages.sSOSettings.subtitle")}
@@ -209,14 +226,14 @@ export default function SSOSettings() { {isSSOConfigured && ( <> )} diff --git a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/SSOSettingsEmptyPlaceholder.tsx b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/SSOSettingsEmptyPlaceholder.tsx index fc315493a54..e135e9daec4 100644 --- a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/SSOSettingsEmptyPlaceholder.tsx +++ b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/SSOSettingsEmptyPlaceholder.tsx @@ -1,4 +1,5 @@ import { Empty, Typography, Button } from "antd"; +import { useTranslation } from "react-i18next"; const { Title, Paragraph } = Typography; @@ -7,22 +8,23 @@ interface SSOSettingsEmptyPlaceholderProps { } export default function SSOSettingsEmptyPlaceholder({ onAdd }: SSOSettingsEmptyPlaceholderProps) { + const { t } = useTranslation(); + return (
- No SSO Configuration Found + {t("settingsPages.sSOSettingsEmptyPlaceholder.noConfigTitle")} - Configure Single Sign-On (SSO) to enable seamless authentication for your team members using your identity - provider. + {t("settingsPages.sSOSettingsEmptyPlaceholder.noConfigDesc")}
} >
diff --git a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/SSOSettingsLoadingSkeleton.tsx b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/SSOSettingsLoadingSkeleton.tsx index 59e34f255e3..dd4f12e2349 100644 --- a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/SSOSettingsLoadingSkeleton.tsx +++ b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/SSOSettingsLoadingSkeleton.tsx @@ -2,9 +2,11 @@ import { Card, Descriptions, Skeleton, Space, Typography } from "antd"; import { Shield } from "lucide-react"; +import { useTranslation } from "react-i18next"; const { Title, Text } = Typography; export default function SSOSettingsLoadingSkeleton() { + const { t } = useTranslation(); const descriptionsConfig = { column: { xxl: 1, @@ -24,8 +26,8 @@ export default function SSOSettingsLoadingSkeleton() {
- SSO Configuration - Manage Single Sign-On authentication settings + {t("settingsPages.sSOSettings.title")} + {t("settingsPages.sSOSettings.subtitle")}
diff --git a/ui/litellm-dashboard/src/components/Settings/AdminSettings/UISettings/PageVisibilitySettings.tsx b/ui/litellm-dashboard/src/components/Settings/AdminSettings/UISettings/PageVisibilitySettings.tsx index 9cfe4e7ccc7..a7cee0d20e2 100644 --- a/ui/litellm-dashboard/src/components/Settings/AdminSettings/UISettings/PageVisibilitySettings.tsx +++ b/ui/litellm-dashboard/src/components/Settings/AdminSettings/UISettings/PageVisibilitySettings.tsx @@ -63,15 +63,15 @@ export default function PageVisibilitySettings({ - Internal User Page Visibility + {t("settingsPages.pageVisibilitySettings.title")} {!isPageVisibilitySet && ( - Not set (all pages visible) + {t("settingsPages.pageVisibilitySettings.notSet")} )} {isPageVisibilitySet && ( - {selectedPages.length} page{selectedPages.length !== 1 ? "s" : ""} selected + {t("settingsPages.pageVisibilitySettings.pagesSelected", { count: selectedPages.length })} )} @@ -79,11 +79,10 @@ export default function PageVisibilitySettings({ {enabledPagesPropertyDescription} )} - By default, all pages are visible to internal users. Select specific pages to restrict visibility. + {t("settingsPages.pageVisibilitySettings.defaultHint")} - Note: Only pages accessible to internal user roles are shown here. Admin-only pages are excluded as they - cannot be made visible to internal users regardless of this setting. + {t("settingsPages.pageVisibilitySettings.adminOnlyNote")} @@ -91,7 +90,7 @@ export default function PageVisibilitySettings({ items={[ { key: "page-visibility", - label: "Configure Page Visibility", + label: t("settingsPages.pageVisibilitySettings.configureLabel"), children: ( @@ -131,11 +130,11 @@ export default function PageVisibilitySettings({ {isPageVisibilitySet && ( )} diff --git a/ui/litellm-dashboard/src/components/Settings/AdminSettings/UISettings/UISettings.tsx b/ui/litellm-dashboard/src/components/Settings/AdminSettings/UISettings/UISettings.tsx index 25865c48f9b..8cd044d590e 100644 --- a/ui/litellm-dashboard/src/components/Settings/AdminSettings/UISettings/UISettings.tsx +++ b/ui/litellm-dashboard/src/components/Settings/AdminSettings/UISettings/UISettings.tsx @@ -6,8 +6,10 @@ import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized"; import NotificationManager from "@/components/molecules/notifications_manager"; import PageVisibilitySettings from "./PageVisibilitySettings"; import { Alert, Card, Divider, Skeleton, Space, Switch, Typography } from "antd"; +import { useTranslation } from "react-i18next"; export default function UISettings() { + const { t } = useTranslation(); const { accessToken } = useAuthorized(); const { data, isLoading, isError, error } = useUISettings(); const { mutate: updateSettings, isPending: isUpdating, error: updateError } = useUpdateUISettings(accessToken); @@ -38,7 +40,7 @@ export default function UISettings() { { disable_model_add_for_internal_users: checked }, { onSuccess: () => { - NotificationManager.success("UI settings updated successfully"); + NotificationManager.success(t("settingsPages.uISettings.updateSuccess")); }, onError: (error) => { NotificationManager.fromBackend(error); @@ -52,7 +54,7 @@ export default function UISettings() { { disable_team_admin_delete_team_user: checked }, { onSuccess: () => { - NotificationManager.success("UI settings updated successfully"); + NotificationManager.success(t("settingsPages.uISettings.updateSuccess")); }, onError: (error) => { NotificationManager.fromBackend(error); @@ -66,7 +68,7 @@ export default function UISettings() { { disable_ui_nudges: checked }, { onSuccess: () => { - NotificationManager.success("UI settings updated successfully"); + NotificationManager.success(t("settingsPages.uISettings.updateSuccess")); }, onError: (error) => { NotificationManager.fromBackend(error); @@ -78,7 +80,7 @@ export default function UISettings() { const handleUpdatePageVisibility = (settings: { enabled_ui_pages_internal_users: string[] | null }) => { updateSettings(settings, { onSuccess: () => { - NotificationManager.success("Page visibility settings updated successfully"); + NotificationManager.success(t("settingsPages.uISettings.pageVisibilityUpdateSuccess")); }, onError: (error) => { NotificationManager.fromBackend(error); @@ -91,7 +93,7 @@ export default function UISettings() { { forward_client_headers_to_llm_api: checked }, { onSuccess: () => { - NotificationManager.success("UI settings updated successfully"); + NotificationManager.success(t("settingsPages.uISettings.updateSuccess")); }, onError: (error) => { NotificationManager.fromBackend(error); @@ -105,7 +107,7 @@ export default function UISettings() { { forward_llm_provider_auth_headers: checked }, { onSuccess: () => { - NotificationManager.success("UI settings updated successfully"); + NotificationManager.success(t("settingsPages.uISettings.updateSuccess")); }, onError: (error) => { NotificationManager.fromBackend(error); @@ -119,7 +121,7 @@ export default function UISettings() { { enable_projects_ui: checked }, { onSuccess: () => { - NotificationManager.success("UI settings updated successfully. Refreshing page..."); + NotificationManager.success(t("settingsPages.uISettings.updateSuccessRefreshing")); setTimeout(() => window.location.reload(), 1000); }, onError: (error) => { @@ -134,7 +136,7 @@ export default function UISettings() { { require_auth_for_public_ai_hub: checked }, { onSuccess: () => { - NotificationManager.success("UI settings updated successfully"); + NotificationManager.success(t("settingsPages.uISettings.updateSuccess")); }, onError: (error) => { NotificationManager.fromBackend(error); @@ -148,7 +150,7 @@ export default function UISettings() { { disable_agents_for_internal_users: checked }, { onSuccess: () => { - NotificationManager.success("UI settings updated successfully"); + NotificationManager.success(t("settingsPages.uISettings.updateSuccess")); }, onError: (error) => { NotificationManager.fromBackend(error); @@ -162,7 +164,7 @@ export default function UISettings() { { allow_agents_for_team_admins: checked }, { onSuccess: () => { - NotificationManager.success("UI settings updated successfully"); + NotificationManager.success(t("settingsPages.uISettings.updateSuccess")); }, onError: (error) => { NotificationManager.fromBackend(error); @@ -176,7 +178,7 @@ export default function UISettings() { { disable_vector_stores_for_internal_users: checked }, { onSuccess: () => { - NotificationManager.success("UI settings updated successfully"); + NotificationManager.success(t("settingsPages.uISettings.updateSuccess")); }, onError: (error) => { NotificationManager.fromBackend(error); @@ -190,7 +192,7 @@ export default function UISettings() { { allow_vector_stores_for_team_admins: checked }, { onSuccess: () => { - NotificationManager.success("UI settings updated successfully"); + NotificationManager.success(t("settingsPages.uISettings.updateSuccess")); }, onError: (error) => { NotificationManager.fromBackend(error); @@ -204,7 +206,7 @@ export default function UISettings() { { scope_user_search_to_org: checked }, { onSuccess: () => { - NotificationManager.success("UI settings updated successfully"); + NotificationManager.success(t("settingsPages.uISettings.updateSuccess")); }, onError: (error) => { NotificationManager.fromBackend(error); @@ -218,7 +220,7 @@ export default function UISettings() { { disable_custom_api_keys: checked }, { onSuccess: () => { - NotificationManager.success("UI settings updated successfully"); + NotificationManager.success(t("settingsPages.uISettings.updateSuccess")); }, onError: (error) => { NotificationManager.fromBackend(error); @@ -228,13 +230,13 @@ export default function UISettings() { }; return ( - + {isLoading ? ( ) : isError ? ( ) : ( @@ -246,7 +248,7 @@ export default function UISettings() { {updateError && ( )} @@ -257,10 +259,10 @@ export default function UISettings() { disabled={isUpdating} loading={isUpdating} onChange={handleToggle} - aria-label={property?.description ?? "Disable model add for internal users"} + aria-label={property?.description ?? t("settingsPages.uISettings.disableModelAddLabel")} /> - Disable model add for internal users + {t("settingsPages.uISettings.disableModelAddLabel")} {property?.description && {property.description}} @@ -271,10 +273,12 @@ export default function UISettings() { disabled={isUpdating} loading={isUpdating} onChange={handleToggleTeamAdminDelete} - aria-label={disableTeamAdminDeleteProperty?.description ?? "Disable team admin delete team user"} + aria-label={ + disableTeamAdminDeleteProperty?.description ?? t("settingsPages.uISettings.disableTeamAdminDeleteLabel") + } /> - Disable team admin delete team user + {t("settingsPages.uISettings.disableTeamAdminDeleteLabel")} {disableTeamAdminDeleteProperty?.description && ( {disableTeamAdminDeleteProperty.description} )} @@ -287,10 +291,13 @@ export default function UISettings() { disabled={isUpdating} loading={isUpdating} onChange={handleToggleRequireAuthForPublicAIHub} - aria-label={requireAuthForPublicAIHubProperty?.description ?? "Require authentication for public AI Hub"} + aria-label={ + requireAuthForPublicAIHubProperty?.description ?? + t("settingsPages.uISettings.requireAuthPublicAIHubLabel") + } /> - Require authentication for public AI Hub + {t("settingsPages.uISettings.requireAuthPublicAIHubLabel")} {requireAuthForPublicAIHubProperty?.description && ( {requireAuthForPublicAIHubProperty.description} )} @@ -303,13 +310,14 @@ export default function UISettings() { disabled={isUpdating} loading={isUpdating} onChange={handleToggleForwardClientHeaders} - aria-label={forwardClientHeadersProperty?.description ?? "Forward client headers to LLM API"} + aria-label={ + forwardClientHeadersProperty?.description ?? t("settingsPages.uISettings.forwardClientHeadersLabel") + } /> - Forward client headers to LLM API + {t("settingsPages.uISettings.forwardClientHeadersLabel")} - {forwardClientHeadersProperty?.description ?? - "Forwards client headers (Authorization, anthropic-beta, and x-* custom headers) to the upstream LLM. Enable for Claude Code with a Max subscription (forwards the OAuth token) or to pass custom/tracing headers through to the provider. Independent of the BYOK toggle — enable only the one(s) you need."} + {forwardClientHeadersProperty?.description ?? t("settingsPages.uISettings.forwardClientHeadersDesc")} @@ -320,13 +328,18 @@ export default function UISettings() { disabled={isUpdating} loading={isUpdating} onChange={handleToggleForwardLLMProviderAuthHeaders} - aria-label={forwardLLMProviderAuthHeadersProperty?.description ?? "Forward LLM provider auth headers"} + aria-label={ + forwardLLMProviderAuthHeadersProperty?.description ?? + t("settingsPages.uISettings.forwardLLMProviderAuthHeadersLabel") + } /> - Forward LLM provider auth headers + + {t("settingsPages.uISettings.forwardLLMProviderAuthHeadersLabel")} + {forwardLLMProviderAuthHeadersProperty?.description ?? - "Forwards provider auth headers (x-api-key, x-goog-api-key, api-key, ocp-apim-subscription-key) to the upstream LLM, overriding any deployment-configured key for that request. Enable for Claude Code BYOK (clients bring their own API key). Independent of the client-headers toggle — enable only the one(s) you need."} + t("settingsPages.uISettings.forwardLLMProviderAuthHeadersDesc")} @@ -338,13 +351,12 @@ export default function UISettings() { disabled={isUpdating} loading={isUpdating} onChange={handleToggleEnableProjectsUI} - aria-label={enableProjectsUIProperty.description ?? "Enable Projects UI"} + aria-label={enableProjectsUIProperty.description ?? t("settingsPages.uISettings.enableProjectsUILabel")} /> - [BETA] Enable Projects (page will refresh) + {t("settingsPages.uISettings.enableProjectsUILabel")} - {enableProjectsUIProperty.description ?? - "If enabled, shows the Projects feature in the UI sidebar and the project field in key management."} + {enableProjectsUIProperty.description ?? t("settingsPages.uISettings.enableProjectsUIDesc")} @@ -359,10 +371,10 @@ export default function UISettings() { disabled={isUpdating} loading={isUpdating} onChange={handleToggleDisableAgents} - aria-label={disableAgentsProperty?.description ?? "Disable agents for internal users"} + aria-label={disableAgentsProperty?.description ?? t("settingsPages.uISettings.disableAgentsLabel")} /> - Disable agents for internal users + {t("settingsPages.uISettings.disableAgentsLabel")} {disableAgentsProperty?.description && ( {disableAgentsProperty.description} )} @@ -375,11 +387,13 @@ export default function UISettings() { disabled={isUpdating || !isAgentsDisabled} loading={isUpdating} onChange={handleToggleAllowAgentsTeamAdmins} - aria-label={allowAgentsTeamAdminsProperty?.description ?? "Allow agents for team admins"} + aria-label={ + allowAgentsTeamAdminsProperty?.description ?? t("settingsPages.uISettings.allowAgentsTeamAdminsLabel") + } /> - Allow agents for team admins + {t("settingsPages.uISettings.allowAgentsTeamAdminsLabel")} {allowAgentsTeamAdminsProperty?.description && ( {allowAgentsTeamAdminsProperty.description} @@ -396,10 +410,12 @@ export default function UISettings() { disabled={isUpdating} loading={isUpdating} onChange={handleToggleDisableVectorStores} - aria-label={disableVectorStoresProperty?.description ?? "Disable vector stores for internal users"} + aria-label={ + disableVectorStoresProperty?.description ?? t("settingsPages.uISettings.disableVectorStoresLabel") + } /> - Disable vector stores for internal users + {t("settingsPages.uISettings.disableVectorStoresLabel")} {disableVectorStoresProperty?.description && ( {disableVectorStoresProperty.description} )} @@ -412,11 +428,14 @@ export default function UISettings() { disabled={isUpdating || !isVectorStoresDisabled} loading={isUpdating} onChange={handleToggleAllowVectorStoresTeamAdmins} - aria-label={allowVectorStoresTeamAdminsProperty?.description ?? "Allow vector stores for team admins"} + aria-label={ + allowVectorStoresTeamAdminsProperty?.description ?? + t("settingsPages.uISettings.allowVectorStoresTeamAdminsLabel") + } /> - Allow vector stores for team admins + {t("settingsPages.uISettings.allowVectorStoresTeamAdminsLabel")} {allowVectorStoresTeamAdminsProperty?.description && ( {allowVectorStoresTeamAdminsProperty.description} @@ -433,13 +452,12 @@ export default function UISettings() { disabled={isUpdating} loading={isUpdating} onChange={handleToggleScopeUserSearch} - aria-label={scopeUserSearchProperty?.description ?? "Scope user search to organization"} + aria-label={scopeUserSearchProperty?.description ?? t("settingsPages.uISettings.scopeUserSearchLabel")} /> - Scope user search to organization + {t("settingsPages.uISettings.scopeUserSearchLabel")} - {scopeUserSearchProperty?.description ?? - "If enabled, the user search endpoint restricts results by organization. When off, any authenticated user can search all users."} + {scopeUserSearchProperty?.description ?? t("settingsPages.uISettings.scopeUserSearchDesc")} @@ -453,13 +471,14 @@ export default function UISettings() { disabled={isUpdating} loading={isUpdating} onChange={handleToggleDisableCustomApiKeys} - aria-label={disableCustomApiKeysProperty?.description ?? "Disable custom Virtual key values"} + aria-label={ + disableCustomApiKeysProperty?.description ?? t("settingsPages.uISettings.disableCustomApiKeysLabel") + } /> - Disable custom Virtual key values + {t("settingsPages.uISettings.disableCustomApiKeysLabel")} - {disableCustomApiKeysProperty?.description ?? - "If true, users cannot specify custom key values. All keys must be auto-generated."} + {disableCustomApiKeysProperty?.description ?? t("settingsPages.uISettings.disableCustomApiKeysDesc")} @@ -473,13 +492,12 @@ export default function UISettings() { disabled={isUpdating} loading={isUpdating} onChange={handleToggleDisableUINudges} - aria-label={disableUINudgesProperty?.description ?? "Disable UI nudges"} + aria-label={disableUINudgesProperty?.description ?? t("settingsPages.uISettings.disableUINudgesLabel")} /> - Disable UI nudges + {t("settingsPages.uISettings.disableUINudgesLabel")} - {disableUINudgesProperty?.description ?? - "If true, suppresses in-product UI nudges (survey and Claude Code feedback popups) for all users."} + {disableUINudgesProperty?.description ?? t("settingsPages.uISettings.disableUINudgesDesc")} diff --git a/ui/litellm-dashboard/src/components/Settings/LoggingAndAlerts/LoggingCallbacks/LoggingCallbacksTable.tsx b/ui/litellm-dashboard/src/components/Settings/LoggingAndAlerts/LoggingCallbacks/LoggingCallbacksTable.tsx index 8f332d0317a..1cd28f95f84 100644 --- a/ui/litellm-dashboard/src/components/Settings/LoggingAndAlerts/LoggingCallbacks/LoggingCallbacksTable.tsx +++ b/ui/litellm-dashboard/src/components/Settings/LoggingAndAlerts/LoggingCallbacks/LoggingCallbacksTable.tsx @@ -3,6 +3,7 @@ import type { TableProps } from "antd"; import { Table } from "antd"; import Title from "antd/es/typography/Title"; import React from "react"; +import { useTranslation } from "react-i18next"; import TableIconActionButton from "../../../common_components/IconActionButton/TableIconActionButtons/TableIconActionButton"; import { AlertingObject } from "./types"; @@ -27,10 +28,10 @@ type CallbackRow = AlertingObject & { mode?: "success" | "failure" | "info" | string; }; -const CALLBACK_MODES: { value: string; label: string }[] = [ - { value: "success", label: "Success" }, - { value: "failure", label: "Failure" }, - { value: "success_and_failure", label: "Success & Failure" }, +const getCallbackModes = (t: ReturnType["t"]): { value: string; label: string }[] => [ + { value: "success", label: t("settingsPages.loggingCallbacksTable.modeSuccess") }, + { value: "failure", label: t("settingsPages.loggingCallbacksTable.modeFailure") }, + { value: "success_and_failure", label: t("settingsPages.loggingCallbacksTable.modeSuccessAndFailure") }, ]; export const LoggingCallbacksTable: React.FC = ({ @@ -41,9 +42,14 @@ export const LoggingCallbacksTable: React.FC = ({ onDelete = () => {}, onAdd = () => {}, }) => { + const { t } = useTranslation(); + const callbackModes = React.useMemo(() => getCallbackModes(t), [t]); + const columns: TableProps["columns"] = [ { - title: Callback Name, + title: ( + {t("settingsPages.loggingCallbacksTable.callbackNameColumn")} + ), dataIndex: "name", key: "name", render: (_: string, record: CallbackRow) => { @@ -54,11 +60,11 @@ export const LoggingCallbacksTable: React.FC = ({ }, }, { - title: Mode, + title: {t("settingsPages.loggingCallbacksTable.modeColumn")}, key: "mode", render: (_: unknown, record: CallbackRow) => { const mode = record.mode || "success"; - const label = CALLBACK_MODES.find((m) => m.value === mode)?.label || mode; + const label = callbackModes.find((m) => m.value === mode)?.label || mode; const badgeClass = mode === "success" ? "bg-green-100 text-green-800" @@ -74,14 +80,26 @@ export const LoggingCallbacksTable: React.FC = ({ width: 240, }, { - title: Actions, + title: {t("common.actions")}, key: "actions", align: "right", render: (_: unknown, record: CallbackRow) => (
- onTest(record)} /> - onEdit(record)} /> - onDelete(record)} /> + onTest(record)} + /> + onEdit(record)} + /> + onDelete(record)} + />
), width: 240, @@ -91,17 +109,18 @@ export const LoggingCallbacksTable: React.FC = ({ <>
- Active Logging Callbacks + {t("settingsPages.loggingCallbacksTable.activeCallbacksTitle")}
- {/* Empty state */} {callbacks.length === 0 ? (
-

No callbacks configured

-

Add your first callback to start logging data to external services.

+

+ {t("settingsPages.loggingCallbacksTable.emptyStateTitle")} +

+

{t("settingsPages.loggingCallbacksTable.emptyStateDesc")}

) : ( diff --git a/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/AddFallbacks.tsx b/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/AddFallbacks.tsx index 8b86ff862f9..6fa4c5375f0 100644 --- a/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/AddFallbacks.tsx +++ b/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/AddFallbacks.tsx @@ -7,6 +7,7 @@ import { Button as TremorButton } from "@tremor/react"; import { Button } from "antd"; import React, { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; import MessageManager from "@/components/molecules/message_manager"; import NotificationManager from "../../../molecules/notifications_manager"; import { fetchAvailableModels, ModelGroup } from "../../../playground/llm_calls/fetch_models"; @@ -25,6 +26,7 @@ interface AddFallbacksProps { } export default function AddFallbacks({ models, accessToken, value = [], onChange }: AddFallbacksProps) { + const { t } = useTranslation(); const [isModalVisible, setIsModalVisible] = useState(false); const [modelInfo, setModelInfo] = useState([]); const [modalKey, setModalKey] = useState(0); // Key to force remount of form when modal opens @@ -84,9 +86,7 @@ export default function AddFallbacks({ models, accessToken, value = [], onChange // Validation const invalidGroups = groups.filter((g) => !g.primaryModel || g.fallbackModels.length === 0); if (invalidGroups.length > 0) { - MessageManager.error( - `Please complete configuration for all groups. ${invalidGroups.length} group(s) incomplete.`, - ); + MessageManager.error(t("settingsPages.addFallbacks.incompleteGroups", { count: invalidGroups.length })); return; } @@ -106,7 +106,7 @@ export default function AddFallbacks({ models, accessToken, value = [], onChange setIsSaving(true); try { await onChange(updatedFallbacks); - NotificationManager.success(`${groups.length} fallback configuration(s) added successfully!`); + NotificationManager.success(t("settingsPages.addFallbacks.addSuccess", { count: groups.length })); handleCancel(); } catch (error) { // Error handling is done in handleFallbacksChange, so we don't need to show another notification here @@ -126,7 +126,7 @@ export default function AddFallbacks({ models, accessToken, value = [], onChange onClick={() => setIsModalVisible(true)} icon={() => +} > - Add Fallbacks + {t("settingsPages.addFallbacks.addButton")} 0 && (
)} diff --git a/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/AddFallbacksModal.tsx b/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/AddFallbacksModal.tsx index 5af85d6989e..4e12d375e98 100644 --- a/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/AddFallbacksModal.tsx +++ b/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/AddFallbacksModal.tsx @@ -6,6 +6,7 @@ import { Modal } from "antd"; import { ArrowRight } from "lucide-react"; import React from "react"; +import { useTranslation } from "react-i18next"; interface AddFallbacksModalProps { open: boolean; @@ -14,6 +15,8 @@ interface AddFallbacksModalProps { } export function AddFallbacksModal({ open, onCancel, children }: AddFallbacksModalProps) { + const { t } = useTranslation(); + return (
-

Configure Model Fallbacks

-

- Manage multiple fallback chains for different models (up to 5 groups at a time) -

+

{t("settingsPages.addFallbacksModal.title")}

+

{t("settingsPages.addFallbacksModal.subtitle")}

diff --git a/ui/litellm-dashboard/src/locales/en.json b/ui/litellm-dashboard/src/locales/en.json index 32647c5ee1f..019aba2332a 100644 --- a/ui/litellm-dashboard/src/locales/en.json +++ b/ui/litellm-dashboard/src/locales/en.json @@ -4353,6 +4353,103 @@ "updateSuccess": "SSO settings updated successfully", "saveFailed": "Failed to save SSO settings: {{error}}", "processFailed": "Failed to process SSO settings: {{error}}" + }, + "redactableField": { + "notConfigured": "Not configured" + }, + "roleMappings": { + "title": "Role Mappings", + "roleColumn": "Role", + "mappedGroupsColumn": "Mapped Groups", + "noGroupsMapped": "No groups mapped", + "groupClaim": "Group Claim", + "defaultRole": "Default Role" + }, + "sSOSettings": { + "title": "SSO Configuration", + "subtitle": "Manage Single Sign-On authentication settings", + "notConfigured": "Not configured", + "provider": "Provider", + "clientId": "Client ID", + "clientSecret": "Client Secret", + "proxyBaseUrl": "Proxy Base URL", + "tenant": "Tenant", + "authorizationEndpoint": "Authorization Endpoint", + "tokenEndpoint": "Token Endpoint", + "userInfoEndpoint": "User Info Endpoint", + "teamIdsJwtField": "Team IDs JWT Field", + "editSSOSettings": "Edit SSO Settings", + "deleteSSOSettings": "Delete SSO Settings" + }, + "sSOSettingsEmptyPlaceholder": { + "noConfigTitle": "No SSO Configuration Found", + "noConfigDesc": "Configure Single Sign-On (SSO) to enable seamless authentication for your team members using your identity provider.", + "configureButton": "Configure SSO" + }, + "pageVisibilitySettings": { + "title": "Internal User Page Visibility", + "notSet": "Not set (all pages visible)", + "pagesSelected_one": "{{count}} page selected", + "pagesSelected_other": "{{count}} pages selected", + "defaultHint": "By default, all pages are visible to internal users. Select specific pages to restrict visibility.", + "adminOnlyNote": "Note: Only pages accessible to internal user roles are shown here. Admin-only pages are excluded as they cannot be made visible to internal users regardless of this setting.", + "configureLabel": "Configure Page Visibility", + "saveButton": "Save Page Visibility Settings", + "resetButton": "Reset to Default (All Pages)" + }, + "uISettings": { + "cardTitle": "UI Settings", + "loadError": "Could not load UI settings", + "updateError": "Could not update UI settings", + "updateSuccess": "UI settings updated successfully", + "updateSuccessRefreshing": "UI settings updated successfully. Refreshing page...", + "pageVisibilityUpdateSuccess": "Page visibility settings updated successfully", + "disableModelAddLabel": "Disable model add for internal users", + "disableTeamAdminDeleteLabel": "Disable team admin delete team user", + "requireAuthPublicAIHubLabel": "Require authentication for public AI Hub", + "forwardClientHeadersLabel": "Forward client headers to LLM API", + "forwardClientHeadersDesc": "Forwards client headers (Authorization, anthropic-beta, and x-* custom headers) to the upstream LLM. Enable for Claude Code with a Max subscription (forwards the OAuth token) or to pass custom/tracing headers through to the provider. Independent of the BYOK toggle — enable only the one(s) you need.", + "forwardLLMProviderAuthHeadersLabel": "Forward LLM provider auth headers", + "forwardLLMProviderAuthHeadersDesc": "Forwards provider auth headers (x-api-key, x-goog-api-key, api-key, ocp-apim-subscription-key) to the upstream LLM, overriding any deployment-configured key for that request. Enable for Claude Code BYOK (clients bring their own API key). Independent of the client-headers toggle — enable only the one(s) you need.", + "enableProjectsUILabel": "[BETA] Enable Projects (page will refresh)", + "enableProjectsUIDesc": "If enabled, shows the Projects feature in the UI sidebar and the project field in key management.", + "disableAgentsLabel": "Disable agents for internal users", + "allowAgentsTeamAdminsLabel": "Allow agents for team admins", + "disableVectorStoresLabel": "Disable vector stores for internal users", + "allowVectorStoresTeamAdminsLabel": "Allow vector stores for team admins", + "scopeUserSearchLabel": "Scope user search to organization", + "scopeUserSearchDesc": "If enabled, the user search endpoint restricts results by organization. When off, any authenticated user can search all users.", + "disableCustomApiKeysLabel": "Disable custom Virtual key values", + "disableCustomApiKeysDesc": "If true, users cannot specify custom key values. All keys must be auto-generated.", + "disableUINudgesLabel": "Disable UI nudges", + "disableUINudgesDesc": "If true, suppresses in-product UI nudges (survey and Claude Code feedback popups) for all users." + }, + "loggingCallbacksTable": { + "addCallbackButton": "+ Add Callback", + "activeCallbacksTitle": "Active Logging Callbacks", + "callbackNameColumn": "Callback Name", + "modeColumn": "Mode", + "modeSuccess": "Success", + "modeFailure": "Failure", + "modeSuccessAndFailure": "Success & Failure", + "testCallbackTooltip": "Test Callback", + "editCallbackTooltip": "Edit Callback", + "deleteCallbackTooltip": "Delete Callback", + "emptyStateTitle": "No callbacks configured", + "emptyStateDesc": "Add your first callback to start logging data to external services." + }, + "addFallbacks": { + "addButton": "Add Fallbacks", + "incompleteGroups_one": "Please complete configuration for all groups. {{count}} group incomplete.", + "incompleteGroups_other": "Please complete configuration for all groups. {{count}} groups incomplete.", + "addSuccess_one": "{{count}} fallback configuration added successfully!", + "addSuccess_other": "{{count}} fallback configurations added successfully!", + "savingButton": "Saving Configuration...", + "saveButton": "Save All Configurations" + }, + "addFallbacksModal": { + "title": "Configure Model Fallbacks", + "subtitle": "Manage multiple fallback chains for different models (up to 5 groups at a time)" } } } diff --git a/ui/litellm-dashboard/src/locales/zh-CN.json b/ui/litellm-dashboard/src/locales/zh-CN.json index 92ffcd67c0a..b270f859e39 100644 --- a/ui/litellm-dashboard/src/locales/zh-CN.json +++ b/ui/litellm-dashboard/src/locales/zh-CN.json @@ -4353,6 +4353,103 @@ "updateSuccess": "SSO 设置更新成功", "saveFailed": "保存 SSO 设置失败:{{error}}", "processFailed": "处理 SSO 设置失败:{{error}}" + }, + "redactableField": { + "notConfigured": "未配置" + }, + "roleMappings": { + "title": "角色映射", + "roleColumn": "角色", + "mappedGroupsColumn": "映射的用户组", + "noGroupsMapped": "未映射用户组", + "groupClaim": "Group Claim", + "defaultRole": "默认角色" + }, + "sSOSettings": { + "title": "SSO 配置", + "subtitle": "管理单点登录认证设置", + "notConfigured": "未配置", + "provider": "提供商", + "clientId": "Client ID", + "clientSecret": "Client Secret", + "proxyBaseUrl": "代理基础 URL", + "tenant": "租户", + "authorizationEndpoint": "授权端点", + "tokenEndpoint": "Token 端点", + "userInfoEndpoint": "用户信息端点", + "teamIdsJwtField": "团队 ID JWT 字段", + "editSSOSettings": "编辑 SSO 设置", + "deleteSSOSettings": "删除 SSO 设置" + }, + "sSOSettingsEmptyPlaceholder": { + "noConfigTitle": "未找到 SSO 配置", + "noConfigDesc": "配置单点登录(SSO)可让团队成员通过您的身份提供商进行无缝认证。", + "configureButton": "配置 SSO" + }, + "pageVisibilitySettings": { + "title": "内部用户页面可见性", + "notSet": "未设置(所有页面可见)", + "pagesSelected_one": "已选择 {{count}} 个页面", + "pagesSelected_other": "已选择 {{count}} 个页面", + "defaultHint": "默认情况下,所有页面对内部用户可见。选择特定页面可限制可见性。", + "adminOnlyNote": "注意:此处仅显示内部用户角色可访问的页面。仅管理员可访问的页面已排除,无论此设置如何都无法对内部用户显示。", + "configureLabel": "配置页面可见性", + "saveButton": "保存页面可见性设置", + "resetButton": "重置为默认值(所有页面)" + }, + "uISettings": { + "cardTitle": "界面设置", + "loadError": "无法加载界面设置", + "updateError": "无法更新界面设置", + "updateSuccess": "界面设置更新成功", + "updateSuccessRefreshing": "界面设置更新成功,正在刷新页面...", + "pageVisibilityUpdateSuccess": "页面可见性设置更新成功", + "disableModelAddLabel": "禁止内部用户添加模型", + "disableTeamAdminDeleteLabel": "禁止团队管理员删除团队用户", + "requireAuthPublicAIHubLabel": "公共 AI Hub 需要认证", + "forwardClientHeadersLabel": "将客户端请求头转发到 LLM API", + "forwardClientHeadersDesc": "将客户端请求头(Authorization、anthropic-beta 及 x-* 自定义头)转发到上游 LLM。可用于带 Max 订阅的 Claude Code(转发 OAuth Token)或将自定义/追踪头透传到提供商。与 BYOK 开关相互独立,按需启用其一。", + "forwardLLMProviderAuthHeadersLabel": "转发 LLM 提供商认证请求头", + "forwardLLMProviderAuthHeadersDesc": "将提供商认证请求头(x-api-key、x-goog-api-key、api-key、ocp-apim-subscription-key)转发到上游 LLM,覆盖该请求的部署配置密钥。可用于 Claude Code BYOK(客户端自带 API 密钥)。与客户端请求头开关相互独立,按需启用其一。", + "enableProjectsUILabel": "[BETA] 启用项目功能(页面将刷新)", + "enableProjectsUIDesc": "启用后,将在界面侧边栏显示项目功能,并在密钥管理中显示项目字段。", + "disableAgentsLabel": "禁止内部用户使用 Agent", + "allowAgentsTeamAdminsLabel": "允许团队管理员使用 Agent", + "disableVectorStoresLabel": "禁止内部用户使用向量存储", + "allowVectorStoresTeamAdminsLabel": "允许团队管理员使用向量存储", + "scopeUserSearchLabel": "将用户搜索范围限定到组织", + "scopeUserSearchDesc": "启用后,用户搜索端点将按组织限制结果。关闭时,任何已认证用户均可搜索所有用户。", + "disableCustomApiKeysLabel": "禁用自定义虚拟密钥值", + "disableCustomApiKeysDesc": "若为 true,用户无法指定自定义密钥值,所有密钥必须自动生成。", + "disableUINudgesLabel": "禁用界面提示", + "disableUINudgesDesc": "若为 true,将为所有用户屏蔽产品内界面提示(调查问卷和 Claude Code 反馈弹窗)。" + }, + "loggingCallbacksTable": { + "addCallbackButton": "+ 添加回调", + "activeCallbacksTitle": "已激活的日志回调", + "callbackNameColumn": "回调名称", + "modeColumn": "模式", + "modeSuccess": "成功", + "modeFailure": "失败", + "modeSuccessAndFailure": "成功与失败", + "testCallbackTooltip": "测试回调", + "editCallbackTooltip": "编辑回调", + "deleteCallbackTooltip": "删除回调", + "emptyStateTitle": "未配置回调", + "emptyStateDesc": "添加您的第一个回调,开始将数据记录到外部服务。" + }, + "addFallbacks": { + "addButton": "添加回退", + "incompleteGroups_one": "请完成所有组的配置,{{count}} 个组尚未完成。", + "incompleteGroups_other": "请完成所有组的配置,{{count}} 个组尚未完成。", + "addSuccess_one": "成功添加 {{count}} 个回退配置!", + "addSuccess_other": "成功添加 {{count}} 个回退配置!", + "savingButton": "正在保存配置...", + "saveButton": "保存所有配置" + }, + "addFallbacksModal": { + "title": "配置模型回退", + "subtitle": "管理不同模型的多个回退链(每次最多 5 组)" } } }