Upstream v0.50.95 features merged (Russian localization, slash commands, mic toggle fix, gateway sync fix, KaTeX/Prism.js, etc.) Custom additions preserved: - Tier-2 agent switching commands in commands.js - MC panel in index.html + MC CSS - _resolve_cli_toolsets() in config.py - Custom routes.py, server.py, boot.js, i18n.js, messages.js, workspace.js Files with conflict resolution (took upstream, custom code in other files): - CHANGELOG.md, config.py, commands.js, index.html, panels.js, style.css, ui.js
2410 lines
137 KiB
JavaScript
2410 lines
137 KiB
JavaScript
// ── i18n: locale bundles and t() helper ──────────────────────────────────────
|
||
// To add a new language: add an entry to LOCALES below with all keys translated.
|
||
// The language code must match a valid BCP 47 tag (used for speech recognition).
|
||
// Keys missing in a non-English locale fall back to English automatically.
|
||
|
||
const LOCALES = {
|
||
en: {
|
||
_lang: 'en',
|
||
_label: 'English',
|
||
_speech: 'en-US',
|
||
// boot.js
|
||
cancelling: 'Cancelling\u2026',
|
||
cancel_failed: 'Cancel failed: ',
|
||
mic_denied: 'Microphone access denied. Check browser permissions.',
|
||
mic_no_speech: 'No speech detected. Try again.',
|
||
mic_network: 'Speech recognition unavailable.',
|
||
mic_error: 'Voice input error: ',
|
||
session_imported: 'Session imported',
|
||
import_failed: 'Import failed: ',
|
||
import_invalid_json: 'Invalid JSON',
|
||
image_pasted: 'Image pasted: ',
|
||
// messages.js
|
||
edit_message: 'Edit message',
|
||
regenerate: 'Regenerate response',
|
||
copy: 'Copy',
|
||
copied: 'Copied!',
|
||
you: 'You',
|
||
thinking: 'Thinking',
|
||
expand_all: 'Expand all',
|
||
collapse_all: 'Collapse all',
|
||
show_all_tools: 'Show all tools',
|
||
hide_tools: 'Hide tools',
|
||
edit_failed: 'Edit failed: ',
|
||
regen_failed: 'Regenerate failed: ',
|
||
reconnect_active: 'A response is still being generated. Reload when ready?',
|
||
reconnect_finished: 'A response was in progress when you last left. Messages may have updated.',
|
||
// approval card
|
||
approval_heading: 'Approval required',
|
||
approval_desc_prefix: 'Dangerous command detected',
|
||
approval_btn_once: 'Allow once',
|
||
approval_btn_once_title: 'Allow this one command (Enter)',
|
||
approval_btn_session: 'Allow session',
|
||
approval_btn_session_title: 'Allow for this conversation session',
|
||
approval_btn_always: 'Always allow',
|
||
approval_btn_always_title: 'Always allow this command pattern',
|
||
approval_btn_deny: 'Deny',
|
||
approval_btn_deny_title: 'Deny — do not run this command',
|
||
approval_responding: 'Responding\u2026',
|
||
clarify_heading: 'Clarification needed',
|
||
clarify_hint: 'Pick a choice, or type your own answer below.',
|
||
clarify_other: 'Other',
|
||
clarify_send: 'Send',
|
||
clarify_input_placeholder: 'Type your response…',
|
||
clarify_responding: 'Responding\u2026',
|
||
untitled: 'Untitled',
|
||
n_messages: (n) => `${n} messages`,
|
||
model_unavailable: ' (unavailable)',
|
||
model_unavailable_title: 'This model is no longer in your current provider list',
|
||
provider_mismatch_warning: (m,p)=>`"${m}" may not work with your configured provider (${p}). Send anyway, or run \`hermes model\` in your terminal to switch.`,
|
||
provider_mismatch_label: 'Provider mismatch',
|
||
model_custom_label: 'Custom model ID',
|
||
model_custom_placeholder: 'e.g. openai/gpt-5.4',
|
||
model_search_placeholder: 'Search models…',
|
||
model_search_no_results: 'No models found',
|
||
// commands.js
|
||
cmd_clear: 'Clear conversation messages',
|
||
cmd_compress: 'Manually compress conversation context (usage: /compress [focus topic])',
|
||
cmd_compact_alias: 'Legacy alias for /compress',
|
||
cmd_model: 'Switch model (e.g. /model gpt-4o)',
|
||
cmd_workspace: 'Switch workspace by name',
|
||
cmd_new: 'Start a new chat session',
|
||
cmd_usage: 'Toggle token usage display on/off',
|
||
cmd_theme: 'Switch appearance (theme: system/dark/light, skin: default/ares/mono/slate/poseidon/sisyphus/charizard)',
|
||
cmd_personality: 'Switch agent personality',
|
||
cmd_skills: 'List available Hermes skills',
|
||
available_commands: 'Available commands:',
|
||
type_slash: 'Type / to see commands',
|
||
conversation_cleared: 'Conversation cleared',
|
||
command_label: 'Command',
|
||
context_compaction_label: 'Context compaction',
|
||
reference_only_label: 'Reference only',
|
||
model_usage: 'Usage: /model <name>',
|
||
no_model_match: 'No model matching "',
|
||
switched_to: 'Switched to ',
|
||
workspace_usage: 'Usage: /workspace <name>',
|
||
no_workspace_match: 'No workspace matching "',
|
||
switched_workspace: 'Switched to workspace: ',
|
||
workspace_switch_failed: 'Workspace switch failed: ',
|
||
new_session: 'New session created',
|
||
compressing: 'Requesting context compression...',
|
||
compress_running_label: 'Compressing',
|
||
compress_complete_label: 'Compression complete',
|
||
compress_failed_label: 'Compression failed',
|
||
focus_label: 'Focus',
|
||
token_usage_on: 'Token usage on',
|
||
token_usage_off: 'Token usage off',
|
||
theme_usage: 'Usage: /theme ',
|
||
theme_set: 'Theme: ',
|
||
no_active_session: 'No active session',
|
||
|
||
slash_skill_badge:'Skill',
|
||
slash_skill_desc:'Invoke this skill',
|
||
cmd_stop:'Stop the current response',
|
||
cmd_title:'Get or set the session title',
|
||
cmd_retry:'Resend the last message',
|
||
cmd_undo:'Remove the last exchange',
|
||
cmd_status:'Show session info',
|
||
cmd_voice:'Toggle microphone input',
|
||
stream_stopped:'Response stopped.',
|
||
no_active_task:'No active task to stop.',
|
||
cancel_unavailable:'Cancel not available.',
|
||
retry_failed:'Retry failed: ',
|
||
undo_failed:'Undo failed: ',
|
||
undid_n_messages:'Removed',
|
||
undid_messages_suffix:'message(s).',
|
||
status_heading:'Session Status',
|
||
status_session_id:'Session ID',
|
||
status_title:'Title',
|
||
status_model:'Model',
|
||
status_workspace:'Workspace',
|
||
status_personality:'Personality',
|
||
status_messages:'Messages',
|
||
status_agent_running:'Agent running',
|
||
status_yes:'Yes',
|
||
status_no:'No',
|
||
status_load_failed:'Failed to load status: ',
|
||
title_current:'Current title',
|
||
title_change_hint:'Use `/title <new name>` to rename.',
|
||
title_set:'Title set to',
|
||
cmd_webui_only_session:'This command is not available for CLI-imported sessions.',
|
||
cmd_voice_use_mic:'Click the mic button in the composer.',
|
||
usage_heading:'Token Usage',
|
||
usage_default_model:'default',
|
||
usage_unknown:'unknown',
|
||
usage_input_tokens:'Input tokens',
|
||
usage_output_tokens:'Output tokens',
|
||
usage_total:'Total tokens',
|
||
usage_estimated_cost:'Estimated cost',
|
||
usage_settings_tip:'Note: cost estimates are approximate.',
|
||
usage_load_failed:'Failed to load usage: ',
|
||
usage_personality_none:'none',
|
||
untitled:'Untitled',
|
||
no_personalities: 'No personalities found (add them to ~/.hermes/personalities/)',
|
||
available_personalities: 'Available personalities:',
|
||
personality_switch_hint: '\n\nUse `/personality <name>` to switch, or `/personality none` to clear.',
|
||
personalities_load_failed: 'Failed to load personalities',
|
||
personality_cleared: 'Personality cleared',
|
||
personality_set: 'Personality: ',
|
||
failed_colon: 'Failed: ',
|
||
// ui.js
|
||
no_workspace: 'No workspace',
|
||
workspace_empty_no_path: 'No workspace selected. Set a workspace in Settings \u2192 Workspace to browse files.',
|
||
workspace_empty_dir: 'This workspace is empty.',
|
||
dialog_confirm_title: 'Confirm action',
|
||
dialog_prompt_title: 'Enter a value',
|
||
dialog_confirm_btn: 'Confirm',
|
||
// workspace.js
|
||
unsaved_confirm: 'You have unsaved changes in the preview. Discard and navigate?',
|
||
discard: 'Discard',
|
||
save: 'Save',
|
||
edit: 'Edit',
|
||
clear: 'Clear',
|
||
create: 'Create',
|
||
remove: 'Remove',
|
||
save_title: 'Save changes',
|
||
edit_title: 'Edit this file',
|
||
saved: 'Saved',
|
||
save_failed: 'Save failed: ',
|
||
image_load_failed: 'Could not load image',
|
||
file_open_failed: 'Could not open file',
|
||
downloading: (name) => `Downloading ${name}\u2026`,
|
||
double_click_rename: 'Double-click to rename',
|
||
renamed_to: 'Renamed to ',
|
||
rename_failed: 'Rename failed: ',
|
||
delete_title: 'Delete',
|
||
delete_confirm: (name) => `Delete ${name}?`,
|
||
deleted: 'Deleted ',
|
||
delete_failed: 'Delete failed: ',
|
||
new_file_prompt: 'New file name (e.g. notes.md):',
|
||
project_name_prompt: 'Project name:',
|
||
created: 'Created ',
|
||
create_failed: 'Create failed: ',
|
||
new_folder_prompt: 'New folder name:',
|
||
folder_created: 'Created folder ',
|
||
folder_create_failed: 'Create folder failed: ',
|
||
remove_title: 'Remove',
|
||
empty_dir: '(empty)',
|
||
upload_failed: 'Upload failed: ',
|
||
all_uploads_failed: (n) => `All ${n} upload(s) failed`,
|
||
// settings panel
|
||
settings_title: 'Settings',
|
||
settings_save_btn: 'Save Settings',
|
||
settings_label_model: 'Default Model',
|
||
settings_label_send_key: 'Send Key',
|
||
settings_label_theme: 'Theme',
|
||
settings_label_skin: 'Skin',
|
||
settings_label_language: 'Language',
|
||
settings_label_token_usage: 'Show token usage',
|
||
settings_label_bubble_layout: 'Chat bubble layout',
|
||
settings_label_cli_sessions: 'Show agent sessions',
|
||
settings_label_sync_insights: 'Sync to insights',
|
||
settings_label_check_updates: 'Check for updates',
|
||
settings_label_bot_name: 'Assistant Name',
|
||
settings_label_password: 'Access Password',
|
||
settings_saved: 'Settings saved',
|
||
settings_save_failed: 'Save failed: ',
|
||
settings_load_failed: 'Failed to load settings: ',
|
||
settings_saved_pw: 'Settings saved — password protection enabled and this browser stays signed in',
|
||
settings_saved_pw_updated: 'Settings saved — password updated',
|
||
// login page (used server-side via /api/i18n/login endpoint)
|
||
login_title: 'Sign in',
|
||
login_subtitle: 'Enter your password to continue',
|
||
login_placeholder: 'Password',
|
||
login_btn: 'Sign in',
|
||
login_invalid_pw: 'Invalid password',
|
||
login_conn_failed: 'Connection failed',
|
||
dialog_confirm_title: 'Confirm action',
|
||
dialog_prompt_title: 'Enter a value',
|
||
dialog_confirm_btn: 'Confirm',
|
||
discard: 'Discard',
|
||
clear: 'Clear',
|
||
create: 'Create',
|
||
remove: 'Remove',
|
||
project_name_prompt: 'Project name:',
|
||
// Sidebar & Tabs
|
||
tab_chat: 'Chat',
|
||
tab_tasks: 'Tasks',
|
||
tab_skills: 'Skills',
|
||
tab_memory: 'Memory',
|
||
tab_workspaces: 'Spaces',
|
||
tab_profiles: 'Profiles',
|
||
tab_todos: 'Todos',
|
||
new_conversation: 'New conversation',
|
||
filter_conversations: 'Filter conversations...',
|
||
session_time_unknown: 'Unknown',
|
||
session_time_just_now: 'just now',
|
||
session_time_minutes_ago: (n) => `${n} minute${n === 1 ? '' : 's'} ago`,
|
||
session_time_hours_ago: (n) => `${n} hour${n === 1 ? '' : 's'} ago`,
|
||
session_time_days_ago: (n) => `${n} day${n === 1 ? '' : 's'} ago`,
|
||
session_time_last_week: 'last week',
|
||
session_time_bucket_today: 'Today',
|
||
session_time_bucket_yesterday: 'Yesterday',
|
||
session_time_bucket_this_week: 'This week',
|
||
session_time_bucket_last_week: 'Last week',
|
||
session_time_bucket_older: 'Older',
|
||
scheduled_jobs: 'Scheduled jobs',
|
||
new_job: 'New job',
|
||
loading: 'Loading...',
|
||
search_skills: 'Search skills...',
|
||
new_skill: 'New skill',
|
||
personal_memory: 'Personal memory',
|
||
current_task_list: 'Current task list',
|
||
workspace_desc: 'Add and switch workspaces for your sessions.',
|
||
new_profile: 'New profile',
|
||
transcript: 'Transcript',
|
||
download_transcript: 'Download as Markdown',
|
||
import: 'Import',
|
||
// Settings detail
|
||
settings_label_sound: 'Notification sound',
|
||
settings_desc_sound: 'Play a sound when the assistant finishes a response.',
|
||
settings_label_notifications: 'Browser notifications',
|
||
settings_desc_notifications: 'Show a system notification when a response completes while the app is in the background.',
|
||
settings_desc_token_usage: 'Displays input/output token count below each assistant reply. Also toggled with /usage.',
|
||
settings_desc_bubble_layout: 'Right-align user messages and left-align assistant replies. Off by default to keep code blocks and tool output full-width.',
|
||
settings_desc_cli_sessions: 'Merges sessions from the Hermes CLI (state.db) into the session list. Click a CLI session to import it and continue the conversation.',
|
||
settings_desc_sync_insights: 'Mirrors WebUI token usage to state.db so hermes /insights includes browser session data. Off by default.',
|
||
settings_desc_check_updates: 'Show a banner when newer versions of the WebUI or Agent are available. Runs a background git fetch periodically.',
|
||
settings_desc_bot_name: 'Display name for the assistant throughout the UI. Defaults to Hermes.',
|
||
settings_desc_password: 'Enter a new password to set or change it. Leave blank to keep current setting.',
|
||
password_placeholder: 'Enter new password…',
|
||
disable_auth: 'Disable Auth',
|
||
sign_out: 'Sign Out',
|
||
cancel: 'Cancel',
|
||
create_job: 'Create job',
|
||
save_skill: 'Save skill',
|
||
editing: 'Editing',
|
||
// Empty state
|
||
empty_title: 'What can I help with?',
|
||
empty_subtitle: 'Ask anything, run commands, explore files, or manage your scheduled tasks.',
|
||
suggest_files: 'What files are in this workspace?',
|
||
suggest_schedule: "What's on my schedule today?",
|
||
suggest_plan: 'Help me plan a small project.',
|
||
// onboarding
|
||
onboarding_badge: 'FIRST RUN',
|
||
onboarding_title: 'Welcome to Hermes Web UI',
|
||
onboarding_lead: 'A quick guided setup will verify Hermes, save a real provider configuration, choose a workspace and model, and optionally protect the app with a password.',
|
||
onboarding_back: 'Back',
|
||
onboarding_continue: 'Continue',
|
||
onboarding_skip: 'Skip setup',
|
||
onboarding_skipped: 'Setup skipped — using existing config.',
|
||
onboarding_open: 'Open Hermes',
|
||
onboarding_step_system_title: 'System check',
|
||
onboarding_step_system_desc: 'Verify Hermes Agent and config visibility.',
|
||
onboarding_step_setup_title: 'Provider setup',
|
||
onboarding_step_setup_desc: 'Save the minimum Hermes provider config.',
|
||
onboarding_step_workspace_title: 'Workspace + model',
|
||
onboarding_step_workspace_desc: 'Pick defaults for new sessions and chat.',
|
||
onboarding_step_password_title: 'Optional password',
|
||
onboarding_step_password_desc: 'Protect the Web UI before sharing it.',
|
||
onboarding_step_finish_title: 'Finish',
|
||
onboarding_step_finish_desc: 'Review and enter the app.',
|
||
onboarding_notice_system_ready: 'Hermes Agent looks reachable from the Web UI.',
|
||
onboarding_notice_system_unavailable: 'Hermes Agent is not fully available yet. Bootstrap can install it, but provider setup may still require a terminal.',
|
||
onboarding_check_agent: 'Hermes Agent',
|
||
onboarding_check_agent_ready: 'Detected and importable',
|
||
onboarding_check_agent_missing: 'Missing or partially importable',
|
||
onboarding_check_password: 'Password',
|
||
onboarding_check_password_enabled: 'Already enabled',
|
||
onboarding_check_password_disabled: 'Not enabled yet',
|
||
onboarding_check_provider: 'Provider config',
|
||
onboarding_check_provider_ready: 'Ready to chat',
|
||
onboarding_check_provider_partial: 'Saved but incomplete',
|
||
onboarding_check_provider_pending: 'Needs verification',
|
||
onboarding_config_file: 'Config file:',
|
||
onboarding_env_file: '.env file:',
|
||
onboarding_unknown: 'Unknown',
|
||
onboarding_current_provider: 'Current setup:',
|
||
onboarding_missing_imports: 'Missing imports:',
|
||
onboarding_notice_setup_required: 'Choose a simple provider path here. Advanced OAuth flows still belong in the Hermes CLI for now.',
|
||
onboarding_notice_setup_already_ready: 'A working Hermes provider setup is already detected. You can keep it or replace it here.',
|
||
onboarding_oauth_provider_ready_title: 'Provider already authenticated',
|
||
onboarding_oauth_provider_ready_body: 'This instance is configured to use an OAuth provider (<strong>{provider}</strong>) that was set up via the Hermes CLI. No API key is needed here — click Continue to finish setup.',
|
||
onboarding_oauth_provider_not_ready_title: 'OAuth provider not yet authenticated',
|
||
onboarding_oauth_provider_not_ready_body: 'This instance is configured to use <strong>{provider}</strong>, which uses OAuth rather than an API key. Run <code>hermes auth</code> or <code>hermes model</code> in a terminal to authenticate, then reload the Web UI.',
|
||
onboarding_oauth_switch_hint: 'Or choose a different provider below to switch to an API-key setup:',
|
||
onboarding_notice_workspace: 'These values reuse the same settings APIs as the normal app.',
|
||
onboarding_workspace_label: 'Workspace',
|
||
onboarding_workspace_or_path: 'Or enter a workspace path',
|
||
onboarding_workspace_placeholder: '/home/you/workspace',
|
||
onboarding_provider_label: 'Setup mode',
|
||
onboarding_quick_setup_badge: 'quick setup',
|
||
onboarding_api_key_label: 'API key',
|
||
onboarding_api_key_placeholder: 'Leave blank to keep an existing saved key',
|
||
onboarding_api_key_help_prefix: 'Saved as a secret in your Hermes .env file using',
|
||
onboarding_base_url_label: 'Base URL',
|
||
onboarding_base_url_placeholder: 'https://your-endpoint.example/v1',
|
||
onboarding_base_url_help: 'Use this for OpenAI-compatible routers, self-hosted servers, LiteLLM, Ollama, LM Studio, vLLM, or similar endpoints.',
|
||
onboarding_model_label: 'Default model',
|
||
onboarding_workspace_help: 'Pick the model Hermes should use for new chats after setup completes.',
|
||
onboarding_custom_model_placeholder: 'your-model-name',
|
||
onboarding_custom_model_help: 'For custom endpoints, enter the exact model ID your server expects.',
|
||
onboarding_notice_password_enabled: 'A password is already configured. Enter a new one only if you want to replace it.',
|
||
onboarding_notice_password_recommended: 'Optional but recommended if you will expose the UI beyond localhost.',
|
||
onboarding_password_label: 'Password (optional)',
|
||
onboarding_password_placeholder: 'Leave blank to skip',
|
||
onboarding_password_help: 'Passwords are stored through the existing settings API and hashed server-side.',
|
||
onboarding_notice_finish: 'You can reopen Settings later to change any of this.',
|
||
onboarding_not_set: 'Not set',
|
||
onboarding_password_will_enable: 'Will be enabled',
|
||
onboarding_password_will_replace: 'Will be replaced',
|
||
onboarding_password_keep_existing: 'Keep current password',
|
||
onboarding_password_remains_disabled: 'Will remain disabled',
|
||
onboarding_password_skipped: 'Skipped for now',
|
||
onboarding_finish_help: 'Finishing stores <code>onboarding_completed</code> in settings and drops you into the normal app.',
|
||
onboarding_error_choose_workspace: 'Choose a workspace before continuing.',
|
||
onboarding_error_choose_model: 'Choose a model before continuing.',
|
||
onboarding_error_provider_required: 'Choose a setup mode before continuing.',
|
||
onboarding_error_base_url_required: 'Base URL is required for custom endpoints.',
|
||
onboarding_error_workspace_required: 'Workspace is required.',
|
||
onboarding_error_model_required: 'Model is required.',
|
||
onboarding_complete: 'Onboarding complete',
|
||
// panel/runtime i18n
|
||
error_prefix: 'Error: ',
|
||
not_available: 'N/A',
|
||
never: 'never',
|
||
add: 'Add',
|
||
add_failed: 'Add failed: ',
|
||
remove_failed: 'Remove failed: ',
|
||
switch_failed: 'Switch failed: ',
|
||
name_required: 'Name is required',
|
||
content_required: 'Content is required',
|
||
view: 'View',
|
||
dismiss: 'Dismiss',
|
||
disable: 'Disable',
|
||
cron_no_jobs: 'No scheduled jobs found.',
|
||
cron_status_off: 'off',
|
||
cron_status_paused: 'paused',
|
||
cron_status_error: 'error',
|
||
cron_status_active: 'active',
|
||
cron_next: 'Next',
|
||
cron_last: 'Last',
|
||
cron_run_now: 'Run now',
|
||
cron_pause: 'Pause',
|
||
cron_resume: 'Resume',
|
||
cron_job_name_placeholder: 'Job name',
|
||
cron_schedule_placeholder: 'Schedule',
|
||
cron_prompt_placeholder: 'Prompt',
|
||
cron_last_output: 'Last output',
|
||
cron_all_runs: 'All runs',
|
||
cron_hide_runs: 'Hide runs',
|
||
cron_no_runs_yet: '(no runs yet)',
|
||
cron_schedule_required_example: 'Schedule is required (e.g. "0 9 * * *" or "every 1h")',
|
||
cron_schedule_required: 'Schedule is required',
|
||
cron_prompt_required: 'Prompt is required',
|
||
cron_job_created: 'Job created',
|
||
cron_job_triggered: 'Job triggered',
|
||
cron_job_paused: 'Job paused',
|
||
cron_job_resumed: 'Job resumed',
|
||
cron_job_updated: 'Job updated',
|
||
cron_delete_confirm_title: 'Delete cron job',
|
||
cron_delete_confirm_message: 'This cannot be undone.',
|
||
cron_job_deleted: 'Job deleted',
|
||
cron_completion_status: (name, status) => `Cron "${name}" ${status}`,
|
||
status_failed: 'failed',
|
||
status_completed: 'completed',
|
||
todos_no_active: 'No active task list in this session.',
|
||
clear_conversation_title: 'Clear conversation',
|
||
clear_conversation_message: 'Clear all messages? This cannot be undone.',
|
||
clear_failed: 'Clear failed: ',
|
||
skills_no_match: 'No skills match.',
|
||
linked_files: 'Linked Files',
|
||
skill_load_failed: 'Could not load skill: ',
|
||
skill_file_load_failed: 'Could not load file: ',
|
||
skill_name_required: 'Skill name is required',
|
||
skill_updated: 'Skill updated',
|
||
skill_created: 'Skill created',
|
||
memory_notes_label: 'memory (notes)',
|
||
memory_saved: 'Memory saved',
|
||
my_notes: 'My Notes',
|
||
user_profile: 'User Profile',
|
||
no_notes_yet: 'No notes yet.',
|
||
no_profile_yet: 'No profile yet.',
|
||
workspace_choose_path: 'Choose workspace path',
|
||
workspace_choose_path_meta: 'Add a validated path and switch this conversation',
|
||
workspace_manage: 'Manage workspaces',
|
||
workspace_manage_meta: 'Open the Spaces panel',
|
||
workspace_use_title: 'Use in current session',
|
||
workspace_use: 'Use',
|
||
workspace_add_path_placeholder: 'Add workspace path (e.g. /home/user/my-project)',
|
||
workspace_paths_validated_hint: 'Paths are validated as existing directories before saving.',
|
||
workspace_added: 'Workspace added',
|
||
workspace_remove_confirm_title: 'Remove workspace',
|
||
workspace_remove_confirm_message: (path) => `Remove "${path}"?`,
|
||
workspace_removed: 'Workspace removed',
|
||
workspace_switch_prompt_title: 'Switch workspace',
|
||
workspace_switch_prompt_message: 'Enter an absolute workspace path to add and switch this conversation to.',
|
||
workspace_switch_prompt_confirm: 'Switch',
|
||
workspace_switch_prompt_placeholder: '/Users/you/project',
|
||
workspace_not_added: 'Workspace was not added',
|
||
workspace_already_saved: 'Workspace already saved — choose it from the list',
|
||
workspace_busy_switch: 'Cannot switch workspace while agent is running',
|
||
discard_file_edits_title: 'Discard file edits?',
|
||
discard_file_edits_message: 'Switching workspaces will discard unsaved file edits in the preview.',
|
||
workspace_switched_to: (name) => `Switched to ${name}`,
|
||
profiles_no_profiles: 'No profiles found.',
|
||
profile_api_keys_configured: 'API keys configured',
|
||
profile_gateway_running: 'Gateway running',
|
||
profile_gateway_stopped: 'Gateway stopped',
|
||
profile_active: 'ACTIVE',
|
||
profile_no_configuration: 'No configuration',
|
||
profile_skill_count: (count) => `${count} skill${count === 1 ? '' : 's'}`,
|
||
profile_use: 'Use',
|
||
profile_switch_title: 'Switch to this profile',
|
||
profile_delete_title: 'Delete this profile',
|
||
profile_default_label: '(default)',
|
||
profile_name_placeholder: 'Profile name (lowercase, a-z 0-9 hyphens)',
|
||
profile_clone_label: 'Clone config from active profile',
|
||
profile_base_url_placeholder: 'Base URL (optional, e.g. http://localhost:11434)',
|
||
profile_api_key_placeholder: 'API key (optional)',
|
||
manage_profiles: 'Manage profiles',
|
||
profiles_load_failed: 'Failed to load profiles',
|
||
profiles_busy_switch: 'Cannot switch profiles while agent is running',
|
||
profile_switched_new_conversation: (name) => `Switched to profile: ${name} — new conversation started`,
|
||
profile_switched: (name) => `Switched to profile: ${name}`,
|
||
profile_name_rule: 'Lowercase letters, numbers, hyphens, underscores only',
|
||
profile_base_url_rule: 'Base URL must start with http:// or https://',
|
||
profile_created: (name) => `Profile created: ${name}`,
|
||
profile_delete_confirm_title: (name) => `Delete profile "${name}"?`,
|
||
profile_delete_confirm_message: 'This removes all config, skills, memory, and sessions for this profile.',
|
||
profile_deleted: (name) => `Profile deleted: ${name}`,
|
||
gateways_no_gateways: 'No gateways configured.',
|
||
gateway_running: 'Running',
|
||
gateway_stopped: 'Stopped',
|
||
gateway_stop: 'Stop',
|
||
gateway_start: 'Start',
|
||
gateway_restart: 'Restart',
|
||
gateway_stop_title: 'Stop this gateway',
|
||
gateway_start_title: 'Start this gateway',
|
||
gateway_restart_title: 'Restart this gateway',
|
||
gateway_started: (name) => `Gateway started: ${name}`,
|
||
gateway_stopped_msg: (name) => `Gateway stopped: ${name}`,
|
||
gateway_restarted: (name) => `Gateway restarted: ${name}`,
|
||
gateway_start_failed: 'Failed to start gateway: ',
|
||
gateway_stop_failed: 'Failed to stop gateway: ',
|
||
gateway_restart_failed: 'Failed to restart gateway: ',
|
||
gateway_add: 'Add Gateway',
|
||
gateway_add_title: 'Add New Gateway',
|
||
gateway_add_message: 'Enter gateway name (e.g. telegram, openclaw):',
|
||
gateway_added: (name) => `Gateway added: ${name}`,
|
||
gateway_add_failed: 'Failed to add gateway: ',
|
||
active_conversation_none: 'No active conversation selected.',
|
||
active_conversation_meta: (title, count) => `${title} · ${count} message${count === 1 ? '' : 's'}`,
|
||
settings_unsaved_changes: 'You have unsaved changes.',
|
||
sign_out_failed: 'Sign out failed: ',
|
||
disable_auth_confirm_title: 'Disable password protection',
|
||
disable_auth_confirm_message: 'Anyone will be able to access this instance.',
|
||
auth_disabled: 'Auth disabled — password protection removed',
|
||
disable_auth_failed: 'Failed to disable auth: ',
|
||
bg_error_single: (title) => `"${title}" has encountered an error`,
|
||
bg_error_multi: (count) => `${count} sessions have encountered an error`,
|
||
},
|
||
|
||
ru: {
|
||
_lang: 'ru',
|
||
_label: 'Русский',
|
||
_speech: 'ru-RU',
|
||
cancelling: 'Отменяю…',
|
||
cancel_failed: 'Не удалось отменить: ',
|
||
mic_denied: 'Доступ к микрофону запрещён. Проверьте разрешения браузера.',
|
||
mic_no_speech: 'Речь не распознана. Попробуйте ещё раз.',
|
||
mic_network: 'Распознавание речи недоступно.',
|
||
mic_error: 'Ошибка ввода речи: ',
|
||
session_imported: 'Сеанс импортирован',
|
||
import_failed: 'Не удалось импортировать: ',
|
||
import_invalid_json: 'Неверный JSON',
|
||
image_pasted: 'Изображение вставлено: ',
|
||
edit_message: 'Редактировать сообщение',
|
||
regenerate: 'Сгенерировать ответ заново',
|
||
copy: 'Копировать',
|
||
copied: 'Скопировано!',
|
||
you: 'Вы',
|
||
thinking: 'Думаю',
|
||
expand_all: 'Развернуть всё',
|
||
collapse_all: 'Свернуть всё',
|
||
edit_failed: 'Не удалось отредактировать: ',
|
||
regen_failed: 'Не удалось сгенерировать заново: ',
|
||
reconnect_active: 'Ответ всё ещё генерируется. Обновить, когда будет готово?',
|
||
reconnect_finished: 'Когда вы уходили, ответ ещё генерировался. Сообщения могли обновиться.',
|
||
approval_heading: 'Требуется подтверждение',
|
||
approval_desc_prefix: 'Обнаружена опасная команда',
|
||
approval_btn_once: 'Разрешить один раз',
|
||
approval_btn_once_title: 'Разрешить только эту команду (Enter)',
|
||
approval_btn_session: 'Разрешить на этот сеанс',
|
||
approval_btn_session_title: 'Разрешить для этого сеанса разговора',
|
||
approval_btn_always: 'Всегда разрешать',
|
||
approval_btn_always_title: 'Всегда разрешать команды по этому шаблону',
|
||
approval_btn_deny: 'Запретить',
|
||
approval_btn_deny_title: 'Запретить — не выполнять эту команду',
|
||
approval_responding: 'Отвечаю…',
|
||
untitled: 'Без названия',
|
||
n_messages: (n) => `${n} сообщений`,
|
||
model_unavailable: ' (недоступна)',
|
||
model_unavailable_title: 'Эта модель больше не входит в ваш текущий список провайдеров',
|
||
provider_mismatch_warning: (m, p) =>
|
||
`"${m}" может не работать с вашим настроенным провайдером (${p}). Всё равно отправить или запустите \`hermes model\` в терминале, чтобы переключиться.`,
|
||
provider_mismatch_label: 'Несовпадение провайдера',
|
||
model_custom_label: 'Пользовательский ID модели',
|
||
model_custom_placeholder: 'например, openai/gpt-5.4',
|
||
cmd_help: 'Показать доступные команды',
|
||
cmd_clear: 'Очистить сообщения беседы',
|
||
cmd_compact: 'Сжать контекст беседы',
|
||
cmd_model: 'Переключить модель (например, /model gpt-4o)',
|
||
cmd_workspace: 'Переключить рабочее пространство по названию',
|
||
cmd_new: 'Начать новую сессию чата',
|
||
cmd_usage: 'Показать или скрыть использование токенов',
|
||
cmd_theme: 'Переключить тему (dark/light/slate/solarized/monokai/nord/oled)',
|
||
cmd_personality: 'Переключить личность агента',
|
||
cmd_skills: 'Показать доступные навыки Hermes',
|
||
available_commands: 'Доступные команды:',
|
||
type_slash: 'Введите /, чтобы увидеть команды',
|
||
conversation_cleared: 'Беседа очищена',
|
||
model_usage: 'Использование: /model <name>',
|
||
no_model_match: 'Нет модели, соответствующей "',
|
||
switched_to: 'Переключено на ',
|
||
workspace_usage: 'Использование: /workspace <name>',
|
||
no_workspace_match: 'Нет рабочего пространства, соответствующего "',
|
||
switched_workspace: 'Переключено на рабочее пространство: ',
|
||
workspace_switch_failed: 'Не удалось переключить рабочее пространство: ',
|
||
new_session: 'Новая сессия создана',
|
||
compressing: 'Запрашиваю сжатие контекста...',
|
||
token_usage_on: 'Отображение токенов включено',
|
||
token_usage_off: 'Отображение токенов выключено',
|
||
theme_usage: 'Использование: /theme ',
|
||
theme_set: 'Тема: ',
|
||
no_active_session: 'Нет активной сессии',
|
||
|
||
no_personalities: 'Личности не найдены (добавьте их в ~/.hermes/personalities/)',
|
||
clarify_heading: 'Требуется уточнение',
|
||
clarify_hint: 'Выберите вариант или введите свой ответ ниже.',
|
||
clarify_input_placeholder: 'Введите ответ…',
|
||
clarify_other: 'Другое',
|
||
clarify_responding: 'Отвечаю…',
|
||
clarify_send: 'Отправить',
|
||
cmd_compact_alias: 'Устаревший псевдоним для /compress',
|
||
cmd_compress: 'Сжать контекст беседы (использование: /compress [тема])',
|
||
command_label: 'Команда',
|
||
compress_complete_label: 'Сжатие завершено',
|
||
compress_failed_label: 'Ошибка сжатия',
|
||
compress_running_label: 'Сжатие…',
|
||
context_compaction_label: 'Сжатие контекста',
|
||
focus_label: 'Фокус',
|
||
model_search_no_results: 'Модели не найдены',
|
||
model_search_placeholder: 'Поиск моделей…',
|
||
reference_only_label: 'Только справка',
|
||
settings_label_skin: 'Скин',
|
||
workspace_empty_dir: 'Это рабочее пространство пусто.',
|
||
workspace_empty_no_path: 'Рабочее пространство не выбрано. Настройте его в Настройки → Рабочее пространство.',
|
||
available_personalities: 'Доступные личности:',
|
||
personality_switch_hint: '\n\nИспользуйте `/personality <name>` для переключения или `/personality none` для сброса.',
|
||
personalities_load_failed: 'Не удалось загрузить личности',
|
||
personality_cleared: 'Личность очищена',
|
||
personality_set: 'Личность: ',
|
||
failed_colon: 'Не удалось: ',
|
||
no_workspace: 'Нет рабочего пространства',
|
||
dialog_confirm_title: 'Подтвердить действие',
|
||
dialog_prompt_title: 'Введите значение',
|
||
dialog_confirm_btn: 'Подтвердить',
|
||
unsaved_confirm: 'У вас есть несохранённые изменения в предпросмотре. Отменить и перейти дальше?',
|
||
discard: 'Отменить',
|
||
save: 'Сохранить',
|
||
edit: 'Редактировать',
|
||
clear: 'Очистить',
|
||
create: 'Создать',
|
||
remove: 'Удалить',
|
||
save_title: 'Сохранить изменения',
|
||
edit_title: 'Редактировать этот файл',
|
||
saved: 'Сохранено',
|
||
save_failed: 'Не удалось сохранить: ',
|
||
image_load_failed: 'Не удалось загрузить изображение',
|
||
file_open_failed: 'Не удалось открыть файл',
|
||
downloading: (name) => `Скачиваю ${name}…`,
|
||
double_click_rename: 'Дважды щёлкните, чтобы переименовать',
|
||
renamed_to: 'Переименовано в ',
|
||
rename_failed: 'Не удалось переименовать: ',
|
||
delete_title: 'Удалить',
|
||
delete_confirm: (name) => `Удалить ${name}?`,
|
||
deleted: 'Удалено ',
|
||
delete_failed: 'Не удалось удалить: ',
|
||
new_file_prompt: 'Имя нового файла (например, notes.md):',
|
||
project_name_prompt: 'Имя проекта:',
|
||
created: 'Создано ',
|
||
create_failed: 'Не удалось создать: ',
|
||
new_folder_prompt: 'Имя новой папки:',
|
||
folder_created: 'Папка создана ',
|
||
folder_create_failed: 'Не удалось создать папку: ',
|
||
remove_title: 'Удаление',
|
||
empty_dir: '(пусто)',
|
||
upload_failed: 'Не удалось загрузить: ',
|
||
all_uploads_failed: (n) => `Не удалось загрузить все ${n} файлов`,
|
||
settings_title: 'Настройки',
|
||
settings_save_btn: 'Сохранить настройки',
|
||
settings_label_model: 'Модель по умолчанию',
|
||
settings_label_send_key: 'Клавиша отправки',
|
||
settings_label_theme: 'Тема',
|
||
settings_label_language: 'Язык',
|
||
settings_label_token_usage: 'Показывать использование токенов',
|
||
settings_label_bubble_layout: 'Раскладка пузырьков чата',
|
||
settings_label_cli_sessions: 'Показывать сеансы агента',
|
||
settings_label_sync_insights: 'Синхронизировать с Insights',
|
||
settings_label_check_updates: 'Проверять обновления',
|
||
settings_label_bot_name: 'Имя помощника',
|
||
settings_label_password: 'Пароль доступа',
|
||
settings_saved: 'Настройки сохранены',
|
||
settings_save_failed: 'Не удалось сохранить: ',
|
||
settings_load_failed: 'Не удалось загрузить настройки: ',
|
||
settings_saved_pw: 'Настройки сохранены (пароль задан — теперь требуется вход)',
|
||
settings_saved_pw_updated: 'Настройки сохранены (пароль обновлён)',
|
||
login_title: 'Вход',
|
||
login_subtitle: 'Введите пароль, чтобы продолжить',
|
||
login_placeholder: 'Пароль',
|
||
login_btn: 'Войти',
|
||
login_invalid_pw: 'Неверный пароль',
|
||
login_conn_failed: 'Не удалось подключиться',
|
||
tab_chat: 'Чат',
|
||
tab_tasks: 'Задачи',
|
||
tab_skills: 'Навыки',
|
||
tab_memory: 'Память',
|
||
tab_workspaces: 'Рабочие пространства',
|
||
tab_profiles: 'Профили',
|
||
tab_todos: 'Список дел',
|
||
new_conversation: 'Новая беседа',
|
||
filter_conversations: 'Фильтр бесед...',
|
||
session_time_unknown: 'Неизвестно',
|
||
session_time_just_now: 'только что',
|
||
session_time_minutes_ago: (n) => {
|
||
const mod10 = n % 10;
|
||
const mod100 = n % 100;
|
||
const word = mod10 === 1 && mod100 !== 11
|
||
? 'минута'
|
||
: (mod10 >= 2 && mod10 <= 4 && (mod100 < 10 || mod100 >= 20)
|
||
? 'минуты'
|
||
: 'минут');
|
||
return `${n} ${word} назад`;
|
||
},
|
||
session_time_hours_ago: (n) => {
|
||
const mod10 = n % 10;
|
||
const mod100 = n % 100;
|
||
const word = mod10 === 1 && mod100 !== 11
|
||
? 'час'
|
||
: (mod10 >= 2 && mod10 <= 4 && (mod100 < 10 || mod100 >= 20)
|
||
? 'часа'
|
||
: 'часов');
|
||
return `${n} ${word} назад`;
|
||
},
|
||
session_time_days_ago: (n) => {
|
||
const mod10 = n % 10;
|
||
const mod100 = n % 100;
|
||
const word = mod10 === 1 && mod100 !== 11
|
||
? 'день'
|
||
: (mod10 >= 2 && mod10 <= 4 && (mod100 < 10 || mod100 >= 20)
|
||
? 'дня'
|
||
: 'дней');
|
||
return `${n} ${word} назад`;
|
||
},
|
||
session_time_last_week: 'на прошлой неделе',
|
||
session_time_bucket_today: 'Сегодня',
|
||
session_time_bucket_yesterday: 'Вчера',
|
||
session_time_bucket_this_week: 'На этой неделе',
|
||
session_time_bucket_last_week: 'На прошлой неделе',
|
||
session_time_bucket_older: 'Ранее',
|
||
scheduled_jobs: 'Запланированные задания',
|
||
new_job: 'Новое задание',
|
||
loading: 'Загрузка...',
|
||
search_skills: 'Поиск навыков...',
|
||
new_skill: 'Новый навык',
|
||
personal_memory: 'Личная память',
|
||
current_task_list: 'Текущий список задач',
|
||
workspace_desc: 'Добавляйте рабочие пространства и переключайтесь между ними в своих сеансах.',
|
||
new_profile: 'Новый профиль',
|
||
transcript: 'Транскрипт',
|
||
download_transcript: 'Скачать как Markdown',
|
||
import: 'Импорт',
|
||
settings_label_sound: 'Звук уведомления',
|
||
settings_desc_sound: 'Проигрывать звук, когда помощник завершает ответ.',
|
||
settings_label_notifications: 'Уведомления браузера',
|
||
settings_desc_notifications: 'Показывать системное уведомление, когда ответ готов, а вкладка находится в фоне.',
|
||
settings_desc_token_usage: 'Показывает количество входных и выходных токенов под каждым ответом помощника. Также переключается через /usage.',
|
||
settings_desc_bubble_layout: 'Выравнивает сообщения пользователя справа, а ответы помощника слева. Выключено по умолчанию, чтобы блоки кода и вывод инструментов занимали всю ширину.',
|
||
settings_desc_cli_sessions: 'Объединяет сеансы из Hermes CLI (state.db) в список сеансов. Нажмите на CLI-сеанс, чтобы импортировать его и продолжить разговор.',
|
||
settings_desc_sync_insights: 'Синхронизирует использование токенов WebUI в state.db, чтобы Hermes /insights включал данные браузерных сеансов. Выключено по умолчанию.',
|
||
settings_desc_check_updates: 'Показывает баннер, когда доступны более новые версии WebUI или Agent. Периодически выполняет git fetch в фоне.',
|
||
settings_desc_bot_name: 'Отображаемое имя помощника во всём интерфейсе. По умолчанию Hermes.',
|
||
settings_desc_password: 'Введите новый пароль, чтобы задать или изменить его. Оставьте пустым, чтобы сохранить текущую настройку.',
|
||
password_placeholder: 'Введите новый пароль…',
|
||
disable_auth: 'Отключить авторизацию',
|
||
sign_out: 'Выйти',
|
||
cancel: 'Отмена',
|
||
create_job: 'Создать задание',
|
||
save_skill: 'Сохранить навык',
|
||
editing: 'Редактирование',
|
||
empty_title: 'Чем я могу помочь?',
|
||
empty_subtitle: 'Спрашивайте что угодно, запускайте команды, изучайте файлы или управляйте запланированными задачами.',
|
||
suggest_files: 'Какие файлы есть в этом рабочем пространстве?',
|
||
suggest_schedule: 'Что у меня сегодня в расписании?',
|
||
suggest_plan: 'Помоги спланировать небольшой проект.',
|
||
onboarding_badge: 'ПЕРВЫЙ ЗАПУСК',
|
||
onboarding_title: 'Добро пожаловать в Hermes Web UI',
|
||
onboarding_lead: 'Краткая пошаговая настройка проверит Hermes, сохранит рабочую конфигурацию провайдера, выберет рабочее пространство и модель и при желании защитит приложение паролем.',
|
||
onboarding_back: 'Назад',
|
||
onboarding_continue: 'Продолжить',
|
||
onboarding_skip: 'Пропустить настройку',
|
||
onboarding_skipped: 'Настройка пропущена — используется существующая конфигурация.',
|
||
onboarding_open: 'Открыть Hermes',
|
||
onboarding_step_system_title: 'Проверка системы',
|
||
onboarding_step_system_desc: 'Проверить Hermes Agent и видимость конфигурации.',
|
||
onboarding_step_setup_title: 'Настройка провайдера',
|
||
onboarding_step_setup_desc: 'Сохранить минимальную рабочую конфигурацию провайдера Hermes.',
|
||
onboarding_step_workspace_title: 'Рабочее пространство и модель',
|
||
onboarding_step_workspace_desc: 'Выбрать значения по умолчанию для новых сеансов и чатов.',
|
||
onboarding_step_password_title: 'Необязательный пароль',
|
||
onboarding_step_password_desc: 'Защитить Web UI перед тем, как делиться им.',
|
||
onboarding_step_finish_title: 'Готово',
|
||
onboarding_step_finish_desc: 'Проверьте настройки и войдите в приложение.',
|
||
onboarding_notice_system_ready: 'Hermes Agent, похоже, доступен из Web UI.',
|
||
onboarding_notice_system_unavailable: 'Hermes Agent ещё не полностью доступен. Bootstrap может установить его, но для настройки провайдера всё ещё может понадобиться терминал.',
|
||
onboarding_check_agent: 'Hermes Agent',
|
||
onboarding_check_agent_ready: 'Обнаружен и доступен для импорта',
|
||
onboarding_check_agent_missing: 'Отсутствует или доступен только частично',
|
||
onboarding_check_password: 'Пароль',
|
||
onboarding_check_password_enabled: 'Уже включён',
|
||
onboarding_check_password_disabled: 'Пока не включён',
|
||
onboarding_check_provider: 'Конфигурация провайдера',
|
||
onboarding_check_provider_ready: 'Готова к чату',
|
||
onboarding_check_provider_partial: 'Сохранена, но не завершена',
|
||
onboarding_check_provider_pending: 'Требует проверки',
|
||
onboarding_config_file: 'Файл конфигурации:',
|
||
onboarding_env_file: 'Файл .env:',
|
||
onboarding_unknown: 'Неизвестно',
|
||
onboarding_current_provider: 'Текущая конфигурация:',
|
||
onboarding_missing_imports: 'Отсутствующие импорты:',
|
||
onboarding_notice_setup_required: 'Выберите здесь простой путь настройки провайдера. Продвинутые OAuth-сценарии пока остаются в Hermes CLI.',
|
||
onboarding_notice_setup_already_ready: 'Уже обнаружена рабочая конфигурация провайдера Hermes. Вы можете оставить её или заменить здесь.',
|
||
onboarding_oauth_provider_ready_title: 'Провайдер уже авторизован',
|
||
onboarding_oauth_provider_ready_body: 'Этот экземпляр настроен на использование OAuth-провайдера (<strong>{provider}</strong>), настроенного через Hermes CLI. API-ключ здесь не нужен — нажмите «Продолжить», чтобы завершить настройку.',
|
||
onboarding_oauth_provider_not_ready_title: 'OAuth-провайдер ещё не авторизован',
|
||
onboarding_oauth_provider_not_ready_body: 'Этот экземпляр настроен на использование <strong>{provider}</strong>, который работает через OAuth, а не через API-ключ. Запустите <code>hermes auth</code> или <code>hermes model</code> в терминале, чтобы пройти авторизацию, затем обновите Web UI.',
|
||
onboarding_oauth_switch_hint: 'Или выберите ниже другой провайдер, чтобы перейти на настройку с ключом API:',
|
||
onboarding_notice_workspace: 'Эти значения используют те же API настроек, что и обычное приложение.',
|
||
onboarding_workspace_label: 'Рабочее пространство',
|
||
onboarding_workspace_or_path: 'Или укажите путь к рабочему пространству',
|
||
onboarding_workspace_placeholder: '/home/you/workspace',
|
||
onboarding_provider_label: 'Режим настройки',
|
||
onboarding_quick_setup_badge: 'Быстрая настройка',
|
||
onboarding_api_key_label: 'Ключ API',
|
||
onboarding_api_key_placeholder: 'Оставьте пустым, чтобы сохранить уже сохранённый ключ',
|
||
onboarding_api_key_help_prefix: 'Сохраняется как секрет в вашем файле `.env` Hermes с помощью',
|
||
onboarding_base_url_label: 'Базовый URL',
|
||
onboarding_base_url_placeholder: 'https://your-endpoint.example/v1',
|
||
onboarding_base_url_help: 'Используйте это для OpenAI-compatible маршрутизаторов, self-hosted серверов, LiteLLM, Ollama, LM Studio, vLLM и похожих endpoint-ов.',
|
||
onboarding_model_label: 'Модель по умолчанию',
|
||
onboarding_workspace_help: 'Выберите модель, которую Hermes должен использовать для новых чатов после завершения настройки.',
|
||
onboarding_custom_model_placeholder: 'имя_вашей_модели',
|
||
onboarding_custom_model_help: 'Для собственных endpoint-ов укажите точный ID модели, который ожидает ваш сервер.',
|
||
onboarding_notice_password_enabled: 'Пароль уже настроен. Вводите новый только если хотите заменить текущий.',
|
||
onboarding_notice_password_recommended: 'Необязательно, но рекомендуется, если вы собираетесь открывать UI не только на localhost.',
|
||
onboarding_password_label: 'Пароль (необязательно)',
|
||
onboarding_password_placeholder: 'Оставьте пустым, чтобы пропустить',
|
||
onboarding_password_help: 'Пароли сохраняются через существующий API настроек и хэшируются на сервере.',
|
||
onboarding_notice_finish: 'Позже вы сможете снова открыть настройки и изменить любое из этих значений.',
|
||
onboarding_not_set: 'Не задано',
|
||
onboarding_password_will_enable: 'Будет включён',
|
||
onboarding_password_will_replace: 'Будет заменён текущий пароль',
|
||
onboarding_password_keep_existing: 'Оставить текущий пароль',
|
||
onboarding_password_remains_disabled: 'Останется отключённым',
|
||
onboarding_password_skipped: 'Пропустить пока',
|
||
onboarding_finish_help: 'После завершения в настройках сохранится <code>onboarding_completed</code>, и вы попадёте в обычное приложение.',
|
||
onboarding_error_choose_workspace: 'Выберите рабочее пространство перед продолжением.',
|
||
onboarding_error_choose_model: 'Выберите модель перед продолжением.',
|
||
onboarding_error_provider_required: 'Выберите режим настройки перед продолжением.',
|
||
onboarding_error_base_url_required: 'Для собственных endpoint-ов требуется базовый URL.',
|
||
onboarding_error_workspace_required: 'Рабочее пространство обязательно.',
|
||
onboarding_error_model_required: 'Модель обязательна.',
|
||
onboarding_complete: 'Первичная настройка завершена',
|
||
error_prefix: 'Ошибка: ',
|
||
not_available: 'н/д',
|
||
never: 'никогда',
|
||
add: 'Добавить',
|
||
add_failed: 'Не удалось добавить: ',
|
||
remove_failed: 'Не удалось удалить: ',
|
||
switch_failed: 'Не удалось переключить: ',
|
||
name_required: 'Требуется имя',
|
||
content_required: 'Требуется содержимое',
|
||
view: 'Просмотр',
|
||
dismiss: 'Скрыть',
|
||
disable: 'Отключить',
|
||
cron_no_jobs: 'Запланированные задания не найдены.',
|
||
cron_status_off: 'неактивно',
|
||
cron_status_paused: 'на паузе',
|
||
cron_status_error: 'ошибка',
|
||
cron_status_active: 'активно',
|
||
cron_next: 'Следующий',
|
||
cron_last: 'Последний',
|
||
cron_run_now: 'Запустить сейчас',
|
||
cron_pause: 'Пауза',
|
||
cron_resume: 'Возобновить',
|
||
cron_job_name_placeholder: 'Имя задания',
|
||
cron_schedule_placeholder: 'Расписание',
|
||
cron_prompt_placeholder: 'Промпт',
|
||
cron_last_output: 'Последний вывод',
|
||
cron_all_runs: 'Все запуски',
|
||
cron_hide_runs: 'Скрыть запуски',
|
||
cron_no_runs_yet: '(пока запусков нет)',
|
||
cron_schedule_required_example: 'Требуется расписание (например, "0 9 * * *" или "every 1h")',
|
||
cron_schedule_required: 'Требуется расписание',
|
||
cron_prompt_required: 'Требуется промпт',
|
||
cron_job_created: 'Задание создано',
|
||
cron_job_triggered: 'Задание запущено',
|
||
cron_job_paused: 'Задание поставлено на паузу',
|
||
cron_job_resumed: 'Задание возобновлено',
|
||
cron_job_updated: 'Задание обновлено',
|
||
cron_delete_confirm_title: 'Удалить cron-задание',
|
||
cron_delete_confirm_message: 'Это действие нельзя отменить.',
|
||
cron_job_deleted: 'Задание удалено',
|
||
cron_completion_status: (name, status) => `Cron-задание «${name}» — ${status}`,
|
||
status_failed: 'неудачно',
|
||
status_completed: 'завершено',
|
||
todos_no_active: 'В этой сессии нет активного списка задач.',
|
||
clear_conversation_title: 'Очистить беседу',
|
||
clear_conversation_message: 'Очистить все сообщения? Это действие нельзя отменить.',
|
||
clear_failed: 'Не удалось очистить: ',
|
||
skills_no_match: 'Подходящих навыков не найдено.',
|
||
linked_files: 'Связанные файлы',
|
||
skill_load_failed: 'Не удалось загрузить навык: ',
|
||
skill_file_load_failed: 'Не удалось загрузить файл: ',
|
||
skill_name_required: 'Требуется имя навыка',
|
||
skill_updated: 'Навык обновлён',
|
||
skill_created: 'Навык создан',
|
||
memory_notes_label: 'память (заметки)',
|
||
memory_saved: 'Память сохранена',
|
||
my_notes: 'Мои заметки',
|
||
user_profile: 'Пользовательский профиль',
|
||
no_notes_yet: 'Пока нет заметок.',
|
||
no_profile_yet: 'Пока нет профиля.',
|
||
workspace_choose_path: 'Выберите путь к рабочему пространству',
|
||
workspace_choose_path_meta: 'Добавьте проверенный путь и переключите эту беседу',
|
||
workspace_manage: 'Управление рабочими пространствами',
|
||
workspace_manage_meta: 'Открыть панель Spaces',
|
||
workspace_use_title: 'Использовать в текущем сеансе',
|
||
workspace_use: 'Использовать',
|
||
workspace_add_path_placeholder: 'Добавьте путь к рабочему пространству (например, /Users/you/project)',
|
||
workspace_paths_validated_hint: 'Перед сохранением пути проверяются на существование.',
|
||
workspace_added: 'Рабочее пространство добавлено',
|
||
workspace_remove_confirm_title: 'Удалить рабочее пространство',
|
||
workspace_remove_confirm_message: (path) => `Удалить «${path}»?`,
|
||
workspace_removed: 'Рабочее пространство удалено',
|
||
workspace_switch_prompt_title: 'Переключить рабочее пространство',
|
||
workspace_switch_prompt_message: 'Введите абсолютный путь к рабочему пространству, чтобы добавить его и переключить эту беседу.',
|
||
workspace_switch_prompt_confirm: 'Переключить',
|
||
workspace_switch_prompt_placeholder: '/Users/you/project',
|
||
workspace_not_added: 'Рабочее пространство не добавлено',
|
||
workspace_already_saved: 'Рабочее пространство уже сохранено — выберите его из списка',
|
||
workspace_busy_switch: 'Нельзя переключать рабочее пространство, пока агент работает',
|
||
discard_file_edits_title: 'Отменить изменения файлов?',
|
||
discard_file_edits_message: 'При переключении рабочих пространств несохранённые изменения в предпросмотре будут потеряны.',
|
||
workspace_switched_to: (name) => `Переключено на ${name}`,
|
||
profiles_no_profiles: 'Профили не найдены.',
|
||
profile_api_keys_configured: 'API-ключи настроены',
|
||
profile_gateway_running: 'Gateway запущен',
|
||
profile_gateway_stopped: 'Gateway остановлен',
|
||
profile_active: 'АКТИВЕН',
|
||
profile_no_configuration: 'Нет конфигурации',
|
||
profile_skill_count: (count) => {
|
||
const mod10 = count % 10;
|
||
const mod100 = count % 100;
|
||
const word = mod10 === 1 && mod100 !== 11
|
||
? 'навык'
|
||
: (mod10 >= 2 && mod10 <= 4 && (mod100 < 10 || mod100 >= 20)
|
||
? 'навыка'
|
||
: 'навыков');
|
||
return `${count} ${word}`;
|
||
},
|
||
profile_use: 'Использовать',
|
||
profile_switch_title: 'Переключиться на этот профиль',
|
||
profile_delete_title: 'Удалить этот профиль',
|
||
profile_default_label: '(по умолчанию)',
|
||
profile_name_placeholder: 'Название профиля (строчные буквы, a-z, 0-9, дефисы)',
|
||
profile_clone_label: 'Скопировать конфигурацию из активного профиля',
|
||
profile_base_url_placeholder: 'Базовый URL (необязательно, например http://localhost:11434)',
|
||
profile_api_key_placeholder: 'API-ключ (необязательно)',
|
||
manage_profiles: 'Управление профилями',
|
||
profiles_load_failed: 'Не удалось загрузить профили',
|
||
profiles_busy_switch: 'Нельзя переключать профили, пока агент работает',
|
||
profile_switched_new_conversation: (name) => `Переключено на профиль: ${name} — начата новая беседа`,
|
||
profile_switched: (name) => `Переключено на профиль: ${name}`,
|
||
profile_name_rule: 'Только строчные буквы, цифры, дефисы и подчёркивания',
|
||
profile_base_url_rule: 'Базовый URL должен начинаться с http:// или https://',
|
||
profile_created: (name) => `Профиль создан: ${name}`,
|
||
profile_delete_confirm_title: (name) => `Удалить профиль «${name}»?`,
|
||
profile_delete_confirm_message: 'Это удалит всю конфигурацию, навыки, память и сеансы этого профиля.',
|
||
profile_deleted: (name) => `Профиль удалён: ${name}`,
|
||
active_conversation_none: 'Активная беседа не выбрана.',
|
||
active_conversation_meta: (title, count) => {
|
||
const mod10 = count % 10;
|
||
const mod100 = count % 100;
|
||
const word = mod10 === 1 && mod100 !== 11
|
||
? 'сообщение'
|
||
: (mod10 >= 2 && mod10 <= 4 && (mod100 < 10 || mod100 >= 20)
|
||
? 'сообщения'
|
||
: 'сообщений');
|
||
return `${title} · ${count} ${word}`;
|
||
},
|
||
settings_unsaved_changes: 'У вас есть несохранённые изменения.',
|
||
sign_out_failed: 'Не удалось выйти: ',
|
||
disable_auth_confirm_title: 'Отключить защиту паролем',
|
||
disable_auth_confirm_message: 'Любой сможет получить доступ к этому экземпляру.',
|
||
auth_disabled: 'Авторизация отключена — защита паролем снята',
|
||
disable_auth_failed: 'Не удалось отключить авторизацию: ',
|
||
bg_error_single: (title) => `В "${title}" возникла ошибка`,
|
||
bg_error_multi: (count) => `${count} сеансов столкнулись с ошибкой`,
|
||
},
|
||
|
||
es: {
|
||
_lang: 'es',
|
||
_label: 'Español',
|
||
_speech: 'es-ES',
|
||
// boot.js
|
||
cancelling: 'Cancelando…',
|
||
cancel_failed: 'Error al cancelar: ',
|
||
mic_denied: 'Acceso al micrófono denegado. Revisa los permisos del navegador.',
|
||
mic_no_speech: 'No se detectó voz. Inténtalo de nuevo.',
|
||
mic_network: 'El reconocimiento de voz no está disponible.',
|
||
mic_error: 'Error de entrada por voz: ',
|
||
session_imported: 'Sesión importada',
|
||
import_failed: 'Error al importar: ',
|
||
import_invalid_json: 'JSON inválido',
|
||
image_pasted: 'Imagen pegada: ',
|
||
// messages.js
|
||
edit_message: 'Editar mensaje',
|
||
regenerate: 'Regenerar respuesta',
|
||
copy: 'Copiar',
|
||
copied: '¡Copiado!',
|
||
you: 'Tú',
|
||
thinking: 'Pensando',
|
||
expand_all: 'Expandir todo',
|
||
collapse_all: 'Contraer todo',
|
||
edit_failed: 'Error al editar: ',
|
||
regen_failed: 'Error al regenerar: ',
|
||
reconnect_active: 'Todavía se está generando una respuesta. ¿Recargar cuando termine?',
|
||
reconnect_finished: 'Había una respuesta en curso cuando te fuiste. Puede que los mensajes se hayan actualizado.',
|
||
// approval card
|
||
approval_heading: 'Se requiere aprobación',
|
||
approval_desc_prefix: 'Se detectó un comando peligroso',
|
||
approval_btn_once: 'Permitir una vez',
|
||
approval_btn_once_title: 'Permitir solo este comando (Enter)',
|
||
approval_btn_session: 'Permitir en la sesión',
|
||
approval_btn_session_title: 'Permitir durante esta sesión de conversación',
|
||
approval_btn_always: 'Permitir siempre',
|
||
approval_btn_always_title: 'Permitir siempre este patrón de comando',
|
||
approval_btn_deny: 'Denegar',
|
||
approval_btn_deny_title: 'Denegar — no ejecutar este comando',
|
||
approval_responding: 'Respondiendo…',
|
||
clarify_heading: 'Se necesita aclaración',
|
||
clarify_hint: 'Elige una opción o escribe tu propia respuesta abajo.',
|
||
clarify_other: 'Otra',
|
||
clarify_send: 'Enviar',
|
||
clarify_input_placeholder: 'Escribe tu respuesta…',
|
||
clarify_responding: 'Respondiendo…',
|
||
untitled: 'Sin título',
|
||
n_messages: (n) => `${n} mensajes`,
|
||
model_unavailable: ' (no disponible)',
|
||
model_unavailable_title: 'Este modelo ya no está en tu lista actual de proveedores',
|
||
provider_mismatch_warning: (m,p)=>`"${m}" puede no funcionar con tu proveedor configurado (${p}). Envía de todas formas, o ejecuta \`hermes model\` en la terminal para cambiar.`,
|
||
provider_mismatch_label: 'Proveedor incompatible',
|
||
model_custom_label: 'ID de modelo personalizado',
|
||
model_custom_placeholder: 'p. ej. openai/gpt-5.4',
|
||
model_search_placeholder: 'Buscar modelos…',
|
||
model_search_no_results: 'No se encontraron modelos',
|
||
// commands.js
|
||
cmd_help: 'Listar los comandos disponibles',
|
||
cmd_clear: 'Borrar los mensajes de la conversación',
|
||
cmd_compress: 'Comprimir manualmente el contexto de la conversación (uso: /compress [tema])',
|
||
cmd_compact_alias: 'Alias antiguo de /compress',
|
||
cmd_compact: 'Comprimir contexto de la conversación',
|
||
cmd_model: 'Cambiar de modelo (p. ej. /model gpt-4o)',
|
||
cmd_workspace: 'Cambiar de espacio de trabajo por nombre',
|
||
cmd_new: 'Iniciar una nueva sesión de chat',
|
||
cmd_usage: 'Activar o desactivar el uso de tokens',
|
||
cmd_theme: 'Cambiar apariencia (tema: system/dark/light, skin: default/ares/mono/slate/poseidon/sisyphus/charizard)',
|
||
cmd_personality: 'Cambiar la personalidad del agente',
|
||
cmd_skills: 'Listar las skills de Hermes disponibles',
|
||
available_commands: 'Comandos disponibles:',
|
||
type_slash: 'Escribe / para ver los comandos',
|
||
conversation_cleared: 'Conversación borrada',
|
||
command_label: 'Comando',
|
||
context_compaction_label: 'Compacción de contexto',
|
||
reference_only_label: 'Solo referencia',
|
||
model_usage: 'Uso: /model <name>',
|
||
no_model_match: 'No hay ningún modelo que coincida con "',
|
||
switched_to: 'Se cambió a ',
|
||
workspace_usage: 'Uso: /workspace <name>',
|
||
no_workspace_match: 'No hay ningún espacio de trabajo que coincida con "',
|
||
switched_workspace: 'Se cambió al espacio de trabajo: ',
|
||
workspace_switch_failed: 'Error al cambiar de espacio de trabajo: ',
|
||
new_session: 'Nueva sesión creada',
|
||
compressing: 'Solicitando compresión del contexto...',
|
||
compress_running_label: 'Comprimiendo',
|
||
compress_complete_label: 'Compresión completa',
|
||
compress_failed_label: 'La compresión falló',
|
||
focus_label: 'Tema',
|
||
token_usage_on: 'Uso de tokens activado',
|
||
token_usage_off: 'Uso de tokens desactivado',
|
||
theme_usage: 'Uso: /theme ',
|
||
theme_set: 'Tema: ',
|
||
no_active_session: 'No hay ninguna sesión activa',
|
||
no_personalities: 'No se encontraron personalidades (añádelas a ~/.hermes/personalities/)',
|
||
available_personalities: 'Personalidades disponibles:',
|
||
personality_switch_hint: '\n\nUsa `/personality <name>` para cambiar, o `/personality none` para limpiar.',
|
||
personalities_load_failed: 'No se pudieron cargar las personalidades',
|
||
personality_cleared: 'Personalidad borrada',
|
||
personality_set: 'Personalidad: ',
|
||
failed_colon: 'Error: ',
|
||
// ui.js
|
||
no_workspace: 'Sin espacio de trabajo',
|
||
workspace_empty_no_path: 'No hay espacio de trabajo seleccionado. Configure un espacio de trabajo en Ajustes \u2192 Workspace para explorar archivos.',
|
||
workspace_empty_dir: 'Este espacio de trabajo está vacío.',
|
||
// workspace.js
|
||
unsaved_confirm: 'Tienes cambios sin guardar en la vista previa. ¿Descartar y navegar?',
|
||
save: 'Guardar',
|
||
edit: 'Editar',
|
||
save_title: 'Guardar cambios',
|
||
edit_title: 'Editar este archivo',
|
||
saved: 'Guardado',
|
||
save_failed: 'Error al guardar: ',
|
||
image_load_failed: 'No se pudo cargar la imagen',
|
||
file_open_failed: 'No se pudo abrir el archivo',
|
||
downloading: (name) => `Descargando ${name}…`,
|
||
double_click_rename: 'Haz doble clic para renombrar',
|
||
renamed_to: 'Renombrado a ',
|
||
rename_failed: 'Error al renombrar: ',
|
||
delete_title: 'Eliminar',
|
||
delete_confirm: (name) => `¿Eliminar ${name}?`,
|
||
deleted: 'Eliminado ',
|
||
delete_failed: 'Error al eliminar: ',
|
||
new_file_prompt: 'Nombre del archivo nuevo (p. ej. notes.md):',
|
||
created: 'Creado ',
|
||
create_failed: 'Error al crear: ',
|
||
new_folder_prompt: 'Nombre de la carpeta nueva:',
|
||
folder_created: 'Carpeta creada ',
|
||
folder_create_failed: 'Error al crear la carpeta: ',
|
||
remove_title: 'Quitar',
|
||
empty_dir: '(vacío)',
|
||
upload_failed: 'Error al subir: ',
|
||
all_uploads_failed: (n) => `Fallaron las ${n} subida(s)`,
|
||
// settings panel
|
||
settings_title: 'Configuración',
|
||
settings_save_btn: 'Guardar configuración',
|
||
settings_label_model: 'Modelo predeterminado',
|
||
settings_label_send_key: 'Tecla de envío',
|
||
settings_label_theme: 'Tema',
|
||
settings_label_skin: 'Piel',
|
||
settings_label_language: 'Idioma',
|
||
settings_label_token_usage: 'Mostrar uso de tokens',
|
||
settings_label_bubble_layout: 'Disposición en burbujas',
|
||
settings_label_cli_sessions: 'Mostrar sesiones de CLI',
|
||
settings_label_sync_insights: 'Sincronizar con insights',
|
||
settings_label_check_updates: 'Buscar actualizaciones',
|
||
settings_label_bot_name: 'Nombre del asistente',
|
||
settings_label_password: 'Contraseña de acceso',
|
||
settings_saved: 'Configuración guardada',
|
||
settings_save_failed: 'Error al guardar: ',
|
||
settings_load_failed: 'Error al cargar la configuración: ',
|
||
settings_saved_pw: 'Configuración guardada — la contraseña queda activada y este navegador sigue autenticado',
|
||
settings_saved_pw_updated: 'Configuración guardada — contraseña actualizada',
|
||
// login page (used server-side via /api/i18n/login endpoint)
|
||
login_title: 'Iniciar sesión',
|
||
login_subtitle: 'Introduce tu contraseña para continuar',
|
||
login_placeholder: 'Contraseña',
|
||
login_btn: 'Entrar',
|
||
login_invalid_pw: 'Contraseña inválida',
|
||
login_conn_failed: 'Error de conexión',
|
||
dialog_confirm_title: 'Confirmar acción',
|
||
dialog_prompt_title: 'Introduce un valor',
|
||
dialog_confirm_btn: 'Confirmar',
|
||
discard: 'Descartar',
|
||
clear: 'Borrar',
|
||
create: 'Crear',
|
||
remove: 'Quitar',
|
||
project_name_prompt: 'Nombre del proyecto:',
|
||
// Sidebar & Tabs
|
||
tab_chat: 'Chat',
|
||
tab_tasks: 'Tareas',
|
||
tab_skills: 'Habilidades',
|
||
tab_memory: 'Memoria',
|
||
tab_workspaces: 'Espacios',
|
||
tab_profiles: 'Perfiles',
|
||
tab_todos: 'Todos',
|
||
new_conversation: 'Nueva conversación',
|
||
filter_conversations: 'Filtrar conversaciones...',
|
||
session_time_unknown: 'Desconocido',
|
||
session_time_just_now: 'justo ahora',
|
||
session_time_minutes_ago: (n) => `hace ${n} minuto${n === 1 ? '' : 's'}`,
|
||
session_time_hours_ago: (n) => `hace ${n} hora${n === 1 ? '' : 's'}`,
|
||
session_time_days_ago: (n) => `hace ${n} día${n === 1 ? '' : 's'}`,
|
||
session_time_last_week: 'la semana pasada',
|
||
session_time_bucket_today: 'Hoy',
|
||
session_time_bucket_yesterday: 'Ayer',
|
||
session_time_bucket_this_week: 'Esta semana',
|
||
session_time_bucket_last_week: 'La semana pasada',
|
||
session_time_bucket_older: 'Más antiguo',
|
||
scheduled_jobs: 'Tareas programadas',
|
||
new_job: 'Nueva tarea',
|
||
loading: 'Cargando...',
|
||
search_skills: 'Buscar skills...',
|
||
new_skill: 'Nueva skill',
|
||
personal_memory: 'Memoria personal',
|
||
current_task_list: 'Lista de tareas actual',
|
||
workspace_desc: 'Añade y cambia espacios de trabajo para tus sesiones.',
|
||
new_profile: 'Nuevo perfil',
|
||
transcript: 'Transcripción',
|
||
download_transcript: 'Descargar como Markdown',
|
||
import: 'Importar',
|
||
// Settings detail
|
||
settings_label_sound: 'Sonido de notificación',
|
||
settings_desc_sound: 'Reproduce un sonido cuando el asistente termina una respuesta.',
|
||
settings_label_notifications: 'Notificaciones del navegador',
|
||
settings_desc_notifications: 'Muestra una notificación del sistema cuando una respuesta termina mientras la pestaña está en segundo plano.',
|
||
settings_desc_token_usage: 'Muestra el conteo de tokens de entrada/salida debajo de cada respuesta del asistente. También se puede alternar con /usage.',
|
||
settings_desc_bubble_layout: 'Alinea los mensajes del usuario a la derecha y las respuestas del asistente a la izquierda. Desactivado por defecto para mantener los bloques de código y la salida de herramientas a ancho completo.',
|
||
settings_desc_cli_sessions: 'Fusiona las sesiones del CLI de Hermes (state.db) en la lista de sesiones. Haz clic en una sesión de CLI para importarla y continuar la conversación.',
|
||
settings_desc_sync_insights: 'Refleja el uso de tokens de la WebUI en state.db para que hermes /insights incluya datos de sesiones del navegador. Desactivado por defecto.',
|
||
settings_desc_check_updates: 'Muestra un banner cuando haya versiones más nuevas de la WebUI o del Agent. Ejecuta periódicamente un git fetch en segundo plano.',
|
||
settings_desc_bot_name: 'Nombre visible del asistente en toda la UI. Por defecto es Hermes.',
|
||
settings_desc_password: 'Introduce una nueva contraseña para establecerla o cambiarla. Déjalo en blanco para mantener la configuración actual.',
|
||
password_placeholder: 'Introduce una contraseña nueva…',
|
||
disable_auth: 'Desactivar autenticación',
|
||
sign_out: 'Cerrar sesión',
|
||
cancel: 'Cancelar',
|
||
create_job: 'Crear tarea',
|
||
save_skill: 'Guardar skill',
|
||
editing: 'Editando',
|
||
// Empty state
|
||
empty_title: '¿En qué puedo ayudarte?',
|
||
empty_subtitle: 'Pregunta lo que quieras, ejecuta comandos, explora archivos o gestiona tus tareas programadas.',
|
||
suggest_files: '¿Qué archivos hay en este espacio de trabajo?',
|
||
suggest_schedule: '¿Qué tengo hoy en mi agenda?',
|
||
suggest_plan: 'Ayúdame a planificar un proyecto pequeño.',
|
||
// onboarding
|
||
onboarding_badge: 'PRIMER USO',
|
||
onboarding_title: 'Bienvenido a Hermes Web UI',
|
||
onboarding_lead: 'Una guía rápida verificará Hermes, guardará una configuración real del proveedor, elegirá un espacio de trabajo y un modelo, y opcionalmente protegerá la app con una contraseña.',
|
||
onboarding_back: 'Atrás',
|
||
onboarding_continue: 'Continuar',
|
||
onboarding_skip: 'Omitir configuración',
|
||
onboarding_skipped: 'Configuración omitida — se usa la configuración existente.',
|
||
onboarding_open: 'Abrir Hermes',
|
||
onboarding_step_system_title: 'Comprobación del sistema',
|
||
onboarding_step_system_desc: 'Verifica Hermes Agent y la visibilidad de la configuración.',
|
||
onboarding_step_setup_title: 'Configuración del proveedor',
|
||
onboarding_step_setup_desc: 'Guarda la configuración mínima real de Hermes.',
|
||
onboarding_step_workspace_title: 'Espacio de trabajo + modelo',
|
||
onboarding_step_workspace_desc: 'Elige los valores predeterminados para nuevas sesiones y chats.',
|
||
onboarding_step_password_title: 'Contraseña opcional',
|
||
onboarding_step_password_desc: 'Protege la Web UI antes de compartirla.',
|
||
onboarding_step_finish_title: 'Finalizar',
|
||
onboarding_step_finish_desc: 'Revisa todo y entra en la app.',
|
||
onboarding_notice_system_ready: 'Parece que Hermes Agent está accesible desde la Web UI.',
|
||
onboarding_notice_system_unavailable: 'Hermes Agent todavía no está totalmente disponible. Bootstrap puede instalarlo, pero la configuración del proveedor quizá aún requiera una terminal.',
|
||
onboarding_check_agent: 'Hermes Agent',
|
||
onboarding_check_agent_ready: 'Detectado e importable',
|
||
onboarding_check_agent_missing: 'Falta o solo es parcialmente importable',
|
||
onboarding_check_password: 'Contraseña',
|
||
onboarding_check_password_enabled: 'Ya está activada',
|
||
onboarding_check_password_disabled: 'Todavía no está activada',
|
||
onboarding_check_provider: 'Configuración del proveedor',
|
||
onboarding_check_provider_ready: 'Listo para chatear',
|
||
onboarding_check_provider_partial: 'Guardado pero incompleto',
|
||
onboarding_check_provider_pending: 'Necesita verificación',
|
||
onboarding_config_file: 'Archivo de configuración:',
|
||
onboarding_env_file: 'Archivo .env:',
|
||
onboarding_unknown: 'Desconocido',
|
||
onboarding_current_provider: 'Configuración actual:',
|
||
onboarding_missing_imports: 'Importaciones faltantes:',
|
||
onboarding_notice_setup_required: 'Elige aquí una ruta simple de proveedor. Los flujos OAuth avanzados siguen siendo del CLI de Hermes por ahora.',
|
||
onboarding_notice_setup_already_ready: 'Ya se detectó una configuración funcional del proveedor de Hermes. Puedes conservarla o reemplazarla aquí.',
|
||
onboarding_oauth_provider_ready_title: 'Proveedor ya autenticado',
|
||
onboarding_oauth_provider_ready_body: 'Esta instancia está configurada para usar un proveedor OAuth (<strong>{provider}</strong>) configurado mediante la CLI de Hermes. No se necesita clave API aquí — haz clic en Continuar para finalizar la configuración.',
|
||
onboarding_oauth_provider_not_ready_title: 'Proveedor OAuth no autenticado aún',
|
||
onboarding_oauth_provider_not_ready_body: 'Esta instancia está configurada para usar <strong>{provider}</strong>, que utiliza OAuth en lugar de una clave API. Ejecuta <code>hermes auth</code> o <code>hermes model</code> en una terminal para autenticarte y recarga la interfaz web.',
|
||
onboarding_oauth_switch_hint: 'O elige un proveedor diferente a continuación para cambiar a la configuración con clave API:',
|
||
onboarding_notice_workspace: 'Estos valores reutilizan las mismas APIs de configuración que la app normal.',
|
||
onboarding_workspace_label: 'Espacio de trabajo',
|
||
onboarding_workspace_or_path: 'O introduce la ruta de un espacio de trabajo',
|
||
onboarding_workspace_placeholder: '/home/you/workspace',
|
||
onboarding_provider_label: 'Modo de configuración',
|
||
onboarding_quick_setup_badge: 'configuración rápida',
|
||
onboarding_api_key_label: 'API key',
|
||
onboarding_api_key_placeholder: 'Déjala en blanco para conservar una key ya guardada',
|
||
onboarding_api_key_help_prefix: 'Se guarda como secreto en tu archivo .env de Hermes usando',
|
||
onboarding_base_url_label: 'Base URL',
|
||
onboarding_base_url_placeholder: 'https://tu-endpoint.example/v1',
|
||
onboarding_base_url_help: 'Úsalo para routers OpenAI-compatible, servidores autoalojados, LiteLLM, Ollama, LM Studio, vLLM o endpoints parecidos.',
|
||
onboarding_model_label: 'Modelo predeterminado',
|
||
onboarding_workspace_help: 'Elige el modelo que Hermes debe usar para nuevos chats cuando termine la configuración.',
|
||
onboarding_custom_model_placeholder: 'tu-modelo',
|
||
onboarding_custom_model_help: 'Para endpoints personalizados, introduce el identificador exacto del modelo que espera tu servidor.',
|
||
onboarding_notice_password_enabled: 'Ya hay una contraseña configurada. Introduce una nueva solo si quieres reemplazarla.',
|
||
onboarding_notice_password_recommended: 'Es opcional, pero recomendable si vas a exponer la UI más allá de localhost.',
|
||
onboarding_password_label: 'Contraseña (opcional)',
|
||
onboarding_password_placeholder: 'Déjala en blanco para omitirla',
|
||
onboarding_password_help: 'Las contraseñas se guardan mediante la API de configuración existente y se hashean en el servidor.',
|
||
onboarding_notice_finish: 'Puedes volver a abrir Configuración más tarde para cambiar cualquiera de estos valores.',
|
||
onboarding_not_set: 'Sin definir',
|
||
onboarding_password_will_enable: 'Se activará',
|
||
onboarding_password_will_replace: 'Se reemplazará',
|
||
onboarding_password_keep_existing: 'Mantener la contraseña actual',
|
||
onboarding_password_remains_disabled: 'Seguirá desactivada',
|
||
onboarding_password_skipped: 'Se omitirá por ahora',
|
||
onboarding_finish_help: 'Al finalizar se guarda <code>onboarding_completed</code> en la configuración y entras en la app normal.',
|
||
onboarding_error_choose_workspace: 'Elige un espacio de trabajo antes de continuar.',
|
||
onboarding_error_choose_model: 'Elige un modelo antes de continuar.',
|
||
onboarding_error_provider_required: 'Elige un modo de configuración antes de continuar.',
|
||
onboarding_error_base_url_required: 'La base URL es obligatoria para endpoints personalizados.',
|
||
onboarding_error_workspace_required: 'El espacio de trabajo es obligatorio.',
|
||
onboarding_error_model_required: 'El modelo es obligatorio.',
|
||
onboarding_complete: 'Onboarding completado',
|
||
// panel/runtime i18n
|
||
error_prefix: 'Error: ',
|
||
not_available: 'N/A',
|
||
never: 'never',
|
||
add: 'Add',
|
||
add_failed: 'Add failed: ',
|
||
remove_failed: 'Remove failed: ',
|
||
switch_failed: 'Switch failed: ',
|
||
name_required: 'Name is required',
|
||
content_required: 'Content is required',
|
||
view: 'View',
|
||
dismiss: 'Dismiss',
|
||
disable: 'Disable',
|
||
cron_no_jobs: 'No scheduled jobs found.',
|
||
cron_status_off: 'off',
|
||
cron_status_paused: 'paused',
|
||
cron_status_error: 'error',
|
||
cron_status_active: 'active',
|
||
cron_next: 'Next',
|
||
cron_last: 'Last',
|
||
cron_run_now: 'Run now',
|
||
cron_pause: 'Pause',
|
||
cron_resume: 'Resume',
|
||
cron_job_name_placeholder: 'Job name',
|
||
cron_schedule_placeholder: 'Schedule',
|
||
cron_prompt_placeholder: 'Prompt',
|
||
cron_last_output: 'Last output',
|
||
cron_all_runs: 'All runs',
|
||
cron_hide_runs: 'Hide runs',
|
||
cron_no_runs_yet: '(no runs yet)',
|
||
cron_schedule_required_example: 'Schedule is required (e.g. "0 9 * * *" or "every 1h")',
|
||
cron_schedule_required: 'Schedule is required',
|
||
cron_prompt_required: 'Prompt is required',
|
||
cron_job_created: 'Job created',
|
||
cron_job_triggered: 'Job triggered',
|
||
cron_job_paused: 'Job paused',
|
||
cron_job_resumed: 'Job resumed',
|
||
cron_job_updated: 'Job updated',
|
||
cron_delete_confirm_title: 'Delete cron job',
|
||
cron_delete_confirm_message: 'This cannot be undone.',
|
||
cron_job_deleted: 'Job deleted',
|
||
cron_completion_status: (name, status) => `Cron "${name}" ${status}`,
|
||
status_failed: 'failed',
|
||
status_completed: 'completed',
|
||
todos_no_active: 'No active task list in this session.',
|
||
clear_conversation_title: 'Clear conversation',
|
||
clear_conversation_message: 'Clear all messages? This cannot be undone.',
|
||
clear_failed: 'Clear failed: ',
|
||
skills_no_match: 'No skills match.',
|
||
linked_files: 'Linked Files',
|
||
skill_load_failed: 'Could not load skill: ',
|
||
skill_file_load_failed: 'Could not load file: ',
|
||
skill_name_required: 'Skill name is required',
|
||
skill_updated: 'Skill updated',
|
||
skill_created: 'Skill created',
|
||
memory_notes_label: 'memory (notes)',
|
||
memory_saved: 'Memory saved',
|
||
my_notes: 'My Notes',
|
||
user_profile: 'User Profile',
|
||
no_notes_yet: 'No notes yet.',
|
||
no_profile_yet: 'No profile yet.',
|
||
workspace_choose_path: 'Choose workspace path',
|
||
workspace_choose_path_meta: 'Add a validated path and switch this conversation',
|
||
workspace_manage: 'Manage workspaces',
|
||
workspace_manage_meta: 'Open the Spaces panel',
|
||
workspace_use_title: 'Use in current session',
|
||
workspace_use: 'Use',
|
||
workspace_add_path_placeholder: 'Add workspace path (e.g. /home/user/my-project)',
|
||
workspace_paths_validated_hint: 'Paths are validated as existing directories before saving.',
|
||
workspace_added: 'Workspace added',
|
||
workspace_remove_confirm_title: 'Remove workspace',
|
||
workspace_remove_confirm_message: (path) => `Remove "${path}"?`,
|
||
workspace_removed: 'Workspace removed',
|
||
workspace_switch_prompt_title: 'Switch workspace',
|
||
workspace_switch_prompt_message: 'Enter an absolute workspace path to add and switch this conversation to.',
|
||
workspace_switch_prompt_confirm: 'Switch',
|
||
workspace_switch_prompt_placeholder: '/Users/you/project',
|
||
workspace_not_added: 'Workspace was not added',
|
||
workspace_already_saved: 'Workspace already saved — choose it from the list',
|
||
workspace_busy_switch: 'Cannot switch workspace while agent is running',
|
||
discard_file_edits_title: 'Discard file edits?',
|
||
discard_file_edits_message: 'Switching workspaces will discard unsaved file edits in the preview.',
|
||
workspace_switched_to: (name) => `Switched to ${name}`,
|
||
profiles_no_profiles: 'No profiles found.',
|
||
profile_api_keys_configured: 'API keys configured',
|
||
profile_gateway_running: 'Gateway running',
|
||
profile_gateway_stopped: 'Gateway stopped',
|
||
profile_active: 'ACTIVE',
|
||
profile_no_configuration: 'No configuration',
|
||
profile_skill_count: (count) => `${count} habilidad${count === 1 ? '' : 'es'}`,
|
||
profile_use: 'Use',
|
||
profile_switch_title: 'Switch to this profile',
|
||
profile_delete_title: 'Eliminar este perfil',
|
||
profile_default_label: '(predeterminado)',
|
||
profile_name_placeholder: 'Nombre del perfil (minúsculas, a-z, 0-9, guiones)',
|
||
profile_clone_label: 'Clonar configuración del perfil activo',
|
||
profile_base_url_placeholder: 'URL base (opcional, p. ej. http://localhost:11434)',
|
||
profile_api_key_placeholder: 'Clave API (opcional)',
|
||
manage_profiles: 'Manage profiles',
|
||
profiles_load_failed: 'Failed to load profiles',
|
||
profiles_busy_switch: 'Cannot switch profiles while agent is running',
|
||
profile_switched_new_conversation: (name) => `Switched to profile: ${name} — new conversation started`,
|
||
profile_switched: (name) => `Switched to profile: ${name}`,
|
||
profile_name_rule: 'Lowercase letters, numbers, hyphens, underscores only',
|
||
profile_base_url_rule: 'Base URL must start with http:// or https://',
|
||
profile_created: (name) => `Profile created: ${name}`,
|
||
profile_delete_confirm_title: (name) => `Delete profile "${name}"?`,
|
||
profile_delete_confirm_message: 'This removes all config, skills, memory, and sessions for this profile.',
|
||
profile_deleted: (name) => `Profile deleted: ${name}`,
|
||
gateways_no_gateways: 'No gateways configured.',
|
||
gateway_running: 'Running',
|
||
gateway_stopped: 'Stopped',
|
||
gateway_stop: 'Stop',
|
||
gateway_start: 'Start',
|
||
gateway_restart: 'Restart',
|
||
gateway_stop_title: 'Stop this gateway',
|
||
gateway_start_title: 'Start this gateway',
|
||
gateway_restart_title: 'Restart this gateway',
|
||
gateway_started: (name) => `Gateway started: ${name}`,
|
||
gateway_stopped_msg: (name) => `Gateway stopped: ${name}`,
|
||
gateway_restarted: (name) => `Gateway restarted: ${name}`,
|
||
gateway_start_failed: 'Failed to start gateway: ',
|
||
gateway_stop_failed: 'Failed to stop gateway: ',
|
||
gateway_restart_failed: 'Failed to restart gateway: ',
|
||
gateway_add: 'Add Gateway',
|
||
gateway_add_title: 'Add New Gateway',
|
||
gateway_add_message: 'Enter gateway name (e.g. telegram, openclaw):',
|
||
gateway_added: (name) => `Gateway added: ${name}`,
|
||
gateway_add_failed: 'Failed to add gateway: ',
|
||
active_conversation_none: 'No active conversation selected.',
|
||
active_conversation_meta: (title, count) => `${title} · ${count} message${count === 1 ? '' : 's'}`,
|
||
settings_unsaved_changes: 'You have unsaved changes.',
|
||
sign_out_failed: 'Sign out failed: ',
|
||
disable_auth_confirm_title: 'Disable password protection',
|
||
disable_auth_confirm_message: 'Anyone will be able to access this instance.',
|
||
auth_disabled: 'Auth disabled — password protection removed',
|
||
disable_auth_failed: 'Failed to disable auth: ',
|
||
bg_error_single: (title) => `"${title}" has encountered an error`,
|
||
bg_error_multi: (count) => `${count} sessions have encountered an error`,
|
||
},
|
||
|
||
de: {
|
||
_lang: 'de',
|
||
_label: 'Deutsch',
|
||
_speech: 'de-DE',
|
||
// boot.js
|
||
cancelling: 'Wird abgebrochen\u2026',
|
||
cancel_failed: 'Abbrechen fehlgeschlagen: ',
|
||
mic_denied: 'Mikrofonzugriff verweigert. Überprüfen Sie die Browserberechtigungen.',
|
||
mic_no_speech: 'Keine Sprache erkannt. Versuchen Sie es erneut.',
|
||
mic_network: 'Spracherkennung nicht verfügbar.',
|
||
mic_error: 'Spracheingabefehler: ',
|
||
session_imported: 'Sitzung importiert',
|
||
import_failed: 'Import fehlgeschlagen: ',
|
||
import_invalid_json: 'Ungültiges JSON',
|
||
image_pasted: 'Bild eingefügt: ',
|
||
// messages.js
|
||
edit_message: 'Nachricht bearbeiten',
|
||
regenerate: 'Antwort regenerieren',
|
||
copy: 'Kopieren',
|
||
copied: 'Kopiert!',
|
||
you: 'Du',
|
||
thinking: 'Nachdenken',
|
||
expand_all: 'Alle ausklappen',
|
||
collapse_all: 'Alle einklappen',
|
||
edit_failed: 'Bearbeiten fehlgeschlagen: ',
|
||
regen_failed: 'Regeneration fehlgeschlagen: ',
|
||
reconnect_active: 'Eine Antwort wird noch generiert. Neu laden, wenn bereit?',
|
||
reconnect_finished: 'Eine Antwort war in Arbeit, als Sie zuletzt gegangen sind. Nachrichten könnten aktualisiert worden sein.',
|
||
// approval card
|
||
approval_heading: 'Genehmigung erforderlich',
|
||
approval_desc_prefix: 'Gefährlicher Befehl erkannt',
|
||
approval_btn_once: 'Einmal zulassen',
|
||
approval_btn_once_title: 'Diesen einen Befehl zulassen (Enter)',
|
||
approval_btn_session: 'Sitzung zulassen',
|
||
approval_btn_session_title: 'Für diese Konversationssitzung zulassen',
|
||
approval_btn_always: 'Immer zulassen',
|
||
approval_btn_always_title: 'Dieses Befehlsmuster immer zulassen',
|
||
approval_btn_deny: 'Ablehnen',
|
||
approval_btn_deny_title: 'Ablehnen \u2014 diesen Befehl nicht ausführen',
|
||
approval_responding: 'Antwortet\u2026',
|
||
clarify_heading: 'Klärung erforderlich',
|
||
clarify_hint: 'Wähle eine Option oder schreibe deine eigene Antwort unten.',
|
||
clarify_other: 'Andere',
|
||
clarify_send: 'Senden',
|
||
clarify_input_placeholder: 'Gib deine Antwort ein…',
|
||
clarify_responding: 'Antwortet\u2026',
|
||
untitled: 'Unbenannt',
|
||
n_messages: (n) => `${n} Nachrichten`,
|
||
model_unavailable: ' (nicht verfügbar)',
|
||
model_unavailable_title: 'Dieses Modell ist nicht mehr in Ihrer aktuellen Provider-Liste',
|
||
provider_mismatch_warning: (m,p)=>`"${m}" funktioniert möglicherweise nicht mit Ihrem konfigurierten Provider (${p}). Trotzdem senden, oder \`hermes model\` im Terminal ausführen.`,
|
||
provider_mismatch_label: 'Provider-Konflikt',
|
||
// commands.js
|
||
cmd_help: 'Verfügbare Befehle auflisten',
|
||
cmd_clear: 'Konversationsverlauf löschen',
|
||
cmd_compress: 'Kontext manuell komprimieren (Nutzung: /compress [Thema])',
|
||
cmd_compact_alias: 'Alte Alias für /compress',
|
||
cmd_model: 'Modell wechseln (z.B. /model gpt-4o)',
|
||
cmd_workspace: 'Workspace nach Namen wechseln',
|
||
cmd_new: 'Neue Chat-Sitzung starten',
|
||
cmd_usage: 'Token-Verbrauchsanzeige umschalten',
|
||
cmd_theme: 'Darstellung wechseln (Theme: system/dark/light, Skin: default/ares/mono/slate/poseidon/sisyphus/charizard)',
|
||
cmd_personality: 'Agenten-Persönlichkeit wechseln',
|
||
cmd_skills: 'Verfügbare Hermes-Skills auflisten',
|
||
available_commands: 'Verfügbare Befehle:',
|
||
type_slash: 'Tippe / für Befehle',
|
||
conversation_cleared: 'Konversation gelöscht',
|
||
command_label: 'Befehl',
|
||
context_compaction_label: 'Kontextkomprimierung',
|
||
reference_only_label: 'Nur Referenz',
|
||
model_usage: 'Nutzung: /model <name>',
|
||
no_model_match: 'Kein Modell gefunden für "',
|
||
switched_to: 'Gewechselt zu ',
|
||
workspace_usage: 'Nutzung: /workspace <name>',
|
||
no_workspace_match: 'Kein Workspace gefunden für "',
|
||
switched_workspace: 'Gewechselt zu Workspace: ',
|
||
workspace_switch_failed: 'Workspace-Wechsel fehlgeschlagen: ',
|
||
new_session: 'Neue Sitzung erstellt',
|
||
compressing: 'Kontext-Komprimierung wird angefordert...',
|
||
compress_running_label: 'Komprimierung',
|
||
compress_complete_label: 'Komprimierung abgeschlossen',
|
||
compress_failed_label: 'Komprimierung fehlgeschlagen',
|
||
focus_label: 'Thema',
|
||
token_usage_on: 'Token-Verbrauch an',
|
||
token_usage_off: 'Token-Verbrauch aus',
|
||
theme_usage: 'Nutzung: /theme ',
|
||
theme_set: 'Theme: ',
|
||
no_active_session: 'Keine aktive Sitzung',
|
||
no_personalities: 'Keine Persönlichkeiten gefunden (füge sie in ~/.hermes/personalities/ hinzu)',
|
||
available_personalities: 'Verfügbare Persönlichkeiten:',
|
||
personality_switch_hint: '\n\nNutze `/personality <name>` zum Wechseln, oder `/personality none` zum Löschen.',
|
||
personalities_load_failed: 'Fehler beim Laden der Persönlichkeiten',
|
||
personality_cleared: 'Persönlichkeit gelöscht',
|
||
personality_set: 'Persönlichkeit: ',
|
||
failed_colon: 'Fehlgeschlagen: ',
|
||
// ui.js
|
||
no_workspace: 'Kein Workspace',
|
||
workspace_empty_no_path: 'Kein Workspace ausgewählt. Wähle einen Workspace unter Einstellungen \u2192 Workspace, um Dateien zu durchsuchen.',
|
||
workspace_empty_dir: 'Dieser Workspace ist leer.',
|
||
dialog_confirm_title: 'Aktion bestätigen',
|
||
dialog_prompt_title: 'Wert eingeben',
|
||
dialog_confirm_btn: 'Bestätigen',
|
||
// workspace.js
|
||
unsaved_confirm: 'Sie haben ungespeicherte Änderungen in der Vorschau. Verwerfen und fortfahren?',
|
||
discard: 'Verwerfen',
|
||
save: 'Speichern',
|
||
edit: 'Bearbeiten',
|
||
clear: 'Leeren',
|
||
create: 'Erstellen',
|
||
remove: 'Entfernen',
|
||
save_title: 'Änderungen speichern',
|
||
edit_title: 'Diese Datei bearbeiten',
|
||
saved: 'Gespeichert',
|
||
save_failed: 'Speichern fehlgeschlagen: ',
|
||
image_load_failed: 'Bild konnte nicht geladen werden',
|
||
file_open_failed: 'Datei konnte nicht geöffnet werden',
|
||
downloading: (name) => `Lade ${name} herunter\u2026`,
|
||
double_click_rename: 'Doppelklick zum Umbenennen',
|
||
renamed_to: 'Umbenannt in ',
|
||
rename_failed: 'Umbenennen fehlgeschlagen: ',
|
||
delete_title: 'Löschen',
|
||
delete_confirm: (name) => `${name} löschen?`,
|
||
deleted: 'Gelöscht ',
|
||
delete_failed: 'Löschen fehlgeschlagen: ',
|
||
new_file_prompt: 'Neuer Dateiname (z.B. notes.md):',
|
||
project_name_prompt: 'Projektname:',
|
||
created: 'Erstellt ',
|
||
create_failed: 'Erstellen fehlgeschlagen: ',
|
||
new_folder_prompt: 'Neuer Ordnername:',
|
||
folder_created: 'Ordner erstellt ',
|
||
folder_create_failed: 'Ordner erstellen fehlgeschlagen: ',
|
||
remove_title: 'Entfernen',
|
||
empty_dir: '(leer)',
|
||
upload_failed: 'Upload fehlgeschlagen: ',
|
||
all_uploads_failed: (n) => `Alle ${n} Upload(s) fehlgeschlagen`,
|
||
// settings panel
|
||
settings_title: 'Einstellungen',
|
||
settings_save_btn: 'Einstellungen speichern',
|
||
settings_label_model: 'Standard-Modell',
|
||
settings_label_send_key: 'Sende-Taste',
|
||
settings_label_theme: 'Theme',
|
||
settings_label_skin: 'Skin',
|
||
settings_label_language: 'Sprache',
|
||
settings_label_token_usage: 'Token-Verbrauch anzeigen',
|
||
settings_label_cli_sessions: 'Agent-Sitzungen anzeigen',
|
||
settings_label_sync_insights: 'Mit Insights synchronisieren',
|
||
settings_label_check_updates: 'Nach Updates suchen',
|
||
settings_label_bot_name: 'Assistenten-Name',
|
||
settings_label_password: 'Zugangspasswort',
|
||
settings_saved: 'Einstellungen gespeichert',
|
||
settings_save_failed: 'Speichern fehlgeschlagen: ',
|
||
settings_load_failed: 'Laden der Einstellungen fehlgeschlagen: ',
|
||
settings_saved_pw: 'Einstellungen gespeichert — Passwortschutz aktiviert und dieser Browser bleibt angemeldet',
|
||
settings_saved_pw_updated: 'Einstellungen gespeichert — Passwort aktualisiert',
|
||
// login page
|
||
login_title: 'Anmelden',
|
||
login_subtitle: 'Geben Sie Ihr Passwort ein, um fortzufahren',
|
||
login_placeholder: 'Passwort',
|
||
login_btn: 'Anmelden',
|
||
login_invalid_pw: 'Ungültiges Passwort',
|
||
login_conn_failed: 'Verbindung fehlgeschlagen',
|
||
dialog_confirm_title: 'Aktion bestätigen',
|
||
dialog_prompt_title: 'Wert eingeben',
|
||
dialog_confirm_btn: 'Bestätigen',
|
||
discard: 'Verwerfen',
|
||
clear: 'Leeren',
|
||
create: 'Erstellen',
|
||
remove: 'Entfernen',
|
||
project_name_prompt: 'Projektname:',
|
||
// Sidebar & Tabs
|
||
tab_chat: 'Chat',
|
||
tab_tasks: 'Aufgaben',
|
||
tab_skills: 'Skills',
|
||
tab_memory: 'Gedächtnis',
|
||
tab_workspaces: 'Spaces',
|
||
tab_profiles: 'Profile',
|
||
tab_todos: 'Todos',
|
||
new_conversation: 'Neuer Chat',
|
||
filter_conversations: 'Chats filtern...',
|
||
scheduled_jobs: 'Geplante Aufgaben',
|
||
new_job: 'Neuer Job',
|
||
loading: 'Lädt...',
|
||
search_skills: 'Skills suchen...',
|
||
new_skill: 'Neuer Skill',
|
||
personal_memory: 'Persönliches Gedächtnis',
|
||
current_task_list: 'Aktuelle Aufgabenliste',
|
||
workspace_desc: 'Workspaces hinzufügen und wechseln.',
|
||
new_profile: 'Neues Profil',
|
||
transcript: 'Protokoll',
|
||
download_transcript: 'Als Markdown herunterladen',
|
||
import: 'Importieren',
|
||
// Settings detail
|
||
settings_label_sound: 'Benachrichtigungston',
|
||
settings_desc_sound: 'Spielt einen Ton ab, wenn der Assistent eine Antwort beendet.',
|
||
settings_label_notifications: 'Browser-Benachrichtigungen',
|
||
settings_desc_notifications: 'Zeigt eine Systembenachrichtigung an, wenn eine Antwort fertiggestellt wird, während der Tab im Hintergrund ist.',
|
||
settings_desc_token_usage: 'Zeigt die Anzahl der Input/Output-Token unter jeder Antwort des Assistenten an. Auch umschaltbar mit /usage.',
|
||
settings_desc_cli_sessions: 'Fügt Sitzungen aus der Hermes CLI (state.db) in die Sitzungsliste ein. Klicken Sie auf eine CLI-Sitzung, um sie zu importieren und das Gespräch fortzusetzen.',
|
||
settings_desc_sync_insights: 'Spiegelt den WebUI-Token-Verbrauch in die state.db, sodass hermes /insights Browser-Sitzungsdaten enthält. Standardmäßig aus.',
|
||
settings_desc_check_updates: 'Zeigt ein Banner an, wenn neuere Versionen der WebUI oder des Agenten verfügbar sind. Führt regelmäßig einen Git-Fetch im Hintergrund aus.',
|
||
settings_desc_bot_name: 'Anzeigename für den Assistenten in der UI. Standardmäßig Hermes.',
|
||
settings_desc_password: 'Geben Sie ein neues Passwort ein, um es zu setzen oder zu ändern. Leer lassen, um die aktuelle Einstellung beizubehalten.',
|
||
password_placeholder: 'Neues Passwort eingeben…',
|
||
disable_auth: 'Authentifizierung deaktivieren',
|
||
sign_out: 'Abmelden',
|
||
cancel: 'Abbrechen',
|
||
create_job: 'Job erstellen',
|
||
save_skill: 'Skill speichern',
|
||
editing: 'Bearbeitung',
|
||
// Empty state
|
||
empty_title: 'Wie kann ich helfen?',
|
||
empty_subtitle: 'Frage mich alles, führe Befehle aus, erkunde Dateien oder verwalte deine Aufgaben.',
|
||
suggest_files: 'Welche Dateien sind in diesem Workspace?',
|
||
suggest_schedule: 'Was steht heute auf meinem Plan?',
|
||
suggest_plan: 'Hilf mir, ein kleines Projekt zu planen.',
|
||
onboarding_password_will_enable: 'Wird aktiviert',
|
||
onboarding_password_will_replace: 'Wird ersetzt',
|
||
onboarding_password_keep_existing: 'Aktuelles Passwort beibehalten',
|
||
onboarding_password_remains_disabled: 'Bleibt deaktiviert',
|
||
},
|
||
|
||
zh: {
|
||
_lang: 'zh',
|
||
_label: '\u7b80\u4f53\u4e2d\u6587',
|
||
_speech: 'zh-CN',
|
||
// boot.js
|
||
cancelling: '\u6b63\u5728\u53d6\u6d88...',
|
||
cancel_failed: '\u53d6\u6d88\u5931\u8d25\uff1a',
|
||
mic_denied: '\u9ea6\u514b\u98ce\u8bbf\u95ee\u88ab\u62d2\u7edd\uff0c\u8bf7\u68c0\u67e5\u6d4f\u89c8\u5668\u6743\u9650\u3002',
|
||
mic_no_speech: '\u6ca1\u6709\u68c0\u6d4b\u5230\u8bed\u97f3\uff0c\u8bf7\u518d\u8bd5\u4e00\u6b21\u3002',
|
||
mic_network: '\u8bed\u97f3\u8bc6\u522b\u5f53\u524d\u4e0d\u53ef\u7528\u3002',
|
||
mic_error: '\u8bed\u97f3\u8f93\u5165\u51fa\u9519\uff1a',
|
||
session_imported: '\u4f1a\u8bdd\u5df2\u5bfc\u5165',
|
||
import_failed: '\u5bfc\u5165\u5931\u8d25\uff1a',
|
||
import_invalid_json: 'JSON \u65e0\u6548',
|
||
image_pasted: '\u5df2\u7c98\u8d34\u56fe\u7247\uff1a',
|
||
// messages.js
|
||
edit_message: '\u7f16\u8f91\u6d88\u606f',
|
||
regenerate: '\u91cd\u65b0\u751f\u6210\u56de\u590d',
|
||
copy: '\u590d\u5236',
|
||
copied: '\u5df2\u590d\u5236',
|
||
you: '\u4f60',
|
||
thinking: '\u601d\u8003\u8fc7\u7a0b',
|
||
expand_all: '\u5168\u90e8\u5c55\u5f00',
|
||
collapse_all: '\u5168\u90e8\u6298\u53e0',
|
||
edit_failed: '\u7f16\u8f91\u5931\u8d25\uff1a',
|
||
regen_failed: '\u91cd\u65b0\u751f\u6210\u5931\u8d25\uff1a',
|
||
reconnect_active: '\u56de\u590d\u4ecd\u5728\u751f\u6210\u4e2d\uff0c\u51c6\u5907\u597d\u540e\u8981\u91cd\u65b0\u52a0\u8f7d\u5417\uff1f',
|
||
reconnect_finished: '\u4f60\u79bb\u5f00\u65f6\u6709\u56de\u590d\u6b63\u5728\u751f\u6210\uff0c\u6d88\u606f\u5185\u5bb9\u53ef\u80fd\u5df2\u7ecf\u66f4\u65b0\u3002',
|
||
// approval card
|
||
approval_heading: '需要审批',
|
||
approval_desc_prefix: '检测到危险命令',
|
||
approval_btn_once: '允许一次',
|
||
approval_btn_once_title: '允许执行此命令一次(Enter)',
|
||
approval_btn_session: '本次允许',
|
||
approval_btn_session_title: '本次会话期间允许',
|
||
approval_btn_always: '始终允许',
|
||
approval_btn_always_title: '始终允许此命令模式',
|
||
approval_btn_deny: '拒绝',
|
||
approval_btn_deny_title: '拒绝 — 不执行此命令',
|
||
approval_responding: '处理中…',
|
||
clarify_heading: '需要澄清',
|
||
clarify_hint: '请选择一个选项,或在下方输入你自己的回答。',
|
||
clarify_other: '其他',
|
||
clarify_send: '发送',
|
||
clarify_input_placeholder: '请输入你的回答…',
|
||
clarify_responding: '处理中…',
|
||
untitled: '\u672a\u547d\u540d',
|
||
n_messages: (n) => `${n} \u6761\u6d88\u606f`,
|
||
model_unavailable: '\uff08\u4e0d\u53ef\u7528\uff09',
|
||
model_unavailable_title: '\u8fd9\u4e2a\u6a21\u578b\u5df2\u7ecf\u4e0d\u5728\u5f53\u524d provider \u5217\u8868\u4e2d',
|
||
provider_mismatch_warning: (m,p)=>`\"${m}\" \u53ef\u80fd\u65e0\u6cd5\u5728\u5f53\u524d\u914d\u7f6e\u7684\u63d0\u4f9b\u5546 (${p}) \u4e0b\u5de5\u4f5c\u3002\u76f4\u63a5\u53d1\u9001\uff0c\u6216\u5728\u7ec8\u7aef\u8fd0\u884c \`hermes model\` \u5207\u6362\u3002`,
|
||
provider_mismatch_label: '\u63d0\u4f9b\u5546\u4e0d\u5339\u914d',
|
||
model_custom_label: '\u81ea\u5b9a\u4e49\u6a21\u578b ID',
|
||
model_custom_placeholder: '\u4f8b\u5982 openai/gpt-5.4',
|
||
model_search_placeholder: '\u641c\u7d22\u6a21\u578b\u2026',
|
||
model_search_no_results: '\u672a\u627e\u5230\u6a21\u578b',
|
||
// commands.js
|
||
cmd_help: '\u67e5\u770b\u53ef\u7528\u547d\u4ee4',
|
||
cmd_clear: '\u6e05\u7a7a\u5f53\u524d\u5bf9\u8bdd\u6d88\u606f',
|
||
cmd_compress: '\u624b\u52a8\u538b\u7f29\u5bf9\u8bdd\u4e0a\u4e0b\u6587\uff08\u7528\u6cd5\uff1a/compress [\u4e3b\u9898]\uff09',
|
||
cmd_compact_alias: '\u65e7\u522b\u540d\uff1a/compress',
|
||
cmd_model: '\u5207\u6362\u6a21\u578b\uff08\u4f8b\u5982 /model gpt-4o\uff09',
|
||
cmd_workspace: '\u6309\u540d\u79f0\u5207\u6362\u5de5\u4f5c\u533a',
|
||
cmd_new: '\u65b0\u5efa\u804a\u5929\u4f1a\u8bdd',
|
||
cmd_usage: '\u5207\u6362 token \u7528\u91cf\u663e\u793a',
|
||
cmd_theme: '\u5207\u6362\u5916\u89c2\uff08\u4e3b\u9898\uff1asystem/dark/light\uff0c\u76ae\u80a4\uff1adefault/ares/mono/slate/poseidon/sisyphus/charizard\uff09',
|
||
cmd_personality: '\u5207\u6362 Agent \u4eba\u8bbe',
|
||
cmd_skills: '\u5217\u51fa\u53ef\u7528\u7684 Hermes \u6280\u80fd',
|
||
available_commands: '\u53ef\u7528\u547d\u4ee4\uff1a',
|
||
type_slash: '\u8f93\u5165 / \u53ef\u67e5\u770b\u547d\u4ee4',
|
||
conversation_cleared: '\u5bf9\u8bdd\u5df2\u6e05\u7a7a',
|
||
command_label: '\u547d\u4ee4',
|
||
context_compaction_label: '\u4e0a\u4e0b\u6587\u538b\u7f29',
|
||
reference_only_label: '\u4ec5\u4f9b\u53c2\u8003',
|
||
model_usage: '\u7528\u6cd5\uff1a/model <name>',
|
||
no_model_match: '\u6ca1\u6709\u5339\u914d\u201c',
|
||
switched_to: '\u5df2\u5207\u6362\u5230 ',
|
||
workspace_usage: '\u7528\u6cd5\uff1a/workspace <name>',
|
||
no_workspace_match: '\u6ca1\u6709\u5339\u914d\u201c',
|
||
switched_workspace: '\u5df2\u5207\u6362\u5de5\u4f5c\u533a\uff1a',
|
||
workspace_switch_failed: '\u5de5\u4f5c\u533a\u5207\u6362\u5931\u8d25\uff1a',
|
||
new_session: '\u5df2\u65b0\u5efa\u4f1a\u8bdd',
|
||
compressing: '\u6b63\u5728\u8bf7\u6c42\u538b\u7f29\u4e0a\u4e0b\u6587...',
|
||
compress_running_label: '\u538b\u7f29\u4e2d',
|
||
compress_complete_label: '\u538b\u7f29\u5b8c\u6210',
|
||
compress_failed_label: '\u538b\u7f29\u5931\u8d25',
|
||
focus_label: '\u4e3b\u9898',
|
||
token_usage_on: 'Token \u7528\u91cf\u663e\u793a\u5df2\u5f00\u542f',
|
||
token_usage_off: 'Token \u7528\u91cf\u663e\u793a\u5df2\u5173\u95ed',
|
||
theme_usage: '\u7528\u6cd5\uff1a/theme ',
|
||
theme_set: '\u4e3b\u9898\uff1a',
|
||
no_active_session: '\u5f53\u524d\u6ca1\u6709\u6d3b\u52a8\u4f1a\u8bdd',
|
||
|
||
workspace_empty_no_path: '未选择工作区。请在 设置 → 工作区 中设置工作区以浏览文件。',
|
||
workspace_empty_dir: '此工作区为空。',
|
||
no_personalities: '\u6ca1\u6709\u627e\u5230\u4eba\u8bbe\uff08\u53ef\u6dfb\u52a0\u5230 ~/.hermes/personalities/\uff09',
|
||
available_personalities: '\u53ef\u7528\u4eba\u8bbe\uff1a',
|
||
personality_switch_hint: '\n\n\u4f7f\u7528 `/personality <name>` \u5207\u6362\uff0c\u6216\u7528 `/personality none` \u6e05\u7a7a\u3002',
|
||
personalities_load_failed: '\u52a0\u8f7d\u4eba\u8bbe\u5931\u8d25',
|
||
personality_cleared: '\u4eba\u8bbe\u5df2\u6e05\u7a7a',
|
||
personality_set: '\u5f53\u524d\u4eba\u8bbe\uff1a',
|
||
failed_colon: '\u5931\u8d25\uff1a',
|
||
// ui.js
|
||
no_workspace: '\u672a\u9009\u62e9\u5de5\u4f5c\u533a',
|
||
dialog_confirm_title: '\u786e\u8ba4\u64cd\u4f5c',
|
||
dialog_prompt_title: '\u8f93\u5165\u5185\u5bb9',
|
||
dialog_confirm_btn: '\u786e\u8ba4',
|
||
// workspace.js
|
||
unsaved_confirm: '\u9884\u89c8\u533a\u6709\u672a\u4fdd\u5b58\u4fee\u6539\uff0c\u8981\u653e\u5f03\u66f4\u6539\u5e76\u7ee7\u7eed\u8df3\u8f6c\u5417\uff1f',
|
||
discard: '\u653e\u5f03',
|
||
save: '\u4fdd\u5b58',
|
||
edit: '\u7f16\u8f91',
|
||
clear: '\u6e05\u7a7a',
|
||
create: '\u521b\u5efa',
|
||
remove: '\u79fb\u9664',
|
||
save_title: '\u4fdd\u5b58\u4fee\u6539',
|
||
edit_title: '\u7f16\u8f91\u6b64\u6587\u4ef6',
|
||
saved: '\u5df2\u4fdd\u5b58',
|
||
save_failed: '\u4fdd\u5b58\u5931\u8d25\uff1a',
|
||
image_load_failed: '\u56fe\u7247\u52a0\u8f7d\u5931\u8d25',
|
||
file_open_failed: '\u65e0\u6cd5\u6253\u5f00\u6587\u4ef6',
|
||
downloading: (name) => `\u6b63\u5728\u4e0b\u8f7d ${name}...`,
|
||
double_click_rename: '\u53cc\u51fb\u91cd\u547d\u540d',
|
||
renamed_to: '\u5df2\u91cd\u547d\u540d\u4e3a ',
|
||
rename_failed: '\u91cd\u547d\u540d\u5931\u8d25\uff1a',
|
||
delete_title: '\u5220\u9664',
|
||
delete_confirm: (name) => `\u8981\u5220\u9664 ${name} \u5417\uff1f`,
|
||
deleted: '\u5df2\u5220\u9664 ',
|
||
delete_failed: '\u5220\u9664\u5931\u8d25\uff1a',
|
||
new_file_prompt: '\u65b0\u6587\u4ef6\u540d\uff08\u4f8b\u5982 notes.md\uff09\uff1a',
|
||
project_name_prompt: '\u9879\u76ee\u540d\u79f0\uff1a',
|
||
created: '\u5df2\u521b\u5efa ',
|
||
create_failed: '\u521b\u5efa\u5931\u8d25\uff1a',
|
||
new_folder_prompt: '\u65b0\u6587\u4ef6\u5939\u540d\u79f0\uff1a',
|
||
folder_created: '\u5df2\u521b\u5efa\u6587\u4ef6\u5939 ',
|
||
folder_create_failed: '\u521b\u5efa\u6587\u4ef6\u5939\u5931\u8d25\uff1a',
|
||
remove_title: '\u79fb\u9664',
|
||
empty_dir: '(\u7a7a)',
|
||
upload_failed: '\u4e0a\u4f20\u5931\u8d25\uff1a',
|
||
all_uploads_failed: (n) => `${n} \u4e2a\u6587\u4ef6\u5168\u90e8\u4e0a\u4f20\u5931\u8d25`,
|
||
// settings panel
|
||
settings_title: '\u8bbe\u7f6e',
|
||
settings_save_btn: '\u4fdd\u5b58\u8bbe\u7f6e',
|
||
settings_label_model: '\u9ed8\u8ba4\u6a21\u578b',
|
||
settings_label_send_key: '\u53d1\u9001\u5feb\u6377\u952e',
|
||
settings_label_theme: '\u4e3b\u9898',
|
||
settings_label_skin: '\u76ae\u80a4',
|
||
settings_label_language: '\u8bed\u8a00',
|
||
settings_label_token_usage: '\u663e\u793a token \u7528\u91cf',
|
||
settings_label_bubble_layout: '聊天气泡布局',
|
||
settings_label_cli_sessions: '\u663e\u793a CLI \u4f1a\u8bdd',
|
||
settings_label_sync_insights: '\u540c\u6b65\u5230 insights',
|
||
settings_label_check_updates: '\u68c0\u67e5\u66f4\u65b0',
|
||
settings_label_bot_name: '\u52a9\u624b\u540d\u79f0',
|
||
settings_label_password: '\u8bbf\u95ee\u5bc6\u7801',
|
||
settings_saved: '\u8bbe\u7f6e\u5df2\u4fdd\u5b58',
|
||
settings_save_failed: '\u4fdd\u5b58\u5931\u8d25\uff1a',
|
||
settings_load_failed: '\u8bbe\u7f6e\u52a0\u8f7d\u5931\u8d25\uff1a',
|
||
settings_saved_pw: '\u8bbe\u7f6e\u5df2\u4fdd\u5b58\uff0c\u5df2\u542f\u7528\u5bc6\u7801\u4fdd\u62a4\uff0c\u5f53\u524d\u6d4f\u89c8\u5668\u4f1a\u4fdd\u6301\u767b\u5f55',
|
||
settings_saved_pw_updated: '\u8bbe\u7f6e\u5df2\u4fdd\u5b58\uff0c\u5bc6\u7801\u5df2\u66f4\u65b0',
|
||
// login page
|
||
login_title: '\u767b\u5f55',
|
||
login_subtitle: '\u8f93\u5165\u5bc6\u7801\u7ee7\u7eed\u4f7f\u7528',
|
||
login_placeholder: '\u5bc6\u7801',
|
||
login_btn: '\u767b\u5f55',
|
||
login_invalid_pw: '\u5bc6\u7801\u9519\u8bef',
|
||
login_conn_failed: '\u8fde\u63a5\u5931\u8d25',
|
||
// sidebar & navigation
|
||
tab_chat: '聊天',
|
||
tab_memory: '记忆',
|
||
tab_skills: '技能',
|
||
tab_tasks: '任务',
|
||
tab_todos: '待办',
|
||
tab_workspaces: '工作区',
|
||
tab_profiles: '配置',
|
||
new_conversation: '新建对话',
|
||
filter_conversations: '筛选对话…',
|
||
session_time_unknown: '未知',
|
||
session_time_just_now: '刚刚',
|
||
session_time_minutes_ago: (n) => `${n} 分钟前`,
|
||
session_time_hours_ago: (n) => `${n} 小时前`,
|
||
session_time_days_ago: (n) => `${n} 天前`,
|
||
session_time_last_week: '上周',
|
||
session_time_bucket_today: '今天',
|
||
session_time_bucket_yesterday: '昨天',
|
||
session_time_bucket_this_week: '本周',
|
||
session_time_bucket_last_week: '上周',
|
||
session_time_bucket_older: '更早',
|
||
scheduled_jobs: '定时任务',
|
||
new_job: '新任务',
|
||
search_skills: '搜索技能…',
|
||
new_skill: '新技能',
|
||
save_skill: '保存技能',
|
||
personal_memory: '个人记忆',
|
||
current_task_list: '当前任务列表',
|
||
workspace_desc: '为你的会话添加并切换工作区。',
|
||
new_profile: '新配置',
|
||
transcript: '记录',
|
||
download_transcript: '下载为 Markdown',
|
||
import: '导入',
|
||
editing: '编辑中',
|
||
empty_title: '有什么可以帮您?',
|
||
empty_subtitle: '随时提问、运行命令、浏览文件或管理定时任务。',
|
||
cancel: '取消',
|
||
loading: '加载中…',
|
||
create_job: '创建任务',
|
||
suggest_plan: '帮我规划一个小项目。',
|
||
suggest_schedule: '今天有什么安排?',
|
||
suggest_files: '这个工作区有哪些文件?',
|
||
sign_out: '退出登录',
|
||
password_placeholder: '输入新密码…',
|
||
disable_auth: '停用认证',
|
||
settings_label_sound: '通知声音',
|
||
settings_label_notifications: '浏览器通知',
|
||
settings_desc_sound: '助手完成回复时播放提示音。',
|
||
settings_desc_notifications: '当标签页在后台时,回复完成后显示系统通知。',
|
||
settings_desc_token_usage: '在助手每次回复下方显示输入/输出 token 数量。也可以用 /usage 切换。',
|
||
settings_desc_bubble_layout: '开启后将用户消息右对齐、助手消息左对齐。默认关闭,以保持代码块和工具输出为全宽显示。',
|
||
settings_desc_cli_sessions: '将 Hermes CLI(state.db)中的会话合并到会话列表。点击某个 CLI 会话可导入并继续对话。',
|
||
settings_desc_sync_insights: '将 WebUI token 使用情况同步到 state.db,使 hermes /insights 包含浏览器会话数据。默认关闭。',
|
||
settings_desc_check_updates: '当有更新的 WebUI 或助手版本时显示横幅。会在后台定期执行 git fetch。',
|
||
settings_desc_bot_name: '助手在 UI 中的显示名称。默认为 Hermes。',
|
||
settings_desc_password: '输入新密码以设置或更改。留空保持当前设置。',
|
||
// onboarding
|
||
onboarding_badge: '首次运行',
|
||
onboarding_title: '欢迎使用 Hermes Web UI',
|
||
onboarding_lead: '快速引导将验证 Hermes、保存真实的提供商配置、选择工作区和模型,并可选设置密码保护应用。',
|
||
onboarding_back: '返回',
|
||
onboarding_continue: '继续',
|
||
onboarding_skip: '跳过设置',
|
||
onboarding_skipped: '设置已跳过 — 使用现有配置。',
|
||
onboarding_open: '打开 Hermes',
|
||
onboarding_step_system_title: '系统检查',
|
||
onboarding_step_system_desc: '验证 Hermes Agent 与配置可见性。',
|
||
onboarding_step_setup_title: '提供商设置',
|
||
onboarding_step_setup_desc: '保存最小可用的 Hermes 提供商配置。',
|
||
onboarding_step_workspace_title: '工作区 + 模型',
|
||
onboarding_step_workspace_desc: '为新会话和聊天选择默认值。',
|
||
onboarding_step_password_title: '可选密码',
|
||
onboarding_step_password_desc: '在分享前为 Web UI 添加保护。',
|
||
onboarding_step_finish_title: '完成',
|
||
onboarding_step_finish_desc: '确认信息并进入应用。',
|
||
onboarding_notice_system_ready: 'Hermes Agent 看起来可从 Web UI 访问。',
|
||
onboarding_notice_system_unavailable: 'Hermes Agent 尚未完全可用。Bootstrap 可以安装它,但提供商设置可能仍需要终端。',
|
||
onboarding_check_agent: 'Hermes Agent',
|
||
onboarding_check_agent_ready: '已检测且可导入',
|
||
onboarding_check_agent_missing: '缺失或仅部分可导入',
|
||
onboarding_check_password: '密码',
|
||
onboarding_check_password_enabled: '已启用',
|
||
onboarding_check_password_disabled: '尚未启用',
|
||
onboarding_check_provider: '提供商配置',
|
||
onboarding_check_provider_ready: '可开始聊天',
|
||
onboarding_check_provider_partial: '已保存但不完整',
|
||
onboarding_check_provider_pending: '需要验证',
|
||
onboarding_config_file: '配置文件:',
|
||
onboarding_env_file: '.env 文件:',
|
||
onboarding_unknown: '未知',
|
||
onboarding_current_provider: '当前配置:',
|
||
onboarding_missing_imports: '缺失导入:',
|
||
onboarding_notice_setup_required: '请先在此选择一个简单的提供商路径。高级 OAuth 流程暂时仍建议在 Hermes CLI 中完成。',
|
||
onboarding_notice_setup_already_ready: '已检测到可用的 Hermes 提供商配置。你可以保留它,或在这里替换。',
|
||
onboarding_oauth_provider_ready_title: '提供商已完成认证',
|
||
onboarding_oauth_provider_ready_body: '此实例已配置为使用通过 Hermes CLI 设置的 OAuth 提供商(<strong>{provider}</strong>)。这里不需要 API key,点击继续即可完成设置。',
|
||
onboarding_oauth_provider_not_ready_title: 'OAuth 提供商尚未认证',
|
||
onboarding_oauth_provider_not_ready_body: '此实例已配置为使用 <strong>{provider}</strong>,该提供商使用 OAuth 而非 API key。请在终端运行 <code>hermes auth</code> 或 <code>hermes model</code> 完成认证,然后重新加载 Web UI。',
|
||
onboarding_oauth_switch_hint: '或者在下方选择其他提供商,切换到 API key 配置:',
|
||
onboarding_notice_workspace: '这些值复用与正式应用相同的设置 API。',
|
||
onboarding_workspace_label: '工作区',
|
||
onboarding_workspace_or_path: '或输入工作区路径',
|
||
onboarding_workspace_placeholder: '/home/you/workspace',
|
||
onboarding_provider_label: '设置模式',
|
||
onboarding_quick_setup_badge: '快速设置',
|
||
onboarding_api_key_label: 'API key',
|
||
onboarding_api_key_placeholder: '留空可保留已保存的 key',
|
||
onboarding_api_key_help_prefix: '会作为密钥保存到 Hermes .env 文件中,变量名为',
|
||
onboarding_base_url_label: 'Base URL',
|
||
onboarding_base_url_placeholder: 'https://your-endpoint.example/v1',
|
||
onboarding_base_url_help: '用于 OpenAI 兼容路由、自托管服务、LiteLLM、Ollama、LM Studio、vLLM 或类似端点。',
|
||
onboarding_model_label: '默认模型',
|
||
onboarding_workspace_help: '选择设置完成后 Hermes 在新聊天中使用的模型。',
|
||
onboarding_custom_model_placeholder: 'your-model-name',
|
||
onboarding_custom_model_help: '对于自定义端点,请填写服务端要求的精确模型 ID。',
|
||
onboarding_notice_password_enabled: '已配置密码。仅在你想替换时输入新密码。',
|
||
onboarding_notice_password_recommended: '可选,但如果你会把 UI 暴露到 localhost 之外,建议设置。',
|
||
onboarding_password_label: '密码(可选)',
|
||
onboarding_password_placeholder: '留空则跳过',
|
||
onboarding_password_help: '密码通过现有设置 API 保存,并在服务端进行哈希处理。',
|
||
onboarding_notice_finish: '你之后仍可在设置中修改这些选项。',
|
||
onboarding_not_set: '未设置',
|
||
onboarding_password_will_enable: '将启用',
|
||
onboarding_password_will_replace: '将被替换',
|
||
onboarding_password_keep_existing: '保留当前密码',
|
||
onboarding_password_remains_disabled: '将保持禁用',
|
||
onboarding_password_skipped: '暂时跳过',
|
||
onboarding_finish_help: '完成后会在设置中写入 <code>onboarding_completed</code>,并进入常规应用界面。',
|
||
onboarding_error_choose_workspace: '继续前请先选择工作区。',
|
||
onboarding_error_choose_model: '继续前请先选择模型。',
|
||
onboarding_error_provider_required: '继续前请先选择设置模式。',
|
||
onboarding_error_base_url_required: '自定义端点必须填写 Base URL。',
|
||
onboarding_error_workspace_required: '必须填写工作区。',
|
||
onboarding_error_model_required: '必须填写模型。',
|
||
onboarding_complete: '引导完成',
|
||
// panel/runtime i18n
|
||
error_prefix: '错误:',
|
||
not_available: '无',
|
||
never: '从未',
|
||
add: '添加',
|
||
add_failed: '添加失败:',
|
||
remove_failed: '移除失败:',
|
||
switch_failed: '切换失败:',
|
||
name_required: '名称不能为空',
|
||
content_required: '内容不能为空',
|
||
view: '查看',
|
||
dismiss: '忽略',
|
||
disable: '停用',
|
||
cron_no_jobs: '未找到定时任务。',
|
||
cron_status_off: '关闭',
|
||
cron_status_paused: '暂停',
|
||
cron_status_error: '错误',
|
||
cron_status_active: '运行中',
|
||
cron_next: '下次',
|
||
cron_last: '上次',
|
||
cron_run_now: '立即运行',
|
||
cron_pause: '暂停',
|
||
cron_resume: '恢复',
|
||
cron_job_name_placeholder: '任务名称',
|
||
cron_schedule_placeholder: '调度表达式',
|
||
cron_prompt_placeholder: '提示词',
|
||
cron_last_output: '最近输出',
|
||
cron_all_runs: '全部运行记录',
|
||
cron_hide_runs: '隐藏记录',
|
||
cron_no_runs_yet: '(暂无运行记录)',
|
||
cron_schedule_required_example: '必须填写调度(例如 "0 9 * * *" 或 "every 1h")',
|
||
cron_schedule_required: '必须填写调度',
|
||
cron_prompt_required: '必须填写提示词',
|
||
cron_job_created: '任务已创建',
|
||
cron_job_triggered: '任务已触发',
|
||
cron_job_paused: '任务已暂停',
|
||
cron_job_resumed: '任务已恢复',
|
||
cron_job_updated: '任务已更新',
|
||
cron_delete_confirm_title: '删除定时任务',
|
||
cron_delete_confirm_message: '此操作无法撤销。',
|
||
cron_job_deleted: '任务已删除',
|
||
cron_completion_status: (name, status) => `定时任务“${name}”${status}`,
|
||
status_failed: '失败',
|
||
status_completed: '完成',
|
||
todos_no_active: '此会话暂无活动任务列表。',
|
||
clear_conversation_title: '清空对话',
|
||
clear_conversation_message: '要清空所有消息吗?此操作无法撤销。',
|
||
clear_failed: '清空失败:',
|
||
skills_no_match: '没有匹配的技能。',
|
||
linked_files: '关联文件',
|
||
skill_load_failed: '加载技能失败:',
|
||
skill_file_load_failed: '加载文件失败:',
|
||
skill_name_required: '技能名称不能为空',
|
||
skill_updated: '技能已更新',
|
||
skill_created: '技能已创建',
|
||
memory_notes_label: '记忆(备注)',
|
||
memory_saved: '记忆已保存',
|
||
my_notes: '我的备注',
|
||
user_profile: '用户画像',
|
||
no_notes_yet: '暂无备注。',
|
||
no_profile_yet: '暂无用户画像。',
|
||
workspace_choose_path: '选择工作区路径',
|
||
workspace_choose_path_meta: '添加已校验路径并切换当前会话',
|
||
workspace_manage: '管理工作区',
|
||
workspace_manage_meta: '打开 Spaces 面板',
|
||
workspace_use_title: '用于当前会话',
|
||
workspace_use: '使用',
|
||
workspace_add_path_placeholder: '添加工作区路径(例如 /home/user/my-project)',
|
||
workspace_paths_validated_hint: '保存前会校验路径是否为已存在目录。',
|
||
workspace_added: '工作区已添加',
|
||
workspace_remove_confirm_title: '移除工作区',
|
||
workspace_remove_confirm_message: (path) => `要移除"${path}"吗?`,
|
||
workspace_removed: '工作区已移除',
|
||
workspace_switch_prompt_title: '切换工作区',
|
||
workspace_switch_prompt_message: '输入绝对路径以添加并切换当前会话的工作区。',
|
||
workspace_switch_prompt_confirm: '切换',
|
||
workspace_switch_prompt_placeholder: '/Users/you/project',
|
||
workspace_not_added: '工作区未添加成功',
|
||
workspace_already_saved: '工作区已存在,请在列表中选择',
|
||
workspace_busy_switch: 'Agent 运行中,无法切换工作区',
|
||
discard_file_edits_title: '放弃文件编辑?',
|
||
discard_file_edits_message: '切换工作区将丢弃预览区未保存的文件修改。',
|
||
workspace_switched_to: (name) => `已切换到 ${name}`,
|
||
profiles_no_profiles: '未找到配置档。',
|
||
profile_api_keys_configured: '已配置 API 密钥',
|
||
profile_gateway_running: '网关运行中',
|
||
profile_gateway_stopped: '网关已停止',
|
||
profile_active: '当前',
|
||
profile_no_configuration: '无配置',
|
||
profile_skill_count: (count) => `${count} 个技能`,
|
||
profile_use: '使用',
|
||
profile_switch_title: '切换到此配置档',
|
||
profile_delete_title: '删除此配置档',
|
||
profile_default_label: '(默认)',
|
||
profile_name_placeholder: '配置档名称(小写字母、a-z、0-9、连字符)',
|
||
profile_clone_label: '复制当前配置档的配置',
|
||
profile_base_url_placeholder: 'Base URL(可选,例如 http://localhost:11434)',
|
||
profile_api_key_placeholder: 'API 密钥(可选)',
|
||
manage_profiles: '管理配置档',
|
||
profiles_load_failed: '加载配置档失败',
|
||
profiles_busy_switch: 'Agent 运行中,无法切换配置档',
|
||
profile_switched_new_conversation: (name) => `已切换到配置档:${name},并新建对话`,
|
||
profile_switched: (name) => `已切换到配置档:${name}`,
|
||
profile_name_rule: '仅允许小写字母、数字、连字符和下划线',
|
||
profile_base_url_rule: 'Base URL 必须以 http:// 或 https:// 开头',
|
||
profile_created: (name) => `配置档已创建:${name}`,
|
||
profile_delete_confirm_title: (name) => `删除配置档“${name}”?`,
|
||
profile_delete_confirm_message: '这将删除该配置档的所有配置、技能、记忆和会话。',
|
||
profile_deleted: (name) => `配置档已删除:${name}`,
|
||
gateways_no_gateways: '未配置网关。',
|
||
gateway_running: '运行中',
|
||
gateway_stopped: '已停止',
|
||
gateway_stop: '停止',
|
||
gateway_start: '启动',
|
||
gateway_restart: '重启',
|
||
gateway_stop_title: '停止此网关',
|
||
gateway_start_title: '启动此网关',
|
||
gateway_restart_title: '重启此网关',
|
||
gateway_started: (name) => `网关已启动:${name}`,
|
||
gateway_stopped_msg: (name) => `网关已停止:${name}`,
|
||
gateway_restarted: (name) => `网关已重启:${name}`,
|
||
gateway_start_failed: '启动网关失败:',
|
||
gateway_stop_failed: '停止网关失败:',
|
||
gateway_restart_failed: '重启网关失败:',
|
||
gateway_add: '添加网关',
|
||
gateway_add_title: '添加新网关',
|
||
gateway_add_message: '输入网关名称(例如:telegram, openclaw):',
|
||
gateway_added: (name) => `网关已添加:${name}`,
|
||
gateway_add_failed: '添加网关失败:',
|
||
active_conversation_none: '当前未选择活动会话。',
|
||
active_conversation_meta: (title, count) => `${title} · ${count} 条消息`,
|
||
settings_unsaved_changes: '你有未保存的更改。',
|
||
sign_out_failed: '退出登录失败:',
|
||
disable_auth_confirm_title: '停用密码保护',
|
||
disable_auth_confirm_message: '任何人都可以访问此实例。',
|
||
auth_disabled: '认证已停用,密码保护已移除',
|
||
disable_auth_failed: '停用认证失败:',
|
||
bg_error_single: (title) => `“${title}”出现错误`,
|
||
bg_error_multi: (count) => `${count} 个会话出现错误`,
|
||
},
|
||
|
||
// Traditional Chinese (zh-Hant)
|
||
'zh-Hant': {
|
||
_lang: 'zh-Hant',
|
||
_label: '\u7e41\u9ad4\u4e2d\u6587',
|
||
_speech: 'zh-TW',
|
||
// boot.js
|
||
cancelling: '\u6b63\u5728\u53d6\u6d88...',
|
||
cancel_failed: '\u53d6\u6d88\u5931\u6557\uff1a',
|
||
mic_denied: '\u9ea6\u514b\u98a8\u8a2a\u554f\u88ab\u62d2\u7d75\uff0c\u8acb\u6aa2\u67e5\u700f\u89bd\u5668\u6b0a\u9650\u3002',
|
||
mic_no_speech: '\u6c92\u6709\u6aa2\u6e2c\u5230\u8a71\u97f3\uff0c\u8acb\u518d\u5617\u4e00\u6b21\u3002',
|
||
mic_network: '\u8a71\u97f3\u8b58\u5225\u76ee\u524d\u4e0d\u53ef\u7528\u3002',
|
||
mic_error: '\u8a71\u97f3\u8f38\u5165\u51fa\u932f\uff1a',
|
||
session_imported: '\u6703\u8a71\u5df2\u5c0e\u5165',
|
||
import_failed: '\u5c0e\u5165\u5931\u6557\uff1a',
|
||
import_invalid_json: 'JSON \u7121\u6548',
|
||
image_pasted: '\u5df2\u7c98\u8cbc\u5716\u7247\uff1a',
|
||
// messages.js
|
||
edit_message: '\u7de8\u8f2f\u8a0a\u606f',
|
||
regenerate: '\u91cd\u65b0\u751f\u6210\u56de\u8986',
|
||
copy: '\u8907\u88fd',
|
||
copied: '\u5df2\u8907\u88fd',
|
||
you: '\u4f60',
|
||
thinking: '\u601d\u8003\u904e\u7a0b',
|
||
expand_all: '\u5168\u90e8\u5c55\u958b',
|
||
collapse_all: '\u5168\u90e8\u6298\u758a',
|
||
edit_failed: '\u7de8\u8f2f\u5931\u6557\uff1a',
|
||
regen_failed: '\u91cd\u65b0\u751f\u6210\u5931\u6557\uff1a',
|
||
reconnect_active: '\u56de\u8986\u4ecd\u5728\u751f\u6210\u4e2d\uff0c\u6e96\u5099\u597d\u5f8c\u8981\u91cd\u65b0\u52a0\u8f09\u55ce\uff1f',
|
||
reconnect_finished: '\u4f60\u96e2\u958b\u6642\u6709\u56de\u8986\u6b63\u5728\u751f\u6210\uff0c\u8a0a\u606f\u5167\u5bb9\u53ef\u80fd\u5df2\u7d93\u66f4\u65b0\u3002',
|
||
// approval card
|
||
approval_heading: '\u9700\u8981\u5ba1\u6838',
|
||
approval_desc_prefix: '\u6aa2\u6e2c\u5230\u5371\u96aa\u547d\u4ee4',
|
||
approval_btn_once: '\u5141\u8a31\u4e00\u6b21',
|
||
approval_btn_once_title: '\u5141\u8a31\u57f7\u884c\u6b64\u547d\u4ee4\u4e00\u6b21\uff08Enter\uff09',
|
||
approval_btn_session: '\u672c\u6b21\u5141\u8a31',
|
||
approval_btn_session_title: '\u672c\u6b21\u6703\u8a71\u671f\u9593\u5141\u8a31',
|
||
approval_btn_always: '始終允許',
|
||
approval_btn_always_title: '始終允許此命令模式',
|
||
approval_btn_deny: '\u62d2\u7edd',
|
||
approval_btn_deny_title: '\u62d2\u7edd — \u4e0d\u57f7\u884c\u6b64\u547d\u4ee4',
|
||
approval_responding: '\u8655\u7406\u4e2d\u2026',
|
||
clarify_heading: '\u9700\u8981\u91cb\u6e05',
|
||
clarify_hint: '\u8acb\u9078\u64c7\u4e00\u500b\u9078\u9805\uff0c\u6216\u5728\u4e0b\u65b9\u8f38\u5165\u4f60\u81ea\u5df1\u7684\u56de\u7b54\u3002',
|
||
clarify_other: '\u5176\u4ed6',
|
||
clarify_send: '\u9001\u51fa',
|
||
clarify_input_placeholder: '\u8f38\u5165\u4f60\u7684\u56de\u7b54\u2026',
|
||
clarify_responding: '\u8655\u7406\u4e2d\u2026',
|
||
untitled: '\u672a\u547d\u540d',
|
||
n_messages: (n) => `${n} \u689d\u8a0a\u606f`,
|
||
model_unavailable: '\uff08\u4e0d\u53ef\u7528\uff09',
|
||
model_unavailable_title: '\u6b64\u6a21\u578b\u5df2\u7d93\u4e0d\u5728\u7576\u524d provider \u5217\u8868\u4e2d',
|
||
provider_mismatch_warning: (m,p)=>`\"${m}\" \u53ef\u80fd\u7121\u6cd5\u5728\u7576\u524d\u914d\u7f6e\u7684\u63d0\u4f9b\u8005 (${p}) \u4e0b\u904b\u4f5c\u3002\u5c1a\u9001\uff0c\u6216\u5728\u7d42\u7aef\u57f7\u884c \`hermes model\` \u5207\u63db\u3002`,
|
||
provider_mismatch_label: '\u63d0\u4f9b\u8005\u4e0d\u76f8\u7b26',
|
||
// commands.js
|
||
cmd_help: '\u67e5\u770b\u53ef\u7528\u547d\u4ee4',
|
||
cmd_clear: '\u6e05\u7a7a\u7576\u524d\u5c0d\u8a71\u8a0a\u606f',
|
||
cmd_compress: '\u624b\u52d5\u58d3\u7e2e\u5c0d\u8a71\u4e0a\u4e0b\u6587\uff08\u7528\u6cd5\uff1a/compress [\u4e3b\u984c]\uff09',
|
||
cmd_compact_alias: '\u820a\u5225\u540d\uff1a/compress',
|
||
cmd_model: '\u5207\u63db\u6a21\u578b\uff08\u4f8b\u5982 /model gpt-4o\uff09',
|
||
cmd_workspace: '\u6309\u540d\u7a31\u5207\u63db\u5de5\u4f5c\u5340',
|
||
cmd_new: '\u65b0\u5efa\u804a\u5929\u6703\u8a71',
|
||
cmd_usage: '\u5207\u63db token \u7528\u91cf\u986f\u793a',
|
||
cmd_theme: '\u5207\u63db\u5916\u89c0\uff08\u4e3b\u984c\uff1asystem/dark/light\uff0c\u76ae\u819a\uff1adefault/ares/mono/slate/poseidon/sisyphus/charizard\uff09',
|
||
cmd_personality: '\u5207\u63db Agent \u4eba\u8a2d',
|
||
cmd_skills: '\u5217\u51fa\u53ef\u7528\u7684 Hermes \u6280\u80fd',
|
||
available_commands: '\u53ef\u7528\u547d\u4ee4\uff1a',
|
||
type_slash: '\u8f38\u5165 / \u53ef\u67e5\u770b\u547d\u4ee4',
|
||
conversation_cleared: '\u5c0d\u8a71\u5df2\u6e05\u7a7a',
|
||
command_label: '\u547d\u4ee4',
|
||
context_compaction_label: '\u4e0a\u4e0b\u6587\u58d3\u7e2e',
|
||
reference_only_label: '\u50c5\u4f9b\u53c3\u8003',
|
||
model_usage: '\u7528\u6cd5\uff1a/model <name>',
|
||
no_model_match: '\u6c92\u6709\u5339\u914d\u201c',
|
||
switched_to: '\u5df2\u5207\u63db\u5230 ',
|
||
workspace_usage: '\u7528\u6cd5\uff1a/workspace <name>',
|
||
no_workspace_match: '\u6c92\u6709\u5339\u914d\u201c',
|
||
switched_workspace: '\u5df2\u5207\u63db\u5de5\u4f5c\u5340\uff1a',
|
||
workspace_switch_failed: '\u5de5\u4f5c\u5340\u5207\u63db\u5931\u6557\uff1a',
|
||
new_session: '\u5df2\u65b0\u5efa\u6703\u8a71',
|
||
compressing: '\u6b63\u5728\u8981\u6c42\u58d3\u7e2e\u4e0a\u4e0b\u6587...',
|
||
compress_running_label: '\u58d3\u7e2e\u4e2d',
|
||
compress_complete_label: '\u58d3\u7e2e\u5b8c\u6210',
|
||
compress_failed_label: '\u58d3\u7e2e\u5931\u6557',
|
||
focus_label: '\u4e3b\u984c',
|
||
token_usage_on: 'Token \u7528\u91cf\u986f\u793a\u5df2\u958b\u555f',
|
||
token_usage_off: 'Token \u7528\u91cf\u986f\u793a\u5df2\u95dc\u9589',
|
||
theme_usage: '\u7528\u6cd5\uff1a/theme ',
|
||
theme_set: '\u4e3b\u984c\uff1a',
|
||
no_active_session: '\u7576\u524d\u6c92\u6709\u6d3b\u52d5\u6703\u8a71',
|
||
|
||
workspace_empty_no_path: '未選擇工作區。請在 設定 → 工作區 中設定工作區以瀏覽檔案。',
|
||
workspace_empty_dir: '此工作區為空。',
|
||
no_personalities: '\u6c92\u6709\u627e\u5230\u4eba\u8a2d\uff08\u53ef\u6dfb\u52a0\u5230 ~/.hermes/personalities/\uff09',
|
||
available_personalities: '\u53ef\u7528\u4eba\u8a2d\uff1a',
|
||
personality_switch_hint: '\n\n\u4f7f\u7528 `/personality <name>` \u5207\u63db\uff0c\u6216\u7528 `/personality none` \u6e05\u7a7a\u3002',
|
||
personalities_load_failed: '\u52a0\u8f7d\u4eba\u8a2d\u5931\u6557',
|
||
personality_cleared: '\u4eba\u8a2d\u5df2\u6e05\u7a7a',
|
||
personality_set: '\u7576\u524d\u4eba\u8a2d\uff1a',
|
||
failed_colon: '\u5931\u6557\uff1a',
|
||
// ui.js
|
||
no_workspace: '\u672a\u9078\u64c7\u5de5\u4f5c\u5340',
|
||
// workspace.js
|
||
unsaved_confirm: '\u9810\u89bd\u5340\u6709\u672a\u5132\u5b58\u4fee\u6539\uff0c\u8981\u653e\u68c4\u66f4\u6539\u5e76\u7e7c\u7e8c\u8df3\u8ee2\u55ce\uff1f',
|
||
save: '\u5132\u5b58',
|
||
edit: '\u7de8\u8f2f',
|
||
save_title: '\u5132\u5b58\u4fee\u6539',
|
||
edit_title: '\u7de8\u8f2f\u6b64\u6587\u4ef6',
|
||
saved: '\u5df2\u5132\u5b58',
|
||
save_failed: '\u5132\u5b58\u5931\u6557\uff1a',
|
||
image_load_failed: '\u5716\u7247\u52a0\u8f09\u5931\u6557',
|
||
file_open_failed: '\u7121\u6cd5\u6253\u958b\u6587\u4ef6',
|
||
downloading: (name) => `\u6b63\u5728\u4e0b\u8f09 ${name}...`,
|
||
double_click_rename: '\u96d9\u64ca\u91cd\u547d\u540d',
|
||
renamed_to: '\u5df2\u91cd\u547d\u540d\u70ba ',
|
||
rename_failed: '\u91cd\u547d\u540d\u5931\u6557\uff1a',
|
||
delete_title: '\u522a\u9664',
|
||
delete_confirm: (name) => `\u8981\u522a\u9664 ${name} \u55ce\uff1f`,
|
||
deleted: '\u5df2\u522a\u9664 ',
|
||
delete_failed: '\u522a\u9664\u5931\u6557\uff1a',
|
||
new_file_prompt: '\u65b0\u6587\u4ef6\u540d\uff08\u4f8b\u5982 notes.md\uff09\uff1a',
|
||
created: '\u5df2\u5275\u5efa ',
|
||
create_failed: '\u5275\u5efa\u5931\u6557\uff1a',
|
||
new_folder_prompt: '\u65b0\u6587\u4ef6\u593e\u540d\u7a31\uff1a',
|
||
folder_created: '\u5df2\u5275\u5efa\u6587\u4ef6\u593e ',
|
||
folder_create_failed: '\u5275\u5efa\u6587\u4ef6\u593e\u5931\u6557\uff1a',
|
||
remove_title: '\u79fb\u9664',
|
||
empty_dir: '(\u7a7a)',
|
||
upload_failed: '\u4e0a\u50b3\u5931\u6557\uff1a',
|
||
all_uploads_failed: (n) => `${n} \u500b\u6587\u4ef6\u5168\u90e8\u4e0a\u50b3\u5931\u6557`,
|
||
// settings panel
|
||
settings_title: '\u8a2d\u5b9a',
|
||
settings_save_btn: '\u5132\u5b58\u8a2d\u5b9a',
|
||
settings_label_model: '\u9ed8\u8a8d\u6a21\u578b',
|
||
settings_label_send_key: '\u767c\u9001\u5feb\u6377\u9375',
|
||
settings_label_theme: '\u4e3b\u984c',
|
||
settings_label_skin: '\u76ae\u819a',
|
||
settings_label_language: '\u8a9d\u8a00',
|
||
settings_label_token_usage: '\u986f\u793a token \u7528\u91cf',
|
||
settings_label_cli_sessions: '\u986f\u793a CLI \u6703\u8a71',
|
||
settings_label_sync_insights: '\u540c\u6b65\u5230 insights',
|
||
settings_label_check_updates: '\u6aa2\u67e5\u66f4\u65b0',
|
||
settings_label_bot_name: '\u52a9\u624b\u540d\u7a31',
|
||
settings_label_password: '\u8a2a\u8aad\u5bc6\u78bc',
|
||
settings_saved: '\u8a2d\u5b9a\u5df2\u5132\u5b58',
|
||
settings_save_failed: '\u5132\u5b58\u5931\u6557\uff1a',
|
||
settings_load_failed: '\u8a2d\u5b9a\u52a0\u8f09\u5931\u6557\uff1a',
|
||
settings_saved_pw: '\u8a2d\u5b9a\u5df2\u5132\u5b58\uff0c\u5bc6\u78bc\u4fdd\u8b77\u5df2\u555f\u7528\uff0c\u7576\u524d\u700f\u89bd\u5668\u6703\u4fdd\u6301\u767b\u5165',
|
||
settings_saved_pw_updated: '\u8a2d\u5b9a\u5df2\u5132\u5b58\uff0c\u5bc6\u78bc\u5df2\u66f4\u65b0',
|
||
// login page
|
||
login_title: '\u767b\u5f55',
|
||
login_subtitle: '\u8f38\u5165\u5bc6\u78bc\u7e7c\u7e8c\u4f7f\u7528',
|
||
login_placeholder: '\u5bc6\u78bc',
|
||
login_btn: '\u767b\u5f55',
|
||
login_invalid_pw: '\u5bc6\u78bc\u932f\u8aa4',
|
||
login_conn_failed: '\u9023\u63a5\u5931\u6557',
|
||
// missing keys from English
|
||
dialog_confirm_title: '確認操作',
|
||
dialog_prompt_title: '輸入內容',
|
||
dialog_confirm_btn: '確認',
|
||
discard: '放棄',
|
||
clear: '清空',
|
||
create: '建立',
|
||
remove: '移除',
|
||
project_name_prompt: '專案名稱:',
|
||
tab_chat: '\u804a\u5929',
|
||
tab_memory: '\u8a18\u61b6',
|
||
tab_skills: '\u6280\u80fd',
|
||
tab_tasks: '\u4efb\u52d9',
|
||
tab_todos: '\u5f85\u8e29',
|
||
tab_workspaces: '\u5de5\u4f5c\u5340',
|
||
new_conversation: '\u65b0\u5b58\u5c0d\u8a71',
|
||
filter_conversations: '\u7b5c\u9078\u5b58\u5c0d\u8a71',
|
||
scheduled_jobs: '\u5b58\u5287\u4efb\u52d9',
|
||
new_job: '\u65b0\u4efb\u52d9',
|
||
search_skills: '\u641c\u5c0b\u6280\u80fd',
|
||
new_skill: '\u65b0\u6280\u80fd',
|
||
save_skill: '\u5132\u5b58\u6280\u80fd',
|
||
personal_memory: '\u500b\u4eba\u8a18\u61b6',
|
||
current_task_list: '\u76ee\u524d\u4efb\u52d9\u6e05\u55ae',
|
||
new_profile: '\u65b0\u914d\u7f6e\u6a94',
|
||
transcript: '\u8a18\u9304',
|
||
download_transcript: '\u4e0b\u8f09\u8a18\u9304',
|
||
import: '\u5c0e\u5165',
|
||
editing: '\u7de8\u8f2f\u4e2d',
|
||
empty_title: '\u7a7a\u767c\u5b58\u7a7a\u9593',
|
||
empty_subtitle: '\u9ede\u64ca\u4e0a\u65b9\u6309\u9215\u958b\u59cb\u5c0d\u8a71',
|
||
cancel: '\u53d6\u6d88',
|
||
loading: '\u52a0\u8f09\u4e2d',
|
||
create_job: '\u5efa\u7acb\u4efb\u52d9',
|
||
suggest_plan: '\u5efa\u8b70\u8a08\u5287',
|
||
suggest_schedule: '\u5efa\u8b70\u6642\u7a0b',
|
||
suggest_files: '\u5efa\u8b70\u6a94\u6848',
|
||
sign_out: '\u767b\u51fa',
|
||
password_placeholder: '\u5bc6\u78bc',
|
||
disable_auth: '\u505c\u7528\u9a57\u8b49',
|
||
settings_label_sound: '\u901a\u77e5\u8072\u97f3',
|
||
settings_label_notifications: '\u700f\u89bd\u901a\u77e5',
|
||
settings_desc_sound: '\u52a9\u624b\u5b8c\u6210\u56de\u7b54\u6642\u64a9\u653e\u8072\u97f3\u3002',
|
||
settings_desc_notifications: '\u7576\u5206\u9801\u5728\u5f8c\u81ea\u6642\uff0c\u6709\u56de\u7b54\u5b8c\u6210\u6e05\u55ae\u6703\u986f\u793a\u7cfb\u7d71\u901a\u77e5\u3002',
|
||
settings_desc_token_usage: '\u5728\u52a9\u624b\u6bcf\u6b21\u56de\u7b54\u4e0b\u65b9\u986f\u793a Input/Output token \u6578\u91cf\u3002\u4e5f\u53ef\u4ee5\u7528 /usage \u5207\u63db\u3002',
|
||
settings_desc_cli_sessions: '\u5c07 Hermes CLI (\u7684 state.db) \u4e2d\u7684\u6703\u8a71\u6dfb\u52a0\u5230\u6703\u8a71\u6e05\u55ae\u3002\u9ede\u64ca\u4e00\u500b CLI \u6703\u8a71\u5c07\u5c0e\u5165\u5b83\u7a0b\u5f0f\u4e26\u7e7c\u7e8c\u5b58\u5c0d\u8a71\u3002',
|
||
settings_desc_sync_insights: '\u5c07 WebUI token \u4f7f\u7528\u60c5\u6cc1\u540c\u6b65\u5230 state.db\uff0c\u8a93 hermes /insights \u5305\u542b\u700f\u89bd\u5668\u6703\u8a71\u6578\u64da\u3002\u9810\u8a2d\u70b8\u555f\u7528\u3002',
|
||
settings_desc_check_updates: '\u7576\u6709\u66f4\u65b0\u7684 WebUI \u6216\u52a9\u624b\u7248\u672c\u6642\u986f\u793a\u6a19\u8a18\u3002\u5c07\u5728\u5f8c\u81ea\u6b63\u5e38\u57f7\u884c Git-Fetch\u3002',
|
||
settings_desc_bot_name: '\u52a9\u624b\u5728 UI \u4e2d\u7684\u986f\u793a\u540d\u7a31\u3002\u9810\u8a2d\u70b8\u7528\u6539\u3002',
|
||
settings_desc_password: '\u8a2d\u5b9a WebUI \u767b\u5165\u5bc6\u78bc\u3002\u5047\u5982\u5df2\u8a2d\u7f6e\uff0c\u6bcf\u6b21\u52a0\u8f09\u90fd\u9700\u8981\u767b\u5165\u3002',
|
||
onboarding_password_will_enable: '\u5c07\u6703\u555f\u7528',
|
||
onboarding_password_will_replace: '\u5c07\u6703\u53d6\u4ee3',
|
||
onboarding_password_keep_existing: '\u4fdd\u7559\u76ee\u524d\u5bc6\u78bc',
|
||
onboarding_password_remains_disabled: '\u6703\u7e7c\u7e8c\u4fdd\u6301\u95dc\u9589',
|
||
settings_label_sound: '\u901a\u77e5\u8072\u97f3',
|
||
// boot.js
|
||
cancelling: '\u6b63\u5728\u53d6\u6d88...',
|
||
cancel_failed: '\u53d6\u6d88\u5931\u6557\uff1a',
|
||
mic_denied: '\u9ea6\u514b\u98a8\u8a2a\u554f\u88ab\u62d2\u7d75\uff0c\u8acb\u6aa2\u67e5\u700f\u89bd\u5668\u6b0a\u9650\u3002',
|
||
mic_no_speech: '\u6c92\u6709\u6aa2\u6e2c\u5230\u8a71\u97f3\uff0c\u8acb\u518d\u5617\u4e00\u6b21\u3002',
|
||
mic_network: '\u8a71\u97f3\u8b58\u5225\u76ee\u524d\u4e0d\u53ef\u7528\u3002',
|
||
mic_error: '\u8a71\u97f3\u8f38\u5165\u51fa\u932f\uff1a',
|
||
session_imported: '\u6703\u8a71\u5df2\u5c0e\u5165',
|
||
import_failed: '\u5c0e\u5165\u5931\u6557\uff1a',
|
||
import_invalid_json: 'JSON \u7121\u6548',
|
||
image_pasted: '\u5df2\u7c98\u8cbc\u5716\u7247\uff1a',
|
||
// messages.js
|
||
edit_message: '\u7de8\u8f2f\u8a0a\u606f',
|
||
regenerate: '\u91cd\u65b0\u751f\u6210\u56de\u8986',
|
||
copy: '\u8907\u88fd',
|
||
copied: '\u5df2\u8907\u88fd',
|
||
// ui.js
|
||
workspace_desc: '\u8acb\u9078\u64c7\u5de5\u4f5c\u5340\uff0c\u6216\u8f09\u5165\u65b0\u540d\u7a31\u5beb\u4e00\u500b',
|
||
tab_profiles: '\u914d\u7f6e',
|
||
},
|
||
};
|
||
|
||
// Active locale — defaults to English; overridden by loadLocale() at boot.
|
||
let _locale = LOCALES.en;
|
||
|
||
/**
|
||
* Resolve an incoming locale tag to a known LOCALES key.
|
||
* Supports exact keys, case-insensitive matches, and a few common aliases
|
||
* (e.g. zh-CN -> zh, zh-TW -> zh-Hant). Returns null when unresolved.
|
||
* @param {string} lang
|
||
* @returns {string|null}
|
||
*/
|
||
function resolveLocale(lang) {
|
||
if (typeof lang !== 'string') return null;
|
||
const raw = lang.trim();
|
||
if (!raw) return null;
|
||
if (LOCALES[raw]) return raw;
|
||
|
||
const lower = raw.toLowerCase().replace(/_/g, '-');
|
||
|
||
// Case-insensitive direct match first.
|
||
const direct = Object.keys(LOCALES).find((k) => k.toLowerCase() === lower);
|
||
if (direct) return direct;
|
||
|
||
// Common Chinese variants.
|
||
if (lower === 'zh' || lower.startsWith('zh-cn') || lower.startsWith('zh-sg') || lower.startsWith('zh-hans')) {
|
||
return LOCALES.zh ? 'zh' : null;
|
||
}
|
||
if (lower.startsWith('zh-tw') || lower.startsWith('zh-hk') || lower.startsWith('zh-mo') || lower.startsWith('zh-hant')) {
|
||
return LOCALES['zh-Hant'] ? 'zh-Hant' : null;
|
||
}
|
||
|
||
// Fallback to base language subtag (e.g. en-US -> en).
|
||
const base = lower.split('-')[0];
|
||
const baseMatch = Object.keys(LOCALES).find((k) => k.toLowerCase() === base);
|
||
return baseMatch || null;
|
||
}
|
||
|
||
/**
|
||
* Resolve locale with precedence:
|
||
* 1) primary (typically server setting)
|
||
* 2) fallback (typically localStorage)
|
||
* 3) English
|
||
* @param {string} primary
|
||
* @param {string} fallback
|
||
* @returns {string}
|
||
*/
|
||
function resolvePreferredLocale(primary, fallback) {
|
||
return resolveLocale(primary) || resolveLocale(fallback) || 'en';
|
||
}
|
||
|
||
/**
|
||
* Translate a key. Falls back to English if the key is missing in the active locale.
|
||
* Supports function values (for interpolated strings): call t('key', arg).
|
||
* @param {string} key
|
||
* @param {...*} args - forwarded to function-valued translations
|
||
* @returns {string}
|
||
*/
|
||
function t(key, ...args) {
|
||
const val = _locale[key] ?? LOCALES.en[key];
|
||
if (val === undefined) return key; // final fallback: return key itself
|
||
return typeof val === 'function' ? val(...args) : val;
|
||
}
|
||
|
||
/**
|
||
* Switch locale by language code (e.g. 'en', 'zh').
|
||
* Persists to localStorage and updates the <html lang> attribute.
|
||
* @param {string} lang
|
||
*/
|
||
function setLocale(lang) {
|
||
const resolved = resolveLocale(lang) || 'en';
|
||
_locale = LOCALES[resolved];
|
||
localStorage.setItem('hermes-lang', resolved);
|
||
document.documentElement.lang = _locale._speech || resolved;
|
||
}
|
||
|
||
/**
|
||
* Load locale from localStorage (called once at boot, before DOMContentLoaded).
|
||
* Server-persisted preference is applied later in loadSettingsPanel().
|
||
*/
|
||
function loadLocale() {
|
||
setLocale(resolvePreferredLocale(null, localStorage.getItem('hermes-lang')));
|
||
}
|
||
|
||
/**
|
||
* Re-stamp all [data-i18n] elements in the DOM with the current locale.
|
||
* Safe to call at any time — missing keys fall back to English.
|
||
* Call after setLocale() to make static HTML text update without a reload.
|
||
*/
|
||
function applyLocaleToDOM() {
|
||
document.querySelectorAll('[data-i18n]').forEach(el => {
|
||
const key = el.getAttribute('data-i18n');
|
||
const val = t(key);
|
||
if (val && val !== key) el.textContent = val;
|
||
});
|
||
document.querySelectorAll('[data-i18n-title]').forEach(el => {
|
||
const key = el.getAttribute('data-i18n-title');
|
||
const val = t(key);
|
||
if (val && val !== key) el.title = val;
|
||
});
|
||
document.querySelectorAll('[data-i18n-placeholder]').forEach(el => {
|
||
const key = el.getAttribute('data-i18n-placeholder');
|
||
const val = t(key);
|
||
if (val && val !== key) el.placeholder = val;
|
||
});
|
||
}
|
||
|
||
// Apply saved locale immediately so there's no flash of English on reload.
|
||
loadLocale();
|