mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-16 04:18:17 +08:00
3343 lines
139 KiB
TypeScript
3343 lines
139 KiB
TypeScript
export default {
|
||
app: {
|
||
title: 'MateClaw - AI Assistant',
|
||
},
|
||
common: {
|
||
save: 'Save',
|
||
saving: 'Saving...',
|
||
saved: 'Saved',
|
||
cancel: 'Cancel',
|
||
reset: 'Reset',
|
||
edit: 'Edit',
|
||
delete: 'Delete',
|
||
create: 'Create',
|
||
update: 'Update',
|
||
loading: 'Loading...',
|
||
enabled: 'Enabled',
|
||
disabled: 'Disabled',
|
||
default: 'Default',
|
||
view: 'View',
|
||
copy: 'Copy',
|
||
copied: 'Copied',
|
||
copyFailed: 'Copy failed',
|
||
confirm: 'Confirm',
|
||
close: 'Close',
|
||
add: 'Add',
|
||
search: 'Search',
|
||
noResults: 'No matches',
|
||
noOptions: 'No options',
|
||
clear: 'Clear',
|
||
expandSidebar: 'Expand sidebar',
|
||
collapseSidebar: 'Collapse sidebar',
|
||
manageWorkspaces: 'Manage Workspaces',
|
||
show: 'Show',
|
||
hide: 'Hide',
|
||
on: 'On',
|
||
off: 'Off',
|
||
yes: 'Yes',
|
||
no: 'No',
|
||
configure: 'Configure',
|
||
refresh: 'Refresh',
|
||
collapse: 'Collapse',
|
||
enable: 'Enable',
|
||
disable: 'Disable',
|
||
pager: {
|
||
total: '{n} total',
|
||
perPage: '{n}/page',
|
||
prev: 'Previous',
|
||
next: 'Next',
|
||
jumpTo: 'Go to',
|
||
pageSuffix: '',
|
||
},
|
||
iconPicker: {
|
||
title: 'Pick an icon',
|
||
tabPixelart: 'Pixelart',
|
||
tabEmoji: 'Emoji',
|
||
tabUrl: 'Image URL',
|
||
search: 'Search by name…',
|
||
empty: 'No icons match',
|
||
preview: 'Preview',
|
||
none: 'No icon',
|
||
apply: 'Apply',
|
||
emojiHint: 'Type or paste any emoji / text glyph.',
|
||
emojiPlaceholder: '🎬 / 📊 / any symbol',
|
||
urlHint: 'Use a hosted image (PNG / SVG / JPG) as the icon.',
|
||
urlPlaceholder: 'https://example.com/icon.svg',
|
||
pixelartCount: '{n} pixelart icons by pixelarticons (MIT)',
|
||
pickerOpen: 'Open icon picker',
|
||
reprojectionWarning: 'Heads up: if SKILL.md frontmatter declares `icon`, your override will be overwritten on next resolve — edit the body to make it permanent.',
|
||
},
|
||
},
|
||
auth: {
|
||
changePassword: 'Change Password',
|
||
oldPassword: 'Current Password',
|
||
newPassword: 'New Password',
|
||
confirmPassword: 'Confirm New Password',
|
||
fieldsRequired: 'Please enter current and new password',
|
||
passwordMismatch: 'New passwords do not match',
|
||
passwordChanged: 'Password changed successfully',
|
||
passwordChangeFailed: 'Failed to change password',
|
||
},
|
||
chat: {
|
||
status: {
|
||
idle: 'Ready',
|
||
streaming: 'Generating...',
|
||
error: 'Disconnected',
|
||
},
|
||
thinking: 'Thinking',
|
||
thinkingInProgress: 'Thinking...',
|
||
stopped: 'Generation stopped',
|
||
interrupted: 'Interrupted',
|
||
expandLines: 'Show more ({hidden} more lines)',
|
||
collapse: 'Show less',
|
||
failed: 'Generation failed',
|
||
compressionSummary: 'Previous conversations summarized',
|
||
compressionWithCount: '{count} previous messages summarized',
|
||
loadingOlder: 'Loading older messages...',
|
||
loadOlderMessages: 'Click to load older messages',
|
||
retry: 'Retry',
|
||
errorCode: 'Error code',
|
||
error: {
|
||
rate_limit: {
|
||
title: 'Too many requests',
|
||
description: 'You\'ve exceeded the rate limit. The server is temporarily unable to process your request.',
|
||
action: 'Please wait a moment before retrying, or reduce consecutive submissions.',
|
||
},
|
||
auth_expired: {
|
||
title: 'Session expired',
|
||
description: 'Your login session has expired and you need to sign in again.',
|
||
action: 'You will be redirected to the login page.',
|
||
},
|
||
provider_auth_error: {
|
||
title: 'Model authentication failed',
|
||
description: 'The current model\'s API key is invalid or has expired. This is unrelated to your login session.',
|
||
action: 'Open Settings → Models to check and update the API key.',
|
||
},
|
||
forbidden: {
|
||
title: 'Access denied',
|
||
description: 'You don\'t have permission to perform this action.',
|
||
action: 'Please contact the administrator for access.',
|
||
},
|
||
bad_request: {
|
||
title: 'Invalid request',
|
||
description: 'The request was malformed and could not be processed by the server.',
|
||
action: 'Please check your input and try again. If the problem persists, contact the administrator.',
|
||
},
|
||
server_error: {
|
||
title: 'Server error',
|
||
description: 'The server encountered an error while processing your request.',
|
||
action: 'Please try again later. If the problem persists, contact the administrator.',
|
||
},
|
||
service_unavailable: {
|
||
title: 'Service unavailable',
|
||
description: 'The service is currently under maintenance or temporarily overloaded.',
|
||
action: 'Please try again later.',
|
||
},
|
||
timeout: {
|
||
title: 'Request timed out',
|
||
description: 'The server did not respond within the expected time. This may be due to network issues or high server load.',
|
||
action: 'Please check your network connection and try again.',
|
||
},
|
||
network: {
|
||
title: 'Network error',
|
||
description: 'Unable to connect to the server. Please check your network connection.',
|
||
action: 'Verify your network is working and try again.',
|
||
},
|
||
unknown: {
|
||
title: 'Unexpected error',
|
||
description: 'An unexpected problem occurred during the request.',
|
||
action: 'Please try again. If the problem persists, contact the administrator.',
|
||
},
|
||
},
|
||
copy: 'Copy',
|
||
copied: 'Copied',
|
||
regenerate: 'Regenerate',
|
||
replyModel: 'Reply model: {model}',
|
||
routing: {
|
||
kind: {
|
||
image: 'image',
|
||
video: 'video',
|
||
media: 'media',
|
||
},
|
||
tooltip: 'This turn was answered by {primary}; image attachments were captioned via {sidecar} ({sidecarProvider}) before reaching the primary model.',
|
||
hint: {
|
||
willRoute: 'Detected {kind} attachment. The current model "{primary}" does not support {kind} input — it will be captioned by "{sidecar}" first (sidecar mode, primary chat unchanged).',
|
||
notConfigured: 'Detected {kind} attachment. The current model does not support {kind} input and no sidecar model has been configured.',
|
||
videoReserved: 'Detected video attachment. Video sidecar is reserved (pre-configured "{sidecar}") but not yet wired in this version. Switch to a video-capable primary model instead.',
|
||
action: {
|
||
gotoSettings: 'Configure',
|
||
},
|
||
},
|
||
},
|
||
ttsPlay: 'Read Aloud',
|
||
ttsStop: 'Stop Reading',
|
||
conversations: 'Conversations',
|
||
newChat: 'New Chat',
|
||
loadingAgents: 'Loading employees...',
|
||
selectAgent: 'Please select an employee',
|
||
noConversations: 'No conversations yet',
|
||
startNewChat: 'Start a new chat above',
|
||
messages: '{count} messages',
|
||
configModel: 'Configure Model',
|
||
clearMessages: 'Clear Messages',
|
||
goToModelSettings: 'Go to Model Settings',
|
||
configModelFirst: 'Please configure a model first',
|
||
modelUnavailable: 'Current model is unavailable',
|
||
noActiveModel: 'No active model. Go to Model Management to select an available model before chatting.',
|
||
providerNotReady: 'The active model belongs to {name}, but this provider is not fully configured. Please complete the API Key or Base URL in Model Management.',
|
||
noAvailableModel: 'No available model.',
|
||
loadAgentsFailed: 'Failed to load employees',
|
||
loadModelFailed: 'Failed to load model state',
|
||
loadConversationsFailed: 'Failed to load conversations',
|
||
loadMessagesFailed: 'Failed to load messages',
|
||
deleteConversationFailed: 'Failed to delete conversation',
|
||
deleteConfirm: 'Delete this conversation? This cannot be undone.',
|
||
switchModelFailed: 'Failed to switch model',
|
||
searchModel: 'Search models…',
|
||
noMatchModel: 'No matching models',
|
||
// RFC-073: liveness hints shown in the model dropdown header
|
||
modelLivenessUnprobed: 'Checking availability',
|
||
modelLivenessCooldown: 'In cooldown ({seconds}s remaining)',
|
||
// RFC-074 PR-2: empty-state inside the model dropdown
|
||
noProvidersConfigured: 'No models available yet',
|
||
goConfigure: 'Configure',
|
||
// Issue #81: liveness-aware popup state machine.
|
||
prompt: {
|
||
noActive: {
|
||
title: 'Pick a model first',
|
||
desc: 'No active model. Choose one in Model Management before chatting.',
|
||
},
|
||
unconfigured: {
|
||
title: '{name} is not fully configured',
|
||
desc: 'Missing: {fields}. {hint}',
|
||
},
|
||
removed: {
|
||
title: '{name} is unavailable',
|
||
descFallback: 'The last probe failed — check whether the service is running.',
|
||
},
|
||
cooldown: {
|
||
title: '{name} is temporarily unavailable',
|
||
desc: 'Auto-retrying in about {seconds}s.',
|
||
},
|
||
unprobed: {
|
||
title: 'Checking model availability',
|
||
desc: 'Hold on or refresh to retry.',
|
||
},
|
||
noModels: {
|
||
title: '{name} has no usable models',
|
||
desc: 'Discover models or add one manually.',
|
||
},
|
||
},
|
||
promptAction: {
|
||
fillBaseUrl: 'Fill Base URL',
|
||
fillApiKey: 'Fill API Key',
|
||
fillRequiredFields: 'Complete required fields',
|
||
startOAuth: 'Sign in',
|
||
testConnection: 'Test connection',
|
||
pullModel: 'Discover models',
|
||
waitCooldown: 'Retry now',
|
||
reprobe: 'Re-probe',
|
||
switchToModel: 'Switch to {name}',
|
||
fixThis: 'Fix',
|
||
},
|
||
recoverableBanner: {
|
||
message: '{name} is unavailable; sends will fall back to {fallback} automatically',
|
||
switched: 'Primary model unavailable; switched to {fallback}',
|
||
},
|
||
uploadFailed: 'File upload failed',
|
||
dropToUpload: 'Drop files or folders here',
|
||
copyFailed: 'Copy failed',
|
||
datePinned: 'Pinned',
|
||
dateToday: 'Today',
|
||
dateYesterday: 'Yesterday',
|
||
dateLast7Days: 'Last 7 Days',
|
||
dateEarlier: 'Earlier',
|
||
hasUnread: 'New activity',
|
||
cronRunning: {
|
||
executing: 'Executing…',
|
||
fallbackName: 'Scheduled task',
|
||
},
|
||
suggestionIntro: 'Remember I hate cilantro and love iced Americanos — remind me when ordering',
|
||
suggestionPoem: 'Search for today\'s biggest tech news and summarize it in one sentence',
|
||
suggestionCode: 'Ask the writer agent to polish a draft I\'m about to send you',
|
||
suggestionWeather: 'What skills and tools do you have right now? Show me how to add more',
|
||
approvalRequired: 'Approval Required',
|
||
approve: 'Approve',
|
||
deny: 'Deny',
|
||
approvalHint: 'or type <code>/approve</code> / <code>/deny</code>',
|
||
approved: '✅ Approved',
|
||
denied: '⛔ Denied',
|
||
approvalWaiting: 'Awaiting confirmation below...',
|
||
pendingApprovalPlaceholder: 'Type /approve or /deny to respond...',
|
||
messagePlaceholder: 'Type a message... (Enter to send, Shift+Enter for new line)',
|
||
thinkingOn: 'Deep thinking enabled',
|
||
thinkingOff: 'Click to enable deep thinking',
|
||
thinkingUnsupported: 'Current model does not support deep thinking',
|
||
subtitle: 'Your intelligent AI assistant powered by Spring AI Alibaba',
|
||
// Queue related
|
||
queuedSending: 'Sending queued message...',
|
||
queuedWillSend: 'Queued, will send after current step',
|
||
queuedCancel: 'Cancel',
|
||
queuedReplace: 'Message queued. Press Enter to replace...',
|
||
queuedBadge: '{count} queued',
|
||
// Stream status
|
||
streamPreparingContext: 'Preparing context...',
|
||
streamReadingMemory: 'Reading memory...',
|
||
streamReasoning: 'Analyzing...',
|
||
streamDraftingAnswer: 'Drafting answer...',
|
||
streamSummarizingObservations: 'Organizing information...',
|
||
streamThinking: 'Thinking...',
|
||
streamGenerating: 'Generating...',
|
||
streamExecutingTool: 'Executing tool...',
|
||
streamAwaitingApproval: 'Awaiting approval',
|
||
streamFinalizing: 'Finalizing...',
|
||
streamFailed: 'Interrupted',
|
||
streamInterrupting: 'Interrupting...',
|
||
streamQueued: 'Queued, waiting...',
|
||
streamReconnecting: 'Reconnecting...',
|
||
streamStopped: 'Stopped',
|
||
streamCompleted: 'Completed',
|
||
// Context compaction (compact_status SSE)
|
||
compactStart: 'Compacting context…',
|
||
compactPairSafe: 'Adjusting boundary to preserve tool_call pairs…',
|
||
compactSummarize: 'Summarizing the older turns…',
|
||
compactStartWithTokens: 'Compacting context… ({tokens})',
|
||
compactSummarizeWithCount: 'Summarizing the older turns… ({count} msgs)',
|
||
streamPreparingContextDetail: 'Collecting the current question, conversation history, and required context.',
|
||
streamReadingMemoryDetail: 'Looking up the most relevant long-term memory and recent notes for this question.',
|
||
streamReasoningDetail: 'Comparing options and organizing the answer structure based on the available information.',
|
||
streamDraftingAnswerDetail: 'The main analysis is done. Turning it into a readable answer now.',
|
||
streamSummarizingObservationsDetail: 'A larger tool result just came back. Condensing the key points before continuing.',
|
||
streamThinkingDetail: 'The model is still reasoning internally. Visible text may not appear immediately.',
|
||
streamGeneratingDetail: 'Visible output has started and more content should appear shortly.',
|
||
streamExecutingToolDetail: 'Reading files, querying data, or running the necessary operation for a more accurate answer.',
|
||
streamAwaitingApprovalDetail: 'Your confirmation is required before continuing.',
|
||
streamFinalizingDetail: 'Saving the result and closing out this response.',
|
||
streamFailedDetail: 'This run did not finish cleanly, but you can retry or keep asking follow-up questions.',
|
||
streamSlowShort: 'This step is taking a bit longer than usual, but it is still running.',
|
||
streamSlowSummarizing: 'Organizing a larger tool result. This step often takes longer.',
|
||
streamSlowReasoning: 'The model is doing heavier analysis here. This is not a frozen connection.',
|
||
streamSlowGeneral: 'Processing is still ongoing. The time is currently being spent in internal analysis.',
|
||
// Pre-token lifecycle stages
|
||
streamConnecting: 'Connecting to server...',
|
||
streamStarted: 'Connection established, preparing context...',
|
||
streamContextPrepared: 'Context ready, calling LLM...',
|
||
streamLlmRequestSent: 'Waiting for first token...',
|
||
streamElapsedSuffix: ' ({sec}s elapsed)',
|
||
// Per-iteration grouping
|
||
iterationEmpty: 'Iteration {index} interrupted (no output)',
|
||
contentRepetitionWarning: 'Repetitive content detected near the end (model artifact)',
|
||
// INCOMPLETE truncation card (finishReason=incomplete)
|
||
incompleteTitle: 'Answer auto-truncated after repeated output was detected',
|
||
incompleteDescription: 'After the visible text above, the model started repeating itself (or stalled in thinking with no output) and was cut short to avoid wasted tokens. Click below to regenerate the full answer, or refine your prompt to focus on the missing parts.',
|
||
incompleteRetry: 'Regenerate',
|
||
// EVIDENCE_INSUFFICIENT info card (finishReason=evidence_insufficient)
|
||
evidenceTitle: 'Run completed — some source references could not be verified',
|
||
evidenceDescription: 'The full answer is preserved above. The classes/files listed in the trailing "[evidence insufficient] …" line were not actually opened during this run; the model may have inferred them from naming. Ask a follow-up to have each one read before relying on those references.',
|
||
// feedback_event card — emitted when a turn ends in a non-transient error.
|
||
// Buttons are data-driven from the event's `actions` array; labels live
|
||
// under chat.feedback.{action} so a future backend can ship a new action
|
||
// (e.g. "switch_model") with a single new translation key.
|
||
feedback: {
|
||
title: 'This turn failed',
|
||
description: 'The model call did not finish normally; the error reason is shown above. Click Retry to replay the same prompt, or Report to copy the error details for a bug report.',
|
||
retry: 'Retry',
|
||
regenerate: 'Regenerate',
|
||
report: 'Report',
|
||
reportCopied: 'Error details copied to clipboard',
|
||
reportFailed: 'Copy failed — check browser permissions',
|
||
},
|
||
// Approval bar
|
||
approvalAllow: 'Allow',
|
||
approvalExecute: 'to execute?',
|
||
// Time format
|
||
timeJustNow: 'Just now',
|
||
timeMinutesAgo: '{n}m ago',
|
||
timeHoursAgo: '{n}h ago',
|
||
},
|
||
nav: {
|
||
dashboard: 'Dashboard',
|
||
chat: 'Chat',
|
||
control: 'Control',
|
||
channels: 'Channels',
|
||
sessions: 'Sessions',
|
||
agent: 'Agent',
|
||
workspace: 'Workspace',
|
||
agentContext: 'Agent Context',
|
||
skills: 'Skills',
|
||
wiki: 'Wiki KB',
|
||
enterprise: 'Enterprise',
|
||
tools: 'Tools',
|
||
plugins: 'Plugins',
|
||
core: 'Core',
|
||
connect: 'Connect',
|
||
system: 'System',
|
||
datasources: 'Datasources',
|
||
mcpServers: 'MCP Connections',
|
||
mcpConnections: 'MCP Connections',
|
||
toolsCatalog: 'Tools (Catalog)',
|
||
activity: 'Activity',
|
||
acpEndpoints: 'ACP Endpoints',
|
||
settingsGroup: 'Settings',
|
||
agents: 'Digital Employees',
|
||
backstage: 'Backstage',
|
||
backstageTooltip: 'See what your employees are doing right now',
|
||
security: 'Security',
|
||
tokenUsage: 'Token Usage',
|
||
cronJobs: 'Cron Jobs',
|
||
workflows: 'Workflows',
|
||
triggers: 'Triggers',
|
||
settings: 'Settings',
|
||
logout: 'Logout',
|
||
memory: 'Memory',
|
||
themeLight: 'Light',
|
||
themeDark: 'Dark',
|
||
themeSystem: 'System',
|
||
themeLabel: 'Appearance',
|
||
languageLabel: 'Language',
|
||
appearance: 'Appearance & Language',
|
||
roleUser: 'User',
|
||
roleAdmin: 'Admin',
|
||
},
|
||
backstage: {
|
||
kicker: 'Backstage',
|
||
title: 'See what your employees are doing',
|
||
attention: 'Someone needs your attention',
|
||
unknownAgent: 'Employee',
|
||
aTool: 'a tool',
|
||
orphan: 'no one watching',
|
||
orphanHint: 'The browser tab closed but this employee is still working.',
|
||
subagentsBadge: '{n} helping',
|
||
headline: {
|
||
loading: 'Looking around...',
|
||
allQuiet: 'All quiet. No one is working right now.',
|
||
working: 'Your {n} employees are at work.',
|
||
someoneNeedsAttention: '{n} need a look from you.',
|
||
workingAlone: '{running} working — {orphan} with no one listening.',
|
||
},
|
||
status: {
|
||
running: '{n} running',
|
||
stuck: '{n} stuck',
|
||
orphan: '{n} unwatched',
|
||
helpers: '{n} helpers',
|
||
},
|
||
filters: {
|
||
all: 'All',
|
||
working: 'Working',
|
||
attention: 'Needs attention',
|
||
quiet: 'Unwatched',
|
||
},
|
||
saying: {
|
||
thinking: 'Thinking...',
|
||
replying: 'Writing the reply...',
|
||
planning: 'Planning the next steps...',
|
||
summarizing: 'Wrapping up...',
|
||
usingToolBare: 'Running',
|
||
usingSomething: 'Using a tool...',
|
||
awaitingApproval: 'Waiting for your approval.',
|
||
toolSilentBare: 'Stuck on a tool, no progress.',
|
||
idleSilent: 'Quiet for too long.',
|
||
hardCap: 'Has been at this far too long.',
|
||
},
|
||
callout: {
|
||
toolSilent: '{tool} has been silent for {time}. It looks stuck.',
|
||
idleSilent: 'No sign of activity for {time}.',
|
||
hardCap: 'Running for {time} — well past normal.',
|
||
},
|
||
dotTitle: {
|
||
healthy: 'Working normally',
|
||
stuck: 'Looks stuck',
|
||
orphan: 'Running with no audience',
|
||
},
|
||
detail: {
|
||
who: 'Who',
|
||
doing: 'What it\'s doing',
|
||
runningFor: 'Running for',
|
||
lastHeard: 'Last heard from',
|
||
ago: 'ago',
|
||
audience: 'Audience',
|
||
noOneListening: 'No one watching the chat right now.',
|
||
peopleListening: '{n} listening',
|
||
helpers: 'Helpers',
|
||
session: 'Session',
|
||
},
|
||
actions: {
|
||
live: 'Live',
|
||
paused: 'Paused',
|
||
pauseRefresh: 'Pause auto-refresh',
|
||
resumeRefresh: 'Resume auto-refresh',
|
||
tidyUp: 'Tidy up',
|
||
stop: 'Stop',
|
||
stopHint: 'Ask it to wind down at the next checkpoint.',
|
||
endIt: 'End it',
|
||
endHint: 'Force it to stop now.',
|
||
close: 'Close',
|
||
},
|
||
confirm: {
|
||
stopTitle: 'Stop this employee?',
|
||
stopBody: 'Ask {name} to wind down. The current step will finish first.',
|
||
endTitle: 'Force {name} to stop now?',
|
||
endBody: 'This will stop the employee immediately. Any work in progress will be lost. The user will see "stopped by admin".',
|
||
subTitle: 'Stop this helper?',
|
||
subBody: 'Stop {name}. The owning employee will keep running.',
|
||
sweepTitle: 'Tidy up stuck employees?',
|
||
sweepBody: '{n} employee(s) look stuck. Stop all of them now?',
|
||
},
|
||
toast: {
|
||
stopped: 'Asked it to stop.',
|
||
ended: 'Stopped.',
|
||
subStopped: 'Helper stopped.',
|
||
swept: 'Tidied up {n} employee(s).',
|
||
},
|
||
empty: {
|
||
allQuiet: 'All quiet.',
|
||
hint: 'No employees are working right now. This page will light up when one is.',
|
||
},
|
||
time: {
|
||
justNow: 'just now',
|
||
seconds: '{n}s',
|
||
minutes: '{n}m {s}s',
|
||
hours: '{n}h {m}m',
|
||
},
|
||
errors: {
|
||
loadFailed: 'Could not load runtime status.',
|
||
},
|
||
},
|
||
doctor: {
|
||
title: 'System Diagnostics',
|
||
checking: 'Checking...',
|
||
allGood: 'All systems healthy',
|
||
hasWarnings: '{count} warning(s)',
|
||
hasErrors: '{count} issue(s)',
|
||
refresh: 'Re-check',
|
||
lastChecked: 'Checked {time} ago',
|
||
diagnose: 'Diagnose',
|
||
},
|
||
// Issue #81: provider-level hint / status text shared across chat popup and ModelSelector.
|
||
provider: {
|
||
hint: {
|
||
ollamaBaseUrlExample: 'Example: {example}',
|
||
lmstudioBaseUrlExample: 'Example: {example} (LM Studio default port)',
|
||
llamacppBaseUrlExample: 'Example: {example} (llama-server default port)',
|
||
vllmBaseUrlExample: 'Example: {example}',
|
||
openaiCompatBaseUrlExample: 'Example: OpenAI-compatible endpoint, e.g. {example}',
|
||
},
|
||
status: {
|
||
unconfigured: 'Not configured',
|
||
removed: 'Unavailable',
|
||
cooldown: 'Retry in {s}s',
|
||
unprobed: 'Probing',
|
||
},
|
||
},
|
||
settings: {
|
||
title: 'Settings',
|
||
kicker: 'Configuration',
|
||
layoutDesc: 'Tune models, system behavior, and media capabilities without letting the product collapse into a pile of controls.',
|
||
sections: {
|
||
model: 'Model Management',
|
||
system: 'System',
|
||
image: 'Image Generation',
|
||
tts: 'Text-to-Speech',
|
||
stt: 'Speech Recognition',
|
||
music: 'Music Generation',
|
||
video: 'Video Generation',
|
||
model3d: '3D Generation',
|
||
featureFlags: 'Feature Flags',
|
||
about: 'About',
|
||
advanced: 'Advanced',
|
||
},
|
||
models: {
|
||
sidecar: {
|
||
title: 'Multimodal sidecar',
|
||
hint: "When the primary model can't handle images or video, the sidecar model captions the attachment to text first.",
|
||
notConfigured: 'Not configured (skip attachment)',
|
||
idle: 'Off',
|
||
reserved: 'Reserved',
|
||
vision: {
|
||
label: 'Vision sidecar model',
|
||
desc: 'Invoked once per uploaded image to produce a structured description. The primary chat model is unchanged.',
|
||
empty: 'No vision-capable model is enabled yet. Add one under "Cloud Models" above.',
|
||
},
|
||
video: {
|
||
label: 'Video sidecar model (reserved)',
|
||
desc: 'Reserved for a future iteration: when the user uploads a video, this model will sample frames and describe them. Not yet wired in v1.',
|
||
empty: 'No video-capable model is enabled yet.',
|
||
},
|
||
},
|
||
},
|
||
featureFlags: {
|
||
title: 'Feature Flags',
|
||
description: 'Runtime-toggleable feature switches. Edits apply immediately on the writing instance and propagate to peers within one cache refresh tick (≈30 s); no server restart required.',
|
||
empty: 'No feature flags registered.',
|
||
enabled: 'Enabled {key}',
|
||
disabled: 'Disabled {key}',
|
||
toggleFailed: 'Toggle failed, please retry',
|
||
footer: 'New features ship disabled by default. After enabling, watch the metrics and logs for the relevant module before widening the rollout.',
|
||
notWired: 'Not yet wired',
|
||
notWiredTooltip: 'This flag is reserved but the underlying feature is not implemented yet — toggling has no effect.',
|
||
scope: {
|
||
kb: 'KB whitelist',
|
||
user: 'User whitelist',
|
||
rollout: 'Rollout {pct}%',
|
||
},
|
||
descriptions: {
|
||
'wiki.ocr.enabled': 'Image OCR / vision-in pipeline for wiki uploads — captions images via a vision model on upload',
|
||
'wiki.compile.4stage.enabled': 'Four-stage knowledge base compilation pipeline (Summary / Planning / Generation / Index)',
|
||
'wiki.compile.cache.enabled': 'Prompt cache layer for the wiki compile pipeline — cuts ~30% input tokens on cache hits',
|
||
'wiki.confidence.enabled': 'Confidence taxonomy on wiki relations and pages (EXTRACTED / INFERRED / AMBIGUOUS / UNVERIFIED)',
|
||
'wiki.hot_cache.enabled': 'KB-level recent-activity snapshot injected into the agent system prompt',
|
||
'wiki.graph.insights.enabled': 'Wiki graph insights panel (surprising connections / gaps / bridges)',
|
||
'wiki.graph.adamic_adar.enabled': 'Adamic-Adar topology signal, additive to the existing four relevance signals',
|
||
'wiki.graph.boundary.enabled': 'Boundary score for surfacing dangling pages (high out-degree, low in-degree)',
|
||
'wiki.relation.cache.enabled': 'Persistent cache for wiki page-to-page relation computation (default on, performance baseline)',
|
||
},
|
||
},
|
||
modelTitle: 'Model Management',
|
||
modelDesc: 'Manage provider presets and default model selection',
|
||
systemTitle: 'System',
|
||
systemDesc: 'Language and runtime behavior settings',
|
||
aboutTitle: 'About MateClaw',
|
||
aboutDesc: 'Version and system information',
|
||
about: {
|
||
heroDesc: 'A personal AI operating system that places models inside a continuous loop of context, memory, execution, knowledge, and delivery.',
|
||
foundationTitle: 'Built With',
|
||
pillars: {
|
||
contextTitle: 'Keep context continuous',
|
||
contextDesc: 'Models, knowledge, workspace, and the active task live inside the same frame instead of starting over every turn.',
|
||
executionTitle: 'Make execution real',
|
||
executionDesc: 'Tools, channels, and async tasks are the real execution surface, not bolted-on extras.',
|
||
memoryTitle: 'Make memory compound',
|
||
memoryDesc: 'Memory is shaped, recalled, and turned into leverage for the next task.',
|
||
},
|
||
},
|
||
model: {
|
||
title: 'Model Management',
|
||
desc: 'Configure model providers, credentials, and model lists',
|
||
addProvider: 'Add Provider',
|
||
localProviders: 'Local Models',
|
||
cloudProviders: 'Cloud Models',
|
||
active: 'Active',
|
||
setActive: 'Set Active',
|
||
configured: 'Configured',
|
||
partial: 'Partial',
|
||
unavailable: 'Unavailable',
|
||
builtin: 'Built-in',
|
||
custom: 'Custom',
|
||
notSet: 'Not set',
|
||
noModels: 'No models',
|
||
baseUrl: 'Base URL',
|
||
apiKey: 'API Key',
|
||
apiKeyInput: 'Enter API Key',
|
||
leaveBlankKeep: 'Leave blank to keep the current value',
|
||
modelCount: '{count} models',
|
||
createTitle: 'Add Provider',
|
||
editTitle: 'Provider Settings',
|
||
manageTitle: 'Manage Models',
|
||
addModel: 'Add Model',
|
||
// Inline API Key on the provider card — primary entry point for the
|
||
// 90% case (paste a key, hit save). Modal stays for advanced fields.
|
||
inlineApiKeyTitle: 'API Key',
|
||
inlineApiKeyPlaceholder: 'Paste API key and press Enter',
|
||
inlineApiKeyMasked: 'Set ••••••••',
|
||
inlineApiKeyChange: 'Change',
|
||
inlineApiKeySaving: 'Saving…',
|
||
inlineApiKeySaved: 'API key saved',
|
||
inlineApiKeySaveFailed: 'Failed to save API key',
|
||
inlineApiKeyEnvHint: 'Or set {var} in your environment and restart',
|
||
// Headline status pill on the card — what the user reads first.
|
||
statusNotSet: 'NOT SET',
|
||
statusReady: 'READY',
|
||
statusError: 'ERROR',
|
||
modelCountAvailable: '{count} models available',
|
||
activeChanged: 'Active model updated',
|
||
providerSaved: 'Provider settings saved',
|
||
providerDeleted: 'Provider deleted',
|
||
modelAdded: 'Model added',
|
||
modelRemoved: 'Model removed',
|
||
modelAddFailed: 'Failed to add model',
|
||
modelRemoveFailed: 'Failed to remove model',
|
||
activeChangeFailed: 'Failed to change active model',
|
||
deleteConfirm: 'Delete provider "{name}"?',
|
||
removeConfirm: 'Remove model "{name}"?',
|
||
generateConfigInvalidJson: 'Generate kwargs is not valid JSON',
|
||
generateConfigMustBeObject: 'Generate kwargs must be a JSON object',
|
||
advancedSettings: 'Advanced Settings',
|
||
protocolHint: 'This selects the provider API protocol, not an internal class name.',
|
||
protocolOpenAI: 'OpenAI Compatible (Chat Completions)',
|
||
protocolAnthropic: 'Anthropic (Messages API)',
|
||
protocolGemini: 'Gemini Native',
|
||
protocolDashScope: 'DashScope Native',
|
||
advancedHint: 'Use this for generation options such as temperature, max_tokens, and top_p.',
|
||
requireApiKeyHint: 'Turn this off for internal or local OpenAI-compatible services that do not require auth. Connection tests will omit the Authorization header.',
|
||
fallbackPriorityHint: 'Pool try-order (lower wins): 0 = excluded, 1 = first in line, 2 = second, and so on. Providers sharing the same value are tried in alphabetical order of their ID.',
|
||
fallbackBadge: 'Preferred #{priority}',
|
||
fallbackBadgeTitle: 'Position in the available pool — lower numbers are tried first',
|
||
// RFC-009 Phase 4: provider pool status badges
|
||
poolBadgeInPool: 'In Pool',
|
||
poolBadgeInPoolTitle: 'Passed startup probe; participates in failover',
|
||
poolBadgeRemoved: 'Removed',
|
||
poolBadgeRemovedTitle: 'Removed from pool ({source}): {message}',
|
||
poolBadgeCooldown: 'Cooling Down',
|
||
poolBadgeCooldownTitle: 'Recent failures; recovers automatically in {seconds}s',
|
||
poolSourceAuthError: 'API key invalid',
|
||
poolSourceBilling: 'Billing/quota issue',
|
||
poolSourceModelNotFound: 'Model not found',
|
||
poolSourceInitProbe: 'Startup probe failed',
|
||
poolSourceManual: 'Manually removed',
|
||
poolReprobe: 'Reprobe',
|
||
poolReprobing: 'Probing...',
|
||
poolReprobeOk: 'Probe passed; back in the available pool',
|
||
poolReprobeFail: 'Probe failed: {error}',
|
||
// RFC-073: status-pill labels driven by Liveness
|
||
livenessLive: 'Live',
|
||
livenessCooldown: 'Cooling down',
|
||
livenessRemoved: 'Disconnected',
|
||
livenessUnprobed: 'Probing',
|
||
livenessUnprobedTooltip: 'Checking availability after startup; will refresh shortly',
|
||
livenessUnconfigured: 'Needs setup',
|
||
// RFC-074 PR-2: enable / disable / drawer
|
||
enableProviderCta: '+ Enable Provider',
|
||
addCustomProvider: '+ Custom',
|
||
enable: 'Enable',
|
||
disable: 'Disable',
|
||
alreadyEnabled: 'Enabled',
|
||
disableConfirm: 'Disable provider "{name}"? It will disappear from the dropdown but its config is kept — you can re-enable any time.',
|
||
defaultSwitchedToast: 'Default model switched to {provider} / {model}',
|
||
addProviderDrawerTitle: 'Add Provider',
|
||
addProviderDrawerSubtitle: 'Once enabled the provider appears in the model dropdown. Cloud providers still need an API key after enabling.',
|
||
catalogEmpty: 'Catalog is empty',
|
||
catalogSearchPlaceholder: 'Search providers…',
|
||
catalogSearchEmpty: 'No providers match “{query}”',
|
||
enabledToast: 'Enabled {name}',
|
||
emptyTitle: 'No providers enabled yet',
|
||
emptyDesc: 'Enable a built-in from the catalog, or create a custom provider.',
|
||
searchHint: 'When enabled, the LLM will use its built-in search engine to retrieve real-time information (DashScope/Kimi/OpenAI supported).',
|
||
searchStrategyDefault: 'Default',
|
||
oauthTitle: 'OpenAI OAuth Login',
|
||
oauthLogin: 'OAuth Login',
|
||
oauthConnected: 'Connected',
|
||
oauthDisconnected: 'Not Connected',
|
||
oauthDisconnect: 'Disconnect',
|
||
oauthHint: 'Sign in with your OpenAI account to use ChatGPT Plus/Pro member quota (not API credits).',
|
||
oauthLoginSuccess: 'OpenAI OAuth login successful',
|
||
oauthRevokeSuccess: 'OpenAI OAuth disconnected',
|
||
// Device Authorization Grant (used for remote deployments where the browser
|
||
// cannot reach localhost:1455 for the PKCE callback).
|
||
oauthDeviceTitle: 'Sign in to ChatGPT (Device Code)',
|
||
oauthDeviceStep1: '1. Open this link in any browser or on your phone:',
|
||
oauthDeviceStep2: '2. Enter this verification code:',
|
||
oauthDeviceStep3: 'This page will connect automatically once you finish ({seconds}s remaining)',
|
||
oauthDeviceExpired: 'The device code expired. Please try again.',
|
||
copy: 'Copy',
|
||
copied: 'Copied',
|
||
copyFailed: 'Clipboard refused — please select and copy manually',
|
||
// RFC-062: Claude Code OAuth (subscription piggyback)
|
||
claudeCodeOauthDetect: 'Detect Claude Code Login',
|
||
claudeCodeOauthHint: 'Reuses your local Claude Code Pro/Max subscription. Sign in via the Claude Code app first, then click "Detect" to pick up the credentials.',
|
||
claudeCodeOauthInstructions: 'No Claude Code credentials found. Install Claude Code, sign in with a Pro/Max account, then click Detect again.',
|
||
claudeCodeOauthRevokeHint: 'Sign out from the Claude Code app to revoke. MateClaw does not modify Claude Code\'s on-disk credentials.',
|
||
providerIdPlaceholder: 'e.g. my-local-gemma',
|
||
providerIdHint: 'Used only as an internal key. Lowercase letters/digits, plus . _ - are fine — no slashes or spaces (cannot be changed after create).',
|
||
providerIdInvalid: 'Provider ID may only contain letters, digits, dot, underscore, and hyphen (no slashes or spaces). Must start with a letter or digit and be 1–64 chars.',
|
||
fields: {
|
||
providerId: 'Provider ID',
|
||
providerName: 'Provider Name',
|
||
defaultBaseUrl: 'Default Base URL',
|
||
apiKeyPrefix: 'API Key Prefix',
|
||
requireApiKey: 'Requires API Key',
|
||
protocol: 'Protocol',
|
||
generateKwargs: 'Generate Kwargs (JSON)',
|
||
fallbackPriority: 'Pool Try-Order',
|
||
enableSearch: 'Built-in Search',
|
||
searchStrategy: 'Search Strategy',
|
||
modelId: 'Model ID',
|
||
modelDisplayName: 'Display Name',
|
||
},
|
||
actions: {
|
||
manageModels: 'Manage Models',
|
||
providerSettings: 'Settings',
|
||
},
|
||
hints: {
|
||
openai: 'OpenAI defaults to https://api.openai.com/v1',
|
||
azureOpenai: 'Use an Azure resource endpoint such as https://<resource>.openai.azure.com/openai/v1',
|
||
anthropic: 'Anthropic defaults to https://api.anthropic.com',
|
||
ollama: 'Ollama usually runs locally at http://localhost:11434',
|
||
lmstudio: 'LM Studio usually exposes an OpenAI-compatible endpoint at http://localhost:1234/v1',
|
||
gemini: 'Gemini defaults to https://generativelanguage.googleapis.com',
|
||
openrouter: 'OpenRouter defaults to https://openrouter.ai/api/v1, aggregating multiple model providers',
|
||
zhipu: 'Zhipu AI defaults to https://open.bigmodel.cn/api/paas/v4',
|
||
zhipuIntl: 'Zhipu AI International uses https://open.z.ai/api/paas/v4',
|
||
volcengine: 'Volcano Engine (Doubao) defaults to https://ark.cn-beijing.volces.com/api/v3, requires an endpoint created on the Volcengine Ark platform',
|
||
xiaomiMimo: 'Xiaomi MiMo defaults to https://api.xiaomimimo.com/v1 (OpenAI-compatible). API keys are issued at platform.xiaomimimo.com',
|
||
openaiCompatible: 'OpenAI-compatible services usually use a Base URL ending with /v1',
|
||
},
|
||
discovery: {
|
||
discover: 'Discover Models',
|
||
discovering: 'Discovering...',
|
||
testConnection: 'Test Connection',
|
||
testing: 'Testing...',
|
||
testModel: 'Test',
|
||
testingModel: 'Testing...',
|
||
discoveredTitle: 'Discovered New Models',
|
||
discoveredCount: 'Found {total} models, {count} are new',
|
||
noNewModels: 'No new models found, all remote models already exist',
|
||
selectAll: 'Select All',
|
||
addSelected: 'Add Selected',
|
||
adding: 'Adding...',
|
||
addedCount: '{count} models added',
|
||
connectionOk: 'Connection successful',
|
||
connectionFail: 'Connection failed',
|
||
latency: 'Latency {ms}ms',
|
||
modelOk: 'Model available',
|
||
modelFail: 'Model unavailable',
|
||
probeVerified: 'Verified',
|
||
probeVerifiedTitle: 'Verified reachable',
|
||
probeFailedBanner: '⚠ {count} discovered model(s) failed the reachability probe and were not listed above:',
|
||
probeUnreachable: 'not reachable',
|
||
},
|
||
},
|
||
fields: {
|
||
name: 'Display Name',
|
||
provider: 'Provider',
|
||
modelName: 'Model Name',
|
||
description: 'Description',
|
||
temperature: 'Temperature',
|
||
maxTokens: 'Max Tokens',
|
||
topP: 'Top P',
|
||
language: 'Language',
|
||
streamEnabled: 'Stream Response',
|
||
debugMode: 'Debug Mode',
|
||
searchEnabled: 'Enable Search',
|
||
searchProvider: 'Search Provider',
|
||
searchFallbackEnabled: 'Fallback on Failure',
|
||
serperApiKey: 'Serper API Key',
|
||
serperBaseUrl: 'Serper Base URL',
|
||
tavilyApiKey: 'Tavily API Key',
|
||
tavilyBaseUrl: 'Tavily Base URL',
|
||
duckduckgoEnabled: 'DuckDuckGo (Keyless)',
|
||
searxngBaseUrl: 'SearXNG Base URL',
|
||
sttEnabled: 'Enable Speech Recognition',
|
||
sttProvider: 'Preferred STT Provider',
|
||
sttFallbackEnabled: 'Provider Fallback',
|
||
// Issue #76: route the OpenAI-compat STT endpoint
|
||
sttOpenAiCompatProviderId: 'OpenAI-compatible Credential',
|
||
sttOpenAiCompatModel: 'OpenAI-compatible Model',
|
||
musicEnabled: 'Enable Music Generation',
|
||
musicProvider: 'Preferred Music Provider',
|
||
musicFallbackEnabled: 'Provider Fallback',
|
||
model3dEnabled: 'Enable 3D Model Generation',
|
||
model3dProvider: 'Preferred 3D Provider',
|
||
model3dFallbackEnabled: 'Provider Fallback',
|
||
ttsEnabled: 'Enable Text-to-Speech',
|
||
ttsProvider: 'Preferred TTS Provider',
|
||
ttsFallbackEnabled: 'Provider Fallback',
|
||
ttsAutoMode: 'Auto Read Aloud',
|
||
ttsSpeed: 'Speed',
|
||
imageEnabled: 'Enable Image Generation',
|
||
imageProvider: 'Preferred Image Provider',
|
||
imageFallbackEnabled: 'Provider Fallback',
|
||
openaiStatus: 'OpenAI Status',
|
||
videoEnabled: 'Enable Video Generation',
|
||
videoProvider: 'Preferred Video Provider',
|
||
videoFallbackEnabled: 'Provider Fallback',
|
||
dashscopeStatus: 'DashScope Status',
|
||
zhipuApiKey: 'Zhipu API Key',
|
||
zhipuBaseUrl: 'Zhipu API Base URL',
|
||
falApiKey: 'fal.ai API Key',
|
||
klingAccessKey: 'Kling Access Key',
|
||
klingSecretKey: 'Kling Secret Key',
|
||
runwayApiKey: 'Runway API Key',
|
||
minimaxApiKey: 'MiniMax API Key',
|
||
minimaxRegion: 'MiniMax API Region',
|
||
},
|
||
hints: {
|
||
provider: 'Current implementation applies DashScope model options at runtime.',
|
||
language: 'Interface language preference stored in backend settings.',
|
||
streamEnabled: 'Controls whether chat prefers streaming output in UI settings.',
|
||
debugMode: 'Reserved for showing more execution details later.',
|
||
searchEnabled: 'When disabled, the search tool will be unavailable to agents.',
|
||
searchProvider: 'Primary search provider used when the search tool is invoked.',
|
||
searchFallbackEnabled: 'Automatically try the other provider when the primary one fails.',
|
||
serperApiKey: 'API key for Google Serper search, get it from serper.dev.',
|
||
serperBaseUrl: 'Usually no need to change unless using a custom proxy.',
|
||
tavilyApiKey: 'API key for Tavily search, get it from tavily.com.',
|
||
tavilyBaseUrl: 'Usually no need to change unless using a custom proxy.',
|
||
duckduckgoEnabled: 'Free keyless search fallback. No API key required. Enabled by default as a zero-config fallback.',
|
||
searxngBaseUrl: 'Self-hosted SearXNG instance URL. Auto-configured when deploying via Docker.',
|
||
sttEnabled: 'Enable speech-to-text for voice messages. Both providers reuse existing API keys.',
|
||
sttProvider: 'Select preferred STT provider. Auto mode picks the first available one.',
|
||
sttFallbackEnabled: 'Automatically try other configured providers if the preferred one fails.',
|
||
openaiSttInfo: 'Reuses OpenAI API Key from Model Management. Whisper model, supports multilingual auto-detection.',
|
||
dashscopeSttInfo: 'Reuses DashScope API Key from Model Management. Paraformer Realtime over WebSocket — strong Chinese recognition, sub-second latency.',
|
||
// Issue #76
|
||
sttOpenAiCompatProviderId: 'Pick any OpenAI-compatible provider from Model Management as the credential source (baseUrl + API key). Beyond OpenAI itself this covers self-hosted FunASR, SiliconFlow, Groq, Together, Volcano, Qiniu, and any custom provider you add with the OpenAI-compatible protocol.',
|
||
sttOpenAiCompatModel: 'Model id sent in the multipart "model" field. Defaults to whisper-1; use paraformer-large for FunASR, or whatever id your vendor documents.',
|
||
sttOpenAiCompatNote: 'Tip: to plug in a private ASR service, head to Model Management → Add Custom Provider → pick the "OpenAI Compatible" protocol → fill in Base URL (and an optional API key), then come back and select it here.',
|
||
musicEnabled: 'Enable to let Agent use the music generation tool. Google Lyria reuses Google Key.',
|
||
musicProvider: 'Select preferred music provider. Auto mode prioritizes Google Lyria.',
|
||
musicFallbackEnabled: 'Automatically try other configured providers if the preferred one fails.',
|
||
googleLyriaInfo: 'Reuses Google API Key from Model Management. Lyria 3 model, supports lyrics and instrumental.',
|
||
minimaxMusicInfo: 'Reuses MiniMax API Key from video settings. music-2.5+ model, supports lyrics and instrumental.',
|
||
model3dEnabled: 'Enable to let Agent use model3d_generate (.glb output). Configure the hunyuan-3d provider with SecretId:SecretKey first under Models & Credentials.',
|
||
model3dProvider: 'Select preferred 3D provider. Auto mode picks the first available one.',
|
||
model3dFallbackEnabled: 'Automatically try other configured providers if the preferred one fails.',
|
||
hunyuan3dInfo: 'Tencent Hunyuan 3D (ai3d.tencentcloudapi.com). HY-3D-3.1 / HY-3D-3.0 use the Pro action; HY-3D-Express uses the Rapid action. Configure as SecretId:SecretKey under Models & Credentials.',
|
||
ttsEnabled: 'Enable to use TTS via Read Aloud button or auto mode. Edge TTS is free, no API key needed.',
|
||
ttsProvider: 'Select preferred TTS provider. Auto mode prioritizes free Edge TTS.',
|
||
ttsFallbackEnabled: 'Automatically try other configured providers if the preferred one fails.',
|
||
ttsAutoMode: 'off = manual read aloud only, always = auto-play voice for every AI reply.',
|
||
ttsSpeed: 'Speech playback speed. 1.0 is normal speed.',
|
||
edgeTtsInfo: 'Microsoft Edge built-in TTS. Free to use, supports Chinese, English, Japanese and more. Auto-detects language.',
|
||
dashscopeTtsInfo: 'Reuses DashScope API Key from Model Management. Uses CosyVoice model with multiple Chinese voices.',
|
||
openaiTtsInfo: 'Reuses OpenAI API Key from Model Management. Supports alloy, echo, nova and other voice styles.',
|
||
imageEnabled: 'Enable to let Agent use the image generation tool. Requires at least one configured image provider.',
|
||
imageProvider: 'Select preferred image provider. Auto mode picks the first available one.',
|
||
imageFallbackEnabled: 'Automatically try other configured providers if the preferred one fails.',
|
||
dashscopeImageStatus: 'Reuses the DashScope API Key configured in Model Management. No extra setup needed.',
|
||
openaiImageStatus: 'Reuses the OpenAI API Key configured in Model Management. No extra setup needed.',
|
||
zhipuImageApiKey: 'Get from bigmodel.cn. CogView-3-Flash model is free. Shared with video generation.',
|
||
falImageApiKey: 'Get from fal.ai for Flux image generation models. Shared with video generation.',
|
||
googleImagenInfo: 'Reuses Google API Key from Model Management. Supports Gemini image generation and Imagen 4.0.',
|
||
minimaxImageInfo: 'Reuses MiniMax API Key from video settings. image-01 model, multiple aspect ratios, up to 9 images.',
|
||
videoEnabled: 'Enable to let Agent use the video generation tool. Requires at least one configured video provider.',
|
||
videoProvider: 'Select preferred video provider. Auto mode picks the first available one.',
|
||
videoFallbackEnabled: 'Automatically try other configured providers if the preferred one fails.',
|
||
dashscopeVideoStatus: 'Reuses the DashScope API Key configured in Model Management. No extra setup needed.',
|
||
zhipuApiKey: 'Get from bigmodel.cn. CogVideoX-Flash model is free.',
|
||
zhipuBaseUrl: 'Usually no need to change unless using a custom proxy.',
|
||
falApiKey: 'Get from fal.ai. One key accesses Kling, Runway, Luma and more.',
|
||
klingAccessKey: 'Get from Kuaishou Open Platform for Kling video generation API.',
|
||
klingSecretKey: 'Paired with Access Key for JWT authentication.',
|
||
runwayApiKey: 'Get from runwayml.com. Supports gen4.5, gen4_turbo flagship models.',
|
||
minimaxApiKey: 'Get from minimaxi.com. Hailuo video with free quota, excellent for Chinese scenes.',
|
||
minimaxRegion: 'Choose the API host. Mainland China accounts must use the CN endpoint; others use Global.',
|
||
},
|
||
searchTitle: 'Search Service',
|
||
searchDesc: 'Configure the built-in search tool provider and API credentials',
|
||
sttTitle: 'Speech Recognition',
|
||
sttDesc: 'Configure STT speech-to-text with OpenAI Whisper and DashScope Paraformer',
|
||
sttProviderOptions: { auto: 'Auto Select' },
|
||
sttProviderTags: { reuseLlmKey: 'Reuses LLM API Key' },
|
||
musicTitle: 'Music Generation',
|
||
musicDesc: 'Configure AI music generation with Google Lyria and MiniMax Music',
|
||
musicProviderOptions: { auto: 'Auto Select' },
|
||
musicProviderTags: { reuseLlmKey: 'Reuses LLM API Key', sharedWithVideo: 'Shared with Video' },
|
||
model3dTitle: '3D Model Generation',
|
||
model3dDesc: 'Configure AI 3D model generation with Tencent Hunyuan 3D (HY-3D-3.1 / HY-3D-3.0 / HY-3D-Express)',
|
||
model3dProviderOptions: { auto: 'Auto Select', hunyuan: 'Tencent Hunyuan 3D' },
|
||
model3dProviderTags: { requiresKey: 'Requires SecretId:SecretKey' },
|
||
ttsTitle: 'Text-to-Speech',
|
||
ttsDesc: 'Configure TTS with Edge TTS (free), OpenAI TTS, and DashScope CosyVoice',
|
||
ttsProviderOptions: {
|
||
auto: 'Auto Select',
|
||
},
|
||
ttsProviderTags: {
|
||
free: 'Free',
|
||
noKeyNeeded: 'No API Key Needed',
|
||
reuseLlmKey: 'Reuses LLM API Key',
|
||
},
|
||
ttsAutoModeOptions: {
|
||
off: 'Off (Manual only)',
|
||
always: 'Always Auto Read',
|
||
},
|
||
imageTitle: 'Image Generation',
|
||
imageDesc: 'Configure AI image generation with DashScope, OpenAI DALL-E, fal.ai Flux, and Zhipu CogView',
|
||
imageProviderOptions: {
|
||
auto: 'Auto Select',
|
||
},
|
||
imageProviderTags: {
|
||
reuseLlmKey: 'Reuses LLM API Key',
|
||
freeQuota: 'Free Quota Available',
|
||
configuredInModels: 'See Model Settings',
|
||
sharedWithVideo: 'Shared with Video',
|
||
},
|
||
videoTitle: 'Video Generation',
|
||
videoDesc: 'Configure AI video generation capabilities, supporting text-to-video and image-to-video',
|
||
videoProviderOptions: {
|
||
auto: 'Auto Select',
|
||
},
|
||
videoProviderTags: {
|
||
reuseLlmKey: 'Reuses LLM API Key',
|
||
freeQuota: 'Free Quota Available',
|
||
configuredInModels: 'See Model Settings',
|
||
},
|
||
minimaxRegionGlobal: 'Global (api.minimax.io)',
|
||
minimaxRegionCn: 'China (api.minimaxi.com)',
|
||
actions: {
|
||
setDefault: 'Set Default',
|
||
saveSystem: 'Save System Settings',
|
||
},
|
||
messages: {
|
||
loadFailed: 'Failed to load settings',
|
||
saveSuccess: 'Settings saved successfully',
|
||
saveFailed: 'Failed to save settings',
|
||
deleteConfirm: 'Delete this model preset?',
|
||
modelSaved: 'Model preset saved',
|
||
modelDeleted: 'Model preset deleted',
|
||
defaultChanged: 'Default model updated',
|
||
},
|
||
languageOptions: {
|
||
zhCN: 'Simplified Chinese',
|
||
enUS: 'English',
|
||
},
|
||
},
|
||
agentContext: {
|
||
kicker: 'Context Studio',
|
||
title: 'Agent Context',
|
||
desc: 'Manage prompt files and memory for agents',
|
||
selectAgent: 'Select Agent',
|
||
noAgent: 'Please select an agent first',
|
||
files: 'Files',
|
||
coreFiles: 'Core Files',
|
||
coreFilesDesc: 'Enabled files are concatenated in order as Agent system prompt',
|
||
newFile: 'New File',
|
||
noFiles: 'No files yet',
|
||
selectFile: 'Select a file from the left to view its content',
|
||
fileContent: 'Edit Markdown content here...',
|
||
preview: 'Preview',
|
||
editOnly: 'Edit',
|
||
splitView: 'Split',
|
||
modified: 'Modified',
|
||
saveSuccess: 'Saved successfully',
|
||
saveFailed: 'Failed to save',
|
||
deleteConfirm: 'Delete file "{name}"?',
|
||
deleteSuccess: 'File deleted',
|
||
deleteFailed: 'Failed to delete',
|
||
promptUpdated: 'System prompt files updated',
|
||
promptUpdateFailed: 'Failed to update system prompt files',
|
||
newFileTitle: 'New File',
|
||
newFilePlaceholder: 'Enter filename (e.g. AGENTS.md)',
|
||
newFileHint: 'Filename must end with .md',
|
||
fileExists: 'Filename already exists',
|
||
invalidFilename: 'Please enter a valid .md filename',
|
||
loadFailed: 'Failed to load file list',
|
||
loadFileFailed: 'Failed to load file content',
|
||
},
|
||
agents: {
|
||
kicker: 'Employee Studio',
|
||
title: 'Digital Employees',
|
||
desc: 'Hire, train, and manage your digital employees',
|
||
newAgent: 'Hire Employee',
|
||
live: {
|
||
atWork: '{n} at work — see backstage',
|
||
needsAttention: '{n} need attention — see backstage',
|
||
},
|
||
templates: {
|
||
title: 'Choose a Role',
|
||
desc: 'Hire from a pre-written job description, or start from scratch.',
|
||
skip: 'Start from Scratch',
|
||
applied: 'Employee onboarded',
|
||
},
|
||
search: 'Search employees...',
|
||
tabs: {
|
||
all: 'All',
|
||
react: 'ReAct',
|
||
planExecute: 'Plan-Execute',
|
||
enabled: 'Enabled',
|
||
disabled: 'Disabled',
|
||
basic: 'Basic',
|
||
skills: 'Skills',
|
||
tools: 'Tools',
|
||
providers: 'Providers',
|
||
context: 'Context',
|
||
},
|
||
columns: {
|
||
name: 'Name',
|
||
description: 'Description',
|
||
agentType: 'Type',
|
||
modelName: 'Model',
|
||
tags: 'Tags',
|
||
enabled: 'Status',
|
||
updateTime: 'Updated',
|
||
actions: 'Actions',
|
||
},
|
||
status: {
|
||
enabled: 'Enabled',
|
||
disabled: 'Disabled',
|
||
},
|
||
emptyTitle: 'No Employees Yet',
|
||
emptyDesc: 'Hire your first employee to get started',
|
||
modal: {
|
||
newTitle: 'New Employee',
|
||
editTitle: 'Edit Employee',
|
||
},
|
||
fields: {
|
||
name: 'Name',
|
||
icon: 'Icon',
|
||
type: 'Type',
|
||
description: 'Description',
|
||
systemPrompt: 'System Prompt',
|
||
role: 'Role',
|
||
roleHint: 'A one-line job title. e.g. Senior Data Analyst, Customer Support.',
|
||
goal: 'Goal',
|
||
goalHint: 'Why this employee exists — the outcome they help you reach.',
|
||
taglinePreview: 'Card preview:',
|
||
backstory: 'Backstory',
|
||
backstoryHint: 'Invisible to users, felt in every conversation. Their experience, beliefs, and working principles.',
|
||
extraInstructions: 'Advanced: Additional Instructions',
|
||
extraInstructionsHint: 'Optional. Use for output format, process checklists, or boundary rules.',
|
||
maxIterations: 'Max Iterations',
|
||
defaultThinkingLevel: 'Default Thinking Level',
|
||
modelName: 'Model',
|
||
modelGlobalDefault: 'Use global default',
|
||
modelHint: 'Override the global default model for this employee. Leave blank to follow Settings → Models.',
|
||
tags: 'Tags',
|
||
enabled: 'Enabled',
|
||
},
|
||
thinkingLevels: {
|
||
auto: 'Follow Model',
|
||
off: 'Off',
|
||
low: 'Low',
|
||
medium: 'Standard',
|
||
high: 'Deep',
|
||
max: 'Maximum',
|
||
},
|
||
types: {
|
||
react: 'ReAct (Tool Calling)',
|
||
planExecute: 'Plan-and-Execute',
|
||
},
|
||
actions: {
|
||
chat: 'Chat',
|
||
edit: 'Edit',
|
||
delete: 'Delete',
|
||
create: 'Create',
|
||
update: 'Save',
|
||
},
|
||
placeholders: {
|
||
name: 'Employee name',
|
||
icon: 'Emoji or URL',
|
||
description: 'Brief description',
|
||
systemPrompt: 'You are a helpful AI assistant...',
|
||
role: 'e.g. Senior Data Analyst',
|
||
goal: 'e.g. Turn data into actionable insights',
|
||
backstory: 'e.g. Spent 10 years in data — believes in asking the right question before writing SQL...',
|
||
extraInstructions: 'Optional: output format, process checklist, or boundary rules...',
|
||
tags: 'tag1,tag2',
|
||
},
|
||
messages: {
|
||
noDescription: 'No description',
|
||
noTagline: 'No role and goal yet',
|
||
deleteConfirm: 'Let this employee go? This cannot be undone.',
|
||
loadFailed: 'Failed to load employees',
|
||
saveFailed: 'Failed to save employee',
|
||
saveSuccess: 'Employee saved',
|
||
deleteFailed: 'Failed to delete employee',
|
||
deleteSuccess: 'Employee let go',
|
||
toggleFailed: 'Failed to toggle status',
|
||
toggleSuccess: 'Status updated',
|
||
},
|
||
binding: {
|
||
skillsKicker: 'Trained workflows',
|
||
skillsTagline: 'A skill is a workflow — a step-by-step playbook the LLM follows for a coherent multi-step task.',
|
||
skillsHint: 'Select skills this agent can use. Leave empty to use all enabled skills.',
|
||
toolsKicker: 'Atomic tools the agent can call',
|
||
toolsTagline: 'A tool is one call, one thing. The LLM decides when to invoke each tool autonomously.',
|
||
toolsHint: 'Select tools this agent can use. Leave empty to use all enabled tools.',
|
||
searchSkills: 'Search skill name, description, or version',
|
||
searchTools: 'Search tool name, description, source, or group',
|
||
advancedToolsTitle: 'Advanced: Hand-picked atomic tools',
|
||
advancedToolsHint: 'Skill bindings already auto-expand allowed tools. Use this only for built-in micro-utilities not packaged as a skill (e.g. datetime, delegate_agent).',
|
||
toolUnionHint: 'Tools selected here are unioned with tools from any bound skills. MCP servers enabled at the system level are available to this agent by default — ticking MCP rows here only records an explicit binding, leaving them unticked does not block the agent. To deny a specific MCP tool, configure it under Security → Tool Guard.',
|
||
mcpAutoIncludedBadge: 'Auto-available',
|
||
mcpAutoIncludedTooltip: 'MCP servers enabled at the system level are available to every agent by default. Ticking only records an explicit binding; leaving rows unticked does not restrict this agent. To deny a specific MCP tool, configure it under Security → Tool Guard.',
|
||
toolStaleBadge: 'Cached (offline)',
|
||
toolStaleTooltip: 'The owning MCP server is not currently connected. This tool entry comes from the last successful snapshot; the LLM will not invoke it until the connection is restored.',
|
||
toolUnavailableBadge: 'Unavailable',
|
||
toolUnavailableTooltip: 'This tool\'s name conflicts with another tool on the same server and cannot be bound ({reason}). Rename the upstream tool to resolve.',
|
||
toolOrphanGroup: 'Bound but no longer available',
|
||
toolOrphanDescription: 'This tool was previously bound but is no longer in the available catalog (its MCP server may have been removed, or the tool was retired upstream). Uncheck and save to clean up the leftover binding.',
|
||
providersHint: 'Preferred provider order for this agent (lower index tried first). Leave empty to use the global available-pool order. Cooling-down or pool-removed providers are still skipped automatically.',
|
||
providersAddHint: 'Click a provider below to add it to the preference list:',
|
||
noSkills: 'No skills available',
|
||
noTools: 'No tools available',
|
||
noMatchingSkills: 'No matching skills',
|
||
noMatchingTools: 'No matching tools',
|
||
noProviderPreferences: 'No preferences set — the agent uses the global fallback chain order.',
|
||
contextHint: 'Manage context files (e.g. AGENT.md) that define this agent\'s behavior, knowledge, and instructions.',
|
||
goToContext: 'Edit Context Files',
|
||
},
|
||
},
|
||
security: {
|
||
title: 'Security',
|
||
kicker: 'Governance',
|
||
layoutDesc: 'Boundaries, approvals, audit, and workspace governance have to speak the same language or the system will not feel trustworthy.',
|
||
sections: {
|
||
toolGuard: 'Tool Guard',
|
||
fileGuard: 'File Guard',
|
||
auditLogs: 'Audit Logs',
|
||
members: 'Members',
|
||
workspaces: 'Workspaces',
|
||
activity: 'Activity',
|
||
},
|
||
activity: {
|
||
title: 'Activity',
|
||
desc: 'Who did what, in plain English. Click any event to see the full story.',
|
||
allActions: 'All Actions',
|
||
allResources: 'All Resources',
|
||
allSources: 'All',
|
||
sourceAudit: 'Audit',
|
||
sourceApproval: 'Approvals',
|
||
detailTitle: 'Event detail',
|
||
detailDetails: 'Detail',
|
||
loading: 'Loading…',
|
||
noEvents: 'No activity yet',
|
||
emptyHint: 'As you create agents, bind skills, or approve tool calls, they show up here.',
|
||
moreFilters: 'More filters',
|
||
changes: 'Changes',
|
||
environment: 'Environment',
|
||
absoluteTime: 'Absolute time',
|
||
noValue: '(empty)',
|
||
rawPayload: 'Raw payload',
|
||
today: 'Today',
|
||
yesterday: 'Yesterday',
|
||
justNow: 'just now',
|
||
minutesAgo: '{n} min ago',
|
||
hoursAgo: '{n} h ago',
|
||
daysAgo: '{n} d ago',
|
||
verbs: {
|
||
create: 'created',
|
||
update: 'updated',
|
||
delete: 'deleted',
|
||
enable: 'enabled',
|
||
disable: 'disabled',
|
||
login: 'signed in',
|
||
logout: 'signed out',
|
||
approvalGranted: 'approved',
|
||
approvalDenied: 'denied',
|
||
approvalPending: 'requested',
|
||
},
|
||
resources: {
|
||
agent: 'agent',
|
||
channel: 'channel',
|
||
skill: 'skill',
|
||
wiki: 'wiki page',
|
||
member: 'member',
|
||
workspace: 'workspace',
|
||
toolApproval: 'tool call',
|
||
},
|
||
columns: {
|
||
time: 'Time',
|
||
source: 'Source',
|
||
user: 'User',
|
||
action: 'Action',
|
||
resource: 'Resource',
|
||
name: 'Name',
|
||
ip: 'IP',
|
||
},
|
||
},
|
||
members: {
|
||
title: 'Workspace Members',
|
||
desc: 'Manage members and roles for the current workspace.',
|
||
addMember: 'Add Member',
|
||
noMembers: 'No members found.',
|
||
loading: 'Loading...',
|
||
columns: {
|
||
user: 'User',
|
||
role: 'Role',
|
||
joined: 'Joined',
|
||
actions: 'Actions',
|
||
},
|
||
roles: {
|
||
owner: 'Owner',
|
||
admin: 'Admin',
|
||
member: 'Member',
|
||
viewer: 'Viewer',
|
||
},
|
||
addDialog: {
|
||
title: 'Add Member',
|
||
userId: 'User ID',
|
||
userIdPlaceholder: 'Enter user ID',
|
||
user: 'Select User',
|
||
userPlaceholder: 'Search username…',
|
||
username: 'Username',
|
||
usernamePlaceholder: 'Enter username',
|
||
usernameHint: 'Account will be created automatically if user does not exist',
|
||
password: 'Password',
|
||
passwordPlaceholder: 'Required for new users',
|
||
passwordHint: 'Leave empty for existing users, required for new users',
|
||
nickname: 'Nickname',
|
||
nicknamePlaceholder: 'Optional display name',
|
||
role: 'Role',
|
||
},
|
||
actions: {
|
||
remove: 'Remove',
|
||
cancel: 'Cancel',
|
||
confirm: 'Confirm',
|
||
},
|
||
messages: {
|
||
addSuccess: 'Member added successfully',
|
||
addFailed: 'Failed to add member',
|
||
updateSuccess: 'Role updated successfully',
|
||
updateFailed: 'Failed to update role',
|
||
removeConfirm: 'Are you sure you want to remove this member?',
|
||
removeSuccess: 'Member removed',
|
||
removeFailed: 'Failed to remove member',
|
||
},
|
||
},
|
||
workspaces: {
|
||
title: 'Workspaces',
|
||
desc: 'Manage workspaces for your organization.',
|
||
manage: 'Manage Workspaces',
|
||
newWorkspace: 'New Workspace',
|
||
loading: 'Loading workspaces...',
|
||
noWorkspaces: 'No workspaces found.',
|
||
current: 'Current',
|
||
columns: {
|
||
name: 'Name',
|
||
slug: 'Slug',
|
||
description: 'Description',
|
||
basePath: 'Working Directory',
|
||
created: 'Created',
|
||
actions: 'Actions',
|
||
},
|
||
createDialog: {
|
||
title: 'New Workspace',
|
||
name: 'Name',
|
||
namePlaceholder: 'e.g. Engineering',
|
||
slug: 'Slug',
|
||
slugPlaceholder: 'e.g. engineering',
|
||
slugHint: 'Slug cannot be changed after creation.',
|
||
description: 'Description',
|
||
descriptionPlaceholder: 'Optional description',
|
||
basePath: 'Working Directory',
|
||
basePathPlaceholder: 'e.g. /home/user/project or D:\\codes\\MyProject',
|
||
basePathHint: 'Restrict agent file access to this directory. Leave empty for no restriction.',
|
||
},
|
||
editDialog: {
|
||
title: 'Edit Workspace',
|
||
},
|
||
deleteDialog: {
|
||
title: 'Delete Workspace',
|
||
confirm: 'Are you sure you want to delete {name}? This will remove all resources associated with this workspace.',
|
||
},
|
||
actions: {
|
||
edit: 'Edit',
|
||
delete: 'Delete',
|
||
cancel: 'Cancel',
|
||
create: 'Create',
|
||
save: 'Save',
|
||
},
|
||
messages: {
|
||
saveSuccess: 'Workspace saved successfully',
|
||
saveFailed: 'Failed to save workspace',
|
||
deleteSuccess: 'Workspace deleted',
|
||
deleteFailed: 'Failed to delete workspace',
|
||
},
|
||
},
|
||
toolGuard: {
|
||
title: 'Tool Guard',
|
||
desc: 'Manage tool invocation security rules and global guard settings',
|
||
enabled: 'Enable Tool Guard',
|
||
enabledHint: 'When enabled, tool invocations will be checked against security rules',
|
||
guardScope: 'Guard Scope',
|
||
scopeAll: 'All Tools',
|
||
scopeSelected: 'Selected Tools',
|
||
guardedTools: 'Guarded Tools',
|
||
guardedToolsPlaceholder: 'Type tool name and press Enter',
|
||
deniedTools: 'Denied Tools',
|
||
deniedToolsPlaceholder: 'Type tool name and press Enter',
|
||
rules: 'Security Rules',
|
||
rulesDesc: 'Manage built-in and custom security rules',
|
||
addRule: 'Add Rule',
|
||
editRule: 'Edit Rule',
|
||
columns: {
|
||
name: 'Rule Name',
|
||
severity: 'Severity',
|
||
category: 'Category',
|
||
pattern: 'Pattern',
|
||
decision: 'Decision',
|
||
enabled: 'Status',
|
||
builtin: 'Type',
|
||
actions: 'Actions',
|
||
},
|
||
builtinBadge: 'Built-in',
|
||
customBadge: 'Custom',
|
||
deleteConfirm: 'Delete rule "{name}"?',
|
||
fields: {
|
||
ruleId: 'Rule ID',
|
||
name: 'Name',
|
||
description: 'Description',
|
||
toolName: 'Target Tool',
|
||
pattern: 'Regex Pattern',
|
||
excludePattern: 'Exclude Pattern',
|
||
category: 'Category',
|
||
severity: 'Severity',
|
||
decision: 'Decision',
|
||
remediation: 'Remediation',
|
||
priority: 'Priority',
|
||
},
|
||
messages: {
|
||
ruleIdRequired: 'Rule ID is required',
|
||
nameRequired: 'Name is required',
|
||
patternRequired: 'Regex pattern is required',
|
||
ruleIdDuplicate: 'Rule ID already exists',
|
||
saveFailed: 'Failed to save rule',
|
||
},
|
||
},
|
||
fileGuard: {
|
||
title: 'File Guard',
|
||
desc: 'Manage sensitive file path protection',
|
||
enabled: 'Enable File Guard',
|
||
enabledHint: 'When enabled, sensitive file paths will be protected from unauthorized access',
|
||
sensitivePaths: 'Sensitive Paths',
|
||
sensitivePathsDesc: 'Configure file paths to protect (supports wildcards)',
|
||
addPath: 'Add Path',
|
||
pathPlaceholder: 'Type path and press Enter (e.g. ~/.ssh/)',
|
||
},
|
||
audit: {
|
||
title: 'Audit Logs',
|
||
desc: 'View tool security check records',
|
||
config: {
|
||
title: 'Audit Configuration',
|
||
enabled: 'Enable Audit Logging',
|
||
enabledHint: 'When disabled, tool invocation audit logs will not be recorded',
|
||
minSeverity: 'Minimum Severity',
|
||
minSeverityHint: 'Only record audit events at this severity level and above',
|
||
retentionDays: 'Retention Days',
|
||
retentionDaysHint: 'Audit logs older than this will be auto-cleaned (0=never)',
|
||
},
|
||
stats: {
|
||
total: 'Total Checks',
|
||
blocked: 'Blocked',
|
||
needsApproval: 'Needs Approval',
|
||
allowed: 'Allowed',
|
||
},
|
||
filters: {
|
||
toolName: 'Tool Name',
|
||
decision: 'Decision',
|
||
severity: 'Severity',
|
||
conversationId: 'Conversation ID',
|
||
},
|
||
columns: {
|
||
time: 'Time',
|
||
tool: 'Tool',
|
||
decision: 'Decision',
|
||
severity: 'Severity',
|
||
conversationId: 'Conversation',
|
||
},
|
||
noLogs: 'No audit logs yet',
|
||
expandFindings: 'Expand Details',
|
||
},
|
||
severity: {
|
||
CRITICAL: 'Critical',
|
||
HIGH: 'High',
|
||
MEDIUM: 'Medium',
|
||
LOW: 'Low',
|
||
INFO: 'Info',
|
||
},
|
||
decision: {
|
||
ALLOW: 'Allow',
|
||
NEEDS_APPROVAL: 'Needs Approval',
|
||
BLOCK: 'Block',
|
||
},
|
||
messages: {
|
||
loadFailed: 'Failed to load security config',
|
||
saveSuccess: 'Security config saved',
|
||
saveFailed: 'Failed to save security config',
|
||
ruleCreated: 'Rule created',
|
||
ruleUpdated: 'Rule updated',
|
||
ruleDeleted: 'Rule deleted',
|
||
ruleToggled: 'Rule status updated',
|
||
},
|
||
approval: {
|
||
title: 'Approval Required',
|
||
severity: 'Risk Level',
|
||
summary: 'Summary',
|
||
findings: 'Findings',
|
||
remediation: 'Remediation',
|
||
approved: 'Approved',
|
||
denied: 'Denied',
|
||
hint: 'Type /approve to allow, or /deny to reject',
|
||
},
|
||
},
|
||
tokenUsage: {
|
||
kicker: 'Runtime Cost',
|
||
title: 'Token Usage',
|
||
desc: 'View token consumption and model invocation statistics',
|
||
refresh: 'Refresh',
|
||
startDate: 'Start',
|
||
endDate: 'End',
|
||
promptTokens: 'Prompt Tokens',
|
||
completionTokens: 'Completion Tokens',
|
||
assistantMessages: 'Assistant Messages',
|
||
byModel: 'By Model',
|
||
byDate: 'By Date',
|
||
model: 'Model',
|
||
provider: 'Provider',
|
||
date: 'Date',
|
||
messageCount: 'Messages',
|
||
loadFailed: 'Failed to load token usage',
|
||
noData: 'No token usage data',
|
||
},
|
||
acp: {
|
||
kicker: 'External Agents',
|
||
title: 'ACP Endpoints',
|
||
desc: 'Delegate prompts to external coding agents (codex / claude-code / opencode / qwen-code) over stdio. Enable an endpoint after installing its CLI.',
|
||
addEndpoint: 'Add Endpoint',
|
||
builtin: 'Builtin',
|
||
test: 'Test',
|
||
testing: 'Testing...',
|
||
statusUnknown: 'untested',
|
||
empty: 'No ACP endpoints yet.',
|
||
loadFailed: 'Failed to load ACP endpoints',
|
||
saveFailed: 'Failed to save endpoint',
|
||
deleteTitle: 'Confirm Delete',
|
||
deleteConfirm: 'Delete ACP endpoint "{name}"? Builtin endpoints are protected.',
|
||
deleteFailed: 'Failed to delete endpoint',
|
||
toggleFailed: 'Failed to toggle endpoint',
|
||
invalidJson: 'Invalid JSON',
|
||
columns: {
|
||
name: 'Endpoint',
|
||
command: 'Command',
|
||
status: 'Last Test',
|
||
enabled: 'Enabled',
|
||
actions: 'Actions',
|
||
},
|
||
fields: {
|
||
name: 'Name (slug)',
|
||
displayName: 'Display name',
|
||
description: 'Description',
|
||
command: 'Command',
|
||
args: 'Args (JSON array)',
|
||
env: 'Environment variables',
|
||
toolParseMode: 'Tool parse mode',
|
||
enabled: 'Enabled',
|
||
},
|
||
env: {
|
||
formMode: 'Edit as JSON',
|
||
jsonMode: 'Edit as form',
|
||
suggested: 'Suggested',
|
||
addRow: 'Add variable',
|
||
keyPlaceholder: 'KEY_NAME',
|
||
valuePlaceholder: 'value (e.g. sk-…)',
|
||
show: 'Show',
|
||
hide: 'Hide',
|
||
remove: 'Remove',
|
||
hints: {
|
||
anthropic: 'Anthropic API key (sk-ant-…). Get one at https://console.anthropic.com/settings/keys',
|
||
openai: 'OpenAI API key (sk-…). Get one at https://platform.openai.com/api-keys',
|
||
dashscope: 'Aliyun DashScope key — same value as MateClaw .env DASHSCOPE_API_KEY',
|
||
google: 'Google AI Studio API key. Get one at https://aistudio.google.com/apikey',
|
||
claudeOauth: 'Heads up: claude-code OAuth login (the one stored in ~/.claude/) does NOT work here, and worse — the Claude Agent SDK reads it BEFORE this env var, silently shadowing your API key. If you have ever run `claude login` on this host, clear the keychain first: (macOS) `claude logout` or `security delete-generic-password -s "Claude Code-credentials"`; (Linux/Windows) delete ~/.claude/credentials.json. Then put a real API key (sk-ant-…) above. Or switch to qwen-code / opencode to reuse a CLI login.',
|
||
},
|
||
},
|
||
modal: {
|
||
newTitle: 'Add ACP Endpoint',
|
||
editTitle: 'Edit ACP Endpoint',
|
||
},
|
||
},
|
||
mcp: {
|
||
kicker: 'Capability Bridge',
|
||
title: 'MCP Connections',
|
||
desc: 'Manage MCP (Model Context Protocol) server connections',
|
||
addServer: 'Add Connection',
|
||
refreshAll: 'Refresh All',
|
||
columns: {
|
||
name: 'Name',
|
||
transport: 'Transport',
|
||
enabled: 'Status',
|
||
lastStatus: 'Connection',
|
||
lastConnectedTime: 'Last Connected',
|
||
toolCount: 'Tools',
|
||
description: 'Description',
|
||
actions: 'Actions',
|
||
},
|
||
status: {
|
||
connected: 'Connected',
|
||
disconnected: 'Disconnected',
|
||
error: 'Error',
|
||
},
|
||
transport: {
|
||
stdio: 'Stdio',
|
||
sse: 'SSE',
|
||
streamable_http: 'HTTP',
|
||
},
|
||
modal: {
|
||
newTitle: 'Add MCP Connection',
|
||
editTitle: 'Edit MCP Connection',
|
||
},
|
||
fields: {
|
||
name: 'Name',
|
||
description: 'Description',
|
||
transport: 'Transport',
|
||
url: 'URL',
|
||
headers: 'HTTP Headers (JSON)',
|
||
command: 'Command',
|
||
args: 'Arguments (JSON array)',
|
||
env: 'Environment Variables (JSON)',
|
||
cwd: 'Working Directory',
|
||
connectTimeout: 'Connect Timeout (seconds)',
|
||
readTimeout: 'Read Timeout (seconds)',
|
||
enabled: 'Enabled',
|
||
},
|
||
placeholders: {
|
||
name: 'Server name',
|
||
description: 'Brief description',
|
||
url: 'http://localhost:8080/sse',
|
||
headers: '',
|
||
command: 'npx',
|
||
args: '',
|
||
env: '',
|
||
cwd: '/path/to/dir',
|
||
},
|
||
actions: {
|
||
test: 'Test Connection',
|
||
testing: 'Testing...',
|
||
},
|
||
testResult: {
|
||
success: 'Connection successful',
|
||
failed: 'Connection failed',
|
||
tools: 'Discovered {count} tools',
|
||
latency: 'Latency {ms}ms',
|
||
},
|
||
messages: {
|
||
loadFailed: 'Failed to load MCP connections',
|
||
createSuccess: 'MCP connection created',
|
||
updateSuccess: 'MCP connection updated',
|
||
deleteSuccess: 'MCP connection deleted',
|
||
deleteConfirm: 'Delete MCP connection "{name}"?',
|
||
toggleSuccess: 'Status updated',
|
||
refreshSuccess: 'All connections refreshed',
|
||
saveFailed: 'Failed to save',
|
||
empty: 'No MCP connections',
|
||
emptyDesc: 'Add an MCP connection to extend your agents\' capabilities',
|
||
},
|
||
},
|
||
sessions: {
|
||
title: 'Sessions',
|
||
desc: 'View and manage all conversation sessions',
|
||
search: 'Search sessions...',
|
||
columns: {
|
||
session: 'Session',
|
||
source: 'Source',
|
||
agent: 'Agent',
|
||
messages: 'Messages',
|
||
status: 'Status',
|
||
lastActive: 'Last Active',
|
||
actions: 'Actions',
|
||
},
|
||
status: {
|
||
active: 'Active',
|
||
closed: 'Closed',
|
||
},
|
||
empty: 'No sessions found',
|
||
loadFailed: 'Failed to load sessions',
|
||
deleteConfirm: 'Are you sure you want to delete this session?',
|
||
deleteTitle: 'Confirm Delete',
|
||
deleteFailed: 'Failed to delete session',
|
||
time: {
|
||
justNow: 'Just now',
|
||
minutesAgo: '{n}m ago',
|
||
hoursAgo: '{n}h ago',
|
||
},
|
||
},
|
||
tools: {
|
||
kicker: 'Developer Catalog',
|
||
title: 'Tools (Catalog)',
|
||
desc: 'Atomic actions exposed by installed skills. Use the Skills page for end-user binding.',
|
||
registerButton: 'Register Tool',
|
||
columns: {
|
||
tool: 'Tool',
|
||
beanName: 'Bean Name',
|
||
type: 'Type',
|
||
status: 'Status',
|
||
actions: 'Actions',
|
||
},
|
||
empty: 'No tools registered',
|
||
modal: {
|
||
editTitle: 'Edit Tool',
|
||
newTitle: 'Register Tool',
|
||
},
|
||
fields: {
|
||
name: 'Name',
|
||
beanName: 'Bean Name',
|
||
type: 'Type',
|
||
description: 'Description',
|
||
},
|
||
placeholders: {
|
||
name: 'Tool name',
|
||
beanName: 'Spring Bean name',
|
||
description: 'Tool description',
|
||
},
|
||
types: {
|
||
builtin: 'Built-in',
|
||
mcp: 'MCP',
|
||
custom: 'Custom',
|
||
},
|
||
messages: {
|
||
saveFailed: 'Failed to save tool',
|
||
deleteConfirm: 'Are you sure you want to delete this tool?',
|
||
deleteTitle: 'Confirm Delete',
|
||
deleteFailed: 'Failed to delete tool',
|
||
toggleFailed: 'Failed to toggle tool status',
|
||
},
|
||
},
|
||
skillTemplates: {
|
||
kicker: 'Wizard',
|
||
title: 'Skill Templates',
|
||
desc: 'Pick a starter template, fill in a few fields, and a manifest skill is created in your workspace.',
|
||
backToSkills: '← Skills',
|
||
backToGallery: 'Back to gallery',
|
||
fields: 'fields',
|
||
useTemplate: 'Use template',
|
||
empty: 'No skill templates available yet.',
|
||
step1: 'Fill parameters',
|
||
step2: 'Preview',
|
||
step3: 'Done',
|
||
next: 'Next',
|
||
back: 'Back',
|
||
selectKb: '— Select Knowledge Base —',
|
||
previewHint: 'Preview of the SKILL.md that will be created. Click Install to commit.',
|
||
installSkill: 'Install Skill',
|
||
installing: 'Installing...',
|
||
installFailed: 'Installation failed',
|
||
installed: 'Skill installed',
|
||
installedDesc: '{name} is ready in your workspace.',
|
||
installAnother: 'Install another',
|
||
viewInSkills: 'View in Skills',
|
||
},
|
||
plugins: {
|
||
title: 'Plugins',
|
||
desc: 'Manage external plugins loaded from JAR files',
|
||
refresh: 'Refresh',
|
||
type: 'Type',
|
||
author: 'Author',
|
||
status: 'Status',
|
||
tools: 'Tools',
|
||
channels: 'Channels',
|
||
provider: 'Provider',
|
||
memoryProvider: 'Memory',
|
||
noDescription: 'No description',
|
||
emptyTitle: 'No plugins installed',
|
||
emptyHint: 'Place plugin JAR files in ~/.mateclaw/plugins/ and restart the server',
|
||
loading: 'Loading plugins...',
|
||
loadFailed: 'Failed to load plugins',
|
||
enabled: '{name} enabled',
|
||
disabled: '{name} disabled',
|
||
toggleFailed: 'Failed to toggle plugin status',
|
||
},
|
||
datasources: {
|
||
kicker: 'Data Fabric',
|
||
title: 'Datasources',
|
||
desc: 'Manage external database connections for natural language queries',
|
||
addButton: 'Add Datasource',
|
||
empty: 'No datasources configured. Click Add to get started.',
|
||
columns: {
|
||
name: 'Name',
|
||
type: 'Type',
|
||
connection: 'Connection',
|
||
status: 'Status',
|
||
actions: 'Actions',
|
||
},
|
||
sections: {
|
||
basic: 'Basic Info',
|
||
connection: 'Connection',
|
||
auth: 'Authentication',
|
||
advanced: 'Advanced',
|
||
},
|
||
modal: {
|
||
editTitle: 'Edit Datasource',
|
||
newTitle: 'Add Datasource',
|
||
},
|
||
fields: {
|
||
name: 'Name',
|
||
dbType: 'Database Type',
|
||
host: 'Host',
|
||
port: 'Port',
|
||
databaseName: 'Database Name',
|
||
schemaName: 'Schema',
|
||
username: 'Username',
|
||
password: 'Password',
|
||
description: 'Description',
|
||
extraParams: 'JDBC Parameters',
|
||
},
|
||
placeholders: {
|
||
name: 'e.g. Business Database',
|
||
host: '127.0.0.1',
|
||
port: '3306',
|
||
databaseName: 'Database name',
|
||
schemaName: 'public (default)',
|
||
username: 'Database username',
|
||
password: 'Database password',
|
||
description: 'What this datasource is for (optional)',
|
||
extraParams: 'useSSL=false&serverTimezone=UTC',
|
||
},
|
||
hints: {
|
||
extraParams: 'Additional JDBC URL parameters, separated by &',
|
||
},
|
||
testButton: 'Test Connection',
|
||
messages: {
|
||
saveFailed: 'Failed to save datasource',
|
||
deleteConfirm: 'Are you sure you want to delete this datasource? The agent will no longer be able to query it.',
|
||
deleteTitle: 'Confirm Delete',
|
||
deleteFailed: 'Failed to delete datasource',
|
||
toggleFailed: 'Failed to toggle datasource status',
|
||
testSuccess: 'Connection successful',
|
||
testFailed: 'Connection failed. Please check configuration.',
|
||
},
|
||
},
|
||
wiki: {
|
||
kicker: 'Knowledge Engine',
|
||
desc: 'AI-powered structured knowledge base that digests raw materials into Wiki pages',
|
||
createKB: 'New Knowledge Base',
|
||
knowledgeBases: 'Knowledge Bases',
|
||
noKB: 'No knowledge bases yet',
|
||
selectKB: 'Select a knowledge base',
|
||
library: {
|
||
countLabel: '{count} knowledge bases',
|
||
searchPlaceholder: 'Search knowledge bases...',
|
||
empty: 'No knowledge bases yet',
|
||
emptyHint: 'Click "New Knowledge Base" in the top right to start organizing your knowledge.',
|
||
noMatch: 'No matching knowledge bases',
|
||
open: 'Open',
|
||
pages: '{count} pages',
|
||
raws: '{count} materials',
|
||
noDescription: 'No description',
|
||
updatedAt: 'Updated {time}',
|
||
sortRecent: 'Recently updated',
|
||
sortName: 'Name',
|
||
sortPages: 'Pages',
|
||
backToLibrary: 'Back to library',
|
||
},
|
||
selectPage: 'Select a page from the sidebar',
|
||
pageKicker: 'Knowledge Page',
|
||
confirmDelete: 'Delete page "{title}"? This cannot be undone.',
|
||
confirmBatchDelete: 'Delete {count} pages? This cannot be undone.',
|
||
batchSelect: 'Batch select',
|
||
selectAll: 'Select all',
|
||
kbName: 'Name',
|
||
kbNamePlaceholder: 'Enter knowledge base name',
|
||
kbDescription: 'Description',
|
||
kbDescPlaceholder: 'Briefly describe the knowledge base purpose',
|
||
rawMaterials: 'Raw Materials',
|
||
pages: 'Wiki Pages',
|
||
config: 'Config',
|
||
transformations: {
|
||
tab: 'Transformations',
|
||
title: 'Transformations',
|
||
desc: 'Reusable prompt templates. Each template runs against one raw material; the generated content is persisted here. Toggle "apply default" to fire it automatically after every successful ingest.',
|
||
empty: 'No transformations yet — create one to get started.',
|
||
createBtn: 'New transformation',
|
||
editBtn: 'Edit',
|
||
deleteBtn: 'Delete',
|
||
deleteConfirm: 'Delete this transformation? Past run history is kept.',
|
||
enabled: 'Enabled',
|
||
disabled: 'Disabled',
|
||
applyDefault: 'Apply by default',
|
||
applyDefaultOn: 'Runs automatically after each ingest completes',
|
||
applyDefaultOff: 'Manual or agent-tool runs only',
|
||
modelLabel: 'Model',
|
||
modelDefault: 'Default (KB / system)',
|
||
modelHelp: 'Falls back to the KB-bound chat model or the system default; once chosen this template always uses the specified model',
|
||
outputTargetLabel: 'Output target',
|
||
outputTargetNone: 'None — output stays in run history',
|
||
outputTargetPage: 'Save as wiki page (searchable / agent-accessible / linkable)',
|
||
outputTargetPageBadge: 'Auto-save to page',
|
||
outputFormatLabel: 'Output format',
|
||
outputFormatMarkdown: 'Markdown (default, human-readable)',
|
||
outputFormatJson: 'JSON (structured for downstream tools; one auto-retry on parse failure)',
|
||
outputFormatJsonBadge: 'JSON',
|
||
outputSchemaLabel: 'JSON Schema (optional)',
|
||
outputSchemaHelp: 'Schema text is injected into the prompt and checked for required fields after parsing. Leave blank to skip validation.',
|
||
outputSchemaPlaceholder: '{\n "type": "object",\n "required": ["title", "items"],\n "properties": {\n "title": { "type": "string" },\n "items": { "type": "array" }\n }\n}',
|
||
outputSchemaBadge: 'Schema',
|
||
saveAsPageBtn: 'Save as page',
|
||
saving: 'Saving…',
|
||
savedAsPage: 'Saved as:',
|
||
saveAsPageDone: 'Saved as wiki page',
|
||
saveAsPageFailed: 'Save as page failed',
|
||
openPage: 'Open page',
|
||
scope: 'Scope',
|
||
scopeKb: 'This knowledge base only',
|
||
scopeWorkspace: 'Workspace-wide',
|
||
name: 'Name',
|
||
namePlaceholder: 'e.g. risk-extract',
|
||
nameHelp: 'Used by agent tools; lowercase letters / digits / hyphens',
|
||
title2: 'Title',
|
||
titlePlaceholder: 'e.g. Contract risk extraction',
|
||
description: 'Description',
|
||
descriptionPlaceholder: 'One line about what this transformation produces',
|
||
prompt: 'Prompt template',
|
||
promptHelp: 'Supports {input_text} and {title} placeholders',
|
||
saveBtn: 'Save',
|
||
cancelBtn: 'Cancel',
|
||
compareBtn: 'Compare selected',
|
||
compareHint: 'Pick 1 more run to compare',
|
||
compareCheckTip: 'Tick 2 completed runs to compare side-by-side',
|
||
compareTitle: 'Compare runs',
|
||
aggregateBtn: 'Aggregate all runs',
|
||
aggregating: 'Aggregating…',
|
||
aggregateDone: 'Aggregate page produced',
|
||
aggregateFailed: 'Aggregate failed',
|
||
aggregateNoRuns: 'This template has no completed runs to aggregate yet',
|
||
runs: 'Run history',
|
||
rerunBtn: 'Re-run',
|
||
rerunning: 'Re-running…',
|
||
cancelRunBtn: 'Cancel',
|
||
cancelling: 'Cancelling…',
|
||
cancelDone: 'Cancelled',
|
||
cancelFailed: 'Cancel failed',
|
||
runOn: 'Ran on',
|
||
runStatus: 'Status',
|
||
runDuration: 'Duration',
|
||
runOutput: 'Output',
|
||
runError: 'Error',
|
||
runApply: 'Run',
|
||
running: 'Running…',
|
||
runFailed: 'Run failed',
|
||
pickRaw: 'Pick a raw material',
|
||
pickRawHint: 'Select a raw material to use as input',
|
||
noRuns: 'No runs yet.',
|
||
},
|
||
hotCache: {
|
||
tab: 'Hot Cache',
|
||
title: 'Recent Activity Snapshot (Hot Cache)',
|
||
desc: 'A rolling markdown digest of what has been happening in this knowledge base, injected into the agent system prompt so chat does not have to re-search the obvious. Rebuilt asynchronously by the listener with a 5-minute debounce.',
|
||
empty: 'No snapshot yet — one will be built after the bound agent finishes its next conversation.',
|
||
contentEmpty: '(snapshot body is empty)',
|
||
regenerate: 'Rebuild now',
|
||
regenerating: 'Rebuilding…',
|
||
regenerateQueued: 'Rebuild queued; refreshing in a few seconds',
|
||
regenerateFailed: 'Failed to schedule rebuild',
|
||
reset: 'Clear snapshot',
|
||
resetConfirm: 'Clear the current snapshot? The next agent conversation will regenerate it.',
|
||
resetDone: 'Cleared',
|
||
resetFailed: 'Clear failed',
|
||
lastUpdated: 'Last updated',
|
||
updateReason: 'Trigger reason',
|
||
rebuildCount: 'Rebuilds',
|
||
lastDuration: 'Last duration',
|
||
lastError: 'Last error',
|
||
footer: 'Toggling wiki.hot_cache.enabled off short-circuits the injection path. The "Rebuild now" button bypasses the debounce window for easier debugging.',
|
||
},
|
||
searchPages: 'Search pages...',
|
||
dropFiles: 'Drop files here or click to upload',
|
||
dropToUpload: 'Release to upload',
|
||
uploading: 'Uploading…',
|
||
uploadFailed: 'Upload failed: {name}',
|
||
addText: 'Add Text',
|
||
noRawMaterials: 'No raw materials yet',
|
||
reprocess: 'Reprocess',
|
||
resume: 'Resume',
|
||
cancel: 'Cancel processing',
|
||
cancelling: 'Cancelling…',
|
||
cancelledHint: 'Cancelled by user',
|
||
download: 'Download original file',
|
||
downloadFailed: 'Download failed',
|
||
processAll: 'Process All Pending',
|
||
materialTitle: 'Title',
|
||
materialContent: 'Content',
|
||
pasteContent: 'Paste or type content here...',
|
||
backlinks: 'Backlinks',
|
||
generatedByAi: 'AI generated',
|
||
editedManually: 'Manually edited',
|
||
configTitle: 'Wiki Processing Rules',
|
||
configDesc: 'Configure the rules AI follows when digesting raw materials',
|
||
configPlaceholder: 'Edit wiki processing rules here...',
|
||
pageCount: '{count} pages',
|
||
sourceCount: '{count} sources',
|
||
dirPlaceholder: 'Enter local directory path, e.g. /Users/me/docs',
|
||
scan: 'Scan',
|
||
scanning: 'Scanning...',
|
||
scanResult: 'Scanned {scanned} files, added {added}, skipped {skipped}',
|
||
saving: 'Saving...',
|
||
status: {
|
||
active: 'ACTIVE',
|
||
uploading: 'UPLOADING',
|
||
processing: 'PROCESSING',
|
||
error: 'ERROR',
|
||
pending: 'PENDING',
|
||
completed: 'COMPLETED',
|
||
partial: 'PARTIAL',
|
||
failed: 'FAILED',
|
||
cancelled: 'CANCELLED',
|
||
cancelling: 'CANCELLING…',
|
||
},
|
||
progress: {
|
||
preparing: 'Preparing…',
|
||
uploading: 'Uploading {pct}%',
|
||
},
|
||
jobStage: {
|
||
queued: 'Queued',
|
||
routing: 'Routing',
|
||
phase_a_running: 'Analyzing',
|
||
phase_a_done: 'Analyzed',
|
||
phase_b_running: 'Generating',
|
||
enriching: 'Linking',
|
||
embedding: 'Embedding',
|
||
completed: 'Completed',
|
||
failed: 'Failed',
|
||
cancelled: 'Cancelled',
|
||
},
|
||
jobInfo: {
|
||
currentModel: 'Model',
|
||
fallbackActive: 'Fallback active',
|
||
elapsedTime: 'Elapsed',
|
||
pagesProgress: '{done}/{total} pages',
|
||
},
|
||
page: {
|
||
type: {
|
||
entity: 'Entity',
|
||
concept: 'Concept',
|
||
source: 'Source',
|
||
synthesis: 'Synthesis',
|
||
},
|
||
enriched: 'Linked',
|
||
notEnriched: 'Not linked',
|
||
enrich: 'Add cross-links',
|
||
repair: 'Repair page',
|
||
citations: '{count} source chunks',
|
||
noCitations: 'No source citations found',
|
||
citationUnknownSource: 'Unknown source',
|
||
citationChunkN: 'Chunk {n}',
|
||
citationChunkUnknown: 'Chunk unknown',
|
||
citationOffset: 'offset {start}–{end}',
|
||
},
|
||
relation: {
|
||
shared_chunk: 'Shared chunk',
|
||
shared_raw: 'Shared source',
|
||
direct_link: 'Direct link',
|
||
semantic_near: 'Semantic',
|
||
relatedPages: 'Related Pages',
|
||
explainRelation: 'Explain relation',
|
||
},
|
||
configPanel: {
|
||
embeddingModel: 'Embedding Model',
|
||
embeddingModelHint: 'Semantic search model for this KB; leave empty for system default',
|
||
ingestMode: 'Ingest Mode',
|
||
ingestModeEager: 'Eager',
|
||
ingestModeLazy: 'Lazy',
|
||
ingestModeEagerHint: 'Upload runs the full LLM pipeline to generate wiki pages immediately.',
|
||
ingestModeLazyHint: 'Upload only extracts, chunks, and embeds. No page generation; search works right away.',
|
||
modelStrategy: 'Model Strategy',
|
||
globalDefault: 'Global default',
|
||
selectModel: 'Select a model…',
|
||
otherProvider: 'Other',
|
||
searchModel: 'Search models…',
|
||
noModelMatch: 'No matching models',
|
||
addFallback: '+ Add fallback',
|
||
stepModel: {
|
||
route: 'Analysis / Routing',
|
||
create_page: 'Page Creation',
|
||
merge_page: 'Page Merge',
|
||
enrich: 'Link Annotation',
|
||
summary: 'Summary Update',
|
||
},
|
||
fallbackModels: 'Fallback Models',
|
||
searchPreview: 'Search Preview',
|
||
searchPreviewPlaceholder: 'Enter a user message to preview agent search results…',
|
||
searchPreviewRun: 'Test',
|
||
},
|
||
stats: {
|
||
enrichedRatio: '{enriched}/{total} linked',
|
||
failedJobs: '{count} failed',
|
||
},
|
||
noPages: 'No pages yet',
|
||
noResults: 'No pages match your search',
|
||
loadMore: 'Load {n} more',
|
||
filteredByRaw: 'Filtered by source material',
|
||
clearFilter: 'Clear filter',
|
||
systemPageBadge: 'System',
|
||
systemPageHint: 'overview / log are built-in system pages — they can\'t be deleted',
|
||
lockedPageBadge: 'Locked',
|
||
lockedPageHint: 'This page is locked — AI tools and batch operations skip it',
|
||
archivedSection: 'Archived',
|
||
noArchived: 'No archived pages',
|
||
unarchive: 'Restore',
|
||
pageTypes: {
|
||
concept: 'Concepts',
|
||
person: 'People',
|
||
place: 'Places',
|
||
event: 'Events',
|
||
technology: 'Technology',
|
||
organization: 'Organizations',
|
||
product: 'Products',
|
||
term: 'Terms',
|
||
process: 'Processes',
|
||
other: 'Other',
|
||
},
|
||
graph: {
|
||
tab: 'Knowledge Graph',
|
||
nodes: 'nodes',
|
||
edges: 'edges',
|
||
orphans: 'orphans',
|
||
showOrphans: 'Show orphans',
|
||
allTypes: 'All types',
|
||
resetView: 'Reset view',
|
||
fullscreen: 'Fullscreen',
|
||
exitFullscreen: 'Exit fullscreen',
|
||
linksTo: 'Links to',
|
||
openPage: 'Open page',
|
||
empty: 'No graph data — process some raw materials first',
|
||
},
|
||
},
|
||
cronJobs: {
|
||
kicker: 'Automation',
|
||
title: 'Cron Jobs',
|
||
desc: 'Schedule agents to run messages or goals on a timer',
|
||
createJob: 'New Job',
|
||
editJob: 'Edit Job',
|
||
noJobs: 'No cron jobs yet',
|
||
createFirst: 'Create your first cron job',
|
||
columns: {
|
||
name: 'Name',
|
||
agent: 'Agent',
|
||
taskType: 'Type',
|
||
cron: 'Cron Expression',
|
||
timezone: 'Timezone',
|
||
nextRun: 'Next Run',
|
||
lastRun: 'Last Run',
|
||
enabled: 'Enabled',
|
||
actions: 'Actions',
|
||
// RFC-063r §2.14: list-page "Last Delivery" column
|
||
lastDelivery: 'Last Delivery',
|
||
// RFC-063r post-deploy: channel binding columns
|
||
channel: 'Channel',
|
||
targetId: 'Delivery Target',
|
||
},
|
||
// RFC-063r §2.14: delivery_status state machine labels
|
||
lastDelivery: {
|
||
none: 'No delivery',
|
||
pending: 'In flight',
|
||
delivered: 'Delivered',
|
||
not_delivered: 'Failed',
|
||
},
|
||
taskTypes: { text: 'Text Message', reminder: 'Reminder', agent: 'Agent Goal' },
|
||
cronTypes: { hourly: 'Hourly', daily: 'Daily', weekly: 'Weekly', custom: 'Custom' },
|
||
days: { mon: 'Mon', tue: 'Tue', wed: 'Wed', thu: 'Thu', fri: 'Fri', sat: 'Sat', sun: 'Sun' },
|
||
fields: {
|
||
name: 'Job Name',
|
||
namePlaceholder: 'Enter job name',
|
||
agent: 'Agent',
|
||
agentPlaceholder: 'Select agent',
|
||
taskType: 'Task Type',
|
||
triggerMessage: 'Trigger Message',
|
||
triggerMessagePlaceholder: 'Message to send to the agent',
|
||
reminderText: 'Reminder Text',
|
||
reminderTextPlaceholder: 'Exact text to push when the reminder fires (no LLM rewriting)',
|
||
requestBody: 'Goal',
|
||
requestBodyPlaceholder: 'Describe the goal for the agent',
|
||
cronFrequency: 'Frequency',
|
||
cronTime: 'Time',
|
||
cronDays: 'Days',
|
||
cronExpression: 'Custom Expression',
|
||
cronExpressionPlaceholder: 'min hour day month weekday, e.g. 0 9 * * 1-5',
|
||
timezone: 'Timezone',
|
||
enabled: 'Enable immediately',
|
||
},
|
||
actions: { runNow: 'Run Now', edit: 'Edit', delete: 'Delete' },
|
||
messages: {
|
||
createSuccess: 'Cron job created',
|
||
updateSuccess: 'Cron job updated',
|
||
deleteSuccess: 'Cron job deleted',
|
||
deleteConfirm: 'Delete job "{name}"? This cannot be undone.',
|
||
runTriggered: 'Job triggered. Check conversation "cron_{id}" for results.',
|
||
enableSuccess: 'Job enabled',
|
||
disableSuccess: 'Job disabled',
|
||
invalidCron: 'Invalid cron expression. Use 5-field format (min hour day month weekday).',
|
||
agentRequired: 'Please select an agent',
|
||
textRequired: 'Trigger message is required',
|
||
goalRequired: 'Goal is required',
|
||
},
|
||
},
|
||
workflows: {
|
||
kicker: 'Workflows',
|
||
title: 'Workflow Editor',
|
||
desc: 'Author multi-step workflows. Save the draft as you go, compile to surface diagnostics, then publish a revision when it is ready to run.',
|
||
newWorkflow: '+ New Workflow',
|
||
defined: 'Defined ({count})',
|
||
refresh: 'Refresh',
|
||
unnamed: '(unnamed)',
|
||
draftBadge: 'draft',
|
||
publishedBadge: 'v{rev}',
|
||
listEmpty: 'No workflows yet — create one to get started.',
|
||
namePlaceholder: 'Workflow name',
|
||
descPlaceholder: 'Optional description',
|
||
actions: {
|
||
saveMeta: 'Save Meta',
|
||
saveDraft: 'Save Draft',
|
||
compile: 'Compile',
|
||
publish: 'Publish',
|
||
delete: 'Delete',
|
||
},
|
||
bodyPlaceholder: '{\'{"steps":[{"name":"step-a","agentId":1,"mode":{"type":"sequential"},"promptTemplate":"..."}]}\'}',
|
||
compileErrorsTitle: '{count} compile error(s)',
|
||
templates: {
|
||
label: 'Insert template',
|
||
placeholder: 'Pick a step template',
|
||
sequential: 'Sequential step',
|
||
fan_out: 'Parallel fan-out',
|
||
collect: 'Collect results',
|
||
conditional: 'Conditional branch',
|
||
await_approval: 'Await approval',
|
||
dispatch_channel: 'Dispatch message',
|
||
write_memory: 'Write memory',
|
||
},
|
||
jsonInvalid: 'JSON parse failed: {msg}',
|
||
jsonOk: 'JSON syntax OK.',
|
||
tabs: {
|
||
canvas: 'Canvas',
|
||
json: 'JSON',
|
||
runs: 'Runs ({count})',
|
||
},
|
||
canvas: {
|
||
empty: 'The current draft has no steps. Add one in the JSON editor or pick a template.',
|
||
layoutLR: 'Horizontal',
|
||
layoutTB: 'Vertical',
|
||
stats: '{nodes} nodes · {edges} edges',
|
||
parseError: 'JSON parse failed: {msg}',
|
||
fullscreenEnter: 'Fullscreen',
|
||
fullscreenExit: 'Exit fullscreen',
|
||
addNode: '+ Add node',
|
||
modeLabel: 'Mode',
|
||
nodeAgent: 'Digital employee',
|
||
nodeExpression: 'Condition',
|
||
nodeApprovalKind: 'Approval',
|
||
nodeChannels: 'Channels',
|
||
nodeMergeStrategy: 'Merge',
|
||
approvalDefault: 'manual',
|
||
channelsEmpty: 'unspecified',
|
||
modeLabels: {
|
||
sequential: 'sequential',
|
||
fan_out: 'fan out',
|
||
collect: 'collect',
|
||
conditional: 'conditional',
|
||
await_approval: 'await approval',
|
||
dispatch_channel: 'dispatch',
|
||
write_memory: 'write memory',
|
||
},
|
||
inspector: {
|
||
title: 'Step properties',
|
||
empty: 'Click a node on the canvas to inspect it.',
|
||
rawHeader: 'Raw step JSON',
|
||
shared: 'Shared fields',
|
||
modeFields: '{mode} fields',
|
||
modeNoFields: 'This mode takes no extra fields.',
|
||
duplicate: 'Duplicate step',
|
||
delete: 'Delete step',
|
||
},
|
||
fields: {
|
||
name: 'Name',
|
||
namePlaceholder: 'step-name',
|
||
agentPlaceholder: 'Select digital employee',
|
||
agentMissing: 'Current digital employee is not in the list: {name}',
|
||
promptTemplate: 'Prompt template',
|
||
// promptPlaceholder is intentionally not localized — hardcoded in
|
||
// StepPropertyPanel so vue-i18n's parser never sees the Pebble braces.
|
||
outputVar: 'Output variable',
|
||
outputVarPlaceholder: 'data',
|
||
outputContentType: 'Output type',
|
||
approvalKind: 'Approval kind',
|
||
approverChannels: 'Approver channels (comma-sep)',
|
||
approvalMessage: 'Approval message',
|
||
timeoutSecs: 'Timeout (s)',
|
||
channels: 'Dispatch channels',
|
||
channelsEmptyHint: 'No enabled channels in this workspace. Enable one in Channel Management first.',
|
||
channelsUnknown: 'Draft references unavailable channels: {channels}',
|
||
dispatchTarget: '{channel} target',
|
||
dispatchTargetPlaceholder: 'Group ID / user ID / conversation ID',
|
||
dispatchContent: 'Message content',
|
||
employeeId: 'Employee ID',
|
||
memoryFile: 'Memory file',
|
||
memoryContent: 'Content template',
|
||
},
|
||
},
|
||
dialogs: {
|
||
createTitle: 'New workflow',
|
||
fieldName: 'Name',
|
||
namePlaceholder: 'e.g. employee-onboarding',
|
||
fieldDescription: 'Description',
|
||
descriptionPlaceholder: 'Optional. One or two sentences on what this workflow does.',
|
||
createSubmit: 'Create',
|
||
publishTitle: 'Publish workflow',
|
||
publishHint: 'Publishing compiles the current draft into a new revision. Running instances stay on their current revision.',
|
||
publishNote: 'Publish note',
|
||
publishNotePlaceholder: 'Optional summary of what changed.',
|
||
deleteTitle: 'Delete workflow',
|
||
deleteContent: 'Delete workflow "{name}"? This is reversible via the audit log.',
|
||
},
|
||
selectHint: 'Select a workflow on the left, or click "New Workflow" to start a fresh draft.',
|
||
generate: {
|
||
entryButton: 'Generate from description',
|
||
title: 'Generate workflow draft from natural language',
|
||
hint: 'Describe your business process in a sentence — the AI generates a workflow JSON draft. The draft is saved unpublished and no triggers are auto-enabled; you review and publish afterwards.',
|
||
placeholder: 'e.g. Every Monday at 9 AM, the sales agent summarises last week\'s data; once the manager approves, post to the Feishu ops group',
|
||
submit: 'Generate',
|
||
running: 'Generating…',
|
||
retry: 'Try again',
|
||
accept: 'Accept & open editor',
|
||
compileOk: 'Compile preview OK',
|
||
compileFail: 'Compile preview failed ({count})',
|
||
compileChecking: 'Validating…',
|
||
compileError: 'compile error',
|
||
missing: 'missing',
|
||
warning: 'warning',
|
||
previewDraft: 'Preview generated JSON',
|
||
failed: 'Generate failed: {msg}',
|
||
acceptedWithTriggers: 'Draft saved and {count} trigger(s) created (disabled by default)',
|
||
acceptedSomeTriggersFailed: 'Draft saved; {ok} trigger(s) created, {fail} failed',
|
||
triggersTitle: 'Suggested triggers',
|
||
triggersHint: 'Created with enabled=false; toggle them on later from the Triggers page.',
|
||
applyTemplate: 'Apply template (skip the AI roundtrip)',
|
||
applyTemplatePlaceholder: '— Pick a canonical pattern —',
|
||
},
|
||
paused: {
|
||
header: 'Paused runs ({count})',
|
||
empty: 'No paused runs.',
|
||
pauseTokenLabel: 'pause token',
|
||
deadlineLabel: 'deadline',
|
||
pausedAtLabel: 'paused at',
|
||
runHash: 'Run #{id}',
|
||
resumeApproved: 'Approve',
|
||
resumeRejected: 'Reject',
|
||
resumeTimeout: 'Time out',
|
||
resumeCancelled: 'Cancel',
|
||
resumeOk: 'Run resumed ({outcome}).',
|
||
resumeFailed: 'Resume failed: {msg}',
|
||
},
|
||
runs: {
|
||
header: 'Recent runs ({count})',
|
||
empty: 'No runs yet.',
|
||
detailTitle: 'Run #{id} — {state}',
|
||
runHash: 'run #{id}',
|
||
},
|
||
prompts: {
|
||
newName: 'New workflow name:',
|
||
defaultName: 'untitled-workflow',
|
||
publishNote: 'Optional publish note:',
|
||
deleteConfirm: 'Delete workflow "{name}"? This is reversible via the audit log.',
|
||
},
|
||
status: {
|
||
metaSaved: 'Metadata saved.',
|
||
draftSaved: 'Draft saved.',
|
||
compileOk: 'Compile OK.',
|
||
published: 'Published.',
|
||
deleted: 'Deleted.',
|
||
createFailed: 'Create failed: {msg}',
|
||
saveFailed: 'Save failed: {msg}',
|
||
saveDraftFailed: 'Save draft failed: {msg}',
|
||
deleteFailed: 'Delete failed: {msg}',
|
||
compileFailed: '{count} compile error(s) — see panel below.',
|
||
compileFallback: 'Compile / publish failed.',
|
||
},
|
||
},
|
||
triggers: {
|
||
kicker: 'Triggers',
|
||
title: 'Workflow Triggers',
|
||
desc: 'Connect cron schedules and channel events to your published workflows. pattern_version increments on every cron expression change so multi-node deployments coordinate correctly.',
|
||
newTrigger: '+ New Trigger',
|
||
columns: {
|
||
name: 'Name',
|
||
pattern: 'Pattern',
|
||
target: 'Target Workflow',
|
||
rate: 'Rate',
|
||
fires: 'Fires',
|
||
patternVersion: 'pattern_v',
|
||
lastFired: 'Last fired',
|
||
state: 'State',
|
||
actions: 'Actions',
|
||
},
|
||
targetWorkflowSelect: 'Pick a published workflow',
|
||
targetWorkflowEmpty: 'No published workflows yet.',
|
||
lastDispatchedAt: 'Last attempt',
|
||
patternTypeLabels: {
|
||
cron: 'Cron schedule',
|
||
channel_message: 'Channel message',
|
||
content_match: 'Content match',
|
||
agent_lifecycle: 'Agent lifecycle',
|
||
workflow_completion: 'Workflow completion',
|
||
webhook: 'Webhook',
|
||
},
|
||
patternHints: {
|
||
cron: 'Example: {"cron":"0 0 * * * *","timezone":"UTC"} — every cron change bumps pattern_version.',
|
||
channel_message: 'Optional channelType (e.g. feishu), senderEquals and contentContains narrow the match.',
|
||
webhook: 'Pass-through match. Ensure the HTTP entry validates the webhook secret.',
|
||
content_match: 'Requires substring (case-insensitive). Empty strings refuse to fire.',
|
||
agent_lifecycle: 'Optional agentId and phase (spawned / terminated / crashed).',
|
||
workflow_completion: 'Optional sourceWorkflowId and stateFilter (completed / failed / any).',
|
||
},
|
||
pattern: {
|
||
cronExpression: 'Cron expression',
|
||
cronExpressionPlaceholder: '0 0 * * * *',
|
||
cronExpressionHint: '5 fields (min hour day month weekday) or 6 fields (with seconds). Each change bumps pattern_version.',
|
||
cronTimezone: 'Timezone',
|
||
cronTimezonePlaceholder: 'UTC',
|
||
channelType: 'Channel type',
|
||
channelTypeAny: 'Any channel',
|
||
senderEquals: 'Sender equals',
|
||
senderEqualsPlaceholder: 'Optional sender ID',
|
||
senderEqualsHint: 'Empty matches any sender; filled narrows to that one sender.',
|
||
contentContains: 'Message contains',
|
||
contentContainsPlaceholder: 'Optional keyword',
|
||
contentContainsHint: 'Case-insensitive substring on the message body. Empty matches any content.',
|
||
substring: 'Substring',
|
||
substringPlaceholder: 'order',
|
||
substringHint: 'Case-insensitive. Empty strings refuse to fire (no broadcast trap).',
|
||
agentId: 'Agent ID',
|
||
agentIdPlaceholder: '0 means any',
|
||
agentIdHint: 'Empty or 0 matches any agent.',
|
||
phase: 'Lifecycle phase',
|
||
phaseAny: 'Any phase',
|
||
sourceWorkflowId: 'Source workflow',
|
||
sourceWorkflowAny: 'Any upstream',
|
||
stateFilter: 'Completion state',
|
||
stateFilterAny: 'Any state',
|
||
stateFilterHint: 'completed is an alias for succeeded; failed only matches failed terminal runs.',
|
||
webhookHeader: 'Webhook pass-through',
|
||
webhookBody: 'No filtering on the UI side — make sure the HTTP entry validates the webhook secret; every accepted request reaches the trigger.',
|
||
rawHeader: 'Raw pattern_json (advanced)',
|
||
errCronRequired: 'Cron expression cannot be empty',
|
||
errCronShape: 'Cron must be 5–7 fields',
|
||
errSubstringRequired: 'Substring cannot be empty or the trigger never fires',
|
||
},
|
||
unnamed: '(unnamed)',
|
||
rateUnit: '{count}/min',
|
||
enabled: 'enabled',
|
||
disabled: 'disabled',
|
||
empty: 'No triggers configured.',
|
||
actions: {
|
||
edit: 'Edit',
|
||
delete: 'Delete',
|
||
cancel: 'Cancel',
|
||
save: 'Save',
|
||
close: 'Close',
|
||
},
|
||
formTitleNew: 'New Trigger',
|
||
formTitleEdit: 'Edit Trigger',
|
||
fields: {
|
||
name: 'Name',
|
||
namePlaceholder: 'hourly-cleanup',
|
||
patternType: 'Pattern type',
|
||
patternJson: 'Pattern JSON',
|
||
patternJsonPlaceholder: '{\'{"cron":"0 0 * * * *","timezone":"UTC"}\'}',
|
||
targetType: 'Target type',
|
||
targetId: 'Target id',
|
||
ratePerMin: 'Rate / min',
|
||
dedupWindowSecs: 'Dedup window (s)',
|
||
maxFires: 'Max fires (0 = unlimited)',
|
||
botSelfFilter: 'Bot-self filter (recommended)',
|
||
payloadTemplate: 'Payload template (Pebble)',
|
||
payloadTemplatePlaceholder: '{\'{"who":"{{ event.who }}"}\'}',
|
||
enabled: 'Enabled',
|
||
},
|
||
deleteConfirm: 'Delete trigger "{name}"?',
|
||
saveFailed: 'Save failed: {msg}',
|
||
toggleFailed: 'Toggle failed: {msg}',
|
||
deleteFailed: 'Delete failed: {msg}',
|
||
},
|
||
login: {
|
||
kicker: 'AI Operating System',
|
||
subtitle: 'Your intelligent AI assistant',
|
||
heroTitle: 'Move beyond answers. Put AI inside a system that can keep working.',
|
||
heroDesc: 'MateClaw is not about stuffing more capability into a chat box. It is about pulling context, knowledge, execution, and memory into one reliable operating surface.',
|
||
pointContext: 'Keep context continuous',
|
||
pointKnowledge: 'Organize knowledge into use',
|
||
pointExecution: 'Turn capability into action',
|
||
cardTitle: 'Sign in to the working surface',
|
||
cardDesc: 'Enter the system where models, knowledge, workspace, and runtime state move together instead of living in separate tools.',
|
||
fields: {
|
||
username: 'Username',
|
||
password: 'Password',
|
||
},
|
||
placeholders: {
|
||
username: 'Enter username',
|
||
password: 'Enter password',
|
||
},
|
||
signIn: 'Sign In',
|
||
hint: 'Default: <code>admin</code> / <code>admin123</code>',
|
||
failed: 'Login failed. Please check your credentials.',
|
||
},
|
||
enterprise: {
|
||
eyebrow: 'Enterprise',
|
||
title: 'Enterprise AI Workbench',
|
||
subtitle: 'Verifiable judgment with cited evidence, owned approvals, and a complete audit trail — AI inside enterprise workflows, not yet another chatbox.',
|
||
tabs: { overview: 'Overview', contract: 'Contract Review', account: 'Account Intel', approvals: 'Approvals', audit: 'Audit' },
|
||
risk: { high: 'High', medium: 'Medium', low: 'Low' },
|
||
status: { aiReviewed: 'AI Reviewed', pendingLegal: 'Legal Pending', approved: 'Approved', signal: 'Signal' },
|
||
overview: {
|
||
metricPending: 'Pending', metricHighRisk: 'High Risk', metricAccounts: 'Accounts', metricCited: 'Cited',
|
||
queueTitle: 'Work Queue',
|
||
queueDesc: 'Today\'s items for legal / sales / compliance, each carrying an AI judgment and source citation.',
|
||
evidenceTitle: 'Recent Evidence',
|
||
evidenceDesc: 'Source quotes, playbook clauses, and historical precedents the AI cited.',
|
||
coverageNote: 'of this week\'s judgments link to a verifiable source',
|
||
tagSource: 'source', tagPlaybook: 'playbook', tagPrecedent: 'precedent',
|
||
filterAll: 'All', filterHighRisk: 'High Risk', filterPending: 'Legal Pending', filterToday: 'Today',
|
||
pipelineTitle: 'Contract Review Pipeline',
|
||
pipelineDesc: 'Standard flow from upload to archive — every step leaves a trace.',
|
||
step1: 'Upload', step1Desc: 'Legal or sales drops a PDF',
|
||
step2: 'Extract', step2Desc: 'OCR / text extraction',
|
||
step3: 'AI Review', step3Desc: 'Clause-level risk + playbook diff',
|
||
step4: 'Legal Review', step4Desc: 'Human in the loop',
|
||
step5: 'Approve / Archive', step5Desc: 'Approval chain + audit',
|
||
},
|
||
contract: {
|
||
listTitle: 'Contracts', filterAll: 'All', filterHigh: 'High', filterPending: 'Pending',
|
||
clausesFound: 'clause deviations', deviation: 'Deviation', suggestion: 'AI suggested rewrite',
|
||
approvalChain: 'Approval Chain',
|
||
btnApprove: 'Approve', btnReject: 'Reject', btnRequestRevision: 'Request revision',
|
||
evidenceTitle: 'Evidence', sourceContract: 'Source contract', playbookRule: 'Playbook rule', precedents: 'Precedents',
|
||
confidence: 'Confidence', model: 'Model',
|
||
},
|
||
account: {
|
||
listTitle: 'Accounts', filterAll: 'All', filterHot: 'Hot', filterCooling: 'Cooling',
|
||
opportunityScore: 'Opportunity Score', aum: 'Size',
|
||
keyPeople: 'Key People',
|
||
timelineTitle: 'Account Timeline',
|
||
tlAll: 'All', tlPublic: 'Public', tlMeeting: 'Meetings', tlDoc: 'Docs',
|
||
evidence: 'Evidence',
|
||
actionsTitle: 'Recommended Actions',
|
||
actionsSub: 'Next steps inferred from timeline signals, ranked by priority.',
|
||
btnDoIt: 'Do it', btnSnooze: 'Snooze',
|
||
stage: { prospect: 'Prospect', qualified: 'Qualified', proposal: 'Proposal', negotiation: 'Negotiation', won: 'Won' },
|
||
role: { decider: 'Decider', influencer: 'Influencer', user: 'User', procurement: 'Procurement' },
|
||
eventKind: { news: 'News', hiring: 'Hiring', funding: 'Funding', product: 'Product', meeting: 'Meeting', doc: 'Doc', competitor: 'Competitor' },
|
||
priority: { high: 'High', medium: 'Medium', low: 'Low' },
|
||
},
|
||
approvals: {
|
||
queueTitle: 'My Approval Queue',
|
||
queueDesc: 'Items waiting on your sign-off. AI judgments are ready; your call.',
|
||
filterMine: 'Mine', filterAll: 'All', filterHigh: 'High Risk',
|
||
requester: 'Requested by', target: 'Target', reason: 'Reason', evidence: 'Evidence',
|
||
btnApprove: 'Approve', btnReject: 'Reject', btnDelegate: 'Delegate',
|
||
kind: { contract: 'Contract', tool: 'Tool', transformation: 'Transform', access: 'Access' },
|
||
slaTitle: 'SLA Monitor',
|
||
slaDesc: 'Response time and auto-approval rate — granular data exposes approval bottlenecks.',
|
||
slaAvg: 'Avg response', slaWithin: 'Within SLA', slaOverdue: 'Overdue', slaAutoApproved: 'Auto-approved',
|
||
slaAutoNote: 'Matched allowlist rule',
|
||
},
|
||
audit: {
|
||
title: 'Audit Trail',
|
||
desc: 'Every AI judgment, human action, and tool call carries a timestamp and a piece of evidence. This is the minimum bar for AI in regulated workflows.',
|
||
scopeAll: 'All events', scopeContract: 'Contract', scopeAccount: 'Account', scopeTool: 'AI / Tools',
|
||
evidence: 'Linked evidence',
|
||
kind: { review: 'AI Review', approve: 'Approve', reject: 'Reject', tool: 'Tool call', access: 'Access', modify: 'Modify', agent: 'Agent action' },
|
||
},
|
||
},
|
||
channels: {
|
||
title: 'Channels',
|
||
desc: 'Connect your agents to messaging platforms and APIs',
|
||
newChannel: 'New Channel',
|
||
addChannel: 'Add Channel',
|
||
status: {
|
||
active: 'Active',
|
||
inactive: 'Inactive',
|
||
},
|
||
configure: 'Configure',
|
||
enable: 'Enable',
|
||
disable: 'Disable',
|
||
empty: {
|
||
title: 'Connect your first channel',
|
||
desc: 'Bring your agents into the apps your team already uses — Slack, WeChat Work, Telegram, and more.',
|
||
cta: 'Connect a Channel',
|
||
},
|
||
stats: {
|
||
active: '{n} active',
|
||
reconnecting: '{n} reconnecting',
|
||
errors: '{n} {n, plural, one {error} other {errors}}',
|
||
disabled: '{n} disabled',
|
||
},
|
||
cardDesc: {
|
||
connectedAs: 'Connected as {account}',
|
||
connectedAsIn: 'Connected as {account} in {team}',
|
||
// Per-type fallback used when the row has no user-provided description
|
||
// and the adapter hasn't written identity_json yet. Keeps every card
|
||
// visually populated instead of leaving a blank middle area.
|
||
typeFallback: {
|
||
web: 'Default web console channel, streaming via browser SSE.',
|
||
dingtalk: 'DingTalk bot channel, receiving messages via Outgoing Webhook / Stream.',
|
||
wecom: 'WeCom (Enterprise WeChat) app channel for member messaging.',
|
||
weixin: 'WeChat Official Account channel — handles user messages and event callbacks.',
|
||
feishu: 'Feishu / Lark channel via event subscriptions.',
|
||
telegram: 'Telegram bot channel via long polling.',
|
||
slack: 'Slack bot channel via the Events API.',
|
||
discord: 'Discord bot channel via the Gateway connection.',
|
||
qq: 'QQ / QQ Channel bot.',
|
||
matrix: 'Matrix room channel via the client-server API.',
|
||
qqbot: 'QQ Channel bot (official API).',
|
||
yuanbao: 'Tencent Yuanbao channel.',
|
||
},
|
||
empty: 'Click Configure to add a description for this channel.',
|
||
},
|
||
catalog: {
|
||
subtitle: 'Pick a service to connect. You can change settings later.',
|
||
groups: {
|
||
im: 'Messaging',
|
||
enterprise: 'Enterprise platforms',
|
||
web: 'Web & API',
|
||
},
|
||
descriptions: {
|
||
telegram: 'Bot via long-poll. No public IP needed.',
|
||
discord: 'Bot via Gateway WebSocket. No public IP needed.',
|
||
slack: 'Slack app via Socket Mode.',
|
||
qq: 'QQ Bot via WebSocket. No public IP needed.',
|
||
wecom: 'WeCom smart bot. Scan QR to connect.',
|
||
weixin: 'WeChat personal account via iLink.',
|
||
feishu: 'Feishu / Lark app. One-click QR creation.',
|
||
dingtalk: 'DingTalk bot. One-click QR creation.',
|
||
web: 'Default browser channel. Always on.',
|
||
webchat: 'Embeddable chat widget for your site.',
|
||
webhook: 'Generic HTTP inbound endpoint.',
|
||
},
|
||
},
|
||
modal: {
|
||
editTitle: 'Edit Channel',
|
||
newTitle: 'New Channel',
|
||
},
|
||
fields: {
|
||
name: 'Name',
|
||
type: 'Type',
|
||
description: 'Description',
|
||
bindAgent: 'Bind Agent',
|
||
},
|
||
placeholders: {
|
||
name: 'Channel name',
|
||
description: 'Channel description',
|
||
selectAgent: 'Select Agent...',
|
||
},
|
||
types: {
|
||
web: 'Web API',
|
||
dingtalk: 'DingTalk',
|
||
feishu: 'Feishu / Lark',
|
||
telegram: 'Telegram',
|
||
discord: 'Discord',
|
||
wecom: 'WeChat Work',
|
||
weixin: 'WeChat',
|
||
qq: 'QQ',
|
||
slack: 'Slack',
|
||
webchat: 'WebChat Embed',
|
||
webhook: 'Webhook',
|
||
},
|
||
tabs: {
|
||
form: 'Form',
|
||
json: 'Raw JSON',
|
||
},
|
||
webhook: {
|
||
url: 'Webhook URL',
|
||
copy: 'Copy',
|
||
copied: 'Copied',
|
||
copyFailed: 'Copy failed, please copy manually',
|
||
localhostWarn: 'You are running on localhost. IM platforms cannot reach localhost. Use ngrok, frp or similar tools to expose your local service to the internet, then replace the host in the URL above.',
|
||
},
|
||
weixin: {
|
||
authHint: 'Click the button below to get a WeChat login QR code. After scanning with WeChat, the Bot Token will be automatically filled in. Requires iLink Bot beta access.',
|
||
qrcodeButton: 'Get Login QR Code',
|
||
rescanButton: 'Re-scan (replaces current account)',
|
||
qrcodeLoading: 'Fetching...',
|
||
qrcodeFailed: 'Failed to get QR code. Please check your network.',
|
||
qrcodeExpired: 'QR code expired. Please get a new one.',
|
||
scanHint: 'Scan this QR code with WeChat to log in',
|
||
polling: 'Waiting for scan...',
|
||
scanned: 'Scanned, please confirm on your phone',
|
||
confirmed: 'Login successful',
|
||
expired: 'QR code expired',
|
||
loginSuccess: 'WeChat login successful, token has been filled in',
|
||
replaceWarning: 'Re-scanning will replace the currently bound WeChat account. To bind an additional account, click the button below to add a new channel.',
|
||
addNewAccount: 'Bind New WeChat Account (Add Channel)',
|
||
newAccountName: 'WeChat',
|
||
},
|
||
wecom: {
|
||
authHint: 'Click the button to open a WeChat Work QR code window. After scanning, the Bot ID and Secret will be automatically filled in.',
|
||
authButton: 'Authorize WeChat Work Bot',
|
||
authLoading: 'Loading...',
|
||
authSuccess: 'WeChat Work bot authorized successfully',
|
||
sdkFailed: 'WeChat Work SDK failed to load. Please check your network.',
|
||
windowBlocked: 'Popup blocked by browser. Please allow popups and try again.',
|
||
authCancelled: 'Authorization cancelled',
|
||
authFailed: 'Authorization failed',
|
||
},
|
||
webHint: 'Web channel uses built-in SSE communication, no additional configuration needed.',
|
||
webchatHint: 'WebChat embeds the MateClaw chat widget into external websites. Configure an API key, title, and primary color, then load the WebChat SDK on your site.',
|
||
webchatApiKeyGenerated: 'The platform will generate the API key after save. Reopen this channel to copy it.',
|
||
webchatApiKeyReadOnly: 'This API key is generated and managed by the platform. It can be copied, but not edited manually.',
|
||
webhookHint: 'Webhook channel configuration should be edited in the "Raw JSON" tab below.',
|
||
jsonHint: 'Edit the complete JSON configuration directly. Switching to "Form" tab will sync automatically.',
|
||
advanced: 'Advanced',
|
||
accessControl: {
|
||
title: 'Access Control',
|
||
dmPolicy: 'DM Policy',
|
||
dmPolicyTooltip: 'Controls whether users can chat with the bot privately',
|
||
groupPolicy: 'Group Policy',
|
||
groupPolicyTooltip: 'Controls whether the bot responds in group chats',
|
||
policyOpen: 'Open',
|
||
policyClosed: 'Closed',
|
||
allowFrom: 'Allowed Users',
|
||
allowFromTooltip: 'Comma-separated user ID whitelist, leave empty to allow all',
|
||
allowFromPlaceholder: 'Comma-separated user IDs (empty = allow all)',
|
||
denyMessage: 'Deny Message',
|
||
denyMessagePlaceholder: 'Sorry, you do not have permission',
|
||
requireMention: "Require {'@'}mention",
|
||
requireMentionTooltip: "Whether the bot requires {'@'}mention in group chats",
|
||
},
|
||
messageFilter: {
|
||
title: 'Message Filter',
|
||
filterThinking: 'Filter Thinking',
|
||
filterThinkingTooltip: 'Filter <think> tag content before sending to users',
|
||
filterToolMessages: 'Filter Tool Messages',
|
||
filterToolMessagesTooltip: 'Filter tool_call / tool_result and ReAct Action/Observation lines',
|
||
messageFormat: 'Message Format',
|
||
formatAuto: 'Auto',
|
||
formatMarkdown: 'Markdown',
|
||
formatText: 'Plain Text',
|
||
formatHtml: 'HTML',
|
||
},
|
||
feishuPermissions: {
|
||
title: 'Required Feishu Permissions',
|
||
goToPermissions: 'Go to Permission Management →',
|
||
},
|
||
connection: {
|
||
connected: 'Connected',
|
||
reconnecting: 'Reconnecting',
|
||
error: 'Disconnected',
|
||
disconnected: 'Not Connected',
|
||
outOfService: 'Not Started',
|
||
retryCount: 'Retry #{n}',
|
||
errorLabel: 'Error',
|
||
},
|
||
messages: {
|
||
loadFailed: 'Failed to load channels',
|
||
saveFailed: 'Failed to save channel',
|
||
saveSuccess: 'Channel saved',
|
||
deleteFailed: 'Failed to delete channel',
|
||
deleteConfirm: 'Are you sure you want to delete this channel?',
|
||
deleteTitle: 'Confirm Delete',
|
||
toggleFailed: 'Failed to toggle channel status',
|
||
invalidJson: 'Invalid config JSON format',
|
||
},
|
||
guide: {
|
||
dingtalk: {
|
||
step1: 'Create a bot on <a href="https://open-dev.dingtalk.com/" target="_blank" rel="noopener">DingTalk Open Platform</a>, fill in <b>AppKey</b> and <b>AppSecret</b>',
|
||
step2: 'Stream mode (recommended): Select "Stream Mode" for message receiving, no public IP required',
|
||
step3: 'Webhook mode: Select "HTTP Mode", paste the Webhook URL as the callback address',
|
||
},
|
||
feishu: {
|
||
step1: 'Go to <a href="https://open.feishu.cn/" target="_blank" rel="noopener">Feishu Open Platform</a> and create an enterprise app',
|
||
step2: 'Fill in the app\'s <b>App ID</b> and <b>App Secret</b> below',
|
||
webhookStep: 'In Feishu "Event Subscriptions", set the request URL to the Webhook URL above and subscribe to <code>im.message.receive_v1</code>',
|
||
websocketStep: 'In Feishu "Event Subscriptions", choose the "Long Connection" subscription method and subscribe to <code>im.message.receive_v1</code> (no public IP required)',
|
||
permissionStep: 'For nickname display, request <code>contact:user.base:readonly</code> permission in "Permission Management"',
|
||
},
|
||
telegram: {
|
||
step1: 'Search for <a href="https://t.me/BotFather" target="_blank" rel="noopener">{at}BotFather</a> in Telegram, send <code>/newbot</code> to create a Bot',
|
||
step2: 'Fill in the <b>Bot Token</b> returned by BotFather below',
|
||
step3: '<b>Long-Polling mode</b> (recommended): Auto-receives messages via <code>getUpdates</code> polling, <b>no public IP required</b>',
|
||
step4: '<b>Webhook mode</b>: Requires a publicly accessible callback URL, switch connection mode and fill in Webhook URL',
|
||
},
|
||
discord: {
|
||
step1: 'Go to <a href="https://discord.com/developers/applications" target="_blank" rel="noopener">Discord Developer Portal</a> and create an Application',
|
||
step2: 'Create a Bot on the Bot page and copy the <b>Bot Token</b> below',
|
||
step3: 'Enable <b>MESSAGE CONTENT Intent</b> on the Bot page (Privileged Gateway Intents section)',
|
||
step4: 'In OAuth2 → URL Generator, check <b>bot</b> scope and <b>Send Messages / Read Message History</b> permissions, generate invite link to add Bot to target server',
|
||
step5: 'Auto-receives messages via <b>Gateway WebSocket</b> after startup, <b>no public IP or callback URL required</b>',
|
||
},
|
||
wecom: {
|
||
step1: 'Go to <a href="https://work.weixin.qq.com/wework_admin/frame" target="_blank" rel="noopener">WeCom Admin Console</a>, navigate to "App Management → Smart Bot" and create a new bot',
|
||
step2: 'In bot configuration, select "<b>API Mode → Configure Long Connection</b>"',
|
||
step3: 'Record the bot\'s <b>Bot ID</b> and <b>Secret</b>, fill in below',
|
||
step4: 'After starting the channel, scan QR code in WeCom to chat with the bot, <b>no public IP or callback URL required</b>',
|
||
},
|
||
weixin: {
|
||
step1: 'Ensure you have WeChat <b>iLink Bot</b> beta access (currently invite-only)',
|
||
step2: 'Click the "Get Login QR Code" button below, scan with WeChat to log in',
|
||
step3: 'After successful scan, the system auto-fills <b>bot_token</b> into config',
|
||
step4: 'After starting the channel, auto-receives messages via <b>HTTP long polling</b>, <b>no public IP or callback URL required</b>',
|
||
},
|
||
qq: {
|
||
step1: 'Go to <a href="https://q.qq.com/" target="_blank" rel="noopener">QQ Open Platform</a> and create a bot application',
|
||
step2: 'Get <b>AppID</b> and <b>AppSecret</b> from the app management page, fill in below',
|
||
step3: "Enable required message types in \"Feature Config → Message Subscription\" (C2C, Group {'@'}, Channel messages, etc.)",
|
||
step4: 'After starting the channel, auto-receives messages via <b>WebSocket long connection</b>, <b>no public IP or callback URL required</b>',
|
||
},
|
||
},
|
||
dingtalkRegister: {
|
||
title: 'One-click DingTalk Bot Creation',
|
||
hint: 'Click the button to get a QR code. Scan it with DingTalk and approve authorization — a bot app will be created in your tenant and the Client ID / Client Secret will be auto-filled below.',
|
||
button: 'Scan to Create Bot',
|
||
buttonLoading: 'Preparing QR code…',
|
||
qrcodeLoading: 'Generating QR code',
|
||
scanHint: 'Scan the QR code above with the DingTalk app and confirm authorization',
|
||
confirmed: 'Bot created. Client ID and Secret have been auto-filled.',
|
||
expired: 'QR code expired, please try again',
|
||
denied: 'Authorization was denied',
|
||
startFailed: 'Failed to fetch QR code, please check your network',
|
||
},
|
||
feishuRegister: {
|
||
title: 'One-click Feishu App Creation',
|
||
hint: 'Click the button to get a QR code. Scan it with Feishu and confirm authorization — an in-house app will be created in your tenant and the App ID / App Secret will be auto-filled below.',
|
||
button: 'Scan to Create App',
|
||
buttonLoading: 'Preparing QR code…',
|
||
qrcodeLoading: 'Generating QR code',
|
||
scanHint: 'Scan the QR code above with the Feishu app and confirm authorization',
|
||
confirmed: 'App created. App ID and Secret have been auto-filled.',
|
||
expired: 'QR code expired, please try again',
|
||
denied: 'Authorization was denied',
|
||
error: 'Registration failed, please retry',
|
||
startFailed: 'Failed to fetch QR code, please check your network',
|
||
},
|
||
feishu: {
|
||
perm: {
|
||
message: 'Send and receive messages',
|
||
messageReason: 'Core: send and receive messages',
|
||
receive: 'Receive message events',
|
||
receiveReason: 'Core: receive user messages',
|
||
resource: 'Access message resources',
|
||
resourceReason: 'Get message content in WebSocket mode',
|
||
reactions: 'Manage message reactions',
|
||
reactionsReason: 'Message reactions: add 👍 emoji',
|
||
contact: 'Get basic user info',
|
||
contactReason: 'Nickname: display real user name',
|
||
media: 'Access message resources',
|
||
mediaReason: 'Media download: download images and files',
|
||
},
|
||
},
|
||
wizard: {
|
||
step1: 'Configure',
|
||
step2: 'Verify',
|
||
step3: 'Ready',
|
||
configureSubtitle: 'Enter your credentials to connect {service}',
|
||
howToGet: 'How to get credentials',
|
||
saveAndTest: 'Save & Test',
|
||
back: 'Back',
|
||
continue: 'Continue',
|
||
done: 'Done',
|
||
verifying: 'Verifying with {service}…',
|
||
verifySuccess: 'Connected',
|
||
// Used on Step 2 in place of the backend's English headline so the
|
||
// success line stays in the user's locale. Backend `headline` is
|
||
// still rendered on the failed path because diagnostic strings
|
||
// (errcodes, upstream error reasons) don't translate cleanly.
|
||
verifySuccessHeadline: 'Connected — {service} accepted the credentials',
|
||
verifyFailed: 'Verification failed',
|
||
verifySkipped: 'No live check needed',
|
||
verifySkippedDetail: "This channel type doesn't have credentials to verify. You can save and start it directly.",
|
||
durationMs: '({n} ms)',
|
||
fixIt: 'Fix it',
|
||
retry: 'Retry',
|
||
readyHeadline: 'Ready to go',
|
||
readySubtitle: 'Bind an agent and send a test message to confirm.',
|
||
bindAgentLabel: 'Bind to agent',
|
||
sendTest: 'Send a test message',
|
||
sendTestHint: 'Open {service} and message the bot — replies should arrive in seconds.',
|
||
saveFailed: 'Could not save the channel',
|
||
noVerifierHint: 'No live check is available for {type}. Saving will start the channel; check the connection dot afterwards.',
|
||
oauthScanHint: 'After scanning, the credentials will be filled and verified automatically — you do not need to copy anything.',
|
||
// Identity field labels rendered on Step 3. Keys not listed here
|
||
// fall back to a camelCase-to-spaces conversion (formatIdentityKey),
|
||
// so adding a new identity field on a new verifier still renders
|
||
// — it just lacks the polished label until i18n catches up.
|
||
identity: {
|
||
accountId: 'Account ID',
|
||
accountName: 'Account',
|
||
firstName: 'First name',
|
||
team: 'Team',
|
||
teamId: 'Team ID',
|
||
botId: 'Bot ID',
|
||
transport: 'Transport',
|
||
region: 'Region',
|
||
tokenTtl: 'Token TTL',
|
||
baseUrl: 'Base URL',
|
||
isBot: 'Bot account',
|
||
verified: 'Verified',
|
||
canJoinGroups: 'Can join groups',
|
||
canReadAllGroupMessages: 'Reads all group messages',
|
||
},
|
||
},
|
||
},
|
||
skills: {
|
||
title: 'Skills',
|
||
desc: 'Manage tools and skills available to your agents',
|
||
newSkill: 'New Skill',
|
||
importSkill: 'Import Skill',
|
||
browseTemplates: 'Browse Templates',
|
||
refreshRuntime: 'Refresh Runtime',
|
||
refreshing: 'Refreshing...',
|
||
refreshSuccess: 'Active skills refreshed',
|
||
refreshFailed: 'Failed to refresh runtime',
|
||
tabs: {
|
||
all: 'All',
|
||
builtin: 'Built-in',
|
||
mcp: 'MCP',
|
||
acp: 'ACP',
|
||
dynamic: 'Dynamic',
|
||
},
|
||
search: {
|
||
placeholder: 'Search by name, description, or tags...',
|
||
},
|
||
filter: {
|
||
all: 'All statuses',
|
||
enabled: 'Enabled',
|
||
disabled: 'Disabled',
|
||
scanFailed: 'Scan failed',
|
||
},
|
||
sort: {
|
||
recommended: 'Recommended',
|
||
name: 'Name',
|
||
status: 'Status',
|
||
source: 'Source',
|
||
updated: 'Recently updated',
|
||
},
|
||
security: {
|
||
scanned: 'Scanned',
|
||
scanFailed: 'Scan failed',
|
||
notScanned: 'Not scanned',
|
||
findingsTitle: 'Security scan failed',
|
||
rescan: 'Rescan',
|
||
rescanning: 'Scanning...',
|
||
rescanPassed: 'Rescan passed',
|
||
rescanStillFailed: 'Rescan still failed — see findings below',
|
||
rescanFailed: 'Rescan request failed',
|
||
noPersistedFindings: 'No persisted findings for this scan. Click "Rescan" to regenerate.',
|
||
fix: 'Suggested fix',
|
||
},
|
||
status: {
|
||
ready: 'Ready',
|
||
setupNeeded: 'Setup needed',
|
||
blocked: 'Blocked',
|
||
unresolved: 'Unresolved',
|
||
disabled: 'Disabled',
|
||
checking: 'Checking…',
|
||
},
|
||
empty: 'No skills found',
|
||
emptyDesc: 'Add skills to enhance your agents\' capabilities',
|
||
noDescription: 'No description',
|
||
// Issue #83: shown on the padlock that replaces the toggle for MCP/ACP virtual skills.
|
||
virtualReadonlyHint: 'MCP/ACP-derived skills can\'t be toggled here — manage the underlying service in Settings ▸ Connections.',
|
||
modal: {
|
||
configureTitle: 'Configure Skill',
|
||
newTitle: 'New Skill',
|
||
newSimpleHint: 'Just the bones — keep configuring icon, body, and tools in the detail panel after this.',
|
||
},
|
||
fields: {
|
||
name: 'Name',
|
||
nameZh: 'Chinese display name',
|
||
nameEn: 'English display name',
|
||
type: 'Type',
|
||
icon: 'Icon',
|
||
version: 'Version',
|
||
author: 'Author',
|
||
tags: 'Tags',
|
||
description: 'Description',
|
||
configJson: 'Configuration (JSON)',
|
||
skillContent: 'Skill Content (SKILL.md)',
|
||
sourceCode: 'Source Code / Script',
|
||
},
|
||
placeholders: {
|
||
name: 'Skill name',
|
||
nameZh: '可选 — 留空则显示原始 name',
|
||
nameEn: 'Optional — leave blank to show the slug',
|
||
icon: '🛠️ (emoji or URL)',
|
||
version: '1.0.0',
|
||
author: 'Author name',
|
||
tags: 'tag1,tag2,tag3',
|
||
description: 'What does this skill do?',
|
||
configJson: '',
|
||
sourceCode: '# Python or script content...',
|
||
},
|
||
hints: {
|
||
directorySkill: '— Directory skill: used as fallback when directory is unavailable',
|
||
primaryContent: '— Primary content for agent prompt injection',
|
||
},
|
||
types: {
|
||
builtin: 'Built-in',
|
||
mcp: 'MCP',
|
||
acp: 'ACP',
|
||
dynamic: 'Dynamic',
|
||
},
|
||
source: {
|
||
builtin: 'Built-in',
|
||
synthesized: 'AI Synthesized',
|
||
local: 'Local',
|
||
},
|
||
usedByTitle: 'Number of agents that have this skill bound',
|
||
lessonsCountTitle: 'Lessons recorded — click to view',
|
||
actions: {
|
||
configure: 'Configure',
|
||
view: 'View',
|
||
setUp: 'Set Up',
|
||
delete: 'Delete',
|
||
saveChanges: 'Save Changes',
|
||
createSkill: 'Create Skill',
|
||
edit: 'Edit',
|
||
save: 'Save',
|
||
cancel: 'Cancel',
|
||
},
|
||
preflight: {
|
||
title: 'Pre-flight check',
|
||
allMet: 'All requirements satisfied',
|
||
allMetDesc: 'This skill is ready to use as soon as you bind it to an agent.',
|
||
setupNeeded: '{count} requirement(s) need attention',
|
||
setupNeededDesc: 'Install the missing pieces below, then re-check or re-resolve the skill.',
|
||
requirements: 'Requirements',
|
||
features: 'Features',
|
||
installCommands: 'Install commands',
|
||
optional: 'Optional',
|
||
noManifest: 'This skill has no v3 manifest. Status falls back to legacy dependency reporting.',
|
||
recheck: 'Re-check',
|
||
loadFailed: 'Failed to load preflight data',
|
||
},
|
||
detail: {
|
||
title: 'Skill detail',
|
||
overview: 'Overview',
|
||
body: 'Body',
|
||
manifest: 'Manifest',
|
||
tools: 'Tools',
|
||
features: 'Features',
|
||
security: 'Security',
|
||
lessons: 'Lessons',
|
||
secrets: 'Secrets',
|
||
memory: 'Memory',
|
||
scanStatus: 'Scan status',
|
||
missingDeps: 'Missing dependencies',
|
||
runtimeError: 'Runtime error',
|
||
path: 'Resolved path',
|
||
synthesized: 'Source',
|
||
identitySection: 'Identity',
|
||
manifestProjectedSection: 'From SKILL.md',
|
||
manifestProjectedHint: 'These fields mirror the SKILL.md frontmatter — editing the row directly does not stick (the next resolve overwrites it). Edit the SKILL.md body below to change them.',
|
||
displayOverridesSection: 'Display & tags',
|
||
displayOverridesHint: 'DB-only — these are not overwritten by the resolver.',
|
||
bodyHint: 'SKILL.md body — injected into the LLM system prompt at load time.',
|
||
sourceCodeHint: 'Executable body (dynamic skills only). Re-runs on next call after save.',
|
||
viewRawManifest: 'View parsed runtime manifest',
|
||
noBody: 'No SKILL.md body has been provided yet.',
|
||
builtinReadonly: 'Built-in skill: only nameZh / nameEn / tags / description / body are editable.',
|
||
virtualReadonly: 'Virtual MCP-derived skill — edit it on the MCP Connections page instead.',
|
||
editSource: 'Edit SKILL.md',
|
||
editingSource: 'Editing SKILL.md',
|
||
sourceSavedReprojection: 'Saved. The next resolve will sync icon/version/author and friends from the new frontmatter.',
|
||
noManifest: 'This skill does not declare a v3 manifest. Legacy fields apply.',
|
||
noTools: 'No allowed-tools declared by this skill. The LLM will fall back to the global tool set when this skill is bound to an agent.',
|
||
noFeatures: 'No features[] matrix declared. The skill is treated as a single default feature.',
|
||
noLessons: 'No lessons recorded yet. Lessons are written by the LLM via the record_lesson tool — ask an agent during a session "remember this lesson for {skill name}".',
|
||
noEmployees: 'This skill is not yet reachable by any agent. Either bind it explicitly in an agent\'s Skills tab, or enable the skill globally so agents without explicit bindings can use it.',
|
||
toolsHint: 'These tool names are merged into the LLM allowed-tool list when this skill is bound to an agent. Tools owned by SETUP_NEEDED features stay hidden.',
|
||
lessonsHint: 'Per-skill LESSONS.md. Auto-injected after SKILL.md body when this skill is loaded.',
|
||
memoryHint: 'Agents that can use this skill. Explicit = wired in the agent\'s Skills tab; Implicit = the agent has no explicit Skill bindings, so it sees every globally-enabled skill including this one.',
|
||
openMemory: 'Open agent memory',
|
||
bindingExplicit: 'Explicit',
|
||
bindingImplicit: 'Implicit',
|
||
clearLessons: 'Clear all',
|
||
clearLessonsConfirm: 'Delete all recorded lessons for this skill? This cannot be undone.',
|
||
secretsHint: 'Key/value pairs injected as environment variables into this skill\'s script subprocess. Stored AES-encrypted; plaintext is never returned over the API. Example: tencent-meeting needs TENCENT_MEETING_TOKEN.',
|
||
secretsEmpty: 'No secrets configured for this skill.',
|
||
secretKey: 'Key',
|
||
secretValue: 'Value',
|
||
secretUpdatedAt: 'Last updated',
|
||
secretAdd: '+ Add secret',
|
||
secretAddTitle: 'Add secret',
|
||
secretEditTitle: 'Edit secret',
|
||
secretEdit: 'Edit',
|
||
secretDelete: 'Delete',
|
||
secretDialogHint: 'Saved immediately and injected into the script subprocess on next skill execution.',
|
||
secretKeyPlaceholder: 'e.g. TENCENT_MEETING_TOKEN',
|
||
secretKeyRule: 'Letters, digits and underscore only; first char must be a letter or underscore; ≤128 chars.',
|
||
secretValuePlaceholder: 'Paste the value (AES-encrypted server-side on submit)',
|
||
secretSaveSuccess: 'Secret saved',
|
||
secretSaveFailed: 'Failed to save',
|
||
secretDeleteConfirm: 'Delete secret "{key}"? This skill\'s scripts will no longer receive this environment variable.',
|
||
secretDeleteSuccess: 'Secret deleted',
|
||
secretDeleteFailed: 'Failed to delete',
|
||
secretLoadFailed: 'Failed to load secrets',
|
||
},
|
||
runtime: {
|
||
disabled: 'Disabled',
|
||
unknown: 'Unknown',
|
||
securityBlocked: 'Security Blocked',
|
||
depsMissing: 'Dependencies Missing',
|
||
directoryActive: 'Directory Active',
|
||
databaseFallback: 'Database Fallback',
|
||
databaseActive: 'Database Active',
|
||
unresolved: 'Unresolved',
|
||
},
|
||
messages: {
|
||
saveFailed: 'Failed to save skill',
|
||
saveSuccess: 'Saved',
|
||
deleteConfirm: 'Are you sure you want to delete this skill? This cannot be undone.',
|
||
deleteTitle: 'Confirm Delete',
|
||
deleteFailed: 'Failed to delete skill',
|
||
toggleFailed: 'Failed to toggle skill status',
|
||
},
|
||
import: {
|
||
title: 'Import Skill',
|
||
urlTab: 'From URL',
|
||
searchTab: 'Search Hub',
|
||
urlPlaceholder: 'Enter GitHub repo URL or ClawHub skill URL',
|
||
urlHint: 'Supports GitHub repositories and ClawHub marketplace links',
|
||
examples: 'Examples',
|
||
install: 'Install',
|
||
installing: 'Installing...',
|
||
installed: 'Installed successfully',
|
||
failed: 'Installation failed',
|
||
cancelled: 'Cancelled',
|
||
cancel: 'Cancel',
|
||
overwrite: 'Overwrite existing skill',
|
||
enableAfterInstall: 'Enable after install',
|
||
searchPlaceholder: 'Search ClawHub marketplace...',
|
||
search: 'Search',
|
||
searching: 'Searching...',
|
||
searchFailed: 'Search failed',
|
||
noResults: 'No matching skills found',
|
||
statusPending: 'Pending',
|
||
zipTab: 'ZIP Import',
|
||
dropHint: 'Drop .zip file here, or click to select',
|
||
zipRequirement: 'ZIP must contain a SKILL.md file',
|
||
uploading: 'Installing...',
|
||
uploadSuccess: 'Skill installed successfully',
|
||
uploadFailed: 'Installation failed',
|
||
invalidZip: 'Please select a .zip file',
|
||
tooLarge: 'File too large (max 50MB)',
|
||
},
|
||
},
|
||
onboarding: {
|
||
title: 'Welcome to MateClaw',
|
||
subtitle: 'Set up your first AI model',
|
||
stepPath: 'Choose Path',
|
||
stepConfigure: 'Configure Model',
|
||
stepVerify: 'Verify',
|
||
localTitle: 'Local Model',
|
||
localDesc: 'Ollama installed? Enable local models in one click',
|
||
localDetected: 'Detected',
|
||
cloudTitle: 'Cloud API',
|
||
cloudDesc: 'Use cloud models like OpenAI, DashScope, etc.',
|
||
selectModel: 'Select Model',
|
||
setDefault: 'Set as Default',
|
||
enterApiKey: 'Enter API Key',
|
||
testConnection: 'Test Connection',
|
||
testSuccess: 'Connection Successful',
|
||
testFailed: 'Connection Failed',
|
||
saveAndContinue: 'Save & Continue',
|
||
verifyTitle: 'Verify Your Model',
|
||
verifyMessage: 'Hello! Tell me briefly about yourself.',
|
||
send: 'Send',
|
||
startUsing: 'Start Using MateClaw',
|
||
skip: 'Skip',
|
||
back: 'Back',
|
||
},
|
||
talk: {
|
||
title: 'Talk Mode',
|
||
ready: 'Ready',
|
||
connecting: 'Connecting...',
|
||
listening: 'Listening...',
|
||
processing: 'Thinking...',
|
||
speaking: 'Speaking...',
|
||
holdToTalk: 'Hold to talk',
|
||
releaseToSend: 'Release to send',
|
||
retry: 'Tap to retry',
|
||
you: 'You',
|
||
ai: 'AI',
|
||
micError: 'Cannot access microphone',
|
||
connectionError: 'Connection error — tap the button to retry',
|
||
playbackError: 'Audio playback failed',
|
||
tooShort: 'Recording too short — hold the button while speaking',
|
||
},
|
||
browser: {
|
||
timeline: {
|
||
title: 'Browser ({count} actions)',
|
||
},
|
||
actions: {
|
||
start: 'start',
|
||
stop: 'stop',
|
||
open: 'open',
|
||
click: 'click',
|
||
type: 'type',
|
||
screenshot: 'screenshot',
|
||
},
|
||
},
|
||
dashboard: {
|
||
title: 'Dashboard',
|
||
kicker: 'Operations Pulse',
|
||
desc: 'System usage overview and runtime status',
|
||
conversations: 'Conversations',
|
||
messages: 'Messages',
|
||
tokens: 'Token Usage',
|
||
toolCalls: 'Tool Calls',
|
||
periodDesc: 'A sharper view of how your system behaves across short, medium, and monthly horizons.',
|
||
runsDesc: 'Execution history with timing, cost, and outcome at a glance.',
|
||
trend: {
|
||
title: 'Your Week',
|
||
subtitle: 'How often you and your AI have been working together.',
|
||
},
|
||
periodComparison: 'Period Comparison',
|
||
periods: {
|
||
today: 'Today',
|
||
thisWeek: 'This Week',
|
||
thisMonth: 'This Month',
|
||
},
|
||
recentRuns: 'Recent Cron Job Runs',
|
||
noRuns: 'No runs yet',
|
||
runColumns: {
|
||
time: 'Time',
|
||
job: 'Job',
|
||
status: 'Status',
|
||
trigger: 'Trigger',
|
||
duration: 'Duration',
|
||
tokens: 'Tokens',
|
||
},
|
||
},
|
||
memory: {
|
||
kicker: 'Memory',
|
||
title: 'Memory',
|
||
desc: 'What your agent thinks about, remembers, and lets go.',
|
||
selectAgent: 'Select Agent',
|
||
selectAgentHint: 'Select an agent to view its memory',
|
||
tabTimeline: 'Timeline',
|
||
tabMemory: 'Long-term',
|
||
tabFacts: 'Facts',
|
||
noReports: 'No dream reports yet',
|
||
modeFocused: 'Focused',
|
||
modeNightly: 'Nightly',
|
||
candidates: 'candidates',
|
||
loadMore: 'Load more',
|
||
retry: 'Retry',
|
||
memoryBrowser: {
|
||
header: 'Overview',
|
||
empty: 'No memory content yet',
|
||
userEdited: 'User edited',
|
||
files: {
|
||
memory: 'Memory',
|
||
profile: 'Profile',
|
||
soul: 'Soul',
|
||
userFacts: 'User facts',
|
||
references: 'References',
|
||
},
|
||
},
|
||
time: {
|
||
justNow: 'just now',
|
||
hoursAgo: '{n}h ago',
|
||
daysAgo: '{n}d ago',
|
||
},
|
||
status: {
|
||
success: 'Success',
|
||
failed: 'Failed',
|
||
skipped: 'Skipped',
|
||
running: 'Running',
|
||
pending: 'Pending',
|
||
},
|
||
report: {
|
||
mode: 'Mode',
|
||
topic: 'Topic',
|
||
status: 'Status',
|
||
time: 'Time',
|
||
candidates: 'Candidates',
|
||
promoted: 'Promoted',
|
||
rejected: 'Rejected',
|
||
trigger: 'Trigger',
|
||
reason: 'LLM Reason',
|
||
diff: 'Change Summary',
|
||
},
|
||
morningCard: {
|
||
title: 'Dream Recap',
|
||
dismiss: 'Got it',
|
||
promoted: '{count} memories consolidated',
|
||
},
|
||
hil: {
|
||
confirm: 'Confirm',
|
||
edit: 'Edit',
|
||
cancel: 'Cancel',
|
||
save: 'Save',
|
||
editPlaceholder: 'Edit memory content...',
|
||
confirmed: 'Confirmed',
|
||
saved: 'Saved to MEMORY.md',
|
||
},
|
||
facts: {
|
||
searchPlaceholder: 'Search facts…',
|
||
empty: 'No facts yet (enable fact projection)',
|
||
trust: 'Trust',
|
||
used: 'Used {n} times',
|
||
helpful: 'Helpful',
|
||
unhelpful: 'Not helpful',
|
||
forget: 'Forget',
|
||
forgotten: 'Forgotten',
|
||
resolved: 'Resolved',
|
||
contradictions: '{count} contradictions pending',
|
||
resolve: {
|
||
KEEP_A: 'Keep A',
|
||
KEEP_B: 'Keep B',
|
||
MERGE: 'Merge',
|
||
IGNORE: 'Ignore',
|
||
},
|
||
},
|
||
focused: {
|
||
desc: 'Re-organize memories around a specific topic, prioritizing related information.',
|
||
placeholder: 'Enter a topic, e.g. "architecture decisions"…',
|
||
trigger: 'Start',
|
||
success: 'Dream completed, timeline updated',
|
||
skipped: 'Nothing to consolidate',
|
||
},
|
||
},
|
||
// Tool display labels consumed by useToolLabel() — keys must mirror zh-CN.ts exactly.
|
||
// Unknown tools (MCP / custom skills) fall back to humanizeToolName() and are not listed here.
|
||
toolLabels: {
|
||
// Delegation
|
||
delegateToAgent: 'Delegate to Agent',
|
||
delegateParallel: 'Parallel Delegation',
|
||
listAvailableAgents: 'List Agents',
|
||
|
||
// Wiki
|
||
wiki_search_pages: 'Search Knowledge Base',
|
||
wiki_semantic_search: 'Semantic Search KB',
|
||
wiki_read_page: 'Read KB Page',
|
||
wiki_list_pages: 'List KB Pages',
|
||
wiki_related_pages: 'Find Related Pages',
|
||
wiki_trace_source: 'Trace Knowledge Source',
|
||
wiki_create_page: 'Create KB Page',
|
||
wiki_delete_page: 'Delete KB Page',
|
||
wiki_enrich_page: 'Enrich KB Page',
|
||
wiki_explain_relation: 'Explain Relation',
|
||
|
||
// Web search
|
||
search: 'Web Search',
|
||
|
||
// Memory
|
||
recall_structured: 'Recall Memory',
|
||
remember_structured: 'Save Memory',
|
||
forget_structured: 'Clear Memory',
|
||
fact_probe: 'Probe Facts',
|
||
fact_list_contradictions: 'Check Contradictions',
|
||
session_search: 'Search Sessions',
|
||
read_workspace_memory_file: 'Read Memory File',
|
||
write_workspace_memory_file: 'Write Memory File',
|
||
edit_workspace_memory_file: 'Edit Memory File',
|
||
list_workspace_memory_files: 'List Memory Files',
|
||
|
||
// Files & shell
|
||
read_file: 'Read File',
|
||
execute_shell_command: 'Execute Command',
|
||
extract_document_text: 'Extract Document',
|
||
extract_pdf_text: 'Extract PDF',
|
||
extract_docx_text: 'Extract Document',
|
||
detect_file_type: 'Detect File Type',
|
||
readMateClawDoc: 'Read System Docs',
|
||
|
||
// Generative
|
||
image_generate: 'Generate Image',
|
||
video_generate: 'Generate Video',
|
||
music_generate: 'Generate Music',
|
||
|
||
// Data
|
||
query_datasource: 'Query Datasource',
|
||
execute_sql: 'Execute SQL',
|
||
|
||
// Browser
|
||
browser_use: 'Browser Action',
|
||
|
||
// Cron
|
||
create_cron_job: 'Create Cron Job',
|
||
list_cron_jobs: 'List Cron Jobs',
|
||
toggle_cron_job: 'Toggle Cron Job',
|
||
delete_cron_job: 'Delete Cron Job',
|
||
|
||
// Time
|
||
getCurrentDateTime: 'Get Current Time',
|
||
getCurrentTime: 'Get Current Time',
|
||
getCurrentDate: 'Get Current Date',
|
||
|
||
// Skills
|
||
skill_manage: 'Manage Skills',
|
||
runSkillScript: 'Run Skill',
|
||
listSkillFiles: 'List Skill Files',
|
||
listAvailableSkills: 'List Skills',
|
||
readSkillFile: 'Read Skill File',
|
||
},
|
||
} as const
|