Every chat session now runs through the Hermes bridge, so the three chat chains become feature-equivalent instead of three partially-maintained dispatch paths. Keeping the coding-agent and in-house agent runtimes alive meant every bridge change had to be mirrored into two more runtimes that had already drifted. Historical rows are read, not migrated: sessions stored with the retired source normalize to cli on load, workflow graphs naming the retired agents keep loading and run on the bridge, and the visible-source check plus SOURCE_LABELS still recognize the old value so those sessions stay listed. The public surface follows the code: the OpenAPI generator and the MCP chat-run tool schema drop the six retired entry fields so external callers are not told about runtimes that no longer exist. harness-check gains a RETIRED_RUNTIME scan so the residual check is a mechanical gate instead of a manual grep, with the two surviving read-side compat sites recorded with reasons. Refs: docs/phases/phase_003.md
2352 lines
90 KiB
TypeScript
2352 lines
90 KiB
TypeScript
export default {
|
||
// Login
|
||
login: {
|
||
title: 'Hermes Studio',
|
||
description: 'Enter your username and password to continue.',
|
||
placeholder: 'Access token',
|
||
submit: 'Login',
|
||
tokenRequired: 'Please enter your access token',
|
||
invalidToken: 'Invalid token',
|
||
connectionFailed: 'Cannot connect to server',
|
||
passwordLogin: 'Password',
|
||
tokenLogin: 'Token',
|
||
usernamePlaceholder: 'Username',
|
||
passwordPlaceholder: 'Password',
|
||
defaultCredentialsHint: 'Default username: admin. Default password: 123456.',
|
||
credentialsRequired: 'Please enter username and password',
|
||
invalidCredentials: 'Invalid username or password',
|
||
tooManyAttempts: 'Too many failed attempts, please try again later',
|
||
lockResetHint: 'If this is your server, clear the login lock with:',
|
||
defaultLoginResetHint: 'To reset the default admin password, run:',
|
||
desktopLockResetHint: 'Too many failed login attempts. Open the system tray menu and choose Reset Login to reset the password.',
|
||
sessionExpired: 'Login expired. Please sign in again.',
|
||
accessDenied: 'You do not have permission to access this resource.',
|
||
passwordMismatch: 'Passwords do not match',
|
||
passwordTooShort: 'Password must be at least 6 characters',
|
||
setupSuccess: 'Password login configured successfully',
|
||
passwordChanged: 'Password changed successfully',
|
||
passwordRemoved: 'Password login removed',
|
||
setupPassword: 'Set Up Password Login',
|
||
changePassword: 'Change Password',
|
||
changeUsername: 'Change Username',
|
||
removePasswordLogin: 'Remove',
|
||
username: 'Username',
|
||
currentPassword: 'Current Password',
|
||
newPassword: 'New Password',
|
||
confirmPassword: 'Confirm Password',
|
||
newUsername: 'New Username',
|
||
usernameChanged: 'Username changed successfully',
|
||
usernameTooShort: 'Username must be at least 2 characters',
|
||
setupDescription: 'Manage the username and password used to sign in.',
|
||
removeConfirm: 'Password login is required for user accounts.',
|
||
passwordLoginNotConfigured: 'Password login is not configured',
|
||
passwordLoginConfigured: 'Current account: {username}',
|
||
defaultCredentialTitle: 'Change the default account credentials',
|
||
defaultCredentialMessage: 'This account is still using the default username or password. To prevent unauthorized access, update the username and password as soon as possible.',
|
||
defaultCredentialAction: 'Update now',
|
||
defaultCredentialLater: 'Remind me later',
|
||
},
|
||
|
||
users: {
|
||
title: 'Account Management',
|
||
description: 'Create users, assign roles, and control which profiles regular admins can access.',
|
||
create: 'Create User',
|
||
edit: 'Edit User',
|
||
username: 'Username',
|
||
role: 'Role',
|
||
statusLabel: 'Status',
|
||
profiles: 'Accessible Profiles',
|
||
profilesPlaceholder: 'Select accessible profiles',
|
||
allProfiles: 'All profiles',
|
||
noProfiles: 'No profiles assigned',
|
||
lastLogin: 'Last Login',
|
||
newPasswordOptional: 'New Password (leave blank to keep)',
|
||
loadFailed: 'Failed to load users',
|
||
deleteConfirm: 'Delete this user?',
|
||
enable: 'Enable',
|
||
disable: 'Disable',
|
||
roles: {
|
||
superAdmin: 'Super Admin',
|
||
admin: 'Admin',
|
||
},
|
||
status: {
|
||
active: 'Active',
|
||
disabled: 'Disabled',
|
||
},
|
||
},
|
||
|
||
// Common
|
||
common: {
|
||
loading: 'Loading...',
|
||
cancel: 'Cancel',
|
||
delete: 'Delete',
|
||
edit: 'Edit',
|
||
save: 'Save',
|
||
retry: 'Retry',
|
||
reset: 'Reset',
|
||
saved: 'Saved',
|
||
update: 'Update',
|
||
create: 'Create',
|
||
saveFailed: 'Save failed',
|
||
deleteFailed: 'Delete failed',
|
||
ok: 'OK',
|
||
copied: 'Copied',
|
||
copy: 'Copy',
|
||
noData: 'No data',
|
||
expired: 'Expired',
|
||
fetch: 'Fetch',
|
||
add: 'Add',
|
||
enable: 'Enable',
|
||
disable: 'Disable',
|
||
configured: 'Configured',
|
||
notConfigured: 'Not configured',
|
||
confirm: 'Confirm',
|
||
expand: 'Expand',
|
||
collapse: 'Collapse',
|
||
start: 'Start',
|
||
stop: 'Stop',
|
||
},
|
||
|
||
// MCP Management
|
||
mcp: {
|
||
title: 'MCP Servers',
|
||
loadFailed: 'Failed to load MCP servers',
|
||
reloadAll: 'Reload All',
|
||
refresh: 'Refresh',
|
||
total: 'Total',
|
||
connected: 'Connected',
|
||
disconnected: 'Disconnected',
|
||
tools: 'tools',
|
||
tool: 'Tools',
|
||
searchPlaceholder: 'Search servers...',
|
||
addServer: '+ Add Server',
|
||
zeroTools: '0 tools',
|
||
loading: 'Loading...',
|
||
empty: 'No MCP servers configured',
|
||
reloaded: 'Reloaded {server}',
|
||
reloadedAll: 'All MCP servers reloaded',
|
||
reloadFailed: 'Reload failed',
|
||
serverAdded: 'Server "{name}" added',
|
||
addFailed: 'Failed to add server',
|
||
serverUpdated: 'Server "{name}" updated',
|
||
updateFailed: 'Failed to update server',
|
||
saveFailed: 'Save failed',
|
||
serverRemoved: 'Removed "{name}"',
|
||
enabled: "Enabled {name}",
|
||
disabled: "Disabled {name}",
|
||
connectedStatus: 'Connected',
|
||
disconnectedStatus: 'Disconnected',
|
||
disabledStatus: 'Disabled',
|
||
toolList: 'Tool List',
|
||
count: ' ',
|
||
more: 'more',
|
||
removeFailed: 'Failed to remove server',
|
||
testOk: 'Test OK — {count} tools available',
|
||
testEmpty: 'Test returned no tools',
|
||
testFailed: 'Test failed',
|
||
edit: 'Edit',
|
||
test: 'Test',
|
||
reload: 'Reload',
|
||
remove: 'Remove',
|
||
confirmRemove: 'Remove server "{name}"?',
|
||
cancel: 'Cancel',
|
||
add: 'Add',
|
||
save: 'Save',
|
||
addTitle: 'Add MCP Server',
|
||
editTitle: 'Edit MCP Server',
|
||
invalidJson: 'Invalid JSON format',
|
||
invalidYaml: 'Invalid YAML format',
|
||
invalidConfig: 'Invalid configuration',
|
||
invalidServerConfig: 'Invalid server configuration',
|
||
missingCommandOrUrl: 'Must have command or url',
|
||
manageTools: 'Manage Tools',
|
||
toolsVisibilityTitle: 'Tools Visibility Management',
|
||
fetchTools: 'Fetch Tools List',
|
||
fetchToolsFailed: 'Failed to fetch tools list',
|
||
toolsMode: 'Mode:',
|
||
toolsModeAll: 'All',
|
||
toolsModeInclude: 'Include',
|
||
toolsModeExclude: 'Exclude',
|
||
toolsListHeader: 'Tool Name',
|
||
toolsEmpty: 'No tools available, please fetch tools list first',
|
||
toolsSummaryAll: '{count} tools total, all enabled',
|
||
toolsSummaryInclude: '{total} tools total, {count} selected',
|
||
toolsSummaryExclude: '{total} tools total, {count} excluded',
|
||
toolsVisibilitySaved: 'Tools visibility saved',
|
||
toolsSelectAll: 'Select all',
|
||
toolsClearSelection: 'Clear selection',
|
||
toolsExcludeAll: 'Exclude all',
|
||
toolsClearExcluded: 'Clear excluded',
|
||
},
|
||
|
||
// Sidebar
|
||
sidebar: {
|
||
chat: 'Chat',
|
||
backToChat: 'Back',
|
||
search: 'Search',
|
||
apiRelay: 'API Relay',
|
||
history: 'History',
|
||
jobs: 'Jobs',
|
||
kanban: 'Kanban',
|
||
workflow: 'Workflow',
|
||
models: 'Models',
|
||
profiles: 'Profiles',
|
||
skills: 'Skills',
|
||
plugins: 'Plugins',
|
||
mcp: 'MCP',
|
||
petdex: 'Pets',
|
||
memory: 'Memory',
|
||
logs: 'Logs',
|
||
usage: 'Usage',
|
||
performance: 'Performance',
|
||
journey: 'Journey',
|
||
skillsUsage: 'Skills Usage',
|
||
channels: 'Channels',
|
||
gateways: 'Gateways',
|
||
terminal: 'Terminal',
|
||
singleChat: 'Chat',
|
||
globalAgent: 'Global Agent',
|
||
groupChat: 'Group Chat',
|
||
files: 'Files',
|
||
devices: 'Devices',
|
||
groupConversation: 'Conversation',
|
||
groupConversationShort: 'Conv',
|
||
groupPlatform: 'Platform',
|
||
groupAgent: 'Agent',
|
||
groupAgentShort: 'Agent',
|
||
groupSystem: 'System',
|
||
groupSystemShort: 'Sys',
|
||
groupMonitoring: 'Monitoring',
|
||
groupMonitoringShort: 'Mon',
|
||
groupTools: 'Tools',
|
||
groupToolsShort: "Tools",
|
||
versionPreview: "Version Preview",
|
||
settings: 'Settings',
|
||
connected: 'Connected',
|
||
disconnected: 'Disconnected',
|
||
collapse: 'Collapse menu',
|
||
expand: 'Expand menu',
|
||
updateTip: 'Run "hermes-ui update" in terminal to update',
|
||
updateVersion: 'Upgrade to v{version}',
|
||
reloadClientVersion: 'Reload for v{version}',
|
||
updating: 'Updating...',
|
||
updateSuccess: 'Update successful. Please refresh the page shortly. If it does not start after a while, start it manually.',
|
||
updateFailed: 'Update failed',
|
||
logout: 'Sign Out',
|
||
nodeVersionWarning: 'Detected Node.js v{version}. Please upgrade to version 23 or later.',
|
||
changelog: 'Changelog',
|
||
noChangelog: 'No changelog available',
|
||
versionManagement: 'Version Management',
|
||
updateAvailableLabel: '(New version)',
|
||
dockerUpdateTitle: 'Docker Update',
|
||
dockerUpdateGuide: 'In Docker environment, please pull the latest image and recreate the container to upgrade:',
|
||
dockerUpdateNote: 'Your data will persist after the container is recreated.',
|
||
},
|
||
|
||
runtimeVersions: {
|
||
title: 'Version Management',
|
||
runtimeTitle: 'Hermes Runtime',
|
||
webUiTitle: 'Web UI',
|
||
platform: 'Platform',
|
||
currentWebUi: 'Current Web UI',
|
||
activeVersion: 'Active version',
|
||
active: 'Active',
|
||
installed: 'Installed',
|
||
download: 'Download',
|
||
downloadGithub: 'GitHub Download',
|
||
downloadCf: 'Cloudflare Download',
|
||
github: 'GitHub',
|
||
cf: 'Cloudflare',
|
||
useVersion: 'Use on next restart',
|
||
deleteVersion: 'Delete',
|
||
deleteRuntimeConfirm: 'Delete Hermes Runtime {version}?',
|
||
deleteWebUiConfirm: 'Delete Web UI {version}?',
|
||
deleteRuntimeSuccess: 'Runtime deleted',
|
||
deleteWebUiSuccess: 'Web UI deleted',
|
||
refresh: 'Refresh',
|
||
noVersions: 'No versions available',
|
||
remoteLoadFailed: 'Failed to load remote versions',
|
||
downloadTasks: 'Download tasks',
|
||
downloadStarted: 'Download started',
|
||
activateSuccess: 'Version selection saved. Restart Hermes Studio to use it.',
|
||
jobStatus: {
|
||
queued: 'Queued',
|
||
running: 'Running',
|
||
completed: 'Completed',
|
||
failed: 'Failed',
|
||
},
|
||
jobStageStatus: {
|
||
queued: 'Queued',
|
||
resolve: 'Resolving',
|
||
download: 'Downloading',
|
||
verify: 'Verifying',
|
||
extract: 'Extracting',
|
||
install: 'Installing',
|
||
completed: 'Completed',
|
||
failed: 'Failed',
|
||
},
|
||
jobStage: {
|
||
queued: 'Queued',
|
||
download: 'Downloading',
|
||
resolveRuntime: 'Resolving runtime package',
|
||
verifyRuntime: 'Verifying runtime archive',
|
||
extractRuntime: 'Extracting runtime archive',
|
||
installRuntime: 'Installing runtime',
|
||
resolveWebUi: 'Resolving Web UI package',
|
||
verifyWebUi: 'Verifying Web UI archive',
|
||
extractWebUi: 'Extracting Web UI archive',
|
||
installWebUi: 'Installing Web UI',
|
||
completed: 'Completed',
|
||
failed: 'Failed',
|
||
},
|
||
},
|
||
|
||
mcuDevices: {
|
||
title: 'Little Box',
|
||
subtitle: 'View device link status',
|
||
name: 'Name',
|
||
nameOptional: 'Name is optional',
|
||
deviceCode: 'Device code',
|
||
deviceCodePlaceholder: 'Enter device code',
|
||
deviceCodeRequired: 'Enter device code',
|
||
channel: 'Channel',
|
||
official: 'Official',
|
||
unofficial: 'Unofficial',
|
||
createdAt: 'Added at',
|
||
lanStatus: 'LAN',
|
||
remoteStatus: 'Remote',
|
||
connected: 'Connected',
|
||
disconnected: 'Disconnected',
|
||
remoteConnect: 'Remote connect',
|
||
remoteConnected: 'Remote connected',
|
||
remoteConnectFailed: 'Failed to connect remote',
|
||
remoteDisconnect: 'Disconnect',
|
||
remoteDisconnected: 'Remote disconnected',
|
||
remoteDisconnectFailed: 'Failed to disconnect remote',
|
||
actions: 'Actions',
|
||
add: 'Add',
|
||
addTitle: 'Add MCU device',
|
||
added: 'MCU device added',
|
||
addFailed: 'Failed to add MCU device',
|
||
purchase: 'Buy',
|
||
edit: 'Edit',
|
||
editNameTitle: 'Edit name',
|
||
nameUpdated: 'Name updated',
|
||
nameUpdateFailed: 'Failed to update name',
|
||
delete: 'Delete',
|
||
deleteTitle: 'Delete MCU device',
|
||
deleteConfirm: 'Delete "{name}"?',
|
||
deleted: 'MCU device deleted',
|
||
deleteFailed: 'Failed to delete MCU device',
|
||
loadFailed: 'Failed to load MCU devices',
|
||
close: 'Close',
|
||
},
|
||
|
||
devices: {
|
||
title: 'Devices',
|
||
count: '{count} devices',
|
||
lastScanned: 'Last scanned: {time}',
|
||
refresh: 'Refresh',
|
||
empty: 'No devices found',
|
||
computer: 'Computer',
|
||
endpointLabel: 'Endpoint',
|
||
statusLabel: 'Status',
|
||
online: 'Online',
|
||
offline: 'Offline',
|
||
address: 'Address',
|
||
os: 'OS',
|
||
agentVersion: 'Agent',
|
||
webUiVersion: 'Web UI',
|
||
responseMs: 'Latency',
|
||
lastSeen: 'Last seen',
|
||
open: 'Open',
|
||
never: 'Never',
|
||
unknown: 'Unknown',
|
||
loadFailed: 'Failed to load devices',
|
||
scanFailed: 'Failed to scan devices',
|
||
updateFailed: 'Failed to update device',
|
||
duplicateRequest: 'A pending pairing request already exists',
|
||
manualPairing: 'Pair by URL',
|
||
copyPairingLink: 'Copy pairing link',
|
||
manualUrlPlaceholder: 'https://device.example.com',
|
||
manualUrlRequired: 'Enter a device URL',
|
||
manualRequestSent: 'Pairing request sent',
|
||
manualRequestFailed: 'Failed to request remote pairing',
|
||
pairingLinkCopied: 'Pairing link copied',
|
||
pairingLinkCopyFailed: 'Failed to copy pairing link',
|
||
pairingCodeTitle: 'Enter pairing code',
|
||
pairingCodePlaceholder: 'Pairing code',
|
||
pairingCodeRequired: 'Enter the pairing code',
|
||
submitPairingRequest: 'Submit request',
|
||
processed: 'Processed',
|
||
unprocessed: 'Unprocessed',
|
||
deleteHistory: 'Delete record',
|
||
deleteHistoryConfirm: 'Delete this request record and revoke this device connection access?',
|
||
requests: 'Requests',
|
||
requestsWithCount: 'Requests ({count})',
|
||
noRequests: 'No requests',
|
||
requestPairing: 'Request pairing',
|
||
paired: 'Paired',
|
||
approve: 'Approve',
|
||
reject: 'Reject',
|
||
block: 'Block',
|
||
unblock: 'Unblock',
|
||
inboundStatus: {
|
||
none: 'Allowed to request',
|
||
pending: 'Pending',
|
||
approved: 'Approved',
|
||
rejected: 'Rejected',
|
||
blocked: 'Blocked',
|
||
},
|
||
outboundStatus: {
|
||
none: 'Unpaired',
|
||
pending: 'Requested',
|
||
approved: 'Paired',
|
||
rejected: 'Rejected',
|
||
blocked: 'Blocked',
|
||
},
|
||
endpoint: {
|
||
web: 'Web',
|
||
desktop: 'Desktop',
|
||
custom: 'Custom',
|
||
},
|
||
},
|
||
|
||
performance: {
|
||
title: 'Performance',
|
||
subtitle: 'Inspect system resources, bridge broker, workers, and active sessions',
|
||
refresh: 'Refresh',
|
||
autoRefreshOn: 'Auto refresh',
|
||
autoRefreshOff: 'Manual refresh',
|
||
loadFailed: 'Failed to load performance metrics',
|
||
systemCpu: 'System CPU',
|
||
systemMemory: 'System Memory',
|
||
activeSessions: 'Active Sessions',
|
||
runningSessions: 'Running {count}',
|
||
workers: 'Workers',
|
||
totalWorkerMemory: 'Worker memory',
|
||
processes: 'Processes',
|
||
uptime: 'Uptime',
|
||
running: 'Running',
|
||
stopped: 'Stopped',
|
||
workerMemory: 'Worker Memory',
|
||
lastUpdated: 'Updated',
|
||
profile: 'Profile',
|
||
memory: 'Memory',
|
||
sessions: 'Sessions',
|
||
runningActiveSessions: 'Running / Active',
|
||
lastUsed: 'Last Used',
|
||
status: 'Status',
|
||
noWorkers: 'No workers',
|
||
sessionsByProfile: 'Sessions by Profile',
|
||
noActiveSessions: 'No active sessions',
|
||
},
|
||
|
||
journey: {
|
||
title: 'Learning Journey',
|
||
play: 'Play journey',
|
||
pause: 'Pause journey',
|
||
refresh: 'Refresh',
|
||
loadFailed: 'Failed to load learning journey',
|
||
nodes: 'Nodes',
|
||
edges: 'Edges',
|
||
skills: 'Skills',
|
||
memories: 'Memories',
|
||
clusters: 'Clusters',
|
||
profile: 'Profile',
|
||
source: 'Source',
|
||
learnedSkills: 'Learned skills',
|
||
memorySkillEdges: 'Memory links',
|
||
allKinds: 'All kinds',
|
||
allCategories: 'All categories',
|
||
searchPlaceholder: 'Search nodes',
|
||
noClusters: 'No clusters',
|
||
noNodes: 'No journey nodes',
|
||
noCategory: 'Uncategorized',
|
||
category: 'Category',
|
||
useCount: 'Use count',
|
||
createdBy: 'Created by',
|
||
timestamp: 'Time',
|
||
pinned: 'Pinned',
|
||
},
|
||
|
||
// Drawer
|
||
drawer: {
|
||
terminal: 'Terminal',
|
||
files: 'Workspace',
|
||
},
|
||
|
||
// Chat
|
||
chat: {
|
||
contextRemaining: 'remaining',
|
||
contextClickToEdit: 'Click to edit context length',
|
||
contextEditTitle: 'Edit Context Length',
|
||
contextEditDesc: 'Set context length limit for current model (in tokens)',
|
||
contextEditPlaceholder: 'Enter context length',
|
||
contextEditHint: 'Common values: 256k (Hermes default), 128k (GPT-4), 32k (GPT-3.5)',
|
||
contextEditSave: 'Save',
|
||
contextEditCancel: 'Cancel',
|
||
contextEditInvalid: 'Please enter a valid context length',
|
||
contextEditSuccess: 'Context length updated',
|
||
contextEditFailed: 'Update failed',
|
||
emptyState: 'Start a conversation with Hermes Agent',
|
||
emptyStateAgent: 'Start a conversation with {agent}',
|
||
viewOlderInHistory: 'View earlier messages in History',
|
||
scrollToBottom: 'Scroll to bottom',
|
||
forkedFrom: 'Forked from',
|
||
previousLastMessage: 'Previous last message',
|
||
cliEmptyState: 'Start a CLI chat session',
|
||
outlineTitle: 'Conversation Outline',
|
||
outlineEmpty: 'No conversation content',
|
||
outlineUserQuestion: 'User question',
|
||
inputPlaceholder: 'Type a message... (Enter to send, Shift+Enter for new line)',
|
||
inputHeightResizeHint: 'Drag to resize the chat input. Double-click to reset.',
|
||
slashCommandArgs: {
|
||
message: '<message>',
|
||
title: '<title>',
|
||
text: '<text>',
|
||
},
|
||
slashCommands: {
|
||
usage: 'Calculate current session usage',
|
||
status: 'Show session status and queue',
|
||
abort: 'Stop the active bridge run',
|
||
queue: 'Queue a message behind the active run',
|
||
learn: 'Learn a reusable skill from described sources',
|
||
plan: 'Write a markdown implementation plan',
|
||
moa: 'Run one prompt through the default model ensemble',
|
||
goal: 'Set a standing goal that continues across turns',
|
||
goalStatus: 'Show the active goal status',
|
||
goalPause: 'Pause the active goal loop',
|
||
goalResume: 'Resume the paused goal loop',
|
||
goalDone: 'Complete and clear the active goal',
|
||
goalClear: 'Clear the active goal',
|
||
subgoal: 'Add a criterion to the active goal',
|
||
clear: 'Clear the current display',
|
||
clearHistory: 'Delete this session’s stored message history',
|
||
title: 'Rename this session',
|
||
compress: 'Run context compression while idle',
|
||
fork: 'Fork this idle session into a new linked conversation',
|
||
steer: 'Send steering text to the active bridge run',
|
||
destroy: 'Release the bridge agent for this session',
|
||
reloadMcp: 'Reload MCP servers',
|
||
reloadSkills: 'Reload skill commands',
|
||
},
|
||
attachFiles: 'Attach files',
|
||
reasoningEffort: {
|
||
tooltip: 'Reasoning effort',
|
||
defaultLabel: 'Default',
|
||
options: {
|
||
default: 'Default (config.yaml)',
|
||
none: 'None',
|
||
minimal: 'Minimal',
|
||
low: 'Low',
|
||
medium: 'Medium',
|
||
high: 'High',
|
||
xhigh: 'Extra high',
|
||
},
|
||
},
|
||
autoPlaySpeech: 'Auto-play voice',
|
||
voiceInput: {
|
||
startCapture: 'Start voice capture',
|
||
stopCaptureAndInsert: 'Stop voice capture and place transcript in the input',
|
||
cancelCapture: 'Cancel voice dialogue',
|
||
statusLabel: 'Status: {status}',
|
||
transcriptLabel: 'Transcript: {text}',
|
||
errorLabel: 'Error: {error}',
|
||
recentEvents: 'Recent events',
|
||
status: {
|
||
idle: 'Idle',
|
||
capturing: 'Capturing',
|
||
transcribing: 'Transcribing',
|
||
sending: 'Adding to input',
|
||
error: 'Error',
|
||
},
|
||
browserSpeechUnsupported: 'Browser speech recognition is not supported in this browser.',
|
||
browserSpeechFailed: 'Browser speech recognition failed.',
|
||
browserSpeechFailedWithReason: 'Browser speech recognition failed: {error}.',
|
||
microphoneUnsupported: 'Microphone capture is not supported in this browser.',
|
||
microphoneRecordingFailed: 'Microphone recording failed.',
|
||
},
|
||
showToolCalls: 'Show tool calls',
|
||
hideToolCalls: 'Hide tool calls',
|
||
messageQueue: 'Message queue',
|
||
removeQueuedMessage: 'Remove queued message',
|
||
stop: 'Stop',
|
||
start: 'Start',
|
||
stopGateway: 'Stop Gateway',
|
||
send: 'Send',
|
||
contextUsed: 'Context used:',
|
||
sessions: 'Sessions',
|
||
webUiSessions: 'Sessions',
|
||
allProfiles: 'All profiles',
|
||
profileMissingModelsTip: 'Profile "{profile}" has no available provider or model for this session',
|
||
sessionScopeHint: 'Chat shows Web UI/API Server sessions only. CLI, Telegram, Discord, Cron, and other channel sessions are read-only in History.',
|
||
openHistory: 'Open History',
|
||
hermesHistory: 'Hermes History',
|
||
historyScopeHint: 'Read-only Hermes history sessions for the current profile, grouped by source.',
|
||
noSessions: 'No sessions',
|
||
searchTitle: 'Search Sessions',
|
||
searchSubtitle: 'Search by title or message content',
|
||
searchScope: 'Search scope: Web UI local session database only. Read-only Hermes history sessions are not included.',
|
||
searchHint: 'Cmd/Ctrl+K',
|
||
searchPlaceholder: 'Search sessions...',
|
||
searchEmpty: 'Recent sessions',
|
||
searchRecent: 'Recent session',
|
||
searchNoResults: 'No sessions match your search',
|
||
searchNoSnippet: 'No snippet available',
|
||
searchEnterHint: 'Enter to open · Esc to close',
|
||
searchFailed: 'Failed to search sessions',
|
||
newChat: 'New Chat',
|
||
agent: 'Agent',
|
||
approvalKicker: 'Terminal permission',
|
||
approvalTitle: 'Review command before running',
|
||
approvalAgree: 'Agree',
|
||
approvalAllowOnce: 'Allow once',
|
||
approvalAllowSession: 'Allow session',
|
||
approvalAlways: 'Always',
|
||
approvalDeny: 'Deny',
|
||
clarifyKicker: 'Agent needs clarification',
|
||
clarifyTitle: 'The agent has a question for you',
|
||
clarifyPlaceholder: 'Type your answer...',
|
||
clarifySubmit: 'Reply',
|
||
clarifyDismiss: 'Dismiss',
|
||
newCliChat: 'New CLI',
|
||
deleteSession: 'Delete this session?',
|
||
sessionDeleted: 'Session deleted',
|
||
toggleBatchMode: 'Batch selection',
|
||
selectAll: 'Select all',
|
||
confirmBatchDelete: 'Delete {count} selected sessions?',
|
||
batchDeleteSuccess: 'Deleted {count} sessions',
|
||
batchDeletePartial: '{failed} sessions failed to delete',
|
||
batchDeleteFailed: 'Batch delete failed',
|
||
importToWebUi: 'Import to Web UI',
|
||
importSessionSuccess: 'Session imported to Web UI',
|
||
importSessionAlreadyExists: 'Session already exists in Web UI',
|
||
importSessionFailed: 'Failed to import session',
|
||
rename: 'Rename',
|
||
archiveSession: 'Archive',
|
||
unarchiveSession: 'Unarchive',
|
||
pin: 'Pin',
|
||
unpin: 'Unpin',
|
||
pinned: 'Pinned',
|
||
chatMode: 'Chat',
|
||
liveMode: 'Live',
|
||
liveSessions: 'Live Sessions',
|
||
recentBadge: 'Recent',
|
||
linkedSessions: '{count} linked',
|
||
noVisibleMessages: 'No human-visible messages.',
|
||
monitorRoleUser: 'User',
|
||
monitorRoleAssistant: 'Assistant',
|
||
copySessionLink: 'Copy Session Link',
|
||
openSessionInNewTab: 'Open in new tab',
|
||
sessionLinkCopied: 'Session link copied',
|
||
copySessionId: 'Copy Session ID',
|
||
export: 'Export',
|
||
exportFull: 'Full Export (JSON)',
|
||
exportCompressed: 'Compressed Export (TXT)',
|
||
exportCompressing: 'Compressing context, please wait...',
|
||
exportSuccess: 'Session exported',
|
||
exportFailed: 'Export failed',
|
||
renamed: 'Renamed',
|
||
renameFailed: 'Rename failed',
|
||
sessionArchived: 'Session archived',
|
||
archiveSessionFailed: 'Failed to archive session',
|
||
sessionUnarchived: 'Session unarchived',
|
||
unarchiveSessionFailed: 'Failed to unarchive session',
|
||
renameSession: 'Rename Session',
|
||
sessionNotFound: 'Session not found',
|
||
enterNewTitle: 'Enter new title',
|
||
workspace: 'Workspace',
|
||
workspaceDefault: 'Default',
|
||
workspaceDefaultTooltip: 'This workspace is set as default and will be auto-filled for new chats',
|
||
workspacePin: 'Set as default workspace',
|
||
workspaceUnpin: 'Unset default workspace',
|
||
workspaceRecent: 'Recent',
|
||
defaultWorkspace: 'Default Workspace',
|
||
more: 'More',
|
||
setWorkspace: 'Set Workspace',
|
||
setWorkspaceTitle: 'Set Session Workspace',
|
||
workspacePlaceholder: 'Enter project path, e.g. /home/user/project',
|
||
folderPickerEmpty: '(Empty)',
|
||
folderPickerNoFolders: 'No workspace folders',
|
||
folderPickerSelected: 'Selected:',
|
||
workspaceSet: 'Workspace set',
|
||
workspaceSetFailed: 'Failed to set workspace',
|
||
setModel: 'Set Model',
|
||
setModelTitle: 'Set Session Model',
|
||
modelSet: 'Model set',
|
||
modelSetFailed: 'Failed to set model',
|
||
other: 'Other',
|
||
runFailed: 'Run failed',
|
||
error: 'Error',
|
||
tool: 'Tool',
|
||
arguments: 'Arguments',
|
||
result: 'Result',
|
||
workspaceChanges: 'Workspace changes',
|
||
changedFiles: '{files} files changed',
|
||
diffUnavailable: 'Diff unavailable',
|
||
binaryFileDiffUnavailable: 'Binary file diff unavailable',
|
||
truncated: '... (truncated)',
|
||
unchangedLines: '{count} unchanged lines',
|
||
executionDuration: 'Execution time',
|
||
thinkingLabel: 'Thinking',
|
||
thinkingInProgress: 'Thinking',
|
||
thinkingShow: 'Show thinking',
|
||
thinkingHide: 'Hide thinking',
|
||
thinkingDuration: 'Observed {duration}',
|
||
thinkingChars: '{count} chars',
|
||
copyBubble: 'Copy message',
|
||
copiedBubble: 'Message copied',
|
||
copyFailed: 'Copy failed',
|
||
playSpeech: 'Play voice',
|
||
pauseSpeech: 'Pause',
|
||
resumeSpeech: 'Resume',
|
||
stopSpeech: 'Stop',
|
||
speechNotSupported: 'Voice playback not supported in this browser',
|
||
},
|
||
|
||
workflow: {
|
||
title: 'Workflow',
|
||
profile: 'Profile',
|
||
namePlaceholder: 'Workflow name',
|
||
workspace: {
|
||
title: 'Select Workspace',
|
||
select: 'Select workspace',
|
||
clear: 'Clear workspace',
|
||
},
|
||
actions: {
|
||
newWorkflow: 'New Workflow',
|
||
addNode: 'Add Node',
|
||
createWorkflowFirst: 'Please create a workflow first',
|
||
reset: 'Reset',
|
||
startExecution: 'Start Execution',
|
||
executionPending: 'Workflow execution is not connected yet',
|
||
executionStarted: 'Workflow execution started',
|
||
executionCompleted: 'Workflow execution completed',
|
||
executionFailed: 'Workflow execution failed',
|
||
rerunDownstreamKeepNode: 'Keep this node and run downstream',
|
||
rerunDownstreamClearNode: 'Clear this node and run downstream',
|
||
rerunDownstreamStarted: 'Downstream rerun started',
|
||
rerunFromNodeStarted: 'Rerun from this node started',
|
||
rerunFailed: 'Workflow rerun failed',
|
||
deleteNode: 'Delete Node',
|
||
deleteEdge: 'Delete Connection',
|
||
},
|
||
batch: {
|
||
toggle: 'Batch selection',
|
||
selectAll: 'Select all',
|
||
confirmDelete: 'Delete {count} selected workflows?',
|
||
deleteSuccess: 'Deleted {count} workflows',
|
||
deletePartial: '{failed} workflows failed to delete',
|
||
deleteFailed: 'Batch delete failed',
|
||
},
|
||
validation: {
|
||
nodesRequired: 'Add at least one node',
|
||
nodeNameRequired: 'Node {node} needs a name',
|
||
providerRequired: 'Node {node} needs a provider',
|
||
modelRequired: 'Node {node} needs a model',
|
||
apiModeRequired: 'Node {node} needs an API mode',
|
||
inputRequired: 'Node {node} needs input',
|
||
invalidEdge: 'A connection references a missing node',
|
||
invalidConnectionDirection: 'Connections must go from the right output to the left input',
|
||
orphanNode: 'Node {node} is not connected to the workflow',
|
||
disconnectedFlow: 'The workflow cannot be split into multiple disconnected flows',
|
||
cycle: 'The workflow contains a cycle. Adjust the connections before saving.',
|
||
},
|
||
node: {
|
||
title: 'Node name',
|
||
agent: 'Agent',
|
||
model: 'Model',
|
||
apiMode: 'API Mode',
|
||
input: 'Input',
|
||
approvalRequired: 'Approval gate',
|
||
promptPlaceholder: 'Describe what this agent should do...',
|
||
skillsPlaceholder: 'Skills, press Enter to add',
|
||
uploadImages: 'Upload images',
|
||
},
|
||
status: {
|
||
idle: 'Idle',
|
||
queued: 'Queued',
|
||
running: 'Running',
|
||
pending_approval: 'Pending approval',
|
||
completed: 'Completed',
|
||
failed: 'Failed',
|
||
approval_rejected: 'Approval rejected',
|
||
canceled: 'Canceled',
|
||
},
|
||
runs: {
|
||
title: 'Run Records',
|
||
refresh: 'Refresh',
|
||
empty: 'No run records',
|
||
startNodes: '{count} start nodes',
|
||
show: 'Show run records',
|
||
hide: 'Hide run records',
|
||
nodeSessionTitle: 'Node Session - {node}',
|
||
noNodeSession: 'This node has no session record yet',
|
||
loadNodeSessionFailed: 'Failed to load node session',
|
||
stop: 'Stop run',
|
||
stopRequested: 'Stop requested',
|
||
stopFailed: 'Failed to stop run',
|
||
delete: 'Delete record',
|
||
deleteSuccess: 'Run record deleted',
|
||
},
|
||
inspector: {
|
||
selected: 'Selected Node',
|
||
none: 'No node selected',
|
||
},
|
||
stats: {
|
||
nodes: 'Nodes',
|
||
edges: 'Links',
|
||
},
|
||
agents: {
|
||
planner: 'Planner',
|
||
researcher: 'Researcher',
|
||
builder: 'Builder',
|
||
reviewer: 'Reviewer',
|
||
},
|
||
models: {
|
||
default: 'Default Model',
|
||
fast: 'Fast Model',
|
||
reasoning: 'Reasoning Model',
|
||
},
|
||
initialNodes: {
|
||
node1: 'Node 1',
|
||
node2: 'Node 2',
|
||
node3: 'Node 3',
|
||
plan: 'Plan',
|
||
execute: 'Execute',
|
||
review: 'Review',
|
||
},
|
||
initialPrompts: {
|
||
node1: 'Enter this node input.',
|
||
node2: 'Enter this node input.',
|
||
node3: 'Enter this node input.',
|
||
plan: 'Break the request into actionable steps.',
|
||
execute: 'Run the implementation steps and produce artifacts.',
|
||
review: 'Review output quality and identify follow-up work.',
|
||
},
|
||
newNodeTitle: 'Node {count}',
|
||
},
|
||
|
||
// Kanban
|
||
kanban: {
|
||
title: 'Kanban Board',
|
||
createTask: 'New Task',
|
||
noTasks: 'No tasks',
|
||
allStatuses: 'All Statuses',
|
||
allAssignees: 'All Assignees',
|
||
board: {
|
||
create: 'New Board',
|
||
archive: 'Archive Board',
|
||
slugPlaceholder: 'Board slug, e.g. project-a',
|
||
namePlaceholder: 'Display name (optional)',
|
||
slugRequired: 'Board slug is required',
|
||
created: 'Board created',
|
||
archived: 'Board archived',
|
||
archiveConfirm: 'Archive the current board?',
|
||
},
|
||
columns: {
|
||
triage: 'Triage',
|
||
todo: 'To Do',
|
||
scheduled: 'Scheduled',
|
||
ready: 'Ready',
|
||
running: 'Running',
|
||
blocked: 'Blocked',
|
||
review: 'Review',
|
||
done: 'Done',
|
||
archived: 'Archived',
|
||
},
|
||
form: {
|
||
title: 'Title',
|
||
titlePlaceholder: 'Task title',
|
||
titleRequired: 'Title is required',
|
||
body: 'Description',
|
||
bodyPlaceholder: 'Task description (optional)',
|
||
assignee: 'Assignee',
|
||
selectAssignee: 'Select assignee...',
|
||
priority: 'Priority',
|
||
selectPriority: 'Select priority...',
|
||
tenant: 'Tenant',
|
||
tenantPlaceholder: 'Tenant (optional)',
|
||
workspace: 'Workspace',
|
||
workspaceScratch: 'Scratch workspace',
|
||
workspaceDir: 'Use directory',
|
||
workspaceWorktree: 'Use worktree',
|
||
workspacePath: 'Workspace path',
|
||
workspacePathPlaceholder: 'Absolute path (optional)',
|
||
branch: 'Branch',
|
||
branchPlaceholder: 'Worktree branch',
|
||
skills: 'Skills',
|
||
skillsPlaceholder: 'Select skills...',
|
||
triage: 'Create in triage',
|
||
goalMode: 'Goal mode',
|
||
maxRuntime: 'Max runtime',
|
||
maxRuntimePlaceholder: 'e.g. 30m, 2h',
|
||
maxRetries: 'Max retries',
|
||
maxRetriesPlaceholder: 'Number of retries',
|
||
goalMaxTurns: 'Goal max turns',
|
||
goalMaxTurnsPlaceholder: 'Maximum turns',
|
||
},
|
||
card: {
|
||
assigneeTooltip: 'Assignee',
|
||
priority: {
|
||
low: 'Low',
|
||
medium: 'Medium',
|
||
high: 'High',
|
||
},
|
||
timeAgo: {
|
||
justNow: 'just now',
|
||
minutes: '{count}m ago',
|
||
hours: '{count}h ago',
|
||
days: '{count}d ago',
|
||
},
|
||
},
|
||
detail: {
|
||
status: 'Status',
|
||
assignee: 'Assignee',
|
||
priority: 'Priority',
|
||
tenant: 'Tenant',
|
||
createdAt: 'Created',
|
||
startedAt: 'Started',
|
||
completedAt: 'Completed',
|
||
comments: 'Comments',
|
||
events: 'Events',
|
||
runs: 'Runs',
|
||
result: 'Result',
|
||
sessions: 'Related Sessions',
|
||
sessionMessages: 'Session Messages',
|
||
noSessions: 'No related sessions found.',
|
||
artifacts: 'Artifacts',
|
||
sources: 'Sources',
|
||
highlights: 'Highlights',
|
||
noLog: 'No log found for this task.',
|
||
addComment: 'Add Comment',
|
||
commentPlaceholder: 'Write a task comment...',
|
||
operations: 'Operations',
|
||
},
|
||
action: {
|
||
title: 'Actions',
|
||
complete: 'Complete',
|
||
completeSummary: 'Completion summary (optional)',
|
||
block: 'Block',
|
||
blockReason: 'Reason for blocking',
|
||
unblock: 'Unblock',
|
||
assign: 'Assign',
|
||
assignTo: 'Assign to...',
|
||
dispatch: 'Dispatch',
|
||
recoveryReason: 'Recovery reason (optional)',
|
||
reclaim: 'Reclaim',
|
||
reassign: 'Reassign',
|
||
specify: 'Specify',
|
||
loadLog: 'Load Log',
|
||
loadDiagnostics: 'Load Diagnostics',
|
||
},
|
||
message: {
|
||
taskCreated: 'Task created',
|
||
taskCompleted: 'Task completed',
|
||
taskBlocked: 'Task blocked',
|
||
taskUnblocked: 'Task unblocked',
|
||
taskAssigned: 'Task assigned',
|
||
dispatchNudged: 'Dispatcher nudged',
|
||
commentAdded: 'Comment added',
|
||
taskReclaimed: 'Task reclaimed',
|
||
taskReassigned: 'Task reassigned',
|
||
taskSpecified: 'Task specified',
|
||
loadFailed: 'Failed to load task',
|
||
},
|
||
stats: {
|
||
total: 'Total',
|
||
tasks: 'Tasks',
|
||
},
|
||
},
|
||
|
||
// Jobs
|
||
jobs: {
|
||
title: 'Scheduled Jobs',
|
||
createJob: 'Create Job',
|
||
editJob: 'Edit Job',
|
||
noJobs: 'No scheduled jobs yet. Create one to get started.',
|
||
sortBy: 'Sort',
|
||
sortByName: 'Name Sort',
|
||
sortByTime: 'Time Sort',
|
||
sortByNameHint: 'Click to sort by name',
|
||
sortByTimeHint: 'Click to sort by time',
|
||
sortAsc: 'Ascending',
|
||
sortDesc: 'Descending',
|
||
name: 'Name',
|
||
namePlaceholder: 'Job name',
|
||
schedule: 'Schedule (Cron Expression)',
|
||
schedulePlaceholder: 'e.g. 0 9 * * *',
|
||
quickPresets: 'Quick Presets',
|
||
selectPreset: 'Select a preset...',
|
||
presetEveryMinute: 'Every minute',
|
||
presetEvery5Min: 'Every 5 minutes',
|
||
presetEveryHour: 'Every hour',
|
||
presetEveryDay: 'Every day at 00:00',
|
||
presetEveryDay9: 'Every day at 09:00',
|
||
presetEveryMonday: 'Every Monday at 09:00',
|
||
presetEveryMonth: 'Every month 1st at 09:00',
|
||
prompt: 'Prompt',
|
||
promptPlaceholder: 'The prompt to execute',
|
||
skills: 'Skills',
|
||
skillsPlaceholder: 'Select skills...',
|
||
provider: 'Provider',
|
||
model: 'Model',
|
||
defaultProvider: 'Default provider',
|
||
defaultModel: 'Default model',
|
||
deliverTarget: 'Deliver Target',
|
||
origin: 'Origin',
|
||
local: 'Local',
|
||
repeatCount: 'Repeat Count (optional)',
|
||
modelPlaceholder: 'Default model',
|
||
repeatPlaceholder: 'Leave empty for infinite',
|
||
jobCreated: 'Job created',
|
||
jobUpdated: 'Job updated',
|
||
nameRequired: 'Name is required',
|
||
scheduleRequired: 'Schedule is required',
|
||
loadFailed: 'Failed to load job',
|
||
jobPaused: 'Job paused',
|
||
jobResumed: 'Job resumed',
|
||
jobTriggered: 'Job triggered',
|
||
modelUpdated: 'Model updated',
|
||
jobDeleted: 'Job deleted',
|
||
status: {
|
||
running: 'Running',
|
||
paused: 'Paused',
|
||
disabled: 'Disabled',
|
||
scheduled: 'Scheduled',
|
||
},
|
||
info: {
|
||
model: 'Model',
|
||
provider: 'Provider',
|
||
schedule: 'Schedule',
|
||
lastRun: 'Last Run',
|
||
nextRun: 'Next Run',
|
||
deliver: 'Deliver',
|
||
repeat: 'Repeat',
|
||
},
|
||
action: {
|
||
pause: 'Pause',
|
||
pauseJob: 'Pause job',
|
||
resume: 'Resume',
|
||
resumeJob: 'Resume job',
|
||
runNow: 'Run Now',
|
||
triggerImmediately: 'Trigger immediately',
|
||
},
|
||
runHistory: {
|
||
title: 'Run History',
|
||
runs: 'runs',
|
||
noRuns: 'No run history found.',
|
||
},
|
||
},
|
||
|
||
// Skills
|
||
skills: {
|
||
title: 'Skills',
|
||
targetFilter: 'Runtime',
|
||
targets: {
|
||
hermes: 'Hermes',
|
||
claude: 'Claude',
|
||
codex: 'Codex',
|
||
},
|
||
searchPlaceholder: 'Search skills...',
|
||
noMatch: 'No skills match your search',
|
||
noSkills: 'No skills found',
|
||
backTo: 'Back to',
|
||
attachedFiles: 'Attached Files',
|
||
loadFailed: 'Failed to load skill',
|
||
fileLoadFailed: 'Failed to load file',
|
||
modified: 'Modified',
|
||
archived: 'Archived',
|
||
pinned: 'Pinned',
|
||
pin: 'Pin skill',
|
||
unpin: 'Unpin skill',
|
||
pinFailed: 'Failed to change pin status',
|
||
edit: 'Edit',
|
||
saving: 'Saving...',
|
||
editorLabel: 'Skill editor',
|
||
saveSuccess: 'Skill saved',
|
||
saveFailed: 'Failed to save skill',
|
||
toggleFailed: 'Failed to toggle skill',
|
||
source: {
|
||
builtin: 'Builtin',
|
||
hub: 'Hub',
|
||
local: 'Local',
|
||
external: 'External',
|
||
},
|
||
delete: 'Delete',
|
||
deleteConfirm: 'Delete skill "{name}"? This cannot be undone.',
|
||
deleteSuccess: 'Skill deleted',
|
||
deleteFailed: 'Failed to delete skill',
|
||
import: 'Import',
|
||
importTitle: 'Import skill',
|
||
importModeZip: 'Zip',
|
||
importModeFolder: 'Folder',
|
||
importHintZip: 'Upload a .zip archive containing a directory with SKILL.md',
|
||
importHintFolder: 'Pick a local skill folder (must contain SKILL.md)',
|
||
importTargetCategory: 'Target category (optional)',
|
||
importTargetCategoryPlaceholder: 'Leave empty to drop under misc',
|
||
importSelectFile: 'Choose .zip file',
|
||
importSelectFolder: 'Choose folder',
|
||
importInvalidFile: 'Only .zip archives are supported',
|
||
importFileCount: 'files',
|
||
importNoSelection: 'Please choose a file or folder first',
|
||
importSuccess: 'Skill imported',
|
||
importFailed: 'Failed to import skill',
|
||
path: {
|
||
local: 'Local',
|
||
external: 'External',
|
||
},
|
||
externalDirs: {
|
||
manage: 'External dirs',
|
||
title: 'Manage external skill dirs',
|
||
hint: 'Manages config.skills.external_dirs. Supports ~ and $VAR; missing paths are greyed out.',
|
||
add: 'Add external dir',
|
||
placeholder: '/path/to/skills or ~/my-skills',
|
||
empty: 'No external dirs',
|
||
missing: 'Path not found',
|
||
notDir: 'Not a directory',
|
||
saveSuccess: 'External dirs saved',
|
||
saveFailed: 'Save failed',
|
||
loadFailed: 'Failed to load external dirs',
|
||
removeRow: 'Remove',
|
||
},
|
||
pathCopied: 'Path copied',
|
||
pathCopyFailed: 'Failed to copy path',
|
||
reloadHint: 'Active sessions: run /reload-skills; new sessions pick it up automatically.',
|
||
writeApprovalButton: 'Pending {count}',
|
||
writeApprovalTitle: 'Pending write approvals',
|
||
writeApprovalDescription: 'Approve or reject staged Hermes Agent memory and skill writes.',
|
||
writeApprovalRefresh: 'Refresh',
|
||
writeApprovalEmpty: 'No pending writes.',
|
||
writeApprovalUnsupported: 'This Hermes Agent version does not support write approvals. Upgrade Hermes Agent to use this feature.',
|
||
writeApprovalMemory: 'Memory',
|
||
writeApprovalSkills: 'Skills',
|
||
writeApprovalViewDiff: 'Review',
|
||
writeApprovalHideDiff: 'Hide',
|
||
writeApprovalNoDiff: 'No diff available.',
|
||
writeApprovalLoadFailed: 'Failed to load pending writes',
|
||
writeApprovalDiffFailed: 'Failed to load write details',
|
||
writeApprovalActionFailed: 'Failed to resolve pending write',
|
||
writeApprovalApproved: 'Pending write approved',
|
||
writeApprovalRejected: 'Pending write rejected',
|
||
writeApprovalApprove: 'Approve',
|
||
writeApprovalReject: 'Reject',
|
||
writeApprovalPendingMemoryWrite: 'Pending memory write',
|
||
writeApprovalCurrentFile: 'Current {file}',
|
||
writeApprovalProposedFile: 'Proposed {file}',
|
||
writeApprovalDiffSection: 'Diff',
|
||
writeApprovalPatchOldStringMissing: 'The patch old_string was not found in the current {file}, so approving it will not change the file.',
|
||
writeApprovalRequestedOldString: 'Requested old_string',
|
||
writeApprovalCurrentReadFailed: 'The current {file} could not be read as UTF-8 text.',
|
||
writeApprovalDeleteSkill: 'This approval deletes skill {skill}.',
|
||
writeApprovalRemoveFile: 'This approval removes {file} from skill {skill}.',
|
||
},
|
||
|
||
// Plugins
|
||
plugins: {
|
||
title: 'Plugins',
|
||
refresh: 'Refresh',
|
||
notice: 'Inventory of discoverable Hermes plugin manifests. Discovery metadata is read without loading plugin code. Standalone user plugins can be enabled or disabled here; changes take effect in new Hermes sessions.',
|
||
loadFailed: 'Failed to load plugins',
|
||
updateFailed: 'Failed to update plugin',
|
||
enableSuccess: 'Enabled {name}',
|
||
disableSuccess: 'Disabled {name}',
|
||
commandCopied: 'Command copied',
|
||
searchPlaceholder: 'Search key, name, description, path...',
|
||
source: 'Source',
|
||
kind: 'Kind',
|
||
statusTitle: 'Status',
|
||
configStatus: 'config: {status}',
|
||
notAvailable: 'n/a',
|
||
copyCommand: 'Copy command',
|
||
managedElsewhere: 'managed elsewhere',
|
||
noMatch: 'No plugins match the current filters',
|
||
enabled: 'enabled',
|
||
disabled: 'disabled',
|
||
summary: {
|
||
total: 'Total',
|
||
active: 'Enabled / auto',
|
||
inactive: 'Inactive',
|
||
disabled: 'Disabled',
|
||
providerManaged: 'Provider-managed',
|
||
},
|
||
status: {
|
||
enabled: 'Enabled',
|
||
'auto-active': 'Auto-active',
|
||
inactive: 'Inactive',
|
||
disabled: 'Disabled',
|
||
'provider-managed': 'Provider-managed',
|
||
},
|
||
statusLabel: {
|
||
enabled: 'Enabled by config',
|
||
'auto-active': 'Auto-active',
|
||
inactive: 'Inactive',
|
||
disabled: 'Disabled',
|
||
'provider-managed': 'Provider-managed',
|
||
},
|
||
configStatuses: {
|
||
enabled: 'enabled',
|
||
disabled: 'disabled',
|
||
'not-enabled': 'not enabled',
|
||
auto: 'auto',
|
||
'provider-managed': 'provider-managed',
|
||
},
|
||
table: {
|
||
plugin: 'Plugin',
|
||
status: 'Status',
|
||
source: 'Source',
|
||
kind: 'Kind',
|
||
capabilities: 'Capabilities',
|
||
path: 'Path / entrypoint',
|
||
manage: 'Manage',
|
||
},
|
||
capabilities: {
|
||
tools: '{count} tools',
|
||
hooks: '{count} hooks',
|
||
env: '{count} env',
|
||
},
|
||
metadata: {
|
||
agentRoot: 'Agent root',
|
||
python: 'Python',
|
||
scanCwd: 'Scan cwd',
|
||
projectPlugins: 'Project plugins',
|
||
},
|
||
},
|
||
|
||
petdex: {
|
||
title: 'Petdex Pets',
|
||
subtitle: 'Browse the public petdex catalog used by Hermes desktop pets.',
|
||
refresh: 'Refresh',
|
||
adopt: 'Adopt',
|
||
active: 'Active',
|
||
adopted: 'Adopted {name}',
|
||
adoptFailed: 'Failed to adopt pet',
|
||
loadFailed: 'Failed to load petdex catalog',
|
||
searchPlaceholder: 'Search by name, slug, author, or kind',
|
||
kindFilter: 'Kind',
|
||
spritesheet: 'Spritesheet',
|
||
submittedBy: 'By {name}',
|
||
empty: 'No pets match the current filters.',
|
||
showMore: 'Show {count} more',
|
||
summary: {
|
||
total: 'Catalog total',
|
||
visible: 'Matching',
|
||
kinds: 'Kinds',
|
||
generatedAt: 'Generated at',
|
||
},
|
||
},
|
||
|
||
// Memory
|
||
memory: {
|
||
title: 'Memory',
|
||
refresh: 'Refresh',
|
||
loadFailed: 'Failed to load memory',
|
||
myNotes: 'My Notes',
|
||
noNotes: 'No notes yet.',
|
||
notesPlaceholder: 'Write your notes...',
|
||
userProfile: 'User Profile',
|
||
noProfile: 'No profile yet.',
|
||
profilePlaceholder: 'Write your profile...',
|
||
soul: 'Soul',
|
||
noSoul: 'No soul configuration yet.',
|
||
soulPlaceholder: 'Write soul configuration...',
|
||
},
|
||
|
||
// Models
|
||
models: {
|
||
title: 'Models',
|
||
searchPlaceholder: 'Search models...',
|
||
noResults: 'No results',
|
||
noModels: 'No models',
|
||
addProvider: 'Add Provider',
|
||
refreshModelCache: 'Refresh model cache',
|
||
refreshModelCacheLoading: 'Refreshing model cache...',
|
||
refreshModelCacheSuccess: 'Model cache refreshed',
|
||
refreshModelCacheFailed: 'Failed to refresh model cache',
|
||
providerType: 'Provider Type',
|
||
preset: 'Preset',
|
||
custom: 'Custom',
|
||
selectProvider: 'Select Provider',
|
||
chooseProvider: 'Choose a provider...',
|
||
getApiKey: 'Get API Key',
|
||
name: 'Name',
|
||
autoGeneratedName: 'Auto-generated from Base URL',
|
||
baseUrl: 'Base URL',
|
||
region: 'Region',
|
||
regionIntl: 'International',
|
||
regionCn: 'Mainland China',
|
||
baseUrlPlaceholder: 'e.g. https://api.example.com/v1',
|
||
apiKey: 'API Key',
|
||
apiKeyPlaceholder: 'sk-...',
|
||
defaultModel: 'Default Model',
|
||
selectOrInput: 'Select or type a model name...',
|
||
selectModel: 'Select a model...',
|
||
providerAdded: 'Provider added',
|
||
providerDeleted: 'Provider deleted',
|
||
providerCredentialsCleared: 'Provider credentials cleared',
|
||
clearProviderCredentials: 'Clear credentials',
|
||
clearCredentialsConfirm: 'Clear stored credentials for "{name}"? This built-in provider will stay listed and can be used again after credentials are configured.',
|
||
disableProvider: 'Disable provider',
|
||
disableProviderConfirm: 'Disable built-in provider "{name}"? The provider will stay built in and can be enabled again later.',
|
||
providerDisabled: 'Provider disabled',
|
||
defaultProviderUpdated: 'Default provider updated',
|
||
defaultProviderUpdateFailed: 'Failed to update default provider',
|
||
defaultModelUpdated: 'Default model updated',
|
||
defaultModelUpdateFailed: 'Failed to update default model',
|
||
deleteProvider: 'Delete Provider',
|
||
deleteConfirm: 'Are you sure you want to delete "{name}"?',
|
||
codexLoginTitle: 'OpenAI Codex Login',
|
||
codexWaiting: 'Enter this code at the authorization page to complete login:',
|
||
codexCopyCode: 'Code copied',
|
||
codexOpenLink: 'Open authorization page',
|
||
codexApproved: 'Login successful',
|
||
codexExpired: 'Authorization expired. Please try again.',
|
||
nousLoginTitle: 'Nous Portal Login',
|
||
nousWaiting: 'Enter this code at the authorization page to complete login:',
|
||
nousCopyCode: 'Code copied',
|
||
nousOpenLink: 'Open authorization page',
|
||
nousApproved: 'Login successful',
|
||
nousDenied: 'Authorization was denied. Please try again.',
|
||
nousExpired: 'Authorization expired. Please try again.',
|
||
copilotLoginTitle: 'GitHub Copilot Login',
|
||
copilotWaiting: 'Open GitHub and enter the device code below to authorize. The window will close automatically once approved.',
|
||
copilotCopyCode: 'Code copied',
|
||
copilotOpenLink: 'Open GitHub authorization page',
|
||
copilotApproved: 'Sign-in succeeded!',
|
||
copilotDenied: 'Authorization denied.',
|
||
copilotExpired: 'The authorization link has expired. Please retry.',
|
||
copilotAddDetectedTitle: 'GitHub Copilot detected',
|
||
copilotAddDetected: 'A GitHub Copilot OAuth token was detected on this machine. Click Add to enable Copilot in Hermes.',
|
||
copilotAddSourceEnv: 'Source: ~/.hermes/.env (COPILOT_GITHUB_TOKEN)',
|
||
copilotAddSourceGhCli: 'Source: gh CLI (gh auth token)',
|
||
copilotAddSourceAppsJson: 'Source: VS Code Copilot extension (apps.json)',
|
||
copilotDeleteHintEnv: 'This will clear COPILOT_GITHUB_TOKEN in ~/.hermes/.env. Other tools are not affected.',
|
||
copilotDeleteHintGhCli: 'Copilot will be hidden from Hermes. Your gh CLI login is not affected — `gh auth status` will still show you signed in.',
|
||
copilotDeleteHintAppsJson: 'Copilot will be hidden from Hermes. Your VS Code Copilot extension login is not affected.',
|
||
xaiLoginTitle: 'xAI Grok OAuth Login',
|
||
xaiWaiting: 'Complete authorization in the opened xAI page. This window will close automatically once approved.',
|
||
xaiOpenLink: 'Open xAI authorization page',
|
||
xaiCopyLink: 'Copy authorization link',
|
||
xaiApproved: 'Sign-in succeeded!',
|
||
xaiExpired: 'The authorization link has expired. Please retry.',
|
||
anthropicLoginTitle: 'Claude OAuth Login',
|
||
anthropicWaiting: 'Complete authorization on the Claude page, then paste the returned code here.',
|
||
anthropicOpenLink: 'Open Claude authorization page',
|
||
anthropicCopyLink: 'Copy authorization link',
|
||
anthropicCodePlaceholder: 'Paste the authorization code...',
|
||
anthropicSubmitCode: 'Submit code',
|
||
anthropicApproved: 'Sign-in succeeded!',
|
||
anthropicExpired: 'Authorization expired. Please retry.',
|
||
geminiLoginTitle: 'Google Gemini OAuth Login',
|
||
geminiWaiting: 'Complete authorization on the opened Google page. This window will close automatically once approved.',
|
||
geminiOpenLink: 'Open Google authorization page',
|
||
geminiCopyLink: 'Copy authorization link',
|
||
geminiApproved: 'Sign-in succeeded!',
|
||
geminiExpired: 'The authorization link has expired. Please retry.',
|
||
customBadge: 'CUSTOM',
|
||
previewBadge: 'PREVIEW',
|
||
disabledBadge: 'UNAVAILABLE',
|
||
disabledTooltip: "This model is currently unavailable for your account.",
|
||
customModelPlaceholder: 'Unlisted model ID',
|
||
customModelHint: 'For provider-supported models not returned by the API; not a display rename. Press Enter to load.',
|
||
removeCustomModel: 'Remove this unlisted model',
|
||
refresh: 'Refresh model list (reload config.yaml)',
|
||
noProviders: 'No providers found. Add a custom provider to get started.',
|
||
models: 'Models',
|
||
count: 'models',
|
||
more: 'more',
|
||
aliasEdit: 'Rename',
|
||
aliasTitle: 'Model display name',
|
||
aliasTitleFor: 'Display name for {model}',
|
||
aliasPlaceholder: 'Leave empty to use original model ID',
|
||
aliasHint: 'Display-only alias. Hermes still receives the canonical model ID.',
|
||
aliasCanonical: 'Original ID: {model}',
|
||
aliasUseOriginal: 'Use original ID',
|
||
aliasManage: 'Display names',
|
||
aliasManageFor: 'Display names for {provider}',
|
||
aliasSaveFailed: 'Failed to save display name',
|
||
manageVisibleModels: 'Manage visible models',
|
||
manageVisibleModelsFor: 'Manage visible models for {name}',
|
||
visibilityHint: 'Only affects the Web UI model picker and Models page. Hermes CLI provider/model config is not rewritten; calls still use canonical model IDs.',
|
||
visibilitySelectOne: 'Keep at least one visible model',
|
||
visibilitySaved: 'Visible models saved',
|
||
visibilitySaveFailed: 'Failed to save visible models',
|
||
showAllModels: 'Show all models',
|
||
clearVisibleModels: 'Clear selection',
|
||
generalTitle: 'General Models',
|
||
auxiliaryTitle: 'Auxiliary Models',
|
||
auxiliarySubtitle: 'Side-task model overrides for compression, vision, approvals, MCP, and background maintenance.',
|
||
combinationTitle: 'Model Ensembles',
|
||
combinationSubtitle: 'Configure MoA presets: reference models provide perspectives first, then one aggregator model handles the final response and tool calls.',
|
||
combinationPreset: 'Preset',
|
||
combinationName: 'Name',
|
||
combinationAddModel: 'Add model ensemble',
|
||
combinationEditModel: 'Edit model ensemble',
|
||
combinationNewPreset: 'New preset',
|
||
combinationPresetPlaceholder: 'e.g. review',
|
||
combinationAddPreset: 'Add preset',
|
||
combinationSetDefault: 'Set default',
|
||
combinationEnabled: 'Enable references',
|
||
combinationReferenceModels: 'Reference models',
|
||
combinationReferenceModel: 'Reference model',
|
||
combinationAddReference: 'Add reference model',
|
||
combinationAggregator: 'Aggregator model',
|
||
combinationReferenceTemperature: 'Reference temperature',
|
||
combinationAggregatorTemperature: 'Aggregator temperature',
|
||
combinationMaxTokens: 'Max tokens',
|
||
combinationNotSet: 'Not set',
|
||
combinationSaved: 'Model ensemble saved',
|
||
combinationLoadFailed: 'Failed to load model ensemble',
|
||
combinationSaveFailed: 'Failed to save model ensemble',
|
||
combinationPresetExists: 'Preset already exists',
|
||
combinationNameRequired: 'Enter a model ensemble name',
|
||
combinationNameInvalid: 'Name can only contain letters, numbers, underscores, hyphens, and dots',
|
||
combinationReferenceRequired: 'Add at least one reference model',
|
||
combinationAggregatorRequired: 'Select an aggregator model',
|
||
auxiliaryRefresh: 'Refresh',
|
||
auxiliaryTask: 'Task',
|
||
auxiliaryTimeout: 'Timeout',
|
||
auxiliaryDownloadTimeout: 'Download timeout',
|
||
auxiliaryActions: 'Actions',
|
||
auxiliaryDefault: 'Default',
|
||
auxiliaryCustomEndpoint: 'Custom endpoint',
|
||
auxiliaryProviderAuto: 'Auto',
|
||
auxiliaryProviderMain: 'Main model',
|
||
auxiliaryProviderPlaceholder: 'auto, main, or provider key',
|
||
auxiliaryDownloadShort: 'download',
|
||
auxiliaryExtraBody: 'Extra body JSON',
|
||
auxiliaryClear: 'Clear',
|
||
auxiliarySaved: 'Auxiliary models saved',
|
||
auxiliaryLoadFailed: 'Failed to load auxiliary models',
|
||
auxiliarySaveFailed: 'Failed to save auxiliary models',
|
||
auxiliaryInvalidExtraBody: 'Extra body must be a JSON object',
|
||
auxiliaryTaskCompression: 'Compression',
|
||
auxiliaryTaskVision: 'Vision',
|
||
auxiliaryTaskWebExtract: 'Web extract',
|
||
auxiliaryTaskSkillsHub: 'Skills hub',
|
||
auxiliaryTaskApproval: 'Approval',
|
||
auxiliaryTaskMcp: 'MCP',
|
||
auxiliaryTaskTitleGeneration: 'Title generation',
|
||
auxiliaryTaskTriageSpecifier: 'Triage specifier',
|
||
auxiliaryTaskKanbanDecomposer: 'Kanban decomposer',
|
||
auxiliaryTaskProfileDescriber: 'Profile describer',
|
||
auxiliaryTaskCurator: 'Curator',
|
||
auxiliaryTaskSessionSearch: 'Session search',
|
||
auxiliaryTaskFlushMemories: 'Flush memories',
|
||
currentDefault: 'Current default',
|
||
defaultShort: 'Default',
|
||
setDefaultProvider: 'Set default provider',
|
||
setDefault: 'Set default',
|
||
builtIn: 'Built-in',
|
||
customType: 'Custom',
|
||
provider: 'Provider',
|
||
contextLength: 'Context Length',
|
||
contextLengthPlaceholder: 'e.g. 256000 (optional)',
|
||
apiMode: 'API Mode',
|
||
local: 'Local ({host})',
|
||
selectProviderRequired: 'Please select a provider',
|
||
baseUrlRequired: 'Base URL is required',
|
||
apiKeyRequired: 'API Key is required',
|
||
modelRequired: 'Default Model is required',
|
||
enterBaseUrl: 'Please enter Base URL first',
|
||
unexpectedFormat: 'Unexpected response format',
|
||
foundModels: 'Found {count} models',
|
||
fetchFailed: 'Failed to fetch models',
|
||
},
|
||
|
||
// Profiles
|
||
gateways: {
|
||
title: 'Gateways',
|
||
running: 'Running',
|
||
stopped: 'Stopped',
|
||
started: 'Started',
|
||
startFailed: 'Failed to start gateway',
|
||
stopFailed: 'Failed to stop gateway',
|
||
},
|
||
profiles: {
|
||
title: 'Profiles',
|
||
create: 'Create Profile',
|
||
import: 'Import',
|
||
export: 'Export',
|
||
rename: 'Rename',
|
||
delete: 'Delete',
|
||
editConfig: 'Edit Config',
|
||
switchTo: 'Switch Hermes Profile',
|
||
switchConfirm: 'This will run `hermes profile use {name}` and change the active Hermes CLI profile. Continue?',
|
||
switchSuccess: 'Hermes active profile switched to "{name}"',
|
||
switchFailed: 'Failed to switch Hermes profile. Gateway may need manual restart.',
|
||
createSuccess: 'Profile "{name}" created',
|
||
createFailed: 'Failed to create profile',
|
||
renameSuccess: 'Profile renamed',
|
||
renameFailed: 'Failed to rename profile',
|
||
deleteConfirm: 'Are you sure you want to delete profile "{name}"?',
|
||
deleteSuccess: 'Profile deleted',
|
||
deleteFailed: 'Failed to delete profile',
|
||
exportSuccess: 'Profile exported',
|
||
exportFailed: 'Failed to export profile',
|
||
importSuccess: 'Profile imported',
|
||
importFailed: 'Failed to import profile',
|
||
importSelectFile: 'Select archive file',
|
||
importInvalidFile: 'Please select a valid archive (.tar.gz, .tgz, .gz, .zip)',
|
||
name: 'Profile Name',
|
||
namePlaceholder: 'Lowercase letters, numbers, hyphens only',
|
||
nameValidation: 'Profile name can only contain lowercase letters, numbers, underscores, and hyphens',
|
||
newName: 'New Name',
|
||
newNamePlaceholder: 'Lowercase letters, numbers, hyphens',
|
||
cloneFromCurrent: 'Clone from current profile',
|
||
cloneCleanupNotice: 'Cloning automatically skips exclusive platform credentials (Weixin / Telegram / Slack, etc.) to avoid conflicts with the source profile',
|
||
cloneStrippedCredentials: 'Stripped {count} exclusive credential(s): {list}',
|
||
cloneDisabledPlatforms: 'Disabled {count} platform(s): {list}',
|
||
cloneStrippedConfigCredentials: 'Stripped {count} embedded credential(s) from config.yaml: {list}',
|
||
archivePath: 'Archive Path',
|
||
archivePathPlaceholder: 'Server path to archive file',
|
||
importName: 'Profile Name (optional)',
|
||
importNamePlaceholder: 'Leave empty to use archive name',
|
||
active: 'Active',
|
||
model: 'Model',
|
||
gateway: 'Gateway',
|
||
alias: 'Alias',
|
||
provider: 'Provider',
|
||
path: 'Path',
|
||
skills: 'Skills',
|
||
hasEnv: 'Has .env',
|
||
hasSoulMd: 'Has soul.md',
|
||
noProfiles: 'No profiles found. Create one to get started.',
|
||
avatar: {
|
||
title: 'Custom Avatar',
|
||
customize: 'Avatar',
|
||
upload: 'Upload Image',
|
||
random: 'Randomize',
|
||
reset: 'Use Default',
|
||
hint: 'PNG, JPEG, or WebP. Max 1MB.',
|
||
invalidType: 'Please choose a PNG, JPEG, or WebP image',
|
||
tooLarge: 'Avatar image must be 1MB or smaller',
|
||
saveSuccess: 'Avatar saved',
|
||
saveFailed: 'Failed to save avatar',
|
||
resetSuccess: 'Default avatar restored',
|
||
resetFailed: 'Failed to restore default avatar',
|
||
},
|
||
runtime: {
|
||
activeProfile: 'Active: {name}',
|
||
bridgeWorker: 'Bridge worker',
|
||
gateway: 'Gateway',
|
||
active: 'Active',
|
||
activeTag: 'Active',
|
||
idle: 'Idle',
|
||
checking: 'Checking',
|
||
running: 'Running',
|
||
stopped: 'Stopped',
|
||
restartGateway: 'Restart Gateway',
|
||
restartProfile: 'Restart Profile',
|
||
switchProfile: 'Switch Frontend Profile',
|
||
gatewayRestarted: 'Gateway restarted: {name}',
|
||
gatewayRestartFailed: 'Failed to restart gateway',
|
||
profileRestarted: 'Profile restarted: {name}',
|
||
profileRestartFailed: 'Failed to restart profile',
|
||
},
|
||
},
|
||
|
||
// Logs
|
||
logs: {
|
||
title: 'Logs',
|
||
all: 'All',
|
||
searchPlaceholder: 'Search...',
|
||
refresh: 'Refresh',
|
||
noEntries: 'No log entries',
|
||
},
|
||
|
||
// Settings
|
||
settings: {
|
||
title: 'Settings',
|
||
saved: 'Saved',
|
||
saveFailed: 'Save failed',
|
||
tabs: {
|
||
display: 'Display',
|
||
account: 'Current Account',
|
||
users: 'Account Management',
|
||
agent: 'Agent',
|
||
proxy: 'Proxy',
|
||
memory: 'Memory',
|
||
compression: 'Compression',
|
||
session: 'Session',
|
||
privacy: 'Privacy',
|
||
apiServer: 'API Server',
|
||
models: 'Models',
|
||
voice: 'Voice',
|
||
},
|
||
models: {
|
||
apiKey: 'API Key',
|
||
apiKeyPlaceholder: 'Enter API key',
|
||
save: 'Save',
|
||
saved: 'Saved',
|
||
saveFailed: 'Save failed',
|
||
noProviders: 'No providers configured',
|
||
},
|
||
display: {
|
||
streaming: 'Stream Responses',
|
||
streamingHint: 'Show AI replies in real-time',
|
||
compact: 'Compact Mode',
|
||
compactHint: 'Reduce message spacing',
|
||
showReasoning: 'Show Reasoning',
|
||
showReasoningHint: 'Show model thinking process',
|
||
showCost: 'Show Cost',
|
||
showCostHint: 'Show token usage in replies',
|
||
inlineDiffs: 'Inline Diffs',
|
||
inlineDiffsHint: 'Show code changes inline',
|
||
bellOnComplete: 'Completion Sound',
|
||
bellOnCompleteHint: 'Play sound when AI finishes',
|
||
notifyOnComplete: 'Completion Notification',
|
||
notifyOnCompleteHint: 'Show a system notification when AI finishes',
|
||
notifyOnCompleteMacHint: 'On macOS, allow browser notifications in System Settings.',
|
||
notifyOnCompleteDenied: 'Notification permission was denied',
|
||
notifyOnCompleteInsecure: 'Browser notifications require HTTPS or localhost',
|
||
notifyOnCompleteUnsupported: 'This browser does not support notifications',
|
||
notifyOnCompleteTest: 'Notifications are enabled.',
|
||
notifyOnCompleteTestButton: 'Test',
|
||
notifyOnCompleteTesting: 'Sending test notification...',
|
||
notifyOnCompleteTestSent: 'Test notification sent',
|
||
notifyOnCompleteTestFailed: 'Failed to send test notification',
|
||
busyInputMode: 'Busy Input Mode',
|
||
busyInputModeHint: 'Allow input while AI is processing',
|
||
theme: 'Theme',
|
||
themeHint: 'Choose light, dark, or follow system preference',
|
||
themeLight: 'Light',
|
||
themeDark: 'Dark',
|
||
themeSystem: 'System',
|
||
chatInputHeight: 'Chat input height',
|
||
chatInputHeightHint: 'Default desktop chat input height in pixels. Mobile keeps auto height.'
|
||
},
|
||
agent: {
|
||
maxTurns: 'Max Turns',
|
||
maxTurnsHint: 'Maximum interaction rounds per conversation',
|
||
gatewayTimeout: 'Gateway Timeout',
|
||
gatewayTimeoutHint: 'Request timeout in seconds',
|
||
restartDrainTimeout: 'Restart Drain Timeout',
|
||
restartDrainTimeoutHint: 'Drain timeout before restart in seconds',
|
||
toolEnforcement: 'Tool Enforcement',
|
||
toolEnforcementHint: 'Control tool call execution mode',
|
||
auto: 'Auto',
|
||
always: 'Always',
|
||
never: 'Never',
|
||
},
|
||
gatewayAutoStart: {
|
||
title: 'Gateway Auto-Start',
|
||
description: 'Control which local Hermes profile gateways the Web UI starts during startup. This is stored in the Web UI config, not a profile config.yaml.',
|
||
enabled: 'Auto-start gateways',
|
||
enabledHint: 'When disabled, startup will not automatically start any profile gateway.',
|
||
management: 'Unified gateway',
|
||
managementHint: 'Requires Hermes Agent 0.17.0 or later. When enabled, Web UI writes multiplex_profiles so the default gateway serves every profile; other profiles cannot configure separate Feishu, Weixin, QQBot, or similar messaging entrypoints. Turning it off removes that config.',
|
||
managementAuto: 'Auto',
|
||
managementPerProfile: 'One gateway per profile',
|
||
managementUnified: 'Unified default gateway',
|
||
mode: 'Profile policy',
|
||
modeHint: 'Start all discovered profiles or only the explicit include list.',
|
||
modeAll: 'All discovered profiles',
|
||
modeInclude: 'Only included profiles',
|
||
include: 'Included profiles',
|
||
includeHint: 'Comma-separated profile names. In include mode, an empty list starts none.',
|
||
exclude: 'Excluded profiles',
|
||
excludeHint: 'Comma-separated profile names to skip after the include/all policy is applied.',
|
||
profileListPlaceholder: 'default, reviewer',
|
||
},
|
||
proxy: {
|
||
title: 'Gateway Proxy',
|
||
description: 'Set proxy environment variables for the selected profile gateway. Changes restart the gateway so messaging platforms can use the new network settings.',
|
||
httpsProxy: 'HTTPS_PROXY',
|
||
httpsProxyHint: 'Proxy for HTTPS requests. Usually the main value to set.',
|
||
httpProxy: 'HTTP_PROXY',
|
||
httpProxyHint: 'Proxy for plain HTTP requests.',
|
||
allProxy: 'ALL_PROXY',
|
||
allProxyHint: 'Fallback proxy used when a protocol-specific proxy is not set.',
|
||
noProxy: 'NO_PROXY',
|
||
noProxyHint: 'Comma-separated hosts or domains that should bypass the proxy.',
|
||
save: 'Save Proxy Settings',
|
||
},
|
||
memory: {
|
||
enabled: 'Enable Memory',
|
||
enabledHint: 'Allow AI to remember conversation context',
|
||
userProfile: 'User Profile',
|
||
userProfileHint: 'Allow AI to remember user preferences',
|
||
charLimit: 'Memory Char Limit',
|
||
charLimitHint: 'Max characters for MEMORY.md',
|
||
userCharLimit: 'User Profile Char Limit',
|
||
userCharLimitHint: 'Max characters for USER.md',
|
||
},
|
||
compression: {
|
||
enabled: 'Enable Compression',
|
||
enabledHint: 'Automatically compress long chat history before it exceeds the model context',
|
||
threshold: 'Compression Threshold',
|
||
thresholdHint: 'Start compression when estimated tokens exceed this context ratio',
|
||
targetRatio: 'Target Ratio',
|
||
targetRatioHint: 'Target history size after compression as a context ratio',
|
||
protectLastN: 'Protect Recent Messages',
|
||
protectLastNHint: 'Keep this many latest messages uncompressed',
|
||
protectFirstN: 'Protect First Messages',
|
||
protectFirstNHint: 'Keep this many earliest messages uncompressed',
|
||
},
|
||
session: {
|
||
mode: 'Reset Mode',
|
||
modeHint: 'Trigger condition for session reset',
|
||
modeBoth: 'Idle + Scheduled',
|
||
modeIdle: 'Idle Only',
|
||
modeDaily: 'Scheduled Only',
|
||
modeNone: 'Never (Manual Only)',
|
||
idleMinutes: 'Idle Timeout',
|
||
idleMinutesHint: 'Wait time before auto-reset (minutes)',
|
||
atHour: 'Scheduled Reset Time',
|
||
humanOnly: 'Show human sessions only',
|
||
humanOnlyHint: 'Hide sub-agent/session monitor noise by default',
|
||
liveMonitorHumanOnly: 'Live monitor: show human sessions only',
|
||
liveMonitorHumanOnlyHint: 'Hide sub-agent/session monitor noise in the Live monitor by default',
|
||
atHourHint: 'Reset session at this hour daily',
|
||
requireAuth: 'Session Authorization',
|
||
requireAuthHint: 'Require authorization for session operations',
|
||
memoryWriteApproval: 'Review memory writes',
|
||
memoryWriteApprovalHint: 'Stage Hermes Agent memory writes for approval before they are saved.',
|
||
skillsWriteApproval: 'Review skill writes',
|
||
skillsWriteApprovalHint: 'Stage Hermes Agent skill changes for approval before they are saved.',
|
||
writeApprovalTitle: 'Pending write approvals',
|
||
writeApprovalDescription: 'Approve or reject staged Hermes Agent memory and skill writes.',
|
||
writeApprovalRefresh: 'Refresh',
|
||
writeApprovalEmpty: 'No pending writes.',
|
||
writeApprovalMemory: 'Memory',
|
||
writeApprovalSkills: 'Skills',
|
||
writeApprovalViewDiff: 'Review',
|
||
writeApprovalHideDiff: 'Hide',
|
||
writeApprovalNoDiff: 'No diff available.',
|
||
writeApprovalLoadFailed: 'Failed to load pending writes',
|
||
writeApprovalDiffFailed: 'Failed to load write details',
|
||
writeApprovalActionFailed: 'Failed to resolve pending write',
|
||
writeApprovalApproved: 'Pending write approved',
|
||
writeApprovalRejected: 'Pending write rejected',
|
||
writeApprovalApprove: 'Approve',
|
||
writeApprovalReject: 'Reject',
|
||
writeApprovalPendingMemoryWrite: 'Pending memory write',
|
||
writeApprovalCurrentFile: 'Current {file}',
|
||
writeApprovalProposedFile: 'Proposed {file}',
|
||
writeApprovalDiffSection: 'Diff',
|
||
writeApprovalPatchOldStringMissing: 'The patch old_string was not found in the current {file}, so approving it will not change the file.',
|
||
writeApprovalRequestedOldString: 'Requested old_string',
|
||
writeApprovalCurrentReadFailed: 'The current {file} could not be read as UTF-8 text.',
|
||
writeApprovalDeleteSkill: 'This approval deletes skill {skill}.',
|
||
writeApprovalRemoveFile: 'This approval removes {file} from skill {skill}.',
|
||
},
|
||
privacy: {
|
||
redactPii: 'Redact PII',
|
||
redactPiiHint: 'Auto-detect and hide sensitive info (passwords, keys, etc.)',
|
||
},
|
||
apiServer: {
|
||
enable: 'Enable',
|
||
enableHint: 'Enable API server',
|
||
host: 'Host',
|
||
hostHint: 'Listen address',
|
||
port: 'Port',
|
||
portHint: 'Listen port',
|
||
key: 'Key',
|
||
keyHint: 'API access key',
|
||
cors: 'CORS Origins',
|
||
corsHint: 'Allowed cross-origin sources',
|
||
},
|
||
lockedIps: {
|
||
title: 'Locked IPs',
|
||
count: '{count} locked',
|
||
empty: 'No locked IPs',
|
||
unlock: 'Unlock',
|
||
unlockAll: 'Unlock All',
|
||
unlockAllConfirm: 'Unlock all locked IPs?',
|
||
unlocked: 'IP unlocked',
|
||
allUnlocked: '{count} IPs unlocked',
|
||
type: {
|
||
password: 'Password',
|
||
token: 'API token',
|
||
pairing: 'Device pairing',
|
||
},
|
||
},
|
||
userAvatar: {
|
||
title: 'User Avatar',
|
||
upload: 'Upload Image',
|
||
random: 'Generate Random',
|
||
reset: 'Reset to Default',
|
||
hint: 'Supports PNG/JPEG/WebP up to 1MB, auto-compressed to under 500KB',
|
||
invalidType: 'Please choose a PNG, JPEG, or WebP image',
|
||
tooLarge: 'Avatar image must be under 1MB',
|
||
saveSuccess: 'Avatar saved',
|
||
saveFailed: 'Failed to save avatar',
|
||
resetSuccess: 'Avatar reset to default',
|
||
resetFailed: 'Failed to reset avatar',
|
||
},
|
||
voice: {
|
||
activeTtsApi: 'Active TTS API',
|
||
activeSttApi: 'Active STT API',
|
||
ttsProvidersTitle: 'TTS providers',
|
||
ttsProvidersDescription: 'Manage text-to-speech integrations used to play assistant responses and voice previews.',
|
||
sttProvidersTitle: 'STT providers',
|
||
sttProvidersDescription: 'Manage speech-to-text integrations used by the microphone and voice input flow.',
|
||
noneSelected: 'None selected',
|
||
keyStored: 'Stored',
|
||
keyMissing: 'Missing',
|
||
customApi: 'API',
|
||
localBuiltin: 'Local built-in',
|
||
ttsCardHint: 'Speech synthesis provider',
|
||
sttCardHint: 'Speech transcription provider',
|
||
setActive: 'Set active',
|
||
testAction: 'Test',
|
||
connect: 'Connect',
|
||
presetEdgeTtsLabel: 'Edge TTS',
|
||
presetEdgeTtsDescription: 'Free high-quality cloud voices from Microsoft Edge.',
|
||
presetOpenaiTtsLabel: 'OpenAI TTS',
|
||
presetMimoTtsLabel: 'MiMo TTS',
|
||
presetDoubaoTtsLabel: 'Volcengine Doubao TTS',
|
||
presetCustomTtsLabel: 'Custom TTS',
|
||
presetBrowserSttLabel: 'Browser STT',
|
||
presetBrowserSttDescription: 'Native browser speech recognition API.',
|
||
presetOpenaiWhisperLabel: 'OpenAI Whisper',
|
||
presetGroqSttLabel: 'Groq STT',
|
||
presetDoubaoSttLabel: 'Volcengine Doubao STT',
|
||
presetCustomSttLabel: 'Custom STT',
|
||
apiCompatibility: 'API compatibility',
|
||
openaiCompatible: 'OpenAI-compatible',
|
||
manualCustomEndpoint: 'Manual custom endpoint',
|
||
connectionStep: 'Connection',
|
||
discoveryManualHint: 'Manual custom endpoint selected. Model discovery is not available; enter the model name manually.',
|
||
discoveryCredentialHint: 'Enter Base URL and API key, then connect to fetch available models.',
|
||
discoveryNoAutoProbeHint: 'No requests are sent while typing. Use Connect when the credentials are ready.',
|
||
apiKeyConnectPlaceholder: 'Paste API key to connect; stored keys are never shown',
|
||
connectFetchModels: 'Connect & fetch models',
|
||
modelRecommendedSuffix: 'recommended',
|
||
modelConnectManualHint: 'Connect to auto-fill, or enter manually.',
|
||
modelRequiredConnectManual: 'Model is required. Connect to auto-fill, or enter manually.',
|
||
apiKeyRequired: 'API key is required.',
|
||
apiKeyRequiredForDiscovery: 'API key is required to fetch models.',
|
||
baseUrlRequired: 'Base URL is required.',
|
||
baseUrlHttpsRequired: 'Please use http:// or https://.',
|
||
baseUrlInvalid: 'Enter a valid Base URL, including https://.',
|
||
discoveryFailedManualFallback: 'Could not fetch models. You can still enter the model name manually.',
|
||
completeRequiredProviderFields: 'Complete the required provider fields before saving.',
|
||
fetchingModels: 'Fetching models…',
|
||
recommendedModel: 'Recommended: {model}.',
|
||
useRecommendedModel: 'Use this.',
|
||
modelsDiscovered: '{count} models discovered. Recommended model is selected when the field is empty.',
|
||
remove: 'Remove',
|
||
testSuccess: 'Test completed',
|
||
testTextRequired: 'Enter text before testing.',
|
||
keyMissingForTest: 'Add an API key before testing this provider.',
|
||
testing: 'Testing…',
|
||
transcribing: 'Transcribing…',
|
||
browserSttTestHint: 'Browser STT is tested from the chat microphone.',
|
||
sttEmptyAudio: 'No audio was captured. Try again.',
|
||
sttTestSuccess: 'Transcription completed',
|
||
sttRecordingHint: 'Recording… click Stop to transcribe.',
|
||
keepStoredKeyPlaceholder: 'Leave blank to keep the stored key',
|
||
apiKeyPlaceholder: 'Enter API key',
|
||
lastTest: 'Last test',
|
||
notTested: '—',
|
||
recording: 'Recording',
|
||
testFailedShort: 'Failed',
|
||
testFailedSummary: 'Test failed. Check provider settings and try again.',
|
||
showDetails: 'Show details',
|
||
hideDetails: 'Hide details',
|
||
moreActions: 'More',
|
||
moreActionsFor: 'More actions for {provider}',
|
||
addTtsApi: 'Add TTS API',
|
||
addSttApi: 'Add STT API',
|
||
active: 'Active',
|
||
builtin: 'Built-in',
|
||
connected: 'Connected',
|
||
disconnected: 'Disconnected',
|
||
source: 'Source',
|
||
model: 'Model',
|
||
voice: 'Voice',
|
||
doubaoVoiceHint: 'Select a Seed TTS 2.0 voice; the resource field is updated automatically.',
|
||
apiKey: 'API key',
|
||
confirmDeleteSecret: 'Delete the stored API key for this voice API?',
|
||
ttsTitle: 'Text-to-speech',
|
||
ttsSaved: 'TTS settings saved on the server',
|
||
ttsSaveFailed: 'Failed to save TTS settings',
|
||
ttsTestSaved: 'Audition succeeded; TTS settings saved on the server',
|
||
ttsTestSaving: 'Saving TTS settings before audition…',
|
||
ttsMissingBaseUrl: 'Base URL is required before testing. Enter a provider endpoint, then test again.',
|
||
ttsMissingApiKey: 'API key is required before testing. Paste the key, or save a stored server key first.',
|
||
ttsCleared: 'Stored TTS key cleared',
|
||
ttsClearFailed: 'Failed to clear stored TTS key',
|
||
storedBaseUrlsTitle: 'Stored Base URLs',
|
||
storedBaseUrlsHint: 'Saved voice provider endpoints. Field-level inputs only clear the current value; delete saved endpoints here.',
|
||
storedBaseUrlsEmpty: 'No custom voice Base URLs are saved on the server.',
|
||
storedBaseUrlDelete: 'Delete URL',
|
||
storedApiKeysTitle: 'Stored API keys',
|
||
storedApiKeysHint: 'Masked list of server-stored voice API keys. Only provider/source is shown; raw keys are never displayed.',
|
||
storedApiKeysEmpty: 'No voice API keys are stored on the server.',
|
||
storedKeyKindTts: 'TTS',
|
||
storedKeyKindStt: 'STT',
|
||
storedApiKeyMasked: '[stored]',
|
||
storedApiKeyDelete: 'Delete key',
|
||
baseUrlPresetClear: 'Clear URL',
|
||
baseUrlPresetCleared: 'Base URL cleared from the field.',
|
||
baseUrlPresetDelete: 'Delete URL',
|
||
baseUrlPresetDeleted: 'Base URL removed from saved list.',
|
||
baseUrlPresetDeleteFailed: 'Failed to remove saved Base URL.',
|
||
ttsPendingSecret: 'New key will be saved',
|
||
ttsStoredSecret: 'Server has stored key: {value}',
|
||
ttsClearKey: 'Clear stored key',
|
||
sttTitle: 'Speech-to-text',
|
||
sttProvider: 'STT Provider',
|
||
sttProviderHint: 'Choose how voice input is transcribed',
|
||
sttProviderBrowser: 'Browser',
|
||
sttProviderOpenai: 'OpenAI-compatible',
|
||
sttProviderCustom: 'Custom',
|
||
sttBrowserHint: 'Use built-in browser speech recognition when available.',
|
||
sttApiKey: 'API Key',
|
||
sttApiKeyHint: 'Stored server-side for STT providers that require authentication.',
|
||
sttStoredSecret: 'Stored server key: {value}',
|
||
sttPendingSecret: 'Stored server key: will be updated on save',
|
||
sttClearKey: 'Clear stored key',
|
||
sttModel: 'Model',
|
||
sttModelHint: 'Speech-to-text model to use.',
|
||
sttLanguage: 'Language',
|
||
sttLanguageHint: 'Optional language hint such as en or zh.',
|
||
sttPrompt: 'Prompt',
|
||
sttPromptHint: 'Optional transcription prompt.',
|
||
sttAudioTranscode: 'Audio transcoding',
|
||
sttAudioTranscodeNone: 'Send original audio',
|
||
sttAudioTranscodeFfmpeg: 'Convert to WAV with ffmpeg',
|
||
sttBaseUrl: 'Base URL',
|
||
sttBaseUrlHint: 'Custom OpenAI-compatible speech-to-text endpoint.',
|
||
sttSave: 'Save STT settings',
|
||
sttSaved: 'STT settings saved on server.',
|
||
sttSaveFailed: 'Failed to save STT settings.',
|
||
sttCleared: 'Stored STT secret cleared from server.',
|
||
sttClearFailed: 'Failed to clear stored STT secret.',
|
||
sttActiveSaved: 'Active STT provider saved on server.',
|
||
sttSaveActive: 'Save active STT provider',
|
||
sttEndpointHint: 'Final transcription endpoint: {endpoint}',
|
||
sttTestTitle: 'Test speech-to-text',
|
||
sttTestButton: 'Test STT API',
|
||
sttTestStopButton: 'Stop and transcribe',
|
||
sttTestBackendOnly: 'STT API test is available for OpenAI-compatible and Custom providers.',
|
||
sttTestRecording: 'Recording test sample… click Stop and transcribe when done.',
|
||
sttTestTranscribing: 'Transcribing test sample…',
|
||
sttTestEmpty: 'No audio was captured for the STT test.',
|
||
sttTestSucceeded: 'STT test succeeded.',
|
||
sttTestFailed: 'STT test failed: {error} — {hint}',
|
||
|
||
sttFailureHintMissingConfig: 'Check that the provider is saved with a base URL/model and an API key before testing.',
|
||
|
||
sttFailureHintAuth: 'Check the API key. If a key was already stored, paste the current key again and save before testing.',
|
||
|
||
sttFailureHintForbidden: 'The key reached the provider but does not have permission for this STT model or account. Check provider access/billing.',
|
||
|
||
sttFailureHintEndpointModel: 'Check the Base URL and model. For Groq, use {endpoint} with whisper-large-v3-turbo or another Groq STT model.',
|
||
|
||
sttFailureHintModel: 'Check that the selected STT model exists and is enabled for this account.',
|
||
|
||
sttFailureHintQuota: 'The provider reports quota, billing, or rate-limit trouble. Check account quota/billing or retry later.',
|
||
|
||
sttFailureHintNetworkCustom: 'The server could not reach the custom STT endpoint. Check that {endpoint} is reachable from the Web UI server and is OpenAI-compatible.',
|
||
|
||
sttFailureHintNetwork: 'The Web UI server could not reach the STT provider. Check network/proxy/firewall and retry.',
|
||
|
||
sttFailureHintAudio: 'The recorded audio was empty or rejected. Try a short clear sample, allow microphone access, or retry in Chrome.',
|
||
|
||
sttFailureHintGenericCustom: 'Check API key, Base URL, model, and the final endpoint {endpoint}.',
|
||
|
||
sttFailureHintGeneric: 'Check API key, model, and provider account access, then retry.',
|
||
sttTestRecordFailed: 'Could not start microphone recording: {error}',
|
||
sttTestTranscript: 'Transcript: {text}',
|
||
ttsProvider: 'TTS Provider',
|
||
ttsProviderHint: 'Choose the text-to-speech engine for message playback',
|
||
providerWebSpeech: 'WebSpeech API (Browser)',
|
||
providerOpenai: 'OpenAI TTS',
|
||
providerCustom: 'Custom Endpoint (OpenAI-compatible)',
|
||
providerEdge: 'Edge TTS (Free, no API Key)',
|
||
|
||
// WebSpeech
|
||
webspeechVoice: 'Voice',
|
||
webspeechVoiceHint: 'Select a voice from your browser or OS',
|
||
webspeechVoicePlaceholder: 'Auto (default voice)',
|
||
|
||
// OpenAI
|
||
openaiKey: 'API Key',
|
||
openaiKeyHint: 'Your OpenAI API key with TTS access',
|
||
openaiUrl: 'API Base URL',
|
||
openaiUrlHint: 'e.g. https://api.openai.com/v1/audio/speech',
|
||
openaiModel: 'Model',
|
||
openaiModelHint: 'tts-1 (faster) / tts-1-hd (higher quality)',
|
||
openaiVoice: 'Voice',
|
||
openaiVoiceHint: 'Voice to use for synthesis',
|
||
|
||
// Custom endpoint
|
||
customHint: 'Use any OpenAI-compatible TTS API — works with GPT-SoVITS, CosyVoice, etc.',
|
||
customUrl: 'API URL',
|
||
customUrlHint: 'Base URL of your TTS service',
|
||
customUrlPlaceholder: 'The address configured in the local adapter, e.g. http://127.0.0.1:9880',
|
||
customApiKey: 'API Key (Optional)',
|
||
customApiKeyHint: 'Some custom endpoints require authentication',
|
||
customApiKeyPlaceholder: 'Leave blank if not needed',
|
||
// Edge TTS
|
||
edgeHint: 'Powered by Microsoft Edge TTS (node-edge-tts).',
|
||
edgeUrl: 'Adapter URL',
|
||
edgeUrlHint: 'Address of your Edge TTS adapter, e.g. http://127.0.0.1:9882',
|
||
edgeUrlPlaceholder: 'http://127.0.0.1:9882',
|
||
edgeVoice: 'Voice',
|
||
edgeVoiceHint: 'Select a voice for speech synthesis',
|
||
edgeRate: 'Speed',
|
||
edgeRateHint: 'Adjust speech speed (0.5x ~ 2.0x)',
|
||
edgePitch: 'Pitch',
|
||
edgePitchHint: 'Adjust speech pitch (-20 ~ +20 Hz)',
|
||
|
||
// Test
|
||
testTitle: 'Test Voice',
|
||
testText: 'Test Text',
|
||
testTextPlaceholder: 'Enter text to test...',
|
||
testTextDefault: 'Hello, this is a voice test.',
|
||
testButton: 'Test',
|
||
testButtonPlaying: 'Playing...',
|
||
testFailed: 'Test failed: {error}',
|
||
|
||
// MiMo TTS
|
||
providerMimo: 'MiMo TTS',
|
||
mimoHint: 'Xiaomi MiMo TTS — supports preset voices, voice design, and voice clone modes',
|
||
mimoApiKey: 'API Key',
|
||
mimoApiKeyHint: 'Get your key at platform.xiaomimimo.com',
|
||
mimoApiKeyPlaceholder: 'MiMo API Key',
|
||
mimoAuthMode: 'Authentication Mode',
|
||
mimoAuthModeHint: 'Header format expected by the selected MiMo endpoint',
|
||
mimoAuthModeBearer: 'Bearer token (Authorization)',
|
||
mimoAuthModeApiKey: 'API key header (api-key)',
|
||
mimoAuthModeBoth: 'Both headers',
|
||
mimoBaseUrl: 'Base URL',
|
||
mimoBaseUrlHint: 'MiMo API endpoint URL',
|
||
mimoModel: 'Model',
|
||
mimoModelHint: 'Select speech synthesis model',
|
||
mimoModelPreset: 'Preset Voices',
|
||
mimoModelVoiceDesign: 'Voice Design',
|
||
mimoModelVoiceClone: 'Voice Clone',
|
||
mimoVoice: 'Voice',
|
||
mimoVoiceHint: 'Select a preset voice',
|
||
mimoVoiceDesignPrompt: 'Voice Description',
|
||
mimoVoiceDesignPromptHint: 'Describe the voice characteristics you want',
|
||
mimoVoiceDesignPromptPlaceholder: 'e.g., A warm young female voice, slightly slow, with a magnetic tone',
|
||
mimoCloneAudio: 'Upload Audio',
|
||
mimoCloneAudioHint: 'Upload an audio sample for voice cloning (mp3/wav, max 10MB)',
|
||
mimoCloneAudioUpload: 'Choose File',
|
||
mimoCloneAudioClear: 'Clear',
|
||
mimoStylePrompt: 'Style Prompt',
|
||
mimoStylePromptHint: 'Optional — describe the speaking style in natural language',
|
||
mimoStylePromptPlaceholder: 'e.g., Bright and bouncy tone, fast pace',
|
||
},
|
||
},
|
||
githubPreview: {
|
||
title: "Version Preview",
|
||
description: "Clone a selected GitHub tag into the Web UI preview workspace, install dependencies, and run it with the development ports.",
|
||
refresh: "Refresh",
|
||
selectTag: "Select a tag",
|
||
prepare: "Prepare Code",
|
||
install: "Install Dependencies",
|
||
start: "Start Preview",
|
||
stop: "Stop",
|
||
note: "Preview code is stored under the Web UI data home. Production remains on port 8648; preview development runs on frontend 8651 and backend 8650.",
|
||
path: "Preview Path",
|
||
webuiHome: "Preview Data Home",
|
||
currentTag: "Current Tag",
|
||
repoReady: "Repository Ready",
|
||
dependencies: "Dependencies Installed",
|
||
running: "Running",
|
||
notRunning: "Not running",
|
||
open: "Open Preview",
|
||
log: "Action Log Path",
|
||
logOutput: "Log Output",
|
||
actionLog: "Action Log",
|
||
devLog: "Dev Server Log",
|
||
yes: "Yes",
|
||
no: "No",
|
||
actionFailed: "Action failed",
|
||
nodeEnvironmentMissing: "Node/npm was not detected. Please install Node.js and try again.",
|
||
prepareSuccess: "Preview code is ready",
|
||
installSuccess: "Dependencies installed",
|
||
startSuccess: "Preview completed",
|
||
stopSuccess: "Preview stopped",
|
||
},
|
||
|
||
// Platform channel settings
|
||
platform: {
|
||
requireMention: "Require {'@'}Mention",
|
||
requireMentionGroup: "Require {'@'}mention in groups to respond",
|
||
requireMentionChannel: "Require {'@'}mention in channels to respond",
|
||
requireMentionRoom: "Require {'@'}mention in rooms to respond",
|
||
reactions: 'Reactions',
|
||
reactionsHint: 'React to messages with emoji',
|
||
freeResponseChats: 'Free Response Chats',
|
||
freeResponseChatsHint: "Chat IDs that respond without {'@'}mention (comma-separated)",
|
||
freeResponseChannels: 'Free Response Channels',
|
||
freeResponseChannelsHint: "Channel IDs that respond without {'@'}mention (comma-separated)",
|
||
freeResponseRooms: 'Free Response Rooms',
|
||
freeResponseRoomsHint: "Room IDs that respond without {'@'}mention (comma-separated)",
|
||
mentionPatterns: 'Custom Mention Patterns',
|
||
mentionPatternsHint: 'Additional trigger patterns',
|
||
autoThread: 'Auto Thread',
|
||
autoThreadHint: "Auto-create reply threads after {'@'}mention",
|
||
autoThreadHintRoom: 'Auto-create reply threads in rooms',
|
||
dmMentionThreads: 'DM Mention Threads',
|
||
dmMentionThreadsHint: 'Use thread replies for mentions in DMs',
|
||
allowBots: 'Allow Bot Messages',
|
||
allowBotsHint: 'Respond to messages from other bots',
|
||
allowedChannels: 'Allowed Channels',
|
||
allowedChannelsHint: 'Whitelist channel IDs (comma-separated)',
|
||
ignoredChannels: 'Ignored Channels',
|
||
ignoredChannelsHint: 'Channels where bot never responds (comma-separated)',
|
||
noThreadChannels: 'No-Thread Channels',
|
||
noThreadChannelsHint: 'Channels where bot responds without threads (comma-separated)',
|
||
exclusiveTokenWarning: 'This platform uses exclusive token locking. Each profile must use a different identity token to avoid conflicts with other profiles.',
|
||
botToken: 'Bot Token',
|
||
botTokenHint: 'Bot token from developer portal',
|
||
proxyUrl: 'Proxy URL',
|
||
proxyUrlHint: 'Optional platform proxy. Supports http://, https://, and socks5://',
|
||
accessToken: 'Access Token',
|
||
accessTokenHint: 'Matrix access token',
|
||
homeserver: 'Homeserver URL',
|
||
homeserverHint: 'Matrix homeserver URL',
|
||
matrixUserId: 'Matrix User ID',
|
||
matrixUserIdHint: 'Required with password login; optional with access token',
|
||
matrixPassword: 'Matrix Password',
|
||
matrixPasswordHint: 'Alternative to an access token',
|
||
appId: 'App ID',
|
||
appIdHint: 'Feishu App ID',
|
||
appSecret: 'App Secret',
|
||
appSecretHint: 'Feishu App Secret',
|
||
encryptKey: 'Encrypt Key',
|
||
encryptKeyHint: 'Feishu Encrypt Key',
|
||
verificationToken: 'Verification Token',
|
||
verificationTokenHint: 'Feishu Verification Token',
|
||
clientId: 'Client ID',
|
||
clientIdHint: 'DingTalk Client ID',
|
||
clientSecret: 'Client Secret',
|
||
clientSecretHint: 'DingTalk Client Secret',
|
||
cardTemplateId: 'AI Card Template ID',
|
||
cardTemplateIdHint: 'DingTalk AI Card template ID; leave empty to disable AI Cards',
|
||
allowedUsers: 'Allowed Users',
|
||
allowedUsersHint: 'Whitelist user IDs or OpenIDs (comma-separated)',
|
||
allowAllUsers: 'Allow All Users',
|
||
allowAllUsersHint: 'Allow messages from any user; keep off to use the allowlist',
|
||
botId: 'Bot ID',
|
||
botIdHint: 'WeCom Bot ID',
|
||
wecomSecretHint: 'WeCom Bot Secret',
|
||
waEnabled: 'Enable WhatsApp',
|
||
waEnabledHint: 'Enable WhatsApp via QR code pairing',
|
||
weixinToken: 'Weixin Token',
|
||
weixinTokenHint: 'From weixin CLI QR login (hermes weixin)',
|
||
accountId: 'Account ID',
|
||
accountIdHint: 'Weixin account ID',
|
||
qrLogin: 'QR Login',
|
||
qrRelogin: 'Re-login',
|
||
qrFetching: 'Fetching QR code...',
|
||
qrScanHint: 'Scan with WeChat to login',
|
||
qrScanedHint: 'Scaned, please confirm on phone...',
|
||
// QQ
|
||
qqAppId: 'App ID',
|
||
qqAppIdHint: 'QQ Open Platform Bot App ID',
|
||
qqAppSecret: 'App Secret',
|
||
qqAppSecretHint: 'QQ Open Platform Bot App Secret',
|
||
qqMarkdown: 'Markdown Support',
|
||
qqMarkdownHint: 'Enable Markdown formatted messages (some clients may not support)',
|
||
qqSandbox: 'Sandbox Mode',
|
||
qqSandboxHint: 'Enable sandbox environment (for testing)',
|
||
qqQrScanHint: 'Scan the QR code with QQ, or open the link on your phone to complete binding',
|
||
},
|
||
|
||
// Language
|
||
language: {
|
||
label: 'Language',
|
||
zh: '中文',
|
||
en: 'English',
|
||
},
|
||
|
||
// Terminal
|
||
terminal: {
|
||
sessions: 'Sessions',
|
||
newTab: 'New Terminal',
|
||
closeSession: 'Close this session?',
|
||
sessionExited: 'Exited',
|
||
processExited: 'Process exited with code {code}',
|
||
noSessions: 'No terminal sessions',
|
||
connectionFailed: 'Terminal service connection failed',
|
||
connectionClosed: 'Terminal connection closed',
|
||
connectionError: 'Terminal connection error',
|
||
},
|
||
|
||
// Group Chat
|
||
groupChat: {
|
||
title: 'Group Chat',
|
||
createRoom: 'Create Room',
|
||
joinByCode: 'Join by Code',
|
||
roomName: 'Room Name',
|
||
roomNamePlaceholder: 'Enter room name',
|
||
inviteCode: 'Invite Code',
|
||
autoGenerate: 'Auto-generate',
|
||
noRooms: 'No rooms yet',
|
||
selectOrCreate: 'Select or create a room to start chatting',
|
||
agents: 'Agents',
|
||
addAgent: 'Add Agent',
|
||
selectProfile: 'Select a profile',
|
||
agentAdded: 'Agent added',
|
||
selectRoomFirst: 'Please select a room first',
|
||
agentAlreadyInRoom: 'Agent already in this room',
|
||
agentAddFailedCount: '{count} agent(s) were not added: {details}',
|
||
noAgents: 'No agents in this room',
|
||
members: 'members',
|
||
roomCreated: 'Room created',
|
||
roomDeleted: 'Room deleted',
|
||
roomCloned: 'Room cloned',
|
||
cloneRoom: 'Clone room',
|
||
copyRoomLink: 'Copy Room Link',
|
||
deleteRoomConfirm: 'Delete this room?',
|
||
clearContext: 'Clear context',
|
||
clearContextConfirm: 'Clear this room context? Messages and compression snapshots will be removed, but agents and members stay.',
|
||
contextCleared: 'Context cleared',
|
||
you: 'You',
|
||
joined: 'Joined room',
|
||
joinFailed: 'Failed to join room',
|
||
inputPlaceholder: 'Type a message... (Enter to send)',
|
||
messageDisplayLimit: 'Group chat displays up to 600 messages',
|
||
enterCode: 'Enter invite code',
|
||
yourName: 'Your Name',
|
||
yourNamePlaceholder: 'Enter your display name',
|
||
yourDescription: 'Description (optional)',
|
||
yourDescriptionPlaceholder: 'Tell others who you are...',
|
||
agentName: 'Agent Name',
|
||
agentNamePlaceholder: 'Custom name (leave empty to use profile name)',
|
||
agentDesc: 'Agent Description',
|
||
agentDescPlaceholder: 'Describe what this agent does...',
|
||
agentReplying: 'is replying...',
|
||
agentCompressing: 'is compressing context...',
|
||
compressionSettings: 'Compression Settings',
|
||
triggerTokens: 'Trigger Tokens',
|
||
triggerTokensDesc: 'Token threshold to trigger context compression',
|
||
maxHistoryTokens: 'Max History Tokens',
|
||
maxHistoryTokensDesc: 'Maximum tokens for compressed context sent to LLM',
|
||
tailMessageCount: 'Tail Message Count',
|
||
tailMessageCountDesc: 'Number of recent messages to keep verbatim after compression',
|
||
compressionConfig: 'Compression Config',
|
||
compressionSaved: 'Compression config saved',
|
||
compressNow: 'Compress Now',
|
||
compressingInProgress: 'Compression in progress, please wait',
|
||
},
|
||
|
||
// Usage
|
||
usage: {
|
||
title: 'Usage Statistics',
|
||
refresh: 'Refresh',
|
||
totalTokens: 'Total Tokens',
|
||
inputTokens: 'Input',
|
||
outputTokens: 'Output',
|
||
totalSessions: 'Total Sessions',
|
||
avgPerDay: '~{n}/day avg',
|
||
estimatedCost: 'Est. Cost',
|
||
cacheHitRate: 'Cache Hit Rate',
|
||
modelBreakdown: 'Model Breakdown',
|
||
agentBreakdown: 'Agent Breakdown',
|
||
agents: { hermes: 'Hermes Agent', unknown: 'Unknown' },
|
||
dailyTrend: 'Daily Usage',
|
||
date: 'Date',
|
||
tokens: 'Tokens',
|
||
cache: 'Cache',
|
||
cacheRead: 'Cache Read',
|
||
cacheWrite: 'Cache Write',
|
||
sessions: 'Sessions',
|
||
cost: 'Cost',
|
||
noData: 'No usage data',
|
||
},
|
||
skillsUsage: {
|
||
title: 'Skills Usage',
|
||
subtitle: 'Track skill loads and edits from Hermes sessions',
|
||
refresh: 'Refresh',
|
||
periodSelector: 'Skill usage period',
|
||
periodLabel: '{days}d',
|
||
summary: 'Summary',
|
||
totalActions: 'Actions',
|
||
loads: 'Loads',
|
||
edits: 'Edits',
|
||
distinctSkills: 'Skills',
|
||
topSkills: 'Top Skills',
|
||
dailyTrend: 'Daily Trend',
|
||
periodSummary: 'Last {days} days',
|
||
skill: 'Skill',
|
||
share: 'Share',
|
||
lastUsed: 'Last Used',
|
||
noData: 'No skill usage data',
|
||
loadFailed: 'Failed to load skill usage',
|
||
otherSkills: 'Other skills',
|
||
},
|
||
|
||
// Files
|
||
files: {
|
||
title: 'Files',
|
||
fileTree: 'File Tree',
|
||
tree: 'Directory Tree',
|
||
list: 'File List',
|
||
breadcrumbRoot: 'Home',
|
||
newFile: 'New File',
|
||
newFolder: 'New Folder',
|
||
upload: 'Upload',
|
||
refresh: 'Refresh',
|
||
open: 'Open',
|
||
edit: 'Edit',
|
||
preview: 'Preview',
|
||
download: 'Download',
|
||
copyPath: 'Copy Path',
|
||
rename: 'Rename',
|
||
delete: 'Delete',
|
||
name: 'Name',
|
||
size: 'Size',
|
||
modified: 'Modified',
|
||
actions: 'Actions',
|
||
emptyDir: 'Empty directory',
|
||
loading: 'Loading...',
|
||
confirmDelete: 'Are you sure you want to delete "{name}"?',
|
||
confirmDeleteDir: 'Are you sure you want to delete directory "{name}" and all its contents?',
|
||
deleteFailed: 'Delete failed',
|
||
deleted: 'Deleted',
|
||
renameTo: 'Rename to',
|
||
newFileName: 'File name',
|
||
newFolderName: 'Folder name',
|
||
created: 'Created',
|
||
createFailed: 'Create failed',
|
||
renamed: 'Renamed',
|
||
renameFailed: 'Rename failed',
|
||
uploadSuccess: 'Uploaded {count} file(s)',
|
||
uploadFailed: 'Upload failed',
|
||
saveFailed: 'Save failed',
|
||
saved: 'Saved',
|
||
unsavedChanges: 'You have unsaved changes. Discard?',
|
||
pathCopied: 'Path copied',
|
||
fileTooLarge: 'File too large (max 10MB)',
|
||
permissionDenied: 'Cannot modify protected file',
|
||
notFound: 'File or directory not found',
|
||
backendError: 'File operation failed',
|
||
dragDropHint: 'Drag files here to upload',
|
||
closeEditor: 'Close Editor',
|
||
closePreview: 'Close',
|
||
saveFile: 'Save',
|
||
},
|
||
// Download
|
||
download: {
|
||
downloading: 'Downloading...',
|
||
downloadFailed: 'Download failed',
|
||
fileNotFound: 'File not found or deleted',
|
||
fileTooLarge: 'File too large (exceeds limit)',
|
||
backendError: 'File read failed, remote environment may be unavailable',
|
||
backendTimeout: 'File read timed out',
|
||
unsupportedBackend: 'Current terminal backend does not support file download',
|
||
invalidPath: 'Invalid file path',
|
||
contentDisplay: 'Content display',
|
||
download: 'Download',
|
||
downloadFile: 'Download file',
|
||
},
|
||
|
||
// Changelog
|
||
changelog: {
|
||
new_0_6_29_9: 'The project is now hermes-ui: the Electron desktop app, marketing site, and ESP32 firmware are removed, leaving only the web client and server',
|
||
new_0_6_29_10: 'UI branding is unified under hermes-ui, and locales are consolidated to Simplified Chinese and English',
|
||
},
|
||
}
|