From dc9c44f3b1e9172bc22b1f0b9a6eb7450fcb307b 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 18:31:29 +0900 Subject: [PATCH] feat(ui): i18n for guardrail params, table, LLM judge, and PII components --- .../guardrails/guardrail_optional_params.tsx | 30 ++++-- .../guardrails/guardrail_provider_fields.tsx | 14 ++- .../components/guardrails/guardrail_table.tsx | 39 ++++---- .../guardrails/llm_judge/LLMJudgeFields.tsx | 49 +++++----- .../components/guardrails/pii_components.tsx | 24 +++-- .../guardrails/pii_configuration.tsx | 8 +- .../ToolPermissionRulesEditor.tsx | 55 +++++------ ui/litellm-dashboard/src/locales/en.json | 94 +++++++++++++++++++ ui/litellm-dashboard/src/locales/zh-CN.json | 94 +++++++++++++++++++ 9 files changed, 316 insertions(+), 91 deletions(-) diff --git a/ui/litellm-dashboard/src/components/guardrails/guardrail_optional_params.tsx b/ui/litellm-dashboard/src/components/guardrails/guardrail_optional_params.tsx index 3b52d806a30..0c207eaee2f 100644 --- a/ui/litellm-dashboard/src/components/guardrails/guardrail_optional_params.tsx +++ b/ui/litellm-dashboard/src/components/guardrails/guardrail_optional_params.tsx @@ -1,5 +1,6 @@ import React from "react"; import { Form, Select, Typography, Input, Button } from "antd"; +import { useTranslation } from "react-i18next"; import NumericalInput from "../shared/numerical_input"; const { Title } = Typography; @@ -30,6 +31,7 @@ interface DictFieldProps { } const DictField: React.FC = ({ field, fieldKey, fullFieldKey, value }) => { + const { t } = useTranslation(); const [selectedEntries, setSelectedEntries] = React.useState>([]); const [availableKeys, setAvailableKeys] = React.useState(field.dict_key_options || []); @@ -87,19 +89,23 @@ const DictField: React.FC = ({ field, fieldKey, fullFieldKey, va } > {field.dict_value_type === "number" ? ( - + ) : field.dict_value_type === "boolean" ? ( - True False ) : ( - + )} ))} @@ -108,7 +114,7 @@ const DictField: React.FC = ({ field, fieldKey, fullFieldKey, va {availableKeys.length > 0 && (
- Select a category to add threshold configuration + {t("guardrails.guardrailOptionalParams.selectCategoryHint")}
)} @@ -131,6 +137,8 @@ const GuardrailOptionalParams: React.FC = ({ parentFieldKey, values, }) => { + const { t } = useTranslation(); + const renderField = (fieldKey: string, field: ProviderParam) => { const fullFieldKey = `${parentFieldKey}.${fieldKey}`; const value = values?.[fieldKey]; @@ -156,7 +164,11 @@ const GuardrailOptionalParams: React.FC = ({

{field.description}

} - rules={field.required ? [{ required: true, message: `${fieldKey} is required` }] : undefined} + rules={ + field.required + ? [{ required: true, message: t("guardrails.guardrailOptionalParams.fieldRequired", { fieldKey }) }] + : undefined + } className="mb-0" initialValue={value !== undefined ? value : field.default_value} normalize={ @@ -210,10 +222,10 @@ const GuardrailOptionalParams: React.FC = ({
- Optional Parameters + {t("guardrails.guardrailOptionalParams.title")}

- {optionalParams.description || "Configure additional settings for this guardrail provider"} + {optionalParams.description || t("guardrails.guardrailOptionalParams.defaultDescription")}

diff --git a/ui/litellm-dashboard/src/components/guardrails/guardrail_provider_fields.tsx b/ui/litellm-dashboard/src/components/guardrails/guardrail_provider_fields.tsx index 7967f56c460..688bf583682 100644 --- a/ui/litellm-dashboard/src/components/guardrails/guardrail_provider_fields.tsx +++ b/ui/litellm-dashboard/src/components/guardrails/guardrail_provider_fields.tsx @@ -1,5 +1,6 @@ import React, { useState, useEffect } from "react"; import { Form, Select, Spin, Input, Slider } from "antd"; +import { useTranslation } from "react-i18next"; import { guardrail_provider_map, populateGuardrailProviders, @@ -41,6 +42,7 @@ const GuardrailProviderFields: React.FC = ({ providerParams: providerParamsProp = null, value = null, }) => { + const { t } = useTranslation(); const [loading, setLoading] = useState(false); const [providerParams, setProviderParams] = useState(providerParamsProp); const [error, setError] = useState(null); @@ -69,7 +71,7 @@ const GuardrailProviderFields: React.FC = ({ populateGuardrailProviderMap(data); } catch (error) { console.error("Error fetching provider params:", error); - setError("Failed to load provider parameters"); + setError(t("guardrails.guardrailProviderFields.loadFailed")); } finally { setLoading(false); } @@ -88,7 +90,7 @@ const GuardrailProviderFields: React.FC = ({ // Show loading state if (loading) { - return ; + return ; } // Show error state @@ -106,7 +108,7 @@ const GuardrailProviderFields: React.FC = ({ console.log("Provider fields:", providerFields); if (!providerFields || Object.keys(providerFields).length === 0) { - return
No configuration fields available for this provider.
; + return
{t("guardrails.guardrailProviderFields.noFields")}
; } console.log("Value:", value); @@ -166,7 +168,11 @@ const GuardrailProviderFields: React.FC = ({ name={fullFieldKey} label={fieldKey} tooltip={field.description} - rules={field.required ? [{ required: true, message: `${fieldKey} is required` }] : undefined} + rules={ + field.required + ? [{ required: true, message: t("guardrails.guardrailProviderFields.fieldRequired", { fieldKey }) }] + : undefined + } initialValue={resolvedInitialValue} > {field.type === "select" && field.options ? ( diff --git a/ui/litellm-dashboard/src/components/guardrails/guardrail_table.tsx b/ui/litellm-dashboard/src/components/guardrails/guardrail_table.tsx index ecf6ce48fde..6b526710490 100644 --- a/ui/litellm-dashboard/src/components/guardrails/guardrail_table.tsx +++ b/ui/litellm-dashboard/src/components/guardrails/guardrail_table.tsx @@ -1,4 +1,5 @@ import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; import { Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow, Icon, Button } from "@tremor/react"; import { TrashIcon, SwitchVerticalIcon, ChevronUpIcon, ChevronDownIcon } from "@heroicons/react/outline"; import { Tooltip } from "antd"; @@ -39,6 +40,7 @@ const GuardrailTable: React.FC = ({ isAdmin = false, onGuardrailClick, }) => { + const { t } = useTranslation(); const [sorting, setSorting] = useState([{ id: "created_at", desc: true }]); const [editModalVisible, setEditModalVisible] = useState(false); const [selectedGuardrail, setSelectedGuardrail] = useState(null); @@ -63,7 +65,7 @@ const GuardrailTable: React.FC = ({ const columns: ColumnDef[] = [ { - header: "Guardrail ID", + header: t("guardrails.guardrailTable.colGuardrailId"), accessorKey: "guardrail_id", cell: (info: any) => ( @@ -79,7 +81,7 @@ const GuardrailTable: React.FC = ({ ), }, { - header: "Name", + header: t("guardrails.guardrailTable.colName"), accessorKey: "guardrail_name", cell: ({ row }) => { const guardrail = row.original; @@ -91,7 +93,7 @@ const GuardrailTable: React.FC = ({ }, }, { - header: "Provider", + header: t("guardrails.guardrailTable.colProvider"), accessorKey: "litellm_params.guardrail", cell: ({ row }) => { const guardrail = row.original; @@ -115,7 +117,7 @@ const GuardrailTable: React.FC = ({ }, }, { - header: "Mode", + header: t("guardrails.guardrailTable.colMode"), accessorKey: "litellm_params.mode", cell: ({ row }) => { const guardrail = row.original; @@ -123,7 +125,7 @@ const GuardrailTable: React.FC = ({ }, }, { - header: "Default On", + header: t("guardrails.guardrailTable.colDefaultOn"), accessorKey: "litellm_params.default_on", cell: ({ row }) => { const guardrail = row.original; @@ -133,13 +135,15 @@ const GuardrailTable: React.FC = ({ className="text-xs font-normal" size="xs" > - {guardrail.litellm_params?.default_on ? "Default On" : "Default Off"} + {guardrail.litellm_params?.default_on + ? t("guardrails.guardrailTable.defaultOn") + : t("guardrails.guardrailTable.defaultOff")} ); }, }, { - header: "Created At", + header: t("common.createdAt"), accessorKey: "created_at", cell: ({ row }) => { const guardrail = row.original; @@ -151,7 +155,7 @@ const GuardrailTable: React.FC = ({ }, }, { - header: "Updated At", + header: t("common.updatedAt"), accessorKey: "updated_at", cell: ({ row }) => { const guardrail = row.original; @@ -164,31 +168,34 @@ const GuardrailTable: React.FC = ({ }, { id: "actions", - header: "Actions", + header: t("common.actions"), cell: ({ row }) => { const guardrail = row.original; const isConfigGuardrail = guardrail.guardrail_definition_location === GuardrailDefinitionLocation.CONFIG; return (
{isConfigGuardrail ? ( - + ) : ( - + guardrail.guardrail_id && - onDeleteClick(guardrail.guardrail_id, guardrail.guardrail_name || "Unnamed Guardrail") + onDeleteClick( + guardrail.guardrail_id, + guardrail.guardrail_name || t("guardrails.guardrailTable.unnamedGuardrail"), + ) } className="cursor-pointer hover:text-red-500" /> @@ -254,7 +261,7 @@ const GuardrailTable: React.FC = ({
-

Loading...

+

{t("common.loading")}

@@ -279,7 +286,7 @@ const GuardrailTable: React.FC = ({
-

No guardrails found

+

{t("guardrails.guardrailTable.noGuardrails")}

diff --git a/ui/litellm-dashboard/src/components/guardrails/llm_judge/LLMJudgeFields.tsx b/ui/litellm-dashboard/src/components/guardrails/llm_judge/LLMJudgeFields.tsx index 1f8c644135f..827e760d972 100644 --- a/ui/litellm-dashboard/src/components/guardrails/llm_judge/LLMJudgeFields.tsx +++ b/ui/litellm-dashboard/src/components/guardrails/llm_judge/LLMJudgeFields.tsx @@ -4,6 +4,7 @@ import React from "react"; import { Form, Select, InputNumber, Input, Tooltip } from "antd"; import { PlusOutlined, QuestionCircleOutlined } from "@ant-design/icons"; import { Button } from "antd"; +import { useTranslation, Trans } from "react-i18next"; interface LLMJudgeFieldsProps { availableModels: string[]; @@ -11,6 +12,7 @@ interface LLMJudgeFieldsProps { } const LLMJudgeFields: React.FC = ({ availableModels, form }) => { + const { t } = useTranslation(); return ( <>
= ({ availableModels, form } color: "#389e0d", }} > - After each LLM response, the Judge Model scores it 0–100 against your criteria. If the weighted - average falls below the threshold, the response is blocked (or logged). + }} />
- Judge Model  - + {t("guardrails.lLMJudgeFields.judgeModelLabel")}  + } - rules={[{ required: true, message: "Select a judge model" }]} + rules={[{ required: true, message: t("guardrails.lLMJudgeFields.judgeModelRequired") }]} > - Block (return 422) - Log only + {t("guardrails.lLMJudgeFields.onFailureBlock")} + {t("guardrails.lLMJudgeFields.onFailureLog")} - Evaluation Criteria  - + {t("guardrails.lLMJudgeFields.criteriaLabel")}  + @@ -107,22 +108,23 @@ const LLMJudgeFields: React.FC = ({ availableModels, form } - + + - Weight + {t("guardrails.lLMJudgeFields.weightLabel")}{" "} + } - rules={[{ required: true, message: "Enter weight" }]} + rules={[{ required: true, message: t("guardrails.lLMJudgeFields.weightRequired") }]} style={{ flex: 1, marginBottom: 8 }} > @@ -136,10 +138,10 @@ const LLMJudgeFields: React.FC = ({ availableModels, form } - +
))} @@ -150,7 +152,7 @@ const LLMJudgeFields: React.FC = ({ availableModels, form } onClick={() => add({ name: "", weight: 0, description: "" })} icon={} > - Add Criterion + {t("guardrails.lLMJudgeFields.addCriterion")} {fields.length > 0 && ( @@ -160,7 +162,8 @@ const LLMJudgeFields: React.FC = ({ availableModels, form } const weightOk = weightTotal === 100; return (
- Weights total: {weightTotal}%{weightOk ? " ✓" : " — must add up to 100%"} + {t("guardrails.lLMJudgeFields.weightsTotal", { weightTotal })} + {weightOk ? " ✓" : ` — ${t("guardrails.lLMJudgeFields.weightsMustSum")}`}
); }} diff --git a/ui/litellm-dashboard/src/components/guardrails/pii_components.tsx b/ui/litellm-dashboard/src/components/guardrails/pii_components.tsx index 3365e866aa9..d2f397e2228 100644 --- a/ui/litellm-dashboard/src/components/guardrails/pii_components.tsx +++ b/ui/litellm-dashboard/src/components/guardrails/pii_components.tsx @@ -1,6 +1,7 @@ import React from "react"; import { Typography, Select, Button, Checkbox, Tooltip, Tag } from "antd"; import { CloseOutlined, EyeInvisibleOutlined, StopOutlined, FilterOutlined } from "@ant-design/icons"; +import { useTranslation } from "react-i18next"; import { PiiEntityCategory } from "./types"; const { Text } = Typography; @@ -30,15 +31,16 @@ export interface CategoryFilterProps { } export const CategoryFilter: React.FC = ({ categories, selectedCategories, onChange }) => { + const { t } = useTranslation(); return (
- Filter by category + {t("guardrails.piiComponents.filterByCategory")}
= ({ v }) } > - + Add another constraint + {t("guardrails.toolPermissionRulesEditor.addConstraint")}
); @@ -175,11 +177,8 @@ const ToolPermissionRulesEditor: React.FC = ({ v
- LiteLLM Tool Permission Guardrail - - Provide regex patterns (e.g., ^mcp__github_.*$) for tool names or types and optionally constrain payload - fields. - + {t("guardrails.toolPermissionRulesEditor.title")} + {t("guardrails.toolPermissionRulesEditor.subtitle")}
{!disabled && ( )}
@@ -196,13 +195,15 @@ const ToolPermissionRulesEditor: React.FC = ({ v {config.rules.length === 0 ? ( - + ) : (
{config.rules.map((rule, index) => (
- Rule {index + 1} + + {t("guardrails.toolPermissionRulesEditor.ruleLabel", { index: index + 1 })} +
- Rule ID + {t("guardrails.toolPermissionRulesEditor.ruleId")} = ({ v />
- Tool Name (optional) + {t("guardrails.toolPermissionRulesEditor.toolName")} = ({ v
- Tool Type (optional) + {t("guardrails.toolPermissionRulesEditor.toolType")} = ({ v
- Decision + {t("guardrails.toolPermissionRulesEditor.decision")}
@@ -277,20 +278,20 @@ const ToolPermissionRulesEditor: React.FC = ({ v
- Default action + {t("guardrails.toolPermissionRulesEditor.defaultAction")}
- On disallowed action - + {t("guardrails.toolPermissionRulesEditor.onDisallowedAction")} + @@ -299,18 +300,18 @@ const ToolPermissionRulesEditor: React.FC = ({ v value={config.on_disallowed_action} onChange={(value) => updateConfig({ on_disallowed_action: value as ToolPermissionOnDisallowedAction })} > - Block - Rewrite + {t("guardrails.toolPermissionRulesEditor.block")} + {t("guardrails.toolPermissionRulesEditor.rewrite")}
- Violation message (optional) + {t("guardrails.toolPermissionRulesEditor.violationMessage")} updateConfig({ violation_message_template: e.target.value })} /> diff --git a/ui/litellm-dashboard/src/locales/en.json b/ui/litellm-dashboard/src/locales/en.json index 73210802593..80f6042ed28 100644 --- a/ui/litellm-dashboard/src/locales/en.json +++ b/ui/litellm-dashboard/src/locales/en.json @@ -1365,6 +1365,100 @@ "addAtLeastOneRule": "Add at least one tool permission rule", "createSuccess": "Guardrail created successfully", "createFailed": "Failed to create guardrail: {{error}}" + }, + "guardrailOptionalParams": { + "title": "Optional Parameters", + "defaultDescription": "Configure additional settings for this guardrail provider", + "enterValue": "Enter {{key}} value", + "selectValue": "Select {{key}} value", + "selectCategoryPlaceholder": "Select category to configure", + "selectCategoryHint": "Select a category to add threshold configuration", + "fieldRequired": "{{fieldKey}} is required" + }, + "guardrailProviderFields": { + "loadFailed": "Failed to load provider parameters", + "loadingTip": "Loading provider parameters...", + "noFields": "No configuration fields available for this provider.", + "fieldRequired": "{{fieldKey}} is required" + }, + "guardrailTable": { + "colGuardrailId": "Guardrail ID", + "colName": "Name", + "colProvider": "Provider", + "colMode": "Mode", + "colDefaultOn": "Default On", + "defaultOn": "Default On", + "defaultOff": "Default Off", + "deleteTooltip": "Delete guardrail", + "configDeleteTooltip": "Config guardrail cannot be deleted on the dashboard. Please delete it from the config file.", + "configDeleteAriaLabel": "Delete guardrail (config)", + "unnamedGuardrail": "Unnamed Guardrail", + "noGuardrails": "No guardrails found" + }, + "lLMJudgeFields": { + "description": "After each LLM response, the Judge Model scores it 0–100 against your criteria. If the weighted average falls below the threshold, the response is blocked (or logged).", + "judgeModelLabel": "Judge Model", + "judgeModelTooltip": "The LLM that reads each response and grades it. Pick a capable model — it never sees end-user data beyond what the LLM returned.", + "judgeModelRequired": "Select a judge model", + "judgeModelPlaceholder": "Select a model", + "minScoreLabel": "Minimum Score to Pass", + "minScoreTooltip": "0–100. If the weighted average of criterion scores falls below this, the guardrail triggers. 80 is a good default.", + "onFailureLabel": "On Failure", + "onFailureTooltip": "Block: return HTTP 422 when the score is too low. Log: record the result but let the response through.", + "onFailureBlock": "Block (return 422)", + "onFailureLog": "Log only", + "criteriaLabel": "Evaluation Criteria", + "criteriaTooltip": "Each criterion is something the judge checks. Weights must add up to 100%.", + "criterionNameRequired": "Enter criterion name", + "criterionNamePlaceholder": "Criterion name (e.g. Policy accuracy)", + "weightLabel": "Weight", + "weightTooltip": "How much this criterion counts toward the final score. All weights must add up to 100%.", + "weightRequired": "Enter weight", + "criterionDescRequired": "Describe what to check", + "criterionDescPlaceholder": "What should the judge check for this criterion?", + "addCriterion": "Add Criterion", + "weightsTotal": "Weights total: {{weightTotal}}%", + "weightsMustSum": "must add up to 100%" + }, + "piiComponents": { + "filterByCategory": "Filter by category", + "selectCategoriesPlaceholder": "Select categories to filter by", + "quickActions": "Quick Actions", + "quickActionsTooltip": "Apply action to all PII types at once", + "unselectAll": "Unselect All", + "selectAllMask": "Select All & Mask", + "selectAllBlock": "Select All & Block", + "piiTypeHeader": "PII Type", + "actionHeader": "Action", + "noMatch": "No PII types match your filter criteria" + }, + "piiConfiguration": { + "title": "Configure PII Protection", + "itemsSelected_one": "{{count}} item selected", + "itemsSelected_other": "{{count}} items selected" + }, + "toolPermissionRulesEditor": { + "title": "LiteLLM Tool Permission Guardrail", + "subtitle": "Provide regex patterns (e.g., ^mcp__github_.*$) for tool names or types and optionally constrain payload fields.", + "addRule": "Add Rule", + "noRules": "No tool rules added yet", + "ruleLabel": "Rule {{index}}", + "ruleId": "Rule ID", + "toolName": "Tool Name (optional)", + "toolType": "Tool Type (optional)", + "decision": "Decision", + "allow": "Allow", + "deny": "Deny", + "restrictArgs": "+ Restrict tool arguments (optional)", + "argConstraints": "Argument constraints (dot or array paths)", + "addConstraint": "+ Add another constraint", + "defaultAction": "Default action", + "onDisallowedAction": "On disallowed action", + "onDisallowedTooltip": "Block returns an error when a forbidden tool is invoked. Rewrite strips the tool call but lets the rest of the response continue.", + "block": "Block", + "rewrite": "Rewrite", + "violationMessage": "Violation message (optional)", + "violationMessagePlaceholder": "This violates our org policy..." } }, "keyValueInput": { diff --git a/ui/litellm-dashboard/src/locales/zh-CN.json b/ui/litellm-dashboard/src/locales/zh-CN.json index 1bffd34b59c..b9cc777b0ff 100644 --- a/ui/litellm-dashboard/src/locales/zh-CN.json +++ b/ui/litellm-dashboard/src/locales/zh-CN.json @@ -1365,6 +1365,100 @@ "addAtLeastOneRule": "请至少添加一条工具权限规则", "createSuccess": "护栏创建成功", "createFailed": "创建护栏失败:{{error}}" + }, + "guardrailOptionalParams": { + "title": "可选参数", + "defaultDescription": "为此护栏提供商配置附加设置", + "enterValue": "输入 {{key}} 的值", + "selectValue": "选择 {{key}} 的值", + "selectCategoryPlaceholder": "选择要配置的类别", + "selectCategoryHint": "选择类别以添加阈值配置", + "fieldRequired": "{{fieldKey}} 为必填项" + }, + "guardrailProviderFields": { + "loadFailed": "加载提供商参数失败", + "loadingTip": "正在加载提供商参数...", + "noFields": "此提供商暂无可配置字段。", + "fieldRequired": "{{fieldKey}} 为必填项" + }, + "guardrailTable": { + "colGuardrailId": "护栏 ID", + "colName": "名称", + "colProvider": "提供商", + "colMode": "模式", + "colDefaultOn": "默认启用", + "defaultOn": "默认启用", + "defaultOff": "默认关闭", + "deleteTooltip": "删除护栏", + "configDeleteTooltip": "配置文件中的护栏无法在仪表盘上删除,请从配置文件中删除。", + "configDeleteAriaLabel": "删除护栏(配置文件)", + "unnamedGuardrail": "未命名护栏", + "noGuardrails": "未找到护栏" + }, + "lLMJudgeFields": { + "description": "每次 LLM 响应后,Judge Model 会根据您的标准对其评分(0–100)。若加权平均分低于阈值,响应将被拦截(或记录)。", + "judgeModelLabel": "Judge Model", + "judgeModelTooltip": "读取每条响应并评分的 LLM。请选择能力较强的模型——它仅能看到 LLM 返回的内容,不会接触最终用户数据。", + "judgeModelRequired": "请选择 Judge Model", + "judgeModelPlaceholder": "选择模型", + "minScoreLabel": "最低通过分数", + "minScoreTooltip": "0–100。若标准分数的加权平均值低于此值,护栏将触发。建议默认值为 80。", + "onFailureLabel": "失败时的处理", + "onFailureTooltip": "拦截:分数过低时返回 HTTP 422。仅记录:记录结果但允许响应通过。", + "onFailureBlock": "拦截(返回 422)", + "onFailureLog": "仅记录", + "criteriaLabel": "评估标准", + "criteriaTooltip": "每个标准是 Judge 需要检查的一项内容,权重之和必须为 100%。", + "criterionNameRequired": "请输入标准名称", + "criterionNamePlaceholder": "标准名称(例如:策略准确性)", + "weightLabel": "权重", + "weightTooltip": "此标准在最终分数中所占的比重,所有权重之和必须为 100%。", + "weightRequired": "请输入权重", + "criterionDescRequired": "请描述要检查的内容", + "criterionDescPlaceholder": "Judge 应针对此标准检查什么?", + "addCriterion": "添加标准", + "weightsTotal": "权重合计:{{weightTotal}}%", + "weightsMustSum": "必须合计为 100%" + }, + "piiComponents": { + "filterByCategory": "按类别筛选", + "selectCategoriesPlaceholder": "选择要筛选的类别", + "quickActions": "快速操作", + "quickActionsTooltip": "一次性对所有 PII 类型应用操作", + "unselectAll": "取消全选", + "selectAllMask": "全选并脱敏", + "selectAllBlock": "全选并拦截", + "piiTypeHeader": "PII 类型", + "actionHeader": "操作", + "noMatch": "没有 PII 类型匹配您的筛选条件" + }, + "piiConfiguration": { + "title": "配置 PII 保护", + "itemsSelected_one": "已选择 {{count}} 项", + "itemsSelected_other": "已选择 {{count}} 项" + }, + "toolPermissionRulesEditor": { + "title": "LiteLLM 工具权限护栏", + "subtitle": "为工具名称或类型提供正则表达式模式(例如 ^mcp__github_.*$),并可选择性地约束载荷字段。", + "addRule": "添加规则", + "noRules": "尚未添加工具规则", + "ruleLabel": "规则 {{index}}", + "ruleId": "规则 ID", + "toolName": "工具名称(可选)", + "toolType": "工具类型(可选)", + "decision": "决策", + "allow": "允许", + "deny": "拒绝", + "restrictArgs": "+ 限制工具参数(可选)", + "argConstraints": "参数约束(点路径或数组路径)", + "addConstraint": "+ 添加另一个约束", + "defaultAction": "默认动作", + "onDisallowedAction": "禁止时的处理", + "onDisallowedTooltip": "拦截:调用被禁止工具时返回错误。改写:去除工具调用但允许响应的其余部分继续。", + "block": "拦截", + "rewrite": "改写", + "violationMessage": "违规消息(可选)", + "violationMessagePlaceholder": "这违反了我们的组织策略..." } }, "keyValueInput": {