From 4b0371ae4402c381b7e35f850ab33c36931557ff 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 05:33:45 +0900 Subject: [PATCH] feat(ui): i18n for credentials management --- .../model_add/AddCredentialModal.tsx | 24 +++++----- .../model_add/EditCredentialModal.tsx | 24 +++++----- .../src/components/model_add/credentials.tsx | 37 +++++++++------ .../model_add/reuse_credentials.tsx | 18 +++---- ui/litellm-dashboard/src/locales/en.json | 47 +++++++++++++++++++ ui/litellm-dashboard/src/locales/zh-CN.json | 47 +++++++++++++++++++ 6 files changed, 152 insertions(+), 45 deletions(-) diff --git a/ui/litellm-dashboard/src/components/model_add/AddCredentialModal.tsx b/ui/litellm-dashboard/src/components/model_add/AddCredentialModal.tsx index 694a98201c6..004eb93a050 100644 --- a/ui/litellm-dashboard/src/components/model_add/AddCredentialModal.tsx +++ b/ui/litellm-dashboard/src/components/model_add/AddCredentialModal.tsx @@ -2,6 +2,7 @@ import { TextInput } from "@tremor/react"; import { Select as AntdSelect, Button, Form, Modal, Tooltip, Typography } from "antd"; import type { UploadProps } from "antd/es/upload"; import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; import ProviderSpecificFields from "../add_model/provider_specific_fields"; import { Providers, providerLogoMap } from "../provider_info_helpers"; const { Link } = Typography; @@ -14,6 +15,7 @@ interface AddCredentialsModalProps { } const AddCredentialsModal: React.FC = ({ open, onCancel, onAddCredential, uploadProps }) => { + const { t } = useTranslation(); const [form] = Form.useForm(); const [selectedProvider, setSelectedProvider] = useState(Providers.OpenAI); @@ -30,7 +32,7 @@ const AddCredentialsModal: React.FC = ({ open, onCance return ( { onCancel(); @@ -42,19 +44,19 @@ const AddCredentialsModal: React.FC = ({ open, onCance
{/* Credential Name */} - + {/* Provider Selection */} = ({ open, onCance {/* Modal Footer */}
- - Need Help? + + {t("modelAdd.addCredentialModal.needHelp")}
@@ -105,9 +107,9 @@ const AddCredentialsModal: React.FC = ({ open, onCance }} style={{ marginRight: 10 }} > - Cancel + {t("common.cancel")} - +
diff --git a/ui/litellm-dashboard/src/components/model_add/EditCredentialModal.tsx b/ui/litellm-dashboard/src/components/model_add/EditCredentialModal.tsx index b206ed6c91d..52d30988dca 100644 --- a/ui/litellm-dashboard/src/components/model_add/EditCredentialModal.tsx +++ b/ui/litellm-dashboard/src/components/model_add/EditCredentialModal.tsx @@ -2,6 +2,7 @@ import { TextInput } from "@tremor/react"; import { Select as AntdSelect, Button, Form, Modal, Tooltip, Typography } from "antd"; import type { UploadProps } from "antd/es/upload"; import { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; import ProviderSpecificFields from "../add_model/provider_specific_fields"; import { CredentialItem } from "../networking"; import { Providers, providerLogoMap } from "../provider_info_helpers"; @@ -22,6 +23,7 @@ export default function EditCredentialsModal({ uploadProps, existingCredential, }: EditCredentialsModalProps) { + const { t } = useTranslation(); const [form] = Form.useForm(); const [selectedProvider, setSelectedProvider] = useState(Providers.Anthropic); @@ -58,7 +60,7 @@ export default function EditCredentialsModal({ return ( { onCancel(); @@ -71,23 +73,23 @@ export default function EditCredentialsModal({
{/* Credential Name */} {/* Provider Selection */} - - Need Help? + + {t("modelAdd.editCredentialModal.needHelp")}
@@ -138,9 +140,9 @@ export default function EditCredentialsModal({ }} style={{ marginRight: 10 }} > - Cancel + {t("common.cancel")} - +
diff --git a/ui/litellm-dashboard/src/components/model_add/credentials.tsx b/ui/litellm-dashboard/src/components/model_add/credentials.tsx index 53df9015c97..6986d0dfd05 100644 --- a/ui/litellm-dashboard/src/components/model_add/credentials.tsx +++ b/ui/litellm-dashboard/src/components/model_add/credentials.tsx @@ -20,6 +20,7 @@ import { import { Form } from "antd"; import { UploadProps } from "antd/es/upload"; import { useState } from "react"; +import { useTranslation } from "react-i18next"; import DeleteResourceModal from "../common_components/DeleteResourceModal"; import NotificationsManager from "../molecules/notifications_manager"; import AddCredentialsTab from "./AddCredentialModal"; @@ -32,6 +33,7 @@ interface CredentialsPanelProps { } const CredentialsPanel: React.FC = ({ uploadProps }) => { + const { t } = useTranslation(); const { accessToken, userRole } = useAuthorized(); // Admin Viewer follows the read-parity rule: see credentials, do not modify. const canModifyCredentials = isProxyAdminRole(userRole ?? ""); @@ -65,7 +67,7 @@ const CredentialsPanel: React.FC = ({ uploadProps }) => { }; await credentialUpdateCall(accessToken, values.credential_name, newCredential); - NotificationsManager.success("Credential updated successfully"); + NotificationsManager.success(t("modelAdd.credentials.updatedSuccess")); setIsUpdateModalOpen(false); await refetchCredentials(); }; @@ -89,7 +91,7 @@ const CredentialsPanel: React.FC = ({ uploadProps }) => { // Add to list and close modal await credentialCreateCall(accessToken, newCredential); - NotificationsManager.success("Credential added successfully"); + NotificationsManager.success(t("modelAdd.credentials.addedSuccess")); setIsAddModalOpen(false); await refetchCredentials(); }; @@ -117,10 +119,10 @@ const CredentialsPanel: React.FC = ({ uploadProps }) => { setIsCredentialDeleting(true); try { await credentialDeleteCall(accessToken, credentialToDelete.credential_name); - NotificationsManager.success("Credential deleted successfully"); + NotificationsManager.success(t("modelAdd.credentials.deletedSuccess")); await refetchCredentials(); } catch (error) { - NotificationsManager.error("Failed to delete credential"); + NotificationsManager.error(t("modelAdd.credentials.deleteFailed")); } finally { setCredentialToDelete(null); setIsDeleteModalOpen(false); @@ -140,25 +142,27 @@ const CredentialsPanel: React.FC = ({ uploadProps }) => { return (
- {canModifyCredentials && } + {canModifyCredentials && ( + + )}
- Configured credentials for different AI providers. Add and manage your API credentials. + {t("modelAdd.credentials.configuredCredentials")}
- Credential Name - Provider - Actions + {t("modelAdd.credentials.credentialName")} + {t("modelAdd.credentials.provider")} + {t("common.actions")} {!credentialList || credentialList.length === 0 ? ( - No credentials configured + {t("modelAdd.credentials.noCredentials")} ) : ( @@ -219,12 +223,15 @@ const CredentialsPanel: React.FC = ({ uploadProps }) => { isOpen={isDeleteModalOpen} onCancel={closeDeleteModal} onOk={handleDeleteCredential} - title="Delete Credential?" - message="Are you sure you want to delete this credential? This action cannot be undone and may break existing integrations." - resourceInformationTitle="Credential Information" + title={t("modelAdd.credentials.deleteTitle")} + message={t("modelAdd.credentials.deleteMessage")} + resourceInformationTitle={t("modelAdd.credentials.credentialInformation")} resourceInformation={[ - { label: "Credential Name", value: credentialToDelete?.credential_name }, - { label: "Provider", value: credentialToDelete?.credential_info?.custom_llm_provider || "-" }, + { label: t("modelAdd.credentials.credentialName"), value: credentialToDelete?.credential_name }, + { + label: t("modelAdd.credentials.provider"), + value: credentialToDelete?.credential_info?.custom_llm_provider || "-", + }, ]} confirmLoading={isCredentialDeleting} requiredConfirmation={credentialToDelete?.credential_name} diff --git a/ui/litellm-dashboard/src/components/model_add/reuse_credentials.tsx b/ui/litellm-dashboard/src/components/model_add/reuse_credentials.tsx index e16c0b73ac3..28788321378 100644 --- a/ui/litellm-dashboard/src/components/model_add/reuse_credentials.tsx +++ b/ui/litellm-dashboard/src/components/model_add/reuse_credentials.tsx @@ -1,6 +1,7 @@ import React from "react"; import { Form, Button, Tooltip, Typography, Modal } from "antd"; import { TextInput } from "@tremor/react"; +import { useTranslation } from "react-i18next"; import { CredentialItem } from "../networking"; const { Title, Link } = Typography; @@ -19,6 +20,7 @@ const ReuseCredentialsModal: React.FC = ({ existingCredential, setIsCredentialModalOpen, }) => { + const { t } = useTranslation(); const [form] = Form.useForm(); console.log(`existingCredential in add credentials tab: ${JSON.stringify(existingCredential)}`); @@ -31,7 +33,7 @@ const ReuseCredentialsModal: React.FC = ({ return ( { onCancel(); @@ -43,12 +45,12 @@ const ReuseCredentialsModal: React.FC = ({
{/* Credential Name */} - + {/* Display Credential Values of existingCredential, don't allow user to edit. Credential values is a dictionary */} @@ -60,8 +62,8 @@ const ReuseCredentialsModal: React.FC = ({ {/* Modal Footer */}
- - Need Help? + + {t("modelAdd.reuseCredentials.needHelp")}
@@ -72,9 +74,9 @@ const ReuseCredentialsModal: React.FC = ({ }} style={{ marginRight: 10 }} > - Cancel + {t("common.cancel")} - +
diff --git a/ui/litellm-dashboard/src/locales/en.json b/ui/litellm-dashboard/src/locales/en.json index 29c21c28b1a..f0667c5887f 100644 --- a/ui/litellm-dashboard/src/locales/en.json +++ b/ui/litellm-dashboard/src/locales/en.json @@ -7569,5 +7569,52 @@ "tagUpdatedSuccess": "Tag updated successfully", "errorUpdatingTag": "Error updating tag: {{error}}" } + }, + "modelAdd": { + "addCredentialModal": { + "title": "Add New Credential", + "credentialNameLabel": "Credential Name:", + "credentialNameRequired": "Credential name is required", + "credentialNamePlaceholder": "Enter a friendly name for these credentials", + "providerLabel": "Provider:", + "providerTooltip": "Helper to auto-populate provider specific fields", + "needHelpTooltip": "Get help on our github", + "needHelp": "Need Help?", + "addCredential": "Add Credential" + }, + "editCredentialModal": { + "title": "Edit Credential", + "credentialNameLabel": "Credential Name:", + "credentialNameRequired": "Credential name is required", + "credentialNamePlaceholder": "Enter a friendly name for these credentials", + "providerLabel": "Provider:", + "providerTooltip": "Helper to auto-populate provider specific fields", + "needHelpTooltip": "Get help on our github", + "needHelp": "Need Help?", + "updateCredential": "Update Credential" + }, + "credentials": { + "addCredential": "Add Credential", + "configuredCredentials": "Configured credentials for different AI providers. Add and manage your API credentials.", + "credentialName": "Credential Name", + "provider": "Provider", + "noCredentials": "No credentials configured", + "updatedSuccess": "Credential updated successfully", + "addedSuccess": "Credential added successfully", + "deletedSuccess": "Credential deleted successfully", + "deleteFailed": "Failed to delete credential", + "deleteTitle": "Delete Credential?", + "deleteMessage": "Are you sure you want to delete this credential? This action cannot be undone and may break existing integrations.", + "credentialInformation": "Credential Information" + }, + "reuseCredentials": { + "title": "Reuse Credentials", + "credentialNameLabel": "Credential Name:", + "credentialNameRequired": "Credential name is required", + "credentialNamePlaceholder": "Enter a friendly name for these credentials", + "needHelpTooltip": "Get help on our github", + "needHelp": "Need Help?", + "reuseCredentials": "Reuse Credentials" + } } } diff --git a/ui/litellm-dashboard/src/locales/zh-CN.json b/ui/litellm-dashboard/src/locales/zh-CN.json index 99a38a6733b..3b972d28efe 100644 --- a/ui/litellm-dashboard/src/locales/zh-CN.json +++ b/ui/litellm-dashboard/src/locales/zh-CN.json @@ -7569,5 +7569,52 @@ "tagUpdatedSuccess": "标签更新成功", "errorUpdatingTag": "更新标签失败:{{error}}" } + }, + "modelAdd": { + "addCredentialModal": { + "title": "添加新凭据", + "credentialNameLabel": "凭据名称:", + "credentialNameRequired": "凭据名称不能为空", + "credentialNamePlaceholder": "输入这组凭据的友好名称", + "providerLabel": "提供商:", + "providerTooltip": "帮助自动填充提供商特定字段", + "needHelpTooltip": "在我们的 GitHub 上获取帮助", + "needHelp": "需要帮助?", + "addCredential": "添加凭据" + }, + "editCredentialModal": { + "title": "编辑凭据", + "credentialNameLabel": "凭据名称:", + "credentialNameRequired": "凭据名称不能为空", + "credentialNamePlaceholder": "输入这组凭据的友好名称", + "providerLabel": "提供商:", + "providerTooltip": "帮助自动填充提供商特定字段", + "needHelpTooltip": "在我们的 GitHub 上获取帮助", + "needHelp": "需要帮助?", + "updateCredential": "更新凭据" + }, + "credentials": { + "addCredential": "添加凭据", + "configuredCredentials": "已为不同 AI 提供商配置的凭据。添加并管理您的 API 凭据。", + "credentialName": "凭据名称", + "provider": "提供商", + "noCredentials": "暂无已配置的凭据", + "updatedSuccess": "凭据更新成功", + "addedSuccess": "凭据添加成功", + "deletedSuccess": "凭据删除成功", + "deleteFailed": "删除凭据失败", + "deleteTitle": "删除凭据?", + "deleteMessage": "确定要删除此凭据吗?此操作不可撤销,且可能破坏现有集成。", + "credentialInformation": "凭据信息" + }, + "reuseCredentials": { + "title": "复用凭据", + "credentialNameLabel": "凭据名称:", + "credentialNameRequired": "凭据名称不能为空", + "credentialNamePlaceholder": "输入这组凭据的友好名称", + "needHelpTooltip": "在我们的 GitHub 上获取帮助", + "needHelp": "需要帮助?", + "reuseCredentials": "复用凭据" + } } }