From b00ffa1e04d0c4258dfc49a47e67a917dfde1fb1 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 04:54:44 +0900 Subject: [PATCH] feat(ui): i18n for model dashboard tables and health check --- .../model_dashboard/HealthCheckComponent.tsx | 53 ++++++++++++------- .../ModelSettingsModal/ModelSettingsModal.tsx | 22 +++++--- .../model_dashboard/all_models_table.tsx | 6 ++- .../model_dashboard/health_check_columns.tsx | 34 ++++++------ .../src/components/model_dashboard/table.tsx | 6 ++- ui/litellm-dashboard/src/locales/en.json | 52 ++++++++++++++++++ ui/litellm-dashboard/src/locales/zh-CN.json | 52 ++++++++++++++++++ 7 files changed, 177 insertions(+), 48 deletions(-) diff --git a/ui/litellm-dashboard/src/components/model_dashboard/HealthCheckComponent.tsx b/ui/litellm-dashboard/src/components/model_dashboard/HealthCheckComponent.tsx index d9b7fdd149c..b019e629efe 100644 --- a/ui/litellm-dashboard/src/components/model_dashboard/HealthCheckComponent.tsx +++ b/ui/litellm-dashboard/src/components/model_dashboard/HealthCheckComponent.tsx @@ -8,6 +8,7 @@ import { errorPatterns } from "@/utils/errorPatterns"; import { individualModelHealthCheckCall, latestHealthChecksCall } from "../networking"; import { Table as TableInstance } from "@tanstack/react-table"; import { Team } from "../key_team_helpers/key_list"; +import { useTranslation } from "react-i18next"; interface HealthStatus { status: string; @@ -51,6 +52,7 @@ const HealthCheckComponent: React.FC = ({ pageSize = 50, onPageChange, }) => { + const { t } = useTranslation(); const [modelHealthStatuses, setModelHealthStatuses] = useState<{ [key: string]: HealthStatus }>({}); const [selectedModelsForHealth, setSelectedModelsForHealth] = useState([]); const [allModelsSelected, setAllModelsSelected] = useState(false); @@ -547,15 +549,13 @@ const HealthCheckComponent: React.FC = ({
- Model Health Status - - Run health checks on individual models to verify they are working correctly - + {t("modelDashboard.healthCheckComponent.title")} + {t("modelDashboard.healthCheckComponent.subtitle")}
{selectedModelsForHealth.length > 0 && ( )}
@@ -578,8 +578,12 @@ const HealthCheckComponent: React.FC = ({
{totalCount > 0 - ? `Showing ${resultsStart} - ${resultsEnd} of ${totalCount} results` - : "Showing 0 results"} + ? t("modelDashboard.healthCheckComponent.showingResults", { + start: resultsStart, + end: resultsEnd, + total: totalCount, + }) + : t("modelDashboard.healthCheckComponent.showingZeroResults")}
@@ -590,7 +594,7 @@ const HealthCheckComponent: React.FC = ({ isLoading || currentPage === 1 ? "bg-gray-100 text-gray-400 cursor-not-allowed" : "hover:bg-gray-50" }`} > - Previous + {t("common.previous")}
)} = ({ {/* Error Modal */} - Close + {t("common.close")} , ]} width={800} @@ -641,14 +650,14 @@ const HealthCheckComponent: React.FC = ({ {selectedErrorDetails && (
- Error: + {t("modelDashboard.healthCheckComponent.errorLabel")}
{selectedErrorDetails.cleanedError}
- Full Error Details: + {t("modelDashboard.healthCheckComponent.fullErrorLabel")}
{selectedErrorDetails.fullError}
@@ -660,13 +669,17 @@ const HealthCheckComponent: React.FC = ({ {/* Success Modal */} - Close + {t("common.close")} , ]} width={800} @@ -674,14 +687,14 @@ const HealthCheckComponent: React.FC = ({ {selectedSuccessDetails && (
- Status: + {t("modelDashboard.healthCheckComponent.statusLabel")}
- Health check passed successfully + {t("modelDashboard.healthCheckComponent.healthCheckPassed")}
- Response Details: + {t("modelDashboard.healthCheckComponent.responseDetailsLabel")}
                   {JSON.stringify(selectedSuccessDetails.response, null, 2)}
diff --git a/ui/litellm-dashboard/src/components/model_dashboard/ModelSettingsModal/ModelSettingsModal.tsx b/ui/litellm-dashboard/src/components/model_dashboard/ModelSettingsModal/ModelSettingsModal.tsx
index 25c722b82eb..6a1e11b834c 100644
--- a/ui/litellm-dashboard/src/components/model_dashboard/ModelSettingsModal/ModelSettingsModal.tsx
+++ b/ui/litellm-dashboard/src/components/model_dashboard/ModelSettingsModal/ModelSettingsModal.tsx
@@ -6,6 +6,7 @@ import NotificationsManager from "@/components/molecules/notifications_manager";
 import { parseErrorMessage } from "@/components/shared/errorUtils";
 import { Button, Form, Modal, Skeleton, Space, Switch, Typography } from "antd";
 import React, { useEffect, useMemo } from "react";
+import { useTranslation } from "react-i18next";
 
 interface ModelSettingsModalProps {
   isVisible: boolean;
@@ -14,6 +15,7 @@ interface ModelSettingsModalProps {
 }
 
 const ModelSettingsModal: React.FC = ({ isVisible, onCancel, onSuccess }) => {
+  const { t } = useTranslation();
   const [form] = Form.useForm();
   const { mutateAsync, isPending } = useStoreModelInDB();
   const { data: proxyConfigData, isLoading: isLoadingConfig, refetch } = useProxyConfig(ConfigType.GENERAL_SETTINGS);
@@ -44,16 +46,20 @@ const ModelSettingsModal: React.FC = ({ isVisible, onCa
     try {
       await mutateAsync(formValues, {
         onSuccess: () => {
-          NotificationsManager.success("Model storage settings updated successfully");
+          NotificationsManager.success(t("modelDashboard.modelSettingsModal.updateSuccess"));
           refetch();
           onSuccess?.();
         },
         onError: (error) => {
-          NotificationsManager.fromBackend("Failed to save model storage settings: " + parseErrorMessage(error));
+          NotificationsManager.fromBackend(
+            t("modelDashboard.modelSettingsModal.updateFailed", { error: parseErrorMessage(error) }),
+          );
         },
       });
     } catch (error) {
-      NotificationsManager.fromBackend("Failed to save model storage settings: " + parseErrorMessage(error));
+      NotificationsManager.fromBackend(
+        t("modelDashboard.modelSettingsModal.updateFailed", { error: parseErrorMessage(error) }),
+      );
     }
   };
 
@@ -64,15 +70,15 @@ const ModelSettingsModal: React.FC = ({ isVisible, onCa
 
   return (
     Model Settings}
+      title={{t("modelDashboard.modelSettingsModal.title")}}
       open={isVisible}
       footer={
         
           
           
         
       }
@@ -86,11 +92,11 @@ const ModelSettingsModal: React.FC = ({ isVisible, onCa
         initialValues={initialValues}
       >
          f.field_name === "store_model_in_db")?.field_description ||
-            "If enabled, models and config are stored in and loaded from the database."
+            t("modelDashboard.modelSettingsModal.storeModelInDbTooltip")
           }
           valuePropName="checked"
         >
diff --git a/ui/litellm-dashboard/src/components/model_dashboard/all_models_table.tsx b/ui/litellm-dashboard/src/components/model_dashboard/all_models_table.tsx
index 4372c6e0efc..77c520ebc03 100644
--- a/ui/litellm-dashboard/src/components/model_dashboard/all_models_table.tsx
+++ b/ui/litellm-dashboard/src/components/model_dashboard/all_models_table.tsx
@@ -16,6 +16,7 @@ import {
   TableHeaderSortDropdown,
   SortState,
 } from "../common_components/TableHeaderSortDropdown/TableHeaderSortDropdown";
+import { useTranslation } from "react-i18next";
 
 // Extend the column meta type to include className
 declare module "@tanstack/react-table" {
@@ -47,6 +48,7 @@ export function AllModelsDataTable({
   enablePagination = false,
   onRowClick,
 }: AllModelsDataTableProps) {
+  const { t } = useTranslation();
   const [columnResizeMode] = React.useState("onChange");
   const [columnSizing, setColumnSizing] = React.useState({});
   const [columnVisibility, setColumnVisibility] = React.useState({});
@@ -173,7 +175,7 @@ export function AllModelsDataTable({
                 
                   
                     
-

🚅 Loading models...

+

{t("modelDashboard.allModelsTable.loadingModels")}

@@ -207,7 +209,7 @@ export function AllModelsDataTable({
-

No models found

+

{t("modelDashboard.allModelsTable.noModels")}

diff --git a/ui/litellm-dashboard/src/components/model_dashboard/health_check_columns.tsx b/ui/litellm-dashboard/src/components/model_dashboard/health_check_columns.tsx index 396afb7ed0b..f007b0b4e5b 100644 --- a/ui/litellm-dashboard/src/components/model_dashboard/health_check_columns.tsx +++ b/ui/litellm-dashboard/src/components/model_dashboard/health_check_columns.tsx @@ -3,6 +3,7 @@ import { Tooltip, Checkbox } from "antd"; import { Text } from "@tremor/react"; import { InformationCircleIcon, PlayIcon, RefreshIcon } from "@heroicons/react/outline"; import { Team } from "@/components/key_team_helpers/key_list"; +import { TFunction } from "i18next"; interface HealthCheckData { model_name: string; @@ -32,6 +33,7 @@ interface HealthStatus { } export const healthCheckColumns = ( + t: TFunction, modelHealthStatuses: { [key: string]: HealthStatus }, selectedModelsForHealth: string[], allModelsSelected: boolean, @@ -54,7 +56,7 @@ export const healthCheckColumns = ( onChange={(e) => handleSelectAll(e.target.checked)} onClick={(e) => e.stopPropagation()} /> - Model ID + {t("modelDashboard.healthCheckColumns.modelId")}
), accessorKey: "model_info.id", @@ -85,7 +87,7 @@ export const healthCheckColumns = ( }, }, { - header: "Model Name", + header: () => t("modelDashboard.healthCheckColumns.modelName"), accessorKey: "model_name", enableSorting: true, sortingFn: "alphanumeric", @@ -103,7 +105,7 @@ export const healthCheckColumns = ( }, }, { - header: "Team Alias", + header: () => t("modelDashboard.healthCheckColumns.teamAlias"), accessorKey: "model_info.team_id", enableSorting: true, sortingFn: "alphanumeric", @@ -128,7 +130,7 @@ export const healthCheckColumns = ( }, }, { - header: "Health Status", + header: () => t("modelDashboard.healthCheckColumns.healthStatus"), accessorKey: "health_status", enableSorting: true, sortingFn: (rowA, rowB, columnId) => { @@ -164,7 +166,7 @@ export const healthCheckColumns = ( style={{ animationDelay: "0.4s" }} >
- Checking... + {t("modelDashboard.healthCheckColumns.checking")}
); } @@ -177,7 +179,7 @@ export const healthCheckColumns = (
{getStatusBadge(healthStatus.status)} {hasSuccessResponse && showSuccessModal && ( - +
{showErrorModal && fullError !== cleanedError && ( - +