diff --git a/ui/litellm-dashboard/src/components/guardrails/content_filter/KeywordModal.tsx b/ui/litellm-dashboard/src/components/guardrails/content_filter/KeywordModal.tsx index 56b721adda5..a84a5fa8954 100644 --- a/ui/litellm-dashboard/src/components/guardrails/content_filter/KeywordModal.tsx +++ b/ui/litellm-dashboard/src/components/guardrails/content_filter/KeywordModal.tsx @@ -1,5 +1,6 @@ import React from "react"; import { Typography, Select, Modal, Space, Button, Input } from "antd"; +import { useTranslation } from "react-i18next"; const { Text } = Typography; const { Option } = Select; @@ -27,13 +28,15 @@ const KeywordModal: React.FC = ({ onAdd, onCancel, }) => { + const { t } = useTranslation(); + return ( - +
- Keyword + {t("guardrails.keywordModal.keywordLabel")} onKeywordChange(e.target.value)} style={{ marginTop: 8 }} @@ -41,20 +44,20 @@ const KeywordModal: React.FC = ({
- Action + {t("guardrails.keywordModal.actionLabel")} - Choose what action the guardrail should take when this keyword is detected + {t("guardrails.keywordModal.actionDesc")}
- Description (optional) + {t("guardrails.keywordModal.descriptionLabel")} onDescriptionChange(e.target.value)} rows={3} @@ -64,9 +67,9 @@ const KeywordModal: React.FC = ({
- +
diff --git a/ui/litellm-dashboard/src/components/guardrails/content_filter/KeywordTable.tsx b/ui/litellm-dashboard/src/components/guardrails/content_filter/KeywordTable.tsx index 57e59423aa5..cb32e1cf35f 100644 --- a/ui/litellm-dashboard/src/components/guardrails/content_filter/KeywordTable.tsx +++ b/ui/litellm-dashboard/src/components/guardrails/content_filter/KeywordTable.tsx @@ -1,6 +1,7 @@ import { DeleteOutlined } from "@ant-design/icons"; import { Button, Select, Table, Typography } from "antd"; import React from "react"; +import { useTranslation } from "react-i18next"; const { Text } = Typography; const { Option } = Select; @@ -19,14 +20,16 @@ interface KeywordTableProps { } const KeywordTable: React.FC = ({ keywords, onActionChange, onRemove }) => { + const { t } = useTranslation(); + const columns = [ { - title: "Keyword", + title: t("guardrails.keywordTable.colKeyword"), dataIndex: "keyword", key: "keyword", }, { - title: "Action", + title: t("guardrails.keywordTable.colAction"), dataIndex: "action", key: "action", width: 150, @@ -37,13 +40,13 @@ const KeywordTable: React.FC = ({ keywords, onActionChange, o style={{ width: 120 }} size="small" > - - + + ), }, { - title: "Description", + title: t("guardrails.keywordTable.colDescription"), dataIndex: "description", key: "description", render: (desc: string) => desc || "-", @@ -54,14 +57,18 @@ const KeywordTable: React.FC = ({ keywords, onActionChange, o width: 100, render: (_: any, record: BlockedWord) => ( ), }, ]; if (keywords.length === 0) { - return
No keywords added.
; + return ( +
+ {t("guardrails.keywordTable.noKeywords")} +
+ ); } return ; diff --git a/ui/litellm-dashboard/src/components/guardrails/content_filter/PatternModal.tsx b/ui/litellm-dashboard/src/components/guardrails/content_filter/PatternModal.tsx index 32265fb3888..8eabc740402 100644 --- a/ui/litellm-dashboard/src/components/guardrails/content_filter/PatternModal.tsx +++ b/ui/litellm-dashboard/src/components/guardrails/content_filter/PatternModal.tsx @@ -1,5 +1,6 @@ import React from "react"; import { Typography, Select, Modal, Space, Button } from "antd"; +import { useTranslation } from "react-i18next"; const { Text } = Typography; const { Option } = Select; @@ -34,13 +35,15 @@ const PatternModal: React.FC = ({ onAdd, onCancel, }) => { + const { t } = useTranslation(); + return ( - +
- Pattern type + {t("guardrails.patternModal.patternTypeLabel")} - - + +
- +
diff --git a/ui/litellm-dashboard/src/components/guardrails/content_filter/PatternTable.tsx b/ui/litellm-dashboard/src/components/guardrails/content_filter/PatternTable.tsx index bf5b75b52fb..e6a067396b0 100644 --- a/ui/litellm-dashboard/src/components/guardrails/content_filter/PatternTable.tsx +++ b/ui/litellm-dashboard/src/components/guardrails/content_filter/PatternTable.tsx @@ -1,6 +1,7 @@ import React from "react"; import { Typography, Select, Table, Tag, Button } from "antd"; import { DeleteOutlined } from "@ant-design/icons"; +import { useTranslation } from "react-i18next"; const { Text } = Typography; const { Option } = Select; @@ -21,24 +22,28 @@ interface PatternTableProps { } const PatternTable: React.FC = ({ patterns, onActionChange, onRemove }) => { + const { t } = useTranslation(); + const columns = [ { - title: "Type", + title: t("guardrails.patternTable.colType"), dataIndex: "type", key: "type", width: 100, render: (type: string) => ( - {type === "prebuilt" ? "Prebuilt" : "Custom"} + + {type === "prebuilt" ? t("guardrails.patternTable.typePrebuilt") : t("guardrails.patternTable.typeCustom")} + ), }, { - title: "Pattern name", + title: t("guardrails.patternTable.colPatternName"), dataIndex: "name", key: "name", render: (_: string, record: Pattern) => record.display_name || record.name, }, { - title: "Regex pattern", + title: t("guardrails.patternTable.colRegexPattern"), dataIndex: "pattern", key: "pattern", render: (pattern: string) => @@ -51,7 +56,7 @@ const PatternTable: React.FC = ({ patterns, onActionChange, o ), }, { - title: "Action", + title: t("guardrails.patternTable.colAction"), dataIndex: "action", key: "action", width: 150, @@ -62,8 +67,8 @@ const PatternTable: React.FC = ({ patterns, onActionChange, o style={{ width: 120 }} size="small" > - - + + ), }, @@ -73,14 +78,18 @@ const PatternTable: React.FC = ({ patterns, onActionChange, o width: 100, render: (_: any, record: Pattern) => ( ), }, ]; if (patterns.length === 0) { - return
No patterns added.
; + return ( +
+ {t("guardrails.patternTable.noPatterns")} +
+ ); } return
; diff --git a/ui/litellm-dashboard/src/components/guardrails/custom_code/CustomCodeModal.tsx b/ui/litellm-dashboard/src/components/guardrails/custom_code/CustomCodeModal.tsx index b7881eaf8ad..097acfa4124 100644 --- a/ui/litellm-dashboard/src/components/guardrails/custom_code/CustomCodeModal.tsx +++ b/ui/litellm-dashboard/src/components/guardrails/custom_code/CustomCodeModal.tsx @@ -1,4 +1,4 @@ -import React, { useState, useRef, useEffect } from "react"; +import React, { useState, useRef, useEffect, useMemo } from "react"; import { Modal, Select, Switch, Collapse, Input, Divider } from "antd"; import { Button, TextInput } from "@tremor/react"; import { @@ -11,6 +11,8 @@ import { UsergroupAddOutlined, ExportOutlined, } from "@ant-design/icons"; +import { useTranslation } from "react-i18next"; +import type { TFunction } from "i18next"; import { createGuardrailCall, updateGuardrailCall, testCustomCodeGuardrail } from "../../networking"; import NotificationsManager from "../../molecules/notifications_manager"; @@ -93,47 +95,6 @@ const CODE_TEMPLATES = { }, }; -// Available primitives organized by category -const PRIMITIVES = { - "Return Values": [ - { name: "allow()", desc: "Let request/response through" }, - { name: "block(reason)", desc: "Reject with message" }, - { name: "modify(texts=[], images=[], tool_calls=[])", desc: "Transform content" }, - ], - "HTTP Requests (async)": [ - { name: "await http_request(url, method, headers, body)", desc: "Make async HTTP request" }, - { name: "await http_get(url, headers)", desc: "Async GET request" }, - { name: "await http_post(url, body, headers)", desc: "Async POST request" }, - ], - "Regex Functions": [ - { name: "regex_match(text, pattern)", desc: "Returns True if pattern found" }, - { name: "regex_replace(text, pattern, replacement)", desc: "Replace all matches" }, - { name: "regex_find_all(text, pattern)", desc: "Return list of matches" }, - ], - "JSON Functions": [ - { name: "json_parse(text)", desc: "Parse JSON string, returns None on error" }, - { name: "json_stringify(obj)", desc: "Convert to JSON string" }, - { name: "json_schema_valid(obj, schema)", desc: "Validate against JSON schema" }, - ], - "URL Functions": [ - { name: "extract_urls(text)", desc: "Extract all URLs from text" }, - { name: "is_valid_url(url)", desc: "Check if URL is valid" }, - { name: "all_urls_valid(text)", desc: "Check all URLs in text are valid" }, - ], - "Code Detection": [ - { name: "detect_code(text)", desc: "Returns True if code detected" }, - { name: "detect_code_languages(text)", desc: "Returns list of detected languages" }, - { name: 'contains_code_language(text, ["sql"])', desc: "Check for specific languages" }, - ], - "Text Utilities": [ - { name: "contains(text, substring)", desc: "Check if substring exists" }, - { name: "contains_any(text, [substr1, substr2])", desc: "Check if any substring exists" }, - { name: "word_count(text)", desc: "Count words" }, - { name: "char_count(text)", desc: "Count characters" }, - { name: "lower(text) / upper(text) / trim(text)", desc: "String transforms" }, - ], -}; - const MODE_OPTIONS = [ { value: "pre_call", label: "pre_call (Request)" }, { value: "post_call", label: "post_call (Response)" }, @@ -144,6 +105,49 @@ const MODE_OPTIONS = [ { value: "during_mcp_call", label: "during_mcp_call (During MCP Tool Call)" }, ]; +const getPrimitives = (t: TFunction) => ({ + "Return Values": [ + { name: "allow()", desc: t("guardrails.customCodeModal.primAllowDesc") }, + { name: "block(reason)", desc: t("guardrails.customCodeModal.primBlockDesc") }, + { name: "modify(texts=[], images=[], tool_calls=[])", desc: t("guardrails.customCodeModal.primModifyDesc") }, + ], + "HTTP Requests (async)": [ + { + name: "await http_request(url, method, headers, body)", + desc: t("guardrails.customCodeModal.primHttpRequestDesc"), + }, + { name: "await http_get(url, headers)", desc: t("guardrails.customCodeModal.primHttpGetDesc") }, + { name: "await http_post(url, body, headers)", desc: t("guardrails.customCodeModal.primHttpPostDesc") }, + ], + "Regex Functions": [ + { name: "regex_match(text, pattern)", desc: t("guardrails.customCodeModal.primRegexMatchDesc") }, + { name: "regex_replace(text, pattern, replacement)", desc: t("guardrails.customCodeModal.primRegexReplaceDesc") }, + { name: "regex_find_all(text, pattern)", desc: t("guardrails.customCodeModal.primRegexFindAllDesc") }, + ], + "JSON Functions": [ + { name: "json_parse(text)", desc: t("guardrails.customCodeModal.primJsonParseDesc") }, + { name: "json_stringify(obj)", desc: t("guardrails.customCodeModal.primJsonStringifyDesc") }, + { name: "json_schema_valid(obj, schema)", desc: t("guardrails.customCodeModal.primJsonSchemaValidDesc") }, + ], + "URL Functions": [ + { name: "extract_urls(text)", desc: t("guardrails.customCodeModal.primExtractUrlsDesc") }, + { name: "is_valid_url(url)", desc: t("guardrails.customCodeModal.primIsValidUrlDesc") }, + { name: "all_urls_valid(text)", desc: t("guardrails.customCodeModal.primAllUrlsValidDesc") }, + ], + "Code Detection": [ + { name: "detect_code(text)", desc: t("guardrails.customCodeModal.primDetectCodeDesc") }, + { name: "detect_code_languages(text)", desc: t("guardrails.customCodeModal.primDetectCodeLangsDesc") }, + { name: 'contains_code_language(text, ["sql"])', desc: t("guardrails.customCodeModal.primContainsCodeLangDesc") }, + ], + "Text Utilities": [ + { name: "contains(text, substring)", desc: t("guardrails.customCodeModal.primContainsDesc") }, + { name: "contains_any(text, [substr1, substr2])", desc: t("guardrails.customCodeModal.primContainsAnyDesc") }, + { name: "word_count(text)", desc: t("guardrails.customCodeModal.primWordCountDesc") }, + { name: "char_count(text)", desc: t("guardrails.customCodeModal.primCharCountDesc") }, + { name: "lower(text) / upper(text) / trim(text)", desc: t("guardrails.customCodeModal.primStringTransformsDesc") }, + ], +}); + // Data for editing an existing guardrail export interface EditGuardrailData { guardrail_id: string; @@ -166,7 +170,9 @@ interface CustomCodeModalProps { } const CustomCodeModal: React.FC = ({ visible, onClose, onSuccess, accessToken, editData }) => { + const { t } = useTranslation(); const isEditMode = !!editData; + const primitives = useMemo(() => getPrimitives(t), [t]); const [guardrailName, setGuardrailName] = useState(""); const [mode, setMode] = useState(["pre_call"]); const [defaultOn, setDefaultOn] = useState(false); @@ -338,15 +344,15 @@ const CustomCodeModal: React.FC = ({ visible, onClose, onS // Save guardrail (create or update) const handleSave = async () => { if (!guardrailName.trim()) { - NotificationsManager.fromBackend("Please enter a guardrail name"); + NotificationsManager.fromBackend(t("guardrails.customCodeModal.noGuardrailName")); return; } if (!code.trim()) { - NotificationsManager.fromBackend("Please enter custom code"); + NotificationsManager.fromBackend(t("guardrails.customCodeModal.noCustomCode")); return; } if (!accessToken) { - NotificationsManager.fromBackend("No access token available"); + NotificationsManager.fromBackend(t("guardrails.customCodeModal.noAccessToken")); return; } @@ -374,7 +380,7 @@ const CustomCodeModal: React.FC = ({ visible, onClose, onS } await updateGuardrailCall(accessToken, editData.guardrail_id, updateData); - NotificationsManager.success("Custom code guardrail updated successfully"); + NotificationsManager.success(t("guardrails.customCodeModal.updateSuccess")); } else { // Create new guardrail const guardrailData = { @@ -389,15 +395,17 @@ const CustomCodeModal: React.FC = ({ visible, onClose, onS }; await createGuardrailCall(accessToken, guardrailData); - NotificationsManager.success("Custom code guardrail created successfully"); + NotificationsManager.success(t("guardrails.customCodeModal.createSuccess")); } onSuccess(); onClose(); } catch (error) { console.error("Failed to save guardrail:", error); NotificationsManager.fromBackend( - `Failed to ${isEditMode ? "update" : "create"} guardrail: ` + - (error instanceof Error ? error.message : String(error)), + t("guardrails.customCodeModal.saveFailed", { + action: isEditMode ? "update" : "create", + error: error instanceof Error ? error.message : String(error), + }), ); } finally { setIsSaving(false); @@ -420,7 +428,7 @@ const CustomCodeModal: React.FC = ({ visible, onClose, onS try { parsedInput = JSON.parse(testInput); } catch (e) { - setTestResult({ error: "Invalid test input JSON" }); + setTestResult({ error: t("guardrails.customCodeModal.invalidTestJson") }); setIsTesting(false); return; } @@ -457,7 +465,7 @@ const CustomCodeModal: React.FC = ({ visible, onClose, onS error_type: response.error_type, }); } else { - setTestResult({ error: "Unknown error occurred" }); + setTestResult({ error: t("guardrails.customCodeModal.unknownError") }); } } catch (error) { console.error("Failed to test custom code:", error); @@ -485,19 +493,27 @@ const CustomCodeModal: React.FC = ({ visible, onClose, onS {/* Header */}

- {isEditMode ? "Edit Custom Guardrail" : "Create Custom Guardrail"} + {isEditMode ? t("guardrails.customCodeModal.editTitle") : t("guardrails.customCodeModal.createTitle")}

-

Define custom logic using Python-like syntax

+

{t("guardrails.customCodeModal.subtitle")}

{/* Top Controls */}
- - + +
- + = ({ visible, onClose, onS }} > - Browse Community templates + {t("guardrails.customCodeModal.browseCommunityTemplates")}
)} > - + {Object.entries(CODE_TEMPLATES).map(([key, template]) => ( {template.name} @@ -557,7 +575,7 @@ const CustomCodeModal: React.FC = ({ visible, onClose, onS
- Default On + {t("guardrails.customCodeModal.defaultOnLabel")}
@@ -567,8 +585,10 @@ const CustomCodeModal: React.FC = ({ visible, onClose, onS {/* Code Editor */}
- Python Logic - Restricted environment (no imports) + + {t("guardrails.customCodeModal.pythonLogicLabel")} + + {t("guardrails.customCodeModal.restrictedEnv")}
= ({ visible, onClose, onS header={ - Test Your Guardrail + {t("guardrails.customCodeModal.testPanelHeader")} } key="test" @@ -625,29 +645,33 @@ const CustomCodeModal: React.FC = ({ visible, onClose, onS
- +
- Load example: + + {t("guardrails.customCodeModal.loadExampleLabel")} +
@@ -686,7 +710,9 @@ const CustomCodeModal: React.FC = ({ visible, onClose, onS
{testResult && (
= ({ visible, onClose, onS ) : testResult.action === "allow" ? ( <> - Allowed + {t("guardrails.customCodeModal.testResultAllowed")} ) : testResult.action === "block" ? ( <> - Blocked: {testResult.reason} + {" "} + {t("guardrails.customCodeModal.testResultBlocked", { reason: testResult.reason })} ) : testResult.action === "modify" ? ( <> - Modified + {t("guardrails.customCodeModal.testResultModified")} {testResult.texts && testResult.texts.length > 0 && ( → {testResult.texts[0].substring(0, 50)} @@ -728,7 +755,10 @@ const CustomCodeModal: React.FC = ({ visible, onClose, onS ) : ( <> - {testResult.action || "Unknown"} + {" "} + {t("guardrails.customCodeModal.testResultUnknown", { + action: testResult.action || t("common.unknown"), + })} )}
@@ -744,8 +774,10 @@ const CustomCodeModal: React.FC = ({ visible, onClose, onS
-
Built a useful guardrail?
-
Share it with the community and help others build faster
+
+ {t("guardrails.customCodeModal.contributeBannerTitle")} +
+
{t("guardrails.customCodeModal.contributeBannerDesc")}
@@ -763,23 +795,25 @@ const CustomCodeModal: React.FC = ({ visible, onClose, onS
- Available Primitives + + {t("guardrails.customCodeModal.availablePrimitivesTitle")} +
-

Click to copy functions to clipboard

+

{t("guardrails.customCodeModal.availablePrimitivesDesc")}

- {Object.entries(PRIMITIVES).map(([category, primitives]) => ( + {Object.entries(primitives).map(([category, categoryPrimitives]) => ( {category}} key={category} className="bg-white mb-2 rounded-lg border border-gray-200" >
- {primitives.map((p) => ( + {categoryPrimitives.map((p) => (
diff --git a/ui/litellm-dashboard/src/components/guardrails/edit_guardrail_form.tsx b/ui/litellm-dashboard/src/components/guardrails/edit_guardrail_form.tsx index b5e233edfc8..2d5dff6464a 100644 --- a/ui/litellm-dashboard/src/components/guardrails/edit_guardrail_form.tsx +++ b/ui/litellm-dashboard/src/components/guardrails/edit_guardrail_form.tsx @@ -1,6 +1,7 @@ import React, { useState, useEffect } from "react"; import { Form, Typography, Select, Input, Switch, Modal } from "antd"; import { Button, TextInput } from "@tremor/react"; +import { useTranslation } from "react-i18next"; import { guardrail_provider_map, guardrailLogoMap, @@ -54,6 +55,7 @@ const EditGuardrailForm: React.FC = ({ fullLitellmParams, initialValues, }) => { + const { t } = useTranslation(); const [form] = Form.useForm(); const [loading, setLoading] = useState(false); const [selectedProvider, setSelectedProvider] = useState(initialValues?.provider || null); @@ -71,7 +73,7 @@ const EditGuardrailForm: React.FC = ({ setGuardrailSettings(data); } catch (error) { console.error("Error fetching guardrail settings:", error); - NotificationsManager.fromBackend("Failed to load guardrail settings"); + NotificationsManager.fromBackend(t("guardrails.editGuardrailForm.loadSettingsFailed")); } }; @@ -178,7 +180,7 @@ const EditGuardrailForm: React.FC = ({ guardrail_info = configObj; } } catch (error) { - NotificationsManager.fromBackend("Invalid JSON in configuration"); + NotificationsManager.fromBackend(t("guardrails.editGuardrailForm.invalidJsonConfig")); setLoading(false); return; } @@ -222,7 +224,7 @@ const EditGuardrailForm: React.FC = ({ throw new Error(errorData || "Failed to update guardrail"); } - NotificationsManager.success("Guardrail updated successfully"); + NotificationsManager.success(t("guardrails.editGuardrailForm.updateSuccess")); // Reset and close onSuccess(); @@ -230,7 +232,9 @@ const EditGuardrailForm: React.FC = ({ } catch (error) { console.error("Failed to update guardrail:", error); NotificationsManager.fromBackend( - "Failed to update guardrail: " + (error instanceof Error ? error.message : String(error)), + t("guardrails.editGuardrailForm.updateFailed", { + error: error instanceof Error ? error.message : String(error), + }), ); } finally { setLoading(false); @@ -264,7 +268,11 @@ const EditGuardrailForm: React.FC = ({ switch (selectedProvider) { case "Aporia": return ( - + = ({ ); case "AimSecurity": return ( - + = ({ case "Bedrock": return ( = ({ ); case "CatoNetworks": return ( - + = ({ ); case "GuardrailsAI": return ( - + = ({ ); case "LakeraAI": return ( - + = ({ case "PromptInjection": return ( = ({ ); default: return ( - + = ({ }; return ( - +
- + {guardrailSettings?.supported_modes?.map((mode) => ( @@ -435,8 +469,8 @@ const EditGuardrailForm: React.FC = ({ @@ -444,25 +478,25 @@ const EditGuardrailForm: React.FC = ({ @@ -470,10 +504,10 @@ const EditGuardrailForm: React.FC = ({
diff --git a/ui/litellm-dashboard/src/locales/en.json b/ui/litellm-dashboard/src/locales/en.json index 0b7747a7673..d2e5c81acfc 100644 --- a/ui/litellm-dashboard/src/locales/en.json +++ b/ui/litellm-dashboard/src/locales/en.json @@ -2714,6 +2714,154 @@ "actionHelp": "Choose what action the guardrail should take when this pattern is detected", "actionBlock": "Block", "actionMask": "Mask" + }, + "keywordModal": { + "title": "Add blocked keyword", + "keywordLabel": "Keyword", + "keywordPlaceholder": "Enter sensitive keyword or phrase", + "actionLabel": "Action", + "actionDesc": "Choose what action the guardrail should take when this keyword is detected", + "actionBlock": "Block", + "actionMask": "Mask", + "descriptionLabel": "Description (optional)", + "descriptionPlaceholder": "Explain why this keyword is sensitive" + }, + "keywordTable": { + "colKeyword": "Keyword", + "colAction": "Action", + "colDescription": "Description", + "actionBlock": "Block", + "actionMask": "Mask", + "noKeywords": "No keywords added." + }, + "patternModal": { + "title": "Add prebuilt pattern", + "patternTypeLabel": "Pattern type", + "patternTypePlaceholder": "Choose pattern type", + "actionLabel": "Action", + "actionDesc": "Choose what action the guardrail should take when this pattern is detected", + "actionBlock": "Block", + "actionMask": "Mask" + }, + "patternTable": { + "colType": "Type", + "colPatternName": "Pattern name", + "colRegexPattern": "Regex pattern", + "colAction": "Action", + "typePrebuilt": "Prebuilt", + "typeCustom": "Custom", + "actionBlock": "Block", + "actionMask": "Mask", + "noPatterns": "No patterns added." + }, + "customCodeModal": { + "editTitle": "Edit Custom Guardrail", + "createTitle": "Create Custom Guardrail", + "subtitle": "Define custom logic using Python-like syntax", + "guardrailNameLabel": "Guardrail Name", + "guardrailNamePlaceholder": "e.g., block-pii-custom", + "modeLabel": "Mode (can select multiple)", + "modePlaceholder": "Select modes", + "templateLabel": "Template", + "templateGroupStandard": "STANDARD", + "browseCommunityTemplates": "Browse Community templates", + "defaultOnLabel": "Default On", + "pythonLogicLabel": "Python Logic", + "restrictedEnv": "Restricted environment (no imports)", + "testPanelHeader": "Test Your Guardrail", + "testInputLabel": "Test Input (JSON)", + "loadExampleLabel": "Load example:", + "examplePreCall": "Pre-call", + "examplePreMcp": "Pre MCP", + "examplePostCall": "Post-call", + "runTestButton": "Run Test", + "runningButton": "Running...", + "testResultAllowed": "Allowed", + "testResultBlocked": "Blocked: {{reason}}", + "testResultModified": "Modified", + "testResultUnknown": "{{action}}", + "contributeBannerTitle": "Built a useful guardrail?", + "contributeBannerDesc": "Share it with the community and help others build faster", + "contributeButton": "Contribute Template", + "availablePrimitivesTitle": "Available Primitives", + "availablePrimitivesDesc": "Click to copy functions to clipboard", + "copied": "Copied!", + "autoSaveNotice": "Changes are auto-saved to local draft", + "updateButton": "Update Guardrail", + "saveButton": "Save Guardrail", + "noGuardrailName": "Please enter a guardrail name", + "noCustomCode": "Please enter custom code", + "noAccessToken": "No access token available", + "updateSuccess": "Custom code guardrail updated successfully", + "createSuccess": "Custom code guardrail created successfully", + "saveFailed": "Failed to {{action}} guardrail: {{error}}", + "invalidTestJson": "Invalid test input JSON", + "unknownError": "Unknown error occurred", + "primAllowDesc": "Let request/response through", + "primBlockDesc": "Reject with message", + "primModifyDesc": "Transform content", + "primHttpRequestDesc": "Make async HTTP request", + "primHttpGetDesc": "Async GET request", + "primHttpPostDesc": "Async POST request", + "primRegexMatchDesc": "Returns True if pattern found", + "primRegexReplaceDesc": "Replace all matches", + "primRegexFindAllDesc": "Return list of matches", + "primJsonParseDesc": "Parse JSON string, returns None on error", + "primJsonStringifyDesc": "Convert to JSON string", + "primJsonSchemaValidDesc": "Validate against JSON schema", + "primExtractUrlsDesc": "Extract all URLs from text", + "primIsValidUrlDesc": "Check if URL is valid", + "primAllUrlsValidDesc": "Check all URLs in text are valid", + "primDetectCodeDesc": "Returns True if code detected", + "primDetectCodeLangsDesc": "Returns list of detected languages", + "primContainsCodeLangDesc": "Check for specific languages", + "primContainsDesc": "Check if substring exists", + "primContainsAnyDesc": "Check if any substring exists", + "primWordCountDesc": "Count words", + "primCharCountDesc": "Count characters", + "primStringTransformsDesc": "String transforms" + }, + "editGuardrailForm": { + "modalTitle": "Edit Guardrail", + "guardrailNameLabel": "Guardrail Name", + "guardrailNameRequired": "Please enter a guardrail name", + "guardrailNamePlaceholder": "Enter a name for this guardrail", + "providerLabel": "Guardrail Provider", + "providerRequired": "Please select a provider", + "providerPlaceholder": "Select a guardrail provider", + "modeLabel": "Mode", + "modeTooltip": "How the guardrail should be applied", + "modeRequired": "Please select a mode", + "alwaysOnLabel": "Always On", + "alwaysOnTooltip": "If enabled, this guardrail will be applied to all requests by default", + "skipSystemMsgLabel": "Skip system messages in guardrail", + "skipSystemMsgTooltip": "Unified guardrails only: whether role: system content is omitted from guardrail input (LLM still receives full messages). Use global default follows litellm_settings.skip_system_message_in_guardrail.", + "skipToolMsgLabel": "Skip tool messages in guardrail", + "skipToolMsgTooltip": "Unified guardrails only: whether role: tool content is omitted from guardrail input (LLM still receives full messages). Use global default follows litellm_settings.skip_tool_message_in_guardrail.", + "useGlobalDefault": "Use global default", + "yesExcludeFromScan": "Yes — exclude from guardrail scan", + "noAlwaysInclude": "No — always include in scan", + "updateButton": "Update Guardrail", + "aporiaConfigLabel": "Aporia Configuration", + "aporiaConfigTooltip": "JSON configuration for Aporia", + "aimConfigLabel": "Aim Security Configuration", + "aimConfigTooltip": "JSON configuration for Aim Security", + "bedrockConfigLabel": "Amazon Bedrock Configuration", + "bedrockConfigTooltip": "JSON configuration for Amazon Bedrock guardrails", + "catoConfigLabel": "Cato Networks Configuration", + "catoConfigTooltip": "JSON configuration for Cato Networks", + "guardrailsAiConfigLabel": "Guardrails.ai Configuration", + "guardrailsAiConfigTooltip": "JSON configuration for Guardrails.ai", + "lakeraConfigLabel": "Lakera AI Configuration", + "lakeraConfigTooltip": "JSON configuration for Lakera AI", + "promptInjectionConfigLabel": "Prompt Injection Configuration", + "promptInjectionConfigTooltip": "JSON configuration for prompt injection detection", + "customConfigLabel": "Custom Configuration", + "customConfigTooltip": "JSON configuration for your custom guardrail", + "updateSuccess": "Guardrail updated successfully", + "invalidJsonConfig": "Invalid JSON in configuration", + "loadSettingsFailed": "Failed to load guardrail settings", + "updateFailed": "Failed to update guardrail: {{error}}" } } } diff --git a/ui/litellm-dashboard/src/locales/zh-CN.json b/ui/litellm-dashboard/src/locales/zh-CN.json index df6776f9398..2c2ed69f192 100644 --- a/ui/litellm-dashboard/src/locales/zh-CN.json +++ b/ui/litellm-dashboard/src/locales/zh-CN.json @@ -2714,6 +2714,154 @@ "actionHelp": "选择当检测到此模式时护栏应执行的操作", "actionBlock": "拦截", "actionMask": "遮蔽" + }, + "keywordModal": { + "title": "添加屏蔽关键词", + "keywordLabel": "关键词", + "keywordPlaceholder": "输入敏感关键词或短语", + "actionLabel": "操作", + "actionDesc": "选择当检测到此关键词时护栏应执行的操作", + "actionBlock": "拦截", + "actionMask": "遮蔽", + "descriptionLabel": "描述(可选)", + "descriptionPlaceholder": "说明为何该关键词属于敏感内容" + }, + "keywordTable": { + "colKeyword": "关键词", + "colAction": "操作", + "colDescription": "描述", + "actionBlock": "拦截", + "actionMask": "遮蔽", + "noKeywords": "暂无关键词。" + }, + "patternModal": { + "title": "添加预置模式", + "patternTypeLabel": "模式类型", + "patternTypePlaceholder": "选择模式类型", + "actionLabel": "操作", + "actionDesc": "选择当检测到此模式时护栏应执行的操作", + "actionBlock": "拦截", + "actionMask": "遮蔽" + }, + "patternTable": { + "colType": "类型", + "colPatternName": "模式名称", + "colRegexPattern": "正则表达式", + "colAction": "操作", + "typePrebuilt": "预置", + "typeCustom": "自定义", + "actionBlock": "拦截", + "actionMask": "遮蔽", + "noPatterns": "暂无模式。" + }, + "customCodeModal": { + "editTitle": "编辑自定义护栏", + "createTitle": "创建自定义护栏", + "subtitle": "使用类 Python 语法定义自定义逻辑", + "guardrailNameLabel": "护栏名称", + "guardrailNamePlaceholder": "例如:block-pii-custom", + "modeLabel": "模式(可多选)", + "modePlaceholder": "选择模式", + "templateLabel": "模板", + "templateGroupStandard": "标准", + "browseCommunityTemplates": "浏览社区模板", + "defaultOnLabel": "默认开启", + "pythonLogicLabel": "Python 逻辑", + "restrictedEnv": "受限环境(不可导入模块)", + "testPanelHeader": "测试护栏", + "testInputLabel": "测试输入(JSON)", + "loadExampleLabel": "加载示例:", + "examplePreCall": "Pre-call", + "examplePreMcp": "Pre MCP", + "examplePostCall": "Post-call", + "runTestButton": "运行测试", + "runningButton": "运行中...", + "testResultAllowed": "已放行", + "testResultBlocked": "已拦截:{{reason}}", + "testResultModified": "已修改", + "testResultUnknown": "{{action}}", + "contributeBannerTitle": "构建了实用的护栏?", + "contributeBannerDesc": "分享给社区,帮助他人更快构建", + "contributeButton": "贡献模板", + "availablePrimitivesTitle": "可用原语", + "availablePrimitivesDesc": "点击将函数复制到剪贴板", + "copied": "已复制!", + "autoSaveNotice": "更改已自动保存为本地草稿", + "updateButton": "更新护栏", + "saveButton": "保存护栏", + "noGuardrailName": "请输入护栏名称", + "noCustomCode": "请输入自定义代码", + "noAccessToken": "无可用访问令牌", + "updateSuccess": "自定义代码护栏已成功更新", + "createSuccess": "自定义代码护栏已成功创建", + "saveFailed": "{{action}}护栏失败:{{error}}", + "invalidTestJson": "测试输入 JSON 格式无效", + "unknownError": "发生未知错误", + "primAllowDesc": "放行请求/响应", + "primBlockDesc": "拒绝并返回消息", + "primModifyDesc": "转换内容", + "primHttpRequestDesc": "发起异步 HTTP 请求", + "primHttpGetDesc": "异步 GET 请求", + "primHttpPostDesc": "异步 POST 请求", + "primRegexMatchDesc": "若找到匹配则返回 True", + "primRegexReplaceDesc": "替换所有匹配项", + "primRegexFindAllDesc": "返回所有匹配项列表", + "primJsonParseDesc": "解析 JSON 字符串,出错时返回 None", + "primJsonStringifyDesc": "转换为 JSON 字符串", + "primJsonSchemaValidDesc": "根据 JSON schema 验证", + "primExtractUrlsDesc": "从文本中提取所有 URL", + "primIsValidUrlDesc": "检查 URL 是否有效", + "primAllUrlsValidDesc": "检查文本中所有 URL 是否有效", + "primDetectCodeDesc": "若检测到代码则返回 True", + "primDetectCodeLangsDesc": "返回检测到的语言列表", + "primContainsCodeLangDesc": "检查特定语言", + "primContainsDesc": "检查子字符串是否存在", + "primContainsAnyDesc": "检查是否存在任意子字符串", + "primWordCountDesc": "统计单词数", + "primCharCountDesc": "统计字符数", + "primStringTransformsDesc": "字符串转换" + }, + "editGuardrailForm": { + "modalTitle": "编辑护栏", + "guardrailNameLabel": "护栏名称", + "guardrailNameRequired": "请输入护栏名称", + "guardrailNamePlaceholder": "为此护栏输入名称", + "providerLabel": "护栏提供商", + "providerRequired": "请选择提供商", + "providerPlaceholder": "选择护栏提供商", + "modeLabel": "模式", + "modeTooltip": "护栏的应用方式", + "modeRequired": "请选择模式", + "alwaysOnLabel": "始终开启", + "alwaysOnTooltip": "启用后,此护栏将默认应用于所有请求", + "skipSystemMsgLabel": "在护栏中跳过系统消息", + "skipSystemMsgTooltip": "仅统一护栏:是否从护栏输入中省略 role: system 内容(LLM 仍接收完整消息)。使用全局默认值遵循 litellm_settings.skip_system_message_in_guardrail。", + "skipToolMsgLabel": "在护栏中跳过工具消息", + "skipToolMsgTooltip": "仅统一护栏:是否从护栏输入中省略 role: tool 内容(LLM 仍接收完整消息)。使用全局默认值遵循 litellm_settings.skip_tool_message_in_guardrail。", + "useGlobalDefault": "使用全局默认值", + "yesExcludeFromScan": "是 — 从护栏扫描中排除", + "noAlwaysInclude": "否 — 始终包含在扫描中", + "updateButton": "更新护栏", + "aporiaConfigLabel": "Aporia 配置", + "aporiaConfigTooltip": "Aporia 的 JSON 配置", + "aimConfigLabel": "Aim Security 配置", + "aimConfigTooltip": "Aim Security 的 JSON 配置", + "bedrockConfigLabel": "Amazon Bedrock 配置", + "bedrockConfigTooltip": "Amazon Bedrock 护栏的 JSON 配置", + "catoConfigLabel": "Cato Networks 配置", + "catoConfigTooltip": "Cato Networks 的 JSON 配置", + "guardrailsAiConfigLabel": "Guardrails.ai 配置", + "guardrailsAiConfigTooltip": "Guardrails.ai 的 JSON 配置", + "lakeraConfigLabel": "Lakera AI 配置", + "lakeraConfigTooltip": "Lakera AI 的 JSON 配置", + "promptInjectionConfigLabel": "提示词注入配置", + "promptInjectionConfigTooltip": "提示词注入检测的 JSON 配置", + "customConfigLabel": "自定义配置", + "customConfigTooltip": "自定义护栏的 JSON 配置", + "updateSuccess": "护栏已成功更新", + "invalidJsonConfig": "配置中的 JSON 格式无效", + "loadSettingsFailed": "加载护栏设置失败", + "updateFailed": "更新护栏失败:{{error}}" } } }