fix(ui): i18n audit repair round 2

This commit is contained in:
吹雪 2026-06-11 08:28:52 +09:00
parent 2ed0c0027b
commit de5de438bf
14 changed files with 122 additions and 70 deletions

View file

@ -226,7 +226,7 @@ const MakeModelPublicForm: React.FC<MakeModelPublicFormProps> = ({
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4">
<Text className="text-sm text-yellow-800">
<strong>Warning:</strong>{" "}
<strong>{t("common.warning")}:</strong>{" "}
<Trans i18nKey="aiHub.makeModelPublicForm.warningText" components={{ code: <code key="code" /> }} />
</Text>
</div>

View file

@ -180,7 +180,7 @@ export function AccessGroupDetail({ accessGroupId, onBack }: AccessGroupDetailPr
{accessGroup.access_group_name}
</Title>
<Text type="secondary">
ID: <Text copyable>{accessGroup.access_group_id}</Text>
{t("accessGroups.accessGroupsDetailsPage.idLabel")} <Text copyable>{accessGroup.access_group_id}</Text>
</Text>
</div>
</div>

View file

@ -91,7 +91,7 @@ export const MemoryEditModal: React.FC<MemoryEditModalProps> = ({ open, mode, in
>
<Input.TextArea
rows={4}
placeholder='{"tags": ["example"]}'
placeholder={t("memoryView.memoryEditModal.metadataPlaceholder")}
style={{ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" }}
/>
</Form.Item>

View file

@ -134,7 +134,7 @@ const DynamicForm: React.FC<DynamicFormProps> = ({
</TableCell>
<TableCell>
<Icon icon={TrashIcon} color="red" onClick={() => handleResetField(value.field_name, index)}>
Reset
{t("common.reset")}
</Icon>
</TableCell>
</TableRow>

View file

@ -290,7 +290,8 @@ const ContentCategoryConfiguration: React.FC<ContentCategoryConfigurationProps>
}}
>
<div style={{ marginBottom: 8, fontWeight: 500, fontSize: "14px" }}>
Preview: {availableCategories.find((c) => c.name === selectedCategoryName)?.display_name}
{t("guardrails.contentCategoryConfiguration.previewLabel")}:{" "}
{availableCategories.find((c) => c.name === selectedCategoryName)?.display_name}
{categoryFileTypes[selectedCategoryName] && (
<span style={{ marginLeft: 8, fontSize: "12px", color: "#888", fontWeight: 400 }}>
({categoryFileTypes[selectedCategoryName]?.toUpperCase()})

View file

@ -95,14 +95,14 @@ const CODE_TEMPLATES = {
},
};
const MODE_OPTIONS = [
{ value: "pre_call", label: "pre_call (Request)" },
{ value: "post_call", label: "post_call (Response)" },
{ value: "during_call", label: "during_call (Parallel)" },
const getModeOptions = (t: TFunction) => [
{ value: "pre_call", label: t("guardrails.customCodeModal.modePreCall") },
{ value: "post_call", label: t("guardrails.customCodeModal.modePostCall") },
{ value: "during_call", label: t("guardrails.customCodeModal.modeDuringCall") },
{ value: "logging_only", label: "logging_only" },
{ value: "pre_mcp_call", label: "pre_mcp_call (Before MCP Tool Call)" },
{ value: "post_mcp_call", label: "post_mcp_call (After MCP Tool Call)" },
{ value: "during_mcp_call", label: "during_mcp_call (During MCP Tool Call)" },
{ value: "pre_mcp_call", label: t("guardrails.customCodeModal.modePreMcpCall") },
{ value: "post_mcp_call", label: t("guardrails.customCodeModal.modePostMcpCall") },
{ value: "during_mcp_call", label: t("guardrails.customCodeModal.modeDuringMcpCall") },
];
const getPrimitives = (t: TFunction) => ({
@ -173,6 +173,7 @@ const CustomCodeModal: React.FC<CustomCodeModalProps> = ({ visible, onClose, onS
const { t } = useTranslation();
const isEditMode = !!editData;
const primitives = useMemo(() => getPrimitives(t), [t]);
const modeOptions = useMemo(() => getModeOptions(t), [t]);
const [guardrailName, setGuardrailName] = useState("");
const [mode, setMode] = useState<string[]>(["pre_call"]);
const [defaultOn, setDefaultOn] = useState(false);
@ -518,7 +519,7 @@ const CustomCodeModal: React.FC<CustomCodeModalProps> = ({ visible, onClose, onS
mode="multiple"
value={mode}
onChange={setMode}
options={MODE_OPTIONS}
options={modeOptions}
className="w-full"
size="middle"
placeholder={t("guardrails.customCodeModal.modePlaceholder")}
@ -678,25 +679,28 @@ const CustomCodeModal: React.FC<CustomCodeModalProps> = ({ visible, onClose, onS
<div className="mb-2 p-2 bg-gray-50 rounded text-xs text-gray-600 border border-gray-200">
<div className="grid grid-cols-2 gap-x-4 gap-y-1">
<div>
<strong>texts</strong>: Message content (always)
<strong>texts</strong>: {t("guardrails.customCodeModal.fieldTextsDesc")}
</div>
<div>
<strong>images</strong>: Base64 images (vision)
<strong>images</strong>: {t("guardrails.customCodeModal.fieldImagesDesc")}
</div>
<div>
<strong>tools</strong>: Tool definitions <span className="text-orange-600">(pre_call)</span>,
MCP as OpenAI tool <span className="text-purple-600">(pre_mcp_call)</span>
<strong>tools</strong>: {t("guardrails.customCodeModal.fieldToolsDesc")}{" "}
<span className="text-orange-600">(pre_call)</span>,{" "}
{t("guardrails.customCodeModal.fieldToolsMcpDesc")}{" "}
<span className="text-purple-600">(pre_mcp_call)</span>
</div>
<div>
<strong>tool_calls</strong>: LLM tool calls{" "}
<strong>tool_calls</strong>: {t("guardrails.customCodeModal.fieldToolCallsDesc")}{" "}
<span className="text-green-600">(post_call)</span>
</div>
<div>
<strong>structured_messages</strong>: Full messages{" "}
<strong>structured_messages</strong>:{" "}
{t("guardrails.customCodeModal.fieldStructuredMessagesDesc")}{" "}
<span className="text-orange-600">(pre_call)</span>
</div>
<div>
<strong>model</strong>: Model name (always)
<strong>model</strong>: {t("guardrails.customCodeModal.fieldModelDesc")}
</div>
</div>
</div>
@ -705,7 +709,7 @@ const CustomCodeModal: React.FC<CustomCodeModalProps> = ({ visible, onClose, onS
onChange={(e) => setTestInput(e.target.value)}
rows={8}
className="font-mono text-xs"
placeholder='{"texts": ["test message"], ...}'
placeholder={t("guardrails.customCodeModal.testInputPlaceholder")}
/>
</div>
<div className="flex items-center gap-3">

View file

@ -44,18 +44,7 @@ const StdioConfiguration: React.FC<StdioConfigurationProps> = ({ isVisible, requ
]}
>
<Input.TextArea
placeholder={`{
"mcpServers": {
"circleci-mcp-server": {
"command": "npx",
"args": ["-y", "@circleci/mcp-server-circleci"],
"env": {
"CIRCLECI_TOKEN": "your-circleci-token",
"CIRCLECI_BASE_URL": "https://circleci.com"
}
}
}
}`}
placeholder={t("mcpTools.stdioConfiguration.placeholder")}
rows={12}
className="rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500 font-mono text-sm"
/>

View file

@ -1255,7 +1255,7 @@ export default function ModelInfoView({
<Form.Item name="model_info" className="mb-0">
<Input.TextArea
rows={4}
placeholder='{"gpt-4": 100, "claude-v1": 200}'
placeholder={t("modelInfoView.placeholderModelInfo")}
defaultValue={JSON.stringify(modelData.model_info, null, 2)}
/>
</Form.Item>
@ -1283,14 +1283,7 @@ export default function ModelInfoView({
</Text>
{isEditing ? (
<Form.Item name="litellm_extra_params" rules={[{ validator: formItemValidateJSON }]}>
<Input.TextArea
rows={4}
placeholder='{
"rpm": 100,
"timeout": 0,
"stream_timeout": 0
}'
/>
<Input.TextArea rows={4} placeholder={t("modelInfoView.placeholderLitellmParams")} />
</Form.Item>
) : (
<div className="mt-1 p-2 bg-gray-50 rounded">

View file

@ -132,7 +132,9 @@ const A2AMetrics: React.FC<A2AMetricsProps> = ({ a2aMetadata, timeToFirstToken,
{/* Time to first token */}
{timeToFirstToken !== undefined && (
<Tooltip title={t("playground.a2AMetrics.timeToFirstToken")}>
<span className="flex items-center text-green-600">TTFT: {(timeToFirstToken / 1000).toFixed(2)}s</span>
<span className="flex items-center text-green-600">
{t("playground.a2AMetrics.ttftPrefix")} {(timeToFirstToken / 1000).toFixed(2)}s
</span>
</Tooltip>
)}
</div>

View file

@ -684,7 +684,9 @@ const TeamInfoView: React.FC<TeamInfoProps> = ({
onMouseDown={preventTagMouseDown}
style={{ marginInlineEnd: 4 }}
>
{isGlobal && <GlobalOutlined style={{ marginInlineEnd: 4 }} aria-label="Global guardrail" />}
{isGlobal && (
<GlobalOutlined style={{ marginInlineEnd: 4 }} aria-label={t("teamPage.teamInfo.globalGuardrailAriaLabel")} />
)}
{label}
</Tag>
);
@ -1508,7 +1510,7 @@ const TeamInfoView: React.FC<TeamInfoProps> = ({
>
<Input.TextArea
rows={6}
placeholder='{"namespace": "admin", "mount": "secret", "path_prefix": "litellm"}'
placeholder={t("teamPage.teamInfo.vaultConfigPlaceholder")}
disabled={!premiumUser}
/>
</Form.Item>

View file

@ -412,7 +412,7 @@ const VectorStoreForm: React.FC<VectorStoreFormProps> = ({
rows={4}
value={metadataJson}
onChange={(e) => setMetadataJson(e.target.value)}
placeholder='{"key": "value"}'
placeholder={t("vectorStoreManagement.vectorStoreForm.metadataPlaceholder")}
/>
</Form.Item>

View file

@ -2,38 +2,39 @@
* Utility functions for parsing and formatting messages for pretty view
*/
import type { TFunction } from "i18next";
import { ParsedMessage, ParsedMessages, RoleStyle } from "./prettyMessagesTypes";
/**
* Role color styles for message cards - minimal, professional design
* Color only used for labels and left border accent
*/
export const ROLE_STYLES: Record<string, RoleStyle> = {
export const getRoleStyles = (t: TFunction): Record<string, RoleStyle> => ({
system: {
background: "transparent",
borderColor: "#8c8c8c",
label: "SYSTEM",
label: t("viewLogs.prettyMessagesUtils.roleSystem"),
labelColor: "#8c8c8c",
},
user: {
background: "transparent",
borderColor: "#1677ff",
label: "USER",
label: t("viewLogs.prettyMessagesUtils.roleUser"),
labelColor: "#1677ff",
},
assistant: {
background: "transparent",
borderColor: "#52c41a",
label: "ASSISTANT",
label: t("viewLogs.prettyMessagesUtils.roleAssistant"),
labelColor: "#52c41a",
},
tool: {
background: "transparent",
borderColor: "#fa8c16",
label: "TOOL RESULT",
label: t("viewLogs.prettyMessagesUtils.roleTool"),
labelColor: "#fa8c16",
},
};
});
/**
* Parse request messages and response message from log data

View file

@ -1423,7 +1423,8 @@
"unableToLoadContent": "Unable to load category content",
"viewFileFor": "View {{fileType}} for {{name}}",
"contentWillLoad": "Content will load when expanded",
"noTopicsSelected": "No blocked topics selected. Add topics to detect and block harmful content."
"noTopicsSelected": "No blocked topics selected. Add topics to detect and block harmful content.",
"previewLabel": "Preview"
},
"contentFilterConfiguration": {
"description": "Configure patterns, keywords, and content categories to detect and filter sensitive information in requests and responses.",
@ -1571,7 +1572,21 @@
"primContainsAnyDesc": "Check if any substring exists",
"primWordCountDesc": "Count words",
"primCharCountDesc": "Count characters",
"primStringTransformsDesc": "String transforms"
"primStringTransformsDesc": "String transforms",
"modePreCall": "pre_call (Request)",
"modePostCall": "post_call (Response)",
"modeDuringCall": "during_call (Parallel)",
"modePreMcpCall": "pre_mcp_call (Before MCP Tool Call)",
"modePostMcpCall": "post_mcp_call (After MCP Tool Call)",
"modeDuringMcpCall": "during_mcp_call (During MCP Tool Call)",
"fieldTextsDesc": "Message content (always)",
"fieldImagesDesc": "Base64 images (vision)",
"fieldToolsDesc": "Tool definitions",
"fieldToolsMcpDesc": "MCP as OpenAI tool",
"fieldToolCallsDesc": "LLM tool calls",
"fieldStructuredMessagesDesc": "Full messages",
"fieldModelDesc": "Model name (always)",
"testInputPlaceholder": "{\"texts\": [\"test message\"], ...}"
},
"editGuardrailForm": {
"modalTitle": "Edit Guardrail",
@ -2127,7 +2142,9 @@
"connectionTestSuccess": "Connection test successful!",
"connectionTestError": "Error testing connection: {{error}}",
"modelDeleteSuccess": "Model deleted successfully",
"modelDeleteFailed": "Failed to delete model"
"modelDeleteFailed": "Failed to delete model",
"placeholderModelInfo": "{\"gpt-4\": 100, \"claude-v1\": 200}",
"placeholderLitellmParams": "{\"rpm\": 100, \"timeout\": 0, \"stream_timeout\": 0}"
},
"common": {
"save": "Save",
@ -3221,6 +3238,12 @@
"imagesCoverage": "images {{guarded}}/{{total}}",
"automatedReasoningFindings": "Automated Reasoning Findings",
"rawResponse": "Raw Bedrock Guardrail Response"
},
"prettyMessagesUtils": {
"roleSystem": "SYSTEM",
"roleUser": "USER",
"roleAssistant": "ASSISTANT",
"roleTool": "TOOL RESULT"
}
},
"userAgentActivity": {
@ -3581,7 +3604,8 @@
"label": "Stdio Configuration (JSON)",
"tooltip": "Paste your stdio MCP server configuration in JSON format. You can use the full mcpServers structure from config.yaml or just the inner server configuration.",
"required": "Please enter stdio configuration",
"invalidJson": "Please enter valid JSON"
"invalidJson": "Please enter valid JSON",
"placeholder": "{\n \"mcpServers\": {\n \"circleci-mcp-server\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@circleci/mcp-server-circleci\"],\n \"env\": {\n \"CIRCLECI_TOKEN\": \"your-circleci-token\",\n \"CIRCLECI_BASE_URL\": \"https://circleci.com\"\n }\n }\n }\n}"
},
"userEnvVarsModal": {
"title": "Set your credentials",
@ -4127,7 +4151,8 @@
"statusMessage": "Status Message:",
"taskId": "Task ID:",
"sessionId": "Session ID:",
"customMetadata": "Custom Metadata:"
"customMetadata": "Custom Metadata:",
"ttftPrefix": "TTFT:"
},
"additionalModelSettings": {
"useAdvancedParams": "Use Advanced Parameters",
@ -6084,7 +6109,8 @@
"metadataTooltip": "JSON metadata for the vector store (optional)",
"invalidMetadataJson": "Invalid JSON in metadata field",
"createSuccess": "Vector store created successfully",
"createFailed": "Error creating vector store: {{error}}"
"createFailed": "Error creating vector store: {{error}}",
"metadataPlaceholder": "{\"key\": \"value\"}"
},
"vectorStoreTable": {
"colVectorStoreId": "Vector Store ID",
@ -6639,7 +6665,9 @@
"deleteMemberInfoTitle": "Team Member Information",
"userIdLabel": "User ID",
"emailLabel": "Email",
"roleLabel": "Role"
"roleLabel": "Role",
"globalGuardrailAriaLabel": "Global guardrail",
"vaultConfigPlaceholder": "{\"namespace\": \"admin\", \"mount\": \"secret\", \"path_prefix\": \"litellm\"}"
},
"teamMemberTab": {
"noLimits": "No Limits",
@ -7265,7 +7293,8 @@
"attachedTeams": "Attached Teams",
"noTeams": "No teams attached",
"created": "Created",
"lastUpdated": "Last Updated"
"lastUpdated": "Last Updated",
"idLabel": "ID:"
},
"accessGroupsPage": {
"title": "Access Groups",
@ -8116,7 +8145,8 @@
"valueTooltip": "Markdown/text injected into LLM context. Plain strings are fine.",
"valuePlaceholder": "What the agent should remember…",
"labelMetadata": "Metadata <secondary>(optional JSON)</secondary>",
"metadataTooltip": "Optional structured metadata — must be valid JSON if provided."
"metadataTooltip": "Optional structured metadata — must be valid JSON if provided.",
"metadataPlaceholder": "{\"tags\": [\"example\"]}"
},
"memoryView": {
"pageTitle": "Memory",

View file

@ -1423,7 +1423,8 @@
"unableToLoadContent": "无法加载分类内容",
"viewFileFor": "查看 {{fileType}} 文件:{{name}}",
"contentWillLoad": "展开后将加载内容",
"noTopicsSelected": "未选择封锁主题。添加主题以检测和拦截有害内容。"
"noTopicsSelected": "未选择封锁主题。添加主题以检测和拦截有害内容。",
"previewLabel": "预览"
},
"contentFilterConfiguration": {
"description": "配置模式、关键词和内容分类,以检测和过滤请求及响应中的敏感信息。",
@ -1571,7 +1572,21 @@
"primContainsAnyDesc": "检查是否存在任意子字符串",
"primWordCountDesc": "统计单词数",
"primCharCountDesc": "统计字符数",
"primStringTransformsDesc": "字符串转换"
"primStringTransformsDesc": "字符串转换",
"modePreCall": "pre_call(请求)",
"modePostCall": "post_call(响应)",
"modeDuringCall": "during_call(并行)",
"modePreMcpCall": "pre_mcp_call(MCP 工具调用前)",
"modePostMcpCall": "post_mcp_call(MCP 工具调用后)",
"modeDuringMcpCall": "during_mcp_call(MCP 工具调用中)",
"fieldTextsDesc": "消息内容(始终)",
"fieldImagesDesc": "Base64 图像(视觉)",
"fieldToolsDesc": "工具定义",
"fieldToolsMcpDesc": "MCP 作为 OpenAI 工具",
"fieldToolCallsDesc": "LLM 工具调用",
"fieldStructuredMessagesDesc": "完整消息",
"fieldModelDesc": "模型名称(始终)",
"testInputPlaceholder": "{\"texts\": [\"测试消息\"], ...}"
},
"editGuardrailForm": {
"modalTitle": "编辑护栏",
@ -2127,7 +2142,9 @@
"connectionTestSuccess": "连接测试成功!",
"connectionTestError": "测试连接时出错:{{error}}",
"modelDeleteSuccess": "模型已成功删除",
"modelDeleteFailed": "删除模型失败"
"modelDeleteFailed": "删除模型失败",
"placeholderModelInfo": "{\"gpt-4\": 100, \"claude-v1\": 200}",
"placeholderLitellmParams": "{\"rpm\": 100, \"timeout\": 0, \"stream_timeout\": 0}"
},
"common": {
"save": "保存",
@ -3221,6 +3238,12 @@
"imagesCoverage": "图片 {{guarded}}/{{total}}",
"automatedReasoningFindings": "自动推理发现",
"rawResponse": "原始 Bedrock 护栏响应"
},
"prettyMessagesUtils": {
"roleSystem": "系统",
"roleUser": "用户",
"roleAssistant": "助手",
"roleTool": "工具结果"
}
},
"userAgentActivity": {
@ -3581,7 +3604,8 @@
"label": "Stdio 配置(JSON)",
"tooltip": "以 JSON 格式粘贴您的 stdio MCP 服务器配置。可使用 config.yaml 中的完整 mcpServers 结构,或仅填写内部服务器配置。",
"required": "请输入 stdio 配置",
"invalidJson": "请输入有效的 JSON"
"invalidJson": "请输入有效的 JSON",
"placeholder": "{\n \"mcpServers\": {\n \"circleci-mcp-server\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@circleci/mcp-server-circleci\"],\n \"env\": {\n \"CIRCLECI_TOKEN\": \"your-circleci-token\",\n \"CIRCLECI_BASE_URL\": \"https://circleci.com\"\n }\n }\n }\n}"
},
"userEnvVarsModal": {
"title": "设置您的凭据",
@ -4127,7 +4151,8 @@
"statusMessage": "状态消息:",
"taskId": "任务 ID:",
"sessionId": "会话 ID:",
"customMetadata": "自定义元数据:"
"customMetadata": "自定义元数据:",
"ttftPrefix": "TTFT:"
},
"additionalModelSettings": {
"useAdvancedParams": "使用高级参数",
@ -6084,7 +6109,8 @@
"metadataTooltip": "向量存储的 JSON 元数据(可选)",
"invalidMetadataJson": "元数据字段中的 JSON 无效",
"createSuccess": "向量存储创建成功",
"createFailed": "创建向量存储失败:{{error}}"
"createFailed": "创建向量存储失败:{{error}}",
"metadataPlaceholder": "{\"key\": \"value\"}"
},
"vectorStoreTable": {
"colVectorStoreId": "向量存储 ID",
@ -6639,7 +6665,9 @@
"deleteMemberInfoTitle": "团队成员信息",
"userIdLabel": "用户 ID",
"emailLabel": "邮箱",
"roleLabel": "角色"
"roleLabel": "角色",
"globalGuardrailAriaLabel": "全局护栏",
"vaultConfigPlaceholder": "{\"namespace\": \"admin\", \"mount\": \"secret\", \"path_prefix\": \"litellm\"}"
},
"teamMemberTab": {
"noLimits": "无限制",
@ -7265,7 +7293,8 @@
"attachedTeams": "关联团队",
"noTeams": "暂无关联团队",
"created": "创建时间",
"lastUpdated": "最后更新"
"lastUpdated": "最后更新",
"idLabel": "ID:"
},
"accessGroupsPage": {
"title": "访问组",
@ -8116,7 +8145,8 @@
"valueTooltip": "注入 LLM 上下文的 Markdown/文本内容,普通字符串即可。",
"valuePlaceholder": "Agent 需要记住的内容……",
"labelMetadata": "元数据 <secondary>(可选 JSON)</secondary>",
"metadataTooltip": "可选的结构化元数据——如填写必须为有效 JSON。"
"metadataTooltip": "可选的结构化元数据——如填写必须为有效 JSON。",
"metadataPlaceholder": "{\"tags\": [\"示例\"]}"
},
"memoryView": {
"pageTitle": "记忆",