Files
Hermes-ui/src/i18n/locales/en.ts
T
ekko 9dd5fca9f9 feat: add usage statistics page, CLI improvements, and UI enhancements
- Add Usage Stats page with token breakdown, model distribution, and 30-day trend
- Pass through cache/cost token fields in BFF (cache_read/write_tokens, reasoning_tokens, actual_cost_usd)
- Add CLI commands: -v/--version, -h/--help, update/upgrade with auto-restart
- Auto-open browser on startup, auto-kill port conflicts (cross-platform)
- Validate all api_server config fields on startup (enabled, host, port, key, cors_origins)
- Add streaming thinking video animation with tool calls panel
- Add context token usage display (used / total) in chat header
- Sidebar: white logo area with shadow, dance video beside logo (canvas seamless loop)
- Fix sidebar nav scroll (app-main overflow-y: auto)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 14:48:58 +08:00

364 lines
11 KiB
TypeScript

export default {
// Common
common: {
loading: 'Loading...',
cancel: 'Cancel',
delete: 'Delete',
edit: 'Edit',
save: 'Save',
saved: 'Saved',
update: 'Update',
create: 'Create',
saveFailed: 'Save failed',
ok: 'OK',
copied: 'Copied',
copy: 'Copy',
noData: 'No data',
fetch: 'Fetch',
add: 'Add',
enable: 'Enable',
disable: 'Disable',
configured: 'Configured',
notConfigured: 'Not configured',
},
// Sidebar
sidebar: {
chat: 'Chat',
jobs: 'Jobs',
models: 'Models',
skills: 'Skills',
memory: 'Memory',
logs: 'Logs',
usage: 'Usage',
channels: 'Channels',
settings: 'Settings',
connected: 'Connected',
disconnected: 'Disconnected',
},
// Chat
chat: {
emptyState: 'Start a conversation with Hermes Agent',
inputPlaceholder: 'Type a message... (Enter to send, Shift+Enter for new line)',
attachFiles: 'Attach files',
stop: 'Stop',
send: 'Send',
contextUsed: 'Context used:',
sessions: 'Sessions',
noSessions: 'No sessions',
newChat: 'New Chat',
deleteSession: 'Delete this session?',
sessionDeleted: 'Session deleted',
rename: 'Rename',
copySessionId: 'Copy Session ID',
renamed: 'Renamed',
renameFailed: 'Rename failed',
renameSession: 'Rename Session',
enterNewTitle: 'Enter new title',
other: 'Other',
runFailed: 'Run failed',
tool: 'Tool',
error: 'error',
arguments: 'Arguments',
result: 'Result',
truncated: '... (truncated)',
},
// Jobs
jobs: {
title: 'Scheduled Jobs',
createJob: 'Create Job',
editJob: 'Edit Job',
noJobs: 'No scheduled jobs yet. Create one to get started.',
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',
deliverTarget: 'Deliver Target',
origin: 'Origin',
local: 'Local',
repeatCount: 'Repeat Count (optional)',
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',
jobDeleted: 'Job deleted',
status: {
running: 'Running',
paused: 'Paused',
disabled: 'Disabled',
scheduled: 'Scheduled',
},
info: {
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',
},
},
// Skills
skills: {
title: 'Skills',
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',
},
// 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...',
},
// Models
models: {
title: 'Models',
addProvider: 'Add Provider',
providerType: 'Provider Type',
preset: 'Preset',
custom: 'Custom',
selectProvider: 'Select Provider',
chooseProvider: 'Choose a provider...',
name: 'Name',
autoGeneratedName: 'Auto-generated from Base URL',
baseUrl: 'Base URL',
baseUrlPlaceholder: 'e.g. https://api.example.com/v1',
apiKey: 'API Key',
apiKeyPlaceholder: 'sk-...',
defaultModel: 'Default Model',
selectModel: 'Select a model...',
providerAdded: 'Provider added',
providerDeleted: 'Provider deleted',
deleteProvider: 'Delete Provider',
deleteConfirm: 'Are you sure you want to delete "{name}"?',
noProviders: 'No providers found. Add a custom provider to get started.',
builtIn: 'Built-in',
customType: 'Custom',
provider: 'Provider',
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',
},
// 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',
agent: 'Agent',
memory: 'Memory',
session: 'Session',
privacy: 'Privacy',
apiServer: 'API Server',
},
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',
busyInputMode: 'Busy Input Mode',
busyInputModeHint: 'Allow input while AI is processing',
},
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',
},
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',
},
session: {
mode: 'Reset Mode',
modeHint: 'Trigger condition for session reset',
modeBoth: 'Idle + Scheduled',
modeIdle: 'Idle Only',
modeHourly: 'Scheduled Only',
idleMinutes: 'Idle Timeout',
idleMinutesHint: 'Wait time before auto-reset (minutes)',
atHour: 'Scheduled Reset Time',
atHourHint: 'Reset session at this hour daily',
},
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',
},
},
// 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)',
botToken: 'Bot Token',
botTokenHint: 'Bot token from developer portal',
accessToken: 'Access Token',
accessTokenHint: 'Matrix access token',
homeserver: 'Homeserver URL',
homeserverHint: 'Matrix homeserver URL',
appId: 'App ID',
appIdHint: 'Feishu App ID',
appSecret: 'App Secret',
appSecretHint: 'Feishu App Secret',
clientId: 'Client ID',
clientIdHint: 'DingTalk Client ID',
clientSecret: 'Client Secret',
clientSecretHint: 'DingTalk Client Secret',
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...',
},
// Language
language: {
label: 'Language',
zh: '中文',
en: 'English',
},
// 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',
dailyTrend: 'Daily Usage (Last 30 Days)',
date: 'Date',
tokens: 'Tokens',
cache: 'Cache',
sessions: 'Sessions',
cost: 'Cost',
noData: 'No usage data',
},
}