diff --git a/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/FallbackGroupConfig.tsx b/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/FallbackGroupConfig.tsx
index 2372f626a5c..5acb2d48d53 100644
--- a/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/FallbackGroupConfig.tsx
+++ b/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/FallbackGroupConfig.tsx
@@ -6,6 +6,7 @@
import { Select, Tooltip } from "antd";
import { AlertCircle, ArrowDown, X } from "lucide-react";
import React from "react";
+import { useTranslation } from "react-i18next";
export interface FallbackGroup {
id: string;
@@ -21,6 +22,7 @@ interface FallbackGroupConfigProps {
}
export function FallbackGroupConfig({ group, onChange, availableModels, maxFallbacks }: FallbackGroupConfigProps) {
+ const { t } = useTranslation();
// Filter available options for fallbacks (exclude primary only, allow already selected to be shown for deselection)
const availableFallbackOptions = availableModels.filter((m) => m !== group.primaryModel);
@@ -62,12 +64,12 @@ export function FallbackGroupConfig({ group, onChange, availableModels, maxFallb
{/* Primary Model Section */}
)}
@@ -87,7 +89,7 @@ export function FallbackGroupConfig({ group, onChange, availableModels, maxFallb
- IF FAILS, TRY...
+ {t("settingsPages.fallbackGroupConfig.ifFailsTry")}
@@ -96,8 +98,10 @@ export function FallbackGroupConfig({ group, onChange, availableModels, maxFallb
className={`transition-opacity duration-300 ${!group.primaryModel ? "opacity-50 pointer-events-none" : "opacity-100"}`}
>
@@ -108,7 +112,9 @@ export function FallbackGroupConfig({ group, onChange, availableModels, maxFallb
className="w-full"
size="large"
placeholder={
- canAddMoreFallbacks ? "Select fallback models to add..." : `Maximum ${maxFallbacks} fallbacks reached`
+ canAddMoreFallbacks
+ ? t("settingsPages.fallbackGroupConfig.selectFallbackPlaceholder")
+ : t("settingsPages.fallbackGroupConfig.maxFallbacksReached", { maxFallbacks })
}
value={group.fallbackModels}
onChange={handleFallbackSelect}
@@ -146,8 +152,11 @@ export function FallbackGroupConfig({ group, onChange, availableModels, maxFallb
/>
{canAddMoreFallbacks
- ? `Search and select multiple models. Selected models will appear below in order. (${group.fallbackModels.length}/${maxFallbacks} used)`
- : `Maximum ${maxFallbacks} fallbacks reached. Remove some to add more.`}
+ ? t("settingsPages.fallbackGroupConfig.selectHint", {
+ used: group.fallbackModels.length,
+ max: maxFallbacks,
+ })
+ : t("settingsPages.fallbackGroupConfig.maxReachedHint", { maxFallbacks })}
@@ -155,8 +164,8 @@ export function FallbackGroupConfig({ group, onChange, availableModels, maxFallb
{group.fallbackModels.length === 0 ? (
- No fallback models selected
- Add models from the dropdown above
+ {t("settingsPages.fallbackGroupConfig.noFallbacksSelected")}
+ {t("settingsPages.fallbackGroupConfig.addFromDropdown")}
) : (
group.fallbackModels.map((modelValue, index) => {
diff --git a/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/FallbackSelectionForm.tsx b/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/FallbackSelectionForm.tsx
index 379742f99b4..9fe53b9396b 100644
--- a/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/FallbackSelectionForm.tsx
+++ b/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/FallbackSelectionForm.tsx
@@ -8,6 +8,7 @@ import { Button } from "@tremor/react";
import { Tabs } from "antd";
import { Plus } from "lucide-react";
import React, { useEffect, useState } from "react";
+import { useTranslation } from "react-i18next";
import MessageManager from "@/components/molecules/message_manager";
import { FallbackGroup, FallbackGroupConfig } from "./FallbackGroupConfig";
@@ -26,6 +27,7 @@ export function FallbackSelectionForm({
maxFallbacks = 10,
maxGroups = 5,
}: FallbackSelectionFormProps) {
+ const { t } = useTranslation();
const [activeKey, setActiveKey] = useState(groups.length > 0 ? groups[0].id : "1");
// Reset activeKey when groups change (e.g., when modal reopens)
@@ -61,7 +63,7 @@ export function FallbackSelectionForm({
const handleRemoveGroup = (targetId: string) => {
if (groups.length === 1) {
- MessageManager.warning("At least one group is required");
+ MessageManager.warning(t("settingsPages.fallbackSelectionForm.atLeastOneGroup"));
return;
}
const newGroups = groups.filter((g) => g.id !== targetId);
@@ -78,7 +80,9 @@ export function FallbackSelectionForm({
// Generate tab items
const items = groups.map((group, index) => {
- const label = group.primaryModel ? group.primaryModel : `Group ${index + 1}`;
+ const label = group.primaryModel
+ ? group.primaryModel
+ : t("settingsPages.fallbackSelectionForm.groupLabel", { number: index + 1 });
return {
key: group.id,
label: label,
@@ -97,9 +101,9 @@ export function FallbackSelectionForm({
if (groups.length === 0) {
return (
-
No fallback groups configured
+
{t("settingsPages.fallbackSelectionForm.noGroupsConfigured")}
);
diff --git a/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/Fallbacks.tsx b/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/Fallbacks.tsx
index 55abe698f7e..fe50a608536 100644
--- a/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/Fallbacks.tsx
+++ b/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/Fallbacks.tsx
@@ -4,6 +4,8 @@ import { Icon, Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow
import { Tooltip, Typography } from "antd";
import openai from "openai";
import React, { useEffect, useState } from "react";
+import { Trans, useTranslation } from "react-i18next";
+import { TFunction } from "i18next";
import DeleteResourceModal from "../../../common_components/DeleteResourceModal";
import { ProviderLogo } from "../../../molecules/models/ProviderLogo";
import NotificationsManager from "../../../molecules/notifications_manager";
@@ -68,7 +70,7 @@ interface FallbacksProps {
modelData: any;
}
-async function testFallbackModelResponse(selectedModel: string, accessToken: string) {
+async function testFallbackModelResponse(selectedModel: string, accessToken: string, t: TFunction) {
const isLocal = process.env.NODE_ENV === "development";
if (isLocal != true) {
console.log = function () {};
@@ -81,7 +83,7 @@ async function testFallbackModelResponse(selectedModel: string, accessToken: str
});
try {
- NotificationsManager.info("Testing fallback model response...");
+ NotificationsManager.info(t("settingsPages.fallbacks.testingFallback"));
const response = await client.chat.completions.create({
model: selectedModel,
@@ -96,26 +98,29 @@ async function testFallbackModelResponse(selectedModel: string, accessToken: str
});
NotificationsManager.success(
-
- Test model={selectedModel}, received model=
- {response.model}. See{" "}
- window.open("https://docs.litellm.ai/docs/proxy/reliability", "_blank")}
- style={{ textDecoration: "underline", color: "blue" }}
- >
- curl
-
- ,
+
,
+ receivedModel:
,
+ curlLink: (
+
window.open("https://docs.litellm.ai/docs/proxy/reliability", "_blank")}
+ style={{ textDecoration: "underline", color: "blue" }}
+ />
+ ),
+ }}
+ />,
);
} catch (error) {
- NotificationsManager.fromBackend(
- `Error occurred while generating model response. Please try again. Error: ${error}`,
- );
+ NotificationsManager.fromBackend(t("settingsPages.fallbacks.testError", { error }));
}
}
const Fallbacks: React.FC = ({ accessToken, userRole, userID, modelData }) => {
+ const { t } = useTranslation();
const [routerSettings, setRouterSettings] = useState<{ [key: string]: any }>({});
const [isDeleting, setIsDeleting] = useState(false);
const [fallbackToDelete, setFallbackToDelete] = useState(null);
@@ -181,9 +186,9 @@ const Fallbacks: React.FC = ({ accessToken, userRole, userID, mo
try {
await setCallbacksCall(accessToken, payload);
setRouterSettings(updatedSettings);
- NotificationsManager.success("Router settings updated successfully");
+ NotificationsManager.success(t("settingsPages.fallbacks.updateSuccess"));
} catch (error) {
- NotificationsManager.fromBackend("Failed to update router settings: " + error);
+ NotificationsManager.fromBackend(t("settingsPages.fallbacks.updateFailed", { error }));
} finally {
setIsDeleting(false);
setIsDeleteModalOpen(false);
@@ -220,7 +225,7 @@ const Fallbacks: React.FC = ({ accessToken, userRole, userID, mo
setRouterSettings(updatedSettings);
} catch (error) {
// Revert on error by refetching from server
- NotificationsManager.fromBackend("Failed to update router settings: " + error);
+ NotificationsManager.fromBackend(t("settingsPages.fallbacks.updateFailed", { error }));
if (accessToken && userRole && userID) {
getCallbacksCall(accessToken, userID, userRole).then((data) => {
let router_settings = data.router_settings;
@@ -251,17 +256,15 @@ const Fallbacks: React.FC = ({ accessToken, userRole, userID, mo
)}
{!hasFallbacks ? (
-
- No fallbacks configured. Add fallbacks to automatically try another model when the primary fails.
-
+ {t("settingsPages.fallbacks.noFallbacksConfigured")}
) : (
- Model Name
- Fallbacks
- Actions
+ {t("settingsPages.fallbacks.modelNameColumn")}
+ {t("settingsPages.fallbacks.fallbacksColumn")}
+ {t("common.actions")}
@@ -276,15 +279,15 @@ const Fallbacks: React.FC = ({ accessToken, userRole, userID, mo
{canModify && (
<>
-
+
testFallbackModelResponse(Object.keys(item)[0], accessToken || "")}
+ onClick={() => testFallbackModelResponse(Object.keys(item)[0], accessToken || "", t)}
className="cursor-pointer hover:text-blue-600"
/>
-
+
= ({ accessToken, userRole, userID, mo
)}
{{selectedModel}}, received model={{responseModel}}. See curl",
+ "testError": "Error occurred while generating model response. Please try again. Error: {{error}}",
+ "updateSuccess": "Router settings updated successfully",
+ "updateFailed": "Failed to update router settings: {{error}}",
+ "noFallbacksConfigured": "No fallbacks configured. Add fallbacks to automatically try another model when the primary fails.",
+ "modelNameColumn": "Model Name",
+ "fallbacksColumn": "Fallbacks",
+ "testFallbackTooltip": "Test fallback",
+ "deleteFallbackTooltip": "Delete fallback",
+ "deleteModalTitle": "Delete Fallback?",
+ "deleteModalMessage": "Are you sure you want to delete this fallback? This action cannot be undone.",
+ "deleteModalResourceTitle": "Fallback Information"
}
}
}
diff --git a/ui/litellm-dashboard/src/locales/zh-CN.json b/ui/litellm-dashboard/src/locales/zh-CN.json
index b270f859e39..ef366522f26 100644
--- a/ui/litellm-dashboard/src/locales/zh-CN.json
+++ b/ui/litellm-dashboard/src/locales/zh-CN.json
@@ -4450,6 +4450,41 @@
"addFallbacksModal": {
"title": "配置模型回退",
"subtitle": "管理不同模型的多个回退链(每次最多 5 组)"
+ },
+ "fallbackGroupConfig": {
+ "primaryModelLabel": "主模型",
+ "selectPrimaryModelPlaceholder": "选择主模型",
+ "selectModelHint": "选择一个模型以开始配置回退",
+ "ifFailsTry": "若失败,尝试...",
+ "fallbackChainLabel": "回退链",
+ "maxFallbacksHint": "(每次最多 {{maxFallbacks}} 个回退)",
+ "selectFallbackPlaceholder": "选择要添加的回退模型...",
+ "maxFallbacksReached": "已达到最大 {{maxFallbacks}} 个回退",
+ "selectHint": "搜索并选择多个模型,已选模型将按顺序显示在下方。(已用 {{used}}/{{max}})",
+ "maxReachedHint": "已达到最大 {{maxFallbacks}} 个回退,请先移除一些再添加。",
+ "noFallbacksSelected": "未选择回退模型",
+ "addFromDropdown": "从上方下拉菜单添加模型"
+ },
+ "fallbackSelectionForm": {
+ "atLeastOneGroup": "至少需要一个组",
+ "groupLabel": "组 {{number}}",
+ "noGroupsConfigured": "未配置回退组",
+ "createFirstGroup": "创建第一个组"
+ },
+ "fallbacks": {
+ "testingFallback": "正在测试回退模型响应...",
+ "testSuccess": "测试模型={{selectedModel}},收到模型={{responseModel}}。查看 curl",
+ "testError": "生成模型响应时出错,请重试。错误:{{error}}",
+ "updateSuccess": "路由器设置更新成功",
+ "updateFailed": "更新路由器设置失败:{{error}}",
+ "noFallbacksConfigured": "未配置回退。添加回退可在主模型失败时自动尝试其他模型。",
+ "modelNameColumn": "模型名称",
+ "fallbacksColumn": "回退",
+ "testFallbackTooltip": "测试回退",
+ "deleteFallbackTooltip": "删除回退",
+ "deleteModalTitle": "删除回退?",
+ "deleteModalMessage": "确定要删除此回退吗?此操作无法撤销。",
+ "deleteModalResourceTitle": "回退信息"
}
}
}