diff --git a/src/components/ApiKeysSettings.jsx b/src/components/ApiKeysSettings.jsx index 2687d83..1ab27df 100644 --- a/src/components/ApiKeysSettings.jsx +++ b/src/components/ApiKeysSettings.jsx @@ -3,8 +3,10 @@ import { Button } from './ui/button'; import { Input } from './ui/input'; import { Key, Plus, Trash2, Eye, EyeOff, Copy, Check, Github } from 'lucide-react'; import { authenticatedFetch } from '../utils/api'; +import { useTranslation } from 'react-i18next'; function ApiKeysSettings() { + const { t } = useTranslation('settings'); const [apiKeys, setApiKeys] = useState([]); const [githubTokens, setGithubTokens] = useState([]); const [loading, setLoading] = useState(true); @@ -63,7 +65,7 @@ function ApiKeysSettings() { }; const deleteApiKey = async (keyId) => { - if (!confirm('Are you sure you want to delete this API key?')) return; + if (!confirm(t('apiKeys.confirmDelete'))) return; try { await authenticatedFetch(`/api/settings/api-keys/${keyId}`, { @@ -113,7 +115,7 @@ function ApiKeysSettings() { }; const deleteGithubToken = async (tokenId) => { - if (!confirm('Are you sure you want to delete this GitHub token?')) return; + if (!confirm(t('apiKeys.github.confirmDelete'))) return; try { await authenticatedFetch(`/api/settings/credentials/${tokenId}`, { @@ -144,7 +146,7 @@ function ApiKeysSettings() { }; if (loading) { - return
- This is the only time you'll see this key. Store it securely. + {t('apiKeys.newKey.alertMessage')}
@@ -174,7 +176,7 @@ function ApiKeysSettings() { className="mt-3" onClick={() => setNewlyCreatedKey(null)} > - I've saved it + {t('apiKeys.newKey.iveSavedIt')}
- Generate API keys to access the external API from other applications. + {t('apiKeys.description')}
No API keys created yet.
{t('apiKeys.empty')}
{key.api_key}
- Add GitHub Personal Access Tokens to clone private repositories via the external API. + {t('apiKeys.github.description')}
No GitHub tokens added yet.
{t('apiKeys.github.empty')}
- Learn how to use the external API to trigger Claude/Cursor sessions from your applications. + {t('apiKeys.documentation.description')}
- {children} -
+ {children} +
{children} @@ -485,6 +490,7 @@ const markdownComponents = { // Memoized message component to prevent unnecessary re-renders const MessageComponent = memo(({ message, index, prevMessage, createDiff, onFileOpen, onShowSettings, onGrantToolPermission, autoExpandTools, showRawParameters, showThinking, selectedProject, provider }) => { + const { t } = useTranslation('chat'); const isGrouped = prevMessage && prevMessage.type === message.type && ((prevMessage.type === 'assistant') || (prevMessage.type === 'user') || @@ -587,7 +593,7 @@ const MessageComponent = memo(({ message, index, prevMessage, createDiff, onFile )} - {message.type === 'error' ? 'Error' : message.type === 'tool' ? 'Tool' : ((localStorage.getItem('selected-provider') || 'claude') === 'cursor' ? 'Cursor' : (localStorage.getItem('selected-provider') || 'claude') === 'codex' ? 'Codex' : 'Claude')} + {message.type === 'error' ? t('messageTypes.error') : message.type === 'tool' ? t('messageTypes.tool') : ((localStorage.getItem('selected-provider') || 'claude') === 'cursor' ? t('messageTypes.cursor') : (localStorage.getItem('selected-provider') || 'claude') === 'codex' ? t('messageTypes.codex') : t('messageTypes.claude'))} )} @@ -615,8 +621,8 @@ const MessageComponent = memo(({ message, index, prevMessage, createDiff, onFile const input = JSON.parse(message.toolInput); return ( - {input.pattern && pattern: {input.pattern}} - {input.path && in: {input.path}} + {input.pattern && {t('search.pattern')} {input.pattern}} + {input.path && {t('search.in')} {input.path}} ); } catch (e) { @@ -629,7 +635,7 @@ const MessageComponent = memo(({ message, index, prevMessage, createDiff, onFile href={`#tool-result-${message.toolId}`} className="flex-shrink-0 text-xs text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300 font-medium transition-colors flex items-center gap-1" > - results + {t('tools.searchResults')} @@ -673,7 +679,7 @@ const MessageComponent = memo(({ message, index, prevMessage, createDiff, onFile onShowSettings(); }} className="p-2 rounded-lg hover:bg-white/60 dark:hover:bg-gray-800/60 transition-all duration-200 group/btn backdrop-blur-sm" - title="Tool Settings" + title={t('tools.settings')} > @@ -1851,6 +1857,7 @@ const ImageAttachment = ({ file, onRemove, uploadProgress, error }) => { // This ensures uninterrupted chat experience by pausing sidebar refreshes during conversations. function ChatInterface({ selectedProject, selectedSession, ws, sendMessage, messages, onFileOpen, onInputFocusChange, onSessionActive, onSessionInactive, onSessionProcessing, onSessionNotProcessing, processingSessions, onReplaceTemporarySession, onNavigateToSession, onShowSettings, autoExpandTools, showRawParameters, showThinking, autoScrollToBottom, sendByCtrlEnter, externalMessageUpdate, onTaskClick, onShowAllTasks }) { const { tasksEnabled, isTaskMasterInstalled } = useTasksSettings(); + const { t } = useTranslation('chat'); const [input, setInput] = useState(() => { if (typeof window !== 'undefined' && selectedProject) { return safeLocalStorage.getItem(`draft_input_${selectedProject.name}`) || ''; @@ -5191,7 +5198,7 @@ function ChatInterface({ selectedProject, selectedSession, ws, sendMessage, mess ? 'bg-orange-50 dark:bg-orange-900/20 text-orange-700 dark:text-orange-300 border-orange-300 dark:border-orange-600 hover:bg-orange-100 dark:hover:bg-orange-900/30' : 'bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-300 border-blue-300 dark:border-blue-600 hover:bg-blue-100 dark:hover:bg-blue-900/30' }`} - title="Click to change permission mode (or press Tab in input)" + title={t('input.clickToChangeMode')} > - {permissionMode === 'default' && 'Default Mode'} - {permissionMode === 'acceptEdits' && 'Accept Edits'} - {permissionMode === 'bypassPermissions' && 'Bypass Permissions'} - {permissionMode === 'plan' && 'Plan Mode'} + {permissionMode === 'default' && t('codex.modes.default')} + {permissionMode === 'acceptEdits' && t('codex.modes.acceptEdits')} + {permissionMode === 'bypassPermissions' && t('codex.modes.bypassPermissions')} + {permissionMode === 'plan' && t('codex.modes.plan')} @@ -5236,7 +5243,7 @@ function ChatInterface({ selectedProject, selectedSession, ws, sendMessage, mess } }} className="relative w-8 h-8 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 rounded-full flex items-center justify-center transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:ring-offset-gray-800" - title="Show all commands" + title={t('input.showAllCommands')} > lineHeight * 2; setIsTextareaExpanded(isExpanded); }} - placeholder={`Type / for commands, @ for files, or ask ${provider === 'cursor' ? 'Cursor' : 'Claude'} anything...`} + placeholder={t('input.placeholder', { provider: provider === 'cursor' ? t('messageTypes.cursor') : provider === 'codex' ? t('messageTypes.codex') : t('messageTypes.claude') })} disabled={isLoading} className="chat-input-placeholder block w-full pl-12 pr-20 sm:pr-40 py-1.5 sm:py-4 bg-transparent rounded-2xl focus:outline-none text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 disabled:opacity-50 resize-none min-h-[50px] sm:min-h-[80px] max-h-[40vh] sm:max-h-[300px] overflow-y-auto text-sm sm:text-base leading-[21px] sm:leading-6 transition-all duration-200" style={{ height: '50px' }} @@ -5431,7 +5438,7 @@ function ChatInterface({ selectedProject, selectedSession, ws, sendMessage, mess type="button" onClick={open} className="absolute left-2 top-1/2 transform -translate-y-1/2 p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors" - title="Attach images" + title={t('input.attachImages')} > @@ -5480,8 +5487,8 @@ function ChatInterface({ selectedProject, selectedSession, ws, sendMessage, mess input.trim() ? 'opacity-0' : 'opacity-100' }`}> {sendByCtrlEnter - ? "Ctrl+Enter to send • Shift+Enter for new line • Tab to change modes • / for slash commands" - : "Enter to send • Shift+Enter for new line • Tab to change modes • / for slash commands"} + ? t('input.hintText.ctrlEnter') + : t('input.hintText.enter')} diff --git a/src/components/CredentialsSettings.jsx b/src/components/CredentialsSettings.jsx index 1150b9f..cc7d424 100644 --- a/src/components/CredentialsSettings.jsx +++ b/src/components/CredentialsSettings.jsx @@ -5,8 +5,10 @@ import { Key, Plus, Trash2, Eye, EyeOff, Copy, Check, Github, ExternalLink } fro import { useVersionCheck } from '../hooks/useVersionCheck'; import { version } from '../../package.json'; import { authenticatedFetch } from '../utils/api'; +import { useTranslation } from 'react-i18next'; function CredentialsSettings() { + const { t } = useTranslation('settings'); const [apiKeys, setApiKeys] = useState([]); const [githubCredentials, setGithubCredentials] = useState([]); const [loading, setLoading] = useState(true); @@ -69,7 +71,7 @@ function CredentialsSettings() { }; const deleteApiKey = async (keyId) => { - if (!confirm('Are you sure you want to delete this API key?')) return; + if (!confirm(t('apiKeys.confirmDelete'))) return; try { await authenticatedFetch(`/api/settings/api-keys/${keyId}`, { @@ -121,7 +123,7 @@ function CredentialsSettings() { }; const deleteGithubCredential = async (credentialId) => { - if (!confirm('Are you sure you want to delete this GitHub token?')) return; + if (!confirm(t('apiKeys.github.confirmDelete'))) return; try { await authenticatedFetch(`/api/settings/credentials/${credentialId}`, { @@ -152,7 +154,7 @@ function CredentialsSettings() { }; if (loading) { - return Loading...; + return {t('apiKeys.loading')}; } return ( @@ -160,9 +162,9 @@ function CredentialsSettings() { {/* New API Key Alert */} {newlyCreatedKey && ( - ⚠️ Save Your API Key + {t('apiKeys.newKey.alertTitle')} - This is the only time you'll see this key. Store it securely. + {t('apiKeys.newKey.alertMessage')} @@ -182,7 +184,7 @@ function CredentialsSettings() { className="mt-3" onClick={() => setNewlyCreatedKey(null)} > - I've saved it + {t('apiKeys.newKey.iveSavedIt')} )} @@ -192,20 +194,20 @@ function CredentialsSettings() { - API Keys + {t('apiKeys.title')} setShowNewKeyForm(!showNewKeyForm)} > - New API Key + {t('apiKeys.newButton')} - Generate API keys to access the external API from other applications. + {t('apiKeys.description')} - API Documentation + {t('apiKeys.apiDocsLink')} @@ -221,15 +223,15 @@ function CredentialsSettings() { {showNewKeyForm && ( setNewKeyName(e.target.value)} className="mb-2" /> - Create + {t('apiKeys.form.createButton')} setShowNewKeyForm(false)}> - Cancel + {t('apiKeys.form.cancelButton')} @@ -237,7 +239,7 @@ function CredentialsSettings() { {apiKeys.length === 0 ? ( - No API keys created yet. + {t('apiKeys.empty')} ) : ( apiKeys.map((key) => ( {key.key_name} {key.api_key} - Created: {new Date(key.created_at).toLocaleDateString()} - {key.last_used && ` • Last used: ${new Date(key.last_used).toLocaleDateString()}`} + {t('apiKeys.list.created')} {new Date(key.created_at).toLocaleDateString()} + {key.last_used && ` • ${t('apiKeys.list.lastUsed')} ${new Date(key.last_used).toLocaleDateString()}`} @@ -258,7 +260,7 @@ function CredentialsSettings() { variant={key.is_active ? 'outline' : 'secondary'} onClick={() => toggleApiKey(key.id, key.is_active)} > - {key.is_active ? 'Active' : 'Inactive'} + {key.is_active ? t('apiKeys.status.active') : t('apiKeys.status.inactive')} - GitHub Credentials + {t('apiKeys.github.title')} setShowNewGithubForm(!showNewGithubForm)} > - Add Token + {t('apiKeys.github.addButton')} - Add GitHub Personal Access Tokens to clone private repositories. You can also pass tokens directly in API requests without storing them. + {t('apiKeys.github.descriptionAlt')} {showNewGithubForm && ( setNewGithubName(e.target.value)} /> @@ -305,7 +307,7 @@ function CredentialsSettings() { setNewGithubToken(e.target.value)} className="pr-10" @@ -320,20 +322,20 @@ function CredentialsSettings() { setNewGithubDescription(e.target.value)} /> - Add Token + {t('apiKeys.github.form.addButton')} { setShowNewGithubForm(false); setNewGithubName(''); setNewGithubToken(''); setNewGithubDescription(''); }}> - Cancel + {t('apiKeys.github.form.cancelButton')} @@ -343,14 +345,14 @@ function CredentialsSettings() { rel="noopener noreferrer" className="text-xs text-primary hover:underline block" > - How to create a GitHub Personal Access Token → + {t('apiKeys.github.form.howToCreate')} )} {githubCredentials.length === 0 ? ( - No GitHub tokens added yet. + {t('apiKeys.github.empty')} ) : ( githubCredentials.map((credential) => ( {credential.description} )} - Added: {new Date(credential.created_at).toLocaleDateString()} + {t('apiKeys.github.added')} {new Date(credential.created_at).toLocaleDateString()} @@ -372,7 +374,7 @@ function CredentialsSettings() { variant={credential.is_active ? 'outline' : 'secondary'} onClick={() => toggleGithubCredential(credential.id, credential.is_active)} > - {credential.is_active ? 'Active' : 'Inactive'} + {credential.is_active ? t('apiKeys.status.active') : t('apiKeys.status.inactive')} - Update available: v{latestVersion} + {t('apiKeys.version.updateAvailable', { version: latestVersion })} )} diff --git a/src/components/GitSettings.jsx b/src/components/GitSettings.jsx index 91b0902..cdce8e4 100644 --- a/src/components/GitSettings.jsx +++ b/src/components/GitSettings.jsx @@ -3,8 +3,10 @@ import { Button } from './ui/button'; import { Input } from './ui/input'; import { GitBranch, Check } from 'lucide-react'; import { authenticatedFetch } from '../utils/api'; +import { useTranslation } from 'react-i18next'; function GitSettings() { + const { t } = useTranslation('settings'); const [gitName, setGitName] = useState(''); const [gitEmail, setGitEmail] = useState(''); const [gitConfigLoading, setGitConfigLoading] = useState(false); @@ -61,17 +63,17 @@ function GitSettings() { - Git Configuration + {t('git.title')} - Configure your git identity for commits. These settings will be applied globally via git config --global + {t('git.description')} - Git Name + {t('git.name.label')} - Your name for git commits + {t('git.name.help')} - Git Email + {t('git.email.label')} - Your email for git commits + {t('git.email.help')} @@ -110,13 +112,13 @@ function GitSettings() { onClick={saveGitConfig} disabled={gitConfigSaving || !gitName || !gitEmail} > - {gitConfigSaving ? 'Saving...' : 'Save Configuration'} + {gitConfigSaving ? t('git.actions.saving') : t('git.actions.save')} {saveStatus === 'success' && ( - Saved successfully + {t('git.status.success')} )} diff --git a/src/components/Settings.jsx b/src/components/Settings.jsx index cc8809f..9f541e9 100644 --- a/src/components/Settings.jsx +++ b/src/components/Settings.jsx @@ -950,7 +950,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { - Settings + {t('title')} - Agents + {t('mainTabs.agents')} setActiveTab('appearance')} @@ -985,7 +985,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { : 'border-transparent text-muted-foreground hover:text-foreground' }`} > - Appearance + {t('mainTabs.appearance')} setActiveTab('git')} @@ -996,7 +996,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { }`} > - Git + {t('mainTabs.git')} setActiveTab('api')} @@ -1007,7 +1007,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { }`} > - API & Tokens + {t('mainTabs.apiTokens')} setActiveTab('tasks')} @@ -1017,7 +1017,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { : 'border-transparent text-muted-foreground hover:text-foreground' }`} > - Tasks + {t('mainTabs.tasks')} @@ -1035,10 +1035,10 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { - Dark Mode + {t('appearanceSettings.darkMode.label')} - Toggle between light and dark themes + {t('appearanceSettings.darkMode.description')} - Project Sorting + {t('appearanceSettings.projectSorting.label')} - How projects are ordered in the sidebar + {t('appearanceSettings.projectSorting.description')} setProjectSortOrder(e.target.value)} className="text-sm bg-gray-50 dark:bg-gray-800 border border-gray-300 dark:border-gray-600 text-gray-900 dark:text-gray-100 rounded-lg focus:ring-blue-500 focus:border-blue-500 p-2 w-32" > - Alphabetical - Recent Activity + {t('appearanceSettings.projectSorting.alphabetical')} + {t('appearanceSettings.projectSorting.recentActivity')} @@ -1096,17 +1096,17 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { {/* Code Editor Settings */} - Code Editor + {t('appearanceSettings.codeEditor.title')} {/* Editor Theme */} - Editor Theme + {t('appearanceSettings.codeEditor.theme.label')} - Default theme for the code editor + {t('appearanceSettings.codeEditor.theme.description')} - Word Wrap + {t('appearanceSettings.codeEditor.wordWrap.label')} - Enable word wrapping by default in the editor + {t('appearanceSettings.codeEditor.wordWrap.description')} - Show Minimap + {t('appearanceSettings.codeEditor.showMinimap.label')} - Display a minimap for easier navigation in diff view + {t('appearanceSettings.codeEditor.showMinimap.description')} - Show Line Numbers + {t('appearanceSettings.codeEditor.lineNumbers.label')} - Display line numbers in the editor + {t('appearanceSettings.codeEditor.lineNumbers.description')} - Font Size + {t('appearanceSettings.codeEditor.fontSize.label')} - Editor font size in pixels + {t('appearanceSettings.codeEditor.fontSize.description')} - {editingMcpServer ? 'Edit MCP Server' : 'Add MCP Server'} + {editingMcpServer ? t('mcpForm.title.edit') : t('mcpForm.title.add')} @@ -1472,7 +1472,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { : 'bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700' }`} > - Form Input + {t('mcpForm.importMode.form')} - JSON Import + {t('mcpForm.importMode.json')} )} @@ -1492,12 +1492,12 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { {mcpFormData.importMode === 'form' && editingMcpServer && ( - Scope + {t('mcpForm.scope.label')} {mcpFormData.scope === 'user' ? : } - {mcpFormData.scope === 'user' ? 'User (Global)' : 'Project (Local)'} + {mcpFormData.scope === 'user' ? t('mcpForm.scope.userGlobal') : t('mcpForm.scope.projectLocal')} {mcpFormData.scope === 'local' && mcpFormData.projectPath && ( @@ -1506,7 +1506,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { )} - Scope cannot be changed when editing an existing server + {t('mcpForm.scope.cannotChange')} )} @@ -1516,7 +1516,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { - Scope * + {t('mcpForm.scope.label')} * - User (Global) + {t('mcpForm.scope.userGlobal')} - Project (Local) + {t('mcpForm.scope.projectLocal')} - {mcpFormData.scope === 'user' - ? 'User scope: Available across all projects on your machine' - : 'Local scope: Only available in the selected project' + {mcpFormData.scope === 'user' + ? t('mcpForm.scope.userDescription') + : t('mcpForm.scope.projectDescription') } @@ -1560,7 +1560,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { {mcpFormData.scope === 'local' && !editingMcpServer && ( - Project * + {t('mcpForm.fields.selectProject')} * - Select a project... + {t('mcpForm.fields.selectProject')}... {projects.map(project => ( {project.displayName || project.name} @@ -1577,7 +1577,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { {mcpFormData.projectPath && ( - Path: {mcpFormData.projectPath} + {t('mcpForm.projectPath', { path: mcpFormData.projectPath })} )} @@ -1589,22 +1589,22 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { - Server Name * + {t('mcpForm.fields.serverName')} * { setMcpFormData(prev => ({...prev, name: e.target.value})); }} - placeholder="my-server" + placeholder={t('mcpForm.placeholders.serverName')} required /> - + {mcpFormData.importMode === 'form' && ( - Transport Type * + {t('mcpForm.fields.transportType')} * - Configuration Details (from {editingMcpServer.scope === 'global' ? '~/.claude.json' : 'project config'}) + {t('mcpForm.configDetails', { configFile: editingMcpServer.scope === 'global' ? '~/.claude.json' : 'project config' })} {JSON.stringify(mcpFormData.raw, null, 2)} @@ -1639,7 +1639,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { - JSON Configuration * + {t('mcpForm.fields.jsonConfig')} * {jsonValidationError} )} - Paste your MCP server configuration in JSON format. Example formats: + {t('mcpForm.validation.jsonHelp')} • stdio: {`{"type":"stdio","command":"npx","args":["@upstash/context7-mcp"]}`} • http/sse: {`{"type":"http","url":"https://api.example.com/mcp"}`} @@ -1690,7 +1690,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { - Command * + {t('mcpForm.fields.command')} * - + - Arguments (one per line) + {t('mcpForm.fields.arguments')} - URL * + {t('mcpForm.fields.url')} * - Environment Variables (KEY=value, one per line) + {t('mcpForm.fields.envVars')} `${k}=${v}`).join('\n')} @@ -1758,7 +1758,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { {mcpFormData.importMode === 'form' && (mcpFormData.type === 'sse' || mcpFormData.type === 'http') && ( - Headers (KEY=value, one per line) + {t('mcpForm.fields.headers')} `${k}=${v}`).join('\n')} @@ -1782,14 +1782,14 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { - Cancel + {t('mcpForm.actions.cancel')} - - {mcpLoading ? 'Saving...' : (editingMcpServer ? 'Update Server' : 'Add Server')} + {mcpLoading ? t('mcpForm.actions.saving') : (editingMcpServer ? t('mcpForm.actions.updateServer') : t('mcpForm.actions.addServer'))} @@ -1803,7 +1803,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { - {editingCodexMcpServer ? 'Edit MCP Server' : 'Add MCP Server'} + {editingCodexMcpServer ? t('mcpForm.title.edit') : t('mcpForm.title.add')} @@ -1813,19 +1813,19 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { - Server Name * + {t('mcpForm.fields.serverName')} * setCodexMcpFormData(prev => ({...prev, name: e.target.value}))} - placeholder="my-mcp-server" + placeholder={t('mcpForm.placeholders.serverName')} required /> - Command * + {t('mcpForm.fields.command')} * - Arguments (one per line) + {t('mcpForm.fields.arguments')} - Environment Variables (KEY=VALUE, one per line) + {t('mcpForm.fields.envVars')} `${k}=${v}`).join('\n')} @@ -1881,14 +1881,14 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { - Cancel + {t('mcpForm.actions.cancel')} - {codexMcpLoading ? 'Saving...' : (editingCodexMcpServer ? 'Update Server' : 'Add Server')} + {codexMcpLoading ? t('mcpForm.actions.saving') : (editingCodexMcpServer ? t('mcpForm.actions.updateServer') : t('mcpForm.actions.addServer'))} @@ -1919,7 +1919,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { - Settings saved successfully! + {t('saveStatus.success')} )} {saveStatus === 'error' && ( @@ -1927,31 +1927,31 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { - Failed to save settings + {t('saveStatus.error')} )} - - Cancel + {t('footerActions.cancel')} - {isSaving ? ( - Saving... + {t('saveStatus.saving')} ) : ( - 'Save Settings' + t('footerActions.save') )} diff --git a/src/components/TasksSettings.jsx b/src/components/TasksSettings.jsx index ffb4cc3..dda0cf1 100644 --- a/src/components/TasksSettings.jsx +++ b/src/components/TasksSettings.jsx @@ -1,7 +1,9 @@ import { Zap } from 'lucide-react'; import { useTasksSettings } from '../contexts/TasksSettingsContext'; +import { useTranslation } from 'react-i18next'; function TasksSettings() { + const { t } = useTranslation('settings'); const { tasksEnabled, setTasksEnabled, @@ -16,7 +18,7 @@ function TasksSettings() { - Checking TaskMaster installation... + {t('tasks.checking')} ) : ( @@ -32,13 +34,13 @@ function TasksSettings() { - TaskMaster AI CLI Not Installed + {t('tasks.notInstalled.title')} - TaskMaster CLI is required to use task management features. Install it to get started: + {t('tasks.notInstalled.description')} - npm install -g task-master-ai + {t('tasks.notInstalled.installCommand')} @@ -51,7 +53,7 @@ function TasksSettings() { - View on GitHub + {t('tasks.notInstalled.viewOnGitHub')} @@ -59,11 +61,11 @@ function TasksSettings() { - After installation: + {t('tasks.notInstalled.afterInstallation')} - Restart this application - TaskMaster features will automatically become available - Use task-master init in your project directory + {t('tasks.notInstalled.steps.restart')} + {t('tasks.notInstalled.steps.autoAvailable')} + Use task-master init {t('tasks.notInstalled.steps.initCommand')} @@ -79,10 +81,10 @@ function TasksSettings() { - Enable TaskMaster Integration + {t('tasks.settings.enableLabel')} - Show TaskMaster tasks, banners, and sidebar indicators across the interface + {t('tasks.settings.enableDescription')} diff --git a/src/components/settings/AccountContent.jsx b/src/components/settings/AccountContent.jsx index 93e0a9a..e9b2d3f 100644 --- a/src/components/settings/AccountContent.jsx +++ b/src/components/settings/AccountContent.jsx @@ -4,6 +4,7 @@ import { LogIn } from 'lucide-react'; import ClaudeLogo from '../ClaudeLogo'; import CursorLogo from '../CursorLogo'; import CodexLogo from '../CodexLogo'; +import { useTranslation } from 'react-i18next'; const agentConfig = { claude: { @@ -39,6 +40,7 @@ const agentConfig = { }; export default function AccountContent({ agent, authStatus, onLogin }) { + const { t } = useTranslation('settings'); const config = agentConfig[agent]; const { Logo } = config; @@ -47,8 +49,8 @@ export default function AccountContent({ agent, authStatus, onLogin }) { - {config.name} Account - {config.description} + {config.name} + {t(`agents.account.${agent}.description`)} @@ -58,30 +60,30 @@ export default function AccountContent({ agent, authStatus, onLogin }) { - Connection Status + {t('agents.connectionStatus')} {authStatus?.loading ? ( - 'Checking authentication status...' + t('agents.authStatus.checkingAuth') ) : authStatus?.authenticated ? ( - `Logged in as ${authStatus.email || 'authenticated user'}` + t('agents.authStatus.loggedInAs', { email: authStatus.email || t('agents.authStatus.authenticatedUser') }) ) : ( - 'Not connected' + t('agents.authStatus.notConnected') )} {authStatus?.loading ? ( - Checking... + {t('agents.authStatus.checking')} ) : authStatus?.authenticated ? ( - Connected + {t('agents.authStatus.connected')} ) : ( - Disconnected + {t('agents.authStatus.disconnected')} )} @@ -91,12 +93,12 @@ export default function AccountContent({ agent, authStatus, onLogin }) { - {authStatus?.authenticated ? 'Re-authenticate' : 'Login'} + {authStatus?.authenticated ? t('agents.login.reAuthenticate') : t('agents.login.title')} {authStatus?.authenticated - ? 'Sign in with a different account or refresh credentials' - : `Sign in to your ${config.name} account to enable AI features`} + ? t('agents.login.reAuthDescription') + : t('agents.login.description', { agent: config.name })} - {authStatus?.authenticated ? 'Re-login' : 'Login'} + {authStatus?.authenticated ? t('agents.login.reLoginButton') : t('agents.login.button')} @@ -113,7 +115,7 @@ export default function AccountContent({ agent, authStatus, onLogin }) { {authStatus?.error && ( - Error: {authStatus.error} + {t('agents.error', { error: authStatus.error })} )} diff --git a/src/components/settings/AgentListItem.jsx b/src/components/settings/AgentListItem.jsx index e550c23..06e7477 100644 --- a/src/components/settings/AgentListItem.jsx +++ b/src/components/settings/AgentListItem.jsx @@ -1,6 +1,7 @@ import ClaudeLogo from '../ClaudeLogo'; import CursorLogo from '../CursorLogo'; import CodexLogo from '../CodexLogo'; +import { useTranslation } from 'react-i18next'; const agentConfig = { claude: { @@ -42,6 +43,7 @@ const colorClasses = { }; export default function AgentListItem({ agentId, authStatus, isSelected, onClick, isMobile = false }) { + const { t } = useTranslation('settings'); const config = agentConfig[agentId]; const colors = colorClasses[config.color]; const { Logo } = config; @@ -84,18 +86,18 @@ export default function AgentListItem({ agentId, authStatus, isSelected, onClick {authStatus?.loading ? ( - Checking... + {t('agents.authStatus.checking')} ) : authStatus?.authenticated ? ( - {authStatus.email || 'Connected'} + {authStatus.email || t('agents.authStatus.connected')} ) : ( - Not connected + {t('agents.authStatus.notConnected')} )} diff --git a/src/components/settings/McpServersContent.jsx b/src/components/settings/McpServersContent.jsx index 4495ef9..257f58a 100644 --- a/src/components/settings/McpServersContent.jsx +++ b/src/components/settings/McpServersContent.jsx @@ -3,6 +3,7 @@ import { Button } from '../ui/button'; import { Input } from '../ui/input'; import { Badge } from '../ui/badge'; import { Server, Plus, Edit3, Trash2, Terminal, Globe, Zap, X } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; const getTransportIcon = (type) => { switch (type) { @@ -25,16 +26,17 @@ function ClaudeMcpServers({ serverTools, toolsLoading, }) { + const { t } = useTranslation('settings'); return ( - MCP Servers + {t('mcpServers.title')} - Model Context Protocol servers provide additional tools and data sources to Claude + {t('mcpServers.description.claude')} @@ -44,7 +46,7 @@ function ClaudeMcpServers({ size="sm" > - Add MCP Server + {t('mcpServers.addButton')} @@ -60,19 +62,19 @@ function ClaudeMcpServers({ {server.type} - {server.scope === 'local' ? 'local' : server.scope === 'user' ? 'user' : server.scope} + {server.scope === 'local' ? t('mcpServers.scope.local') : server.scope === 'user' ? t('mcpServers.scope.user') : server.scope} {server.type === 'stdio' && server.config?.command && ( - Command: {server.config.command} + {t('mcpServers.config.command')}: {server.config.command} )} {(server.type === 'sse' || server.type === 'http') && server.config?.url && ( - URL: {server.config.url} + {t('mcpServers.config.url')}: {server.config.url} )} {server.config?.args && server.config.args.length > 0 && ( - Args: {server.config.args.join(' ')} + {t('mcpServers.config.args')}: {server.config.args.join(' ')} )} @@ -90,13 +92,13 @@ function ClaudeMcpServers({ {/* Tools Discovery Results */} {serverTools?.[server.id] && serverTools[server.id].tools?.length > 0 && ( - Tools ({serverTools[server.id].tools.length}): + {t('mcpServers.tools.title')} {t('mcpServers.tools.count', { count: serverTools[server.id].tools.length })} {serverTools[server.id].tools.slice(0, 5).map((tool, i) => ( {tool.name} ))} {serverTools[server.id].tools.length > 5 && ( - +{serverTools[server.id].tools.length - 5} more + {t('mcpServers.tools.more', { count: serverTools[server.id].tools.length - 5 })} )} @@ -109,7 +111,7 @@ function ClaudeMcpServers({ variant="ghost" size="sm" className="text-gray-600 hover:text-gray-700" - title="Edit server" + title={t('mcpServers.actions.edit')} > @@ -118,7 +120,7 @@ function ClaudeMcpServers({ variant="ghost" size="sm" className="text-red-600 hover:text-red-700" - title="Delete server" + title={t('mcpServers.actions.delete')} > @@ -128,7 +130,7 @@ function ClaudeMcpServers({ ))} {servers.length === 0 && ( - No MCP servers configured + {t('mcpServers.empty')} )} @@ -138,16 +140,17 @@ function ClaudeMcpServers({ // Cursor MCP Servers function CursorMcpServers({ servers, onAdd, onEdit, onDelete }) { + const { t } = useTranslation('settings'); return ( - MCP Servers + {t('mcpServers.title')} - Model Context Protocol servers provide additional tools and data sources to Cursor + {t('mcpServers.description.cursor')} @@ -157,7 +160,7 @@ function CursorMcpServers({ servers, onAdd, onEdit, onDelete }) { size="sm" > - Add MCP Server + {t('mcpServers.addButton')} @@ -173,7 +176,7 @@ function CursorMcpServers({ servers, onAdd, onEdit, onDelete }) { {server.config?.command && ( - Command: {server.config.command} + {t('mcpServers.config.command')}: {server.config.command} )} @@ -183,6 +186,7 @@ function CursorMcpServers({ servers, onAdd, onEdit, onDelete }) { variant="ghost" size="sm" className="text-gray-600 hover:text-gray-700" + title={t('mcpServers.actions.edit')} > @@ -191,6 +195,7 @@ function CursorMcpServers({ servers, onAdd, onEdit, onDelete }) { variant="ghost" size="sm" className="text-red-600 hover:text-red-700" + title={t('mcpServers.actions.delete')} > @@ -200,7 +205,7 @@ function CursorMcpServers({ servers, onAdd, onEdit, onDelete }) { ))} {servers.length === 0 && ( - No MCP servers configured + {t('mcpServers.empty')} )} @@ -210,16 +215,17 @@ function CursorMcpServers({ servers, onAdd, onEdit, onDelete }) { // Codex MCP Servers function CodexMcpServers({ servers, onAdd, onEdit, onDelete }) { + const { t } = useTranslation('settings'); return ( - MCP Servers + {t('mcpServers.title')} - Model Context Protocol servers provide additional tools and data sources to Codex + {t('mcpServers.description.codex')} @@ -229,7 +235,7 @@ function CodexMcpServers({ servers, onAdd, onEdit, onDelete }) { size="sm" > - Add MCP Server + {t('mcpServers.addButton')} @@ -246,13 +252,13 @@ function CodexMcpServers({ servers, onAdd, onEdit, onDelete }) { {server.config?.command && ( - Command: {server.config.command} + {t('mcpServers.config.command')}: {server.config.command} )} {server.config?.args && server.config.args.length > 0 && ( - Args: {server.config.args.join(' ')} + {t('mcpServers.config.args')}: {server.config.args.join(' ')} )} {server.config?.env && Object.keys(server.config.env).length > 0 && ( - Environment: {Object.entries(server.config.env).map(([k, v]) => `${k}=${v}`).join(', ')} + {t('mcpServers.config.environment')}: {Object.entries(server.config.env).map(([k, v]) => `${k}=${v}`).join(', ')} )} @@ -263,7 +269,7 @@ function CodexMcpServers({ servers, onAdd, onEdit, onDelete }) { variant="ghost" size="sm" className="text-gray-600 hover:text-gray-700" - title="Edit server" + title={t('mcpServers.actions.edit')} > @@ -272,7 +278,7 @@ function CodexMcpServers({ servers, onAdd, onEdit, onDelete }) { variant="ghost" size="sm" className="text-red-600 hover:text-red-700" - title="Delete server" + title={t('mcpServers.actions.delete')} > @@ -282,17 +288,16 @@ function CodexMcpServers({ servers, onAdd, onEdit, onDelete }) { ))} {servers.length === 0 && ( - No MCP servers configured + {t('mcpServers.empty')} )} {/* Help Section */} - About Codex MCP + {t('mcpServers.help.title')} - Codex supports stdio-based MCP servers. You can add servers that extend Codex's capabilities - with additional tools and resources. + {t('mcpServers.help.description')} diff --git a/src/components/settings/PermissionsContent.jsx b/src/components/settings/PermissionsContent.jsx index 608d43e..7bbd53d 100644 --- a/src/components/settings/PermissionsContent.jsx +++ b/src/components/settings/PermissionsContent.jsx @@ -1,6 +1,7 @@ import { Button } from '../ui/button'; import { Input } from '../ui/input'; import { Shield, AlertTriangle, Plus, X } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; // Common tool patterns for Claude const commonClaudeTools = [ @@ -49,6 +50,7 @@ function ClaudePermissions({ newDisallowedTool, setNewDisallowedTool, }) { + const { t } = useTranslation('settings'); const addAllowedTool = (tool) => { if (tool && !allowedTools.includes(tool)) { setAllowedTools([...allowedTools, tool]); @@ -78,7 +80,7 @@ function ClaudePermissions({ - Permission Settings + {t('permissions.title')} @@ -91,10 +93,10 @@ function ClaudePermissions({ /> - Skip permission prompts (use with caution) + {t('permissions.skipPermissions.label')} - Equivalent to --dangerously-skip-permissions flag + {t('permissions.skipPermissions.claudeDescription')} @@ -106,18 +108,18 @@ function ClaudePermissions({ - Allowed Tools + {t('permissions.allowedTools.title')} - Tools that are automatically allowed without prompting for permission + {t('permissions.allowedTools.description')} setNewAllowedTool(e.target.value)} - placeholder='e.g., "Bash(git log:*)" or "Write"' + placeholder={t('permissions.allowedTools.placeholder')} onKeyPress={(e) => { if (e.key === 'Enter') { e.preventDefault(); @@ -133,14 +135,14 @@ function ClaudePermissions({ className="h-10 px-4" > - Add + {t('permissions.actions.add')} {/* Quick add buttons */} - Quick add common tools: + {t('permissions.allowedTools.quickAdd')} {commonClaudeTools.map(tool => ( @@ -176,7 +178,7 @@ function ClaudePermissions({ ))} {allowedTools.length === 0 && ( - No allowed tools configured + {t('permissions.allowedTools.empty')} )} @@ -187,18 +189,18 @@ function ClaudePermissions({ - Blocked Tools + {t('permissions.blockedTools.title')} - Tools that are automatically blocked without prompting for permission + {t('permissions.blockedTools.description')} setNewDisallowedTool(e.target.value)} - placeholder='e.g., "Bash(rm:*)"' + placeholder={t('permissions.blockedTools.placeholder')} onKeyPress={(e) => { if (e.key === 'Enter') { e.preventDefault(); @@ -214,7 +216,7 @@ function ClaudePermissions({ className="h-10 px-4" > - Add + {t('permissions.actions.add')} @@ -236,7 +238,7 @@ function ClaudePermissions({ ))} {disallowedTools.length === 0 && ( - No blocked tools configured + {t('permissions.blockedTools.empty')} )} @@ -245,13 +247,13 @@ function ClaudePermissions({ {/* Help Section */} - Tool Pattern Examples: + {t('permissions.toolExamples.title')} - "Bash(git log:*)" - Allow all git log commands - "Bash(git diff:*)" - Allow all git diff commands - "Write" - Allow all Write tool usage - "Bash(rm:*)" - Block all rm commands (dangerous) + "Bash(git log:*)" {t('permissions.toolExamples.bashGitLog')} + "Bash(git diff:*)" {t('permissions.toolExamples.bashGitDiff')} + "Write" {t('permissions.toolExamples.write')} + "Bash(rm:*)" {t('permissions.toolExamples.bashRm')} @@ -271,6 +273,7 @@ function CursorPermissions({ newDisallowedCommand, setNewDisallowedCommand, }) { + const { t } = useTranslation('settings'); const addAllowedCommand = (cmd) => { if (cmd && !allowedCommands.includes(cmd)) { setAllowedCommands([...allowedCommands, cmd]); @@ -300,7 +303,7 @@ function CursorPermissions({ - Permission Settings + {t('permissions.title')} @@ -313,10 +316,10 @@ function CursorPermissions({ /> - Skip permission prompts (use with caution) + {t('permissions.skipPermissions.label')} - Equivalent to -f flag in Cursor CLI + {t('permissions.skipPermissions.cursorDescription')} @@ -328,18 +331,18 @@ function CursorPermissions({ - Allowed Shell Commands + {t('permissions.allowedCommands.title')} - Shell commands that are automatically allowed without prompting + {t('permissions.allowedCommands.description')} setNewAllowedCommand(e.target.value)} - placeholder='e.g., "Shell(ls)" or "Shell(git status)"' + placeholder={t('permissions.allowedCommands.placeholder')} onKeyPress={(e) => { if (e.key === 'Enter') { e.preventDefault(); @@ -355,14 +358,14 @@ function CursorPermissions({ className="h-10 px-4" > - Add + {t('permissions.actions.add')} {/* Quick add buttons */} - Quick add common commands: + {t('permissions.allowedCommands.quickAdd')} {commonCursorCommands.map(cmd => ( @@ -398,7 +401,7 @@ function CursorPermissions({ ))} {allowedCommands.length === 0 && ( - No allowed commands configured + {t('permissions.allowedCommands.empty')} )} @@ -409,18 +412,18 @@ function CursorPermissions({ - Blocked Shell Commands + {t('permissions.blockedCommands.title')} - Shell commands that are automatically blocked + {t('permissions.blockedCommands.description')} setNewDisallowedCommand(e.target.value)} - placeholder='e.g., "Shell(rm -rf)" or "Shell(sudo)"' + placeholder={t('permissions.blockedCommands.placeholder')} onKeyPress={(e) => { if (e.key === 'Enter') { e.preventDefault(); @@ -436,7 +439,7 @@ function CursorPermissions({ className="h-10 px-4" > - Add + {t('permissions.actions.add')} @@ -458,7 +461,7 @@ function CursorPermissions({ ))} {disallowedCommands.length === 0 && ( - No blocked commands configured + {t('permissions.blockedCommands.empty')} )} @@ -467,13 +470,13 @@ function CursorPermissions({ {/* Help Section */} - Shell Command Examples: + {t('permissions.shellExamples.title')} - "Shell(ls)" - Allow ls command - "Shell(git status)" - Allow git status - "Shell(npm install)" - Allow npm install - "Shell(rm -rf)" - Block recursive delete + "Shell(ls)" {t('permissions.shellExamples.ls')} + "Shell(git status)" {t('permissions.shellExamples.gitStatus')} + "Shell(npm install)" {t('permissions.shellExamples.npmInstall')} + "Shell(rm -rf)" {t('permissions.shellExamples.rmRf')} @@ -482,17 +485,18 @@ function CursorPermissions({ // Codex Permissions function CodexPermissions({ permissionMode, setPermissionMode }) { + const { t } = useTranslation('settings'); return ( - Permission Mode + {t('permissions.codex.permissionMode')} - Controls how Codex handles file modifications and command execution + {t('permissions.codex.description')} {/* Default Mode */} @@ -513,10 +517,9 @@ function CodexPermissions({ permissionMode, setPermissionMode }) { className="mt-1 w-4 h-4 text-green-600" /> - Default + {t('permissions.codex.modes.default.title')} - Only trusted commands (ls, cat, grep, git status, etc.) run automatically. - Other commands are skipped. Can write to workspace. + {t('permissions.codex.modes.default.description')} @@ -540,10 +543,9 @@ function CodexPermissions({ permissionMode, setPermissionMode }) { className="mt-1 w-4 h-4 text-green-600" /> - Accept Edits + {t('permissions.codex.modes.acceptEdits.title')} - All commands run automatically within the workspace. - Full auto mode with sandboxed execution. + {t('permissions.codex.modes.acceptEdits.description')} @@ -568,12 +570,11 @@ function CodexPermissions({ permissionMode, setPermissionMode }) { /> - Bypass Permissions + {t('permissions.codex.modes.bypassPermissions.title')} - Full system access with no restrictions. All commands run automatically - with full disk and network access. Use with caution. + {t('permissions.codex.modes.bypassPermissions.description')} @@ -582,13 +583,13 @@ function CodexPermissions({ permissionMode, setPermissionMode }) { {/* Technical Details */} - Technical details + {t('permissions.codex.technicalDetails')} - Default: sandboxMode=workspace-write, approvalPolicy=untrusted. Trusted commands: cat, cd, grep, head, ls, pwd, tail, git status/log/diff/show, find (without -exec), etc. - Accept Edits: sandboxMode=workspace-write, approvalPolicy=never. All commands auto-execute within project directory. - Bypass Permissions: sandboxMode=danger-full-access, approvalPolicy=never. Full system access, use only in trusted environments. - You can override this per-session using the mode button in the chat interface. + {t('permissions.codex.modes.default.title')}: {t('permissions.codex.technicalInfo.default')} + {t('permissions.codex.modes.acceptEdits.title')}: {t('permissions.codex.technicalInfo.acceptEdits')} + {t('permissions.codex.modes.bypassPermissions.title')}: {t('permissions.codex.technicalInfo.bypassPermissions')} + {t('permissions.codex.technicalInfo.overrideNote')} diff --git a/src/i18n/config.js b/src/i18n/config.js index 334a411..789b993 100644 --- a/src/i18n/config.js +++ b/src/i18n/config.js @@ -18,11 +18,13 @@ import enCommon from './locales/en/common.json'; import enSettings from './locales/en/settings.json'; import enAuth from './locales/en/auth.json'; import enSidebar from './locales/en/sidebar.json'; +import enChat from './locales/en/chat.json'; import zhCommon from './locales/zh-CN/common.json'; import zhSettings from './locales/zh-CN/settings.json'; import zhAuth from './locales/zh-CN/auth.json'; import zhSidebar from './locales/zh-CN/sidebar.json'; +import zhChat from './locales/zh-CN/chat.json'; // Import supported languages configuration import { languages } from './languages.js'; @@ -53,12 +55,14 @@ i18n settings: enSettings, auth: enAuth, sidebar: enSidebar, + chat: enChat, }, 'zh-CN': { common: zhCommon, settings: zhSettings, auth: zhAuth, sidebar: zhSidebar, + chat: zhChat, }, }, @@ -72,7 +76,7 @@ i18n debug: import.meta.env.DEV, // Namespaces - load only what's needed - ns: ['common', 'settings', 'auth', 'sidebar'], + ns: ['common', 'settings', 'auth', 'sidebar', 'chat'], defaultNS: 'common', // Key separator for nested keys (default: '.') diff --git a/src/i18n/locales/en/chat.json b/src/i18n/locales/en/chat.json new file mode 100644 index 0000000..4083a49 --- /dev/null +++ b/src/i18n/locales/en/chat.json @@ -0,0 +1,111 @@ +{ + "codeBlock": { + "copy": "Copy", + "copied": "Copied", + "copyCode": "Copy code" + }, + "messageTypes": { + "user": "U", + "error": "Error", + "tool": "Tool", + "claude": "Claude", + "cursor": "Cursor", + "codex": "Codex" + }, + "tools": { + "settings": "Tool Settings", + "error": "Tool Error", + "result": "Tool Result", + "viewParams": "View input parameters", + "viewRawParams": "View raw parameters", + "viewDiff": "View edit diff for", + "creatingFile": "Creating new file:", + "updatingTodo": "Updating Todo List", + "read": "Read", + "readFile": "Read file", + "updateTodo": "Update todo list", + "readTodo": "Read todo list", + "searchResults": "results" + }, + "search": { + "found": "Found {{count}} {{type}}", + "file": "file", + "files": "files", + "pattern": "pattern:", + "in": "in:" + }, + "fileOperations": { + "updated": "File updated successfully", + "created": "File created successfully", + "written": "File written successfully", + "diff": "Diff", + "newFile": "New File", + "viewContent": "View file content", + "viewFullOutput": "View full output ({{count}} chars)", + "contentDisplayed": "The file content is displayed in the diff view above" + }, + "interactive": { + "title": "Interactive Prompt", + "waiting": "Waiting for your response in the CLI", + "instruction": "Please select an option in your terminal where Claude is running.", + "selectedOption": "✓ Claude selected option {{number}}", + "instructionDetail": "In the CLI, you would select this option interactively using arrow keys or by typing the number." + }, + "thinking": { + "title": "Thinking...", + "emoji": "💭 Thinking..." + }, + "json": { + "response": "JSON Response" + }, + "permissions": { + "grant": "Grant permission for {{tool}}", + "added": "Permission added", + "addTo": "Adds {{entry}} to Allowed Tools.", + "retry": "Permission saved. Retry the request to use the tool.", + "error": "Unable to update permissions. Please try again.", + "openSettings": "Open settings" + }, + "todo": { + "updated": "Todo list has been updated successfully", + "current": "Current Todo List" + }, + "plan": { + "viewPlan": "📋 View implementation plan", + "title": "Implementation Plan" + }, + "usageLimit": { + "resetAt": "Claude usage limit reached. Your limit will reset at **{{time}} {{timezone}}** - {{date}}" + }, + "codex": { + "permissionMode": "Permission Mode", + "modes": { + "default": "Default Mode", + "acceptEdits": "Accept Edits", + "bypassPermissions": "Bypass Permissions", + "plan": "Plan Mode" + }, + "descriptions": { + "default": "Only trusted commands (ls, cat, grep, git status, etc.) run automatically. Other commands are skipped. Can write to workspace.", + "acceptEdits": "All commands run automatically within the workspace. Full auto mode with sandboxed execution.", + "bypassPermissions": "Full system access with no restrictions. All commands run automatically with full disk and network access. Use with caution.", + "plan": "Planning mode - no commands are executed" + }, + "technicalDetails": "Technical details" + }, + "input": { + "placeholder": "Type / for commands, @ for files, or ask {{provider}} anything...", + "placeholderDefault": "Type your message...", + "disabled": "Input disabled", + "attachFiles": "Attach files", + "attachImages": "Attach images", + "send": "Send", + "stop": "Stop", + "hintText": { + "ctrlEnter": "Ctrl+Enter to send • Shift+Enter for new line • Tab to change modes • / for slash commands", + "enter": "Enter to send • Shift+Enter for new line • Tab to change modes • / for slash commands" + }, + "clickToChangeMode": "Click to change permission mode (or press Tab in input)", + "showAllCommands": "Show all commands" + } +} diff --git a/src/i18n/locales/en/settings.json b/src/i18n/locales/en/settings.json index c23233f..b8a5f71 100644 --- a/src/i18n/locales/en/settings.json +++ b/src/i18n/locales/en/settings.json @@ -7,6 +7,7 @@ "appearance": "Appearance" }, "account": { + "title": "Account", "language": "Language", "languageLabel": "Display Language", "languageDescription": "Choose your preferred language for the interface", @@ -15,13 +16,6 @@ "profile": "Profile", "changePassword": "Change Password" }, - "permissions": { - "allowedTools": "Allowed Tools", - "disallowedTools": "Disallowed Tools", - "addTool": "Add Tool", - "removeTool": "Remove Tool", - "description": "Configure which tools Claude can use. Tools must be enabled here before Claude can access them." - }, "mcp": { "title": "MCP Servers", "addServer": "Add Server", @@ -71,5 +65,337 @@ "autoScrollToBottom": "Auto-scroll to bottom", "sendByCtrlEnter": "Send by Ctrl+Enter", "sendByCtrlEnterDescription": "When enabled, pressing Ctrl+Enter will send the message instead of just Enter. This is useful for IME users to avoid accidental sends." + }, + "mainTabs": { + "agents": "Agents", + "appearance": "Appearance", + "git": "Git", + "apiTokens": "API & Tokens", + "tasks": "Tasks" + }, + "appearanceSettings": { + "darkMode": { + "label": "Dark Mode", + "description": "Toggle between light and dark themes" + }, + "projectSorting": { + "label": "Project Sorting", + "description": "How projects are ordered in the sidebar", + "alphabetical": "Alphabetical", + "recentActivity": "Recent Activity" + }, + "codeEditor": { + "title": "Code Editor", + "theme": { + "label": "Editor Theme", + "description": "Default theme for the code editor" + }, + "wordWrap": { + "label": "Word Wrap", + "description": "Enable word wrapping by default in the editor" + }, + "showMinimap": { + "label": "Show Minimap", + "description": "Display a minimap for easier navigation in diff view" + }, + "lineNumbers": { + "label": "Show Line Numbers", + "description": "Display line numbers in the editor" + }, + "fontSize": { + "label": "Font Size", + "description": "Editor font size in pixels" + } + } + }, + "mcpForm": { + "title": { + "add": "Add MCP Server", + "edit": "Edit MCP Server" + }, + "importMode": { + "form": "Form Input", + "json": "JSON Import" + }, + "scope": { + "label": "Scope", + "userGlobal": "User (Global)", + "projectLocal": "Project (Local)", + "userDescription": "User scope: Available across all projects on your machine", + "projectDescription": "Local scope: Only available in the selected project", + "cannotChange": "Scope cannot be changed when editing an existing server" + }, + "fields": { + "serverName": "Server Name", + "transportType": "Transport Type", + "command": "Command", + "arguments": "Arguments (one per line)", + "jsonConfig": "JSON Configuration", + "url": "URL", + "envVars": "Environment Variables (KEY=value, one per line)", + "headers": "Headers (KEY=value, one per line)", + "selectProject": "Select a project..." + }, + "placeholders": { + "serverName": "my-server" + }, + "validation": { + "missingType": "Missing required field: type", + "stdioRequiresCommand": "stdio type requires a command field", + "httpRequiresUrl": "{{type}} type requires a url field", + "invalidJson": "Invalid JSON format", + "jsonHelp": "Paste your MCP server configuration in JSON format. Example formats:", + "jsonExampleStdio": "• stdio: {\"type\":\"stdio\",\"command\":\"npx\",\"args\":[\"@upstash/context7-mcp\"]}", + "jsonExampleHttp": "• http/sse: {\"type\":\"http\",\"url\":\"https://api.example.com/mcp\"}" + }, + "configDetails": "Configuration Details (from {{configFile}})", + "projectPath": "Path: {{path}}", + "actions": { + "cancel": "Cancel", + "saving": "Saving...", + "addServer": "Add Server", + "updateServer": "Update Server" + } + }, + "saveStatus": { + "success": "Settings saved successfully!", + "error": "Failed to save settings", + "saving": "Saving..." + }, + "footerActions": { + "save": "Save Settings", + "cancel": "Cancel" + }, + "git": { + "title": "Git Configuration", + "description": "Configure your git identity for commits. These settings will be applied globally via git config --global", + "name": { + "label": "Git Name", + "help": "Your name for git commits" + }, + "email": { + "label": "Git Email", + "help": "Your email for git commits" + }, + "actions": { + "save": "Save Configuration", + "saving": "Saving..." + }, + "status": { + "success": "Saved successfully" + } + }, + "apiKeys": { + "title": "API Keys", + "description": "Generate API keys to access the external API from other applications.", + "newKey": { + "alertTitle": "⚠️ Save Your API Key", + "alertMessage": "This is the only time you'll see this key. Store it securely.", + "iveSavedIt": "I've saved it" + }, + "form": { + "placeholder": "API Key Name (e.g., Production Server)", + "createButton": "Create", + "cancelButton": "Cancel" + }, + "newButton": "New API Key", + "empty": "No API keys created yet.", + "list": { + "created": "Created:", + "lastUsed": "Last used:" + }, + "confirmDelete": "Are you sure you want to delete this API key?", + "status": { + "active": "Active", + "inactive": "Inactive" + }, + "github": { + "title": "GitHub Tokens", + "description": "Add GitHub Personal Access Tokens to clone private repositories via the external API.", + "descriptionAlt": "Add GitHub Personal Access Tokens to clone private repositories. You can also pass tokens directly in API requests without storing them.", + "addButton": "Add Token", + "form": { + "namePlaceholder": "Token Name (e.g., Personal Repos)", + "tokenPlaceholder": "GitHub Personal Access Token (ghp_...)", + "descriptionPlaceholder": "Description (optional)", + "addButton": "Add Token", + "cancelButton": "Cancel", + "howToCreate": "How to create a GitHub Personal Access Token →" + }, + "empty": "No GitHub tokens added yet.", + "added": "Added:", + "confirmDelete": "Are you sure you want to delete this GitHub token?" + }, + "apiDocsLink": "API Documentation", + "documentation": { + "title": "External API Documentation", + "description": "Learn how to use the external API to trigger Claude/Cursor sessions from your applications.", + "viewLink": "View API Documentation →" + }, + "loading": "Loading...", + "version": { + "updateAvailable": "Update available: v{{version}}" + } + }, + "tasks": { + "checking": "Checking TaskMaster installation...", + "notInstalled": { + "title": "TaskMaster AI CLI Not Installed", + "description": "TaskMaster CLI is required to use task management features. Install it to get started:", + "installCommand": "npm install -g task-master-ai", + "viewOnGitHub": "View on GitHub", + "afterInstallation": "After installation:", + "steps": { + "restart": "Restart this application", + "autoAvailable": "TaskMaster features will automatically become available", + "initCommand": "Use task-master init in your project directory" + } + }, + "settings": { + "enableLabel": "Enable TaskMaster Integration", + "enableDescription": "Show TaskMaster tasks, banners, and sidebar indicators across the interface" + } + }, + "agents": { + "authStatus": { + "checking": "Checking...", + "connected": "Connected", + "notConnected": "Not connected", + "disconnected": "Disconnected", + "checkingAuth": "Checking authentication status...", + "loggedInAs": "Logged in as {{email}}", + "authenticatedUser": "authenticated user" + }, + "account": { + "claude": { + "description": "Anthropic Claude AI assistant" + }, + "cursor": { + "description": "Cursor AI-powered code editor" + }, + "codex": { + "description": "OpenAI Codex AI assistant" + } + }, + "connectionStatus": "Connection Status", + "login": { + "title": "Login", + "reAuthenticate": "Re-authenticate", + "description": "Sign in to your {{agent}} account to enable AI features", + "reAuthDescription": "Sign in with a different account or refresh credentials", + "button": "Login", + "reLoginButton": "Re-login" + }, + "error": "Error: {{error}}" + }, + "permissions": { + "title": "Permission Settings", + "skipPermissions": { + "label": "Skip permission prompts (use with caution)", + "claudeDescription": "Equivalent to --dangerously-skip-permissions flag", + "cursorDescription": "Equivalent to -f flag in Cursor CLI" + }, + "allowedTools": { + "title": "Allowed Tools", + "description": "Tools that are automatically allowed without prompting for permission", + "placeholder": "e.g., \"Bash(git log:*)\" or \"Write\"", + "quickAdd": "Quick add common tools:", + "empty": "No allowed tools configured" + }, + "blockedTools": { + "title": "Blocked Tools", + "description": "Tools that are automatically blocked without prompting for permission", + "placeholder": "e.g., \"Bash(rm:*)\"", + "empty": "No blocked tools configured" + }, + "allowedCommands": { + "title": "Allowed Shell Commands", + "description": "Shell commands that are automatically allowed without prompting", + "placeholder": "e.g., \"Shell(ls)\" or \"Shell(git status)\"", + "quickAdd": "Quick add common commands:", + "empty": "No allowed commands configured" + }, + "blockedCommands": { + "title": "Blocked Shell Commands", + "description": "Shell commands that are automatically blocked", + "placeholder": "e.g., \"Shell(rm -rf)\" or \"Shell(sudo)\"", + "empty": "No blocked commands configured" + }, + "toolExamples": { + "title": "Tool Pattern Examples:", + "bashGitLog": "- Allow all git log commands", + "bashGitDiff": "- Allow all git diff commands", + "write": "- Allow all Write tool usage", + "bashRm": "- Block all rm commands (dangerous)" + }, + "shellExamples": { + "title": "Shell Command Examples:", + "ls": "- Allow ls command", + "gitStatus": "- Allow git status", + "npmInstall": "- Allow npm install", + "rmRf": "- Block recursive delete" + }, + "codex": { + "permissionMode": "Permission Mode", + "description": "Controls how Codex handles file modifications and command execution", + "modes": { + "default": { + "title": "Default", + "description": "Only trusted commands (ls, cat, grep, git status, etc.) run automatically. Other commands are skipped. Can write to workspace." + }, + "acceptEdits": { + "title": "Accept Edits", + "description": "All commands run automatically within the workspace. Full auto mode with sandboxed execution." + }, + "bypassPermissions": { + "title": "Bypass Permissions", + "description": "Full system access with no restrictions. All commands run automatically with full disk and network access. Use with caution." + } + }, + "technicalDetails": "Technical details", + "technicalInfo": { + "default": "sandboxMode=workspace-write, approvalPolicy=untrusted. Trusted commands: cat, cd, grep, head, ls, pwd, tail, git status/log/diff/show, find (without -exec), etc.", + "acceptEdits": "sandboxMode=workspace-write, approvalPolicy=never. All commands auto-execute within project directory.", + "bypassPermissions": "sandboxMode=danger-full-access, approvalPolicy=never. Full system access, use only in trusted environments.", + "overrideNote": "You can override this per-session using the mode button in the chat interface." + } + }, + "actions": { + "add": "Add" + } + }, + "mcpServers": { + "title": "MCP Servers", + "description": { + "claude": "Model Context Protocol servers provide additional tools and data sources to Claude", + "cursor": "Model Context Protocol servers provide additional tools and data sources to Cursor", + "codex": "Model Context Protocol servers provide additional tools and data sources to Codex" + }, + "addButton": "Add MCP Server", + "empty": "No MCP servers configured", + "serverType": "Type", + "scope": { + "local": "local", + "user": "user" + }, + "config": { + "command": "Command", + "url": "URL", + "args": "Args", + "environment": "Environment" + }, + "tools": { + "title": "Tools", + "count": "({{count}}):", + "more": "+{{count}} more" + }, + "actions": { + "edit": "Edit server", + "delete": "Delete server" + }, + "help": { + "title": "About Codex MCP", + "description": "Codex supports stdio-based MCP servers. You can add servers that extend Codex's capabilities with additional tools and resources." + } } } diff --git a/src/i18n/locales/zh-CN/chat.json b/src/i18n/locales/zh-CN/chat.json new file mode 100644 index 0000000..6f20225 --- /dev/null +++ b/src/i18n/locales/zh-CN/chat.json @@ -0,0 +1,111 @@ +{ + "codeBlock": { + "copy": "复制", + "copied": "已复制", + "copyCode": "复制代码" + }, + "messageTypes": { + "user": "U", + "error": "错误", + "tool": "工具", + "claude": "Claude", + "cursor": "Cursor", + "codex": "Codex" + }, + "tools": { + "settings": "工具设置", + "error": "工具错误", + "result": "工具结果", + "viewParams": "查看输入参数", + "viewRawParams": "查看原始参数", + "viewDiff": "查看编辑差异", + "creatingFile": "创建新文件:", + "updatingTodo": "更新待办事项", + "read": "读取", + "readFile": "读取文件", + "updateTodo": "更新待办列表", + "readTodo": "读取待办列表", + "searchResults": "结果" + }, + "search": { + "found": "找到 {{count}} 个{{type}}", + "file": "文件", + "files": "文件", + "pattern": "模式:", + "in": "在:" + }, + "fileOperations": { + "updated": "文件更新成功", + "created": "文件创建成功", + "written": "文件写入成功", + "diff": "差异", + "newFile": "新文件", + "viewContent": "查看文件内容", + "viewFullOutput": "查看完整输出({{count}} 个字符)", + "contentDisplayed": "文件内容显示在上面的差异视图中" + }, + "interactive": { + "title": "交互式提示", + "waiting": "等待您在 CLI 中响应", + "instruction": "请在 Claude 运行的终端中选择一个选项。", + "selectedOption": "✓ Claude 选择了选项 {{number}}", + "instructionDetail": "在 CLI 中,您可以使用方向键或输入数字来交互式地选择此选项。" + }, + "thinking": { + "title": "思考中...", + "emoji": "💭 思考中..." + }, + "json": { + "response": "JSON 响应" + }, + "permissions": { + "grant": "授予 {{tool}} 权限", + "added": "权限已添加", + "addTo": "将 {{entry}} 添加到允许的工具。", + "retry": "权限已保存。重试请求以使用该工具。", + "error": "无法更新权限。请重试。", + "openSettings": "打开设置" + }, + "todo": { + "updated": "待办列表已成功更新", + "current": "当前待办列表" + }, + "plan": { + "viewPlan": "📋 查看实施计划", + "title": "实施计划" + }, + "usageLimit": { + "resetAt": "Claude 使用限制已达到。您的限制将在 **{{time}} {{timezone}}** - {{date}} 重置" + }, + "codex": { + "permissionMode": "权限模式", + "modes": { + "default": "默认模式", + "acceptEdits": "编辑模式", + "bypassPermissions": "无限制模式", + "plan": "计划模式" + }, + "descriptions": { + "default": "只有受信任的命令(ls、cat、grep、git status 等)自动运行。其他命令将被跳过。可以写入工作区。", + "acceptEdits": "工作区内的所有命令自动运行。完全自动模式,具有沙盒执行功能。", + "bypassPermissions": "完全的系统访问,无限制。所有命令自动运行,具有完整的磁盘和网络访问权限。请谨慎使用。", + "plan": "计划模式 - 不执行任何命令" + }, + "technicalDetails": "技术细节" + }, + "input": { + "placeholder": "输入 / 调用命令,@ 选择文件,或向 {{provider}} 提问...", + "placeholderDefault": "输入您的消息...", + "disabled": "输入已禁用", + "attachFiles": "附加文件", + "attachImages": "附加图片", + "send": "发送", + "stop": "停止", + "hintText": { + "ctrlEnter": "Ctrl+Enter 发送 • Shift+Enter 换行 • Tab 切换模式 • / 斜杠命令", + "enter": "Enter 发送 • Shift+Enter 换行 • Tab 切换模式 • / 斜杠命令" + }, + "clickToChangeMode": "点击更改权限模式(或在输入框中按 Tab)", + "showAllCommands": "显示所有命令" + } +} diff --git a/src/i18n/locales/zh-CN/settings.json b/src/i18n/locales/zh-CN/settings.json index 2814fb5..f8a60f2 100644 --- a/src/i18n/locales/zh-CN/settings.json +++ b/src/i18n/locales/zh-CN/settings.json @@ -7,6 +7,7 @@ "appearance": "外观" }, "account": { + "title": "账户", "language": "语言", "languageLabel": "显示语言", "languageDescription": "选择您偏好的界面语言", @@ -15,13 +16,6 @@ "profile": "个人资料", "changePassword": "修改密码" }, - "permissions": { - "allowedTools": "允许的工具", - "disallowedTools": "禁止的工具", - "addTool": "添加工具", - "removeTool": "移除工具", - "description": "配置 Claude 可以使用的工具。工具必须在此处启用后,Claude 才能访问它们。" - }, "mcp": { "title": "MCP 服务器", "addServer": "添加服务器", @@ -71,5 +65,337 @@ "autoScrollToBottom": "自动滚动到底部", "sendByCtrlEnter": "使用 Ctrl+Enter 发送", "sendByCtrlEnterDescription": "启用后,按 Ctrl+Enter 发送消息,而不是仅按 Enter。这对于使用输入法的用户可以避免意外发送。" + }, + "mainTabs": { + "agents": "智能体", + "appearance": "外观", + "git": "Git", + "apiTokens": "API 和令牌", + "tasks": "任务" + }, + "appearanceSettings": { + "darkMode": { + "label": "深色模式", + "description": "切换浅色和深色主题" + }, + "projectSorting": { + "label": "项目排序", + "description": "项目在侧边栏中的排列方式", + "alphabetical": "按字母顺序", + "recentActivity": "最近活动" + }, + "codeEditor": { + "title": "代码编辑器", + "theme": { + "label": "编辑器主题", + "description": "代码编辑器的默认主题" + }, + "wordWrap": { + "label": "自动换行", + "description": "在编辑器中默认启用自动换行" + }, + "showMinimap": { + "label": "显示缩略图", + "description": "在差异视图中显示缩略图以便于导航" + }, + "lineNumbers": { + "label": "显示行号", + "description": "在编辑器中显示行号" + }, + "fontSize": { + "label": "字体大小", + "description": "编辑器字体大小(px)" + } + } + }, + "mcpForm": { + "title": { + "add": "添加 MCP 服务器", + "edit": "编辑 MCP 服务器" + }, + "importMode": { + "form": "表单输入", + "json": "JSON 导入" + }, + "scope": { + "label": "范围", + "userGlobal": "用户(全局)", + "projectLocal": "项目(本地)", + "userDescription": "用户范围:在您机器上的所有项目中可用", + "projectDescription": "本地范围:仅在选定项目中可用", + "cannotChange": "编辑现有服务器时无法更改范围" + }, + "fields": { + "serverName": "服务器名称", + "transportType": "传输类型", + "command": "命令", + "arguments": "参数(每行一个)", + "jsonConfig": "JSON 配置", + "url": "URL", + "envVars": "环境变量(KEY=值,每行一个)", + "headers": "请求头(KEY=值,每行一个)", + "selectProject": "选择项目..." + }, + "placeholders": { + "serverName": "我的服务" + }, + "validation": { + "missingType": "缺少必填字段:type", + "stdioRequiresCommand": "stdio 类型需要 command 字段", + "httpRequiresUrl": "{{type}} 类型需要 url 字段", + "invalidJson": "无效的 JSON 格式", + "jsonHelp": "粘贴您的 MCP 服务器配置(JSON 格式)。示例格式:", + "jsonExampleStdio": "• stdio: {\"type\":\"stdio\",\"command\":\"npx\",\"args\":[\"@upstash/context7-mcp\"]}", + "jsonExampleHttp": "• http/sse: {\"type\":\"http\",\"url\":\"https://api.example.com/mcp\"}" + }, + "configDetails": "配置详细信息(来自 {{configFile}})", + "projectPath": "路径:{{path}}", + "actions": { + "cancel": "取消", + "saving": "保存中...", + "addServer": "添加服务器", + "updateServer": "更新服务器" + } + }, + "saveStatus": { + "success": "设置保存成功!", + "error": "保存设置失败", + "saving": "保存中..." + }, + "footerActions": { + "save": "保存设置", + "cancel": "取消" + }, + "git": { + "title": "Git 配置", + "description": "配置您的 git 提交身份。这些设置将通过 git config --global 全局应用", + "name": { + "label": "Git 名称", + "help": "您的 git 提交名称" + }, + "email": { + "label": "Git 邮箱", + "help": "您的 git 提交邮箱" + }, + "actions": { + "save": "保存配置", + "saving": "保存中..." + }, + "status": { + "success": "保存成功" + } + }, + "apiKeys": { + "title": "API 密钥", + "description": "生成 API 密钥以从其他应用访问外部 API。", + "newKey": { + "alertTitle": "⚠️ 保存您的 API 密钥", + "alertMessage": "这是您唯一一次看到此密钥。请妥善保存。", + "iveSavedIt": "我已保存" + }, + "form": { + "placeholder": "API 密钥名称(例如:生产服务器)", + "createButton": "创建", + "cancelButton": "取消" + }, + "newButton": "新建 API 密钥", + "empty": "尚未创建 API 密钥。", + "list": { + "created": "创建时间:", + "lastUsed": "最后使用:" + }, + "confirmDelete": "确定要删除此 API 密钥吗?", + "status": { + "active": "激活", + "inactive": "未激活" + }, + "github": { + "title": "GitHub 令牌", + "description": "添加 GitHub 个人访问令牌以通过外部 API 克隆私有仓库。", + "descriptionAlt": "添加 GitHub 个人访问令牌以克隆私有仓库。您也可以直接在 API 请求中传递令牌而无需存储。", + "addButton": "添加令牌", + "form": { + "namePlaceholder": "令牌名称(例如:个人仓库)", + "tokenPlaceholder": "GitHub 个人访问令牌(ghp_...)", + "descriptionPlaceholder": "描述(可选)", + "addButton": "添加令牌", + "cancelButton": "取消", + "howToCreate": "如何创建 GitHub 个人访问令牌 →" + }, + "empty": "尚未添加 GitHub 令牌。", + "added": "添加时间:", + "confirmDelete": "确定要删除此 GitHub 令牌吗?" + }, + "apiDocsLink": "API 文档", + "documentation": { + "title": "外部 API 文档", + "description": "了解如何使用外部 API 从您的应用程序触发 Claude/Cursor 会话。", + "viewLink": "查看 API 文档 →" + }, + "loading": "加载中...", + "version": { + "updateAvailable": "有可用更新:v{{version}}" + } + }, + "tasks": { + "checking": "正在检查 TaskMaster 安装...", + "notInstalled": { + "title": "未安装 TaskMaster AI CLI", + "description": "需要 TaskMaster CLI 才能使用任务管理功能。安装它以开始使用:", + "installCommand": "npm install -g task-master-ai", + "viewOnGitHub": "在 GitHub 上查看", + "afterInstallation": "安装后:", + "steps": { + "restart": "重启此应用程序", + "autoAvailable": "TaskMaster 功能将自动可用", + "initCommand": "在项目目录中使用 task-master init" + } + }, + "settings": { + "enableLabel": "启用 TaskMaster 集成", + "enableDescription": "在整个界面中显示 TaskMaster 任务、横幅和侧边栏指示器" + } + }, + "agents": { + "authStatus": { + "checking": "检查中...", + "connected": "已连接", + "notConnected": "未连接", + "disconnected": "已断开", + "checkingAuth": "正在检查认证状态...", + "loggedInAs": "登录为 {{email}}", + "authenticatedUser": "已认证用户" + }, + "account": { + "claude": { + "description": "Anthropic Claude AI 助手" + }, + "cursor": { + "description": "Cursor AI 驱动的代码编辑器" + }, + "codex": { + "description": "OpenAI Codex AI 助手" + } + }, + "connectionStatus": "连接状态", + "login": { + "title": "登录", + "reAuthenticate": "重新认证", + "description": "登录您的 {{agent}} 账户以启用 AI 功能", + "reAuthDescription": "使用其他账户登录或刷新凭据", + "button": "登录", + "reLoginButton": "重新登录" + }, + "error": "错误:{{error}}" + }, + "permissions": { + "title": "权限设置", + "skipPermissions": { + "label": "跳过权限提示(请谨慎使用)", + "claudeDescription": "等同于 --dangerously-skip-permissions 标志", + "cursorDescription": "等同于 Cursor CLI 中的 -f 标志" + }, + "allowedTools": { + "title": "允许的工具", + "description": "无需权限提示即可自动使用的工具", + "placeholder": "例如:\"Bash(git log:*)\" 或 \"Write\"", + "quickAdd": "快速添加常用工具:", + "empty": "未配置允许的工具" + }, + "blockedTools": { + "title": "禁用的工具", + "description": "无需权限提示即可自动禁用的工具", + "placeholder": "例如:\"Bash(rm:*)\"", + "empty": "未配置禁用的工具" + }, + "allowedCommands": { + "title": "允许的 Shell 命令", + "description": "无需权限提示即可自动执行的 Shell 命令", + "placeholder": "例如:\"Shell(ls)\" 或 \"Shell(git status)\"", + "quickAdd": "快速添加常用命令:", + "empty": "未配置允许的命令" + }, + "blockedCommands": { + "title": "阻止的 Shell 命令", + "description": "自动阻止的 Shell 命令", + "placeholder": "例如:\"Shell(rm -rf)\" 或 \"Shell(sudo)\"", + "empty": "未配置阻止的命令" + }, + "toolExamples": { + "title": "工具模式示例:", + "bashGitLog": "- 允许所有 git log 命令", + "bashGitDiff": "- 允许所有 git diff 命令", + "write": "- 允许所有 Write 工具使用", + "bashRm": "- 阻止所有 rm 命令(危险)" + }, + "shellExamples": { + "title": "Shell 命令示例:", + "ls": "- 允许 ls 命令", + "gitStatus": "- 允许 git status", + "npmInstall": "- 允许 npm install", + "rmRf": "- 阻止递归删除" + }, + "codex": { + "permissionMode": "权限模式", + "description": "控制 Codex 如何处理文件修改和命令执行", + "modes": { + "default": { + "title": "默认", + "description": "只有受信任的命令(ls、cat、grep、git status 等)会自动运行。其他命令将被跳过。可以写入工作区。" + }, + "acceptEdits": { + "title": "接受编辑", + "description": "所有命令在工作区内自动运行。具有沙箱执行的全自动模式。" + }, + "bypassPermissions": { + "title": "绕过权限", + "description": "完全系统访问,无任何限制。所有命令自动运行,具有完整的磁盘和网络访问权限。请谨慎使用。" + } + }, + "technicalDetails": "技术详情", + "technicalInfo": { + "default": "sandboxMode=workspace-write, approvalPolicy=untrusted。受信任的命令:cat、cd、grep、head、ls、pwd、tail、git status/log/diff/show、find(不带 -exec)等。", + "acceptEdits": "sandboxMode=workspace-write, approvalPolicy=never。所有命令在项目目录内自动执行。", + "bypassPermissions": "sandboxMode=danger-full-access, approvalPolicy=never。完全系统访问权限,仅在可信环境中使用。", + "overrideNote": "您可以使用聊天界面中的模式按钮按会话覆盖此设置。" + } + }, + "actions": { + "add": "添加" + } + }, + "mcpServers": { + "title": "MCP 服务器", + "description": { + "claude": "Model Context Protocol 服务器为 Claude 提供额外的工具和数据源", + "cursor": "Model Context Protocol 服务器为 Cursor 提供额外的工具和数据源", + "codex": "Model Context Protocol 服务器为 Codex 提供额外的工具和数据源" + }, + "addButton": "添加 MCP 服务器", + "empty": "未配置 MCP 服务器", + "serverType": "类型", + "scope": { + "local": "本地", + "user": "用户" + }, + "config": { + "command": "命令", + "url": "URL", + "args": "参数", + "environment": "环境变量" + }, + "tools": { + "title": "工具", + "count": "({{count}}):", + "more": "还有 {{count}} 个" + }, + "actions": { + "edit": "编辑服务器", + "delete": "删除服务器" + }, + "help": { + "title": "关于 Codex MCP", + "description": "Codex 支持基于 stdio 的 MCP 服务器。您可以添加服务器,通过额外的工具和资源来扩展 Codex 的功能。" + } } }
@@ -182,7 +184,7 @@ function CredentialsSettings() { className="mt-3" onClick={() => setNewlyCreatedKey(null)} > - I've saved it + {t('apiKeys.newKey.iveSavedIt')}
- Add GitHub Personal Access Tokens to clone private repositories. You can also pass tokens directly in API requests without storing them. + {t('apiKeys.github.descriptionAlt')}
- Configure your git identity for commits. These settings will be applied globally via git config --global + {t('git.description')}
git config --global
- Your name for git commits + {t('git.name.help')}
- Your email for git commits + {t('git.email.help')}
- Scope cannot be changed when editing an existing server + {t('mcpForm.scope.cannotChange')}
- {mcpFormData.scope === 'user' - ? 'User scope: Available across all projects on your machine' - : 'Local scope: Only available in the selected project' + {mcpFormData.scope === 'user' + ? t('mcpForm.scope.userDescription') + : t('mcpForm.scope.projectDescription') }
- Path: {mcpFormData.projectPath} + {t('mcpForm.projectPath', { path: mcpFormData.projectPath })}
{JSON.stringify(mcpFormData.raw, null, 2)} @@ -1639,7 +1639,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { - JSON Configuration * + {t('mcpForm.fields.jsonConfig')} * {jsonValidationError} )} - Paste your MCP server configuration in JSON format. Example formats: + {t('mcpForm.validation.jsonHelp')} • stdio: {`{"type":"stdio","command":"npx","args":["@upstash/context7-mcp"]}`} • http/sse: {`{"type":"http","url":"https://api.example.com/mcp"}`} @@ -1690,7 +1690,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { - Command * + {t('mcpForm.fields.command')} * - + - Arguments (one per line) + {t('mcpForm.fields.arguments')} - URL * + {t('mcpForm.fields.url')} * - Environment Variables (KEY=value, one per line) + {t('mcpForm.fields.envVars')} `${k}=${v}`).join('\n')} @@ -1758,7 +1758,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { {mcpFormData.importMode === 'form' && (mcpFormData.type === 'sse' || mcpFormData.type === 'http') && ( - Headers (KEY=value, one per line) + {t('mcpForm.fields.headers')} `${k}=${v}`).join('\n')} @@ -1782,14 +1782,14 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { - Cancel + {t('mcpForm.actions.cancel')} - - {mcpLoading ? 'Saving...' : (editingMcpServer ? 'Update Server' : 'Add Server')} + {mcpLoading ? t('mcpForm.actions.saving') : (editingMcpServer ? t('mcpForm.actions.updateServer') : t('mcpForm.actions.addServer'))} @@ -1803,7 +1803,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { - {editingCodexMcpServer ? 'Edit MCP Server' : 'Add MCP Server'} + {editingCodexMcpServer ? t('mcpForm.title.edit') : t('mcpForm.title.add')} @@ -1813,19 +1813,19 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { - Server Name * + {t('mcpForm.fields.serverName')} * setCodexMcpFormData(prev => ({...prev, name: e.target.value}))} - placeholder="my-mcp-server" + placeholder={t('mcpForm.placeholders.serverName')} required /> - Command * + {t('mcpForm.fields.command')} * - Arguments (one per line) + {t('mcpForm.fields.arguments')} - Environment Variables (KEY=VALUE, one per line) + {t('mcpForm.fields.envVars')} `${k}=${v}`).join('\n')} @@ -1881,14 +1881,14 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { - Cancel + {t('mcpForm.actions.cancel')} - {codexMcpLoading ? 'Saving...' : (editingCodexMcpServer ? 'Update Server' : 'Add Server')} + {codexMcpLoading ? t('mcpForm.actions.saving') : (editingCodexMcpServer ? t('mcpForm.actions.updateServer') : t('mcpForm.actions.addServer'))} @@ -1919,7 +1919,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { - Settings saved successfully! + {t('saveStatus.success')} )} {saveStatus === 'error' && ( @@ -1927,31 +1927,31 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }) { - Failed to save settings + {t('saveStatus.error')} )} - - Cancel + {t('footerActions.cancel')} - {isSaving ? ( - Saving... + {t('saveStatus.saving')} ) : ( - 'Save Settings' + t('footerActions.save') )} diff --git a/src/components/TasksSettings.jsx b/src/components/TasksSettings.jsx index ffb4cc3..dda0cf1 100644 --- a/src/components/TasksSettings.jsx +++ b/src/components/TasksSettings.jsx @@ -1,7 +1,9 @@ import { Zap } from 'lucide-react'; import { useTasksSettings } from '../contexts/TasksSettingsContext'; +import { useTranslation } from 'react-i18next'; function TasksSettings() { + const { t } = useTranslation('settings'); const { tasksEnabled, setTasksEnabled, @@ -16,7 +18,7 @@ function TasksSettings() { - Checking TaskMaster installation... + {t('tasks.checking')} ) : ( @@ -32,13 +34,13 @@ function TasksSettings() { - TaskMaster AI CLI Not Installed + {t('tasks.notInstalled.title')} - TaskMaster CLI is required to use task management features. Install it to get started: + {t('tasks.notInstalled.description')} - npm install -g task-master-ai + {t('tasks.notInstalled.installCommand')} @@ -51,7 +53,7 @@ function TasksSettings() { - View on GitHub + {t('tasks.notInstalled.viewOnGitHub')} @@ -59,11 +61,11 @@ function TasksSettings() { - After installation: + {t('tasks.notInstalled.afterInstallation')} - Restart this application - TaskMaster features will automatically become available - Use task-master init in your project directory + {t('tasks.notInstalled.steps.restart')} + {t('tasks.notInstalled.steps.autoAvailable')} + Use task-master init {t('tasks.notInstalled.steps.initCommand')} @@ -79,10 +81,10 @@ function TasksSettings() { - Enable TaskMaster Integration + {t('tasks.settings.enableLabel')} - Show TaskMaster tasks, banners, and sidebar indicators across the interface + {t('tasks.settings.enableDescription')} diff --git a/src/components/settings/AccountContent.jsx b/src/components/settings/AccountContent.jsx index 93e0a9a..e9b2d3f 100644 --- a/src/components/settings/AccountContent.jsx +++ b/src/components/settings/AccountContent.jsx @@ -4,6 +4,7 @@ import { LogIn } from 'lucide-react'; import ClaudeLogo from '../ClaudeLogo'; import CursorLogo from '../CursorLogo'; import CodexLogo from '../CodexLogo'; +import { useTranslation } from 'react-i18next'; const agentConfig = { claude: { @@ -39,6 +40,7 @@ const agentConfig = { }; export default function AccountContent({ agent, authStatus, onLogin }) { + const { t } = useTranslation('settings'); const config = agentConfig[agent]; const { Logo } = config; @@ -47,8 +49,8 @@ export default function AccountContent({ agent, authStatus, onLogin }) { - {config.name} Account - {config.description} + {config.name} + {t(`agents.account.${agent}.description`)} @@ -58,30 +60,30 @@ export default function AccountContent({ agent, authStatus, onLogin }) { - Connection Status + {t('agents.connectionStatus')} {authStatus?.loading ? ( - 'Checking authentication status...' + t('agents.authStatus.checkingAuth') ) : authStatus?.authenticated ? ( - `Logged in as ${authStatus.email || 'authenticated user'}` + t('agents.authStatus.loggedInAs', { email: authStatus.email || t('agents.authStatus.authenticatedUser') }) ) : ( - 'Not connected' + t('agents.authStatus.notConnected') )} {authStatus?.loading ? ( - Checking... + {t('agents.authStatus.checking')} ) : authStatus?.authenticated ? ( - Connected + {t('agents.authStatus.connected')} ) : ( - Disconnected + {t('agents.authStatus.disconnected')} )} @@ -91,12 +93,12 @@ export default function AccountContent({ agent, authStatus, onLogin }) { - {authStatus?.authenticated ? 'Re-authenticate' : 'Login'} + {authStatus?.authenticated ? t('agents.login.reAuthenticate') : t('agents.login.title')} {authStatus?.authenticated - ? 'Sign in with a different account or refresh credentials' - : `Sign in to your ${config.name} account to enable AI features`} + ? t('agents.login.reAuthDescription') + : t('agents.login.description', { agent: config.name })} - {authStatus?.authenticated ? 'Re-login' : 'Login'} + {authStatus?.authenticated ? t('agents.login.reLoginButton') : t('agents.login.button')} @@ -113,7 +115,7 @@ export default function AccountContent({ agent, authStatus, onLogin }) { {authStatus?.error && ( - Error: {authStatus.error} + {t('agents.error', { error: authStatus.error })} )} diff --git a/src/components/settings/AgentListItem.jsx b/src/components/settings/AgentListItem.jsx index e550c23..06e7477 100644 --- a/src/components/settings/AgentListItem.jsx +++ b/src/components/settings/AgentListItem.jsx @@ -1,6 +1,7 @@ import ClaudeLogo from '../ClaudeLogo'; import CursorLogo from '../CursorLogo'; import CodexLogo from '../CodexLogo'; +import { useTranslation } from 'react-i18next'; const agentConfig = { claude: { @@ -42,6 +43,7 @@ const colorClasses = { }; export default function AgentListItem({ agentId, authStatus, isSelected, onClick, isMobile = false }) { + const { t } = useTranslation('settings'); const config = agentConfig[agentId]; const colors = colorClasses[config.color]; const { Logo } = config; @@ -84,18 +86,18 @@ export default function AgentListItem({ agentId, authStatus, isSelected, onClick {authStatus?.loading ? ( - Checking... + {t('agents.authStatus.checking')} ) : authStatus?.authenticated ? ( - {authStatus.email || 'Connected'} + {authStatus.email || t('agents.authStatus.connected')} ) : ( - Not connected + {t('agents.authStatus.notConnected')} )} diff --git a/src/components/settings/McpServersContent.jsx b/src/components/settings/McpServersContent.jsx index 4495ef9..257f58a 100644 --- a/src/components/settings/McpServersContent.jsx +++ b/src/components/settings/McpServersContent.jsx @@ -3,6 +3,7 @@ import { Button } from '../ui/button'; import { Input } from '../ui/input'; import { Badge } from '../ui/badge'; import { Server, Plus, Edit3, Trash2, Terminal, Globe, Zap, X } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; const getTransportIcon = (type) => { switch (type) { @@ -25,16 +26,17 @@ function ClaudeMcpServers({ serverTools, toolsLoading, }) { + const { t } = useTranslation('settings'); return ( - MCP Servers + {t('mcpServers.title')} - Model Context Protocol servers provide additional tools and data sources to Claude + {t('mcpServers.description.claude')} @@ -44,7 +46,7 @@ function ClaudeMcpServers({ size="sm" > - Add MCP Server + {t('mcpServers.addButton')} @@ -60,19 +62,19 @@ function ClaudeMcpServers({ {server.type} - {server.scope === 'local' ? 'local' : server.scope === 'user' ? 'user' : server.scope} + {server.scope === 'local' ? t('mcpServers.scope.local') : server.scope === 'user' ? t('mcpServers.scope.user') : server.scope} {server.type === 'stdio' && server.config?.command && ( - Command: {server.config.command} + {t('mcpServers.config.command')}: {server.config.command} )} {(server.type === 'sse' || server.type === 'http') && server.config?.url && ( - URL: {server.config.url} + {t('mcpServers.config.url')}: {server.config.url} )} {server.config?.args && server.config.args.length > 0 && ( - Args: {server.config.args.join(' ')} + {t('mcpServers.config.args')}: {server.config.args.join(' ')} )} @@ -90,13 +92,13 @@ function ClaudeMcpServers({ {/* Tools Discovery Results */} {serverTools?.[server.id] && serverTools[server.id].tools?.length > 0 && ( - Tools ({serverTools[server.id].tools.length}): + {t('mcpServers.tools.title')} {t('mcpServers.tools.count', { count: serverTools[server.id].tools.length })} {serverTools[server.id].tools.slice(0, 5).map((tool, i) => ( {tool.name} ))} {serverTools[server.id].tools.length > 5 && ( - +{serverTools[server.id].tools.length - 5} more + {t('mcpServers.tools.more', { count: serverTools[server.id].tools.length - 5 })} )} @@ -109,7 +111,7 @@ function ClaudeMcpServers({ variant="ghost" size="sm" className="text-gray-600 hover:text-gray-700" - title="Edit server" + title={t('mcpServers.actions.edit')} > @@ -118,7 +120,7 @@ function ClaudeMcpServers({ variant="ghost" size="sm" className="text-red-600 hover:text-red-700" - title="Delete server" + title={t('mcpServers.actions.delete')} > @@ -128,7 +130,7 @@ function ClaudeMcpServers({ ))} {servers.length === 0 && ( - No MCP servers configured + {t('mcpServers.empty')} )} @@ -138,16 +140,17 @@ function ClaudeMcpServers({ // Cursor MCP Servers function CursorMcpServers({ servers, onAdd, onEdit, onDelete }) { + const { t } = useTranslation('settings'); return ( - MCP Servers + {t('mcpServers.title')} - Model Context Protocol servers provide additional tools and data sources to Cursor + {t('mcpServers.description.cursor')} @@ -157,7 +160,7 @@ function CursorMcpServers({ servers, onAdd, onEdit, onDelete }) { size="sm" > - Add MCP Server + {t('mcpServers.addButton')} @@ -173,7 +176,7 @@ function CursorMcpServers({ servers, onAdd, onEdit, onDelete }) { {server.config?.command && ( - Command: {server.config.command} + {t('mcpServers.config.command')}: {server.config.command} )} @@ -183,6 +186,7 @@ function CursorMcpServers({ servers, onAdd, onEdit, onDelete }) { variant="ghost" size="sm" className="text-gray-600 hover:text-gray-700" + title={t('mcpServers.actions.edit')} > @@ -191,6 +195,7 @@ function CursorMcpServers({ servers, onAdd, onEdit, onDelete }) { variant="ghost" size="sm" className="text-red-600 hover:text-red-700" + title={t('mcpServers.actions.delete')} > @@ -200,7 +205,7 @@ function CursorMcpServers({ servers, onAdd, onEdit, onDelete }) { ))} {servers.length === 0 && ( - No MCP servers configured + {t('mcpServers.empty')} )} @@ -210,16 +215,17 @@ function CursorMcpServers({ servers, onAdd, onEdit, onDelete }) { // Codex MCP Servers function CodexMcpServers({ servers, onAdd, onEdit, onDelete }) { + const { t } = useTranslation('settings'); return ( - MCP Servers + {t('mcpServers.title')} - Model Context Protocol servers provide additional tools and data sources to Codex + {t('mcpServers.description.codex')} @@ -229,7 +235,7 @@ function CodexMcpServers({ servers, onAdd, onEdit, onDelete }) { size="sm" > - Add MCP Server + {t('mcpServers.addButton')} @@ -246,13 +252,13 @@ function CodexMcpServers({ servers, onAdd, onEdit, onDelete }) { {server.config?.command && ( - Command: {server.config.command} + {t('mcpServers.config.command')}: {server.config.command} )} {server.config?.args && server.config.args.length > 0 && ( - Args: {server.config.args.join(' ')} + {t('mcpServers.config.args')}: {server.config.args.join(' ')} )} {server.config?.env && Object.keys(server.config.env).length > 0 && ( - Environment: {Object.entries(server.config.env).map(([k, v]) => `${k}=${v}`).join(', ')} + {t('mcpServers.config.environment')}: {Object.entries(server.config.env).map(([k, v]) => `${k}=${v}`).join(', ')} )} @@ -263,7 +269,7 @@ function CodexMcpServers({ servers, onAdd, onEdit, onDelete }) { variant="ghost" size="sm" className="text-gray-600 hover:text-gray-700" - title="Edit server" + title={t('mcpServers.actions.edit')} > @@ -272,7 +278,7 @@ function CodexMcpServers({ servers, onAdd, onEdit, onDelete }) { variant="ghost" size="sm" className="text-red-600 hover:text-red-700" - title="Delete server" + title={t('mcpServers.actions.delete')} > @@ -282,17 +288,16 @@ function CodexMcpServers({ servers, onAdd, onEdit, onDelete }) { ))} {servers.length === 0 && ( - No MCP servers configured + {t('mcpServers.empty')} )} {/* Help Section */} - About Codex MCP + {t('mcpServers.help.title')} - Codex supports stdio-based MCP servers. You can add servers that extend Codex's capabilities - with additional tools and resources. + {t('mcpServers.help.description')} diff --git a/src/components/settings/PermissionsContent.jsx b/src/components/settings/PermissionsContent.jsx index 608d43e..7bbd53d 100644 --- a/src/components/settings/PermissionsContent.jsx +++ b/src/components/settings/PermissionsContent.jsx @@ -1,6 +1,7 @@ import { Button } from '../ui/button'; import { Input } from '../ui/input'; import { Shield, AlertTriangle, Plus, X } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; // Common tool patterns for Claude const commonClaudeTools = [ @@ -49,6 +50,7 @@ function ClaudePermissions({ newDisallowedTool, setNewDisallowedTool, }) { + const { t } = useTranslation('settings'); const addAllowedTool = (tool) => { if (tool && !allowedTools.includes(tool)) { setAllowedTools([...allowedTools, tool]); @@ -78,7 +80,7 @@ function ClaudePermissions({ - Permission Settings + {t('permissions.title')} @@ -91,10 +93,10 @@ function ClaudePermissions({ /> - Skip permission prompts (use with caution) + {t('permissions.skipPermissions.label')} - Equivalent to --dangerously-skip-permissions flag + {t('permissions.skipPermissions.claudeDescription')} @@ -106,18 +108,18 @@ function ClaudePermissions({ - Allowed Tools + {t('permissions.allowedTools.title')} - Tools that are automatically allowed without prompting for permission + {t('permissions.allowedTools.description')} setNewAllowedTool(e.target.value)} - placeholder='e.g., "Bash(git log:*)" or "Write"' + placeholder={t('permissions.allowedTools.placeholder')} onKeyPress={(e) => { if (e.key === 'Enter') { e.preventDefault(); @@ -133,14 +135,14 @@ function ClaudePermissions({ className="h-10 px-4" > - Add + {t('permissions.actions.add')} {/* Quick add buttons */} - Quick add common tools: + {t('permissions.allowedTools.quickAdd')} {commonClaudeTools.map(tool => ( @@ -176,7 +178,7 @@ function ClaudePermissions({ ))} {allowedTools.length === 0 && ( - No allowed tools configured + {t('permissions.allowedTools.empty')} )} @@ -187,18 +189,18 @@ function ClaudePermissions({ - Blocked Tools + {t('permissions.blockedTools.title')} - Tools that are automatically blocked without prompting for permission + {t('permissions.blockedTools.description')} setNewDisallowedTool(e.target.value)} - placeholder='e.g., "Bash(rm:*)"' + placeholder={t('permissions.blockedTools.placeholder')} onKeyPress={(e) => { if (e.key === 'Enter') { e.preventDefault(); @@ -214,7 +216,7 @@ function ClaudePermissions({ className="h-10 px-4" > - Add + {t('permissions.actions.add')} @@ -236,7 +238,7 @@ function ClaudePermissions({ ))} {disallowedTools.length === 0 && ( - No blocked tools configured + {t('permissions.blockedTools.empty')} )} @@ -245,13 +247,13 @@ function ClaudePermissions({ {/* Help Section */} - Tool Pattern Examples: + {t('permissions.toolExamples.title')} - "Bash(git log:*)" - Allow all git log commands - "Bash(git diff:*)" - Allow all git diff commands - "Write" - Allow all Write tool usage - "Bash(rm:*)" - Block all rm commands (dangerous) + "Bash(git log:*)" {t('permissions.toolExamples.bashGitLog')} + "Bash(git diff:*)" {t('permissions.toolExamples.bashGitDiff')} + "Write" {t('permissions.toolExamples.write')} + "Bash(rm:*)" {t('permissions.toolExamples.bashRm')} @@ -271,6 +273,7 @@ function CursorPermissions({ newDisallowedCommand, setNewDisallowedCommand, }) { + const { t } = useTranslation('settings'); const addAllowedCommand = (cmd) => { if (cmd && !allowedCommands.includes(cmd)) { setAllowedCommands([...allowedCommands, cmd]); @@ -300,7 +303,7 @@ function CursorPermissions({ - Permission Settings + {t('permissions.title')} @@ -313,10 +316,10 @@ function CursorPermissions({ /> - Skip permission prompts (use with caution) + {t('permissions.skipPermissions.label')} - Equivalent to -f flag in Cursor CLI + {t('permissions.skipPermissions.cursorDescription')} @@ -328,18 +331,18 @@ function CursorPermissions({ - Allowed Shell Commands + {t('permissions.allowedCommands.title')} - Shell commands that are automatically allowed without prompting + {t('permissions.allowedCommands.description')} setNewAllowedCommand(e.target.value)} - placeholder='e.g., "Shell(ls)" or "Shell(git status)"' + placeholder={t('permissions.allowedCommands.placeholder')} onKeyPress={(e) => { if (e.key === 'Enter') { e.preventDefault(); @@ -355,14 +358,14 @@ function CursorPermissions({ className="h-10 px-4" > - Add + {t('permissions.actions.add')} {/* Quick add buttons */} - Quick add common commands: + {t('permissions.allowedCommands.quickAdd')} {commonCursorCommands.map(cmd => ( @@ -398,7 +401,7 @@ function CursorPermissions({ ))} {allowedCommands.length === 0 && ( - No allowed commands configured + {t('permissions.allowedCommands.empty')} )} @@ -409,18 +412,18 @@ function CursorPermissions({ - Blocked Shell Commands + {t('permissions.blockedCommands.title')} - Shell commands that are automatically blocked + {t('permissions.blockedCommands.description')} setNewDisallowedCommand(e.target.value)} - placeholder='e.g., "Shell(rm -rf)" or "Shell(sudo)"' + placeholder={t('permissions.blockedCommands.placeholder')} onKeyPress={(e) => { if (e.key === 'Enter') { e.preventDefault(); @@ -436,7 +439,7 @@ function CursorPermissions({ className="h-10 px-4" > - Add + {t('permissions.actions.add')} @@ -458,7 +461,7 @@ function CursorPermissions({ ))} {disallowedCommands.length === 0 && ( - No blocked commands configured + {t('permissions.blockedCommands.empty')} )} @@ -467,13 +470,13 @@ function CursorPermissions({ {/* Help Section */} - Shell Command Examples: + {t('permissions.shellExamples.title')} - "Shell(ls)" - Allow ls command - "Shell(git status)" - Allow git status - "Shell(npm install)" - Allow npm install - "Shell(rm -rf)" - Block recursive delete + "Shell(ls)" {t('permissions.shellExamples.ls')} + "Shell(git status)" {t('permissions.shellExamples.gitStatus')} + "Shell(npm install)" {t('permissions.shellExamples.npmInstall')} + "Shell(rm -rf)" {t('permissions.shellExamples.rmRf')} @@ -482,17 +485,18 @@ function CursorPermissions({ // Codex Permissions function CodexPermissions({ permissionMode, setPermissionMode }) { + const { t } = useTranslation('settings'); return ( - Permission Mode + {t('permissions.codex.permissionMode')} - Controls how Codex handles file modifications and command execution + {t('permissions.codex.description')} {/* Default Mode */} @@ -513,10 +517,9 @@ function CodexPermissions({ permissionMode, setPermissionMode }) { className="mt-1 w-4 h-4 text-green-600" /> - Default + {t('permissions.codex.modes.default.title')} - Only trusted commands (ls, cat, grep, git status, etc.) run automatically. - Other commands are skipped. Can write to workspace. + {t('permissions.codex.modes.default.description')} @@ -540,10 +543,9 @@ function CodexPermissions({ permissionMode, setPermissionMode }) { className="mt-1 w-4 h-4 text-green-600" /> - Accept Edits + {t('permissions.codex.modes.acceptEdits.title')} - All commands run automatically within the workspace. - Full auto mode with sandboxed execution. + {t('permissions.codex.modes.acceptEdits.description')} @@ -568,12 +570,11 @@ function CodexPermissions({ permissionMode, setPermissionMode }) { /> - Bypass Permissions + {t('permissions.codex.modes.bypassPermissions.title')} - Full system access with no restrictions. All commands run automatically - with full disk and network access. Use with caution. + {t('permissions.codex.modes.bypassPermissions.description')} @@ -582,13 +583,13 @@ function CodexPermissions({ permissionMode, setPermissionMode }) { {/* Technical Details */} - Technical details + {t('permissions.codex.technicalDetails')} - Default: sandboxMode=workspace-write, approvalPolicy=untrusted. Trusted commands: cat, cd, grep, head, ls, pwd, tail, git status/log/diff/show, find (without -exec), etc. - Accept Edits: sandboxMode=workspace-write, approvalPolicy=never. All commands auto-execute within project directory. - Bypass Permissions: sandboxMode=danger-full-access, approvalPolicy=never. Full system access, use only in trusted environments. - You can override this per-session using the mode button in the chat interface. + {t('permissions.codex.modes.default.title')}: {t('permissions.codex.technicalInfo.default')} + {t('permissions.codex.modes.acceptEdits.title')}: {t('permissions.codex.technicalInfo.acceptEdits')} + {t('permissions.codex.modes.bypassPermissions.title')}: {t('permissions.codex.technicalInfo.bypassPermissions')} + {t('permissions.codex.technicalInfo.overrideNote')} diff --git a/src/i18n/config.js b/src/i18n/config.js index 334a411..789b993 100644 --- a/src/i18n/config.js +++ b/src/i18n/config.js @@ -18,11 +18,13 @@ import enCommon from './locales/en/common.json'; import enSettings from './locales/en/settings.json'; import enAuth from './locales/en/auth.json'; import enSidebar from './locales/en/sidebar.json'; +import enChat from './locales/en/chat.json'; import zhCommon from './locales/zh-CN/common.json'; import zhSettings from './locales/zh-CN/settings.json'; import zhAuth from './locales/zh-CN/auth.json'; import zhSidebar from './locales/zh-CN/sidebar.json'; +import zhChat from './locales/zh-CN/chat.json'; // Import supported languages configuration import { languages } from './languages.js'; @@ -53,12 +55,14 @@ i18n settings: enSettings, auth: enAuth, sidebar: enSidebar, + chat: enChat, }, 'zh-CN': { common: zhCommon, settings: zhSettings, auth: zhAuth, sidebar: zhSidebar, + chat: zhChat, }, }, @@ -72,7 +76,7 @@ i18n debug: import.meta.env.DEV, // Namespaces - load only what's needed - ns: ['common', 'settings', 'auth', 'sidebar'], + ns: ['common', 'settings', 'auth', 'sidebar', 'chat'], defaultNS: 'common', // Key separator for nested keys (default: '.') diff --git a/src/i18n/locales/en/chat.json b/src/i18n/locales/en/chat.json new file mode 100644 index 0000000..4083a49 --- /dev/null +++ b/src/i18n/locales/en/chat.json @@ -0,0 +1,111 @@ +{ + "codeBlock": { + "copy": "Copy", + "copied": "Copied", + "copyCode": "Copy code" + }, + "messageTypes": { + "user": "U", + "error": "Error", + "tool": "Tool", + "claude": "Claude", + "cursor": "Cursor", + "codex": "Codex" + }, + "tools": { + "settings": "Tool Settings", + "error": "Tool Error", + "result": "Tool Result", + "viewParams": "View input parameters", + "viewRawParams": "View raw parameters", + "viewDiff": "View edit diff for", + "creatingFile": "Creating new file:", + "updatingTodo": "Updating Todo List", + "read": "Read", + "readFile": "Read file", + "updateTodo": "Update todo list", + "readTodo": "Read todo list", + "searchResults": "results" + }, + "search": { + "found": "Found {{count}} {{type}}", + "file": "file", + "files": "files", + "pattern": "pattern:", + "in": "in:" + }, + "fileOperations": { + "updated": "File updated successfully", + "created": "File created successfully", + "written": "File written successfully", + "diff": "Diff", + "newFile": "New File", + "viewContent": "View file content", + "viewFullOutput": "View full output ({{count}} chars)", + "contentDisplayed": "The file content is displayed in the diff view above" + }, + "interactive": { + "title": "Interactive Prompt", + "waiting": "Waiting for your response in the CLI", + "instruction": "Please select an option in your terminal where Claude is running.", + "selectedOption": "✓ Claude selected option {{number}}", + "instructionDetail": "In the CLI, you would select this option interactively using arrow keys or by typing the number." + }, + "thinking": { + "title": "Thinking...", + "emoji": "💭 Thinking..." + }, + "json": { + "response": "JSON Response" + }, + "permissions": { + "grant": "Grant permission for {{tool}}", + "added": "Permission added", + "addTo": "Adds {{entry}} to Allowed Tools.", + "retry": "Permission saved. Retry the request to use the tool.", + "error": "Unable to update permissions. Please try again.", + "openSettings": "Open settings" + }, + "todo": { + "updated": "Todo list has been updated successfully", + "current": "Current Todo List" + }, + "plan": { + "viewPlan": "📋 View implementation plan", + "title": "Implementation Plan" + }, + "usageLimit": { + "resetAt": "Claude usage limit reached. Your limit will reset at **{{time}} {{timezone}}** - {{date}}" + }, + "codex": { + "permissionMode": "Permission Mode", + "modes": { + "default": "Default Mode", + "acceptEdits": "Accept Edits", + "bypassPermissions": "Bypass Permissions", + "plan": "Plan Mode" + }, + "descriptions": { + "default": "Only trusted commands (ls, cat, grep, git status, etc.) run automatically. Other commands are skipped. Can write to workspace.", + "acceptEdits": "All commands run automatically within the workspace. Full auto mode with sandboxed execution.", + "bypassPermissions": "Full system access with no restrictions. All commands run automatically with full disk and network access. Use with caution.", + "plan": "Planning mode - no commands are executed" + }, + "technicalDetails": "Technical details" + }, + "input": { + "placeholder": "Type / for commands, @ for files, or ask {{provider}} anything...", + "placeholderDefault": "Type your message...", + "disabled": "Input disabled", + "attachFiles": "Attach files", + "attachImages": "Attach images", + "send": "Send", + "stop": "Stop", + "hintText": { + "ctrlEnter": "Ctrl+Enter to send • Shift+Enter for new line • Tab to change modes • / for slash commands", + "enter": "Enter to send • Shift+Enter for new line • Tab to change modes • / for slash commands" + }, + "clickToChangeMode": "Click to change permission mode (or press Tab in input)", + "showAllCommands": "Show all commands" + } +} diff --git a/src/i18n/locales/en/settings.json b/src/i18n/locales/en/settings.json index c23233f..b8a5f71 100644 --- a/src/i18n/locales/en/settings.json +++ b/src/i18n/locales/en/settings.json @@ -7,6 +7,7 @@ "appearance": "Appearance" }, "account": { + "title": "Account", "language": "Language", "languageLabel": "Display Language", "languageDescription": "Choose your preferred language for the interface", @@ -15,13 +16,6 @@ "profile": "Profile", "changePassword": "Change Password" }, - "permissions": { - "allowedTools": "Allowed Tools", - "disallowedTools": "Disallowed Tools", - "addTool": "Add Tool", - "removeTool": "Remove Tool", - "description": "Configure which tools Claude can use. Tools must be enabled here before Claude can access them." - }, "mcp": { "title": "MCP Servers", "addServer": "Add Server", @@ -71,5 +65,337 @@ "autoScrollToBottom": "Auto-scroll to bottom", "sendByCtrlEnter": "Send by Ctrl+Enter", "sendByCtrlEnterDescription": "When enabled, pressing Ctrl+Enter will send the message instead of just Enter. This is useful for IME users to avoid accidental sends." + }, + "mainTabs": { + "agents": "Agents", + "appearance": "Appearance", + "git": "Git", + "apiTokens": "API & Tokens", + "tasks": "Tasks" + }, + "appearanceSettings": { + "darkMode": { + "label": "Dark Mode", + "description": "Toggle between light and dark themes" + }, + "projectSorting": { + "label": "Project Sorting", + "description": "How projects are ordered in the sidebar", + "alphabetical": "Alphabetical", + "recentActivity": "Recent Activity" + }, + "codeEditor": { + "title": "Code Editor", + "theme": { + "label": "Editor Theme", + "description": "Default theme for the code editor" + }, + "wordWrap": { + "label": "Word Wrap", + "description": "Enable word wrapping by default in the editor" + }, + "showMinimap": { + "label": "Show Minimap", + "description": "Display a minimap for easier navigation in diff view" + }, + "lineNumbers": { + "label": "Show Line Numbers", + "description": "Display line numbers in the editor" + }, + "fontSize": { + "label": "Font Size", + "description": "Editor font size in pixels" + } + } + }, + "mcpForm": { + "title": { + "add": "Add MCP Server", + "edit": "Edit MCP Server" + }, + "importMode": { + "form": "Form Input", + "json": "JSON Import" + }, + "scope": { + "label": "Scope", + "userGlobal": "User (Global)", + "projectLocal": "Project (Local)", + "userDescription": "User scope: Available across all projects on your machine", + "projectDescription": "Local scope: Only available in the selected project", + "cannotChange": "Scope cannot be changed when editing an existing server" + }, + "fields": { + "serverName": "Server Name", + "transportType": "Transport Type", + "command": "Command", + "arguments": "Arguments (one per line)", + "jsonConfig": "JSON Configuration", + "url": "URL", + "envVars": "Environment Variables (KEY=value, one per line)", + "headers": "Headers (KEY=value, one per line)", + "selectProject": "Select a project..." + }, + "placeholders": { + "serverName": "my-server" + }, + "validation": { + "missingType": "Missing required field: type", + "stdioRequiresCommand": "stdio type requires a command field", + "httpRequiresUrl": "{{type}} type requires a url field", + "invalidJson": "Invalid JSON format", + "jsonHelp": "Paste your MCP server configuration in JSON format. Example formats:", + "jsonExampleStdio": "• stdio: {\"type\":\"stdio\",\"command\":\"npx\",\"args\":[\"@upstash/context7-mcp\"]}", + "jsonExampleHttp": "• http/sse: {\"type\":\"http\",\"url\":\"https://api.example.com/mcp\"}" + }, + "configDetails": "Configuration Details (from {{configFile}})", + "projectPath": "Path: {{path}}", + "actions": { + "cancel": "Cancel", + "saving": "Saving...", + "addServer": "Add Server", + "updateServer": "Update Server" + } + }, + "saveStatus": { + "success": "Settings saved successfully!", + "error": "Failed to save settings", + "saving": "Saving..." + }, + "footerActions": { + "save": "Save Settings", + "cancel": "Cancel" + }, + "git": { + "title": "Git Configuration", + "description": "Configure your git identity for commits. These settings will be applied globally via git config --global", + "name": { + "label": "Git Name", + "help": "Your name for git commits" + }, + "email": { + "label": "Git Email", + "help": "Your email for git commits" + }, + "actions": { + "save": "Save Configuration", + "saving": "Saving..." + }, + "status": { + "success": "Saved successfully" + } + }, + "apiKeys": { + "title": "API Keys", + "description": "Generate API keys to access the external API from other applications.", + "newKey": { + "alertTitle": "⚠️ Save Your API Key", + "alertMessage": "This is the only time you'll see this key. Store it securely.", + "iveSavedIt": "I've saved it" + }, + "form": { + "placeholder": "API Key Name (e.g., Production Server)", + "createButton": "Create", + "cancelButton": "Cancel" + }, + "newButton": "New API Key", + "empty": "No API keys created yet.", + "list": { + "created": "Created:", + "lastUsed": "Last used:" + }, + "confirmDelete": "Are you sure you want to delete this API key?", + "status": { + "active": "Active", + "inactive": "Inactive" + }, + "github": { + "title": "GitHub Tokens", + "description": "Add GitHub Personal Access Tokens to clone private repositories via the external API.", + "descriptionAlt": "Add GitHub Personal Access Tokens to clone private repositories. You can also pass tokens directly in API requests without storing them.", + "addButton": "Add Token", + "form": { + "namePlaceholder": "Token Name (e.g., Personal Repos)", + "tokenPlaceholder": "GitHub Personal Access Token (ghp_...)", + "descriptionPlaceholder": "Description (optional)", + "addButton": "Add Token", + "cancelButton": "Cancel", + "howToCreate": "How to create a GitHub Personal Access Token →" + }, + "empty": "No GitHub tokens added yet.", + "added": "Added:", + "confirmDelete": "Are you sure you want to delete this GitHub token?" + }, + "apiDocsLink": "API Documentation", + "documentation": { + "title": "External API Documentation", + "description": "Learn how to use the external API to trigger Claude/Cursor sessions from your applications.", + "viewLink": "View API Documentation →" + }, + "loading": "Loading...", + "version": { + "updateAvailable": "Update available: v{{version}}" + } + }, + "tasks": { + "checking": "Checking TaskMaster installation...", + "notInstalled": { + "title": "TaskMaster AI CLI Not Installed", + "description": "TaskMaster CLI is required to use task management features. Install it to get started:", + "installCommand": "npm install -g task-master-ai", + "viewOnGitHub": "View on GitHub", + "afterInstallation": "After installation:", + "steps": { + "restart": "Restart this application", + "autoAvailable": "TaskMaster features will automatically become available", + "initCommand": "Use task-master init in your project directory" + } + }, + "settings": { + "enableLabel": "Enable TaskMaster Integration", + "enableDescription": "Show TaskMaster tasks, banners, and sidebar indicators across the interface" + } + }, + "agents": { + "authStatus": { + "checking": "Checking...", + "connected": "Connected", + "notConnected": "Not connected", + "disconnected": "Disconnected", + "checkingAuth": "Checking authentication status...", + "loggedInAs": "Logged in as {{email}}", + "authenticatedUser": "authenticated user" + }, + "account": { + "claude": { + "description": "Anthropic Claude AI assistant" + }, + "cursor": { + "description": "Cursor AI-powered code editor" + }, + "codex": { + "description": "OpenAI Codex AI assistant" + } + }, + "connectionStatus": "Connection Status", + "login": { + "title": "Login", + "reAuthenticate": "Re-authenticate", + "description": "Sign in to your {{agent}} account to enable AI features", + "reAuthDescription": "Sign in with a different account or refresh credentials", + "button": "Login", + "reLoginButton": "Re-login" + }, + "error": "Error: {{error}}" + }, + "permissions": { + "title": "Permission Settings", + "skipPermissions": { + "label": "Skip permission prompts (use with caution)", + "claudeDescription": "Equivalent to --dangerously-skip-permissions flag", + "cursorDescription": "Equivalent to -f flag in Cursor CLI" + }, + "allowedTools": { + "title": "Allowed Tools", + "description": "Tools that are automatically allowed without prompting for permission", + "placeholder": "e.g., \"Bash(git log:*)\" or \"Write\"", + "quickAdd": "Quick add common tools:", + "empty": "No allowed tools configured" + }, + "blockedTools": { + "title": "Blocked Tools", + "description": "Tools that are automatically blocked without prompting for permission", + "placeholder": "e.g., \"Bash(rm:*)\"", + "empty": "No blocked tools configured" + }, + "allowedCommands": { + "title": "Allowed Shell Commands", + "description": "Shell commands that are automatically allowed without prompting", + "placeholder": "e.g., \"Shell(ls)\" or \"Shell(git status)\"", + "quickAdd": "Quick add common commands:", + "empty": "No allowed commands configured" + }, + "blockedCommands": { + "title": "Blocked Shell Commands", + "description": "Shell commands that are automatically blocked", + "placeholder": "e.g., \"Shell(rm -rf)\" or \"Shell(sudo)\"", + "empty": "No blocked commands configured" + }, + "toolExamples": { + "title": "Tool Pattern Examples:", + "bashGitLog": "- Allow all git log commands", + "bashGitDiff": "- Allow all git diff commands", + "write": "- Allow all Write tool usage", + "bashRm": "- Block all rm commands (dangerous)" + }, + "shellExamples": { + "title": "Shell Command Examples:", + "ls": "- Allow ls command", + "gitStatus": "- Allow git status", + "npmInstall": "- Allow npm install", + "rmRf": "- Block recursive delete" + }, + "codex": { + "permissionMode": "Permission Mode", + "description": "Controls how Codex handles file modifications and command execution", + "modes": { + "default": { + "title": "Default", + "description": "Only trusted commands (ls, cat, grep, git status, etc.) run automatically. Other commands are skipped. Can write to workspace." + }, + "acceptEdits": { + "title": "Accept Edits", + "description": "All commands run automatically within the workspace. Full auto mode with sandboxed execution." + }, + "bypassPermissions": { + "title": "Bypass Permissions", + "description": "Full system access with no restrictions. All commands run automatically with full disk and network access. Use with caution." + } + }, + "technicalDetails": "Technical details", + "technicalInfo": { + "default": "sandboxMode=workspace-write, approvalPolicy=untrusted. Trusted commands: cat, cd, grep, head, ls, pwd, tail, git status/log/diff/show, find (without -exec), etc.", + "acceptEdits": "sandboxMode=workspace-write, approvalPolicy=never. All commands auto-execute within project directory.", + "bypassPermissions": "sandboxMode=danger-full-access, approvalPolicy=never. Full system access, use only in trusted environments.", + "overrideNote": "You can override this per-session using the mode button in the chat interface." + } + }, + "actions": { + "add": "Add" + } + }, + "mcpServers": { + "title": "MCP Servers", + "description": { + "claude": "Model Context Protocol servers provide additional tools and data sources to Claude", + "cursor": "Model Context Protocol servers provide additional tools and data sources to Cursor", + "codex": "Model Context Protocol servers provide additional tools and data sources to Codex" + }, + "addButton": "Add MCP Server", + "empty": "No MCP servers configured", + "serverType": "Type", + "scope": { + "local": "local", + "user": "user" + }, + "config": { + "command": "Command", + "url": "URL", + "args": "Args", + "environment": "Environment" + }, + "tools": { + "title": "Tools", + "count": "({{count}}):", + "more": "+{{count}} more" + }, + "actions": { + "edit": "Edit server", + "delete": "Delete server" + }, + "help": { + "title": "About Codex MCP", + "description": "Codex supports stdio-based MCP servers. You can add servers that extend Codex's capabilities with additional tools and resources." + } } } diff --git a/src/i18n/locales/zh-CN/chat.json b/src/i18n/locales/zh-CN/chat.json new file mode 100644 index 0000000..6f20225 --- /dev/null +++ b/src/i18n/locales/zh-CN/chat.json @@ -0,0 +1,111 @@ +{ + "codeBlock": { + "copy": "复制", + "copied": "已复制", + "copyCode": "复制代码" + }, + "messageTypes": { + "user": "U", + "error": "错误", + "tool": "工具", + "claude": "Claude", + "cursor": "Cursor", + "codex": "Codex" + }, + "tools": { + "settings": "工具设置", + "error": "工具错误", + "result": "工具结果", + "viewParams": "查看输入参数", + "viewRawParams": "查看原始参数", + "viewDiff": "查看编辑差异", + "creatingFile": "创建新文件:", + "updatingTodo": "更新待办事项", + "read": "读取", + "readFile": "读取文件", + "updateTodo": "更新待办列表", + "readTodo": "读取待办列表", + "searchResults": "结果" + }, + "search": { + "found": "找到 {{count}} 个{{type}}", + "file": "文件", + "files": "文件", + "pattern": "模式:", + "in": "在:" + }, + "fileOperations": { + "updated": "文件更新成功", + "created": "文件创建成功", + "written": "文件写入成功", + "diff": "差异", + "newFile": "新文件", + "viewContent": "查看文件内容", + "viewFullOutput": "查看完整输出({{count}} 个字符)", + "contentDisplayed": "文件内容显示在上面的差异视图中" + }, + "interactive": { + "title": "交互式提示", + "waiting": "等待您在 CLI 中响应", + "instruction": "请在 Claude 运行的终端中选择一个选项。", + "selectedOption": "✓ Claude 选择了选项 {{number}}", + "instructionDetail": "在 CLI 中,您可以使用方向键或输入数字来交互式地选择此选项。" + }, + "thinking": { + "title": "思考中...", + "emoji": "💭 思考中..." + }, + "json": { + "response": "JSON 响应" + }, + "permissions": { + "grant": "授予 {{tool}} 权限", + "added": "权限已添加", + "addTo": "将 {{entry}} 添加到允许的工具。", + "retry": "权限已保存。重试请求以使用该工具。", + "error": "无法更新权限。请重试。", + "openSettings": "打开设置" + }, + "todo": { + "updated": "待办列表已成功更新", + "current": "当前待办列表" + }, + "plan": { + "viewPlan": "📋 查看实施计划", + "title": "实施计划" + }, + "usageLimit": { + "resetAt": "Claude 使用限制已达到。您的限制将在 **{{time}} {{timezone}}** - {{date}} 重置" + }, + "codex": { + "permissionMode": "权限模式", + "modes": { + "default": "默认模式", + "acceptEdits": "编辑模式", + "bypassPermissions": "无限制模式", + "plan": "计划模式" + }, + "descriptions": { + "default": "只有受信任的命令(ls、cat、grep、git status 等)自动运行。其他命令将被跳过。可以写入工作区。", + "acceptEdits": "工作区内的所有命令自动运行。完全自动模式,具有沙盒执行功能。", + "bypassPermissions": "完全的系统访问,无限制。所有命令自动运行,具有完整的磁盘和网络访问权限。请谨慎使用。", + "plan": "计划模式 - 不执行任何命令" + }, + "technicalDetails": "技术细节" + }, + "input": { + "placeholder": "输入 / 调用命令,@ 选择文件,或向 {{provider}} 提问...", + "placeholderDefault": "输入您的消息...", + "disabled": "输入已禁用", + "attachFiles": "附加文件", + "attachImages": "附加图片", + "send": "发送", + "stop": "停止", + "hintText": { + "ctrlEnter": "Ctrl+Enter 发送 • Shift+Enter 换行 • Tab 切换模式 • / 斜杠命令", + "enter": "Enter 发送 • Shift+Enter 换行 • Tab 切换模式 • / 斜杠命令" + }, + "clickToChangeMode": "点击更改权限模式(或在输入框中按 Tab)", + "showAllCommands": "显示所有命令" + } +} diff --git a/src/i18n/locales/zh-CN/settings.json b/src/i18n/locales/zh-CN/settings.json index 2814fb5..f8a60f2 100644 --- a/src/i18n/locales/zh-CN/settings.json +++ b/src/i18n/locales/zh-CN/settings.json @@ -7,6 +7,7 @@ "appearance": "外观" }, "account": { + "title": "账户", "language": "语言", "languageLabel": "显示语言", "languageDescription": "选择您偏好的界面语言", @@ -15,13 +16,6 @@ "profile": "个人资料", "changePassword": "修改密码" }, - "permissions": { - "allowedTools": "允许的工具", - "disallowedTools": "禁止的工具", - "addTool": "添加工具", - "removeTool": "移除工具", - "description": "配置 Claude 可以使用的工具。工具必须在此处启用后,Claude 才能访问它们。" - }, "mcp": { "title": "MCP 服务器", "addServer": "添加服务器", @@ -71,5 +65,337 @@ "autoScrollToBottom": "自动滚动到底部", "sendByCtrlEnter": "使用 Ctrl+Enter 发送", "sendByCtrlEnterDescription": "启用后,按 Ctrl+Enter 发送消息,而不是仅按 Enter。这对于使用输入法的用户可以避免意外发送。" + }, + "mainTabs": { + "agents": "智能体", + "appearance": "外观", + "git": "Git", + "apiTokens": "API 和令牌", + "tasks": "任务" + }, + "appearanceSettings": { + "darkMode": { + "label": "深色模式", + "description": "切换浅色和深色主题" + }, + "projectSorting": { + "label": "项目排序", + "description": "项目在侧边栏中的排列方式", + "alphabetical": "按字母顺序", + "recentActivity": "最近活动" + }, + "codeEditor": { + "title": "代码编辑器", + "theme": { + "label": "编辑器主题", + "description": "代码编辑器的默认主题" + }, + "wordWrap": { + "label": "自动换行", + "description": "在编辑器中默认启用自动换行" + }, + "showMinimap": { + "label": "显示缩略图", + "description": "在差异视图中显示缩略图以便于导航" + }, + "lineNumbers": { + "label": "显示行号", + "description": "在编辑器中显示行号" + }, + "fontSize": { + "label": "字体大小", + "description": "编辑器字体大小(px)" + } + } + }, + "mcpForm": { + "title": { + "add": "添加 MCP 服务器", + "edit": "编辑 MCP 服务器" + }, + "importMode": { + "form": "表单输入", + "json": "JSON 导入" + }, + "scope": { + "label": "范围", + "userGlobal": "用户(全局)", + "projectLocal": "项目(本地)", + "userDescription": "用户范围:在您机器上的所有项目中可用", + "projectDescription": "本地范围:仅在选定项目中可用", + "cannotChange": "编辑现有服务器时无法更改范围" + }, + "fields": { + "serverName": "服务器名称", + "transportType": "传输类型", + "command": "命令", + "arguments": "参数(每行一个)", + "jsonConfig": "JSON 配置", + "url": "URL", + "envVars": "环境变量(KEY=值,每行一个)", + "headers": "请求头(KEY=值,每行一个)", + "selectProject": "选择项目..." + }, + "placeholders": { + "serverName": "我的服务" + }, + "validation": { + "missingType": "缺少必填字段:type", + "stdioRequiresCommand": "stdio 类型需要 command 字段", + "httpRequiresUrl": "{{type}} 类型需要 url 字段", + "invalidJson": "无效的 JSON 格式", + "jsonHelp": "粘贴您的 MCP 服务器配置(JSON 格式)。示例格式:", + "jsonExampleStdio": "• stdio: {\"type\":\"stdio\",\"command\":\"npx\",\"args\":[\"@upstash/context7-mcp\"]}", + "jsonExampleHttp": "• http/sse: {\"type\":\"http\",\"url\":\"https://api.example.com/mcp\"}" + }, + "configDetails": "配置详细信息(来自 {{configFile}})", + "projectPath": "路径:{{path}}", + "actions": { + "cancel": "取消", + "saving": "保存中...", + "addServer": "添加服务器", + "updateServer": "更新服务器" + } + }, + "saveStatus": { + "success": "设置保存成功!", + "error": "保存设置失败", + "saving": "保存中..." + }, + "footerActions": { + "save": "保存设置", + "cancel": "取消" + }, + "git": { + "title": "Git 配置", + "description": "配置您的 git 提交身份。这些设置将通过 git config --global 全局应用", + "name": { + "label": "Git 名称", + "help": "您的 git 提交名称" + }, + "email": { + "label": "Git 邮箱", + "help": "您的 git 提交邮箱" + }, + "actions": { + "save": "保存配置", + "saving": "保存中..." + }, + "status": { + "success": "保存成功" + } + }, + "apiKeys": { + "title": "API 密钥", + "description": "生成 API 密钥以从其他应用访问外部 API。", + "newKey": { + "alertTitle": "⚠️ 保存您的 API 密钥", + "alertMessage": "这是您唯一一次看到此密钥。请妥善保存。", + "iveSavedIt": "我已保存" + }, + "form": { + "placeholder": "API 密钥名称(例如:生产服务器)", + "createButton": "创建", + "cancelButton": "取消" + }, + "newButton": "新建 API 密钥", + "empty": "尚未创建 API 密钥。", + "list": { + "created": "创建时间:", + "lastUsed": "最后使用:" + }, + "confirmDelete": "确定要删除此 API 密钥吗?", + "status": { + "active": "激活", + "inactive": "未激活" + }, + "github": { + "title": "GitHub 令牌", + "description": "添加 GitHub 个人访问令牌以通过外部 API 克隆私有仓库。", + "descriptionAlt": "添加 GitHub 个人访问令牌以克隆私有仓库。您也可以直接在 API 请求中传递令牌而无需存储。", + "addButton": "添加令牌", + "form": { + "namePlaceholder": "令牌名称(例如:个人仓库)", + "tokenPlaceholder": "GitHub 个人访问令牌(ghp_...)", + "descriptionPlaceholder": "描述(可选)", + "addButton": "添加令牌", + "cancelButton": "取消", + "howToCreate": "如何创建 GitHub 个人访问令牌 →" + }, + "empty": "尚未添加 GitHub 令牌。", + "added": "添加时间:", + "confirmDelete": "确定要删除此 GitHub 令牌吗?" + }, + "apiDocsLink": "API 文档", + "documentation": { + "title": "外部 API 文档", + "description": "了解如何使用外部 API 从您的应用程序触发 Claude/Cursor 会话。", + "viewLink": "查看 API 文档 →" + }, + "loading": "加载中...", + "version": { + "updateAvailable": "有可用更新:v{{version}}" + } + }, + "tasks": { + "checking": "正在检查 TaskMaster 安装...", + "notInstalled": { + "title": "未安装 TaskMaster AI CLI", + "description": "需要 TaskMaster CLI 才能使用任务管理功能。安装它以开始使用:", + "installCommand": "npm install -g task-master-ai", + "viewOnGitHub": "在 GitHub 上查看", + "afterInstallation": "安装后:", + "steps": { + "restart": "重启此应用程序", + "autoAvailable": "TaskMaster 功能将自动可用", + "initCommand": "在项目目录中使用 task-master init" + } + }, + "settings": { + "enableLabel": "启用 TaskMaster 集成", + "enableDescription": "在整个界面中显示 TaskMaster 任务、横幅和侧边栏指示器" + } + }, + "agents": { + "authStatus": { + "checking": "检查中...", + "connected": "已连接", + "notConnected": "未连接", + "disconnected": "已断开", + "checkingAuth": "正在检查认证状态...", + "loggedInAs": "登录为 {{email}}", + "authenticatedUser": "已认证用户" + }, + "account": { + "claude": { + "description": "Anthropic Claude AI 助手" + }, + "cursor": { + "description": "Cursor AI 驱动的代码编辑器" + }, + "codex": { + "description": "OpenAI Codex AI 助手" + } + }, + "connectionStatus": "连接状态", + "login": { + "title": "登录", + "reAuthenticate": "重新认证", + "description": "登录您的 {{agent}} 账户以启用 AI 功能", + "reAuthDescription": "使用其他账户登录或刷新凭据", + "button": "登录", + "reLoginButton": "重新登录" + }, + "error": "错误:{{error}}" + }, + "permissions": { + "title": "权限设置", + "skipPermissions": { + "label": "跳过权限提示(请谨慎使用)", + "claudeDescription": "等同于 --dangerously-skip-permissions 标志", + "cursorDescription": "等同于 Cursor CLI 中的 -f 标志" + }, + "allowedTools": { + "title": "允许的工具", + "description": "无需权限提示即可自动使用的工具", + "placeholder": "例如:\"Bash(git log:*)\" 或 \"Write\"", + "quickAdd": "快速添加常用工具:", + "empty": "未配置允许的工具" + }, + "blockedTools": { + "title": "禁用的工具", + "description": "无需权限提示即可自动禁用的工具", + "placeholder": "例如:\"Bash(rm:*)\"", + "empty": "未配置禁用的工具" + }, + "allowedCommands": { + "title": "允许的 Shell 命令", + "description": "无需权限提示即可自动执行的 Shell 命令", + "placeholder": "例如:\"Shell(ls)\" 或 \"Shell(git status)\"", + "quickAdd": "快速添加常用命令:", + "empty": "未配置允许的命令" + }, + "blockedCommands": { + "title": "阻止的 Shell 命令", + "description": "自动阻止的 Shell 命令", + "placeholder": "例如:\"Shell(rm -rf)\" 或 \"Shell(sudo)\"", + "empty": "未配置阻止的命令" + }, + "toolExamples": { + "title": "工具模式示例:", + "bashGitLog": "- 允许所有 git log 命令", + "bashGitDiff": "- 允许所有 git diff 命令", + "write": "- 允许所有 Write 工具使用", + "bashRm": "- 阻止所有 rm 命令(危险)" + }, + "shellExamples": { + "title": "Shell 命令示例:", + "ls": "- 允许 ls 命令", + "gitStatus": "- 允许 git status", + "npmInstall": "- 允许 npm install", + "rmRf": "- 阻止递归删除" + }, + "codex": { + "permissionMode": "权限模式", + "description": "控制 Codex 如何处理文件修改和命令执行", + "modes": { + "default": { + "title": "默认", + "description": "只有受信任的命令(ls、cat、grep、git status 等)会自动运行。其他命令将被跳过。可以写入工作区。" + }, + "acceptEdits": { + "title": "接受编辑", + "description": "所有命令在工作区内自动运行。具有沙箱执行的全自动模式。" + }, + "bypassPermissions": { + "title": "绕过权限", + "description": "完全系统访问,无任何限制。所有命令自动运行,具有完整的磁盘和网络访问权限。请谨慎使用。" + } + }, + "technicalDetails": "技术详情", + "technicalInfo": { + "default": "sandboxMode=workspace-write, approvalPolicy=untrusted。受信任的命令:cat、cd、grep、head、ls、pwd、tail、git status/log/diff/show、find(不带 -exec)等。", + "acceptEdits": "sandboxMode=workspace-write, approvalPolicy=never。所有命令在项目目录内自动执行。", + "bypassPermissions": "sandboxMode=danger-full-access, approvalPolicy=never。完全系统访问权限,仅在可信环境中使用。", + "overrideNote": "您可以使用聊天界面中的模式按钮按会话覆盖此设置。" + } + }, + "actions": { + "add": "添加" + } + }, + "mcpServers": { + "title": "MCP 服务器", + "description": { + "claude": "Model Context Protocol 服务器为 Claude 提供额外的工具和数据源", + "cursor": "Model Context Protocol 服务器为 Cursor 提供额外的工具和数据源", + "codex": "Model Context Protocol 服务器为 Codex 提供额外的工具和数据源" + }, + "addButton": "添加 MCP 服务器", + "empty": "未配置 MCP 服务器", + "serverType": "类型", + "scope": { + "local": "本地", + "user": "用户" + }, + "config": { + "command": "命令", + "url": "URL", + "args": "参数", + "environment": "环境变量" + }, + "tools": { + "title": "工具", + "count": "({{count}}):", + "more": "还有 {{count}} 个" + }, + "actions": { + "edit": "编辑服务器", + "delete": "删除服务器" + }, + "help": { + "title": "关于 Codex MCP", + "description": "Codex 支持基于 stdio 的 MCP 服务器。您可以添加服务器,通过额外的工具和资源来扩展 Codex 的功能。" + } } }
- Paste your MCP server configuration in JSON format. Example formats: + {t('mcpForm.validation.jsonHelp')} • stdio: {`{"type":"stdio","command":"npx","args":["@upstash/context7-mcp"]}`} • http/sse: {`{"type":"http","url":"https://api.example.com/mcp"}`}
TaskMaster CLI is required to use task management features. Install it to get started:
{t('tasks.notInstalled.description')}
npm install -g task-master-ai
{t('tasks.notInstalled.installCommand')}
After installation:
{t('tasks.notInstalled.afterInstallation')}
task-master init
{config.description}
{t(`agents.account.${agent}.description`)}
- Model Context Protocol servers provide additional tools and data sources to Claude + {t('mcpServers.description.claude')}
{server.config.command}
{server.config.url}
{server.config.args.join(' ')}
{tool.name}
- Model Context Protocol servers provide additional tools and data sources to Cursor + {t('mcpServers.description.cursor')}
- Model Context Protocol servers provide additional tools and data sources to Codex + {t('mcpServers.description.codex')}
{Object.entries(server.config.env).map(([k, v]) => `${k}=${v}`).join(', ')}
- Codex supports stdio-based MCP servers. You can add servers that extend Codex's capabilities - with additional tools and resources. + {t('mcpServers.help.description')}
- Tools that are automatically allowed without prompting for permission + {t('permissions.allowedTools.description')}
- Quick add common tools: + {t('permissions.allowedTools.quickAdd')}
- Tools that are automatically blocked without prompting for permission + {t('permissions.blockedTools.description')}
"Bash(git log:*)"
"Bash(git diff:*)"
"Write"
"Bash(rm:*)"
- Shell commands that are automatically allowed without prompting + {t('permissions.allowedCommands.description')}
- Quick add common commands: + {t('permissions.allowedCommands.quickAdd')}
- Shell commands that are automatically blocked + {t('permissions.blockedCommands.description')}
"Shell(ls)"
"Shell(git status)"
"Shell(npm install)"
"Shell(rm -rf)"
- Controls how Codex handles file modifications and command execution + {t('permissions.codex.description')}
Default: sandboxMode=workspace-write, approvalPolicy=untrusted. Trusted commands: cat, cd, grep, head, ls, pwd, tail, git status/log/diff/show, find (without -exec), etc.
Accept Edits: sandboxMode=workspace-write, approvalPolicy=never. All commands auto-execute within project directory.
Bypass Permissions: sandboxMode=danger-full-access, approvalPolicy=never. Full system access, use only in trusted environments.
You can override this per-session using the mode button in the chat interface.
{t('permissions.codex.modes.default.title')}: {t('permissions.codex.technicalInfo.default')}
{t('permissions.codex.modes.acceptEdits.title')}: {t('permissions.codex.technicalInfo.acceptEdits')}
{t('permissions.codex.modes.bypassPermissions.title')}: {t('permissions.codex.technicalInfo.bypassPermissions')}
{t('permissions.codex.technicalInfo.overrideNote')}