diff --git a/ui/litellm-dashboard/src/components/common_components/AccessGroupSelector.tsx b/ui/litellm-dashboard/src/components/common_components/AccessGroupSelector.tsx index 0ee363f9d1e..fda982fde8c 100644 --- a/ui/litellm-dashboard/src/components/common_components/AccessGroupSelector.tsx +++ b/ui/litellm-dashboard/src/components/common_components/AccessGroupSelector.tsx @@ -2,6 +2,7 @@ import React from "react"; import { Select, Skeleton } from "antd"; import { TeamOutlined } from "@ant-design/icons"; import { Text } from "@tremor/react"; +import { useTranslation } from "react-i18next"; import { useAccessGroups, AccessGroupResponse } from "@/app/(dashboard)/hooks/accessGroups/useAccessGroups"; export interface AccessGroupSelectorProps { @@ -28,14 +29,15 @@ export interface AccessGroupSelectorProps { const AccessGroupSelector: React.FC = ({ value, onChange, - placeholder = "Select access groups", + placeholder, disabled = false, style, className, showLabel = false, - labelText = "Access Group", + labelText, allowClear = true, }) => { + const { t } = useTranslation(); const { data: accessGroups, isLoading, isError } = useAccessGroups(); // ── Loading skeleton ───────────────────────────────────────────────────── @@ -44,7 +46,7 @@ const AccessGroupSelector: React.FC = ({
{showLabel && ( - {labelText} + {labelText ?? t("commonComponents.accessGroupSelector.labelText")} )} @@ -70,13 +72,13 @@ const AccessGroupSelector: React.FC = ({
{showLabel && ( - {labelText} + {labelText ?? t("commonComponents.accessGroupSelector.labelText")} )} - Daily - Weekly - Monthly + {t("commonComponents.durationSelect.daily")} + {t("commonComponents.durationSelect.weekly")} + {t("commonComponents.durationSelect.monthly")} ); } diff --git a/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.tsx b/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.tsx index 7c4738f9ede..1b975ec4a3f 100644 --- a/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.tsx +++ b/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.tsx @@ -2,6 +2,7 @@ import React, { useState } from "react"; import { Select, Tooltip, Divider, Switch, Checkbox } from "antd"; import { InfoCircleOutlined } from "@ant-design/icons"; import { TextInput } from "@tremor/react"; +import { useTranslation } from "react-i18next"; const { Option } = Select; @@ -26,6 +27,8 @@ const KeyLifecycleSettings: React.FC = ({ neverExpire = false, onNeverExpireChange, }) => { + const { t } = useTranslation(); + // Predefined intervals const predefinedIntervals = ["7d", "30d", "90d", "180d", "365d"]; @@ -65,12 +68,14 @@ const KeyLifecycleSettings: React.FC = ({
{/* Key Expiry Section */}
- Key Expiry Settings + + {t("commonComponents.keyLifecycleSettings.keyExpirySectionTitle")} +
= ({ {/* Auto-Rotation Section */}
- Auto-Rotation Settings + + {t("commonComponents.keyLifecycleSettings.autoRotationSectionTitle")} +
@@ -130,8 +141,8 @@ const KeyLifecycleSettings: React.FC = ({ {autoRotationEnabled && (
@@ -140,14 +151,14 @@ const KeyLifecycleSettings: React.FC = ({ value={showCustomInput ? "custom" : rotationInterval} onChange={handleIntervalChange} className="w-full" - placeholder="Select interval" + placeholder={t("commonComponents.keyLifecycleSettings.selectInterval")} > - - - - - - + + + + + + {showCustomInput && ( @@ -155,10 +166,10 @@ const KeyLifecycleSettings: React.FC = ({
- Supported formats: seconds (s), minutes (m), hours (h), days (d) + {t("commonComponents.keyLifecycleSettings.customIntervalFormats")}
)} @@ -169,8 +180,7 @@ const KeyLifecycleSettings: React.FC = ({ {autoRotationEnabled && (
- When rotation occurs, you'll receive a notification with the new key. The old key will be deactivated - after a brief grace period. + {t("commonComponents.keyLifecycleSettings.rotationNotice")}
)}
diff --git a/ui/litellm-dashboard/src/components/common_components/LoadingScreen.tsx b/ui/litellm-dashboard/src/components/common_components/LoadingScreen.tsx index 6144fa6aad1..ebe6a2d2721 100644 --- a/ui/litellm-dashboard/src/components/common_components/LoadingScreen.tsx +++ b/ui/litellm-dashboard/src/components/common_components/LoadingScreen.tsx @@ -1,14 +1,17 @@ import { cx } from "@/lib/cva.config"; import { UiLoadingSpinner } from "../ui/ui-loading-spinner"; +import { useTranslation } from "react-i18next"; export default function LoadingScreen() { + const { t } = useTranslation(); + return (
🚅 LiteLLM
- Loading... + {t("common.loading")}
); diff --git a/ui/litellm-dashboard/src/components/common_components/MemberTable.tsx b/ui/litellm-dashboard/src/components/common_components/MemberTable.tsx index d58094642d2..50802bdd917 100644 --- a/ui/litellm-dashboard/src/components/common_components/MemberTable.tsx +++ b/ui/litellm-dashboard/src/components/common_components/MemberTable.tsx @@ -3,6 +3,7 @@ import { CrownOutlined, InfoCircleOutlined, UserAddOutlined, UserOutlined } from import { Button, Space, Table, Tag, Tooltip, Typography } from "antd"; import type { ColumnsType } from "antd/es/table"; import React from "react"; +import { useTranslation } from "react-i18next"; import TableIconActionButton from "./IconActionButton/TableIconActionButtons/TableIconActionButton"; const { Text } = Typography; @@ -26,36 +27,41 @@ export default function MemberTable({ onEdit, onDelete, onAddMember, - roleColumnTitle = "Role", + roleColumnTitle, roleTooltip, extraColumns = [], showDeleteForMember, emptyText, }: MemberTableProps) { + const { t } = useTranslation(); const baseColumns: ColumnsType = [ { - title: "User Email", + title: t("commonComponents.memberTable.userEmail"), dataIndex: "user_email", key: "user_email", render: (email: string | null) => {email || "-"}, }, { - title: "User ID", + title: t("commonComponents.memberTable.userId"), dataIndex: "user_id", key: "user_id", render: (userId: string | null) => - userId === "default_user_id" ? Default Proxy Admin : {userId || "-"}, + userId === "default_user_id" ? ( + {t("commonComponents.memberTable.defaultProxyAdmin")} + ) : ( + {userId || "-"} + ), }, { title: roleTooltip ? ( - {roleColumnTitle} + {roleColumnTitle ?? t("user.role")} ) : ( - roleColumnTitle + roleColumnTitle ?? t("user.role") ), dataIndex: "role", key: "role", @@ -72,7 +78,7 @@ export default function MemberTable({ }, ...extraColumns, { - title: "Actions", + title: t("common.actions"), key: "actions", fixed: "right" as const, width: 120, @@ -81,14 +87,14 @@ export default function MemberTable({ onEdit(record)} /> {(!showDeleteForMember || showDeleteForMember(record)) && ( onDelete(record)} /> @@ -101,7 +107,7 @@ export default function MemberTable({ return ( - {members.length} Member{members.length !== 1 ? "s" : ""} + {t("commonComponents.memberTable.memberCount", { count: members.length })} {onAddMember && canEdit && ( )} diff --git a/ui/litellm-dashboard/src/components/common_components/ModelAliasManager.tsx b/ui/litellm-dashboard/src/components/common_components/ModelAliasManager.tsx index b4b1fa779c6..57c8f13a86f 100644 --- a/ui/litellm-dashboard/src/components/common_components/ModelAliasManager.tsx +++ b/ui/litellm-dashboard/src/components/common_components/ModelAliasManager.tsx @@ -1,6 +1,7 @@ import React, { useState, useEffect } from "react"; import { PlusCircleIcon, PencilIcon, TrashIcon } from "@heroicons/react/outline"; import { Card, Title, Text, Table, TableHead, TableHeaderCell, TableBody, TableRow, TableCell } from "@tremor/react"; +import { useTranslation } from "react-i18next"; import ModelSelector from "./ModelSelector"; import NotificationsManager from "../molecules/notifications_manager"; @@ -23,6 +24,7 @@ const ModelAliasManager: React.FC = ({ onAliasUpdate, showExampleConfig = true, }) => { + const { t } = useTranslation(); const [aliases, setAliases] = useState([]); const [newAlias, setNewAlias] = useState({ aliasName: "", targetModel: "" }); const [editingAlias, setEditingAlias] = useState(null); @@ -39,13 +41,13 @@ const ModelAliasManager: React.FC = ({ const handleAddAlias = () => { if (!newAlias.aliasName || !newAlias.targetModel) { - NotificationsManager.fromBackend("Please provide both alias name and target model"); + NotificationsManager.fromBackend(t("commonComponents.modelAliasManager.bothRequired")); return; } // Check for duplicate alias names if (aliases.some((alias) => alias.aliasName === newAlias.aliasName)) { - NotificationsManager.fromBackend("An alias with this name already exists"); + NotificationsManager.fromBackend(t("commonComponents.modelAliasManager.duplicateAlias")); return; } @@ -69,7 +71,7 @@ const ModelAliasManager: React.FC = ({ onAliasUpdate(aliasObject); } - NotificationsManager.success("Alias added successfully"); + NotificationsManager.success(t("commonComponents.modelAliasManager.addSuccess")); }; const handleEditAlias = (alias: AliasItem) => { @@ -80,13 +82,13 @@ const ModelAliasManager: React.FC = ({ if (!editingAlias) return; if (!editingAlias.aliasName || !editingAlias.targetModel) { - NotificationsManager.fromBackend("Please provide both alias name and target model"); + NotificationsManager.fromBackend(t("commonComponents.modelAliasManager.bothRequired")); return; } // Check for duplicate alias names (excluding current alias) if (aliases.some((alias) => alias.id !== editingAlias.id && alias.aliasName === editingAlias.aliasName)) { - NotificationsManager.fromBackend("An alias with this name already exists"); + NotificationsManager.fromBackend(t("commonComponents.modelAliasManager.duplicateAlias")); return; } @@ -105,7 +107,7 @@ const ModelAliasManager: React.FC = ({ onAliasUpdate(aliasObject); } - NotificationsManager.success("Alias updated successfully"); + NotificationsManager.success(t("commonComponents.modelAliasManager.updateSuccess")); }; const handleCancelEdit = () => { @@ -126,7 +128,7 @@ const ModelAliasManager: React.FC = ({ onAliasUpdate(aliasObject); } - NotificationsManager.success("Alias deleted successfully"); + NotificationsManager.success(t("commonComponents.modelAliasManager.deleteSuccess")); }; // Convert current aliases to object for config example @@ -141,10 +143,14 @@ const ModelAliasManager: React.FC = ({ return (
- Add New Alias + + {t("commonComponents.modelAliasManager.addNewAlias")} +
- + = ({ />
- + = ({ className={`flex items-center px-4 py-2 rounded-md text-sm ${!newAlias.aliasName || !newAlias.targetModel ? "bg-gray-300 text-gray-500 cursor-not-allowed" : "bg-green-600 text-white hover:bg-green-700"}`} > - Add Alias + {t("commonComponents.modelAliasManager.addAlias")}
- Manage Existing Aliases + + {t("commonComponents.modelAliasManager.manageExisting")} +
- Alias Name - Target Model - Actions + + {t("commonComponents.modelAliasManager.aliasName")} + + + {t("commonComponents.modelAliasManager.targetModel")} + + {t("common.actions")} @@ -235,13 +249,13 @@ const ModelAliasManager: React.FC = ({ onClick={handleUpdateAlias} className="text-xs bg-blue-50 text-blue-600 px-2 py-1 rounded hover:bg-blue-100" > - Save + {t("common.save")} @@ -273,7 +287,7 @@ const ModelAliasManager: React.FC = ({ {aliases.length === 0 && ( - No aliases added yet. Add a new alias above. + {t("commonComponents.modelAliasManager.noAliases")} )} @@ -285,8 +299,8 @@ const ModelAliasManager: React.FC = ({ {/* Configuration Example */} {showExampleConfig && ( - Configuration Example - Here's how your current aliases would look in the config: + {t("commonComponents.modelAliasManager.configExample")} + {t("commonComponents.modelAliasManager.configExampleDesc")}
model_aliases: diff --git a/ui/litellm-dashboard/src/components/common_components/ModelSelector.tsx b/ui/litellm-dashboard/src/components/common_components/ModelSelector.tsx index 24d6696dec6..2af5d2bbad0 100644 --- a/ui/litellm-dashboard/src/components/common_components/ModelSelector.tsx +++ b/ui/litellm-dashboard/src/components/common_components/ModelSelector.tsx @@ -2,6 +2,7 @@ import React, { useState, useEffect, useRef } from "react"; import { TextInput, Text } from "@tremor/react"; import { Select } from "antd"; import { RobotOutlined } from "@ant-design/icons"; +import { useTranslation } from "react-i18next"; import { fetchAvailableModels, ModelGroup } from "../playground/llm_calls/fetch_models"; interface ModelSelectorProps { @@ -19,14 +20,15 @@ interface ModelSelectorProps { const ModelSelector: React.FC = ({ accessToken, value, - placeholder = "Select a Model", + placeholder, onChange, disabled = false, style, className, showLabel = true, - labelText = "Select Model", + labelText, }) => { + const { t } = useTranslation(); const [selectedModel, setSelectedModel] = useState(value); const [showCustomModelInput, setShowCustomModelInput] = useState(false); const [modelInfo, setModelInfo] = useState([]); @@ -86,12 +88,12 @@ const ModelSelector: React.FC = ({
{showLabel && ( - {labelText} + {labelText ?? t("commonComponents.modelSelector.labelText")} )}