From 13276aea0afe61800981ae917767d660ebccbd6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B9=E9=9B=AA?= <2b@yorha.xyz> Date: Thu, 11 Jun 2026 00:24:12 +0900 Subject: [PATCH] feat(ui): i18n for policies batch 5 --- .../src/components/policies/policy_info.tsx | 51 ++++++----- .../src/components/policies/policy_table.tsx | 35 +++---- .../components/policies/policy_templates.tsx | 37 ++++---- .../components/policies/policy_test_panel.tsx | 61 +++++++------ .../policies/template_parameter_modal.tsx | 53 ++++++----- ui/litellm-dashboard/src/locales/en.json | 91 +++++++++++++++++++ ui/litellm-dashboard/src/locales/zh-CN.json | 91 +++++++++++++++++++ 7 files changed, 312 insertions(+), 107 deletions(-) diff --git a/ui/litellm-dashboard/src/components/policies/policy_info.tsx b/ui/litellm-dashboard/src/components/policies/policy_info.tsx index d3b53a4505d..0cb37604a2e 100644 --- a/ui/litellm-dashboard/src/components/policies/policy_info.tsx +++ b/ui/litellm-dashboard/src/components/policies/policy_info.tsx @@ -2,6 +2,7 @@ import React, { useState, useEffect, useCallback } from "react"; import { Card, Badge, Button } from "@tremor/react"; import { ArrowLeftIcon, PencilIcon } from "@heroicons/react/outline"; import { Descriptions, Tag, Spin, Divider, Typography, Alert } from "antd"; +import { useTranslation } from "react-i18next"; import { Policy } from "./types"; import { PipelineInfoDisplay } from "./pipeline_flow_builder"; import { getResolvedGuardrails } from "../networking"; @@ -25,6 +26,7 @@ const PolicyInfoView: React.FC = ({ isAdmin, getPolicy, }) => { + const { t } = useTranslation(); const [policy, setPolicy] = useState(null); const [isLoading, setIsLoading] = useState(true); const [resolvedGuardrails, setResolvedGuardrails] = useState([]); @@ -70,10 +72,10 @@ const PolicyInfoView: React.FC = ({ if (!policy) { return ( - Policy not found + {t("policies.policyInfo.notFound")}
); @@ -84,11 +86,11 @@ const PolicyInfoView: React.FC = ({
{isAdmin && ( )}
@@ -96,25 +98,25 @@ const PolicyInfoView: React.FC = ({ {policy.policy_name} - + {policy.policy_id} - - {policy.description || No description} + + {policy.description || {t("policies.policyInfo.noDescription")}} - + {policy.inherit ? ( {policy.inherit} ) : ( - None + {t("common.none")} )} - + {policy.created_at ? new Date(policy.created_at).toLocaleString() : "-"} - + {policy.updated_at ? new Date(policy.updated_at).toLocaleString() : "-"} @@ -122,10 +124,13 @@ const PolicyInfoView: React.FC = ({ {policy.pipeline && ( <> - Pipeline Flow + {t("policies.policyInfo.pipelineFlow")} = ({ )} - Guardrails Configuration + {t("policies.policyInfo.guardrailsConfiguration")} {resolvedGuardrails.length > 0 && ( - Final guardrails that will be applied (including inheritance): + {t("policies.policyInfo.resolvedGuardrailsDesc")}
{resolvedGuardrails.map((g) => ( @@ -162,7 +167,7 @@ const PolicyInfoView: React.FC = ({ )} - +
{policy.guardrails_add && policy.guardrails_add.length > 0 ? ( policy.guardrails_add.map((g) => ( @@ -171,11 +176,11 @@ const PolicyInfoView: React.FC = ({ )) ) : ( - None + {t("common.none")} )}
- +
{policy.guardrails_remove && policy.guardrails_remove.length > 0 ? ( policy.guardrails_remove.map((g) => ( @@ -184,18 +189,18 @@ const PolicyInfoView: React.FC = ({ )) ) : ( - None + {t("common.none")} )}
- Conditions + {t("policies.policyInfo.conditions")} - + {policy.condition?.model ? ( {typeof policy.condition.model === "string" @@ -203,7 +208,7 @@ const PolicyInfoView: React.FC = ({ : JSON.stringify(policy.condition.model)} ) : ( - No model condition (applies to all models) + {t("policies.policyInfo.noModelCondition")} )} diff --git a/ui/litellm-dashboard/src/components/policies/policy_table.tsx b/ui/litellm-dashboard/src/components/policies/policy_table.tsx index f7eee52847a..9f1103e5d92 100644 --- a/ui/litellm-dashboard/src/components/policies/policy_table.tsx +++ b/ui/litellm-dashboard/src/components/policies/policy_table.tsx @@ -2,6 +2,7 @@ import React, { useMemo, useState } from "react"; import { Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow, Icon, Button, Badge } from "@tremor/react"; import { TrashIcon, PencilIcon, SwitchVerticalIcon, ChevronUpIcon, ChevronDownIcon } from "@heroicons/react/outline"; import { Tooltip, Tag } from "antd"; +import { useTranslation } from "react-i18next"; import { ColumnDef, flexRender, @@ -55,6 +56,7 @@ const PolicyTable: React.FC = ({ onViewClick, isAdmin = false, }) => { + const { t } = useTranslation(); const [sorting, setSorting] = useState([{ id: "policy_name", desc: false }]); const rows = useMemo(() => groupPoliciesByName(policies), [policies]); @@ -67,14 +69,14 @@ const PolicyTable: React.FC = ({ const columns: ColumnDef[] = [ { - header: "Name", + header: t("common.name"), accessorKey: "policy_name", cell: ({ row }) => { const { primaryPolicy, versionCount } = row.original; return (
1 ? ` (${versionCount} versions)` : ""}`} + title={`${primaryPolicy.policy_name || "-"}${versionCount > 1 ? ` (${t("policies.policyTable.versionCount", { count: versionCount })})` : ""}`} >
@@ -95,7 +97,7 @@ const PolicyTable: React.FC = ({ }, }, { - header: "Description", + header: t("common.description"), accessorFn: (row) => row.primaryPolicy.description ?? "", cell: ({ row }) => { const policy = row.original.primaryPolicy; @@ -107,7 +109,7 @@ const PolicyTable: React.FC = ({ }, }, { - header: "Inherits From", + header: t("policies.policyTable.inheritsFrom"), accessorFn: (row) => row.primaryPolicy.inherit ?? "", cell: ({ row }) => { const policy = row.original.primaryPolicy; @@ -121,7 +123,7 @@ const PolicyTable: React.FC = ({ }, }, { - header: "Guardrails (Add)", + header: t("policies.policyTable.guardrailsAdd"), accessorFn: (row) => (row.primaryPolicy.guardrails_add ?? []).join(", "), cell: ({ row }) => { const policy = row.original.primaryPolicy; @@ -146,7 +148,7 @@ const PolicyTable: React.FC = ({ }, }, { - header: "Guardrails (Remove)", + header: t("policies.policyTable.guardrailsRemove"), accessorFn: (row) => (row.primaryPolicy.guardrails_remove ?? []).join(", "), cell: ({ row }) => { const policy = row.original.primaryPolicy; @@ -171,7 +173,7 @@ const PolicyTable: React.FC = ({ }, }, { - header: "Model Condition", + header: t("policies.policyTable.modelCondition"), accessorFn: (row) => { const m = row.primaryPolicy.condition?.model; return typeof m === "string" ? m : JSON.stringify(m ?? ""); @@ -189,14 +191,14 @@ const PolicyTable: React.FC = ({ ? modelCondition.length > 20 ? modelCondition.slice(0, 20) + "..." : modelCondition - : "Multiple"} + : t("policies.policyTable.multiple")} ); }, }, { - header: "Created At", + header: t("common.createdAt"), id: "created_at", accessorFn: (row) => row.primaryPolicy.created_at ?? "", cell: ({ row }) => { @@ -210,7 +212,7 @@ const PolicyTable: React.FC = ({ }, { id: "actions", - header: "Actions", + header: t("common.actions"), cell: ({ row }) => { const { primaryPolicy } = row.original; const policy = primaryPolicy; @@ -218,7 +220,7 @@ const PolicyTable: React.FC = ({
{isAdmin && ( <> - + = ({ className="cursor-pointer hover:text-blue-500" /> - + - policy.policy_id && onDeleteClick(policy.policy_id, policy.policy_name || "Unnamed Policy") + policy.policy_id && + onDeleteClick(policy.policy_id, policy.policy_name || t("policies.policyTable.unnamedPolicy")) } className="cursor-pointer hover:text-red-500" /> @@ -298,7 +301,7 @@ const PolicyTable: React.FC = ({
-

Loading...

+

{t("common.loading")}

@@ -323,7 +326,7 @@ const PolicyTable: React.FC = ({
-

No policies found

+

{t("policies.policyTable.noPoliciesFound")}

diff --git a/ui/litellm-dashboard/src/components/policies/policy_templates.tsx b/ui/litellm-dashboard/src/components/policies/policy_templates.tsx index 4043764394b..8ec97774754 100644 --- a/ui/litellm-dashboard/src/components/policies/policy_templates.tsx +++ b/ui/litellm-dashboard/src/components/policies/policy_templates.tsx @@ -1,5 +1,6 @@ import React, { useState, useEffect, useMemo } from "react"; import { Card, Button, Spin, Checkbox } from "antd"; +import { useTranslation } from "react-i18next"; import MessageManager from "@/components/molecules/message_manager"; import { ShieldCheckIcon, @@ -35,6 +36,8 @@ const PolicyTemplateCard: React.FC = ({ complexity, onUseTemplate, }) => { + const { t } = useTranslation(); + const getComplexityStyle = () => { switch (complexity) { case "Low": @@ -56,7 +59,7 @@ const PolicyTemplateCard: React.FC = ({
- {complexity} Complexity + {t("policies.policyTemplates.complexityLabel", { complexity })}
@@ -78,14 +81,14 @@ const PolicyTemplateCard: React.FC = ({ {inherits && (
- Inherits from: + {t("policies.policyTemplates.inheritsFrom")} {inherits}
)}
- Included Guardrails + {t("policies.policyTemplates.includedGuardrails")}
{guardrails.map((g) => ( @@ -100,7 +103,7 @@ const PolicyTemplateCard: React.FC = ({
); @@ -128,6 +131,7 @@ const PolicyTemplates: React.FC = ({ onTemplatesLoaded, accessToken, }) => { + const { t } = useTranslation(); const [templates, setTemplates] = useState([]); const [isLoading, setIsLoading] = useState(false); const [selectedTags, setSelectedTags] = useState>(new Set()); @@ -181,7 +185,7 @@ const PolicyTemplates: React.FC = ({ onTemplatesLoaded?.(data); } catch (error) { console.error("Error fetching policy templates:", error); - MessageManager.error("Failed to fetch policy templates"); + MessageManager.error(t("policies.policyTemplates.fetchFailed")); } finally { setIsLoading(false); } @@ -193,7 +197,7 @@ const PolicyTemplates: React.FC = ({ if (isLoading) { return (
- +
); } @@ -202,16 +206,14 @@ const PolicyTemplates: React.FC = ({
-

Policy Templates

-

- Start with a pre-configured policy template to quickly set up guardrails for your organization. -

+

{t("policies.policyTemplates.title")}

+

{t("policies.policyTemplates.subtitle")}

@@ -221,10 +223,10 @@ const PolicyTemplates: React.FC = ({
- Categories + {t("policies.policyTemplates.categories")} {selectedTags.size > 0 && ( )}
@@ -252,7 +254,10 @@ const PolicyTemplates: React.FC = ({
{selectedTags.size > 0 && (
- Showing {filteredTemplates.length} of {templates.length} templates + {t("policies.policyTemplates.showingCount", { + filtered: filteredTemplates.length, + total: templates.length, + })}
)}
@@ -275,9 +280,9 @@ const PolicyTemplates: React.FC = ({ {filteredTemplates.length === 0 && (
-

No templates match the selected filters.

+

{t("policies.policyTemplates.noTemplatesMatch")}

)} diff --git a/ui/litellm-dashboard/src/components/policies/policy_test_panel.tsx b/ui/litellm-dashboard/src/components/policies/policy_test_panel.tsx index 7e304bc3b0e..b949572eacb 100644 --- a/ui/litellm-dashboard/src/components/policies/policy_test_panel.tsx +++ b/ui/litellm-dashboard/src/components/policies/policy_test_panel.tsx @@ -1,6 +1,7 @@ import React, { useState, useEffect } from "react"; import { Form, Select, Alert, Tag, Empty, Typography } from "antd"; import { Button } from "@tremor/react"; +import { useTranslation } from "react-i18next"; import { resolvePoliciesCall, teamListCall, keyListCall, modelAvailableCall } from "../networking"; import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized"; @@ -22,6 +23,7 @@ interface ResolveResult { } const PolicyTestPanel: React.FC = ({ accessToken }) => { + const { t } = useTranslation(); const [form] = Form.useForm(); const [isLoading, setIsLoading] = useState(false); const [result, setResult] = useState(null); @@ -99,46 +101,43 @@ const PolicyTestPanel: React.FC = ({ accessToken }) => {
-

Policy Simulator

- - Simulate a request to see which policies and guardrails would apply. Select a team, key, model, or tags - below and click "Simulate" to see the results. - +

{t("policies.policyTestPanel.title")}

+ {t("policies.policyTestPanel.subtitle")}
- + ({ label: k, value: k }))} filterOption={(input, option) => (option?.label ?? "").toLowerCase().includes(input.toLowerCase())} /> - + = ({ accessToken }) => {
@@ -175,22 +174,19 @@ const PolicyTestPanel: React.FC = ({ accessToken }) => { />
-

No simulation run yet

-

- Fill in one or more fields above and click "Simulate" to see which policies and guardrails would - apply to that request. -

+

{t("policies.policyTestPanel.noSimulationYet")}

+

{t("policies.policyTestPanel.noSimulationHint")}

)} {hasSearched && result && (
{result.matched_policies.length === 0 ? ( - + ) : ( <>
-

Effective Guardrails

+

{t("policies.policyTestPanel.effectiveGuardrails")}

{result.effective_guardrails.length > 0 ? ( result.effective_guardrails.map((g) => ( @@ -199,19 +195,19 @@ const PolicyTestPanel: React.FC = ({ accessToken }) => { )) ) : ( - None + {t("common.none")} )}
-

Matched Policies

+

{t("policies.policyTestPanel.matchedPolicies")}

- - - + + + @@ -231,7 +227,7 @@ const PolicyTestPanel: React.FC = ({ accessToken }) => { ))} ) : ( - None + {t("common.none")} )} @@ -245,7 +241,12 @@ const PolicyTestPanel: React.FC = ({ accessToken }) => { )} {hasSearched && !result && !isLoading && ( - + )} ); diff --git a/ui/litellm-dashboard/src/components/policies/template_parameter_modal.tsx b/ui/litellm-dashboard/src/components/policies/template_parameter_modal.tsx index e62f12e0095..b3b064c43a3 100644 --- a/ui/litellm-dashboard/src/components/policies/template_parameter_modal.tsx +++ b/ui/litellm-dashboard/src/components/policies/template_parameter_modal.tsx @@ -1,6 +1,7 @@ import React, { useState, useEffect } from "react"; import { Modal, Spin, Radio, Select } from "antd"; import { Button, TextInput } from "@tremor/react"; +import { useTranslation } from "react-i18next"; import { modelHubCall, enrichPolicyTemplateStream } from "../networking"; interface TemplateParameter { @@ -31,6 +32,7 @@ const TemplateParameterModal: React.FC = ({ isLoading = false, accessToken, }) => { + const { t } = useTranslation(); const [parameterValues, setParameterValues] = useState>({}); const [competitorMode, setCompetitorMode] = useState<"ai" | "manual">("ai"); const [selectedModel, setSelectedModel] = useState(undefined); @@ -190,7 +192,7 @@ const TemplateParameterModal: React.FC = ({ title={

{template?.title}

-

Configure competitor blocking for your brand

+

{t("policies.templateParameterModal.subtitle")}

} open={visible} @@ -198,10 +200,12 @@ const TemplateParameterModal: React.FC = ({ width={700} footer={[ , , ]} > @@ -228,7 +232,9 @@ const TemplateParameterModal: React.FC = ({ {hasEnrichment && ( <>
- + setCompetitorMode(e.target.value)} @@ -236,10 +242,10 @@ const TemplateParameterModal: React.FC = ({ >
- ✨ Use AI + ✨ {t("policies.templateParameterModal.useAi")} - Enter Manually + {t("policies.templateParameterModal.enterManually")}
@@ -248,11 +254,11 @@ const TemplateParameterModal: React.FC = ({ {/* Brand Name */}
setParameterValues((prev) => ({ @@ -267,11 +273,11 @@ const TemplateParameterModal: React.FC = ({ <>
setCompetitorTags(values)} tokenSeparators={[","]} open={false} suffixIcon={null} /> -

Type a name and press Enter to add. Click ✕ to remove.

+

{t("policies.templateParameterModal.competitorNamesHint")}

{statusMessage && (
@@ -320,8 +328,9 @@ const TemplateParameterModal: React.FC = ({ )} {Object.keys(variationsMap).length > 0 && !statusMessage && (

- ✓ {Object.values(variationsMap).flat().length} alternate spellings & variations auto-generated for - guardrail matching + {t("policies.templateParameterModal.variationsGenerated", { + count: Object.values(variationsMap).flat().length, + })}

)}
@@ -329,10 +338,12 @@ const TemplateParameterModal: React.FC = ({ {/* Refinement input — shown after initial generation in AI mode */} {competitorMode === "ai" && hasGenerated && competitorTags.length > 0 && (
- +
setRefinementInput(e.target.value)} onKeyDown={(e) => { @@ -348,12 +359,10 @@ const TemplateParameterModal: React.FC = ({ disabled={!refinementInput.trim() || isRefining} size="xs" > - {isRefining ? "..." : "Send"} + {isRefining ? "..." : t("policies.templateParameterModal.send")}
-

- Give instructions to add, remove, or change competitors. Press Enter to send. -

+

{t("policies.templateParameterModal.refineHint")}

)} diff --git a/ui/litellm-dashboard/src/locales/en.json b/ui/litellm-dashboard/src/locales/en.json index 63fffecdffd..3b3f4305393 100644 --- a/ui/litellm-dashboard/src/locales/en.json +++ b/ui/litellm-dashboard/src/locales/en.json @@ -4978,6 +4978,97 @@ "updatePolicy": "Update Policy", "savePolicy": "Save Policy", "addDescriptionPlaceholder": "Add a description (optional)..." + }, + "policyInfo": { + "notFound": "Policy not found", + "backToPolicies": "Back to Policies", + "editPolicy": "Edit Policy", + "policyId": "Policy ID", + "noDescription": "No description", + "inheritsFrom": "Inherits From", + "pipelineFlow": "Pipeline Flow", + "pipelineInfo_one": "Pipeline ({{mode}} mode, {{count}} step)", + "pipelineInfo_other": "Pipeline ({{mode}} mode, {{count}} steps)", + "guardrailsConfiguration": "Guardrails Configuration", + "resolvedGuardrails": "Resolved Guardrails", + "resolvedGuardrailsDesc": "Final guardrails that will be applied (including inheritance):", + "guardrailsToAdd": "Guardrails to Add", + "guardrailsToRemove": "Guardrails to Remove", + "conditions": "Conditions", + "modelCondition": "Model Condition", + "noModelCondition": "No model condition (applies to all models)" + }, + "policyTable": { + "versionCount_one": "{{count}} version", + "versionCount_other": "{{count}} versions", + "inheritsFrom": "Inherits From", + "guardrailsAdd": "Guardrails (Add)", + "guardrailsRemove": "Guardrails (Remove)", + "modelCondition": "Model Condition", + "multiple": "Multiple", + "editPolicy": "Edit policy", + "deletePolicy": "Delete policy", + "unnamedPolicy": "Unnamed Policy", + "noPoliciesFound": "No policies found" + }, + "policyTemplates": { + "title": "Policy Templates", + "subtitle": "Start with a pre-configured policy template to quickly set up guardrails for your organization.", + "useAiToFind": "Use AI to find templates", + "categories": "Categories", + "showingCount": "Showing {{filtered}} of {{total}} templates", + "noTemplatesMatch": "No templates match the selected filters.", + "clearAllFilters": "Clear all filters", + "complexityLabel": "{{complexity}} Complexity", + "inheritsFrom": "Inherits from:", + "includedGuardrails": "Included Guardrails", + "useTemplate": "Use Template", + "loadingTemplates": "Loading policy templates...", + "fetchFailed": "Failed to fetch policy templates" + }, + "policyTestPanel": { + "title": "Policy Simulator", + "subtitle": "Simulate a request to see which policies and guardrails would apply. Select a team, key, model, or tags below and click \"Simulate\" to see the results.", + "teamAliasLabel": "Team Alias", + "teamAliasPlaceholder": "Select or type a team alias", + "keyAliasLabel": "Key Alias", + "keyAliasPlaceholder": "Select or type a key alias", + "modelLabel": "Model", + "modelPlaceholder": "Select or type a model", + "tagsLabel": "Tags", + "tagsPlaceholder": "Type a tag and press Enter", + "simulate": "Simulate", + "noSimulationYet": "No simulation run yet", + "noSimulationHint": "Fill in one or more fields above and click \"Simulate\" to see which policies and guardrails would apply to that request.", + "noPoliciesMatched": "No policies matched this context", + "effectiveGuardrails": "Effective Guardrails", + "matchedPolicies": "Matched Policies", + "colPolicy": "Policy", + "colMatchedVia": "Matched Via", + "colGuardrailsAdded": "Guardrails Added", + "resolveFailed": "Failed to resolve policies. Check the proxy logs." + }, + "templateParameterModal": { + "subtitle": "Configure competitor blocking for your brand", + "creatingGuardrails": "Creating guardrails...", + "continue": "Continue", + "competitorDiscovery": "Competitor Discovery", + "useAi": "Use AI", + "enterManually": "Enter Manually", + "brandName": "Your Brand Name", + "brandNamePlaceholder": "e.g. Acme Airlines", + "selectModel": "Select Model", + "selectModelPlaceholder": "Select a model to generate names", + "generatingNames": "Generating names...", + "generateCompetitorNames": "Generate Competitor Names", + "competitorNames": "Competitor Names", + "competitorNamesPlaceholder": "Type a name and press Enter to add", + "competitorNamesHint": "Type a name and press Enter to add. Click ✕ to remove.", + "variationsGenerated": "✓ {{count}} alternate spellings & variations auto-generated for guardrail matching", + "refineList": "Refine List", + "refinePlaceholder": "e.g. add 10 more from Asia, increase to 50 total...", + "send": "Send", + "refineHint": "Give instructions to add, remove, or change competitors. Press Enter to send." } } } diff --git a/ui/litellm-dashboard/src/locales/zh-CN.json b/ui/litellm-dashboard/src/locales/zh-CN.json index bc27ebe7172..0f4a12115de 100644 --- a/ui/litellm-dashboard/src/locales/zh-CN.json +++ b/ui/litellm-dashboard/src/locales/zh-CN.json @@ -4978,6 +4978,97 @@ "updatePolicy": "更新策略", "savePolicy": "保存策略", "addDescriptionPlaceholder": "添加描述(可选)..." + }, + "policyInfo": { + "notFound": "未找到策略", + "backToPolicies": "返回策略列表", + "editPolicy": "编辑策略", + "policyId": "策略 ID", + "noDescription": "无描述", + "inheritsFrom": "继承自", + "pipelineFlow": "流水线流程", + "pipelineInfo_one": "流水线({{mode}} 模式,{{count}} 个步骤)", + "pipelineInfo_other": "流水线({{mode}} 模式,{{count}} 个步骤)", + "guardrailsConfiguration": "护栏配置", + "resolvedGuardrails": "已解析护栏", + "resolvedGuardrailsDesc": "最终将应用的护栏(含继承):", + "guardrailsToAdd": "要添加的护栏", + "guardrailsToRemove": "要移除的护栏", + "conditions": "条件", + "modelCondition": "模型条件", + "noModelCondition": "无模型条件(应用于所有模型)" + }, + "policyTable": { + "versionCount_one": "{{count}} 个版本", + "versionCount_other": "{{count}} 个版本", + "inheritsFrom": "继承自", + "guardrailsAdd": "护栏(添加)", + "guardrailsRemove": "护栏(移除)", + "modelCondition": "模型条件", + "multiple": "多个", + "editPolicy": "编辑策略", + "deletePolicy": "删除策略", + "unnamedPolicy": "未命名策略", + "noPoliciesFound": "未找到策略" + }, + "policyTemplates": { + "title": "策略模板", + "subtitle": "从预配置的策略模板开始,快速为您的组织设置护栏。", + "useAiToFind": "使用 AI 查找模板", + "categories": "分类", + "showingCount": "显示 {{filtered}} / {{total}} 个模板", + "noTemplatesMatch": "没有模板匹配所选筛选条件。", + "clearAllFilters": "清除所有筛选", + "complexityLabel": "{{complexity}} 复杂度", + "inheritsFrom": "继承自:", + "includedGuardrails": "包含的护栏", + "useTemplate": "使用模板", + "loadingTemplates": "正在加载策略模板...", + "fetchFailed": "获取策略模板失败" + }, + "policyTestPanel": { + "title": "策略模拟器", + "subtitle": "模拟请求,查看哪些策略和护栏将被应用。在下方选择团队、密钥、模型或标签,然后点击「模拟」查看结果。", + "teamAliasLabel": "团队别名", + "teamAliasPlaceholder": "选择或输入团队别名", + "keyAliasLabel": "密钥别名", + "keyAliasPlaceholder": "选择或输入密钥别名", + "modelLabel": "模型", + "modelPlaceholder": "选择或输入模型", + "tagsLabel": "标签", + "tagsPlaceholder": "输入标签后按 Enter", + "simulate": "模拟", + "noSimulationYet": "尚未运行模拟", + "noSimulationHint": "在上方填写一个或多个字段,然后点击「模拟」,查看哪些策略和护栏将应用于该请求。", + "noPoliciesMatched": "没有策略匹配此上下文", + "effectiveGuardrails": "生效护栏", + "matchedPolicies": "已匹配策略", + "colPolicy": "策略", + "colMatchedVia": "匹配方式", + "colGuardrailsAdded": "已添加护栏", + "resolveFailed": "解析策略失败,请检查代理日志。" + }, + "templateParameterModal": { + "subtitle": "为您的品牌配置竞品屏蔽", + "creatingGuardrails": "正在创建护栏...", + "continue": "继续", + "competitorDiscovery": "竞品发现", + "useAi": "使用 AI", + "enterManually": "手动输入", + "brandName": "您的品牌名称", + "brandNamePlaceholder": "例如:Acme Airlines", + "selectModel": "选择模型", + "selectModelPlaceholder": "选择用于生成名称的模型", + "generatingNames": "正在生成名称...", + "generateCompetitorNames": "生成竞品名称", + "competitorNames": "竞品名称", + "competitorNamesPlaceholder": "输入名称后按 Enter 添加", + "competitorNamesHint": "输入名称后按 Enter 添加,点击 ✕ 删除。", + "variationsGenerated": "✓ 已为护栏匹配自动生成 {{count}} 个替代拼写及变体", + "refineList": "精炼列表", + "refinePlaceholder": "例如:再添加 10 个亚洲竞品,增加到 50 个...", + "send": "发送", + "refineHint": "给出添加、移除或修改竞品的指令,按 Enter 发送。" } } }
PolicyMatched ViaGuardrails Added{t("policies.policyTestPanel.colPolicy")}{t("policies.policyTestPanel.colMatchedVia")}{t("policies.policyTestPanel.colGuardrailsAdded")}