From faed97b8692ff9a8cb9a2f24f481e4bc3f3dd6cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B9=E9=9B=AA?= <2b@yorha.xyz> Date: Wed, 10 Jun 2026 17:48:14 +0900 Subject: [PATCH] feat(ui): i18n for add guardrail form --- .../guardrails/add_guardrail_form.tsx | 188 ++++++++++-------- ui/litellm-dashboard/src/locales/en.json | 65 ++++++ ui/litellm-dashboard/src/locales/zh-CN.json | 67 ++++++- 3 files changed, 231 insertions(+), 89 deletions(-) diff --git a/ui/litellm-dashboard/src/components/guardrails/add_guardrail_form.tsx b/ui/litellm-dashboard/src/components/guardrails/add_guardrail_form.tsx index 41a2dd7f67c..1aeb7f0c721 100644 --- a/ui/litellm-dashboard/src/components/guardrails/add_guardrail_form.tsx +++ b/ui/litellm-dashboard/src/components/guardrails/add_guardrail_form.tsx @@ -1,5 +1,7 @@ import { Form, Input, Modal, Select, Tag, Typography, Button } from "antd"; +import type { TFunction } from "i18next"; import React, { useEffect, useMemo, useState } from "react"; +import { Trans, useTranslation } from "react-i18next"; import NotificationsManager from "../molecules/notifications_manager"; import { createGuardrailCall, @@ -29,15 +31,14 @@ import ToolPermissionRulesEditor, { ToolPermissionConfig } from "./tool_permissi const { Title, Text, Link } = Typography; const { Option } = Select; -// Define human-friendly descriptions for each mode -const modeDescriptions = { - pre_call: "Before LLM Call - Runs before the LLM call and checks the input (Recommended)", - during_call: "During LLM Call - Runs in parallel with the LLM call, with response held until check completes", - post_call: "After LLM Call - Runs after the LLM call and checks only the output", - logging_only: "Logging Only - Only runs on logging callbacks without affecting the LLM call", - pre_mcp_call: "Before MCP Tool Call - Runs before MCP tool execution and validates tool calls", - during_mcp_call: "During MCP Tool Call - Runs in parallel with MCP tool execution for monitoring", -}; +const getModeDescriptions = (t: TFunction) => ({ + pre_call: t("guardrails.addGuardrailForm.modeDesc.pre_call"), + during_call: t("guardrails.addGuardrailForm.modeDesc.during_call"), + post_call: t("guardrails.addGuardrailForm.modeDesc.post_call"), + logging_only: t("guardrails.addGuardrailForm.modeDesc.logging_only"), + pre_mcp_call: t("guardrails.addGuardrailForm.modeDesc.pre_mcp_call"), + during_mcp_call: t("guardrails.addGuardrailForm.modeDesc.during_mcp_call"), +}); interface GuardrailPreset { provider: string; @@ -106,6 +107,8 @@ interface ProviderParamsResponse { } const AddGuardrailForm: React.FC = ({ visible, onClose, accessToken, onSuccess, preset }) => { + const { t } = useTranslation(); + const modeDescriptions = useMemo(() => getModeDescriptions(t), [t]); const [form] = Form.useForm(); const [loading, setLoading] = useState(false); const [selectedProvider, setSelectedProvider] = useState(null); @@ -175,7 +178,7 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a populateGuardrailProviderMap(providerParamsResp); } catch (error) { console.error("Error fetching guardrail data:", error); - NotificationsManager.fromBackend("Failed to load guardrail configuration"); + NotificationsManager.fromBackend(t("guardrails.addGuardrailForm.failedToLoadConfig")); } }; @@ -318,7 +321,7 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a // Validate configuration steps if (currentStep === 1) { if (shouldRenderPIIConfigSettings(selectedProvider) && selectedEntities.length === 0) { - NotificationsManager.fromBackend("Please select at least one PII entity to continue"); + NotificationsManager.fromBackend(t("guardrails.addGuardrailForm.selectAtLeastOnePii")); return; } } @@ -473,9 +476,7 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a selectedContentCategories.length === 0 && !hasCompetitorIntent ) { - NotificationsManager.fromBackend( - "Please configure at least one content filter setting (category, pattern, keyword, or competitor intent)", - ); + NotificationsManager.fromBackend(t("guardrails.addGuardrailForm.configureAtLeastOneFilter")); setLoading(false); return; } @@ -528,7 +529,7 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a // For some guardrails, the config values need to be in litellm_params guardrailData.guardrail_info = configObj; } catch (error) { - NotificationsManager.fromBackend("Invalid JSON in configuration"); + NotificationsManager.fromBackend(t("guardrails.addGuardrailForm.invalidJsonConfig")); setLoading(false); return; } @@ -537,13 +538,13 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a if (guardrailProvider === "llm_as_a_judge") { const criteria: any[] = values.criteria || []; if (criteria.length === 0) { - NotificationsManager.fromBackend("Add at least one evaluation criterion"); + NotificationsManager.fromBackend(t("guardrails.addGuardrailForm.addAtLeastOneCriterion")); setLoading(false); return; } const weightTotal = criteria.reduce((sum: number, c: any) => sum + (Number(c?.weight) || 0), 0); if (weightTotal !== 100) { - NotificationsManager.fromBackend(`Criterion weights must sum to 100% (currently ${weightTotal}%)`); + NotificationsManager.fromBackend(t("guardrails.addGuardrailForm.weightsMustSum100", { weightTotal })); setLoading(false); return; } @@ -559,7 +560,7 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a if (guardrailProvider === "tool_permission") { if (toolPermissionConfig.rules.length === 0) { - NotificationsManager.fromBackend("Add at least one tool permission rule"); + NotificationsManager.fromBackend(t("guardrails.addGuardrailForm.addAtLeastOneRule")); setLoading(false); return; } @@ -641,7 +642,7 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a console.log("Sending guardrail data:", JSON.stringify(guardrailData)); await createGuardrailCall(accessToken, guardrailData); - NotificationsManager.success("Guardrail created successfully"); + NotificationsManager.success(t("guardrails.addGuardrailForm.createSuccess")); // Reset form and close modal resetForm(); @@ -650,7 +651,9 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a } catch (error) { console.error("Failed to create guardrail:", error); NotificationsManager.fromBackend( - "Failed to create guardrail: " + (error instanceof Error ? error.message : String(error)), + t("guardrails.addGuardrailForm.createFailed", { + error: error instanceof Error ? error.message : String(error), + }), ); } finally { setLoading(false); @@ -662,19 +665,19 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a <> - + {guardrailSettings?.supported_modes?.map((mode) => ( @@ -745,7 +748,7 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a {mode} {mode === "pre_call" && ( - Recommended + {t("guardrails.addGuardrailForm.recommended")} )} @@ -759,7 +762,7 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a