export default { settings: { // ===== Page title ===== title: '⚙️ Settings', // ===== Left nav categories (phase 3 master-detail) ===== navAppearance: 'Appearance', navAiModel: 'AI Models', navKnowledge: 'Knowledge', navPerformance: 'Performance', navSecurity: 'Security', navAdvanced: 'Advanced', // ===== Settings search (phase 4) ===== searchPlaceholder: 'Search settings…', searchNoResult: 'No results', // ===== Instant feedback (phase 5 SettingRow) ===== savedHint: '✓ Saved', // False-success family: red inline feedback for persist/IPC failure saveFailedHint: '✗ Save failed', nextRoundBadge: 'Next message', // Out-of-range clamp notices (concurrency 1-64 + per-conv ≤ global; temperature reports the corrected value) toastConcurrencyClamped: 'Value out of range, corrected automatically (concurrency 1-{max}; per-conversation capped at global)', toastTempClamped: 'Sampling temperature must be within 0-2, corrected to {v}', toastWeightClamped: 'Model weight must be within 0-100; out-of-range values corrected (cleared inputs default to 50)', // Prompt caching toggle save feedback (previously silent) toastAnthropicCacheSaved: 'Prompt caching setting saved', toastAnthropicCacheFail: 'Failed to save the prompt caching setting', // ===== Connection mgmt (phase 7: experimental badge, not wired to AI yet) ===== experimentalBadge: 'Experimental · not wired to AI tools', // ===== AI Provider panel ===== panelAiProvider: '🤖 AI Model Config', addProvider: '+ Add Provider', editProviderTitle: 'Edit Provider', addProviderTitle: 'Add Provider', emptyProvider: 'No AI provider. Click above to add.', badgeDefault: 'Default', actionSetDefault: 'Set as default', detailBaseUrl: 'Base URL', detailModel: 'Model', detailApiKey: 'API Key', detailPoolEnabled: 'In load-balance pool', detailPoolWeight: 'Pool selection weight', badgePoolDisabled: 'Disabled', descPoolEnabled: 'When on, participates in main-chain routing/pool selection; off = config retained but never selected', descPoolWeight: '0-100, higher weight preferred as primary; equal weights ~ round-robin (backend clamps [0,100])', toastPoolUpdateOk: 'Load-balance pool config updated', toastPoolUpdateFail: 'Failed to update pool config: {msg}', // Provider form labelName: 'Name', labelPreset: 'Vendor preset', presetCustom: 'Custom (manual)', labelProviderType: 'Protocol', labelBaseUrl: 'Base URL', labelApiKey: 'API Key', labelDefaultModel: 'Default', labelSamplingTemp: 'Sampling temperature', phSamplingTemp: 'default 0.7', phProviderName: 'e.g. DeepSeek, GLM-4', phBaseUrl: 'https://api.deepseek.com', phApiKey: 'sk-...', // UX-P2 walkthrough: API key show/hide toggle + "leave empty = keep" note apiKeyShow: 'Show', apiKeyHide: 'Hide', apiKeyKeepHint: 'Leave empty while editing to keep the saved API key unchanged', phDefaultModel: 'deepseek-chat', // Direction A (lightweight): defaultModel is only a "suggested starting point"; // guide users to hit "Test connection" to pull the vendor's real model list and overwrite, // avoiding stale preset model ids (DeepSeek chat deprecated / Gemini 2.5→3.5 etc.) misleading them. defaultModelHint: 'Suggested starting point — hit "Test connection" to pull the vendor’s real model list and overwrite', providerTypeOpenaiCompat: 'OpenAI-compatible (DeepSeek / GLM v4 / OpenAI)', providerTypeAnthropic: 'Anthropic-compatible (GLM subscription / Claude)', saving: 'Saving...', // Model fetch (F-01 phase 6) testConnection: 'Test connection & fetch models', fetchingModels: 'Fetching...', fetchHintSaveFirst: 'Save the provider first, then fetch models', labelWeight: 'Weight', modelListTitle: 'Fetched models ({count})', colEnabled: 'Enabled', colModel: 'Model', colAbility: 'Capability', modelListHint: 'After toggling enabled / weight, click "Save" below to write them into the provider config; the next "Test connection" overwrites with fresh probe results', saveModels: 'Save model config', modelListUnsavedHint: 'Model list has unsaved changes (enabled / weight) — closing or navigating away will discard them', toastFetchOk: 'Fetched {count} models', toastFetchEmpty: 'Fetched 0 models — existing config kept', toastFetchFail: 'Fetch failed: {msg}', fetchFailedTimeout: 'Fetch timed out, check that the Base URL is reachable: {msg}', fetchFailedAuth: 'Authentication failed, check your API Key: {msg}', fetchFailedNotFound: 'Endpoint not found, this vendor may not support model listing: {msg}', toastModelEditLocalOnly: 'Enabled / weight are local edits, overwritten on next fetch', // Model trait tags (modality + capability + probe source; cost/intel 去除见 ) tagModality: { text: 'Text', vision: 'Vision', audio: 'Audio', video: 'Video' }, tagCapability: { tool_use: 'Tool use', embedding: 'Embedding', code_gen: 'Code' }, tagSource: { user_set: 'Manual', preset_table: 'Preset', heuristic: 'Heuristic', default: 'Default' }, // Tag tooltips: explain meaning & source reliability (manual = user-edited, highest priority) tagTooltipModality: 'Modality: input types a model accepts (Vision = can read images). From preset table / name heuristic; editable', tagTooltipCapability: 'Capability: what a model can do (Tool use = can call AI tools to act). From preset table / name heuristic; editable', tagTooltipSource: 'Source: Preset = matched built-in table (reliable); Heuristic = guessed from name (approx); Manual = your override (priority)', // In-table manual capability tagging (× to remove, + to add) addTagTitle: 'Add capability / modality', addTagNone: 'All optional capabilities included', // ===== Connection panel ===== panelConnection: '🔗 Connections', addConnection: '+ Add connection', editConnectionTitle: 'Edit connection', addConnectionTitle: 'Add connection', emptyConnection: 'No connection yet. Click the button above to add one.', labelType: 'Type', labelHost: 'Host', labelPort: 'Port', labelUser: 'Username', labelPassword: 'Password', phConnName: 'flux_dev', phHost: '127.0.0.1', phPort: '3306', phUser: 'root', phPassword: '••••••••', // ===== General settings panel ===== panelGeneral: '🎨 General', // 阶段2 UX 重构:GeneralPanel 拆 3 Section 后各 Section 标题 sectionAppearance: '🎨 Appearance', sectionPerformance: '⚡ Performance', sectionAdvanced: '⚙️ Advanced', labelTheme: 'Theme', descTheme: 'Dark / light', themeDark: '🌙 Dark', themeLight: '☀️ Light', themeSystem: '💻 System', labelLanguage: 'Language', descLanguage: 'Interface language', labelAiLanguage: 'AI language', descAiLanguage: 'Default AI reply language', aiLanguageAuto: '🔄 Follow interface language', aiLanguageZh: '🇨🇳 简体中文', aiLanguageEn: '🇺🇸 English', labelDataDir: 'App Data Directory', descDataDir: 'Where DevFlow stores .trash (recycle bin), database, logs and other internal data', labelAutoExecute: 'AI auto-execute scope', descAutoExecute: 'Control risk level AI auto-executes (low/medium/all-takeover)', autoModeLow: 'Low risk (default)', autoModeMedium: 'Include medium', autoModeAll: 'Full takeover (no approval)', autoModeAllConfirmTitle: 'Confirm full AI takeover?', autoModeAllConfirmContent: 'All actions (including high-risk) will be auto-executed without approval. AI may directly perform dangerous operations (delete files / run arbitrary commands, etc.). Confirm only if you trust the current conversation AI.', labelLogLevel: 'Log level', descLogLevel: 'Verbosity of workflow logs', // ===== Approval timeout ===== labelApprovalTimeout: 'Approval timeout', descApprovalTimeout: 'Auto-reject threshold when user does not respond to an approval prompt (only affects approvals started after the change)', approvalTimeoutUnlimited: 'No limit', approvalTimeout5m: '5 minutes', approvalTimeout15m: '15 minutes (default)', approvalTimeout30m: '30 minutes', approvalTimeout60m: '60 minutes', labelShowTokenUsage: 'Show token usage', descShowTokenUsage: 'Show token consumption of each reply in conversations', labelCustomPrompt: 'Custom prompt', descCustomPrompt: 'Appended to the AI system prompt to customize AI behavior', placeholderCustomPrompt: 'e.g.: You specialize in Rust development questions...', // File upload endpoint labelFileUploadBase: 'File upload endpoint', descFileUploadBase: 'When set, chat images are uploaded to your own file service and turned into public URLs; leave empty to embed images locally (base64)', placeholderFileUploadBase: 'e.g.: https://your-file-service.example.com', labelStreamingMd: 'Streaming Markdown rendering', descStreamingMd: 'Render code blocks/lists/headings during streaming (unclosed code blocks degrade to plain text to avoid flicker); when off, only plain text is shown during streaming and full formatting applies after generation completes', labelGlobalConcurrency: 'Global max concurrency', descGlobalConcurrency: 'Shared cap on simultaneous LLM requests across all conversations', labelPerConvConcurrency: 'Per-conversation concurrency', descPerConvConcurrency: 'Concurrent LLM calls within one conversation (main loop / title / distill shared)', labelAgentMaxIterations: 'Agent max iterations', descAgentMaxIterations: 'Max rounds of the agentic loop (stream → tool → feedback) (0=unlimited, 1-50, default 10); changes take effect on the next message', labelUnlimited: 'Unlimited', labelAgentMaxRetries: 'Stream failure retries', descAgentMaxRetries: 'Auto-retry count on stream failure (0-10, default 3); only retries pre-stream failures (no token output yet); mid-stream failures are abandoned', // ===== F-260619-03 Phase A: AI tool allowed dirs panel ===== panelAllowedDirs: '📁 AI Tool Allowed Dirs', descAllowedDirs: 'AI file tools (read/write/list/patch/search) can only access the following authorized directories. The project root (devflow itself) is always implicitly authorized and need not be added. Access to directories not in the list will be rejected.', allowedDirsLoading: 'Loading…', allowedDirsEmpty: 'No extra authorized directories (only project root is authorized by default)', allowedDirsInputPlaceholder: 'Enter absolute path, e.g. E:/wk-lab/u-abc', allowedDirsSelectDir: 'Select Dir', allowedDirsAdd: 'Add', allowedDirsSave: 'Save', allowedDirsReload: 'Reload', allowedDirsLoadFail: 'Failed to load authorized directories', allowedDirsDup: 'This directory is already in the authorized list', allowedDirsAddFail: 'Failed to add authorized directory', allowedDirsRemoveFail: 'Failed to remove authorized directory', // "Trust all directories" master switch (Settings - Security - AI Tool Allowed Dirs panel) labelPathAuthBypass: 'Trust all directories', descPathAuthBypass: 'When enabled, AI can directly access any directory, including sensitive system and credential folders, without per-access prompts. Only enable in trusted environments; exposing sensitive directories risks credential leakage.', pathAuthBypassConfirmTitle: 'Enable "Trust all directories"?', pathAuthBypassConfirmBody: 'Once enabled, AI tools will no longer ask for per-access authorization and can directly reach any path, including sensitive directories such as .ssh and .aws. Sensitive credentials may end up in the conversation context; proceed at your own risk. Are you sure you want to enable it?', // Anthropic prompt caching (Settings - AI Model; KV df-ai-anthropic-cache, default off, effective immediately) panelAnthropicCache: 'AI Prompt Caching', labelAnthropicCache: 'Enable prompt caching', descAnthropicCache: 'When enabled, Anthropic-protocol endpoints get explicit cache breakpoints on the system prompt and conversation history, greatly reducing token cost for long sessions; OpenAI-compatible endpoints also get prefix-stable splitting (volatile content moves to the end of the message stream so automatic prefix caches can hit). Only enable for endpoints that support caching; gateways without support may reject the cache_control field.', // ===== ScriptNode command execution safety ===== panelScriptSafety: '🛡️ Command Execution Safety', descScriptSafety: 'Configure ScriptNode command whitelist/blacklist. Command name is the first token (e.g. `rm -rf /` -> `rm`), compared trimmed and lowercase. Blacklist takes precedence over whitelist.', labelScriptWhitelist: 'Command whitelist', descScriptWhitelist: 'Comma-separated command names (e.g. git,npm,cargo); empty = unrestricted. When non-empty, only listed commands are allowed.', labelScriptBlacklist: 'Command blacklist', descScriptBlacklist: 'Comma-separated command names (e.g. rm,format,shutdown); any match rejects execution.', placeholderScriptWhitelist: 'Leave empty for no restriction, or: git,npm,cargo', placeholderScriptBlacklist: 'Leave empty for no blacklist, or: rm,format', noteScriptSafety: 'Note: backend ScriptNode currently reads DF_SCRIPT_WHITELIST / DF_SCRIPT_BLACKLIST env vars (same comma-separated semantics). This UI only persists on the frontend; wiring to backend is planned for a later release.', // ===== Knowledge base panel ===== panelKnowledge: '📚 Knowledge base', labelAutoExtract: 'Auto-distill knowledge', descAutoExtract: 'Automatically distill reusable knowledge from conversations after they finish (AI proposes candidates, manual review required)', labelTriggerMode: 'Distill trigger', descTriggerMode: 'When auto-distillation is triggered', triggerOnComplete: 'On conversation complete', triggerManualOnly: 'Manual only', labelMinMessages: 'Min message count', descMinMessages: 'Distillation triggers only after this many messages (filters out small talk noise)', labelAutoInject: 'Auto-inject related knowledge', descAutoInject: 'Retrieve related knowledge and inject it into the conversation context during chat', labelVectorEnabled: 'Semantic retrieval (vector)', descVectorEnabled: 'Use Embedding vectors for semantic matching — close meanings surface even with different wording; when off, pure keyword matching with zero external calls', labelEmbeddingProvider: 'Embedding provider', descEmbeddingProvider: 'AI provider used for vectorization (OpenAI-compatible only; switching requires re-embedding all knowledge)', labelEmbeddingModel: 'Embedding model', descEmbeddingModel: 'e.g. embedding-3 (Zhipu) / text-embedding-v4 (Alibaba) / text-embedding-3-small (OpenAI)', embeddingProviderNone: 'Not selected', phEmbeddingModel: 'embedding-3', // ===== Toast ===== toastLoadProviderFail: 'Failed to load providers', toastSaveIncomplete: 'Please fill in all fields (Name / Base URL / API Key / Model)', // L19: confirm before discarding an edited form confirmDiscardUnsaved: 'The form has unsaved changes. Discard them?', toastSaved: 'Saved', toastSaveFail: 'Save failed: {msg}', // save-failure classified guidance (persistent banner, not raw Err text) saveErrKeyringTitle: 'Failed to write key to the OS keychain', saveErrKeyringDetail: 'Original config left unchanged. Backend reason: {msg}\nSuggestion: check the OS keychain/credential store permissions (Windows Credential Manager / macOS Keychain / Linux secret-service daemon), then click "Save" again to retry.', saveErrGenericTitle: 'Failed to save provider config', saveErrGenericDetail: 'Backend reason: {msg}\nSuggestion: double-check the form fields (Name / Base URL / Model), then click "Save" again to retry; check the logs if it keeps failing.', toastDeleted: 'Deleted', toastDeleteFail: 'Delete failed: {msg}', toastSetDefaultOk: 'Set as default', toastSetDefaultFail: 'Failed to set default: {msg}', toastConnIncomplete: 'Please fill in Name and Host', toastConnPortInvalid: 'Port must be between 1 and 65535', // ===== Import / Export (phase 6) ===== export: 'Export', import: 'Import', exportHint: 'Export all preferences (appSettings + knowledge config) as a JSON file', importHint: 'Import from a JSON file and overwrite current preferences', importConfirm: 'Importing will overwrite all current preferences (appearance / performance / knowledge, etc.). Continue?', importSuccess: 'Imported successfully (some items like concurrency / iterations take effect after restart or next message)', importFail: 'Import failed: {msg}', exportFail: 'Export failed: {msg}', importInvalidJson: 'The file is not a valid DevFlow settings backup (wrong format)', importScopeNote: 'Scope: appSettings + knowledge config (no provider keys)', // ===== Confirm dialogs ===== confirmDeleteProvider: 'Delete provider "{name}"? This cannot be undone.', confirmDeleteConn: 'Delete connection "{name}"?', }, }