Files
webui-develop/static/i18n.ts

1047 lines
45 KiB
TypeScript

// ── 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.
// Type definitions for locale entries
type LocaleString = string;
type LocaleStringFn = (n: number) => string;
type LocaleStringFn2 = (m: string, p: string) => string;
type LocaleStringFnPath = (path: string) => string;
type LocaleStringFnName = (name: string) => string;
type LocaleStringFnStatus = (name: string, status: string) => string;
type LocaleStringFnTitle = (title: string) => string;
type LocaleStringFnCount = (count: number) => string;
type LocaleStringFnTitleCount = (title: string, count: number) => string;
interface LocaleEntry {
_lang: string;
_label: string;
_speech: string;
// boot.js
cancelling?: LocaleString;
cancel_failed?: LocaleString;
mic_denied?: LocaleString;
mic_no_speech?: LocaleString;
mic_network?: LocaleString;
mic_error?: LocaleString;
session_imported?: LocaleString;
import_failed?: LocaleString;
import_invalid_json?: LocaleString;
image_pasted?: LocaleString;
// messages.js
edit_message?: LocaleString;
regenerate?: LocaleString;
copy?: LocaleString;
copied?: LocaleString;
you?: LocaleString;
thinking?: LocaleString;
expand_all?: LocaleString;
collapse_all?: LocaleString;
edit_failed?: LocaleString;
regen_failed?: LocaleString;
reconnect_active?: LocaleString;
reconnect_finished?: LocaleString;
// approval card
approval_heading?: LocaleString;
approval_desc_prefix?: LocaleString;
approval_btn_once?: LocaleString;
approval_btn_once_title?: LocaleString;
approval_btn_session?: LocaleString;
approval_btn_session_title?: LocaleString;
approval_btn_always?: LocaleString;
approval_btn_always_title?: LocaleString;
approval_btn_deny?: LocaleString;
approval_btn_deny_title?: LocaleString;
approval_responding?: LocaleString;
clarify_heading?: LocaleString;
clarify_hint?: LocaleString;
clarify_other?: LocaleString;
clarify_send?: LocaleString;
clarify_input_placeholder?: LocaleString;
clarify_responding?: LocaleString;
untitled?: LocaleString;
n_messages?: LocaleStringFn;
model_unavailable?: LocaleString;
model_unavailable_title?: LocaleString;
provider_mismatch_warning?: LocaleStringFn2;
provider_mismatch_label?: LocaleString;
model_custom_label?: LocaleString;
model_custom_placeholder?: LocaleString;
model_search_placeholder?: LocaleString;
model_search_no_results?: LocaleString;
// commands.js
cmd_clear?: LocaleString;
cmd_compress?: LocaleString;
cmd_compact_alias?: LocaleString;
cmd_model?: LocaleString;
cmd_workspace?: LocaleString;
cmd_new?: LocaleString;
cmd_usage?: LocaleString;
cmd_theme?: LocaleString;
cmd_personality?: LocaleString;
cmd_skills?: LocaleString;
available_commands?: LocaleString;
type_slash?: LocaleString;
conversation_cleared?: LocaleString;
command_label?: LocaleString;
context_compaction_label?: LocaleString;
reference_only_label?: LocaleString;
model_usage?: LocaleString;
no_model_match?: LocaleString;
switched_to?: LocaleString;
workspace_usage?: LocaleString;
no_workspace_match?: LocaleString;
switched_workspace?: LocaleString;
workspace_switch_failed?: LocaleString;
new_session?: LocaleString;
compressing?: LocaleString;
compress_running_label?: LocaleString;
compress_complete_label?: LocaleString;
compress_failed_label?: LocaleString;
focus_label?: LocaleString;
token_usage_on?: LocaleString;
token_usage_off?: LocaleString;
theme_usage?: LocaleString;
theme_set?: LocaleString;
no_active_session?: LocaleString;
slash_skill_badge?: LocaleString;
slash_skill_desc?: LocaleString;
cmd_stop?: LocaleString;
cmd_title?: LocaleString;
cmd_retry?: LocaleString;
cmd_undo?: LocaleString;
cmd_status?: LocaleString;
cmd_voice?: LocaleString;
stream_stopped?: LocaleString;
no_active_task?: LocaleString;
cancel_unavailable?: LocaleString;
retry_failed?: LocaleString;
undo_failed?: LocaleString;
undid_n_messages?: LocaleString;
undid_messages_suffix?: LocaleString;
status_heading?: LocaleString;
status_session_id?: LocaleString;
status_title?: LocaleString;
status_model?: LocaleString;
status_workspace?: LocaleString;
status_personality?: LocaleString;
status_messages?: LocaleString;
status_agent_running?: LocaleString;
status_yes?: LocaleString;
status_no?: LocaleString;
status_load_failed?: LocaleString;
title_current?: LocaleString;
title_change_hint?: LocaleString;
title_set?: LocaleString;
cmd_webui_only_session?: LocaleString;
cmd_voice_use_mic?: LocaleString;
usage_heading?: LocaleString;
usage_default_model?: LocaleString;
usage_unknown?: LocaleString;
usage_input_tokens?: LocaleString;
usage_output_tokens?: LocaleString;
usage_total?: LocaleString;
usage_estimated_cost?: LocaleString;
usage_settings_tip?: LocaleString;
usage_load_failed?: LocaleString;
usage_personality_none?: LocaleString;
no_personalities?: LocaleString;
available_personalities?: LocaleString;
personality_switch_hint?: LocaleString;
personalities_load_failed?: LocaleString;
personality_cleared?: LocaleString;
personality_set?: LocaleString;
failed_colon?: LocaleString;
// ui.js
no_workspace?: LocaleString;
workspace_empty_no_path?: LocaleString;
workspace_empty_dir?: LocaleString;
dialog_confirm_title?: LocaleString;
dialog_prompt_title?: LocaleString;
dialog_confirm_btn?: LocaleString;
// workspace.js
unsaved_confirm?: LocaleString;
discard?: LocaleString;
save?: LocaleString;
edit?: LocaleString;
clear?: LocaleString;
create?: LocaleString;
remove?: LocaleString;
save_title?: LocaleString;
edit_title?: LocaleString;
saved?: LocaleString;
save_failed?: LocaleString;
image_load_failed?: LocaleString;
file_open_failed?: LocaleString;
downloading?: LocaleStringFnPath;
double_click_rename?: LocaleString;
renamed_to?: LocaleString;
rename_failed?: LocaleString;
delete_title?: LocaleString;
delete_confirm?: LocaleStringFnPath;
deleted?: LocaleString;
delete_failed?: LocaleString;
new_file_prompt?: LocaleString;
project_name_prompt?: LocaleString;
created?: LocaleString;
create_failed?: LocaleString;
new_folder_prompt?: LocaleString;
folder_created?: LocaleString;
folder_create_failed?: LocaleString;
remove_title?: LocaleString;
empty_dir?: LocaleString;
upload_failed?: LocaleString;
all_uploads_failed?: LocaleStringFn;
// settings panel
settings_title?: LocaleString;
settings_save_btn?: LocaleString;
settings_label_model?: LocaleString;
settings_label_send_key?: LocaleString;
settings_label_theme?: LocaleString;
settings_label_skin?: LocaleString;
settings_label_language?: LocaleString;
settings_label_token_usage?: LocaleString;
settings_label_bubble_layout?: LocaleString;
settings_label_cli_sessions?: LocaleString;
settings_label_sync_insights?: LocaleString;
settings_label_check_updates?: LocaleString;
settings_label_bot_name?: LocaleString;
settings_label_password?: LocaleString;
settings_saved?: LocaleString;
settings_save_failed?: LocaleString;
settings_load_failed?: LocaleString;
settings_saved_pw?: LocaleString;
settings_saved_pw_updated?: LocaleString;
// login page
login_title?: LocaleString;
login_subtitle?: LocaleString;
login_placeholder?: LocaleString;
login_btn?: LocaleString;
login_invalid_pw?: LocaleString;
login_conn_failed?: LocaleString;
// Sidebar & Tabs
tab_chat?: LocaleString;
tab_tasks?: LocaleString;
tab_skills?: LocaleString;
tab_memory?: LocaleString;
tab_workspaces?: LocaleString;
tab_profiles?: LocaleString;
new_conversation?: LocaleString;
filter_conversations?: LocaleString;
session_time_unknown?: LocaleString;
session_time_just_now?: LocaleString;
session_time_minutes_ago?: LocaleStringFn;
session_time_hours_ago?: LocaleStringFn;
session_time_days_ago?: LocaleStringFn;
session_time_last_week?: LocaleString;
session_time_bucket_today?: LocaleString;
session_time_bucket_yesterday?: LocaleString;
session_time_bucket_this_week?: LocaleString;
session_time_bucket_last_week?: LocaleString;
session_time_bucket_older?: LocaleString;
scheduled_jobs?: LocaleString;
new_job?: LocaleString;
loading?: LocaleString;
search_skills?: LocaleString;
new_skill?: LocaleString;
personal_memory?: LocaleString;
workspace_desc?: LocaleString;
new_profile?: LocaleString;
transcript?: LocaleString;
download_transcript?: LocaleString;
import?: LocaleString;
// Settings detail
settings_label_sound?: LocaleString;
settings_desc_sound?: LocaleString;
settings_label_notifications?: LocaleString;
settings_desc_notifications?: LocaleString;
settings_desc_token_usage?: LocaleString;
settings_desc_bubble_layout?: LocaleString;
settings_desc_cli_sessions?: LocaleString;
settings_desc_sync_insights?: LocaleString;
settings_desc_check_updates?: LocaleString;
settings_desc_bot_name?: LocaleString;
settings_desc_password?: LocaleString;
password_placeholder?: LocaleString;
disable_auth?: LocaleString;
sign_out?: LocaleString;
cancel?: LocaleString;
create_job?: LocaleString;
save_skill?: LocaleString;
editing?: LocaleString;
// Empty state
empty_title?: LocaleString;
empty_subtitle?: LocaleString;
suggest_files?: LocaleString;
suggest_schedule?: LocaleString;
suggest_plan?: LocaleString;
// onboarding
onboarding_badge?: LocaleString;
onboarding_title?: LocaleString;
onboarding_lead?: LocaleString;
onboarding_back?: LocaleString;
onboarding_continue?: LocaleString;
onboarding_skip?: LocaleString;
onboarding_skipped?: LocaleString;
onboarding_open?: LocaleString;
onboarding_step_system_title?: LocaleString;
onboarding_step_system_desc?: LocaleString;
onboarding_step_setup_title?: LocaleString;
onboarding_step_setup_desc?: LocaleString;
onboarding_step_workspace_title?: LocaleString;
onboarding_step_workspace_desc?: LocaleString;
onboarding_step_password_title?: LocaleString;
onboarding_step_password_desc?: LocaleString;
onboarding_step_finish_title?: LocaleString;
onboarding_step_finish_desc?: LocaleString;
onboarding_notice_system_ready?: LocaleString;
onboarding_notice_system_unavailable?: LocaleString;
onboarding_check_agent?: LocaleString;
onboarding_check_agent_ready?: LocaleString;
onboarding_check_agent_missing?: LocaleString;
onboarding_check_password?: LocaleString;
onboarding_check_password_enabled?: LocaleString;
onboarding_check_password_disabled?: LocaleString;
onboarding_check_provider?: LocaleString;
onboarding_check_provider_ready?: LocaleString;
onboarding_check_provider_partial?: LocaleString;
onboarding_check_provider_pending?: LocaleString;
onboarding_config_file?: LocaleString;
onboarding_env_file?: LocaleString;
onboarding_unknown?: LocaleString;
onboarding_current_provider?: LocaleString;
onboarding_missing_imports?: LocaleString;
onboarding_notice_setup_required?: LocaleString;
onboarding_notice_setup_already_ready?: LocaleString;
onboarding_oauth_provider_ready_title?: LocaleString;
onboarding_oauth_provider_ready_body?: LocaleString;
onboarding_oauth_provider_not_ready_title?: LocaleString;
onboarding_oauth_provider_not_ready_body?: LocaleString;
onboarding_oauth_switch_hint?: LocaleString;
onboarding_notice_workspace?: LocaleString;
onboarding_workspace_label?: LocaleString;
onboarding_workspace_or_path?: LocaleString;
onboarding_workspace_placeholder?: LocaleString;
onboarding_provider_label?: LocaleString;
onboarding_quick_setup_badge?: LocaleString;
onboarding_api_key_label?: LocaleString;
onboarding_api_key_placeholder?: LocaleString;
onboarding_api_key_help_prefix?: LocaleString;
onboarding_base_url_label?: LocaleString;
onboarding_base_url_placeholder?: LocaleString;
onboarding_base_url_help?: LocaleString;
onboarding_model_label?: LocaleString;
onboarding_workspace_help?: LocaleString;
onboarding_custom_model_placeholder?: LocaleString;
onboarding_custom_model_help?: LocaleString;
onboarding_notice_password_enabled?: LocaleString;
onboarding_notice_password_recommended?: LocaleString;
onboarding_password_label?: LocaleString;
onboarding_password_placeholder?: LocaleString;
onboarding_password_help?: LocaleString;
onboarding_notice_finish?: LocaleString;
onboarding_not_set?: LocaleString;
onboarding_password_will_enable?: LocaleString;
onboarding_password_will_replace?: LocaleString;
onboarding_password_keep_existing?: LocaleString;
onboarding_password_remains_disabled?: LocaleString;
onboarding_password_skipped?: LocaleString;
onboarding_finish_help?: LocaleString;
onboarding_error_choose_workspace?: LocaleString;
onboarding_error_choose_model?: LocaleString;
onboarding_error_provider_required?: LocaleString;
onboarding_error_base_url_required?: LocaleString;
onboarding_error_workspace_required?: LocaleString;
onboarding_error_model_required?: LocaleString;
onboarding_complete?: LocaleString;
// panel/runtime i18n
error_prefix?: LocaleString;
not_available?: LocaleString;
never?: LocaleString;
add?: LocaleString;
add_failed?: LocaleString;
remove_failed?: LocaleString;
switch_failed?: LocaleString;
name_required?: LocaleString;
content_required?: LocaleString;
view?: LocaleString;
dismiss?: LocaleString;
disable?: LocaleString;
cron_no_jobs?: LocaleString;
cron_status_off?: LocaleString;
cron_status_paused?: LocaleString;
cron_status_error?: LocaleString;
cron_status_active?: LocaleString;
cron_next?: LocaleString;
cron_last?: LocaleString;
cron_run_now?: LocaleString;
cron_pause?: LocaleString;
cron_resume?: LocaleString;
cron_job_name_placeholder?: LocaleString;
cron_schedule_placeholder?: LocaleString;
cron_prompt_placeholder?: LocaleString;
cron_last_output?: LocaleString;
cron_all_runs?: LocaleString;
cron_hide_runs?: LocaleString;
cron_no_runs_yet?: LocaleString;
cron_schedule_required_example?: LocaleString;
cron_schedule_required?: LocaleString;
cron_prompt_required?: LocaleString;
cron_job_created?: LocaleString;
cron_job_triggered?: LocaleString;
cron_job_paused?: LocaleString;
cron_job_resumed?: LocaleString;
cron_job_updated?: LocaleString;
cron_delete_confirm_title?: LocaleString;
cron_delete_confirm_message?: LocaleString;
cron_job_deleted?: LocaleString;
cron_completion_status?: LocaleStringFnStatus;
status_failed?: LocaleString;
status_completed?: LocaleString;
clear_conversation_title?: LocaleString;
clear_conversation_message?: LocaleString;
clear_failed?: LocaleString;
// inline cron labels
cron_label_schedule?: LocaleString;
cron_label_next_run?: LocaleString;
cron_label_last_ran?: LocaleString;
cron_label_prompt?: LocaleString;
cron_label_edit?: LocaleString;
cron_label_delete?: LocaleString;
cron_label_never?: LocaleString;
cron_running?: LocaleString;
skills_no_match?: LocaleString;
linked_files?: LocaleString;
skill_load_failed?: LocaleString;
skill_file_load_failed?: LocaleString;
skill_name_required?: LocaleString;
skill_updated?: LocaleString;
skill_created?: LocaleString;
memory_notes_label?: LocaleString;
memory_saved?: LocaleString;
my_notes?: LocaleString;
user_profile?: LocaleString;
no_notes_yet?: LocaleString;
no_profile_yet?: LocaleString;
workspace_choose_path?: LocaleString;
workspace_choose_path_meta?: LocaleString;
workspace_manage?: LocaleString;
workspace_manage_meta?: LocaleString;
workspace_use_title?: LocaleString;
workspace_use?: LocaleString;
workspace_add_path_placeholder?: LocaleString;
workspace_paths_validated_hint?: LocaleString;
workspace_added?: LocaleString;
workspace_remove_confirm_title?: LocaleString;
workspace_remove_confirm_message?: LocaleStringFnPath;
workspace_removed?: LocaleString;
workspace_switch_prompt_title?: LocaleString;
workspace_switch_prompt_message?: LocaleString;
workspace_switch_prompt_confirm?: LocaleString;
workspace_switch_prompt_placeholder?: LocaleString;
workspace_not_added?: LocaleString;
workspace_already_saved?: LocaleString;
workspace_busy_switch?: LocaleString;
discard_file_edits_title?: LocaleString;
discard_file_edits_message?: LocaleString;
workspace_switched_to?: LocaleStringFnPath;
profiles_no_profiles?: LocaleString;
profile_api_keys_configured?: LocaleString;
profile_gateway_running?: LocaleString;
profile_gateway_stopped?: LocaleString;
profile_active?: LocaleString;
profile_no_configuration?: LocaleString;
profile_skill_count?: LocaleStringFnCount;
profile_use?: LocaleString;
profile_switch_title?: LocaleString;
profile_delete_title?: LocaleString;
profile_default_label?: LocaleString;
profile_name_placeholder?: LocaleString;
profile_clone_label?: LocaleString;
profile_base_url_placeholder?: LocaleString;
profile_api_key_placeholder?: LocaleString;
manage_profiles?: LocaleString;
profiles_load_failed?: LocaleString;
profiles_busy_switch?: LocaleString;
profile_switched_new_conversation?: LocaleStringFnPath;
profile_switched?: LocaleStringFnPath;
profile_name_rule?: LocaleString;
profile_base_url_rule?: LocaleString;
profile_created?: LocaleStringFnPath;
profile_delete_confirm_title?: LocaleStringFnPath;
profile_delete_confirm_message?: LocaleString;
profile_deleted?: LocaleStringFnPath;
gateways_no_gateways?: LocaleString;
gateway_running?: LocaleString;
gateway_stopped?: LocaleString;
gateway_stop?: LocaleString;
gateway_start?: LocaleString;
gateway_restart?: LocaleString;
gateway_stop_title?: LocaleString;
gateway_start_title?: LocaleString;
gateway_restart_title?: LocaleString;
gateway_started?: LocaleStringFnPath;
gateway_stopped_msg?: LocaleStringFnPath;
gateway_restarted?: LocaleStringFnPath;
gateway_start_failed?: LocaleString;
gateway_stop_failed?: LocaleString;
gateway_restart_failed?: LocaleString;
gateway_add?: LocaleString;
gateway_add_title?: LocaleString;
gateway_add_message?: LocaleString;
gateway_added?: LocaleStringFnPath;
gateway_add_failed?: LocaleString;
active_conversation_none?: LocaleString;
active_conversation_meta?: LocaleStringFnTitleCount;
settings_unsaved_changes?: LocaleString;
sign_out_failed?: LocaleString;
disable_auth_confirm_title?: LocaleString;
disable_auth_confirm_message?: LocaleString;
auth_disabled?: LocaleString;
disable_auth_failed?: LocaleString;
bg_error_single?: LocaleStringFnTitle;
bg_error_multi?: LocaleStringFnCount;
// Fallback keys
[key: string]: LocaleString | LocaleStringFn | LocaleStringFn2 | LocaleStringFnPath | LocaleStringFnName | LocaleStringFnStatus | LocaleStringFnTitle | LocaleStringFnCount | LocaleStringFnTitleCount | undefined;
}
const LOCALES: Record<string, LocaleEntry> = {
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',
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\u2026',
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\u2026',
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',
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
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',
// Sidebar & Tabs
tab_chat: 'Chat',
tab_tasks: 'Tasks',
tab_skills: 'Skills',
tab_memory: 'Memory',
tab_workspaces: 'Spaces',
tab_profiles: 'Profiles',
new_conversation: 'New conversation',
filter_conversations: 'Filter conversations...',
session_time_unknown: 'Unknown',
session_time_just_now: 'gerade eben',
session_time_minutes_ago: (n) => `vor ${n} Min.`,
session_time_hours_ago: (n) => `vor ${n} Std.`,
session_time_days_ago: (n) => `vor ${n} Tag${n === 1 ? '' : 'en'}`,
session_time_last_week: 'letzte Woche',
session_time_bucket_today: 'Heute',
session_time_bucket_yesterday: 'Gestern',
session_time_bucket_this_week: 'Diese Woche',
session_time_bucket_last_week: 'Letzte Woche',
session_time_bucket_older: 'Älter',
scheduled_jobs: 'Geplante Aufgaben',
new_job: '+ Neue Aufgabe',
loading: 'Wird geladen...',
search_skills: 'Search skills...',
new_skill: 'New skill',
personal_memory: 'Personal memory',
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\u2026',
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: 'Keine geplanten Aufgaben gefunden.',
cron_status_off: 'AUS',
cron_status_paused: 'PAUSIERT',
cron_status_error: 'FEHLER',
cron_status_active: 'AKTIV',
cron_next: 'N\u00e4chste',
cron_last: 'Letzte',
cron_run_now: 'Jetzt starten',
cron_pause: 'Pausieren',
cron_resume: 'Fortsetzen',
cron_job_name_placeholder: 'Aufgabenname',
cron_schedule_placeholder: 'Zeitplan',
cron_prompt_placeholder: 'Prompt',
cron_last_output: 'Letzte Ausgabe',
cron_all_runs: 'Alle Ausf\u00fchrungen',
cron_hide_runs: 'Ausf\u00fchrungen verbergen',
cron_no_runs_yet: '(noch keine Ausf\u00fchrung)',
cron_schedule_required_example: 'Zeitplan erforderlich (z.B. "0 9 * * *" oder "every 1h")',
cron_schedule_required: 'Zeitplan erforderlich',
cron_prompt_required: 'Prompt erforderlich',
cron_loading: 'Laden...',
cron_add_skills_placeholder: 'Skills hinzufügen (optional)...',
cron_deliver_local: 'Lokal (nur speichern)',
cron_deliver_discord: 'Discord',
cron_deliver_telegram: 'Telegram',
cron_job_created: 'Aufgabe erstellt',
cron_job_triggered: 'Aufgabe gestartet',
cron_job_paused: 'Aufgabe pausiert',
cron_job_resumed: 'Aufgabe fortgesetzt',
cron_job_updated: 'Aufgabe aktualisiert',
cron_delete_confirm_title: 'Aufgabe l\u00f6schen',
cron_delete_confirm_message: 'Dies kann nicht r\u00fcckg\u00e4ngig gemacht werden.',
cron_job_deleted: 'Aufgabe gel\u00f6scht',
cron_completion_status: (name, status) => `Aufgabe "${name}" ${status}`,
status_failed: 'fehlgeschlagen',
status_completed: 'abgeschlossen',
clear_conversation_title: 'Chat leeren',
clear_conversation_message: 'Alle Nachrichten löschen? Dies kann nicht rückgängig gemacht werden.',
clear_failed: 'Leeren fehlgeschlagen: ',
cron_running: 'L\u00e4uft...',
// inline cron labels (used directly in HTML templates)
cron_label_schedule: 'Zeitplan',
cron_label_next_run: 'N\u00e4chste Ausf\u00fchrung',
cron_label_last_ran: 'Zuletzt gelaufen',
cron_label_prompt: 'Prompt',
cron_label_edit: 'Bearbeiten',
cron_label_delete: 'L\u00f6schen',
cron_label_never: 'nie',
skills_no_match: 'Keine Skills gefunden.',
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`,
},
};
// Helper type for t() function arguments
type TranslationValue = LocaleString | LocaleStringFn | LocaleStringFn2 | LocaleStringFnPath | LocaleStringFnName | LocaleStringFnStatus | LocaleStringFnTitle | LocaleStringFnCount | LocaleStringFnTitleCount | undefined;
function t(key: string, ...args: unknown[]): string {
const lang = (typeof _locale !== 'undefined' && _locale && _locale._lang) ? _locale._lang : 'en';
const locale = LOCALES[lang] || LOCALES['en'] || LOCALES.en;
const en = LOCALES['en'];
// Try current locale first, fall back to English
let val: TranslationValue = locale[key];
if (val === undefined) val = en[key];
if (val === undefined) return key;
// Handle function types (parameterized translations)
if (typeof val === 'function') {
try {
return (val as (...args: unknown[]) => string)(...args);
} catch {
return key;
}
}
// Handle string replacements for simple string values with {0}, {1} style placeholders
if (typeof val === 'string' && args.length > 0) {
return args.reduce<string>((result, arg, i) => {
return result.replace(new RegExp(`\\{${i}\\}`, 'g'), String(arg));
}, val);
}
return val as string;
}
// Declare the global _locale variable
declare global {
var _locale: LocaleEntry | undefined;
}
export { LOCALES, t };
export type { LocaleEntry };