From 6a86662d4891d4639077ffe2c5f2eff9d5d99dae Mon Sep 17 00:00:00 2001 From: duskzhen Date: Mon, 8 Dec 2025 13:04:34 +0800 Subject: [PATCH 01/12] fix: Multiple Issues Affecting Conversation Flow and Model Settings (#1166) * fix: #1164 support maxtoken 2 * fix: mcp tool panel close btn #1163 * fix: #1162 file content in converation * fix(search-assistant): exclude acp models * fix: #1072 thinkcontent respects the global font size set --- .../threadPresenter/utils/promptBuilder.ts | 12 +++--- .../common/SearchAssistantModelSection.vue | 1 + src/renderer/src/components/ModelSelect.vue | 6 ++- .../mcp-config/components/McpToolPanel.vue | 2 +- .../components/think-content/ThinkContent.vue | 13 ++---- .../src/composables/useChatConfigFields.ts | 2 +- .../src/stores/searchAssistantStore.ts | 42 +++++++++++++++---- 7 files changed, 52 insertions(+), 26 deletions(-) diff --git a/src/main/presenter/threadPresenter/utils/promptBuilder.ts b/src/main/presenter/threadPresenter/utils/promptBuilder.ts index 8d4e7aba7..a20854c12 100644 --- a/src/main/presenter/threadPresenter/utils/promptBuilder.ts +++ b/src/main/presenter/threadPresenter/utils/promptBuilder.ts @@ -445,7 +445,7 @@ function addContextMessages( contextMessages.forEach((msg) => { if (msg.role === 'user') { const msgContent = msg.content as VisionUserMessageContent - const normalizedText = getNormalizedUserMessageText(msgContent) + const finalUserContext = buildUserMessageContext(msgContent) if (vision && msgContent.images && msgContent.images.length > 0) { resultMessages.push({ role: 'user', @@ -454,13 +454,13 @@ function addContextMessages( type: 'image_url' as const, image_url: { url: image, detail: 'auto' as const } })), - { type: 'text' as const, text: normalizedText } + { type: 'text' as const, text: finalUserContext } ] }) } else { resultMessages.push({ role: 'user', - content: normalizedText + content: finalUserContext }) } } else if (msg.role === 'assistant') { @@ -532,7 +532,7 @@ function addContextMessages( contextMessages.forEach((msg) => { if (msg.role === 'user') { const msgContent = msg.content as VisionUserMessageContent - const normalizedText = getNormalizedUserMessageText(msgContent) + const finalUserContext = buildUserMessageContext(msgContent) if (vision && msgContent.images && msgContent.images.length > 0) { resultMessages.push({ role: 'user', @@ -541,13 +541,13 @@ function addContextMessages( type: 'image_url' as const, image_url: { url: image, detail: 'auto' as const } })), - { type: 'text' as const, text: normalizedText } + { type: 'text' as const, text: finalUserContext } ] }) } else { resultMessages.push({ role: 'user', - content: normalizedText + content: finalUserContext }) } } else if (msg.role === 'assistant') { diff --git a/src/renderer/settings/components/common/SearchAssistantModelSection.vue b/src/renderer/settings/components/common/SearchAssistantModelSection.vue index 7a4fbb2f3..1088d94e0 100644 --- a/src/renderer/settings/components/common/SearchAssistantModelSection.vue +++ b/src/renderer/settings/components/common/SearchAssistantModelSection.vue @@ -30,6 +30,7 @@ diff --git a/src/renderer/src/components/ModelSelect.vue b/src/renderer/src/components/ModelSelect.vue index 1d2a07aec..2e73c532b 100644 --- a/src/renderer/src/components/ModelSelect.vue +++ b/src/renderer/src/components/ModelSelect.vue @@ -71,13 +71,17 @@ const props = defineProps({ type: { type: Array as PropType, default: undefined // ← explicit for clarity + }, + excludeProviders: { + type: Array as PropType, + default: () => [] } }) const providers = computed(() => { const sortedProviders = providerStore.sortedProviders const enabledModels = modelStore.enabledModels const orderedProviders = sortedProviders - .filter((provider) => provider.enable) + .filter((provider) => provider.enable && !props.excludeProviders.includes(provider.id)) .map((provider) => { const enabledProvider = enabledModels.find((ep) => ep.providerId === provider.id) if (!enabledProvider || enabledProvider.models.length === 0) { diff --git a/src/renderer/src/components/mcp-config/components/McpToolPanel.vue b/src/renderer/src/components/mcp-config/components/McpToolPanel.vue index 700764f9c..14be83294 100644 --- a/src/renderer/src/components/mcp-config/components/McpToolPanel.vue +++ b/src/renderer/src/components/mcp-config/components/McpToolPanel.vue @@ -166,7 +166,7 @@ const selectTool = (tool: MCPToolDefinition) => { side="right" class="w-4/5 min-w-[80vw] max-w-[80vw] p-0 bg-white dark:bg-black h-screen flex flex-col gap-0" > - + {{ t('mcp.tools.title') }} - {{ serverName }} diff --git a/src/renderer/src/components/think-content/ThinkContent.vue b/src/renderer/src/components/think-content/ThinkContent.vue index e69bc55e2..0c0d54af0 100644 --- a/src/renderer/src/components/think-content/ThinkContent.vue +++ b/src/renderer/src/components/think-content/ThinkContent.vue @@ -109,22 +109,15 @@ setCustomComponents(customId, { @apply my-1.5; } .think-prose :where(p, li, ol, ul) { - font-size: 12px; - line-height: 16px; + font-size: inherit; + line-height: inherit; letter-spacing: 0; - color: rgba(37, 37, 37, 0.5); } .think-prose :where(ol, ul) { padding-left: 1.5em; } .think-prose :where(p, li, ol, ul) :where(a) { - color: rgba(37, 37, 37, 0.6); + color: inherit; text-decoration: underline; } -.dark .think-prose :where(p, li, ol, ul) { - color: rgba(255, 255, 255, 0.5); -} -.dark .think-prose :where(p, li, ol, ul) :where(a) { - color: rgba(255, 255, 255, 0.6); -} diff --git a/src/renderer/src/composables/useChatConfigFields.ts b/src/renderer/src/composables/useChatConfigFields.ts index 36c82538f..3c0024422 100644 --- a/src/renderer/src/composables/useChatConfigFields.ts +++ b/src/renderer/src/composables/useChatConfigFields.ts @@ -74,7 +74,7 @@ export function useChatConfigFields(options: UseChatConfigFieldsOptions) { label: t('settings.model.temperature.label'), description: t('settings.model.temperature.description'), min: 0, - max: 1.5, + max: 2, step: 0.1, getValue: () => options.temperature.value, setValue: (val) => options.emit('update:temperature', val) diff --git a/src/renderer/src/stores/searchAssistantStore.ts b/src/renderer/src/stores/searchAssistantStore.ts index 9434b2131..8127d1874 100644 --- a/src/renderer/src/stores/searchAssistantStore.ts +++ b/src/renderer/src/stores/searchAssistantStore.ts @@ -26,6 +26,13 @@ export const useSearchAssistantStore = defineStore('searchAssistant', () => { const searchAssistantModel = computed(() => modelRef.value) const searchAssistantProvider = computed(() => providerRef.value) + const isProviderAllowed = (providerId?: string) => providerId !== 'acp' + const isModelEnabledForProvider = (model: RENDERER_MODEL_META, providerId: string) => + enabledModels.value.some( + (provider) => + provider.providerId === providerId && + provider.models.some((enabledModel) => enabledModel.id === model.id) + ) const findPriorityModel = (): { model: RENDERER_MODEL_META; providerId: string } | null => { if (!enabledModels.value || enabledModels.value.length === 0) { @@ -34,6 +41,9 @@ export const useSearchAssistantStore = defineStore('searchAssistant', () => { for (const keyword of priorities) { for (const providerModels of enabledModels.value) { + if (!isProviderAllowed(providerModels.providerId)) { + continue + } for (const model of providerModels.models) { if ( model.id.toLowerCase().includes(keyword.toLowerCase()) || @@ -49,6 +59,7 @@ export const useSearchAssistantStore = defineStore('searchAssistant', () => { } const fallback = enabledModels.value + .filter((provider) => isProviderAllowed(provider.providerId)) .flatMap((provider) => provider.models.map((model) => ({ ...model, providerId: provider.providerId })) ) @@ -65,6 +76,10 @@ export const useSearchAssistantStore = defineStore('searchAssistant', () => { } const setSearchAssistantModel = async (model: RENDERER_MODEL_META, providerId: string) => { + if (!isProviderAllowed(providerId)) { + await initOrUpdateSearchAssistantModel() + return + } const rawModel = toRaw(model) modelRef.value = rawModel providerRef.value = providerId @@ -82,10 +97,18 @@ export const useSearchAssistantStore = defineStore('searchAssistant', () => { 'searchAssistantModel' ) savedModel = toRaw(savedModel) - if (savedModel) { - modelRef.value = savedModel.model - providerRef.value = savedModel.providerId - threadP.setSearchAssistantModel(savedModel.model, savedModel.providerId) + const hasEnabledModels = enabledModels.value.length > 0 + const usableSavedModel = + savedModel && + isProviderAllowed(savedModel.providerId) && + (!hasEnabledModels || isModelEnabledForProvider(savedModel.model, savedModel.providerId)) + ? savedModel + : null + + if (usableSavedModel) { + modelRef.value = usableSavedModel.model + providerRef.value = usableSavedModel.providerId + threadP.setSearchAssistantModel(usableSavedModel.model, usableSavedModel.providerId) return } @@ -113,9 +136,14 @@ export const useSearchAssistantStore = defineStore('searchAssistant', () => { return } - const stillAvailable = enabledModels.value.some((provider) => - provider.models.some((model) => model.id === currentModel.id) - ) + const resolvedProviderId = providerRef.value || currentModel.providerId || '' + if (!isProviderAllowed(resolvedProviderId)) { + await initOrUpdateSearchAssistantModel() + return + } + + const stillAvailable = + resolvedProviderId !== '' && isModelEnabledForProvider(currentModel, resolvedProviderId) if (!stillAvailable) { await initOrUpdateSearchAssistantModel() From 2b7a884b2fe0d729546cdc07d84f80eb762c0f64 Mon Sep 17 00:00:00 2001 From: duskzhen Date: Mon, 8 Dec 2025 14:03:36 +0800 Subject: [PATCH 02/12] feat: Hebrew (he-IL) Translation (#1157) * feat: Hebrew (he-IL) Translation * feat: add workspace view to acp agents (#1158) * feat: add workspaceview for acp agent * feat: support workspace dirs * fix: workspace file refresh * fix: tool call status * fix: review refactor * chore: update readme * fix: add file context actions (#1160) * fix: keep last file list * feat(acp-workspace): add file context actions * fix(acp-workspace): move path helpers to preload * fix(preload): allow empty relative path * fix(preload): escape quotes when formatting paths * chore: update docs * fix: Multiple Issues Affecting Conversation Flow and Model Settings (#1166) * fix: #1164 support maxtoken 2 * fix: mcp tool panel close btn #1163 * fix: #1162 file content in converation * fix(search-assistant): exclude acp models * fix: #1072 thinkcontent respects the global font size set * feat: add new i18n translation --- src/main/presenter/configPresenter/index.ts | 3 +- .../settings/components/DisplaySettings.vue | 3 +- src/renderer/src/i18n/he-IL/about.json | 19 + src/renderer/src/i18n/he-IL/artifacts.json | 52 + src/renderer/src/i18n/he-IL/chat.json | 123 +++ src/renderer/src/i18n/he-IL/common.json | 82 ++ src/renderer/src/i18n/he-IL/components.json | 41 + src/renderer/src/i18n/he-IL/contextMenu.json | 17 + src/renderer/src/i18n/he-IL/dialog.json | 44 + src/renderer/src/i18n/he-IL/index.ts | 58 ++ src/renderer/src/i18n/he-IL/mcp.json | 316 ++++++ src/renderer/src/i18n/he-IL/model.json | 30 + src/renderer/src/i18n/he-IL/newThread.json | 4 + src/renderer/src/i18n/he-IL/plan.json | 4 + .../src/i18n/he-IL/promptSetting.json | 95 ++ src/renderer/src/i18n/he-IL/routes.json | 17 + src/renderer/src/i18n/he-IL/settings.json | 964 ++++++++++++++++++ src/renderer/src/i18n/he-IL/sync.json | 17 + src/renderer/src/i18n/he-IL/thread.json | 46 + src/renderer/src/i18n/he-IL/toolCall.json | 19 + src/renderer/src/i18n/he-IL/traceDialog.json | 17 + src/renderer/src/i18n/he-IL/update.json | 16 + src/renderer/src/i18n/he-IL/welcome.json | 37 + src/renderer/src/i18n/index.ts | 5 +- src/renderer/src/stores/language.ts | 2 +- 25 files changed, 2027 insertions(+), 4 deletions(-) create mode 100644 src/renderer/src/i18n/he-IL/about.json create mode 100644 src/renderer/src/i18n/he-IL/artifacts.json create mode 100644 src/renderer/src/i18n/he-IL/chat.json create mode 100644 src/renderer/src/i18n/he-IL/common.json create mode 100644 src/renderer/src/i18n/he-IL/components.json create mode 100644 src/renderer/src/i18n/he-IL/contextMenu.json create mode 100644 src/renderer/src/i18n/he-IL/dialog.json create mode 100644 src/renderer/src/i18n/he-IL/index.ts create mode 100644 src/renderer/src/i18n/he-IL/mcp.json create mode 100644 src/renderer/src/i18n/he-IL/model.json create mode 100644 src/renderer/src/i18n/he-IL/newThread.json create mode 100644 src/renderer/src/i18n/he-IL/plan.json create mode 100644 src/renderer/src/i18n/he-IL/promptSetting.json create mode 100644 src/renderer/src/i18n/he-IL/routes.json create mode 100644 src/renderer/src/i18n/he-IL/settings.json create mode 100644 src/renderer/src/i18n/he-IL/sync.json create mode 100644 src/renderer/src/i18n/he-IL/thread.json create mode 100644 src/renderer/src/i18n/he-IL/toolCall.json create mode 100644 src/renderer/src/i18n/he-IL/traceDialog.json create mode 100644 src/renderer/src/i18n/he-IL/update.json create mode 100644 src/renderer/src/i18n/he-IL/welcome.json diff --git a/src/main/presenter/configPresenter/index.ts b/src/main/presenter/configPresenter/index.ts index c98b549fa..5c87742cd 100644 --- a/src/main/presenter/configPresenter/index.ts +++ b/src/main/presenter/configPresenter/index.ts @@ -686,7 +686,8 @@ export class ConfigPresenter implements IConfigPresenter { 'fr-FR', 'fa-IR', 'pt-BR', - 'da-DK' + 'da-DK', + 'he-IL' ] // Exact match diff --git a/src/renderer/settings/components/DisplaySettings.vue b/src/renderer/settings/components/DisplaySettings.vue index 6b6008092..2f84dfd52 100644 --- a/src/renderer/settings/components/DisplaySettings.vue +++ b/src/renderer/settings/components/DisplaySettings.vue @@ -340,7 +340,8 @@ const languageOptions = [ { value: 'fr-FR', label: 'Français' }, { value: 'fa-IR', label: 'فارسی (ایران)' }, { value: 'pt-BR', label: 'Português (Brasil)' }, - { value: 'da-DK', label: 'Dansk' } + { value: 'da-DK', label: 'Dansk' }, + { value: 'he-IL', label: 'עברית (ישראל)' } ] watch(selectedLanguage, async (newValue) => { diff --git a/src/renderer/src/i18n/he-IL/about.json b/src/renderer/src/i18n/he-IL/about.json new file mode 100644 index 000000000..03e17c5bb --- /dev/null +++ b/src/renderer/src/i18n/he-IL/about.json @@ -0,0 +1,19 @@ +{ + "title": "DeepChat", + "description": "DeepChat הוא לקוח AI חוצה-פלטפורמות, המוקדש להנגשת הבינה המלאכותית ליותר אנשים.", + "website": "בקר באתר שלנו", + "deviceInfo": { + "title": "מידע על המכשיר", + "platform": "פלטפורמה", + "arch": "ארכיטקטורה", + "cpuModel": "דגם מעבד", + "totalMemory": "זיכרון כולל", + "osVersion": "גרסת מערכת" + }, + "disclaimerButton": "כתב ויתור", + "disclaimerTitle": "הצהרת תנאי שימוש", + "checkUpdateButton": "בדוק עדכונים", + "updateChannel": "ערוץ עדכון", + "stableChannel": "יציב (Stable)", + "canaryChannel": "קנרית (Canary)" +} diff --git a/src/renderer/src/i18n/he-IL/artifacts.json b/src/renderer/src/i18n/he-IL/artifacts.json new file mode 100644 index 000000000..28dc8fb98 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/artifacts.json @@ -0,0 +1,52 @@ +{ + "clickToOpen": "לחץ לפתיחה", + "codeSnippet": "קטע קוד", + "function": "פונקציה", + "class": "מחלקה (Class)", + "reactComponent": "רכיב React", + "moduleImport": "ייבוא מודול", + "variableDefinition": "הגדרת משתנה {name}", + "markdownDocument": "מסמך Markdown", + "htmlDocument": "מסמך HTML", + "svgImage": "תמונת SVG", + "flowchart": "תרשים זרימה", + "sequenceDiagram": "דיאגרמת רצף", + "classDiagram": "דיאגרמת מחלקות", + "stateDiagram": "דיאגרמת מצבים", + "erDiagram": "דיאגרמת ER", + "ganttChart": "תרשים גאנט", + "pieChart": "תרשים עוגה", + "mermaidDiagram": "דיאגרמת Mermaid", + "flowchartOf": "תרשים זרימה של {name}", + "sequenceDiagramBetween": "דיאגרמת רצף בין {participants}", + "classDiagramOf": "דיאגרמת מחלקות של {name}", + "stateDiagramOf": "דיאגרמת מצבים של {name}", + "erDiagramOf": "דיאגרמת ER של {name}", + "pieChartOf": "תרשים עוגה של {name}", + "unknownDocument": "מסמך לא ידוע", + "preview": "תצוגה מקדימה", + "code": "קוד", + "export": "ייצוא", + "htmlPreviewTitle": "תצוגה מקדימה של HTML", + "svgPreviewTitle": "תצוגה מקדימה של SVG", + "copy": "העתק", + "copySuccess": "הועתק", + "copySuccessDesc": "התוכן הועתק ללוח", + "copyFailed": "העתקה נכשלה", + "copyFailedDesc": "נכשל בהעתקת התוכן ללוח", + "copyAsImage": "העתק כתמונה", + "copyImageSuccessDesc": "התמונה הועתקה ללוח", + "copyImageFailedDesc": "לא ניתן היה להעתיק את התמונה ללוח.", + "desktop": "שולחן עבודה", + "tablet": "טאבלט", + "mobile": "נייד", + "responsive": "רספונסיבי", + "width": "רוחב", + "height": "גובה", + "sanitizingSvg": "מנקה תוכן SVG...", + "svgSanitizationFailed": "תוכן ה-SVG נכשל באימות אבטחה", + "noSvgContent": "אין תוכן SVG זמין", + "mermaid": { + "renderError": "עיבוד נכשל: {message}" + } +} diff --git a/src/renderer/src/i18n/he-IL/chat.json b/src/renderer/src/i18n/he-IL/chat.json new file mode 100644 index 000000000..effb8f617 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/chat.json @@ -0,0 +1,123 @@ +{ + "input": { + "placeholder": "שאל משהו? ניתן לצטט כלים, קבצים ומשאבים באמצעות {'@'}...", + "fileArea": "אזור קבצים", + "inputArea": "אזור קלט", + "functionSwitch": "מתג פונקציות", + "fileSelect": "בחר קובץ", + "pasteFiles": "הדבק קבצים מהלוח", + "dropFiles": "גרור קבצים לכאן", + "promptFilesAdded": "קבצי הנחיה (Prompt) נוספו", + "promptFilesAddedDesc": "נוספו בהצלחה {count} קבצים", + "promptFilesError": "שגיאה בעיבוד קבצים", + "promptFilesErrorDesc": "{count} קבצים נכשלו בעיבוד", + "historyPlaceholder": "(לחץ Tab להשלמה אוטומטית)", + "rateLimitQueue": "תור {count}", + "rateLimitWait": "המתן {seconds} שניות", + "rateLimitQueueTooltip": "{count} בקשות בתור, מרווח של {interval} שניות", + "rateLimitReadyTooltip": "מוכן לשליחה, מרווח של {interval} שניות", + "rateLimitWaitingTooltip": "המתן {seconds} שניות נוספות, מרווח של {interval} שניות", + "acpWorkdir": "תיקיית עבודה ACP", + "acpWorkdirTooltip": "הגדר תיקיית עבודה ל-ACP", + "acpWorkdirSelect": "בחר תיקייה שתשמש כתיקיית העבודה של ACP", + "acpWorkdirCurrent": "תיקיית עבודה נוכחית: {path}", + "acpMode": "דֶגֶם", + "acpModeTooltip": "מצב נוכחי: {mode}" + }, + "features": { + "webSearch": "חיפוש אינטרנט", + "thoughtForSeconds": "חשב במשך {seconds} שניות", + "thoughtForSecondsLoading": "חושב במשך {seconds} שניות...", + "artifactThinking": "חשיבת תוצר (Artifact Thinking)", + "modeChanged": "המצב הועבר ל: {mode}" + }, + "search": { + "results": "נמצאו {0} דפי אינטרנט", + "searching": "מחפש...", + "title": "תוצאות חיפוש", + "description": "נמצאו {0} תוצאות קשורות", + "optimizing": "ממטב את שאילתת החיפוש...", + "reading": "מחפש וקורא דפי אינטרנט...", + "error": "החיפוש נכשל" + }, + "messages": { + "thinking": "חושב...", + "rateLimitWaiting": "הגעת למגבלת הקצב, ממתין בתור...", + "rateLimitTitle": "מגבלת קצב פעילה", + "rateLimitQueue": "מיקום בתור", + "rateLimitEstimated": "המתנה משוערת", + "rateLimitQuickSettings": "התאם מגבלה", + "rateLimitSwitchProvider": "החלף ספק", + "rateLimitImmediately": "עכשיו", + "rateLimitSeconds": "שניות", + "rateLimitMinutes": "דקות" + }, + "rateLimit": { + "queueTooltip": "{count} בקשות בתור, מרווח של {interval} שניות", + "readyTooltip": "מוכן לשליחה, מרווח של {interval} שניות", + "waitingTooltip": "המתן {seconds} שניות נוספות, מרווח של {interval} שניות" + }, + "notify": { + "generationComplete": "היצירה הושלמה", + "generationError": "היצירה נכשלה" + }, + "navigation": { + "title": "ניווט בהודעות", + "searchPlaceholder": "חפש הודעות...", + "noResults": "לא נמצאו הודעות תואמות", + "noMessages": "אין הודעות עדיין", + "totalMessages": "{count} הודעות סה\"כ", + "searchResults": "נמצאו {count} תוצאות בתוך {total} הודעות", + "userMessage": "הודעת משתמש", + "assistantMessage": "תשובת עוזר", + "unknownMessage": "הודעה לא ידועה" + }, + "mcpUi": { + "title": "ממשק MCP", + "badge": "UI", + "expand": "הרחב", + "collapse": "צמצם" + }, + "toolCall": { + "title": "קריאה לכלי", + "calling": "קריאה לכלי בתהליך", + "response": "תגובת כלי", + "end": "קריאה לכלי הסתיימה", + "error": "שגיאה בקריאה לכלי", + "clickToView": "לחץ לצפייה בפרטים", + "functionName": "פונקציה", + "params": "פרמטרים", + "responseData": "נתוני תגובה" + }, + "acp": { + "workspace": { + "collapse": "לִסְגוֹר", + "files": { + "contextMenu": { + "insertPath": "הכנס לתוך תיבת הקלט", + "openFile": "לפתוח קובץ", + "revealInFolder": "פתח במנהל הקבצים" + }, + "empty": "עדיין אין קבצים", + "loading": "טוען קבצים...", + "section": "מִסְמָך" + }, + "plan": { + "empty": "עדיין אין משימות", + "section": "לְתַכְנֵן", + "status": { + "completed": "הושלם", + "failed": "לְהִכָּשֵׁל", + "in_progress": "בתהליך", + "pending": "תָלוּי וְעוֹמֵד", + "skipped": "דילג" + } + }, + "terminal": { + "empty": "עדיין אין פלט", + "section": "מָסוֹף" + }, + "title": "סביבת עבודה" + } + } +} diff --git a/src/renderer/src/i18n/he-IL/common.json b/src/renderer/src/i18n/he-IL/common.json new file mode 100644 index 000000000..87684afe2 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/common.json @@ -0,0 +1,82 @@ +{ + "enabled": "מופעל", + "disabled": "מושבת", + "loading": "טוען...", + "copySuccess": "הועתק בהצלחה", + "copySuccessDesc": "התוכן הועתק ללוח", + "copyImageSuccess": "הועתק בהצלחה", + "copyImageSuccessDesc": "התמונה הועתקה ללוח", + "copyFailed": "העתקה נכשלה", + "copyFailedDesc": "נכשל בהעתקת התוכן ללוח", + "copyCode": "העתק קוד", + "copy": "העתק", + "copied": "הועתק", + "paste": "הדבק", + "export": "ייצוא", + "newChat": "צ'אט חדש", + "newTopic": "נושא חדש", + "cancel": "ביטול", + "confirm": "אישור", + "close": "סגור", + "error": { + "requestFailed": "הבקשה נכשלה...", + "createChatFailed": "יצירת הצ'אט נכשלה", + "selectChatFailed": "בחירת הצ'אט נכשלה", + "renameChatFailed": "שינוי שם הצ'אט נכשל", + "deleteChatFailed": "מחיקת הצ'אט נכשלה", + "cleanMessagesFailed": "ניקוי ההודעות נכשל", + "userCanceledGeneration": "המשתמש ביטל את היצירה", + "sessionInterrupted": "ההפעלה הופסקה באופן בלתי צפוי, היצירה לא הושלמה", + "noModelResponse": "המודל לא החזיר תוכן, ייתכן שעבר הזמן הקצוב", + "invalidJson": "פורמט JSON לא חוקי", + "maximumToolCallsReached": "הגעת למספר המקסימלי של קריאות לכלים", + "causeOfError": "סיבות אפשריות לשגיאה:", + "error400": "בקשה שגויה, ייתכן שיש בעיה בפרמטרים או בתאימות", + "error401": "אימות נכשל, ייתכן שמפתח ה-API או הדומיין שגויים", + "error403": "הגישה למודל נאסרה, ייתכן שהיתרה אינה מספקת או שאין הרשאה", + "error404": "כתובת ה-URL המבוקשת לא נמצאה, ייתכן שהדומיין או שם המודל שגויים", + "error429": "יותר מדי בקשות, ייתכן שהשירות הגביל את הקצב (Rate Limit)", + "error500": "שגיאת שרת, ייתכן שהשירות אינו יציב, אנא נסה שוב מאוחר יותר", + "error502": "שגיאת Gateway, ייתכן שהשירות אינו יציב, אנא נסה שוב מאוחר יותר", + "error503": "השירות אינו זמין, ייתכן שהשירות אינו יציב, אנא נסה שוב מאוחר יותר", + "error504": "הבקשה הסתיימה (Timeout), ייתכן שהשירות אינו יציב או שיש בעיות רשת, אנא בדוק את הגדרות הפרוקסי ונסה שוב", + "operationFailed": "הפעולה נכשלה" + }, + "resetDataConfirmTitle": "לאפס את כל הנתונים?", + "resetDataConfirmDescription": "פעולה זו תאפס את כל הנתונים שלך להגדרות ברירת המחדל. לא ניתן לבטל פעולה זו.", + "proxyMode": "מצב פרוקסי", + "proxyModeSelect": "בחר מצב פרוקסי", + "proxyModeSystem": "פרוקסי מערכת", + "proxyModeNone": "ללא פרוקסי", + "proxyModeCustom": "פרוקסי מותאם אישית", + "customProxyUrl": "כתובת URL לפרוקסי מותאם", + "customProxyUrlPlaceholder": "דוגמה: http://127.0.0.1:7890", + "invalidProxyUrl": "כתובת פרוקסי לא חוקית, אנא הזן כתובת http/https תקינה", + "disclaimer": "כתב ויתור", + "resetData": "אפס נתונים", + "searchAssistantModel": "מודל עוזר", + "searchEngine": "מנוע חיפוש", + "searchEngineSelect": "בחר מנוע חיפוש", + "searchPreview": "תצוגה מקדימה של חיפוש", + "language": "שפה", + "languageSelect": "בחר שפה", + "selectModel": "בחר מודל", + "title": "הגדרות כלליות", + "languageSystem": "עקוב אחר המערכת", + "watermarkTip": "נוצר על ידי AI", + "collapse": "צמצם", + "expand": "הרחב", + "image": "תמונה", + "add": "הוסף", + "reset": "אפס", + "format": "פורמט", + "edit": "ערוך", + "delete": "מחק", + "save": "שמור", + "clear": "נקה", + "saved": "נשמר", + "newTab": "כרטיסייה חדשה", + "unknownError": "שגיאה לא ידועה", + "testing": "בדיקה בתהליך", + "saving": "שומר" +} diff --git a/src/renderer/src/i18n/he-IL/components.json b/src/renderer/src/i18n/he-IL/components.json new file mode 100644 index 000000000..ba813f421 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/components.json @@ -0,0 +1,41 @@ +{ + "emojiPicker": { + "search": "חפש אימוג'י", + "smileys": "סמיילים ורגשות", + "people": "אנשים וגוף", + "animals": "בעלי חיים וטבע", + "food": "אוכל ושתייה", + "travel": "נסיעות ומקומות", + "activities": "פעילויות", + "objects": "חפצים", + "symbols": "סמלים", + "flags": "דגלים" + }, + "messageBlockAction": { + "continue": "המשך", + "continued": "המשך" + }, + "messageBlockPermissionRequest": { + "title": "נדרשת הרשאה", + "allow": "אפשר", + "deny": "דחה", + "rememberChoice": "זכור בחירה זו", + "granted": "הרשאה ניתנה", + "denied": "הרשאה נדחתה", + "type": { + "read": "גישת קריאה", + "write": "גישת כתיבה", + "all": "גישה מלאה" + }, + "description": { + "read": "האם לאפשר ל-'{toolName}' מ-'{serverName}' לבצע פעולות קריאה?", + "write": "האם לאפשר ל-'{toolName}' מ-'{serverName}' לבצע פעולות כתיבה?", + "all": "האם לאפשר ל-'{toolName}' מ-'{serverName}' לבצע פעולות קריאה וכתיבה?" + } + }, + "promptParamsDialog": { + "title": "הגדרות פרמטרים עבור {name}", + "description": "אנא מלא את הפרמטרים למטה. שדות המסומנים ב-* הם שדות חובה.", + "required": "שדה זה הוא חובה." + } +} diff --git a/src/renderer/src/i18n/he-IL/contextMenu.json b/src/renderer/src/i18n/he-IL/contextMenu.json new file mode 100644 index 000000000..151bccdbc --- /dev/null +++ b/src/renderer/src/i18n/he-IL/contextMenu.json @@ -0,0 +1,17 @@ +{ + "translate": { + "title": "תרגם", + "original": "מקור", + "translated": "תרגום", + "error": "התרגום נכשל" + }, + "askAI": { + "title": "שאל את ה-AI", + "question": "שאלה", + "answer": "תשובה", + "error": "תגובת ה-AI נכשלה" + }, + "copy": "העתק", + "paste": "הדבק", + "cut": "גזור" +} diff --git a/src/renderer/src/i18n/he-IL/dialog.json b/src/renderer/src/i18n/he-IL/dialog.json new file mode 100644 index 000000000..5e6a87302 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/dialog.json @@ -0,0 +1,44 @@ +{ + "cancel": "ביטול", + "confirm": "אישור", + "close": "סגור", + "ok": "אישור", + "delete": { + "title": "האם אתה בטוח שברצונך למחוק שיחה זו?", + "description": "לא ניתן לבטל פעולה זו.", + "confirm": "מחק" + }, + "rename": { + "title": "שנה שם שיחה", + "description": "אנא הזן שם חדש לשיחה." + }, + "cleanMessages": { + "title": "נקה את כל ההודעות", + "description": "פעולה זו תמחק את כל ההודעות והקבצים בשיחה זו. האם אתה בטוח שברצונך להמשיך?", + "confirm": "נקה" + }, + "fork": { + "title": "צור ענף (Branch)", + "description": "פעולה זו תעתיק את כל ההודעות מההודעה הראשונה ועד להודעה הנוכחית לתוך שיחה חדשה בה תוכל להמשיך את הדו-שיח.", + "confirm": "צור ענף", + "tag": "ענף" + }, + "error": { + "title": "שגיאה" + }, + "mutualExclusive": { + "title": { + "reasoning": "אשר הפעלת חשיבה (Reasoning)", + "functionCall": "אשר הפעלת קריאה לפונקציות (Function Calling)" + }, + "message": { + "reasoning": "הפעלת חשיבה תשבית אוטומטית את הקריאה לפונקציות. זוהי מגבלה של מודלי DeepSeek-V3.1, ולא ניתן להשתמש בשתי התכונות בו-זמנית. להמשיך?", + "functionCall": "הפעלת קריאה לפונקציות תשבית אוטומטית את החשיבה. זוהי מגבלה של מודלי DeepSeek-V3.1, ולא ניתן להשתמש בשתי התכונות בו-זמנית. להמשיך?" + }, + "warningText": { + "reasoning": "שים לב: הפעלת חשיבה תשבית אוטומטית את הקריאה לפונקציות, שכן זו דרישה של מודלי DeepSeek-V3.1.", + "functionCall": "שים לב: הפעלת קריאה לפונקציות תשבית אוטומטית את החשיבה, שכן זו דרישה של מודלי DeepSeek-V3.1." + }, + "confirmEnable": "אשר הפעלה" + } +} diff --git a/src/renderer/src/i18n/he-IL/index.ts b/src/renderer/src/i18n/he-IL/index.ts new file mode 100644 index 000000000..9bca15c47 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/index.ts @@ -0,0 +1,58 @@ +import common from './common.json' +import update from './update.json' +import routes from './routes.json' +import chat from './chat.json' +import model from './model.json' +import thread from './thread.json' +import dialog from './dialog.json' +import settings from './settings.json' +import mcp from './mcp.json' +import welcome from './welcome.json' +import artifacts from './artifacts.json' +import sync from './sync.json' +import toolCall from './toolCall.json' +import components from './components.json' +import newThread from './newThread.json' +import about from './about.json' +import contextMenu from './contextMenu.json' +import promptSetting from './promptSetting.json' +import traceDialog from './traceDialog.json' +import plan from './plan.json' + +// Individual top-level keys +const others = { + Silicon: 'SiliconFlow', + Qiniu: 'Qiniu', + QwenLM: 'Qwen Model', + Doubao: 'Doubao', + PPIO: 'PPIO Cloud', + Moonshot: 'Moonshot AI', + DashScope: 'Alibaba Bailian', + Hunyuan: 'Hunyuan', + searchDisclaimer: + 'DeepChat הוא כלי עזר בלבד המארגן ומסכם נתונים ציבוריים המוחזרים על ידי מנועי חיפוש כאשר משתמשים יוזמים חיפושים באופן פעיל, ומסייע למשתמשים לצפות ולהבין את תוצאות החיפוש בצורה נוחה יותר.\n1. שימוש בנתונים ציבוריים\nתוכנה זו מעבדת רק נתונים הזמינים באופן ציבורי באתרי היעד או במנועי החיפוש ללא צורך בהתחברות. לפני השימוש, אנא הקפד לעיין ולציית לתנאי השירות של אתר היעד או מנוע החיפוש כדי להבטיח שהשימוש שלך חוקי ותואם לכללים.\n2. דיוק המידע ואחריות\nהתוכן המאורגן והנוצר על ידי תוכנה זו הוא לעיון בלבד ואינו מהווה כל צורה של ייעוץ משפטי, עסקי או אחר. המפתחים אינם מספקים ערובות לגבי הדיוק, השלמות, העדכניות או החוקיות של תוצאות החיפוש, וכל תוצאה הנובעת משימוש בתוכנה זו הינה באחריות המשתמש בלבד.\n3. סעיף ויתור (Disclaimer)\nתוכנה זו מסופקת "כפי שהיא" (as is), והמפתחים אינם נושאים באחריות מפורשת או משתמעת לביצועיה, יציבותה או התאמתה. במהלך השימוש בתוכנה זו, המפתחים אינם נושאים באחריות לכל מחלוקת, אובדן או חבות משפטית הנובעים מהפרות של חוקים ותקנות רלוונטיים או כללי אתר היעד.\n4. משמעת עצמית של המשתמש\nלפני השימוש בתוכנה זו, על המשתמשים להבין היטב ולאשר שהשימוש שלהם לא יפגע בזכויות קניין רוחני, סודות מסחריים או זכויות לגיטימיות אחרות של אחרים. כל מחלוקת משפטית ותוצאות הנובעות משימוש לא נאות בתוכנה זו על ידי משתמשים הינן באחריות המשתמשים בלבד.\nהשימוש בתוכנה זו מציין שהמשתמש קרא, הבין והסכים לכל תנאי כתב ויתור זה. אם יש לך שאלות, אנא התייעץ עם יועץ משפטי מקצועי.' +} + +export default { + common, + update, + routes, + chat, + model, + thread, + dialog, + settings, + mcp, + welcome, + artifacts, + sync, + toolCall, + components, + newThread, + about, + contextMenu, + promptSetting, + traceDialog, + plan, + ...others +} diff --git a/src/renderer/src/i18n/he-IL/mcp.json b/src/renderer/src/i18n/he-IL/mcp.json new file mode 100644 index 000000000..49b73af67 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/mcp.json @@ -0,0 +1,316 @@ +{ + "tools": { + "searchPlaceholder": "חפש כלים...", + "noToolsAvailable": "אין כלים זמינים", + "selectToolToDebug": "בחר כלי לניפוי באגים", + "dialogDescription": "ניפוי באגים ובדיקת כלים המסופקים על ידי שרתי MCP", + "toolsCount": "{count} כלים", + "availableTools": "כלים זמינים", + "toolList": "רשימת כלים", + "functionDescription": "תיאור פונקציה", + "invalidJson": "פורמט JSON לא חוקי", + "inputHint": "אנא הזן פרמטרים בפורמט JSON", + "required": "נדרש", + "noDescription": "אין תיאור", + "input": "ארגומנטים", + "path": "נתיב", + "pathPlaceholder": "הזן נתיב קובץ", + "searchPattern": "תבנית חיפוש", + "searchPatternPlaceholder": "הזן ביטוי רגולרי (Regex)", + "filePattern": "תבנית קובץ", + "filePatternPlaceholder": "הזן תבנית קובץ, למשל: *.md", + "executeButton": "הפעל כלי", + "resultTitle": "תוצאה", + "runningTool": "מבצע כלי...", + "loading": "טוען...", + "error": "טעינה נכשלה", + "available": "{count} זמינים", + "none": "אין כלים זמינים", + "title": "כלי MCP", + "description": "כלים המסופקים על ידי שרת ה-MCP", + "loadError": "טעינת הכלים נכשלה", + "parameters": "פרמטרים", + "refresh": "רענן", + "disabled": "MCP מושבת", + "enableToUse": "אנא הפעל את MCP כדי להשתמש בכלים", + "enabled": "הפעל את MCP", + "enabledDescription": "הפעל את פונקציונליות MCP כדי להשתמש בקריאות לכלים", + "empty": "ריק", + "jsonInputPlaceholder": "הזן את הפרמטרים בפורמט JSON", + "type": "סוג", + "annotations": "הערות (Annotations)", + "invalidJsonFormat": "פורמט ה-JSON שגוי", + "allowedValues": "ערכים מותרים", + "arrayItemValues": "ערכי פריט במערך" + }, + "addServer": "הוסף שרת", + "addServerDialog": { + "description": "הגדר שרת MCP חדש", + "title": "הוסף שרת" + }, + "confirmDelete": { + "cancel": "ביטול", + "confirm": "מחק", + "description": "האם אתה בטוח שברצונך למחוק את השרת {name}? \nלא ניתן לבטל פעולה זו.", + "title": "אשר מחיקה" + }, + "confirmRemoveServer": "האם אתה בטוח שברצונך למחוק את השרת {name}? \nלא ניתן לבטל פעולה זו.", + "default": "ברירת מחדל", + "deleteServer": "מחק שרת", + "description": "ניהול והגדרה של שרתי וכלים של MCP (Model Context Protocol)", + "editServer": "ערוך שרת", + "editServerDialog": { + "description": "ערוך תצורת שרת MCP", + "title": "ערוך שרת" + }, + "enableToAccess": "אנא הפעל את MCP כדי לגשת לאפשרויות התצורה.", + "enabledDescription": "הפעל או השבת פונקציונליות וכלים של MCP.", + "enabledTitle": "הפעל את MCP", + "isDefault": "שרת ברירת מחדל", + "noServersFound": "שרת לא נמצא", + "removeDefault": "הסר ברירת מחדל", + "removeServer": "הסר שרת", + "removeServerDialog": { + "title": "מחק שרת" + }, + "resetConfirm": "שחזר", + "resetConfirmDescription": "פעולה זו משחזרת את כל שרתי ברירת המחדל תוך שמירה על השרתים המותאמים אישית שלך. \nכל שינוי בשרת ברירת המחדל יאבד.", + "resetConfirmTitle": "שחזר שירות ברירת מחדל", + "resetToDefault": "שחזר שירות ברירת מחדל", + "running": "פועל", + "serverForm": { + "add": "הוסף", + "args": "ארגומנטים", + "argsPlaceholder": "הזן ארגומנט אחד בכל שורה", + "addArg": "הוסף ארגומנט", + "argPlaceholder": "הזן ערך ארגומנט", + "argsRequired": "הפרמטרים לא יכולים להיות ריקים", + "autoApprove": "אישור אוטומטי", + "autoApproveAll": "הכל", + "autoApproveHelp": "בחר את סוג הפעולה הדורש אישור אוטומטי ובצע ללא אישור משתמש", + "autoApproveRead": "קריאה", + "autoApproveWrite": "כתיבה", + "baseUrl": "כתובת בסיס (Base URL)", + "baseUrlPlaceholder": "הזן את כתובת הבסיס של השרת (לדוגמה: http://localhost:3000)", + "cancel": "ביטול", + "command": "פקודה", + "commandPlaceholder": "הזן פקודה", + "commandRequired": "הפקודה לא יכולה להיות ריקה", + "configImported": "ייבוא התצורה הצליח", + "description": "תיאור", + "descriptionPlaceholder": "הזן את תיאור השרת", + "descriptions": "תיאור", + "descriptionsPlaceholder": "הזן את תיאור השרת", + "env": "משתני סביבה", + "envInvalid": "משתני סביבה חייבים להיות בפורמט JSON חוקי", + "envPlaceholder": "הזן משתני סביבה בפורמט JSON", + "icon": "אייקון", + "iconPlaceholder": "הזן אייקון", + "icons": "אייקונים", + "iconsPlaceholder": "הזן אייקונים", + "jsonConfig": "תצורת JSON", + "jsonConfigExample": "דוגמה לתצורת JSON", + "jsonConfigIntro": "ניתן להדביק ישירות את תצורת ה-JSON או לבחור להגדיר את השרת ידנית.", + "jsonConfigPlaceholder": "אנא הדבק את תצורת השרת MCP בפורמט JSON", + "name": "שם השרת", + "namePlaceholder": "הזן את שם השרת", + "nameRequired": "שם השרת לא יכול להיות ריק", + "parseAndContinue": "נתח והמשך", + "parseError": "שגיאת ניתוח", + "parseSuccess": "התצורה נותחה בהצלחה", + "skipToManual": "דלג להגדרה ידנית", + "submit": "שלח", + "folders": "רשימת תיקיות", + "addFolder": "הוסף תיקייה", + "selectFolder": "בחר תיקייה", + "selectFolderError": "בחירת התיקייה נכשלה", + "noFoldersSelected": "לא נבחרו תיקיות", + "type": "סוג שרת", + "typeInMemory": "זיכרון (Memory)", + "typePlaceholder": "בחר סוג שרת", + "typeSse": "אירועים הנשלחים מהשרת (SSE)", + "typeStdio": "קלט ופלט סטנדרטי (Stdio)", + "update": "עדכן" + }, + "serverList": "רשימת שרתים", + "setAsDefault": "הגדר כשרת ברירת המחדל", + "setDefault": "הגדר כברירת מחדל", + "startServer": "התחל את השרת", + "stopServer": "עצור את השרת", + "stopped": "נעצר", + "sampling": { + "title": "דגימת בקשה מ-{server}", + "unknownServer": "שרת לא ידוע", + "description": "סקור את ההקשר המשותף על ידי שרת ה-MCP ובחר האם ליצור תגובה.", + "systemPrompt": "הנחיית מערכת (System prompt)", + "messagesTitle": "הקשר שיחה", + "preferencesTitle": "העדפות מודל", + "approve": "אשר", + "reject": "דחה", + "confirm": "שלח תגובה", + "confirming": "מאשר...", + "sendResponse": "שלח תגובה", + "selectModel": "בחר מודל", + "respondWith": "הגב באמצעות:", + "maxTokensInfo": "אורך תגובה מקסימלי: {maxTokens} טוקנים", + "visionWarning": "המודל שנבחר אינו תומך בקלט חזותי. אנא בחר מודל בעל יכולות ראייה לפני שתמשיך.", + "selectedModelLabel": "מגיב עם {model} ({provider})", + "unsupportedMessage": "סוג תוכן זה אינו נתמך.", + "noVisionModels": "לא מופעלים מודלים בעלי יכולת ראייה. הפעל מודל ראייה בהגדרות כדי להמשיך.", + "noModels": "לא מופעלים מודלים מתאימים. הפעל מודל ישים בהגדרות כדי להמשיך.", + "imageAlt": "תמונה {index}", + "unknownMime": "סוג MIME לא ידוע", + "unknownHint": "רמז ללא שם", + "autoApproving": "בקשת דגימת MCP מאת {server}", + "autoApproveIn": "מאשר אוטומטית בעוד {seconds} שניות באמצעות {model}", + "reviewRequest": "סקירה", + "sessionActive": "הפעלה פעילה - בקשות יאושרו אוטומטית", + "contentType": { + "text": "טקסט", + "image": "תמונה", + "audio": "שמע" + }, + "preference": { + "cost": "עדיפות עלות", + "speed": "עדיפות מהירות", + "intelligence": "עדיפות אינטליגנציה", + "hints": "רמזי מודל" + } + }, + "tabs": { + "servers": "שרתים", + "tools": "כלים" + }, + "title": "הגדרות MCP", + "inmemory": { + "Artifacts": { + "desc": "צור תוצרים (Artifacts) עשירים יותר ב-DeepChat", + "name": "תוצרים (Artifacts)" + }, + "bochaSearch": { + "desc": "Bocha Search API https://open.bochaai.com/", + "name": "Bocha Search" + }, + "buildInFileSystem": { + "desc": "אפשר ל-DeepChat אינטראקציה עם מערכת הקבצים המקומית.", + "name": "מערכת קבצים" + }, + "imageServer": { + "desc": "אפשר לכל מודל ב-DeepChat להבין וליצור תמונות.", + "name": "שירות תמונות" + }, + "braveSearch": { + "desc": "Brave Search API https://brave.com/search/api/", + "name": "Brave Search" + }, + "powerpack": { + "desc": "ספק למודלים שאילתות זמן, גלישה באינטרנט והרצת קוד מאובטחת.", + "name": "Power Pack" + }, + "difyKnowledge": { + "desc": "שירות חיפוש בסיס ידע של Dify, המסוגל לאחזר תוכן מתוך Dify Knowledge Base", + "name": "חיפוש בסיס ידע Dify" + }, + "ragflowKnowledge": { + "name": "חיפוש בסיס ידע RAGFlow", + "desc": "שירות חיפוש בסיס ידע של RAGFlow, יכול לחפש בתוכן בסיס הידע של RAGFlow" + }, + "fastGptKnowledge": { + "name": "חיפוש בסיס ידע FastGPT", + "desc": "שירות חיפוש בסיס ידע של FastGPT, יכול לחפש בתוכן בסיס הידע של FastGPT" + }, + "deepchat-inmemory/custom-prompts-server": { + "desc": "שירות הנחיות מותאמות אישית מובנה של DeepChat", + "name": "הנחיות מותאמות אישית" + }, + "deepchat-inmemory/deep-research-server": { + "desc": "מחקר עמוק מובנה ב-DeepChat המופעל על ידי Bocha Search. מומלץ להשתמש במודלים בעלי הקשר ארוך (Long-context).", + "name": "מחקר עמוק (DeepResearch)" + }, + "deepchat-inmemory/auto-prompting-server": { + "name": "הנחיה אוטומטית לפי תבנית", + "desc": "בחר אוטומטית את ההנחיה המותאמת הטובה ביותר בהתבסס על הקלט ומלא את התבנית בצורה חכמה." + }, + "deepchat-inmemory/conversation-search-server": { + "name": "חיפוש היסטוריית שיחות", + "desc": "חיפוש היסטוריית שיחות מובנה של DeepChat עבור צ'אטים והודעות עבר." + }, + "builtinKnowledge": { + "desc": "חיפוש בסיס ידע מובנה של DeepChat עבור מסמכים ומדריכים של DeepChat.", + "name": "חיפוש בסיס ידע מובנה" + }, + "deepchat-inmemory/meeting-server": { + "name": "פגישות מרובות סוכנים (Multi-Agent)", + "desc": "פגישות מובנות ב-DeepChat לאירוח דיונים מרובי סוכנים." + }, + "deepchat/apple-server": { + "desc": "אפשר למודלים להפעיל אפליקציות macOS כמו יומן, אנשי קשר, דואר, מפות, פתקים ותזכורות.", + "name": "עוזר מערכת macOS" + } + }, + "prompts": { + "noPromptsAvailable": "אין הנחיות (Prompts) זמינות", + "noDescription": "אין תיאור עדיין", + "selectPrompt": "פרטים עבור ההנחיה שנבחרה יוצגו כאן.", + "parameters": "פרמטרים", + "input": "פרמטרים", + "runningPrompt": "מביא הנחיה...", + "executeButton": "קבל הנחיה", + "resultTitle": "פרטי הנחיה", + "invalidJson": "פורמט JSON לא חוקי", + "parametersHint": "אנא הזן את הפרמטרים בפורמט JSON, תומך בעיצוב אוטומטי", + "resetToDefault": "אפס לפרמטרים ברירת מחדל", + "dialogDescription": "ניפוי באגים ובדיקת הנחיות המסופקות על ידי שרתי MCP" + }, + "resources": { + "noResourcesAvailable": "אין משאבים זמינים", + "selectResource": "בחר משאב לצפייה בתוכנו.", + "loading": "טוען...", + "loadContent": "טען תוכן", + "pleaseSelect": "לחץ לצפייה בפרטי המשאב.", + "dialogDescription": "עיין וצפה במשאבים המסופקים על ידי שרתי MCP" + }, + "errors": { + "loadConfigFailed": "טעינת תצורת MCP נכשלה", + "setEnabledFailed": "הגדרת מצב הפעלה של MCP נכשלה", + "getServerStatusFailed": "קבלת סטטוס עבור השרת {serverName} נכשלה", + "addServerFailed": "הוספת השרת נכשלה", + "updateServerFailed": "עדכון השרת נכשל", + "removeServerFailed": "הסרת השרת נכשלה", + "maxDefaultServersReached": "הגעת למספר המקסימלי של שרתי ברירת מחדל (30)", + "toggleDefaultServerFailed": "שינוי סטטוס שרת ברירת המחדל נכשל", + "resetToDefaultFailed": "שחזור לשרתי ברירת מחדל נכשל", + "toggleServerFailed": "שינוי מצב השרת {serverName} נכשל", + "loadToolsFailed": "טעינת הכלים נכשלה", + "loadPromptsFailed": "טעינת ההנחיות נכשלה", + "loadResourcesFailed": "טעינת המשאבים נכשלה", + "callToolFailed": "הקריאה לכלי {toolName} נכשלה", + "toolCallError": "שגיאה בקריאה לכלי: {error}", + "mcpDisabled": "MCP מושבת", + "getPromptFailed": "קבלת ההנחיה נכשלה", + "readResourceFailed": "קריאת המשאב נכשלה", + "promptNotFound": "הנחיה '{name}' לא נמצאה", + "emptyPromptContent": "להנחיה '{name}' אין תוכן", + "missingParameters": "חסרים פרמטרים נדרשים: {params}", + "invalidParameters": "פרמטרים לא חוקיים עבור: {params}" + }, + "market": { + "browseBuiltin": "עיין בחנות ה-MCP המובנית", + "builtinTitle": "חנות MCP", + "poweredBy": "מופעל על ידי MCPRouter", + "keyGuide": "קבל מפתח API", + "keyHelpText": "אנא עבור אל", + "keyHelpEnd": "כדי להגיש בקשה למפתח API ומלא אותו בתיבת הקלט למעלה", + "apiKeyPlaceholder": "הזן מפתח API של MCPRouter", + "apiKeyRequiredTitle": "נדרש מפתח API", + "apiKeyRequiredDesc": "אנא מלא את מפתח ה-API של MCPRouter לפני ההתקנה", + "install": "התקן", + "installed": "מותקן", + "installSuccess": "ההתקנה הצליחה", + "installFailed": "ההתקנה נכשלה", + "noMore": "אין עוד", + "empty": "אין שירותים", + "loadMore": "טען עוד", + "pullDownToLoad": "המשך למשוך למטה כדי לטעון עוד" + } +} diff --git a/src/renderer/src/i18n/he-IL/model.json b/src/renderer/src/i18n/he-IL/model.json new file mode 100644 index 000000000..f3d32b26c --- /dev/null +++ b/src/renderer/src/i18n/he-IL/model.json @@ -0,0 +1,30 @@ +{ + "search": { + "placeholder": "חפש מודלים..." + }, + "error": { + "loadFailed": "טעינת המודלים נכשלה" + }, + "type": { + "custom": "מודל מותאם אישית", + "official": "מודל רשמי" + }, + "add": { + "namePlaceholder": "שם המודל", + "idPlaceholder": "מזהה מודל (ID)", + "contextLengthPlaceholder": "אורך הקשר (Context)", + "maxTokensPlaceholder": "מקסימום טוקנים" + }, + "actions": { + "add": "הוסף מודל", + "enableAll": "הפעל הכל", + "disableAll": "השבת הכל" + }, + "tags": { + "reasoning": "חשיבה (Reasoning)", + "chat": "צ'אט", + "code": "קוד", + "writing": "כתיבה", + "analysis": "ניתוח" + } +} diff --git a/src/renderer/src/i18n/he-IL/newThread.json b/src/renderer/src/i18n/he-IL/newThread.json new file mode 100644 index 000000000..0c5c81044 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/newThread.json @@ -0,0 +1,4 @@ +{ + "greeting": "שלום!", + "prompt": "על מה תרצה לדבר?" +} diff --git a/src/renderer/src/i18n/he-IL/plan.json b/src/renderer/src/i18n/he-IL/plan.json new file mode 100644 index 000000000..d46fe794b --- /dev/null +++ b/src/renderer/src/i18n/he-IL/plan.json @@ -0,0 +1,4 @@ +{ + "completed": "הושלם", + "title": "תכנון משימה" +} diff --git a/src/renderer/src/i18n/he-IL/promptSetting.json b/src/renderer/src/i18n/he-IL/promptSetting.json new file mode 100644 index 000000000..287113a5c --- /dev/null +++ b/src/renderer/src/i18n/he-IL/promptSetting.json @@ -0,0 +1,95 @@ +{ + "title": "ניהול הנחיות (Prompt Management)", + "addTitle": "הוסף הנחיה", + "addDescription": "צור תבנית הנחיה מותאמת אישית חדשה", + "editTitle": "ערוך הנחיה", + "editDescription": "שנה את תבנית ההנחיה שנבחרה", + "name": "שם", + "namePlaceholder": "הזן שם עבור ההנחיה שלך", + "description": "תיאור", + "descriptionPlaceholder": "אנא הזן תיאור (אופציונלי)", + "promptContent": "הנחיה (Prompt)", + "contentPlaceholder": "אנא הזן את תוכן ההנחיה", + "basicInfo": "מידע בסיסי", + "contentTip": "תומך במצייני מקום של משתנים כמו {openBrace}{openBrace}variable{closeBrace}{closeBrace}, ניתן להגדיר פרמטרים מתאימים בסעיף הפרמטרים", + "noPrompt": "אין הנחיות עדיין", + "noPromptDesc": "לחץ על כפתור \"+\" בפינה העליונה כדי ליצור את ההנחיה הראשונה שלך.", + "active": "פעיל", + "noDescription": "אין תיאור", + "customDate": "מותאם אישית", + "showMore": "הצג עוד", + "showLess": "הצג פחות", + "export": "ייצוא", + "import": "ייבוא", + "exportSuccess": "הייצוא הושלם בהצלחה", + "exportFailed": "הייצוא נכשל", + "importSuccess": "הייבוא הושלם בהצלחה", + "importFailed": "הייבוא נכשל", + "importStats": "נוספו {added}, עודכנו {updated} הנחיות", + "parameters": "פרמטרים", + "addParameter": "הוסף פרמטר", + "noParameters": "אין פרמטרים", + "noParametersDesc": "לחץ על הכפתור למעלה כדי להוסיף פרמטרים, שבהם ניתן להשתמש ליצירת מצייני מקום למשתנים בהנחיות", + "parameterName": "שם הפרמטר", + "parameterDescription": "תיאור הפרמטר", + "parameterNamePlaceholder": "אנא הזן שם פרמטר", + "parameterDescriptionPlaceholder": "אנא הזן תיאור פרמטר", + "required": "נדרש", + "characters": "תווים", + "fileManagement": "ניהול קבצים", + "uploadFromDevice": "העלה מהמכשיר", + "uploadFromDeviceDesc": "תומך בטקסט, מסמכים, CSV ועוד.", + "uploadedFiles": "קבצים שהועלו", + "noFiles": "אין קבצים", + "noFilesUploadDesc": "לחץ למעלה להעלאת קבצים", + "uploadSuccess": "ההעלאה הושלמה", + "uploadedCount": "הועלו {count} קבצים", + "confirmDelete": "האם אתה בטוח שברצונך למחוק את ההנחיה \"{name}\"?", + "confirmDeleteDescription": "לא ניתן לבטל פעולה זו. ההנחיה תימחק לצמיתות.", + "confirmDeleteSystemPrompt": "האם אתה בטוח שברצונך למחוק את הנחיית המערכת \"{name}\"?", + "confirmDeleteSystemPromptDescription": "לא ניתן לבטל פעולה זו. הנחיית המערכת תימחק לצמיתות.", + "deleteSuccess": "ההנחיה נמחקה", + "deleteFailed": "מחיקת ההנחיה נכשלה", + "inactive": "לא פעיל", + "clickToEnable": "לחץ להפעלה", + "clickToDisable": "לחץ להשבתה", + "enableSuccess": "הנחיה הופעלה", + "disableSuccess": "הנחיה הושבתה", + "toggleFailed": "שינוי הסטטוס נכשל", + "enablePrompt": "הפעל הנחיה זו", + "sourceLocal": "מקומי", + "sourceImported": "מיובא", + "sourceBuiltin": "מובנה", + "defaultSystemPrompt": "הנחיית מערכת ברירת מחדל", + "defaultSystemPromptPlaceholder": "הזן את הנחיית המערכת שתשמש כברירת מחדל לכל השיחות החדשות...", + "defaultSystemPromptDescription": "הנחיה זו תחול על כל השיחות החדשות. ניתן לשנות אותה בעת יצירת שיחה. שים לב שהגדרה זו תיכנס לתוקף בפעם הבאה שתיצור שיחה חדשה.", + "typing": "מקליד...", + "saving": "שומר...", + "saved": "נשמר", + "saveDefaultPromptFailed": "שמירת הנחיית מערכת ברירת המחדל נכשלה", + "systemPrompts": "הנחיות מערכת", + "customPrompts": "הנחיות מותאמות אישית", + "addSystemPrompt": "הוסף הנחיית מערכת", + "addCustomPrompt": "הוסף הנחיה מותאמת אישית", + "editSystemPrompt": "ערוך הנחיית מערכת", + "addSystemPromptDesc": "צור הנחיית מערכת חדשה", + "editSystemPromptDesc": "שנה את הנחיית המערכת שנבחרה", + "selectSystemPrompt": "בחר הנחיית מערכת", + "systemPromptDescription": "הנחיית המערכת שנבחרה תשמש כברירת מחדל לשיחות חדשות", + "emptySystemPromptOption": "ללא הנחיית מערכת", + "emptySystemPromptDescription": "כאשר אפשרות זו נבחרה, שיחות חדשות יתחילו ללא הנחיית מערכת.", + "preview": "תצוגה מקדימה", + "systemPromptChanged": "הנחיית המערכת שונתה בהצלחה", + "systemPromptChangeFailed": "שינוי הנחיית המערכת נכשל", + "systemPromptAdded": "הנחיית מערכת נוספה בהצלחה", + "systemPromptAddedAndSwitched": "הנחיית מערכת נוספה והוגדרה אוטומטית כברירת מחדל", + "systemPromptUpdated": "הנחיית מערכת עודכנה בהצלחה", + "systemPromptSaveFailed": "שמירת הנחיית המערכת נכשלה", + "systemPromptDeleted": "הנחיית המערכת נמחקה בהצלחה", + "systemPromptDeleteFailed": "מחיקת הנחיית המערכת נכשלה", + "systemPromptEditTip": "שמירה אוטומטית בעת אובדן פוקוס לאחר עריכה", + "resetToDefault": "אפס לברירת מחדל", + "resetToDefaultSuccess": "אופס לתוכן ברירת המחדל בהצלחה", + "resetToDefaultFailed": "האיפוס לברירת המחדל נכשל", + "parameterRequired": "פרמטרים נדרשים" +} diff --git a/src/renderer/src/i18n/he-IL/routes.json b/src/renderer/src/i18n/he-IL/routes.json new file mode 100644 index 000000000..fa3db69b0 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/routes.json @@ -0,0 +1,17 @@ +{ + "chat": "צ'אט", + "welcome": "ברוכים הבאים", + "playground": "אזור ניסויים (Playground)", + "settings": "הגדרות", + "settings-common": "הגדרות כלליות", + "settings-provider": "ספקים", + "settings-mcp": "הגדרות MCP", + "settings-database": "נתונים", + "settings-about": "אודות", + "settings-shortcut": "קיצורי מקשים", + "settings-display": "תצוגה", + "settings-knowledge-base": "בסיס ידע", + "settings-prompt": "הנחיות (Prompts)", + "settings-mcp-market": "חנות MCP", + "settings-acp": "סוכני ACP" +} diff --git a/src/renderer/src/i18n/he-IL/settings.json b/src/renderer/src/i18n/he-IL/settings.json new file mode 100644 index 000000000..4084f2e65 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/settings.json @@ -0,0 +1,964 @@ +{ + "title": "הגדרות", + "common": { + "title": "הגדרות כלליות", + "resetData": "אפס נתונים", + "language": "שפה", + "languageSelect": "בחר שפה", + "searchEngine": "מנוע חיפוש", + "searchEngineSelect": "בחר מנוע חיפוש", + "searchPreview": "תצוגה מקדימה של חיפוש", + "searchAssistantModel": "מודל עוזר", + "selectModel": "בחר מודל", + "proxyMode": "מצב פרוקסי", + "proxyModeSelect": "בחר מצב פרוקסי", + "proxyModeSystem": "פרוקסי מערכת", + "proxyModeNone": "ללא פרוקסי", + "proxyModeCustom": "פרוקסי מותאם אישית", + "customProxyUrl": "כתובת URL לפרוקסי מותאם", + "customProxyUrlPlaceholder": "דוגמה: http://127.0.0.1:7890", + "invalidProxyUrl": "כתובת פרוקסי לא חוקית, אנא הזן כתובת http/https תקינה", + "addCustomSearchEngine": "הוסף מנוע חיפוש מותאם", + "addCustomSearchEngineDesc": "הוסף מנוע חיפוש חדש על ידי מתן שם וכתובת URL לחיפוש. הכתובת חייבת לכלול את {query} כמציין מקום לשאילתה.", + "searchEngineName": "שם מנוע החיפוש", + "searchEngineNamePlaceholder": "הזן את שם מנוע החיפוש", + "searchEngineUrl": "כתובת URL לחיפוש", + "searchEngineUrlPlaceholder": "דוגמה: https://a.com/search?q={'{'}query{'}'}", + "searchEngineUrlError": "הכתובת חייבת לכלול את {'{'}query{'}'} כמציין מקום לשאילתה", + "deleteCustomSearchEngine": "מחק מנוע חיפוש מותאם", + "deleteCustomSearchEngineDesc": "האם אתה בטוח שברצונך למחוק את מנוע החיפוש המותאם \"{name}\"? לא ניתן לבטל פעולה זו.", + "testSearchEngine": "בדוק מנוע חיפוש", + "testSearchEngineDesc": "חיפוש בדיקה עבור \"weather\" יבוצע באמצעות מנוע החיפוש {engine}.", + "testSearchEngineNote": "אם דף החיפוש דורש התחברות או פעולות אחרות, ניתן לבצע אותן בחלון הבדיקה. אנא סגור את חלון הבדיקה בסיום.", + "theme": "ערכת נושא", + "themeSelect": "בחר ערכת נושא", + "themeLight": "בהיר", + "themeDark": "כהה", + "themeSystem": "עקוב אחר המערכת", + "closeToQuit": "צא מהאפליקציה בעת סגירת החלון", + "contentProtectionDialogTitle": "אשר שינוי הגנת מסך", + "contentProtectionEnableDesc": "מנע מיישומי שיתוף מסך ללכוד את חלון DeepChat כדי לעזור להגן על פרטיותך. לא כל האפליקציות מכבדות הגדרה זו; בסביבות מסוימות עשוי להופיע חלון שחור.", + "contentProtectionDisableDesc": "אפשר ליישומי שיתוף מסך ללכוד את חלון DeepChat.", + "contentProtectionRestartNotice": "שינוי הגדרה זו יגרום להפעלה מחדש של האפליקציה. האם להמשיך?", + "soundEnabled": "הפעל אפקטים קוליים", + "copyWithCotEnabled": "העתק פרטי COT (שרשרת מחשבה)", + "traceDebugEnabled": "מעקב אחר קריאה (Trace Call)", + "loggingEnabled": "הפעל רישום לוגים", + "loggingDialogTitle": "אשר שינוי הגדרת רישום לוגים", + "loggingEnableDesc": "הפעלת רישום לוגים תעזור לנו לאבחן בעיות ולשפר את האפליקציה. קבצי הלוג עשויים להכיל מידע רגיש.", + "loggingDisableDesc": "השבתת רישום לוגים תפסיק את איסוף יומני האפליקציה.", + "webContentLengthLimit": "מגבלת אורך תוכן אינטרנט", + "webContentLengthLimitHint": "(הגדר ל-0 ללא הגבלה)", + "charactersUnit": "תווים", + "webContentLengthLimitTooltip": "הגדר את האורך המקסימלי של טקסט המופק מדפי אינטרנט (מספר תווים), טווח: 0-50000. הגדרה ל-0 משמעותה ללא הגבלה ושליפת תוכן האינטרנט המלא; ערכים גבוהים יותר מספקים תוכן שלם יותר אך עשויים להגדיל את זמן העיבוד ואת השימוש בטוקנים.", + "loggingRestartNotice": "שינוי הגדרה זו יגרום להפעלה מחדש של האפליקציה. האם להמשיך?", + "openLogFolder": "פתח תיקיית לוגים", + "shortcut": { + "newChat": "צור צ'אט חדש", + "title": "הגדרות קיצורי מקשים" + }, + "notifications": "התראות מערכת", + "notificationsDesc": "כאשר DeepChat אינו בחזית, אם נוצרת תשובה, תישלח התראת מערכת", + "contentProtection": "הגנה מפני לכידת מסך", + "fileMaxSize": "גודל קובץ מקסימלי", + "fileMaxSizeHint": "מגביל את הגודל המקסימלי של קובץ בודד המועלה" + }, + "data": { + "title": "הגדרות נתונים", + "syncEnable": "הפעל סנכרון נתונים", + "syncFolder": "תיקיית סנכרון", + "openSyncFolder": "פתח תיקיית סנכרון", + "lastSyncTime": "זמן סנכרון אחרון", + "never": "מעולם לא", + "startBackup": "גבה כעת", + "backingUp": "מגבה...", + "importData": "ייבוא נתונים", + "incrementImport": "ייבוא מצטבר (Incremental)", + "overwriteImport": "ייבוא דורס (Overwrite)", + "backupSelectLabel": "בחר גיבוי", + "backupSelectDescription": "בחר את תמונת המצב של הגיבוי לייבוא.", + "selectBackupPlaceholder": "בחר גיבוי", + "noBackupsAvailable": "אין גיבויים זמינים. בצע גיבוי תחילה.", + "importConfirmTitle": "אשר ייבוא נתונים", + "importConfirmDescription": "הייבוא ידרוס את כל הנתונים הנוכחיים, כולל היסטוריית צ'אט והגדרות. ודא שגיבית נתונים חשובים. יהיה עליך להפעיל מחדש את האפליקציה לאחר הייבוא.", + "importing": "מייבא...", + "confirmImport": "אשר ייבוא", + "importSuccessTitle": "הייבוא הושלם בהצלחה", + "importErrorTitle": "הייבוא נכשל", + "resetData": "אפס נתונים", + "resetConfirmTitle": "אשר איפוס נתונים", + "resetConfirmDescription": "אנא בחר את סוג הנתונים לאיפוס. לא ניתן לבטל פעולה זו והאפליקציה תופעל מחדש אוטומטית לאחר האיפוס.", + "resetChatData": "אפס נתוני צ'אט", + "resetChatDataDesc": "מחק את כל היסטוריית הצ'אט ורשומות השיחות", + "resetKnowledgeData": "אפס נתוני בסיס ידע", + "resetKnowledgeDataDesc": "מחק את כל קבצי בסיס הידע ונתוני הוקטורים", + "resetConfig": "אפס תצורה", + "resetConfigDesc": "מחק את כל הגדרות האפליקציה, תצורות המודלים והנחיות מותאמות אישית", + "resetAll": "איפוס מלא", + "resetAllDesc": "מחק את כל הנתונים כולל היסטוריית צ'אט, תצורות וקבצי מטמון", + "resetting": "מאפס...", + "confirmReset": "אשר איפוס", + "resetCompleteDevTitle": "איפוס הנתונים הושלם", + "resetCompleteDevMessage": "אנא הפעל מחדש ידנית את האפליקציה במצב פיתוח. עצור את התהליך הנוכחי והרץ שוב pnpm run dev", + "toast": { + "backupSuccessTitle": "גיבוי הושלם בהצלחה", + "backupSuccessMessage": "הנתונים גובו בהצלחה" + } + }, + "model": { + "title": "הגדרות מודל", + "systemPrompt": { + "label": "הנחיית מערכת", + "placeholder": "אנא הזן את הנחיית המערכת...", + "description": "הגדר את הנחיית המערכת עבור עוזר ה-AI כדי להגדיר את התנהגותו ותפקידו" + }, + "temperature": { + "label": "טמפרטורת מודל", + "description": "שולט באקראיות של הפלט; ערכים גבוהים יותר מייצרים תשובות יצירתיות יותר" + }, + "contextLength": { + "label": "אורך הקשר (Context)", + "description": "הגדר את האורך המקסימלי של הקשר השיחה" + }, + "responseLength": { + "label": "אורך תגובה", + "description": "הגדר את האורך המקסימלי של תגובת ה-AI" + }, + "artifacts": { + "description": "הפעלת תכונת ה-Artifacts (תוצרים) מאפשרת ל-AI ליצור תוכן עשיר יותר", + "title": "תוצרים (Artifacts)" + }, + "addModel": "הוסף מודל", + "configureModel": "הגדר מודל", + "modelList": "רשימת מודלים", + "provider": "ספק שירות", + "providerSetting": "הגדרות ספק שירות", + "selectModel": "בחר מודל", + "modelConfig": { + "cancel": "ביטול", + "contextLength": { + "description": "הגדר את אורך ההקשר שהמודל יכול לטפל בו", + "label": "אורך הקשר" + }, + "description": "שים לב שתצורה זו תקפה רק למודל הנוכחי ולא תשפיע על מודלים אחרים. אנא שנה אותה בזהירות. פרמטרים שגויים עלולים לגרום למודל לא לפעול כראוי.", + "name": { + "label": "שם המודל", + "description": "השם המוצג של המודל", + "placeholder": "הזן שם מודל", + "required": "שם המודל נדרש", + "readonly": "שם המודל (קריאה בלבד)" + }, + "id": { + "label": "מזהה מודל (ID)", + "description": "המזהה הייחודי של המודל", + "placeholder": "הזן מזהה מודל", + "required": "מזהה מודל נדרש", + "readonly": "מזהה מודל (קריאה בלבד)", + "duplicate": "מודל עם מזהה זה כבר קיים" + }, + "createTitle": "הוסף מודל מותאם אישית", + "editTitle": "ערוך תצורת מודל - {name}", + "functionCall": { + "description": "האם המודל תומך בקריאות לפונקציות באופן טבעי (DeepChat יסמלץ אוטומטית קריאות לפונקציות לאחר כיבוי אפשרות זו)", + "label": "קריאות לפונקציות" + }, + "maxTokens": { + "description": "הגדר את המספר המקסימלי של טוקנים לפלט יחיד של המודל", + "label": "אורך פלט מקסימלי" + }, + "reasoning": { + "description": "האם המודל תומך ביכולת חשיבה (Reasoning)?", + "label": "יכולת חשיבה" + }, + "enableSearch": { + "label": "חיפוש אינטרנט", + "description": "אפשר למודל לחפש באינטרנט מידע עדכני" + }, + "forcedSearch": { + "label": "חיפוש כפוי", + "description": "כפה על המודל לבצע חיפוש באינטרנט; כשמושבת, המודל מחליט אוטומטית" + }, + "searchStrategy": { + "label": "אסטרטגיית חיפוש", + "description": "בחר מצב ביצועי חיפוש: turbo מאזן מהירות ויעילות, max מספק תוצאות חיפוש אופטימליות", + "placeholder": "בחר אסטרטגיית חיפוש", + "options": { + "turbo": "Turbo - איזון בין מהירות תגובה ליעילות חיפוש (מומלץ)", + "max": "Max - מצב ביצועים גבוהים, מספק תוצאות חיפוש אופטימליות" + } + }, + "thinkingBudget": { + "label": "תקציב חשיבה", + "description": "הגדר את אורך הטוקנים המקסימלי לתהליך החשיבה כדי לשלוט בעומק החשיבה", + "placeholder": "הזן ערך תקציב חשיבה", + "range": "טווח: {min} - {max}", + "validation": { + "required": "אנא הזן ערך תקציב חשיבה", + "minValue": "ערך תקציב החשיבה נמוך מהמינימום", + "maxValue": "ערך תקציב החשיבה אינו יכול לעלות על {max}" + } + }, + "resetConfirm": { + "confirm": "אשר איפוס", + "message": "האם אתה בטוח שברצונך לאפס את תצורת המודל הזה לברירת המחדל? \nפעולה זו בלתי הפיכה.", + "title": "אשר איפוס" + }, + "reasoningEffort": { + "label": "מאמץ חשיבה", + "description": "שולט בעומק החשיבה של המודל; מאמץ גבוה יותר מפיק תוצאות טובות יותר אך תגובות איטיות יותר", + "placeholder": "בחר מאמץ חשיבה", + "options": { + "minimal": "מינימלי - התגובה המהירה ביותר", + "low": "נמוך - מאמץ נמוך", + "medium": "בינוני - מאמץ בינוני", + "high": "גבוה - מאמץ גבוה" + } + }, + "verbosity": { + "label": "רמת פירוט", + "description": "שולט ברמת הפרטים ואורך תשובות המודל", + "placeholder": "בחר רמת פירוט", + "options": { + "low": "נמוכה - תשובות תמציתיות", + "medium": "בינונית - פירוט מאוזן", + "high": "גבוהה - תשובות מפורטות" + } + }, + "resetToDefault": "אפס לברירת מחדל", + "saveConfig": "שמור תצורה", + "useModelDefault": "השתמש בתצורת ברירת המחדל של המודל", + "currentUsingModelDefault": "משתמש כעת בתצורת ברירת המחדל של המודל", + "temperature": { + "description": "שלוט באקראיות הפלט. רוב המודלים הם 0-1, וחלקם תומכים בין 0-2. ערכים גבוהים יותר מגבירים את האקראיות.", + "label": "טמפרטורה" + }, + "title": "פרמטרים מותאמים למודל", + "type": { + "description": "בחר את סוג המודל", + "label": "סוג מודל", + "options": { + "chat": "מודל שפה (Chat)", + "embedding": "מודל הטמעה (Embedding)", + "imageGeneration": "מודל יצירת תמונות", + "rerank": "מודל דירוג מחדש (Rerank)" + } + }, + "validation": { + "contextLengthMax": "אורך ההקשר אינו יכול לעלות על 10000000", + "contextLengthMin": "אורך ההקשר חייב להיות גדול מ-0", + "contextLengthRequired": "אורך ההקשר אינו יכול להיות ריק", + "maxTokensMax": "אורך הפלט המקסימלי אינו יכול לעלות על 1000000", + "maxTokensMin": "אורך הפלט המקסימלי חייב להיות גדול מ-0", + "maxTokensRequired": "אורך הפלט המקסימלי אינו יכול להיות ריק", + "temperatureMax": "הטמפרטורה חייבת להיות קטנה או שווה ל-2", + "temperatureMin": "הטמפרטורה חייבת להיות גדולה או שווה ל-0", + "temperatureRequired": "הטמפרטורה אינה יכולה להיות ריקה" + }, + "vision": { + "description": "האם המודל תומך ביכולת חזותית?", + "label": "יכולת חזותית" + }, + "searchLimit": { + "label": "מגבלת חיפוש", + "description": "מגבלת מודל: הפעלת חיפוש באינטרנט תשבית קריאות לפונקציות כלים" + } + } + }, + "provider": { + "search": "חפש פלטפורמות ספקים...", + "enable": "הפעל שירות", + "enabled": "מופעל", + "disabled": "מושבת", + "urlPlaceholder": "אנא הזן כתובת API", + "keyPlaceholder": "אנא הזן מפתח API", + "accessKeyIdPlaceholder": "אנא הזן AWS Access Key ID", + "secretAccessKeyPlaceholder": "אנא הזן AWS Secret Access Key", + "regionPlaceholder": "אנא הזן אזור AWS", + "vertexProjectId": "מזהה פרויקט (Project ID)", + "vertexProjectIdPlaceholder": "אנא הזן את מזהה הפרויקט שלך ב-Google Cloud", + "vertexLocation": "אזור", + "vertexLocationPlaceholder": "אנא הזן אזור (למשל us-central1)", + "vertexServiceEmail": "אימייל חשבון שירות", + "vertexServiceEmailPlaceholder": "אנא הזן את אימייל חשבון השירות", + "vertexPrivateKey": "מפתח פרטי של חשבון שירות", + "vertexPrivateKeyPlaceholder": "הדבק את המפתח הפרטי (תומך בשורה אחת \\n)", + "vertexApiVersion": "גרסת API", + "vertexEndpointMode": "מצב נקודת קצה", + "vertexEndpointStandard": "סטנדרטי (נקודת קצה אזורית)", + "vertexEndpointExpress": "אקספרס (נקודת קצה גלובלית)", + "verifyKey": "אמת מפתח", + "howToGet": "כיצד להשיג", + "getKeyTip": "אנא בקר ב", + "getKeyTipEnd": "כדי לקבל מפתח API", + "urlFormat": "דוגמת API: {defaultUrl}", + "modelList": "רשימת מודלים", + "enableModels": "הפעל מודלים", + "disableAllModels": "השבת את כל המודלים", + "modelsEnabled": "מודלים הופעלו", + "noModelsEnabled": { + "title": "אין מודלים מופעלים", + "description": "אנא לחץ על כפתור \"הפעל מודלים\" כדי לבחור ידנית את המודלים שברצונך להשתמש בהם." + }, + "verifyLink": "אמת קישור", + "syncModelsFailed": "סנכרון המודלים נכשל...", + "addCustomProvider": "הוסף ספק מותאם אישית", + "delete": "מחק", + "stopModel": "עצור מודל", + "pulling": "מושך...", + "runModel": "הרץ מודל", + "dialog": { + "disableModel": { + "title": "אשר השבתת מודל", + "content": "האם אתה בטוח שברצונך להשבית את המודל \"{name}\"?", + "confirm": "השבת" + }, + "disableAllModels": { + "title": "אשר השבתת כל המודלים", + "content": "האם אתה בטוח שברצונך להשבית את כל המודלים?", + "confirm": "השבת הכל" + }, + "configModels": { + "title": "הגדר רשימת מודלים", + "description": "בחר מודלים להפעלה או השבתה" + }, + "verify": { + "missingFields": "אנא הזן מפתח API וכתובת API", + "failed": "האימות נכשל", + "success": "האימות עבר בהצלחה", + "failedDesc": "אימות מפתח ה-API או התצורה נכשל, אנא בדוק את ההגדרות שלך", + "successDesc": "מפתח ה-API והתצורה אומתו בהצלחה, מוכן לשימוש", + "connectionError": "שגיאת חיבור, אנא בדוק את חיבור הרשת ואת כתובת ה-API", + "serverError": "שגיאת שרת, אנא נסה שוב מאוחר יותר", + "unauthorized": "האימות נכשל, מפתח ה-API אינו חוקי או פג תוקף" + }, + "addCustomProvider": { + "title": "הוסף ספק מותאם אישית", + "description": "אנא מלא את המידע הדרוש עבור הספק", + "name": "שם", + "namePlaceholder": "אנא הזן את שם הספק", + "apiType": "סוג API", + "apiTypePlaceholder": "אנא בחר את סוג ה-API", + "apiKey": "מפתח API", + "apiKeyPlaceholder": "אנא הזן את מפתח ה-API", + "baseUrl": "כתובת בסיס ל-API", + "baseUrlPlaceholder": "אנא הזן את כתובת הבסיס ל-API", + "enable": "הפעל ספק" + }, + "deleteProvider": { + "title": "אשר מחיקת ספק", + "content": "האם אתה בטוח שברצונך למחוק את הספק \"{name}\"? לא ניתן לבטל פעולה זו.", + "confirm": "מחק" + }, + "deleteModel": { + "title": "אשר מחיקת מודל", + "content": "האם אתה בטוח שברצונך למחוק את המודל \"{name}\"? לא ניתן לבטל פעולה זו.", + "confirm": "מחק" + }, + "pullModel": { + "title": "משיכת מודל (Pull)", + "description": "בחר מודלים להורדה מקומית", + "pull": "משוך" + }, + "modelCheck": { + "title": "בדיקת מודל", + "description": "בחר מודל לבדיקת קישוריות וזמינות", + "model": "בחר מודל", + "modelPlaceholder": "אנא בחר מודל לבדיקה", + "test": "התחל בדיקה", + "checking": "בודק...", + "success": "בדיקת המודל הצליחה", + "failed": "בדיקת המודל נכשלה", + "noModels": "אין מודלים זמינים עבור ספק זה" + } + }, + "pullModels": "משוך מודלים", + "refreshModels": "רענן מודלים", + "modelsRunning": "מודלים רצים", + "runningModels": "מודלים רצים", + "noRunningModels": "אין מודלים רצים", + "deleteModel": "מחק מודל", + "deleteModelConfirm": "האם אתה בטוח שברצונך למחוק את המודל \"{name}\"? לא ניתן לבטל פעולה זו.", + "noLocalModels": "אין מודלים מקומיים", + "localModels": "מודלים מקומיים", + "azureApiVersion": "גרסת API", + "safety": { + "title": "הגדרות בטיחות", + "blockHighest": "חסום סיכון גבוה", + "blockMost": "חסום סיכון בינוני", + "blockNone": "לא נחסם", + "blockSome": "חסום סיכון נמוך" + }, + "serverList": "רשימת שרתים", + "totalServers": "סה\"כ שרתים", + "addServer": "הוסף שרת", + "autoStart": "הפעלה אוטומטית", + "githubCopilotAuth": "אימות GitHub Copilot", + "githubCopilotConnected": "GitHub Copilot מחובר", + "githubCopilotNotConnected": "GitHub Copilot אינו מחובר", + "loginWithGitHub": "התחבר עם GitHub", + "loggingIn": "מתחבר...", + "githubCopilotLoginTip": "אשר ל-DeepChat לגשת למנוי GitHub Copilot שלך. ההרשאות 'read:user' ו-'read:org' נדרשות כדי לגשת ל-API של Copilot.", + "loginSuccess": "ההתחברות הצליחה", + "loginFailed": "ההתחברות נכשלה", + "tokenValid": "הטוקן תקין", + "tokenInvalid": "הטוקן אינו תקין", + "disconnect": "התנתק", + "disconnected": "נותק בהצלחה", + "disconnectFailed": "הניתוק נכשל", + "keyStatus": { + "remaining": "מכסה נותרת", + "usage": "בשימוש" + }, + "refreshingModels": "מרענן...", + "toast": { + "modelRunning": "המודל פועל", + "modelRunningDesc": "אנא עצור את המודל {model} תחילה ואז מחק אותו.", + "backupSuccessTitle": "הגיבוי הושלם", + "backupSuccessMessage": "הגיבוי נשמר ב-{time} ({size})", + "importSuccessTitle": "הייבוא הושלם", + "importSuccessMessage": "יובאו בהצלחה {count} שיחות" + }, + "modelscope": { + "mcpSync": { + "title": "סנכרן שירותי MCP", + "description": "סנכרן שרתי MCP מ-ModelScope לתצורה המקומית, מה שמאפשר הוספה מהירה של כלי MCP נפוצים.", + "sync": "התחל סנכרון", + "syncing": "מסנכרן...", + "pageSize": "גודל עמוד", + "imported": "יובאו {count} שירותים", + "skipped": "דולגו {count} שירותים", + "errors": "{count} שגיאות", + "errorDetails": "פרטי שגיאה", + "noApiKey": "אנא הגדר מפתח API של ModelScope תחילה", + "noServersFound": "לא נמצאו שירותי MCP זמינים", + "authenticationFailed": "האימות נכשל, אנא בדוק את מפתח ה-API", + "convertingServers": "ממיר תצורת שרת...", + "fetchingServers": "מקבל את רשימת שרתי ה-MCP...", + "importingServers": "מייבא תצורת שרת...", + "noOperationalUrls": "לא נמצאה כתובת הפעלה זמינה", + "pageNumber": "מספר עמוד", + "pageNumberPlaceholder": "אנא הזן את מספר העמוד", + "serverAlreadyExists": "השרת כבר קיים, מדלג על ייבוא", + "syncComplete": "הסנכרון הושלם", + "invalidServerData": "נתוני שרת לא חוקיים" + }, + "apiKey": "מפתח API", + "apiKeyHelper": "קבל את מפתח ה-API שלך במסוף ModelScope", + "apiKeyPlaceholder": "אנא הזן מפתח API של ModelScope", + "baseUrl": "כתובת API", + "baseUrlHelper": "כתובת שירות ה-API של ModelScope", + "connected": "מחובר", + "connecting": "מתחבר...", + "description": "ModelScope היא פלטפורמת שיתוף מודל-כשירות שהושקה על ידי Alibaba Damo Academy", + "details": { + "apiConfig": "תצורת API", + "mcpSync": "סנכרון MCP", + "modelManagement": "ניהול מודלים", + "operationalDescription": "סנכרן שרתי MCP שניתן להשתמש בהם ישירות בפלטפורמת ModelScope", + "operationalServers": "שרתים פועלים", + "rateLimitConfig": "תצורת מגבלת קצב", + "safetySettings": "הגדרות אבטחה", + "specialConfig": "תצורה מיוחדת", + "syncFromModelScope": "סנכרן מ-ModelScope", + "title": "פרטי הגדרות ספק" + }, + "invalidKey": "מפתח API לא חוקי", + "keyRequired": "אנא הזן מפתח API", + "name": "ModelScope", + "networkError": "שגיאת חיבור רשת", + "notConnected": "לא מחובר", + "verifyFailed": "האימות נכשל", + "verifySuccess": "האימות הצליח" + }, + "anthropicApiKeyTip": "אנא עבור למסוף Anthropic כדי לקבל את מפתח ה-API שלך", + "anthropicConnected": "Anthropic מחובר", + "anthropicNotConnected": "Anthropic אינו מחובר", + "anthropicOAuthTip": "לחץ כדי לאשר ל-DeepChat לגשת לחשבון Anthropic שלך", + "oauthLogin": "התחברות OAuth", + "authMethod": "שיטת אימות", + "authMethodPlaceholder": "בחר שיטת אימות", + "apiKeyLabel": "מפתח API", + "apiUrlLabel": "כתובת API", + "anthropicOAuthFlowTip": "המערכת תפתח אוטומטית את חלון האישור. אנא חזור והזן את קוד האישור לאחר האישור.", + "anthropicBrowserOpened": "הדפדפן החיצוני פתוח", + "anthropicCodeInstruction": "אנא השלם את האישור בדפדפן החיצוני והדבק את קוד האישור שהתקבל בתיבת הקלט למטה", + "browserOpenedSuccess": "הדפדפן החיצוני נפתח, אנא השלם את האישור", + "codeRequired": "אנא הזן את קוד האישור", + "inputOAuthCode": "הזן את קוד האישור", + "codeExchangeFailed": "החלפת קוד האישור נכשלה", + "invalidCode": "קוד אישור לא חוקי", + "oauthCodeHint": "אנא הדבק את קוד האישור כאן לאחר השלמת האישור בדפדפן חיצוני", + "oauthCodePlaceholder": "אנא הזן את קוד האישור...", + "verifyConnection": "אמת חיבור", + "manageModels": "נהל מודלים", + "anthropicOAuthActiveTip": "אימות OAuth מופעל, ניתן להשתמש בשירותי Anthropic ישירות", + "oauthVerifySuccess": "חיבור OAuth אומת בהצלחה", + "oauthVerifyFailed": "אימות חיבור OAuth נכשל", + "configurationSaved": "התצורה נשמרה", + "configurationUpdated": "התצורה עודכנה", + "dataRefreshed": "הנתונים רועננו", + "operationFailed": "הפעולה נכשלה", + "operationSuccess": "הפעולה הצליחה", + "settingsApplied": "ההגדרות הוחלו", + "bedrockLimitTip": "* נתמך רק עבור Anthropic Claude (כולל מודלי Opus, Sonnet, Haiku)", + "bedrockVerifyTip": "DeepChat משתמש ב-Claude 3.5 Sonnet לאימות. אם אין לך הרשאה להפעיל אותו, האימות ייכשל. זה לא ישפיע על השימוש במודלים אחרים." + }, + "knowledgeBase": { + "title": "הגדרות בסיס ידע", + "addKnowledgeBase": "הוסף בסיס ידע", + "selectKnowledgeBaseType": "אנא בחר את סוג בסיס הידע להוספה", + "difyDescription": "בסיס ידע Dify עוזר לך לנהל ולהשתמש בנתוני מסמכים", + "comingSoon": "בקרוב", + "featureNotAvailable": "תכונה זו אינה זמינה עדיין", + "addDifyConfig": "הוסף תצורת Dify", + "apiKey": "מפתח API", + "datasetId": "מזהה ערכת נתונים (Dataset ID)", + "endpoint": "נקודת קצה (API Endpoint)", + "configAdded": "תצורה נוספה", + "configAddedDesc": "תצורת {name} נוספה בהצלחה", + "addConfig": "הוסף תצורה", + "moreComingSoon": "סוגי בסיסי ידע נוספים יגיעו בקרוב", + "configUpdated": "תצורה עודכנה", + "configUpdatedDesc": "תצורת {name} עודכנה בהצלחה", + "descriptionPlaceholder": "דוגמה: בסיס ידע לתיעוד מוצרי החברה", + "ragflowTitle": "בסיס ידע RAGFlow", + "ragflowDescription": "RAGFlow היא מערכת ניהול בסיס ידע חזקה התומכת בשיטות אחזור מרובות ותכונות ניהול מסמכים.", + "addRagflowConfig": "הוסף תצורת RAGFlow", + "editRagflowConfig": "ערוך תצורת RAGFlow", + "dify": "בסיס ידע Dify", + "editDifyConfig": "שנה את תצורת Dify", + "fastgptTitle": "בסיס ידע FastGPT", + "fastgptDescription": "FastGPT היא מערכת ניהול בסיס ידע חזקה התומכת בשיטות אחזור מרובות ותכונות ניהול מסמכים.", + "addFastGptConfig": "הוסף תצורת FastGPT", + "editFastGptConfig": "ערוך תצורת FastGPT", + "builtInKnowledgeDescription": "בסיס הידע המובנה מספק יישומים פשוטים המאפשרים פונקציות בסיסיות בסביבה לא מקוונת.", + "builtInKnowledgeTitle": "בסיס ידע מובנה", + "addBuiltinKnowledgeConfig": "הוסף תצורת בסיס ידע מובנה", + "editBuiltinKnowledgeConfig": "ערוך את תצורת בסיס הידע המובנה", + "chunkSize": "גודל מקטע (Chunk)", + "chunkSizeHelper": "חתוך את המסמך למקטעים, גודל כל מקטע לא יכול לעלות על מגבלת ההקשר של המודל", + "chunkOverlap": "גודל חפיפה", + "chunkOverlapHelper": "כמות התוכן החוזר בין מקטעי טקסט סמוכים מבטיחה שעדיין קיים הקשר בין מקטעי טקסט מפוצלים, ומשפרת את האפקט הכולל של עיבוד המודל לטקסטים ארוכים", + "selectEmbeddingModel": "בחר מודל הטמעה (Embedding)", + "modelNotFound": "ספק השירות {provider} או המודל {model} לא נמצאו", + "modelNotFoundDesc": "ודא שהמודל מוגדר כראוי ושמודל זה מופעל. \nתוכל לבדוק את תצורת המודל בהגדרות ספק השירות.", + "removeBuiltinKnowledgeConfirmDesc": "מחיקת תצורת בסיס הידע המובנה תמחק את כל הנתונים הרלוונטיים ולא ניתן לשחזרם. אנא היזהר.", + "removeBuiltinKnowledgeConfirmTitle": "האם לאשר את מחיקת בסיס הידע המובנה {name}?", + "descriptionDesc": "תיאור בסיס הידע כך שה-AI יחליט אם לאחזר בסיס ידע זה", + "advanced": "אפשרויות מתקדמות", + "autoDetectDimensions": "זהה אוטומטית ממדים מוטמעים", + "autoDetectHelper": "מזהה אוטומטית ממדים מוטמעים, צורך כמות קטנה של טוקנים", + "chunkOverlapPlaceholder": "ערך ברירת מחדל, לא מומלץ לשנות", + "chunkSizePlaceholder": "ערך ברירת מחדל, לא מומלץ לשנות", + "dimensions": "ממדי הטמעה (Embed dimensions)", + "dimensionsPlaceholder": "גודל ממד הטמעה, כגון 1024", + "selectEmbeddingModelHelper": "מודלי הטמעה אסורים לשינוי לאחר יצירת בסיס הידע", + "dimensionsHelper": "ודא שהמודל תומך בגודל ממד ההטמעה שהוגדר", + "autoDetectDimensionsError": "זיהוי אוטומטי של ממד מוטמע נכשל", + "fragmentsNumber": "מספר מקטעי מסמך מבוקשים", + "fragmentsNumberHelper": "ככל שמבוקשים יותר מקטעי מסמך, כך מתקבל יותר מידע, אך נדרשים יותר טוקנים לצריכה", + "selectRerankModel": "בחר את מודל הדירוג מחדש (Rerank)", + "rerankModel": "מודל דירוג מחדש", + "embeddingModel": "מודל הטמעה", + "return": "חזור", + "uploadHelper": "לחץ להעלאה או גרור את הקובץ לכאן", + "fileSupport": "תומך ב-{accept} וב-{count} פורמטים נוספים", + "searchKnowledge": "חפש בבסיס הידע", + "searchKnowledgePlaceholder": "אנא הזן את תוכן השאילתה", + "noData": "אין נתונים עדיין", + "file": "מסמך", + "uploadProcessing": "מעלה", + "uploadCompleted": "ההעלאה הושלמה", + "reAdd": "העלה מחדש", + "uploadError": "ההעלאה נכשלה", + "delete": "מחק", + "reason": "סיבה", + "deleteSuccess": "נמחק בהצלחה", + "copy": "העתק", + "copySuccess": "הועתק בהצלחה", + "source": "מקור", + "normalized": "נרמול L2", + "normalizedHelper": "אנא ודא שהמודל תומך בנרמול L2 של וקטורי פלט", + "dialog": { + "beforequit": { + "cancel": "ביטול", + "confirm": "אשר", + "title": "אישור יציאה", + "description": "ישנה משימת בסיס ידע שפועלת. האם אתה בטוח שברצונך לצאת מהתוכנה? \nניתן לשחזר משימות שהופסקו לאחר הפעלת התוכנה מחדש." + } + }, + "searchError": "השאילתה נכשלה", + "processing": "מעלה", + "paused": "העלאה מושהית", + "unknown": "סטטוס לא ידוע", + "reAddFile": { + "title": "אישור העלאה מחדש", + "content": "האם אתה בטוח שברצונך להעלות מחדש את הקובץ \"{fileName}\"?" + }, + "nowledgeMem": { + "title": "ייצוא ל-Nowledge Mem", + "description": "ייצוא שיחות לשירות Nowledge Mem.", + "testConnection": "בדוק חיבור", + "configuration": "תצורה", + "baseUrl": "כתובת בסיס (Base URL)", + "apiKey": "מפתח API", + "apiKeyHint": "אופציונלי. אם השירות שלך דורש מפתח API, הזן אותו כאן.", + "timeout": "פסק זמן (Timeout)", + "saveConfig": "שמור", + "resetConfig": "אפס", + "seconds": "שניות" + }, + "deleteFile": { + "title": "אישור מחיקת קובץ", + "content": "האם אתה בטוח שברצונך למחוק את הקובץ \"{fileName}\"? \nפעולה זו אינה ניתנת לשחזור." + }, + "resumeAllPausedTasks": "שחזור בלחיצה אחת", + "pauseAllRunningTasks": "השהייה בלחיצה אחת", + "separators": "מפריד מקטעים", + "separatorsHelper": "מפריד פיצול מסמכים, מפריד בודד מוקף במרכאות כפולות (\"\"), ומפרידים מופרדים בפסיקים (,)", + "invalidSeparators": "מפריד לא חוקי", + "selectLanguage": "בחר הגדרה מוגדרת מראש", + "separatorsPreset": "טוען הגדרות מוגדרות מראש" + }, + "mcp": { + "title": "הגדרות MCP", + "description": "ניהול והגדרה של שרתי וכלים של MCP (Model Context Protocol)", + "enabledTitle": "הפעל את MCP", + "enabledDescription": "הפעל או השבת פונקציונליות וכלים של MCP", + "enableToAccess": "אנא הפעל את MCP כדי לגשת לאפשרויות התצורה", + "marketplace": "עבור לחנות MCP להתקנה בלחיצה אחת", + "technicalDetails": "פרטים טכניים", + "httpServer": "שרת HTTP", + "localProcess": "תהליך מקומי", + "restartServer": "הפעל מחדש שרת", + "viewLogs": "צפה בלוגים", + "starting": "מתחיל", + "error": "שגיאה", + "tabs": { + "servers": "שרתים", + "tools": "כלים", + "prompts": "הנחיות (Prompts)", + "resources": "משאבים" + }, + "serverList": "רשימת שרתים", + "totalServers": "סה\"כ שרתים", + "addServer": "הוסף שרת", + "running": "פועל", + "stopped": "נעצר", + "stopServer": "עצור שרת", + "startServer": "התחל שרת", + "noServersFound": "לא נמצאו שרתים", + "addServerDialog": { + "title": "הוסף שרת", + "description": "הגדר שרת MCP חדש" + }, + "editServerDialog": { + "title": "ערוך שרת", + "description": "ערוך תצורת שרת MCP" + }, + "serverForm": { + "name": "שם השרת", + "namePlaceholder": "הזן את שם השרת", + "nameRequired": "שם השרת נדרש", + "type": "סוג שרת", + "typePlaceholder": "בחר סוג שרת", + "typeStdio": "קלט ופלט סטנדרטי (Stdio)", + "typeSse": "אירועים הנשלחים מהשרת (SSE)", + "typeInMemory": "בזיכרון (In-Memory)", + "typeHttp": "בקשות HTTP זורמות (HTTP)", + "baseUrl": "כתובת בסיס (Base URL)", + "baseUrlPlaceholder": "הזן את כתובת הבסיס של השרת (לדוגמה: http://localhost:3000)", + "command": "פקודה", + "commandPlaceholder": "הזן פקודה", + "commandRequired": "פקודה נדרשת", + "args": "ארגומנטים", + "argsPlaceholder": "הזן ארגומנט אחד בכל שורה", + "addArg": "הוסף ארגומנט", + "argPlaceholder": "הזן ערך ארגומנט", + "argsRequired": "ארגומנטים נדרשים", + "env": "משתני סביבה", + "envPlaceholder": "הזן משתני סביבה בפורמט JSON", + "envInvalid": "משתני סביבה חייבים להיות JSON חוקי", + "description": "תיאור", + "descriptionPlaceholder": "הזן את תיאור השרת", + "descriptions": "תיאור", + "descriptionsPlaceholder": "הזן את תיאור השרת", + "icon": "אייקון", + "iconPlaceholder": "הזן אייקון", + "icons": "אייקון", + "iconsPlaceholder": "הזן אייקון", + "autoApprove": "אישור אוטומטי", + "autoApproveAll": "הכל", + "autoApproveRead": "קריאה", + "autoApproveWrite": "כתיבה", + "autoApproveHelp": "בחר סוגי פעולות לאישור אוטומטי ללא אישור המשתמש", + "submit": "שלח", + "add": "הוסף", + "update": "עדכן", + "cancel": "ביטול", + "jsonConfigIntro": "אתה יכול להדביק תצורת JSON ישירות או לבחור להגדיר את השרת באופן ידני.", + "jsonConfig": "תצורת JSON", + "jsonConfigPlaceholder": "הדבק את תצורת שרת MCP שלך בפורמט JSON", + "jsonConfigExample": "דוגמה לתצורת JSON", + "parseSuccess": "התצורה פוענחה", + "configImported": "התצורה יובאה בהצלחה", + "parseError": "שגיאת פענוח", + "skipToManual": "דלג להגדרה ידנית", + "parseAndContinue": "פענח והמשך", + "jsonParseError": "פענוח JSON נכשל", + "browseMarketplace": "עיין בחנות MCP", + "imageModel": "בחר מודל ראייה", + "customHeadersParseError": "פענוח כותרות מותאמות אישית נכשל", + "customHeaders": "כותרות בקשה מותאמות אישית", + "clickToEdit": "לחץ לעריכה וצפייה בתוכן המלא", + "invalidKeyValueFormat": "פורמט כותרת בקשה שגוי, אנא בדוק אם הקלט תקין.", + "npmRegistry": "NPM Registry מותאם אישית", + "npmRegistryPlaceholder": "הגדר NPM Registry מותאם אישית, השאר ריק כדי שהמערכת תבחר אוטומטית את המהיר ביותר", + "browseHigress": "צפה בחנות Higress MCP", + "selectFolderError": "שגיאה בבחירת תיקייה", + "folders": "תיקיות מותרות", + "addFolder": "הוסף תיקייה", + "noFoldersSelected": "לא נבחרו תיקיות", + "useE2B": "הפעל ארגז חול E2B", + "e2bDescription": "הרץ קוד Python באמצעות ארגז החול של E2B", + "e2bApiKey": "E2B ApiKey", + "e2bApiKeyPlaceholder": "הזן את מפתחות ה-API של E2B כאן, למשל e2b_1111xx*******", + "e2bApiKeyHelp": "עבור ל-e2b.dev כדי לקבל את ה-ApiKey שלך", + "e2bApiKeyRequired": "חובה להזין ApiKey כדי להפעיל את פונקציית E2B" + }, + "deleteServer": "מחק שרת", + "editServer": "ערוך שרת", + "setDefault": "הגדר כברירת מחדל", + "removeDefault": "הסר ברירת מחדל", + "isDefault": "שרת ברירת מחדל", + "default": "ברירת מחדל", + "setAsDefault": "הגדר כברירת מחדל", + "removeServer": "הסר שרת", + "autoStart": "הפעלה אוטומטית", + "confirmRemoveServer": "האם אתה בטוח שברצונך למחוק את השרת {name}? לא ניתן לבטל פעולה זו.", + "removeServerDialog": { + "title": "מחק שרת" + }, + "confirmDelete": { + "title": "אשר מחיקה", + "description": "האם אתה בטוח שברצונך למחוק את השרת {name}? לא ניתן לבטל פעולה זו.", + "confirm": "מחק", + "cancel": "ביטול" + }, + "resetToDefault": "אפס לברירת מחדל", + "resetConfirmTitle": "אפס לשרתי ברירת המחדל", + "resetConfirmDescription": "פעולה זו תשחזר את כל שרתי ברירת המחדל תוך שמירה על השרתים המותאמים אישית שלך. כל שינוי בשרתי ברירת המחדל יאבד.", + "resetConfirm": "אפס", + "builtInServers": "שרתים מובנים", + "customServers": "שרתים מותאמים אישית", + "builtIn": "מובנה", + "cannotRemoveBuiltIn": "לא ניתן להסיר שרת מובנה", + "builtInServerCannotBeRemoved": "לא ניתן להסיר שרתים מובנים, ניתן לשנות רק פרמטרים ומשתני סביבה", + "maxDefaultServersReached": "ניתן להגדיר לכל היותר 3 שרתי ברירת מחדל", + "removeDefaultFirst": "אנא הסר תחילה מספר שרתי ברירת מחדל", + "higressMarket": "עבור להתקנת Higress MCP", + "npmRegistry": { + "title": "תצורת NPM Registry", + "currentSource": "מקור נוכחי", + "cached": "במטמון", + "lastChecked": "נבדק לאחרונה", + "refresh": "רענן", + "advanced": "מתקדם", + "advancedSettings": "הגדרות מתקדמות", + "advancedSettingsDesc": "הגדר אפשרויות מתקדמות של NPM registry, כולל זיהוי אוטומטי והגדרות מקור מותאמות אישית", + "autoDetect": "זהה אוטומטית מקור אופטימלי", + "autoDetectDesc": "מזהה ומשתמש אוטומטית ב-NPM registry המהיר ביותר בעת ההפעלה", + "customSource": "מקור מותאם אישית", + "customSourcePlaceholder": "הזן כתובת URL של NPM registry מותאם אישית", + "currentCustom": "מקור מותאם אישית נוכחי", + "justNow": "ממש עכשיו", + "minutesAgo": "לפני {minutes} דקות", + "hoursAgo": "לפני {hours} שעות", + "daysAgo": "לפני {days} ימים", + "refreshSuccess": "NPM registry רוענן בהצלחה", + "refreshSuccessDesc": "זוהה ועודכן ה-NPM registry האופטימלי", + "refreshFailed": "רענון NPM registry נכשל", + "autoDetectUpdated": "הגדרת זיהוי אוטומטי עודכנה", + "autoDetectEnabled": "זיהוי אוטומטי של NPM registry אופטימלי הופעל", + "autoDetectDisabled": "זיהוי אוטומטי מושבת, ישתמש ב-registry ברירת המחדל", + "updateFailed": "עדכון ההגדרה נכשל", + "customSourceSet": "מקור מותאם אישית הוגדר", + "customSourceSetDesc": "NPM registry מותאם אישית הוגדר: {registry}", + "customSourceCleared": "מקור מותאם אישית נוקה", + "customSourceClearedDesc": "NPM registry מותאם אישית נוקה, ישתמש בזיהוי אוטומטי", + "invalidUrl": "כתובת URL לא חוקית", + "invalidUrlDesc": "אנא הזן כתובת HTTP או HTTPS תקינה", + "testing": "בודק NPM registry", + "testingDesc": "בודק קישוריות ל-{registry}...", + "testFailed": "בדיקת NPM registry נכשלה", + "testFailedDesc": "לא ניתן להתחבר ל-{registry}, שגיאה: {error}. אנא בדוק אם הכתובת נכונה או בדוק את חיבור הרשת.", + "redetectingOptimal": "מזהה מחדש NPM registry אופטימלי...", + "redetectComplete": "זיהוי מחדש הושלם", + "redetectCompleteDesc": "זוהה והוגדר ה-NPM registry האופטימלי הנוכחי", + "redetectFailed": "זיהוי מחדש נכשל", + "redetectFailedDesc": "לא ניתן לזהות מחדש registry אופטימלי, ישתמש בתצורת ברירת המחדל" + } + }, + "about": { + "title": "אודותינו", + "version": "גרסה", + "checkUpdate": "בדוק עדכון", + "checking": "בודק...", + "latestVersion": "גרסה אחרונה" + }, + "display": { + "fontSize": "גודל טקסט", + "text-sm": "קטן", + "text-base": "בינוני", + "text-lg": "גדול", + "text-xl": "גדול מאוד", + "text-2xl": "ענק", + "floatingButton": "כפתור צף", + "floatingButtonDesc": "הצג כפתור צף על שולחן העבודה להפעלה מהירה של חלון האפליקציה" + }, + "shortcuts": { + "title": "הגדרות קיצורי מקשים", + "pressKeys": "לחץ על מקשים", + "pressEnterToSave": "לחץ Enter לשמירה, Esc לביטול", + "noModifierOnly": "לא ניתן להשתמש במקש שינוי (Modifier) בלבד כקיצור דרך", + "keyConflict": "התנגשות מקשי קיצור, אנא בחר שילוב אחר", + "clearShortcut": "נקה קיצור דרך", + "cleanHistory": "נקה היסטוריית צ'אט", + "deleteConversation": "מחק שיחה", + "goSettings": "פתח הגדרות", + "hideWindow": "הסתר חלון", + "quitApp": "צא מהאפליקציה", + "zoomIn": "הגדל תצוגה ", + "zoomOut": "הקטן תצוגה ", + "zoomReset": "אפס תצוגה", + "closeTab": "סגור את הכרטיסייה הנוכחית", + "newTab": "צור כרטיסייה חדשה", + "newWindow": "פתח חלון חדש", + "showHideWindow": "הצג/הסתר חלון", + "newConversation": "שיחה חדשה", + "nextTab": "עבור לכרטיסייה הבאה", + "previousTab": "עבור לכרטיסייה הקודמת", + "specificTab": "עבור לכרטיסייה מסוימת (1-8)", + "lastTab": "עבור לכרטיסייה האחרונה" + }, + "acp": { + "title": "סוכני ACP", + "description": "ניהול סוכני ACP מקומיים (Agent Client Protocol) המופעלים על ידי DeepChat.", + "enabledTitle": "הפעל את ACP", + "enabledDescription": "כאשר מופעל, סוכני ACP מוגדרים יופיעו כמודלים בבוחר.", + "useBuiltinRuntimeTitle": "השתמש בסביבת הרצה מובנית של DeepChat", + "useBuiltinRuntimeDescription": "כאשר מופעל, עוקף פקודות node ו-uv של המערכת, ומשתמש בגרסאות המצורפות ל-DeepChat.", + "enableToAccess": "הפעל את ACP כדי להגדיר סוכנים.", + "addCustomAgent": "הוסף סוכן מותאם אישית", + "customEmpty": "אין סוכנים מותאמים אישית עדיין.", + "customDeleteConfirm": "למחוק את הסוכן המותאם אישית \"{name}\"?", + "builtinSectionTitle": "סוכנים מובנים", + "builtinSectionDescription": "לכל סוכן מובנה יכולים להיות מספר פרופילי הפעלה. רק סוכנים מופעלים עם פרופיל פעיל מופיעים ברשימת המודלים.", + "builtinHint": "הפעל את {name} עם הגדרות אלה.", + "disabledBadge": "מושבת", + "manageProfiles": "נהל פרופילים", + "addProfile": "הוסף פרופיל", + "activeProfile": "פרופיל פעיל", + "profilePlaceholder": "בחר פרופיל", + "profileSwitched": "פרופיל הוחלף", + "customSectionTitle": "סוכנים מותאמים אישית", + "customSectionDescription": "עטוף כל פקודה תואמת ACP כרשומת מודל לשימוש חוזר.", + "loading": "טוען נתוני ACP...", + "none": "ללא", + "saveSuccess": "התצורה נשמרה", + "saveFailed": "שמירת הסוכן נכשלה", + "deleteSuccess": "נמחק בהצלחה", + "initialize": "אתחל", + "initializing": "מאתחל...", + "initializeDescription": "טרמינל נפתח עם פקודות אתחול", + "initializeSuccess": "האתחול התחיל", + "initializeFailed": "האתחול נכשל", + "missingFieldsTitle": "שם ופקודה הם חובה", + "missingFieldsDesc": "אנא מלא גם שם וגם פקודה לפני השמירה.", + "command": "פקודה", + "commandPlaceholder": "נתיב קובץ הפעלה או סקריפט", + "args": "ארגומנטים", + "argsPlaceholder": "אופציונלי, מופרדים ברווחים. השתמש במרכאות כדי לשמור על ארגומנטים יחד.", + "env": "משתני סביבה", + "addEnv": "הוסף משתנה", + "envKeyPlaceholder": "מפתח (KEY)", + "envValuePlaceholder": "ערך (VALUE)", + "profileDialog": { + "addBuiltinTitle": "הוסף פרופיל {name}", + "editBuiltinTitle": "ערוך פרופיל {name}", + "addCustomTitle": "הוסף סוכן מותאם אישית", + "editCustomTitle": "ערוך סוכן מותאם אישית", + "builtinHint": "השתמש בהגדרות קבועות מראש שונות לכל תרחיש והחלף ביניהן בבוחר.", + "customHint": "ספק את הפקודה, הארגומנטים ומשתני הסביבה כדי להפעיל את הסוכן שלך.", + "profileName": "שם הפרופיל", + "profileNamePlaceholder": "לדוגמה: תחנת עבודה", + "agentName": "שם הסוכן", + "agentNamePlaceholder": "לדוגמה: ה-ACP המקומי שלי" + }, + "profileManager": { + "title": "פרופילים", + "description": "החלף, ערוך או מחק פרופילי הפעלה שמורים.", + "count": "{count} פרופילים", + "empty": "אין פרופילים עדיין.", + "active": "פעיל", + "setActive": "הגדר כפעיל", + "deleteConfirm": "למחוק את הפרופיל \"{name}\"?", + "cannotDeleteTitle": "השאר לפחות פרופיל אחד", + "cannotDeleteDesc": "סוכנים מובנים דורשים לפחות תצורה אחת.", + "noAgent": "בחר סוכן כדי לנהל את הפרופילים שלו." + }, + "terminal": { + "title": "טרמינל אתחול", + "waiting": "ממתין לתחילת האתחול...", + "starting": "מתחיל אתחול...", + "close": "סגור", + "closing": "סוגר...", + "exitSuccess": "התהליך הושלם בהצלחה (קוד יציאה: {code})", + "exitError": "התהליך יצא עם שגיאה (קוד יציאה: {code})", + "processError": "שגיאת תהליך", + "paste": "הדבק", + "pasteError": "ההדבקה מהלוח נכשלה", + "status": { + "idle": "בהמתנה", + "running": "פועל", + "completed": "הושלם", + "error": "שגיאה" + } + }, + "dependency": { + "title": "תלויות חיצוניות חסרות", + "description": "יש להתקין את התלויות הבאות לפני האתחול.", + "installCommands": "פקודות התקנה", + "downloadUrl": "קישור להורדה", + "copy": "העתק", + "copied": "הועתק ללוח", + "copyFailed": "ההעתקה נכשלה" + } + }, + "rateLimit": { + "title": "מגבלת קצב (Rate Limit)", + "description": "שלוט במרווח הבקשות כדי למנוע חריגה ממגבלות ה-API", + "intervalLimit": "מרווח בקשות", + "intervalUnit": "שניות", + "intervalHelper": "מרווח מינימלי בין בקשות, השבת את מגבלת הקצב אם אין צורך", + "lastRequestTime": "בקשה אחרונה", + "queueLength": "אורך תור", + "nextAllowedTime": "הבא מותר", + "never": "מעולם לא", + "justNow": "ממש עכשיו", + "secondsAgo": "לפני שניות", + "minutesAgo": "לפני דקות", + "immediately": "עכשיו", + "secondsLater": "שניות מאוחר יותר", + "confirmDisableTitle": "אשר ביטול מגבלת קצב", + "confirmDisableMessage": "הערך לא יכול להיות קטן או שווה ל-0. האם ברצונך לבטל את מגבלת הקצב?", + "confirmDisable": "בטל מגבלה", + "disabled": "מגבלת קצב מושבתת", + "disabledDescription": "מגבלת הקצב הושבתה" + }, + "promptSetting": { + "resetToDefault": "אפס להנחיית ברירת מחדל", + "resetToDefaultSuccess": "איפוס להנחיית מערכת ברירת מחדל הצליח", + "resetToDefaultFailed": "האיפוס נכשל, אנא נסה שוב" + } +} diff --git a/src/renderer/src/i18n/he-IL/sync.json b/src/renderer/src/i18n/he-IL/sync.json new file mode 100644 index 000000000..e641785a2 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/sync.json @@ -0,0 +1,17 @@ +{ + "success": { + "importComplete": "יובאו בהצלחה {count} שיחות. היישום יופעל מחדש כעת." + }, + "error": { + "notEnabled": "הסנכרון אינו מופעל", + "folderNotExists": "תיקיית הסנכרון אינה קיימת", + "noValidBackup": "לא נמצאו קבצי גיבוי תקינים בתיקיית הסנכרון.", + "dbNotExists": "קובץ מסד הנתונים אינו קיים", + "configNotExists": "קובץ התצורה אינו קיים", + "tempDbFailed": "נכשל ביצירת קובץ גיבוי זמני למסד הנתונים", + "tempConfigFailed": "נכשל ביצירת קובץ גיבוי זמני לתצורה", + "importFailed": "הייבוא נכשל, הנתונים המקוריים שוחזרו", + "importProcess": "אירעה שגיאה במהלך תהליך הייבוא", + "unknown": "שגיאה לא ידועה" + } +} diff --git a/src/renderer/src/i18n/he-IL/thread.json b/src/renderer/src/i18n/he-IL/thread.json new file mode 100644 index 000000000..da2240d9b --- /dev/null +++ b/src/renderer/src/i18n/he-IL/thread.json @@ -0,0 +1,46 @@ +{ + "actions": { + "rename": "שנה שם", + "delete": "מחק", + "cleanMessages": "נקה הודעות", + "pin": "נעץ", + "unpin": "בטל נעיצה", + "export": "ייצוא", + "exportText": "טקסט רגיל", + "exportNowledgeMem": "Nowledge-mem" + }, + "toolbar": { + "save": "שמור", + "cancel": "ביטול", + "previousVariant": "גרסה קודמת", + "nextVariant": "גרסה הבאה", + "copy": "העתק כ-Markdown", + "copyImage": "העתק כתמונה", + "copyImageWithLongPress": "העתק כתמונה (לחיצה ארוכה ללכידה מלמעלה)", + "copyFromTopSuccess": "תמונת השיחה המלאה הועתקה", + "capturing": "לוכד...", + "retry": "צור מחדש", + "fork": "צור ענף לשיחה חדשה", + "edit": "ערוך הודעה", + "delete": "מחק הודעה", + "trace": "עקוב אחר בקשה (Trace)" + }, + "message": { + "toolbar": { + "save": "שמור" + } + }, + "export": { + "failed": "הייצוא נכשל", + "failedDesc": "אירעה שגיאה במהלך תהליך הייצוא, אנא נסה שוב", + "success": "הייצוא הושלם בהצלחה", + "successDesc": "השיחה יוצאה בהצלחה", + "nowledgeMemSuccess": "ייצוא ל-Nowledge-mem הושלם בהצלחה", + "nowledgeMemSuccessDesc": "השיחה יוצאה בהצלחה לפורמט nowledge-mem", + "nowledgeMemSubmitPrompt": "האם ברצונך לשלוח שיחה זו ל-nowledge-mem?", + "nowledgeMemSubmitSuccess": "השליחה ל-Nowledge-mem הושלמה בהצלחה", + "nowledgeMemSubmitSuccessDesc": "השיחה נשלחה בהצלחה ל-nowledge-mem", + "nowledgeMemSubmitFailed": "השליחה ל-Nowledge-mem נכשלה", + "nowledgeMemSubmitFailedDesc": "נכשל בשליחת השיחה ל-nowledge-mem" + } +} diff --git a/src/renderer/src/i18n/he-IL/toolCall.json b/src/renderer/src/i18n/he-IL/toolCall.json new file mode 100644 index 000000000..9524fee9e --- /dev/null +++ b/src/renderer/src/i18n/he-IL/toolCall.json @@ -0,0 +1,19 @@ +{ + "calling": "קורא...", + "response": "רץ...", + "end": "בוצע", + "error": "שגיאה", + "title": "קריאה לכלי", + "clickToView": "לחץ לצפייה בפרטים", + "functionName": "שם הפונקציה", + "permission": "מבקש הרשאה...", + "params": "פרמטרי פונקציה", + "responseData": "תגובה", + "failed": "לְהִכָּשֵׁל", + "fileOperation": "פעולות קובץ", + "filePath": "נתיב הקובץ", + "fileRead": "לקרוא קובץ", + "fileWrite": "לכתוב קובץ", + "success": "הַצלָחָה", + "terminalOutput": "פלט מסוף" +} diff --git a/src/renderer/src/i18n/he-IL/traceDialog.json b/src/renderer/src/i18n/he-IL/traceDialog.json new file mode 100644 index 000000000..703332a23 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/traceDialog.json @@ -0,0 +1,17 @@ +{ + "title": "תצוגה מקדימה של הבקשה", + "provider": "ספק", + "model": "מודל", + "endpoint": "נקודת קצה (API Endpoint)", + "headers": "כותרות (Headers)", + "body": "גוף הבקשה (Body)", + "copyJson": "העתק JSON", + "copySuccess": "הועתק ללוח", + "close": "סגור", + "loading": "טוען...", + "error": "הטעינה נכשלה", + "errorDesc": "לא ניתן להביא תצוגה מקדימה של הבקשה, אנא נסה שוב", + "notImplemented": "לא נתמך", + "notImplementedDesc": "ספק זה טרם יישם תצוגה מקדימה של הבקשה", + "mayNotMatch": "הערה: תצוגה מקדימה זו משוחזרת מהגדרות השיחה הנוכחיות ועשויה שלא להתאים במדויק לפרמטרי הבקשה בפועל" +} diff --git a/src/renderer/src/i18n/he-IL/update.json b/src/renderer/src/i18n/he-IL/update.json new file mode 100644 index 000000000..1ca614070 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/update.json @@ -0,0 +1,16 @@ +{ + "newVersion": "גרסה חדשה נמצאה", + "version": "גרסה", + "releaseDate": "תאריך שחרור", + "releaseNotes": "הערות גרסה", + "later": "מאוחר יותר", + "githubDownload": "הורדה מ-GitHub", + "netdiskDownload": "הורדה מהענן", + "checkUpdate": "בדוק עדכונים", + "downloading": "מוריד", + "installNow": "התקן כעת", + "autoUpdate": "עדכון אוטומטי", + "restarting": "מפעיל מחדש", + "alreadyUpToDate": "התוכנה מעודכנת", + "alreadyUpToDateDesc": "ה-DeepChat שלך כבר מעודכן לגרסה האחרונה, אין צורך בעדכון." +} diff --git a/src/renderer/src/i18n/he-IL/welcome.json b/src/renderer/src/i18n/he-IL/welcome.json new file mode 100644 index 000000000..5d742a512 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/welcome.json @@ -0,0 +1,37 @@ +{ + "steps": { + "welcome": { + "title": "ברוכים הבאים", + "description": "בוא נתחיל להגדיר את DeepChat" + }, + "provider": { + "title": "ספק", + "description": "בחר את ספק המודל המועדף עליך" + }, + "configuration": { + "title": "תצורה", + "description": "הגדר את המודלים שברצונך להשתמש בהם" + }, + "complete": { + "title": "סיום", + "description": "הכל מוכן ואפשר לצאת לדרך!" + } + }, + "title": "ברוכים הבאים ל-DeepChat", + "description": "בוא נעבור יחד על ההתקנה.", + "provider": { + "select": "בחר ספק", + "apiUrl": "כתובת API", + "apiKey": "מפתח API", + "verifyLink": "אמת קישור" + }, + "complete": { + "title": "סיימנו!", + "description": "אתה מוכן לשימוש. בוא נתחיל!" + }, + "buttons": { + "getStarted": "התחל", + "next": "הבא", + "back": "חזור" + } +} diff --git a/src/renderer/src/i18n/index.ts b/src/renderer/src/i18n/index.ts index 429e4ff46..12990b2c6 100644 --- a/src/renderer/src/i18n/index.ts +++ b/src/renderer/src/i18n/index.ts @@ -9,6 +9,7 @@ import frFR from './fr-FR' import faIR from './fa-IR' import ptBR from './pt-BR' import daDK from './da-DK' +import heIL from './he-IL' const locales = { 'zh-CN': zhCN, @@ -22,11 +23,13 @@ const locales = { 'fa-IR': faIR, 'pt-BR': ptBR, 'da-DK': daDK, + 'he-IL': heIL, zh: zhCN, en: enUS, fr: frFR, pt: ptBR, - da: daDK + da: daDK, + he: heIL } console.log('locales', locales) export default locales diff --git a/src/renderer/src/stores/language.ts b/src/renderer/src/stores/language.ts index 2a5377350..f6b38d2a5 100644 --- a/src/renderer/src/stores/language.ts +++ b/src/renderer/src/stores/language.ts @@ -5,7 +5,7 @@ import { useI18n } from 'vue-i18n' import { usePresenter } from '@/composables/usePresenter' import { CONFIG_EVENTS } from '@/events' -const RTL_LIST = ['fa-IR'] +const RTL_LIST = ['fa-IR', 'he-IL'] export const useLanguageStore = defineStore('language', () => { const { locale } = useI18n({ useScope: 'global' }) const language = ref('system') From a00109ab930d5b022210cbd81c89a1ec43abcc52 Mon Sep 17 00:00:00 2001 From: duskzhen Date: Mon, 8 Dec 2025 19:05:38 +0800 Subject: [PATCH 03/12] feat: add custom font setting (#1167) * feat(settings): add font customization controls * feat: change font with monaco * chore: remove log and remove unuse key * fix: linux font parse * feat: use font-list to get font --- electron-builder-macx64.yml | 2 + electron-builder.yml | 2 + package.json | 5 +- src/main/events.ts | 2 + src/main/presenter/configPresenter/index.ts | 28 ++ .../configPresenter/uiSettingsHelper.ts | 108 ++++++ .../settings/components/DisplaySettings.vue | 53 +-- .../display/FontSettingsSection.vue | 307 ++++++++++++++++++ src/renderer/src/App.vue | 13 + src/renderer/src/assets/style.css | 24 +- .../src/components/artifacts/CodeArtifact.vue | 30 +- .../src/components/artifacts/HTMLArtifact.vue | 2 +- .../components/artifacts/MarkdownArtifact.vue | 12 +- .../src/components/artifacts/ReactTemplate.ts | 2 +- .../components/markdown/MarkdownRenderer.vue | 8 +- .../mcp-config/components/McpJsonViewer.vue | 4 +- .../message/MessageBlockToolCall.vue | 4 +- .../src/components/trace/TraceDialog.vue | 20 +- .../src/composables/useArtifactCodeEditor.ts | 21 +- src/renderer/src/events.ts | 2 + src/renderer/src/i18n/da-DK/settings.json | 13 +- src/renderer/src/i18n/en-US/settings.json | 11 + src/renderer/src/i18n/fa-IR/settings.json | 13 +- src/renderer/src/i18n/fr-FR/settings.json | 13 +- src/renderer/src/i18n/he-IL/settings.json | 13 +- src/renderer/src/i18n/ja-JP/settings.json | 13 +- src/renderer/src/i18n/ko-KR/settings.json | 13 +- src/renderer/src/i18n/pt-BR/settings.json | 13 +- src/renderer/src/i18n/ru-RU/settings.json | 13 +- src/renderer/src/i18n/zh-CN/settings.json | 11 + src/renderer/src/i18n/zh-HK/settings.json | 13 +- src/renderer/src/i18n/zh-TW/settings.json | 13 +- src/renderer/src/stores/uiSettingsStore.ts | 70 ++++ .../types/presenters/legacy.presenters.d.ts | 7 + .../configPresenter/uiSettingsHelper.test.ts | 44 +++ 35 files changed, 853 insertions(+), 69 deletions(-) create mode 100644 src/renderer/settings/components/display/FontSettingsSection.vue create mode 100644 test/main/presenter/configPresenter/uiSettingsHelper.test.ts diff --git a/electron-builder-macx64.yml b/electron-builder-macx64.yml index 4baf06d29..beb6a7b84 100644 --- a/electron-builder-macx64.yml +++ b/electron-builder-macx64.yml @@ -60,6 +60,8 @@ electronLanguages: - pt - da-DK - da + - he-IL + - he mac: entitlementsInherit: build/entitlements.mac.plist extendInfo: diff --git a/electron-builder.yml b/electron-builder.yml index 08b8f3741..93c31acbb 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -59,6 +59,8 @@ electronLanguages: - pt - da-DK - da + - he-IL + - he win: executableName: DeepChat nsis: diff --git a/package.json b/package.json index 20266fe1a..bb6590189 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,7 @@ "electron-window-state": "^5.0.3", "es-mime-types": "^0.1.4", "fflate": "^0.8.2", + "font-list": "^2.0.1", "glob": "^11.0.3", "https-proxy-agent": "^7.0.6", "jsonrepair": "^3.13.1", @@ -146,7 +147,7 @@ "katex": "^0.16.25", "lint-staged": "^16.2.6", "lucide-vue-next": "^0.544.0", - "markstream-vue": "0.0.2-beta.8", + "markstream-vue": "0.0.2", "mermaid": "^11.12.1", "minimatch": "^10.1.1", "monaco-editor": "^0.52.2", @@ -156,7 +157,7 @@ "prettier": "^3.7.1", "reka-ui": "^2.5.1", "simple-git-hooks": "^2.13.1", - "stream-monaco": "^0.0.7", + "stream-monaco": "^0.0.8", "tailwind-merge": "^3.4.0", "tailwind-scrollbar-hide": "^4.0.0", "tailwindcss": "^4.1.17", diff --git a/src/main/events.ts b/src/main/events.ts index 7002f85f7..b4ae56cfc 100644 --- a/src/main/events.ts +++ b/src/main/events.ts @@ -32,6 +32,8 @@ export const CONFIG_EVENTS = { MODEL_CONFIG_CHANGED: 'config:model-config-changed', // 模型配置变更事件 MODEL_CONFIG_RESET: 'config:model-config-reset', // 模型配置重置事件 MODEL_CONFIGS_IMPORTED: 'config:model-configs-imported', // 模型配置批量导入事件 + FONT_FAMILY_CHANGED: 'config:font-family-changed', + CODE_FONT_FAMILY_CHANGED: 'config:code-font-family-changed', // OAuth相关事件 OAUTH_LOGIN_START: 'config:oauth-login-start', // OAuth登录开始 OAUTH_LOGIN_SUCCESS: 'config:oauth-login-success', // OAuth登录成功 diff --git a/src/main/presenter/configPresenter/index.ts b/src/main/presenter/configPresenter/index.ts index 5c87742cd..1d6d666a8 100644 --- a/src/main/presenter/configPresenter/index.ts +++ b/src/main/presenter/configPresenter/index.ts @@ -74,6 +74,8 @@ interface IAppSettings { default_system_prompt?: string // Default system prompt webContentLengthLimit?: number // Web content truncation length limit, default 3000 characters updateChannel?: string // Update channel: 'stable' | 'canary' + fontFamily?: string // Custom UI font + codeFontFamily?: string // Custom code font [key: string]: unknown // Allow arbitrary keys, using unknown type instead of any } @@ -131,6 +133,8 @@ export class ConfigPresenter implements IConfigPresenter { copyWithCotEnabled: true, loggingEnabled: false, floatingButtonEnabled: false, + fontFamily: '', + codeFontFamily: '', default_system_prompt: '', webContentLengthLimit: 3000, updateChannel: 'stable', // Default to stable version @@ -863,6 +867,30 @@ export class ConfigPresenter implements IConfigPresenter { this.uiSettingsHelper.setTraceDebugEnabled(enabled) } + getFontFamily(): string { + return this.uiSettingsHelper.getFontFamily() + } + + setFontFamily(fontFamily?: string | null): void { + this.uiSettingsHelper.setFontFamily(fontFamily) + } + + getCodeFontFamily(): string { + return this.uiSettingsHelper.getCodeFontFamily() + } + + setCodeFontFamily(fontFamily?: string | null): void { + this.uiSettingsHelper.setCodeFontFamily(fontFamily) + } + + resetFontSettings(): void { + this.uiSettingsHelper.resetFontSettings() + } + + async getSystemFonts(): Promise { + return this.uiSettingsHelper.getSystemFonts() + } + // Get floating button switch status getFloatingButtonEnabled(): boolean { const value = this.getSetting('floatingButtonEnabled') ?? false diff --git a/src/main/presenter/configPresenter/uiSettingsHelper.ts b/src/main/presenter/configPresenter/uiSettingsHelper.ts index e599442e0..e64ccab6e 100644 --- a/src/main/presenter/configPresenter/uiSettingsHelper.ts +++ b/src/main/presenter/configPresenter/uiSettingsHelper.ts @@ -1,5 +1,24 @@ import { eventBus, SendTarget } from '@/eventbus' import { CONFIG_EVENTS } from '@/events' +import fontList from 'font-list' + +const normalizeFontNameValue = (name: string): string => { + const trimmed = name + .replace(/\(.*?\)/g, '') + .replace(/\s+/g, ' ') + .trim() + if (!trimmed) return '' + + const stripped = trimmed + .replace( + /\b(Regular|Italic|Oblique|Bold|Light|Medium|Semi\s*Bold|Black|Narrow|Condensed|Extended|Book|Roman)\b/gi, + '' + ) + .replace(/\s+/g, ' ') + .trim() + + return stripped || trimmed +} type SetSetting = (key: string, value: T) => void type GetSetting = (key: string) => T | undefined @@ -12,6 +31,7 @@ interface UiSettingsHelperOptions { export class UiSettingsHelper { private readonly getSetting: GetSetting private readonly setSetting: SetSetting + private systemFontsCache: string[] | null = null constructor(options: UiSettingsHelperOptions) { this.getSetting = options.getSetting @@ -66,4 +86,92 @@ export class UiSettingsHelper { this.setSetting('notificationsEnabled', enabled) eventBus.send(CONFIG_EVENTS.NOTIFICATIONS_CHANGED, SendTarget.ALL_WINDOWS, Boolean(enabled)) } + + getFontFamily(): string { + return this.normalizeStoredFont(this.getSetting('fontFamily')) + } + + setFontFamily(fontFamily?: string | null): void { + const normalized = this.normalizeStoredFont(fontFamily) + this.setSetting('fontFamily', normalized) + eventBus.send(CONFIG_EVENTS.FONT_FAMILY_CHANGED, SendTarget.ALL_WINDOWS, normalized) + } + + getCodeFontFamily(): string { + return this.normalizeStoredFont(this.getSetting('codeFontFamily')) + } + + setCodeFontFamily(fontFamily?: string | null): void { + const normalized = this.normalizeStoredFont(fontFamily) + this.setSetting('codeFontFamily', normalized) + eventBus.send(CONFIG_EVENTS.CODE_FONT_FAMILY_CHANGED, SendTarget.ALL_WINDOWS, normalized) + } + + resetFontSettings(): void { + this.setFontFamily('') + this.setCodeFontFamily('') + } + + async getSystemFonts(): Promise { + if (this.systemFontsCache) { + return this.systemFontsCache + } + + const fonts = await this.loadSystemFonts() + this.systemFontsCache = fonts + return fonts + } + + private normalizeStoredFont(value?: string | null): string { + if (typeof value !== 'string') return '' + const cleaned = value + .replace(/[\r\n\t]/g, ' ') + .replace(/[;:{}()[\]<>]/g, '') + .replace(/['"`\\]/g, '') + .trim() + if (!cleaned) return '' + + const collapsed = cleaned.replace(/\s+/g, ' ').slice(0, 100) + + // If we already have detected system fonts cached, prefer an exact match from that list + if (this.systemFontsCache?.length) { + const match = this.systemFontsCache.find( + (font) => font.toLowerCase() === collapsed.toLowerCase() + ) + if (match) return match + } + + return collapsed + } + + private async loadSystemFonts(): Promise { + try { + const detected = await fontList.getFonts() + const normalized = detected + .map((font) => this.normalizeFontName(font)) + .filter((font): font is string => Boolean(font)) + return this.uniqueFonts(normalized) + } catch (error) { + console.warn('Failed to detect system fonts with font-list:', error) + return [] + } + } + + private uniqueFonts(fonts: string[]): string[] { + const seen = new Set() + const result: string[] = [] + fonts.forEach((font) => { + const name = font.trim() + if (!name) return + const key = name.toLowerCase() + if (seen.has(key)) return + seen.add(key) + result.push(name) + }) + return result + } + + private normalizeFontName(name: string): string { + return normalizeFontNameValue(name) + } } diff --git a/src/renderer/settings/components/DisplaySettings.vue b/src/renderer/settings/components/DisplaySettings.vue index 2f84dfd52..0ffbdfa59 100644 --- a/src/renderer/settings/components/DisplaySettings.vue +++ b/src/renderer/settings/components/DisplaySettings.vue @@ -2,30 +2,32 @@
-
- - - {{ t('settings.common.language') }} - -
- +
+
+ + + {{ t('settings.common.language') }} + +
+ +
@@ -212,6 +214,8 @@
+ +
+
+
+ + + {{ t('settings.display.fontTitle') }} + + +
+ +
+ + + {{ + uiSettingsStore.isLoadingFonts + ? t('settings.display.fontSystemLoading') + : t('settings.display.fontUsageHint') + }} + +
+ +
+
+
+
+ + {{ t('settings.display.fontFamily') }} + +
+
+ + + + + +
+
+ + +
+ +
+ + +

+ {{ t('settings.display.fontSearchEmpty') }} +

+
+
+
+
+
+
+
+

+ {{ t('settings.display.fontFamilyDesc') }} +

+
+ +
+
+
+ + {{ t('settings.display.codeFontFamily') }} + +
+
+ + + + + +
+
+ + +
+ +
+ + +

+ {{ t('settings.display.fontSearchEmpty') }} +

+
+
+
+
+
+
+
+

+ {{ t('settings.display.codeFontFamilyDesc') }} +

+
+
+
+ + + diff --git a/src/renderer/src/App.vue b/src/renderer/src/App.vue index 993fdc6b7..079a82ec0 100644 --- a/src/renderer/src/App.vue +++ b/src/renderer/src/App.vue @@ -64,6 +64,19 @@ watch( { immediate: false } // Initialization is handled in onMounted ) +const applyFontVariables = (textFont: string, codeFont: string) => { + document.documentElement.style.setProperty('--dc-font-family', textFont) + document.documentElement.style.setProperty('--dc-code-font-family', codeFont) +} + +watch( + [() => uiSettingsStore.formattedFontFamily, () => uiSettingsStore.formattedCodeFontFamily], + ([textFont, codeFont]) => { + applyFontVariables(textFont, codeFont) + }, + { immediate: true } +) + // Handle error notifications const showErrorToast = (error: { id: string; title: string; message: string; type: string }) => { // Check if error with same ID already exists in queue to prevent duplicates diff --git a/src/renderer/src/assets/style.css b/src/renderer/src/assets/style.css index cc51968a5..6fe271d58 100644 --- a/src/renderer/src/assets/style.css +++ b/src/renderer/src/assets/style.css @@ -17,6 +17,11 @@ :root { --dc-font-scale: 1; + --dc-font-family: + 'Geist', Noto Sans, ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; + --dc-code-font-family: + 'JetBrains Mono', 'Fira Code', 'Menlo', 'Monaco', 'Consolas', 'Courier New', monospace; --base-50: hsl(0 0% 100%); --base-100: hsl(0 0% 98.1%); --base-200: hsl(0 0% 93.4%); @@ -834,16 +839,15 @@ } html { - font-family: - 'Geist', - Noto Sans, - ui-sans-serif, - system-ui, - sans-serif, - 'Apple Color Emoji', - 'Segoe UI Emoji', - 'Segoe UI Symbol', - 'Noto Color Emoji'; + font-family: var(--dc-font-family); + } + + code, + pre, + kbd, + samp, + .font-mono { + font-family: var(--dc-code-font-family); } @font-face { diff --git a/src/renderer/src/components/artifacts/CodeArtifact.vue b/src/renderer/src/components/artifacts/CodeArtifact.vue index 4ebf134d9..e71c20744 100644 --- a/src/renderer/src/components/artifacts/CodeArtifact.vue +++ b/src/renderer/src/components/artifacts/CodeArtifact.vue @@ -44,6 +44,7 @@ import { useThrottleFn } from '@vueuse/core' import { Icon } from '@iconify/vue' import { MermaidBlockNode } from 'markstream-vue' import { useArtifactStore } from '@/stores/artifact' +import { useUiSettingsStore } from '@/stores/uiSettingsStore' import { getLanguageIcon } from 'markstream-vue' import { detectLanguage, useMonaco } from 'stream-monaco' import { nanoid } from 'nanoid' @@ -63,9 +64,11 @@ const props = defineProps<{ }>() const { t } = useI18n() -const { createEditor, updateCode } = useMonaco({ +const uiSettingsStore = useUiSettingsStore() +const { createEditor, updateCode, getEditorView } = useMonaco({ wordWrap: 'on', - wrappingIndent: 'same' + wrappingIndent: 'same', + fontFamily: uiSettingsStore.formattedCodeFontFamily }) const artifactStore = useArtifactStore() const copyText = ref(t('common.copy')) @@ -89,6 +92,12 @@ const sanitizeLanguage = (language?: string | null) => { } const codeLanguage = ref(sanitizeLanguage(props.block.artifact?.language)) +const applyFontFamily = (fontFamily: string) => { + const editor = getEditorView() + if (editor) { + editor.updateOptions({ fontFamily }) + } +} // 创建节流版本的语言检测函数,1秒内最多执行一次 const throttledDetectLanguage = useThrottleFn( @@ -257,18 +266,19 @@ watch( onMounted(() => { if (!codeEditor.value) return createEditor(codeEditor.value, props.block.content, codeLanguage.value) + applyFontFamily(uiSettingsStore.formattedCodeFontFamily) }) + +watch( + () => uiSettingsStore.formattedCodeFontFamily, + (font) => { + applyFontFamily(font) + } +) diff --git a/src/renderer/src/components/artifacts/HTMLArtifact.vue b/src/renderer/src/components/artifacts/HTMLArtifact.vue index 793be09dd..6c784b53a 100644 --- a/src/renderer/src/components/artifacts/HTMLArtifact.vue +++ b/src/renderer/src/components/artifacts/HTMLArtifact.vue @@ -104,7 +104,7 @@ const setupIframe = () => { } html, body { height: 100%; - font-family: Arial, sans-serif; + font-family: var(--dc-font-family, Arial, sans-serif); } img { max-width: 100%; diff --git a/src/renderer/src/components/artifacts/MarkdownArtifact.vue b/src/renderer/src/components/artifacts/MarkdownArtifact.vue index d4c586d4d..f0123a51d 100644 --- a/src/renderer/src/components/artifacts/MarkdownArtifact.vue +++ b/src/renderer/src/components/artifacts/MarkdownArtifact.vue @@ -34,8 +34,16 @@ const handleCopyClick = () => { .markdown-content-wrapper { line-height: 1.75rem; - font-family: - -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; + font-family: var( + --dc-font-family, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + 'Helvetica Neue', + Arial, + sans-serif + ); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } diff --git a/src/renderer/src/components/artifacts/ReactTemplate.ts b/src/renderer/src/components/artifacts/ReactTemplate.ts index 0f7cb2ff2..72949026e 100644 --- a/src/renderer/src/components/artifacts/ReactTemplate.ts +++ b/src/renderer/src/components/artifacts/ReactTemplate.ts @@ -23,7 +23,7 @@ export const formatTemplate = (title: string, reactCode: string) => { } html, body { height: 100%; - font-family: Arial, sans-serif; + font-family: var(--dc-font-family, Arial, sans-serif); } img { max-width: 100%; diff --git a/src/renderer/src/components/markdown/MarkdownRenderer.vue b/src/renderer/src/components/markdown/MarkdownRenderer.vue index 45781655a..2a04a6688 100644 --- a/src/renderer/src/components/markdown/MarkdownRenderer.vue +++ b/src/renderer/src/components/markdown/MarkdownRenderer.vue @@ -3,6 +3,7 @@
@@ -14,7 +15,7 @@ import { useArtifactStore } from '@/stores/artifact' import { useReferenceStore } from '@/stores/reference' import { nanoid } from 'nanoid' import { useDebounceFn } from '@vueuse/core' -import { h, ref, watch } from 'vue' +import { computed, h, ref, watch } from 'vue' import NodeRenderer, { CodeBlockNode, ReferenceNode, @@ -27,12 +28,14 @@ import NodeRenderer, { import KatexWorker from 'markstream-vue/workers/katexRenderer.worker?worker&inline' import MermaidWorker from 'markstream-vue/workers/mermaidParser.worker?worker&inline' import { useThemeStore } from '@/stores/theme' +import { useUiSettingsStore } from '@/stores/uiSettingsStore' const props = defineProps<{ content: string debug?: boolean }>() const themeStore = useThemeStore() +const uiSettingsStore = useUiSettingsStore() getUseMonaco() setKaTeXWorker(new KatexWorker()) setMermaidWorker(new MermaidWorker()) @@ -45,6 +48,9 @@ const referenceStore = useReferenceStore() const threadPresenter = usePresenter('threadPresenter') const referenceNode = ref(null) const debouncedContent = ref(props.content) +const codeBlockMonacoOption = computed(() => ({ + fontFamily: uiSettingsStore.formattedCodeFontFamily +})) const updateContent = useDebounceFn( (value: string) => { diff --git a/src/renderer/src/components/mcp-config/components/McpJsonViewer.vue b/src/renderer/src/components/mcp-config/components/McpJsonViewer.vue index 0e5fab6b0..dc7623cdf 100644 --- a/src/renderer/src/components/mcp-config/components/McpJsonViewer.vue +++ b/src/renderer/src/components/mcp-config/components/McpJsonViewer.vue @@ -190,7 +190,7 @@ const copyToClipboard = async () => { diff --git a/src/renderer/src/components/trace/TraceDialog.vue b/src/renderer/src/components/trace/TraceDialog.vue index ecb8ac88e..931c6a674 100644 --- a/src/renderer/src/components/trace/TraceDialog.vue +++ b/src/renderer/src/components/trace/TraceDialog.vue @@ -106,16 +106,19 @@ import { Icon } from '@iconify/vue' import { useI18n } from 'vue-i18n' import { usePresenter } from '@/composables/usePresenter' import { useMonaco } from 'stream-monaco' +import { useUiSettingsStore } from '@/stores/uiSettingsStore' const { t } = useI18n() const threadPresenter = usePresenter('threadPresenter') +const uiSettingsStore = useUiSettingsStore() // Monaco Editor setup const jsonEditor = ref(null) -const { createEditor, updateCode, cleanupEditor } = useMonaco({ +const { createEditor, updateCode, cleanupEditor, getEditorView } = useMonaco({ readOnly: true, wordWrap: 'off', wrappingIndent: 'same', + fontFamily: uiSettingsStore.formattedCodeFontFamily, minimap: { enabled: false }, scrollBeyondLastLine: true, fontSize: 12, @@ -191,6 +194,12 @@ watch(isOpen, (newValue) => { // Track if editor is initialized const editorInitialized = ref(false) +const applyFontFamily = (fontFamily: string) => { + const editor = getEditorView() + if (editor) { + editor.updateOptions({ fontFamily }) + } +} // Initialize Monaco Editor when dialog opens and data is ready watch( @@ -205,6 +214,7 @@ watch( try { createEditor(editorEl, json, 'json') editorInitialized.value = true + applyFontFamily(uiSettingsStore.formattedCodeFontFamily) } catch (err) { console.error('Failed to create Monaco Editor:', err) } @@ -225,6 +235,7 @@ onMounted(async () => { try { createEditor(jsonEditor.value, formattedJson.value, 'json') editorInitialized.value = true + applyFontFamily(uiSettingsStore.formattedCodeFontFamily) } catch (err) { console.error('Failed to create Monaco Editor on mount:', err) } @@ -232,6 +243,13 @@ onMounted(async () => { } }) +watch( + () => uiSettingsStore.formattedCodeFontFamily, + (font) => { + applyFontFamily(font) + } +) + onBeforeUnmount(() => { cleanupEditor() editorInitialized.value = false diff --git a/src/renderer/src/composables/useArtifactCodeEditor.ts b/src/renderer/src/composables/useArtifactCodeEditor.ts index 464a776c1..5be3bc055 100644 --- a/src/renderer/src/composables/useArtifactCodeEditor.ts +++ b/src/renderer/src/composables/useArtifactCodeEditor.ts @@ -7,6 +7,7 @@ import { ref, watch, onBeforeUnmount } from 'vue' // === Composables === import { useMonaco, detectLanguage } from 'stream-monaco' +import { useUiSettingsStore } from '@/stores/uiSettingsStore' import { useThrottleFn } from '@vueuse/core' /** @@ -76,12 +77,20 @@ export function useArtifactCodeEditor( // === Local State === const codeLanguage = ref(normalizeLanguage(artifact.value)) + const uiSettingsStore = useUiSettingsStore() // === Monaco Integration === - const { createEditor, updateCode, cleanupEditor } = useMonaco({ + const { createEditor, updateCode, cleanupEditor, getEditorView } = useMonaco({ MAX_HEIGHT: '100%', wordWrap: 'on', - wrappingIndent: 'same' + wrappingIndent: 'same', + fontFamily: uiSettingsStore.formattedCodeFontFamily }) + const applyFontFamily = (fontFamily: string) => { + const editor = getEditorView() + if (editor) { + editor.updateOptions({ fontFamily }) + } + } // === Internal Helpers === /** @@ -159,6 +168,7 @@ export function useArtifactCodeEditor( ([editorEl, previewActive, open]) => { if (!open || previewActive || !editorEl) return void createEditor(editorEl, artifact.value?.content || '', codeLanguage.value) + applyFontFamily(uiSettingsStore.formattedCodeFontFamily) }, { flush: 'post', @@ -191,6 +201,13 @@ export function useArtifactCodeEditor( cleanupEditor() }) + watch( + () => uiSettingsStore.formattedCodeFontFamily, + (font) => { + applyFontFamily(font) + } + ) + // === Return API === return { codeLanguage diff --git a/src/renderer/src/events.ts b/src/renderer/src/events.ts index 85c1d48a3..966aecd1c 100644 --- a/src/renderer/src/events.ts +++ b/src/renderer/src/events.ts @@ -26,6 +26,8 @@ export const CONFIG_EVENTS = { SOUND_ENABLED_CHANGED: 'config:sound-enabled-changed', // 新增:声音启用状态变更事件 COPY_WITH_COT_CHANGED: 'config:copy-with-cot-enabled-changed', TRACE_DEBUG_CHANGED: 'config:trace-debug-changed', // Trace 调试功能开关变更事件 + FONT_FAMILY_CHANGED: 'config:font-family-changed', + CODE_FONT_FAMILY_CHANGED: 'config:code-font-family-changed', THEME_CHANGED: 'config:theme-changed', FONT_SIZE_CHANGED: 'config:font-size-changed', DEFAULT_SYSTEM_PROMPT_CHANGED: 'config:default-system-prompt-changed', diff --git a/src/renderer/src/i18n/da-DK/settings.json b/src/renderer/src/i18n/da-DK/settings.json index ca030a06e..42ca7883c 100644 --- a/src/renderer/src/i18n/da-DK/settings.json +++ b/src/renderer/src/i18n/da-DK/settings.json @@ -814,7 +814,18 @@ "text-xl": "Ekstra stor", "text-2xl": "XXL", "floatingButton": "Flydende knap", - "floatingButtonDesc": "Vis en flydende knap på skrivebordet for hurtigt at aktivere vinduet" + "floatingButtonDesc": "Vis en flydende knap på skrivebordet for hurtigt at aktivere vinduet", + "codeFontFamily": "monospace skrifttype", + "codeFontFamilyDesc": "Anvendes til kodeblokke og områder med konstant bredde.", + "fontDefaultLabel": "Standard (indbygget skrifttypestak)", + "fontFamily": "Interface skrifttype", + "fontFamilyDesc": "Vælg grænsefladens hovedskrifttype. Hvis det efterlades tomt, skal du bruge den indbyggede skrifttypestak.", + "fontReset": "nulstilles til standard", + "fontSearchEmpty": "Ingen matchende skrifttype", + "fontSearchPlaceholder": "Søg skrifttype", + "fontSystemLoading": "Indlæser systemskrifttyper...", + "fontTitle": "skrifttype", + "fontUsageHint": "Nogle grænseflader kræver genstart af applikationen for at træde i kraft. Hvis skrifttypen ikke er tilgængelig, vil den automatisk falde tilbage til standardskrifttypen." }, "shortcuts": { "title": "Indstillinger for genvejstaster", diff --git a/src/renderer/src/i18n/en-US/settings.json b/src/renderer/src/i18n/en-US/settings.json index f7cb503be..8ab4acdc7 100644 --- a/src/renderer/src/i18n/en-US/settings.json +++ b/src/renderer/src/i18n/en-US/settings.json @@ -807,6 +807,17 @@ "latestVersion": "Latest Version" }, "display": { + "fontTitle": "Fonts", + "fontFamily": "Interface font", + "fontFamilyDesc": "Select the primary UI font. Leave empty to use the built-in stack.", + "codeFontFamily": "Monospace font", + "codeFontFamilyDesc": "Applies to code blocks and any monospaced areas.", + "fontDefaultLabel": "Default (built-in stack)", + "fontSearchPlaceholder": "Search fonts", + "fontSearchEmpty": "No matching fonts", + "fontReset": "Reset to default", + "fontSystemLoading": "Loading system fonts...", + "fontUsageHint": "Some interfaces require restarting the application to take effect. If the font is unavailable, it will automatically fall back to the default font.", "fontSize": "Text size", "text-sm": "Small", "text-base": "Medium", diff --git a/src/renderer/src/i18n/fa-IR/settings.json b/src/renderer/src/i18n/fa-IR/settings.json index 0fc4f9afd..a6c290e72 100644 --- a/src/renderer/src/i18n/fa-IR/settings.json +++ b/src/renderer/src/i18n/fa-IR/settings.json @@ -814,7 +814,18 @@ "text-xl": "XL", "text-2xl": "XXL", "floatingButton": "دکمه شناور", - "floatingButtonDesc": "نمایش یک دکمه شناور بر روی دسکتاپ برای فعال‌سازی سریع پنجره برنامه" + "floatingButtonDesc": "نمایش یک دکمه شناور بر روی دسکتاپ برای فعال‌سازی سریع پنجره برنامه", + "codeFontFamily": "فونت تک فاصله", + "codeFontFamilyDesc": "برای بلوک های کد و مناطق با عرض ثابت استفاده می شود.", + "fontDefaultLabel": "پیش فرض (پشته فونت داخلی)", + "fontFamily": "فونت رابط", + "fontFamilyDesc": "فونت اصلی رابط را انتخاب کنید. اگر خالی باقی بماند، از پشته فونت داخلی استفاده کنید.", + "fontReset": "به حالت پیش فرض بازنشانی کنید", + "fontSearchEmpty": "بدون فونت منطبق", + "fontSearchPlaceholder": "جستجوی فونت", + "fontSystemLoading": "در حال بارگیری فونت های سیستم...", + "fontTitle": "فونت", + "fontUsageHint": "برخی از اینترفیس ها برای اعمال شدن نیاز به راه اندازی مجدد برنامه دارند. اگر فونت در دسترس نباشد، به طور خودکار به فونت پیش فرض برمی گردد." }, "shortcuts": { "title": "تنظیمات کلید میانبر", diff --git a/src/renderer/src/i18n/fr-FR/settings.json b/src/renderer/src/i18n/fr-FR/settings.json index ebfd842e1..3f3e93da5 100644 --- a/src/renderer/src/i18n/fr-FR/settings.json +++ b/src/renderer/src/i18n/fr-FR/settings.json @@ -814,7 +814,18 @@ "text-xl": "XL", "text-2xl": "XXL", "floatingButton": "Bouton flottant", - "floatingButtonDesc": "Afficher un bouton flottant sur le bureau pour activer rapidement la fenêtre de l'application" + "floatingButtonDesc": "Afficher un bouton flottant sur le bureau pour activer rapidement la fenêtre de l'application", + "codeFontFamily": "police à espacement fixe", + "codeFontFamilyDesc": "Utilisé pour les blocs de code et les zones de largeur constante.", + "fontDefaultLabel": "Par défaut (pile de polices intégrée)", + "fontFamily": "Police d'interface", + "fontFamilyDesc": "Sélectionnez la police principale de l'interface. Si laissé vide, utilisez la pile de polices intégrée.", + "fontReset": "réinitialiser par défaut", + "fontSearchEmpty": "Aucune police correspondante", + "fontSearchPlaceholder": "Rechercher une police", + "fontSystemLoading": "Chargement des polices système...", + "fontTitle": "fonte", + "fontUsageHint": "Certaines interfaces nécessitent le redémarrage de l'application pour prendre effet. Si la police n'est pas disponible, elle reviendra automatiquement à la police par défaut." }, "shortcuts": { "title": "Paramètres des raccourcis clavier", diff --git a/src/renderer/src/i18n/he-IL/settings.json b/src/renderer/src/i18n/he-IL/settings.json index 4084f2e65..bd6f759d1 100644 --- a/src/renderer/src/i18n/he-IL/settings.json +++ b/src/renderer/src/i18n/he-IL/settings.json @@ -814,7 +814,18 @@ "text-xl": "גדול מאוד", "text-2xl": "ענק", "floatingButton": "כפתור צף", - "floatingButtonDesc": "הצג כפתור צף על שולחן העבודה להפעלה מהירה של חלון האפליקציה" + "floatingButtonDesc": "הצג כפתור צף על שולחן העבודה להפעלה מהירה של חלון האפליקציה", + "codeFontFamily": "גופן מונו-רווח", + "codeFontFamilyDesc": "משמש עבור בלוקי קוד ואזורים ברוחב קבוע.", + "fontDefaultLabel": "ברירת מחדל (ערימת גופנים מובנית)", + "fontFamily": "גופן ממשק", + "fontFamilyDesc": "בחר את הגופן הראשי של הממשק. אם נשאר ריק, השתמש בערימת הגופנים המובנית.", + "fontReset": "לאפס לברירת המחדל", + "fontSearchEmpty": "אין גופן תואם", + "fontSearchPlaceholder": "חיפוש גופן", + "fontSystemLoading": "טוען גופני מערכת...", + "fontTitle": "גוֹפָן", + "fontUsageHint": "ממשקים מסוימים דורשים הפעלה מחדש של היישום כדי להיכנס לתוקף. אם הגופן אינו זמין, הוא יחזור אוטומטית לגופן ברירת המחדל." }, "shortcuts": { "title": "הגדרות קיצורי מקשים", diff --git a/src/renderer/src/i18n/ja-JP/settings.json b/src/renderer/src/i18n/ja-JP/settings.json index 4a9728c75..ecdd36bae 100644 --- a/src/renderer/src/i18n/ja-JP/settings.json +++ b/src/renderer/src/i18n/ja-JP/settings.json @@ -814,7 +814,18 @@ "text-xl": "XL", "text-2xl": "XXL", "floatingButton": "フローティングボタン", - "floatingButtonDesc": "デスクトップにフローティングボタンを表示し、アプリケーションウィンドウを素早く起動できます" + "floatingButtonDesc": "デスクトップにフローティングボタンを表示し、アプリケーションウィンドウを素早く起動できます", + "codeFontFamily": "等幅フォント", + "codeFontFamilyDesc": "コードブロックと固定幅領域に使用されます。", + "fontDefaultLabel": "デフォルト(内蔵フォントスタック)", + "fontFamily": "インターフェースフォント", + "fontFamilyDesc": "インターフェースのメインフォントを選択します。空白のままにすると、組み込みのフォント スタックが使用されます。", + "fontReset": "デフォルトにリセットする", + "fontSearchEmpty": "一致するフォントがありません", + "fontSearchPlaceholder": "フォントの検索", + "fontSystemLoading": "システムフォントを読み込んでいます...", + "fontTitle": "フォント", + "fontUsageHint": "一部のインターフェイスを有効にするには、アプリケーションを再起動する必要があります。フォントが使用できない場合は、自動的にデフォルトのフォントに戻ります。" }, "shortcuts": { "title": "ショートカットキー設定", diff --git a/src/renderer/src/i18n/ko-KR/settings.json b/src/renderer/src/i18n/ko-KR/settings.json index cdcf336f2..3b93a05db 100644 --- a/src/renderer/src/i18n/ko-KR/settings.json +++ b/src/renderer/src/i18n/ko-KR/settings.json @@ -814,7 +814,18 @@ "text-xl": "XL", "text-2xl": "XXL", "floatingButton": "플로팅 버튼", - "floatingButtonDesc": "데스크톱에 플로팅 버튼을 표시하여 애플리케이션 창을 빠르게 활성화할 수 있습니다" + "floatingButtonDesc": "데스크톱에 플로팅 버튼을 표시하여 애플리케이션 창을 빠르게 활성화할 수 있습니다", + "codeFontFamily": "고정 폭 글꼴", + "codeFontFamilyDesc": "코드 블록 및 고정 너비 영역에 사용됩니다.", + "fontDefaultLabel": "기본값(내장 글꼴 스택)", + "fontFamily": "인터페이스 글꼴", + "fontFamilyDesc": "인터페이스의 기본 글꼴을 선택합니다. 비워두면 내장된 글꼴 스택을 사용합니다.", + "fontReset": "기본값으로 재설정", + "fontSearchEmpty": "일치하는 글꼴이 없습니다.", + "fontSearchPlaceholder": "글꼴 검색", + "fontSystemLoading": "시스템 글꼴 로드 중...", + "fontTitle": "세례반", + "fontUsageHint": "일부 인터페이스를 적용하려면 애플리케이션을 다시 시작해야 합니다. 글꼴을 사용할 수 없는 경우 자동으로 기본 글꼴로 돌아갑니다." }, "shortcuts": { "title": "단축키 설정", diff --git a/src/renderer/src/i18n/pt-BR/settings.json b/src/renderer/src/i18n/pt-BR/settings.json index 862d63c4a..7e6c4b519 100644 --- a/src/renderer/src/i18n/pt-BR/settings.json +++ b/src/renderer/src/i18n/pt-BR/settings.json @@ -814,7 +814,18 @@ "text-xl": "X-Grande", "text-2xl": "XX-Grande", "floatingButton": "Botão Flutuante", - "floatingButtonDesc": "Exibir um botão flutuante na área de trabalho para ativar rapidamente a janela do aplicativo" + "floatingButtonDesc": "Exibir um botão flutuante na área de trabalho para ativar rapidamente a janela do aplicativo", + "codeFontFamily": "fonte monoespaçada", + "codeFontFamilyDesc": "Usado para blocos de código e áreas de largura constante.", + "fontDefaultLabel": "Padrão (pilha de fontes integrada)", + "fontFamily": "Fonte da interface", + "fontFamilyDesc": "Selecione a fonte principal da interface. Se deixado em branco, use a pilha de fontes integrada.", + "fontReset": "redefinir para o padrão", + "fontSearchEmpty": "Nenhuma fonte correspondente", + "fontSearchPlaceholder": "Fonte de pesquisa", + "fontSystemLoading": "Carregando fontes do sistema...", + "fontTitle": "fonte", + "fontUsageHint": "Algumas interfaces exigem a reinicialização do aplicativo para que tenham efeito. Se a fonte não estiver disponível, ela retornará automaticamente à fonte padrão." }, "shortcuts": { "title": "Configurações de Teclas de Atalho", diff --git a/src/renderer/src/i18n/ru-RU/settings.json b/src/renderer/src/i18n/ru-RU/settings.json index 26f7dc715..e11a8c4ad 100644 --- a/src/renderer/src/i18n/ru-RU/settings.json +++ b/src/renderer/src/i18n/ru-RU/settings.json @@ -814,7 +814,18 @@ "text-xl": "XL", "text-2xl": "XXL", "floatingButton": "Плавающая кнопка", - "floatingButtonDesc": "Отображать плавающую кнопку на рабочем столе для быстрого активации окна приложения" + "floatingButtonDesc": "Отображать плавающую кнопку на рабочем столе для быстрого активации окна приложения", + "codeFontFamily": "моноширинный шрифт", + "codeFontFamilyDesc": "Используется для блоков кода и областей постоянной ширины.", + "fontDefaultLabel": "По умолчанию (встроенный стек шрифтов)", + "fontFamily": "Шрифт интерфейса", + "fontFamilyDesc": "Выберите основной шрифт интерфейса. Если оставить пустым, используйте встроенный стек шрифтов.", + "fontReset": "сбросить настройки по умолчанию", + "fontSearchEmpty": "Нет подходящего шрифта", + "fontSearchPlaceholder": "Поиск шрифта", + "fontSystemLoading": "Загрузка системных шрифтов...", + "fontTitle": "шрифт", + "fontUsageHint": "Для вступления в силу некоторых интерфейсов требуется перезапуск приложения. Если шрифт недоступен, он автоматически вернется к шрифту по умолчанию." }, "shortcuts": { "title": "Настройки сочетаний клавиш", diff --git a/src/renderer/src/i18n/zh-CN/settings.json b/src/renderer/src/i18n/zh-CN/settings.json index 3b299947f..455fddd2f 100644 --- a/src/renderer/src/i18n/zh-CN/settings.json +++ b/src/renderer/src/i18n/zh-CN/settings.json @@ -807,6 +807,17 @@ "latestVersion": "已是最新版本" }, "display": { + "fontTitle": "字体", + "fontFamily": "界面字体", + "fontFamilyDesc": "选择界面主字体,留空时使用内置字体栈。", + "codeFontFamily": "等宽字体", + "codeFontFamilyDesc": "用于代码块和等宽区域。", + "fontDefaultLabel": "默认(内置字体栈)", + "fontSearchPlaceholder": "搜索字体", + "fontSearchEmpty": "没有匹配的字体", + "fontReset": "重置为默认", + "fontSystemLoading": "正在加载系统字体...", + "fontUsageHint": "部分界面需要重启应用后才会生效,如果字体不可用,将自动回落到默认字体。", "fontSize": "文字大小", "text-sm": "小", "text-base": "标准", diff --git a/src/renderer/src/i18n/zh-HK/settings.json b/src/renderer/src/i18n/zh-HK/settings.json index c5a0b83ea..e85619edf 100644 --- a/src/renderer/src/i18n/zh-HK/settings.json +++ b/src/renderer/src/i18n/zh-HK/settings.json @@ -814,7 +814,18 @@ "text-xl": "特大", "text-2xl": "超大", "floatingButton": "懸浮按鈕", - "floatingButtonDesc": "在桌面顯示一個懸浮按鈕,可以快速喚起應用程式視窗" + "floatingButtonDesc": "在桌面顯示一個懸浮按鈕,可以快速喚起應用程式視窗", + "codeFontFamily": "等寬字體", + "codeFontFamilyDesc": "用於代碼塊和等寬區域。", + "fontDefaultLabel": "默認(內置字體棧)", + "fontFamily": "界面字體", + "fontFamilyDesc": "選擇界面主字體,留空時使用內置字體棧。", + "fontReset": "重置為默認", + "fontSearchEmpty": "沒有匹配的字體", + "fontSearchPlaceholder": "搜索字體", + "fontSystemLoading": "正在加載系統字體...", + "fontTitle": "字體", + "fontUsageHint": "部分界面需要重啟應用後才會生效,如果字體不可用,將自動回落到默認字體。" }, "shortcuts": { "title": "快捷鍵設置", diff --git a/src/renderer/src/i18n/zh-TW/settings.json b/src/renderer/src/i18n/zh-TW/settings.json index f887800e6..f82ca28a5 100644 --- a/src/renderer/src/i18n/zh-TW/settings.json +++ b/src/renderer/src/i18n/zh-TW/settings.json @@ -814,7 +814,18 @@ "text-xl": "特大", "text-2xl": "超大", "floatingButton": "懸浮按鈕", - "floatingButtonDesc": "在桌面顯示一個懸浮按鈕,可以快速喚起應用程式視窗" + "floatingButtonDesc": "在桌面顯示一個懸浮按鈕,可以快速喚起應用程式視窗", + "codeFontFamily": "等寬字體", + "codeFontFamilyDesc": "用於代碼塊和等寬區域。", + "fontDefaultLabel": "默認(內置字體棧)", + "fontFamily": "界面字體", + "fontFamilyDesc": "選擇界面主字體,留空時使用內置字體棧。", + "fontReset": "重置為默認", + "fontSearchEmpty": "沒有匹配的字體", + "fontSearchPlaceholder": "搜索字體", + "fontSystemLoading": "正在加載系統字體...", + "fontTitle": "字體", + "fontUsageHint": "部分界面需要重啟應用後才會生效,如果字體不可用,將自動回落到默認字體。" }, "shortcuts": { "title": "快捷鍵設置", diff --git a/src/renderer/src/stores/uiSettingsStore.ts b/src/renderer/src/stores/uiSettingsStore.ts index 5c30270cb..5bca34005 100644 --- a/src/renderer/src/stores/uiSettingsStore.ts +++ b/src/renderer/src/stores/uiSettingsStore.ts @@ -5,11 +5,27 @@ import { CONFIG_EVENTS } from '@/events' const FONT_SIZE_CLASSES = ['text-sm', 'text-base', 'text-lg', 'text-xl', 'text-2xl'] const DEFAULT_FONT_SIZE_LEVEL = 1 +const DEFAULT_FONT_STACK = + "'Geist', Noto Sans, ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'" +const DEFAULT_CODE_FONT_STACK = + "'JetBrains Mono', 'Fira Code', 'Menlo', 'Monaco', 'Consolas', 'Courier New', monospace" + +const buildFontStack = (custom: string, fallback: string) => { + const normalized = (custom || '').trim() + if (!normalized) return fallback + const wrapped = + /\s/.test(normalized) && !normalized.includes(',') ? `"${normalized}"` : normalized + return `${wrapped}, ${fallback}` +} export const useUiSettingsStore = defineStore('uiSettings', () => { const configP = usePresenter('configPresenter') const fontSizeLevel = ref(DEFAULT_FONT_SIZE_LEVEL) + const fontFamily = ref('') + const codeFontFamily = ref('') + const systemFonts = ref([]) + const isLoadingFonts = ref(false) const artifactsEffectEnabled = ref(false) const searchPreviewEnabled = ref(true) const contentProtectionEnabled = ref(false) @@ -22,12 +38,19 @@ export const useUiSettingsStore = defineStore('uiSettings', () => { () => FONT_SIZE_CLASSES[fontSizeLevel.value] || FONT_SIZE_CLASSES[DEFAULT_FONT_SIZE_LEVEL] ) + const formattedFontFamily = computed(() => buildFontStack(fontFamily.value, DEFAULT_FONT_STACK)) + const formattedCodeFontFamily = computed(() => + buildFontStack(codeFontFamily.value, DEFAULT_CODE_FONT_STACK) + ) + const loadSettings = async () => { fontSizeLevel.value = (await configP.getSetting('fontSizeLevel')) ?? DEFAULT_FONT_SIZE_LEVEL if (fontSizeLevel.value < 0 || fontSizeLevel.value >= FONT_SIZE_CLASSES.length) { fontSizeLevel.value = DEFAULT_FONT_SIZE_LEVEL } + fontFamily.value = (await configP.getFontFamily()) ?? '' + codeFontFamily.value = (await configP.getCodeFontFamily()) ?? '' artifactsEffectEnabled.value = (await configP.getSetting('artifactsEffectEnabled')) ?? false searchPreviewEnabled.value = await configP.getSearchPreviewEnabled() @@ -44,6 +67,35 @@ export const useUiSettingsStore = defineStore('uiSettings', () => { await configP.setSetting('fontSizeLevel', validLevel) } + const setFontFamily = async (value: string) => { + fontFamily.value = (value || '').trim() + await configP.setFontFamily(fontFamily.value) + } + + const setCodeFontFamily = async (value: string) => { + codeFontFamily.value = (value || '').trim() + await configP.setCodeFontFamily(codeFontFamily.value) + } + + const resetFontSettings = async () => { + fontFamily.value = '' + codeFontFamily.value = '' + await configP.resetFontSettings() + } + + const fetchSystemFonts = async () => { + if (isLoadingFonts.value || systemFonts.value.length > 0) return + isLoadingFonts.value = true + try { + const fonts = await configP.getSystemFonts() + systemFonts.value = fonts || [] + } catch (error) { + console.warn('Failed to fetch system fonts', error) + } finally { + isLoadingFonts.value = false + } + } + const setSearchPreviewEnabled = async (enabled: boolean) => { searchPreviewEnabled.value = enabled await configP.setSearchPreviewEnabled(enabled) @@ -99,6 +151,12 @@ export const useUiSettingsStore = defineStore('uiSettings', () => { window.electron.ipcRenderer.on(CONFIG_EVENTS.NOTIFICATIONS_CHANGED, (_event, value) => { notificationsEnabled.value = value }) + window.electron.ipcRenderer.on(CONFIG_EVENTS.FONT_FAMILY_CHANGED, (_event, value) => { + fontFamily.value = value ?? '' + }) + window.electron.ipcRenderer.on(CONFIG_EVENTS.CODE_FONT_FAMILY_CHANGED, (_event, value) => { + codeFontFamily.value = value ?? '' + }) } onMounted(() => { @@ -114,11 +172,19 @@ export const useUiSettingsStore = defineStore('uiSettings', () => { window.electron.ipcRenderer.removeAllListeners(CONFIG_EVENTS.COPY_WITH_COT_CHANGED) window.electron.ipcRenderer.removeAllListeners(CONFIG_EVENTS.TRACE_DEBUG_CHANGED) window.electron.ipcRenderer.removeAllListeners(CONFIG_EVENTS.NOTIFICATIONS_CHANGED) + window.electron.ipcRenderer.removeAllListeners(CONFIG_EVENTS.FONT_FAMILY_CHANGED) + window.electron.ipcRenderer.removeAllListeners(CONFIG_EVENTS.CODE_FONT_FAMILY_CHANGED) }) return { fontSizeLevel, fontSizeClass, + fontFamily, + codeFontFamily, + systemFonts, + isLoadingFonts, + formattedFontFamily, + formattedCodeFontFamily, artifactsEffectEnabled, searchPreviewEnabled, contentProtectionEnabled, @@ -127,6 +193,10 @@ export const useUiSettingsStore = defineStore('uiSettings', () => { notificationsEnabled, loggingEnabled, updateFontSizeLevel, + setFontFamily, + setCodeFontFamily, + resetFontSettings, + fetchSystemFonts, setSearchPreviewEnabled, setArtifactsEffectEnabled, setContentProtectionEnabled, diff --git a/src/shared/types/presenters/legacy.presenters.d.ts b/src/shared/types/presenters/legacy.presenters.d.ts index ba893e731..cc74e3a0e 100644 --- a/src/shared/types/presenters/legacy.presenters.d.ts +++ b/src/shared/types/presenters/legacy.presenters.d.ts @@ -439,6 +439,13 @@ export interface IConfigPresenter { // Chain of Thought copy settings getCopyWithCotEnabled(): boolean setCopyWithCotEnabled(enabled: boolean): void + // Font settings + getFontFamily(): string + setFontFamily(fontFamily?: string | null): void + getCodeFontFamily(): string + setCodeFontFamily(fontFamily?: string | null): void + resetFontSettings(): void + getSystemFonts(): Promise // Floating button settings getFloatingButtonEnabled(): boolean setFloatingButtonEnabled(enabled: boolean): void diff --git a/test/main/presenter/configPresenter/uiSettingsHelper.test.ts b/test/main/presenter/configPresenter/uiSettingsHelper.test.ts new file mode 100644 index 000000000..c8f581d4f --- /dev/null +++ b/test/main/presenter/configPresenter/uiSettingsHelper.test.ts @@ -0,0 +1,44 @@ +import fontList from 'font-list' +import { beforeEach, describe, expect, it, vi } from 'vitest' + +import { UiSettingsHelper } from '@/presenter/configPresenter/uiSettingsHelper' + +vi.mock('font-list', () => { + const getFonts = vi.fn() + return { default: { getFonts } } +}) + +const getFontsMock = vi.mocked(fontList.getFonts) + +const createHelper = () => + new UiSettingsHelper({ + getSetting: () => undefined, + setSetting: () => undefined + }) + +describe('UiSettingsHelper.getSystemFonts', () => { + beforeEach(() => { + vi.clearAllMocks() + }) + + it('normalizes and caches fonts from font-list', async () => { + getFontsMock.mockResolvedValue(['Inter Regular', 'Inter Bold', 'Menlo']) + const helper = createHelper() + + const fonts = await helper.getSystemFonts() + const cachedFonts = await helper.getSystemFonts() + + expect(getFontsMock).toHaveBeenCalledTimes(1) + expect(fonts).toEqual(['Inter', 'Menlo']) + expect(cachedFonts).toBe(fonts) + }) + + it('returns an empty array when font detection fails', async () => { + getFontsMock.mockRejectedValue(new Error('failed to load')) + const helper = createHelper() + + const fonts = await helper.getSystemFonts() + + expect(fonts).toEqual([]) + }) +}) From 08541344dce8fb24bfedeebb6c8aa2940f12288b Mon Sep 17 00:00:00 2001 From: xiaomo Date: Wed, 10 Dec 2025 15:10:30 +0800 Subject: [PATCH 04/12] fix: font setting not work on settings page (#1169) --- src/renderer/settings/App.vue | 4 +++ .../display/FontSettingsSection.vue | 24 +++++++++++------- src/renderer/src/App.vue | 17 +++---------- .../src/composables/useFontManager.ts | 25 +++++++++++++++++++ 4 files changed, 48 insertions(+), 22 deletions(-) create mode 100644 src/renderer/src/composables/useFontManager.ts diff --git a/src/renderer/settings/App.vue b/src/renderer/settings/App.vue index adf19d78e..db26c0eb1 100644 --- a/src/renderer/settings/App.vue +++ b/src/renderer/settings/App.vue @@ -75,6 +75,7 @@ import { useSearchAssistantStore } from '@/stores/searchAssistantStore' import { useSearchEngineStore } from '@/stores/searchEngineStore' import { useMcpStore } from '@/stores/mcp' import { useMcpInstallDeeplinkHandler } from '../src/lib/storeInitializer' +import { useFontManager } from '../src/composables/useFontManager' const devicePresenter = usePresenter('devicePresenter') const windowPresenter = usePresenter('windowPresenter') @@ -82,6 +83,9 @@ const configPresenter = usePresenter('configPresenter') // Initialize stores const uiSettingsStore = useUiSettingsStore() +const { setupFontListener } = useFontManager() +setupFontListener() + const languageStore = useLanguageStore() const modelCheckStore = useModelCheckStore() const { toast } = useToast() diff --git a/src/renderer/settings/components/display/FontSettingsSection.vue b/src/renderer/settings/components/display/FontSettingsSection.vue index aef105d25..36ed83b19 100644 --- a/src/renderer/settings/components/display/FontSettingsSection.vue +++ b/src/renderer/settings/components/display/FontSettingsSection.vue @@ -1,8 +1,8 @@ @@ -304,6 +314,7 @@ import AcpProfileDialog from './AcpProfileDialog.vue' import AcpProfileManagerDialog from './AcpProfileManagerDialog.vue' import AcpTerminalDialog from './AcpTerminalDialog.vue' import AcpDependencyDialog from './AcpDependencyDialog.vue' +import AcpDebugDialog from './AcpDebugDialog.vue' const { t } = useI18n() const { toast } = useToast() @@ -341,6 +352,11 @@ const missingDependencies = ref< requiredFor?: string[] }> >([]) +const debugDialogState = reactive({ + open: false, + agentId: '', + agentName: '' +}) const profileDialogState = reactive({ open: false, @@ -560,6 +576,12 @@ const openCustomAgentDialog = (agent?: AcpCustomAgent) => { profileDialogState.open = true } +const openDebugDialog = (agent: { id: string; name: string }) => { + debugDialogState.agentId = agent.id + debugDialogState.agentName = agent.name + debugDialogState.open = true +} + const handleProfileSave = async (payload: ProfilePayload) => { if (!profileDialogState.open) return savingProfile.value = true diff --git a/src/renderer/src/components/acp-workspace/AcpWorkspaceFileNode.vue b/src/renderer/src/components/acp-workspace/AcpWorkspaceFileNode.vue index 26cf09245..e02ac2e49 100644 --- a/src/renderer/src/components/acp-workspace/AcpWorkspaceFileNode.vue +++ b/src/renderer/src/components/acp-workspace/AcpWorkspaceFileNode.vue @@ -26,12 +26,7 @@ - + {{ t('chat.acp.workspace.files.contextMenu.openFile') }} diff --git a/src/renderer/src/components/chat-input/ChatInput.vue b/src/renderer/src/components/chat-input/ChatInput.vue index d8d8306f9..e39ec2db9 100644 --- a/src/renderer/src/components/chat-input/ChatInput.vue +++ b/src/renderer/src/components/chat-input/ChatInput.vue @@ -152,8 +152,6 @@
- -