Files
hermes-ui/packages/client/src/i18n/locales/en.ts
T
toor 8c1ddf415f Phase 003: remove the coding-agent and ekko-agent runtimes
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
2026-10-16 13:27:50 +08:00

2352 lines
90 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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',
},
}