diff --git a/ui/litellm-dashboard/src/components/survey/ClaudeCodeModal.tsx b/ui/litellm-dashboard/src/components/survey/ClaudeCodeModal.tsx index 8e17a2ce986..06a62fc5667 100644 --- a/ui/litellm-dashboard/src/components/survey/ClaudeCodeModal.tsx +++ b/ui/litellm-dashboard/src/components/survey/ClaudeCodeModal.tsx @@ -1,6 +1,7 @@ import React from "react"; import { X, Code, ExternalLink } from "lucide-react"; import { Button } from "antd"; +import { useTranslation } from "react-i18next"; interface ClaudeCodeModalProps { isOpen: boolean; @@ -11,6 +12,8 @@ interface ClaudeCodeModalProps { const GOOGLE_FORM_URL = "https://forms.gle/LZeJQ3XytBakckYa9"; export function ClaudeCodeModal({ isOpen, onClose, onComplete }: ClaudeCodeModalProps) { + const { t } = useTranslation(); + if (!isOpen) return null; const handleOpenForm = () => { @@ -29,7 +32,9 @@ export function ClaudeCodeModal({ isOpen, onClose, onComplete }: ClaudeCodeModal
- Claude Code Feedback + + {t("survey.claudeCodeModal.headerLabel")} +
diff --git a/ui/litellm-dashboard/src/components/survey/ClaudeCodePrompt.tsx b/ui/litellm-dashboard/src/components/survey/ClaudeCodePrompt.tsx index 2f97c164976..f982f7353eb 100644 --- a/ui/litellm-dashboard/src/components/survey/ClaudeCodePrompt.tsx +++ b/ui/litellm-dashboard/src/components/survey/ClaudeCodePrompt.tsx @@ -1,6 +1,7 @@ import React from "react"; import { Code } from "lucide-react"; import { NudgePrompt } from "./NudgePrompt"; +import { useTranslation } from "react-i18next"; interface ClaudeCodePromptProps { onOpen: () => void; @@ -9,14 +10,16 @@ interface ClaudeCodePromptProps { } export function ClaudeCodePrompt({ onOpen, onDismiss, isVisible }: ClaudeCodePromptProps) { + const { t } = useTranslation(); + return ( void; @@ -30,6 +31,7 @@ export function NudgePrompt({ accentColor, buttonStyle, }: NudgePromptProps) { + const { t } = useTranslation(); const disableShowPrompts = useDisableShowPrompts(); const [progress, setProgress] = useState(100); const [showConfirmation, setShowConfirmation] = useState(false); @@ -86,9 +88,7 @@ export function NudgePrompt({
-

- Got it, we will not ask again. Reactivate this at any time in the User Menu. -

+

{t("survey.nudgePrompt.gotIt")}

@@ -134,7 +134,7 @@ export function NudgePrompt({ {buttonText} diff --git a/ui/litellm-dashboard/src/components/survey/SurveyModal.tsx b/ui/litellm-dashboard/src/components/survey/SurveyModal.tsx index b7213626358..f7ec247515e 100644 --- a/ui/litellm-dashboard/src/components/survey/SurveyModal.tsx +++ b/ui/litellm-dashboard/src/components/survey/SurveyModal.tsx @@ -1,6 +1,8 @@ -import React, { useState } from "react"; +import React, { useState, useMemo } from "react"; import { X, MessageSquare, ArrowRight, ArrowLeft } from "lucide-react"; import { Button, Input, Radio, Space, Progress, Checkbox } from "antd"; +import { useTranslation } from "react-i18next"; +import { TFunction } from "i18next"; interface SurveyModalProps { isOpen: boolean; @@ -8,33 +10,37 @@ interface SurveyModalProps { onComplete: () => void; } -const REASONS_OPTIONS = [ +type ReasonOption = { + id: string; + label: string; + description: string; +}; + +const getReasonsOptions = (t: TFunction): ReasonOption[] => [ { id: "oss_adoption", - label: "OSS Adoption", - description: "Stars, contributors, forks, community support", + label: t("survey.surveyModal.reasonOssLabel"), + description: t("survey.surveyModal.reasonOssDesc"), }, { id: "ai_integration", - label: "AI Integration", - description: - "LiteLLM had the logging/guardrail integration we needed - Langfuse, OTEL, S3 logging, Azure Content Safety guardrails", + label: t("survey.surveyModal.reasonAiIntegrationLabel"), + description: t("survey.surveyModal.reasonAiIntegrationDesc"), }, { id: "unified_api", - label: "Unified API", - description: "LiteLLM had the best OpenAI-compatible API across providers - OpenAI, Anthropic, Gemini, etc.", + label: t("survey.surveyModal.reasonUnifiedApiLabel"), + description: t("survey.surveyModal.reasonUnifiedApiDesc"), }, { id: "breadth_of_models", - label: "Breadth of Models/Providers", - description: - "LiteLLM had the provider + endpoint combinations we needed - /ocr endpoint with Mistral OCR, /batches endppint with Bedrock API, etc.", + label: t("survey.surveyModal.reasonBreadthLabel"), + description: t("survey.surveyModal.reasonBreadthDesc"), }, { id: "other", - label: "Other", - description: "Something else not listed above", + label: t("survey.surveyModal.reasonOtherLabel"), + description: t("survey.surveyModal.reasonOtherDesc"), }, ]; @@ -48,6 +54,7 @@ type SurveyData = { }; export function SurveyModal({ isOpen, onClose, onComplete }: SurveyModalProps) { + const { t } = useTranslation(); const [step, setStep] = useState(1); const [data, setData] = useState({ usingAtCompany: null, @@ -59,6 +66,8 @@ export function SurveyModal({ isOpen, onClose, onComplete }: SurveyModalProps) { }); const [isSubmitting, setIsSubmitting] = useState(false); + const reasonsOptions = useMemo(() => getReasonsOptions(t), [t]); + // Steps: 1=company?, 2=company name (conditional), 3=when, 4=why, 5=email // If not at company: skip step 2, so total is 4 // If at company: total is 5 @@ -169,15 +178,20 @@ export function SurveyModal({ isOpen, onClose, onComplete }: SurveyModalProps) { return step; }; + const startDateOptions = [ + { value: "Less than a month ago", label: t("survey.surveyModal.lessThanMonth") }, + { value: "1-3 months ago", label: t("survey.surveyModal.oneToThreeMonths") }, + { value: "3-6 months ago", label: t("survey.surveyModal.threeToSixMonths") }, + { value: "More than 6 months ago", label: t("survey.surveyModal.moreThanSixMonths") }, + ]; + const renderStepContent = () => { // Step 1: Using at company? if (step === 1) { return (
-

Are you using LiteLLM at your company?

-

- Help us understand how our product is being used in professional environments. -

+

{t("survey.surveyModal.step1Title")}

+

{t("survey.surveyModal.step1Description")}

@@ -210,11 +224,11 @@ export function SurveyModal({ isOpen, onClose, onComplete }: SurveyModalProps) { if (step === 2 && data.usingAtCompany === true) { return (
-

What company are you using LiteLLM at?

-

This helps us understand our user base better.

+

{t("survey.surveyModal.step2Title")}

+

{t("survey.surveyModal.step2Description")}

updateData("companyName", e.target.value)} autoFocus @@ -227,23 +241,23 @@ export function SurveyModal({ isOpen, onClose, onComplete }: SurveyModalProps) { if (step === 3) { return (
-

When did you start using LiteLLM?

+

{t("survey.surveyModal.step3Title")}

updateData("startDate", e.target.value)} className="w-full" > - {["Less than a month ago", "1-3 months ago", "3-6 months ago", "More than 6 months ago"].map((option) => ( + {startDateOptions.map((option) => ( ))} @@ -256,10 +270,10 @@ export function SurveyModal({ isOpen, onClose, onComplete }: SurveyModalProps) { if (step === 4) { return (
-

Why did you pick LiteLLM over other AI Gateways?

-

Select all that apply.

+

{t("survey.surveyModal.step4Title")}

+

{t("survey.surveyModal.step4Description")}

- {REASONS_OPTIONS.map((option) => { + {reasonsOptions.map((option) => { const isSelected = data.reasons.includes(option.id); return (
@@ -289,7 +303,7 @@ export function SurveyModal({ isOpen, onClose, onComplete }: SurveyModalProps) { {option.id === "other" && isSelected && ( updateData("otherReason", e.target.value)} onClick={(e) => e.stopPropagation()} @@ -308,19 +322,17 @@ export function SurveyModal({ isOpen, onClose, onComplete }: SurveyModalProps) { if (step === 5) { return (
-

Want to share more?

-

- Leave your email and we may reach out to learn more about your experience. This is completely optional. -

+

{t("survey.surveyModal.step5Title")}

+

{t("survey.surveyModal.step5Description")}

updateData("email", e.target.value)} autoFocus /> -

We will only use this to follow up on your feedback. No spam, ever.

+

{t("survey.surveyModal.emailNote")}

); } @@ -341,7 +353,7 @@ export function SurveyModal({ isOpen, onClose, onComplete }: SurveyModalProps) {
- Quick Feedback + {t("survey.surveyModal.headerLabel")}
)}
diff --git a/ui/litellm-dashboard/src/components/survey/SurveyPrompt.tsx b/ui/litellm-dashboard/src/components/survey/SurveyPrompt.tsx index e55b724a2a8..f3214037065 100644 --- a/ui/litellm-dashboard/src/components/survey/SurveyPrompt.tsx +++ b/ui/litellm-dashboard/src/components/survey/SurveyPrompt.tsx @@ -1,6 +1,7 @@ import React from "react"; import { MessageSquare } from "lucide-react"; import { NudgePrompt } from "./NudgePrompt"; +import { useTranslation } from "react-i18next"; interface SurveyPromptProps { onOpen: () => void; @@ -9,14 +10,16 @@ interface SurveyPromptProps { } export function SurveyPrompt({ onOpen, onDismiss, isVisible }: SurveyPromptProps) { + const { t } = useTranslation(); + return ( diff --git a/ui/litellm-dashboard/src/locales/en.json b/ui/litellm-dashboard/src/locales/en.json index a079b9565ec..01c316faa9d 100644 --- a/ui/litellm-dashboard/src/locales/en.json +++ b/ui/litellm-dashboard/src/locales/en.json @@ -7329,5 +7329,61 @@ "updateSuccess": "router settings updated successfully", "saveChanges": "Save Changes" } + }, + "survey": { + "claudeCodeModal": { + "headerLabel": "Claude Code Feedback", + "title": "Help us improve your experience", + "description": "We'd love to hear about your experience using LiteLLM with Claude Code. Your feedback helps us improve the product for everyone.", + "durationNote": "This brief survey takes about 2-3 minutes to complete.", + "openFormButton": "Open Feedback Form" + }, + "claudeCodePrompt": { + "title": "Claude Code Feedback", + "description": "Help us improve your Claude Code experience with LiteLLM! Share your feedback in 4 quick questions.", + "buttonText": "Share feedback" + }, + "nudgePrompt": { + "dontAskAgain": "Don't ask me again", + "gotIt": "Got it, we will not ask again. Reactivate this at any time in the User Menu." + }, + "surveyModal": { + "headerLabel": "Quick Feedback", + "stepIndicator": "Step {{current}} of {{total}}", + "step1Title": "Are you using LiteLLM at your company?", + "step1Description": "Help us understand how our product is being used in professional environments.", + "yesSubLabel": "We use it for work", + "noSubLabel": "Personal project / Hobby", + "step2Title": "What company are you using LiteLLM at?", + "step2Description": "This helps us understand our user base better.", + "companyPlaceholder": "Enter your company name", + "step3Title": "When did you start using LiteLLM?", + "lessThanMonth": "Less than a month ago", + "oneToThreeMonths": "1-3 months ago", + "threeToSixMonths": "3-6 months ago", + "moreThanSixMonths": "More than 6 months ago", + "step4Title": "Why did you pick LiteLLM over other AI Gateways?", + "step4Description": "Select all that apply.", + "otherPlaceholder": "Please specify...", + "reasonOssLabel": "OSS Adoption", + "reasonOssDesc": "Stars, contributors, forks, community support", + "reasonAiIntegrationLabel": "AI Integration", + "reasonAiIntegrationDesc": "LiteLLM had the logging/guardrail integration we needed - Langfuse, OTEL, S3 logging, Azure Content Safety guardrails", + "reasonUnifiedApiLabel": "Unified API", + "reasonUnifiedApiDesc": "LiteLLM had the best OpenAI-compatible API across providers - OpenAI, Anthropic, Gemini, etc.", + "reasonBreadthLabel": "Breadth of Models/Providers", + "reasonBreadthDesc": "LiteLLM had the provider + endpoint combinations we needed - /ocr endpoint with Mistral OCR, /batches endppint with Bedrock API, etc.", + "reasonOtherLabel": "Other", + "reasonOtherDesc": "Something else not listed above", + "step5Title": "Want to share more?", + "step5Description": "Leave your email and we may reach out to learn more about your experience. This is completely optional.", + "emailPlaceholder": "your@email.com (optional)", + "emailNote": "We will only use this to follow up on your feedback. No spam, ever." + }, + "surveyPrompt": { + "title": "Quick feedback", + "description": "Help us improve LiteLLM! Share your experience in 5 quick questions.", + "buttonText": "Share feedback" + } } } diff --git a/ui/litellm-dashboard/src/locales/zh-CN.json b/ui/litellm-dashboard/src/locales/zh-CN.json index c4d51b1a0e7..bc458fe6bb1 100644 --- a/ui/litellm-dashboard/src/locales/zh-CN.json +++ b/ui/litellm-dashboard/src/locales/zh-CN.json @@ -7329,5 +7329,61 @@ "updateSuccess": "路由器设置已成功更新", "saveChanges": "保存更改" } + }, + "survey": { + "claudeCodeModal": { + "headerLabel": "Claude Code 反馈", + "title": "帮助我们改善您的体验", + "description": "我们很乐意了解您使用 LiteLLM 与 Claude Code 的体验。您的反馈有助于我们为所有人改进产品。", + "durationNote": "这份简短的调查大约需要 2-3 分钟完成。", + "openFormButton": "打开反馈表单" + }, + "claudeCodePrompt": { + "title": "Claude Code 反馈", + "description": "帮助我们改善您在 LiteLLM 上的 Claude Code 体验!通过 4 个简短问题分享您的反馈。", + "buttonText": "分享反馈" + }, + "nudgePrompt": { + "dontAskAgain": "不再询问", + "gotIt": "好的,我们不再询问。您可以随时在用户菜单中重新激活此功能。" + }, + "surveyModal": { + "headerLabel": "快速反馈", + "stepIndicator": "第 {{current}} 步,共 {{total}} 步", + "step1Title": "您是否在公司中使用 LiteLLM?", + "step1Description": "帮助我们了解我们的产品在专业环境中的使用情况。", + "yesSubLabel": "我们将其用于工作", + "noSubLabel": "个人项目 / 兴趣爱好", + "step2Title": "您在哪家公司使用 LiteLLM?", + "step2Description": "这有助于我们更好地了解我们的用户群。", + "companyPlaceholder": "请输入您的公司名称", + "step3Title": "您何时开始使用 LiteLLM?", + "lessThanMonth": "不到一个月前", + "oneToThreeMonths": "1-3 个月前", + "threeToSixMonths": "3-6 个月前", + "moreThanSixMonths": "超过 6 个月前", + "step4Title": "您为何选择 LiteLLM 而非其他 AI 网关?", + "step4Description": "请选择所有适用项。", + "otherPlaceholder": "请详细说明...", + "reasonOssLabel": "OSS 采用", + "reasonOssDesc": "Star 数、贡献者、Fork 数、社区支持", + "reasonAiIntegrationLabel": "AI 集成", + "reasonAiIntegrationDesc": "LiteLLM 拥有我们所需的日志/护栏集成 - Langfuse、OTEL、S3 日志、Azure Content Safety 护栏", + "reasonUnifiedApiLabel": "统一 API", + "reasonUnifiedApiDesc": "LiteLLM 在各提供商中拥有最佳的 OpenAI 兼容 API - OpenAI、Anthropic、Gemini 等", + "reasonBreadthLabel": "模型/提供商广度", + "reasonBreadthDesc": "LiteLLM 拥有我们所需的提供商 + 端点组合 - 使用 Mistral OCR 的 /ocr 端点、使用 Bedrock API 的 /batches 端点等", + "reasonOtherLabel": "其他", + "reasonOtherDesc": "上面未列出的其他原因", + "step5Title": "想分享更多吗?", + "step5Description": "留下您的邮箱,我们可能会联系您了解更多关于您体验的信息。这完全是可选的。", + "emailPlaceholder": "your@email.com(可选)", + "emailNote": "我们只会用此邮箱跟进您的反馈。绝不发送垃圾邮件。" + }, + "surveyPrompt": { + "title": "快速反馈", + "description": "帮助我们改进 LiteLLM!通过 5 个简短问题分享您的使用体验。", + "buttonText": "分享反馈" + } } }