Files
Skald-Circle/web/i18n/en.js
T

1159 lines
64 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export default {
// ── Navigation ─────────────────────────────────────────────────────────────
'nav.chat': 'Chat',
'nav.inbox': 'Inbox',
'nav.dashboard': 'Dashboard',
'nav.projects': 'Projects',
'nav.tasks': 'Task Manager',
'nav.tasks.running': 'Running Tasks',
'nav.tasks.cron': 'Cron Jobs',
'nav.tasks.scheduled': 'Scheduled Tasks',
'nav.tasks.history': 'History',
'nav.models': 'Models',
'nav.providers': 'Providers',
'nav.security': 'Security',
'nav.agents': 'Agents',
'nav.users': 'Users',
'nav.roles': 'Roles',
'nav.connectors': 'Connectors',
'nav.plugins': 'Plugins',
'nav.plugin_catalog': 'Plugin Catalog',
'nav.catalog': 'Catalog',
'nav.config': 'Settings',
'nav.llm_requests': 'LLM Requests',
'nav.tic': 'TIC Sessions',
// ── Top bar ────────────────────────────────────────────────────────────────
'topbar.profile': 'Profile',
'topbar.logout': 'Log out',
'topbar.account': 'Account',
'topbar.open_chat': 'Open chat',
'topbar.brand': 'Skald',
'topbar.to_light': 'Switch to light mode',
'topbar.to_dark': 'Switch to dark mode',
// ── Chat ───────────────────────────────────────────────────────────────────
'chat.title': 'Skald',
'chat.tab.general': 'General',
'chat.hello': 'Hello! How can I help you today?',
'chat.greeting': 'Hi there!',
'chat.greeting.named': 'Hi, {name}!',
'chat.greeting.sub': 'What can I do for you today?',
'chat.placeholder': 'Message… (Enter to send, Shift+Enter for a new line)',
'chat.mobile.placeholder': 'Type a message…',
'chat.mobile.ask': 'Ask me anything',
'chat.mobile.back_general': 'Back to General',
'chat.mobile.project': 'Project',
'chat.mobile.chat': 'Chat',
'chat.mobile.record_voice': 'Record voice',
'chat.mobile.stop_record': 'Stop recording',
'mobile.coming_soon': 'Coming soon',
'mobile.nav.inbox': 'Inbox',
'mobile.nav.projects': 'Projects',
'mobile.nav.chat': 'Chat',
'mobile.nav.alerts': 'Alerts',
'mobile.nav.settings': 'Settings',
'chat.send': 'Send',
'chat.stop': 'Stop',
'chat.thinking': 'Thinking…',
'chat.attach': 'Attach files',
'chat.new_session': 'New conversation',
'chat.security_group': 'Security group',
'chat.collapse': 'Hide chat',
'chat.close_tab': 'Close tab',
'chat.privacy': 'Private to you',
'chat.privacy.hint': 'Only you can see this conversation. Sharing anything with the group always asks for approval first.',
'chat.suggest.1': 'What can you do?',
'chat.suggest.2': 'Help me plan my day',
'chat.suggest.3': 'Tell me a story',
'chat.suggest.4': 'What do you remember about me?',
'chat.rejected': 'Denied.',
'chat.rejected_by_user': 'Denied by user.',
'chat.truncated': 'Response truncated by the token limit (↓{tokens} tok).',
// ── Copilot render ─────────────────────────────────────────────────────────
'copilot.open_in_viewer': 'Open in viewer',
'copilot.unchanged_lines': '⋯ {n} unchanged lines ⋯',
'copilot.cancel': 'Cancel',
'copilot.clarification_ph': 'Type your answer…',
'copilot.send': 'Send',
'copilot.result': 'result',
'copilot.error_label': 'error',
'copilot.not_sent_to_llm': 'This message is not sent to the LLM',
'copilot.remove': 'Remove',
'copilot.result_json': 'result · json',
'copilot.agent_done': 'done',
'copilot.agent_running': 'running…',
'copilot.agent_finished': 'finished',
'copilot.status_awaiting': 'Awaiting approval',
'copilot.status_cancelled': 'Cancelled by user',
'copilot.status_denied': 'Denied by policy',
'copilot.bypass_session': 'Session',
'copilot.bypass_15min': '15 min',
// ── Copilot slash commands ─────────────────────────────────────────────────
'copilot.cmd.help': 'Show available commands',
'copilot.cmd.clear': 'Start a new conversation',
'copilot.cmd.new': 'Alias for /clear',
'copilot.cmd.models': 'List available LLM models',
'copilot.cmd.model': 'Select the model for this chat',
'copilot.cmd.context': 'Last turn\'s token usage',
'copilot.cmd.cost': 'Session spend (USD)',
'copilot.cmd.compact': 'Force context compaction',
'copilot.cmd.resettools': 'Remove activated tool groups',
'copilot.cmd.sethome': 'Set web as notification home',
// ── LLM Requests ────────────────────────────────────────────────────────────
'llmr.title': 'LLM Requests',
'llmr.loading': 'Loading…',
'llmr.empty': 'No requests found.',
'llmr.total': '{n} rows',
'llmr.filter.agent_id': 'Agent ID',
'llmr.filter.agent_ph': 'e.g. main',
'llmr.filter.source': 'Source',
'llmr.filter.source_ph': 'e.g. web, tic, cron',
'llmr.filter.from': 'From',
'llmr.filter.to': 'To',
'llmr.filter.apply': 'Apply',
'llmr.filter.reset': 'Reset',
'llmr.table.agent': 'Agent',
'llmr.table.source': 'Source',
'llmr.table.model': 'Model',
'llmr.table.date': 'Date',
'llmr.table.in_tokens': 'In tokens',
'llmr.table.out_tokens': 'Out tokens',
'llmr.table.cache_hit': 'Cache hit',
'llmr.cache_read': 'read: {n} tk',
'llmr.cache_write': 'write: {n} tk',
'llmr.pagination': 'Page {cur} of {pages} — {total} results',
// ── LLM Request Detail ──────────────────────────────────────────────────────
'llmr.detail.back': 'Back',
'llmr.detail.loading': 'Loading…',
'llmr.detail.request': 'Request',
'llmr.detail.no_agent': 'no agent',
'llmr.detail.error_badge': 'error',
'llmr.detail.purged': 'Payload not available — this request has been purged by the retention policy.',
'llmr.detail.reasoning_label': 'reasoning',
'llmr.detail.tool_params': 'Parameters',
'llmr.detail.tool_result': 'Result',
'llmr.detail.system_role': 'system',
'llmr.detail.cache_label': 'cache {pct}',
'llmr.detail.stat_input': 'Input tokens',
'llmr.detail.stat_output': 'Output tokens',
'llmr.detail.section_req_headers': 'Request Headers',
'llmr.detail.section_resp_headers':'Response Headers',
'llmr.detail.section_params': 'Parameters',
'llmr.detail.section_system': 'System Prompt',
'llmr.detail.section_conversation':'Conversation',
'llmr.detail.section_tools': 'Tools Defined',
'llmr.detail.section_response': 'Response',
// ── Config ──────────────────────────────────────────────────────────────────
'config.title': 'Config',
'config.loading': 'Loading…',
'config.developer': 'Developer',
'config.error_save':'Error saving "{name}": {msg}',
'config.enabled': 'Enabled',
'config.disabled': 'Disabled',
'config.set.interface.name': 'Interface',
'config.set.interface.desc': 'Look and feel of the web interface.',
'config.set.tic_agent.name': 'TIC Agent',
'config.set.tic_agent.desc': 'TIC is a background agent that monitors all async events generated by connected MCP servers (new emails, calendar updates, WhatsApp messages, etc.). It reads your notification rules from data/notifications.md and your memory to decide — via an LLM call — which events are worth surfacing. Relevant notifications are forwarded to the home agent set via /sethome.',
'config.prop.ui_locale.name': 'Language',
'config.prop.ui_locale.desc': 'Default interface language for the whole instance. Each user can override it on their profile.',
'config.prop.tic__enabled.name': 'Enabled',
'config.prop.tic__enabled.desc': 'Enable or disable the TIC agent. When disabled, no MCP events are processed.',
'config.prop.tic__security_group.name': 'Security Group',
'config.prop.tic__security_group.desc': 'Tool permission group applied to each TIC agent session. Leave empty to use the default group.',
'config.prop.tic__interval_minutes.name': 'Check Interval (minutes)',
'config.prop.tic__interval_minutes.desc': 'How often TIC runs, in minutes. Leave empty to use the value from config.yml (tic.interval_secs).',
// ── Projects ────────────────────────────────────────────────────────────────
'projects.title': 'Projects',
'projects.btn.new': 'New Project',
'projects.empty': 'No projects yet. Create one to get started.',
'projects.action.edit': 'Edit',
'projects.action.delete': 'Delete',
'projects.card.updated': 'Updated',
'projects.confirm.delete': 'Delete project "{name}"?\nAll tickets will also be deleted.',
'projects.modal.title_edit': 'Edit Project',
'projects.modal.title_new': 'New Project',
'projects.modal.name': 'Name',
'projects.modal.name_ph': 'My Project',
'projects.modal.path': 'Path',
'projects.modal.path_ph': '/path/to/project',
'projects.modal.desc': 'Description',
'projects.modal.desc_ph': 'What this project is about',
'projects.modal.cancel': 'Cancel',
'projects.modal.saving': 'Saving…',
'projects.modal.save': 'Save',
'projects.modal.create': 'Create',
// ── Project board ───────────────────────────────────────────────────────────
'project_board.back': 'Projects',
'project_board.open_chat': 'Open Chat',
'project_board.new_ticket': 'New Ticket',
'project_board.tab.tickets': 'Tickets',
'project_board.section.running': 'Running',
'project_board.section.running_empty': 'No tickets running',
'project_board.section.todo': 'Todo',
'project_board.section.todo_empty': 'No tickets to do',
'project_board.section.completed': 'Completed',
'project_board.section.completed_empty': 'No completed tickets',
'project_board.ticket.start': 'Start',
'project_board.ticket.running': 'Running…',
'project_board.ticket.reset': 'Reset',
'project_board.ticket.result': 'Result',
'project_board.ticket.error': 'Error',
'project_board.ticket.no_output': '(no output)',
'project_board.ticket.no_error': '(no error message)',
'project_board.modal.title': 'New Ticket',
'project_board.modal.title_label': 'Title',
'project_board.modal.title_ph': 'What needs to be done',
'project_board.modal.desc_label': 'Description / Prompt',
'project_board.modal.desc_ph': 'Detailed instructions for the agent…',
'project_board.modal.agent': 'Agent',
'project_board.modal.security_group':'Security Group',
'project_board.modal.inherit': '— inherit from project —',
'project_board.modal.cancel': 'Cancel',
'project_board.modal.saving': 'Saving…',
'project_board.modal.create': 'Create',
'project_board.confirm.delete': 'Delete ticket "{title}"?',
// ── Session detail ──────────────────────────────────────────────────────────
'session.back': 'Back',
'session.loading': 'Loading session…',
'session.no_session': 'No session loaded.',
'session.no_session_hint': 'Navigate to <code>#session/{id}</code> to view a session.',
'session.empty': 'No messages in this session.',
'session.user_role': 'User',
'session.assistant_role': 'Assistant',
'session.reasoning_label': 'Reasoning',
'session.thinking_role': 'Thinking',
'session.failed': 'failed',
'session.ephemeral': 'ephemeral',
'session.automated': 'automated',
'session.live': 'live',
'session.agent': 'agent:',
'session.id': 'id:',
'session.sub_agent': 'Sub-agent:',
'session.end_of': 'end of',
'session.depth': 'depth {n}',
'session.synthetic': 'synthetic',
'session.tool_args': 'Arguments',
'session.tool_result': 'Result',
'session.tool_error': 'Error',
// ── Inbox ──────────────────────────────────────────────────────────────────
'inbox.empty': 'No pending requests',
'inbox.reject_prompt': 'Rejection reason (optional):',
// ── Approvals ──────────────────────────────────────────────────────────────
'approval.pending': 'Waiting for your OK',
'approval.approved': 'Allowed',
'approval.rejected': 'Denied',
'approval.approve': 'Allow',
'approval.reject': 'Deny',
'approval.confirm_reject': 'Confirm deny',
'approval.reject_hint': 'Optional: say why (the assistant will read it)',
'approval.bypass_15': 'Allow and skip similar requests for 15 minutes',
'approval.bypass_all': 'Allow and skip all requests for this session',
// ── Login ──────────────────────────────────────────────────────────────────
'login.title': 'Welcome back',
'login.subtitle': 'Sign in to your account.',
'login.username': 'Username',
'login.password': 'Password',
'login.submit': 'Sign in',
'login.signing': 'Signing in…',
'login.missing': 'Enter your username and password.',
'login.error': 'Invalid username or password.',
'login.network': 'Network error — please try again.',
// ── Profile ────────────────────────────────────────────────────────────────
'profile.title': 'Profile',
'profile.account': 'Account',
'profile.username': 'Username',
'profile.role': 'Role',
'profile.name': 'Display name',
'profile.name.ph': 'Your name',
'profile.language': 'Language',
'profile.language.default': 'Group default ({locale})',
'profile.saved': 'Saved.',
'profile.pw': 'Change password',
'profile.pw.current': 'Current password',
'profile.pw.new': 'New password',
'profile.pw.confirm': 'Confirm new password',
'profile.pw.short': 'Password must be at least 4 characters.',
'profile.pw.mismatch': 'Passwords do not match.',
'profile.pw.changed': 'Password changed.',
'profile.pw.submit': 'Change password',
// ── Settings (config page extras) ──────────────────────────────────────────
'config.debug': 'Debug mode',
'config.debug.desc': 'Show developer pages (LLM requests, TIC sessions) in the sidebar.',
// ── First-run setup ────────────────────────────────────────────────────────
'setup.title': 'Welcome to Skald',
'setup.subtitle': 'Create the admin account to get started.',
'setup.username': 'Choose a username.',
'setup.pw.short': 'Password must be at least 4 characters.',
'setup.pw.mismatch': 'The two passwords do not match.',
'setup.confirm': 'Confirm password',
'setup.language': 'Interface language',
'setup.profile': 'Instance type',
'setup.encrypt': 'Encrypt my conversation history',
'setup.warn': 'your password derives the encryption key. If you forget it, your entire conversation history will be permanently lost — there is no recovery.',
'setup.warn.strong': 'Warning:',
'setup.submit': 'Create account',
'setup.creating': 'Creating…',
'setup.network': 'Network error — please try again.',
// ── Dashboard ───────────────────────────────────────────────────────────────
'dashboard.status.loading': 'Loading…',
'dashboard.status.no_models': 'No LLM models',
'dashboard.status.online': 'Online & ready',
'dashboard.status.degraded': 'Degraded',
'dashboard.status.offline': 'All models offline',
'dashboard.stats.loading': 'Loading stats…',
'dashboard.stats.empty': 'No LLM requests in the selected range.',
'dashboard.stats.requests': 'Requests {per}',
'dashboard.stats.tokens': 'Tokens {per}',
'dashboard.stats.latency': 'Avg latency (ms)',
'dashboard.stats.models': 'Models',
'dashboard.stats.per_min': '/ min',
'dashboard.stats.per_hour': '/ hour',
'dashboard.stats.per_day': '/ day',
'dashboard.stats.range.hour': '1h',
'dashboard.stats.range.day': '24h',
'dashboard.stats.range.week': '7d',
'dashboard.stats.range.month': '30d',
'dashboard.stats.chart.input': 'Input',
'dashboard.stats.chart.output': 'Output',
'dashboard.stats.chart.cached': 'Cached',
'dashboard.stats.chart.non_cached': 'Non-cached',
'dashboard.stats.chart.cache_hit': 'Cache hit: {pct}%',
'dashboard.hero.subtitle': 'Your AI command centre — research, code, plan, and orchestrate. All in one place.',
'dashboard.banner.no_models.title': 'No LLM models configured.',
'dashboard.banner.no_models.desc': 'Start by adding a provider (Anthropic, OpenAI, OpenRouter…), then add at least one model in the Models section.',
'dashboard.banner.no_models.action': 'Add a provider',
'dashboard.section.stats': 'LLM Stats',
'dashboard.section.pending': 'Pending',
'dashboard.section.guide': 'Quick guide',
'dashboard.tip.honcho.title': 'Enable Honcho',
'dashboard.tip.honcho.desc': 'Persistent long-term memory — the agent learns your preferences over time. Ask the Copilot to enable it.',
'dashboard.refresh': 'Refresh',
'dashboard.guide.chat.title': 'Chat',
'dashboard.guide.chat.desc': 'Your home page is a conversation — it knows everything: ask it to run agents, enable plugins, write code, or search the web.',
'dashboard.guide.inbox.title': 'Inbox',
'dashboard.guide.inbox.desc': 'Pending approvals and agent questions that need your input before background tasks can continue.',
'dashboard.guide.agents.title': 'Agents',
'dashboard.guide.agents.desc': 'Specialized sub-agents (engineer, architect, QA…). Each has a focused system prompt, tool set, and model selection.',
'dashboard.guide.cron.title': 'Cron',
'dashboard.guide.cron.desc': 'Scheduled tasks that run automatically at set intervals, even when the Copilot is idle.',
'dashboard.guide.models.title': 'Models',
'dashboard.guide.models.desc': 'Manage LLM, transcription, and image generation models. Drag to reorder priority.',
'dashboard.guide.providers.title': 'Providers',
'dashboard.guide.providers.desc': 'Add API keys for LLM providers (Anthropic, OpenAI, OpenRouter, Ollama…).',
'dashboard.guide.security.title': 'Security',
'dashboard.guide.security.desc': 'Define rules to auto-approve or auto-reject tool calls — skip repetitive confirmation prompts.',
// ── Models (hub + sections) ─────────────────────────────────────────────────
'models.hub.title': 'Models',
'models.hub.subtitle': 'Configure LLM, transcription, and image generation providers.',
'models.hub.count.none': 'No models',
'models.hub.count.one': '1 model',
'models.hub.count.many': '{n} models',
'models.hub.card.llm.title': 'LLM',
'models.hub.card.llm.desc': 'Chat & completion models for agents and tools',
'models.hub.card.transcribe.title': 'Transcription',
'models.hub.card.transcribe.desc': 'Speech-to-text models via cloud or local plugin',
'models.hub.card.image.title': 'Image Generation',
'models.hub.card.image.desc': 'Text-to-image models via cloud API',
'models.hub.card.tts.title': 'Text-to-Speech',
'models.hub.card.tts.desc': 'Speech synthesis models via cloud or local plugin',
'models.back': 'Back to models',
'models.add': 'Add',
'models.add_model': 'Add model',
'models.add_first': 'Add your first model',
'models.edit': 'Edit',
'models.delete': 'Delete',
'models.saving': 'Saving…',
'models.save_changes': 'Save changes',
'models.cancel': 'Cancel',
'models.search': 'Search models…',
'models.loading': 'Loading models…',
'models.no_results': 'No models found',
'models.enter_id': 'Enter model ID manually',
'models.managed_plugin': 'Managed by plugin',
'models.readonly_plugin': 'Models with the <strong>Plugin</strong> badge are read-only — managed automatically by the plugin that registered them.',
'models.readonly_plugin_full': 'Models with the <strong>Plugin</strong> badge are read-only — managed automatically by the plugin that registered them. To add, modify, or remove them, ask the agent directly: it has all the documentation it needs.',
'models.default': 'default',
'models.move_up': 'Move up',
'models.move_down': 'Move down',
'models.strength.very_high': 'Very High',
'models.strength.high': 'High',
'models.strength.average': 'Average',
'models.strength.low': 'Low',
'models.strength.very_low': 'Very Low',
'models.strength.none': '— none —',
'models.reasoning.off': '— off —',
'models.reasoning.label': 'Reasoning',
'models.reasoning.thinking': 'Reasoning (thinking)',
'models.strength': 'Strength',
'models.priority': 'Priority',
'models.scope': 'Scope',
'models.default_model': 'Default model',
'models.extra_params': 'Extra params',
'models.extra_params_hint': '(JSON, optional)',
'models.model_id': 'Model ID',
'models.model_id_hint': '(sent to API)',
'models.model_id_immutable': 'Model ID cannot be changed after creation.',
'models.name_alias': 'Name / Alias',
'models.name_alias_hint': '(optional)',
'models.name_alias_ph': 'same as model ID',
'models.edit_title': 'Edit {name}',
'models.edit_info': 'Model ID and provider cannot be changed. To use a different model, add a new entry.',
'models.name_help': 'Used to reference this model (e.g. in an agent\'s <code>client</code>). Must be unique.',
'models.no_providers_llm': 'Add a <strong>Provider</strong> first, then come back here to add models.',
'models.no_providers_transcribe': 'No provider supports transcription yet. Add an <strong>OpenAI</strong> or <strong>OpenRouter</strong> provider first.',
'models.no_providers_image': 'No provider supports image generation yet. Add an <strong>OpenRouter</strong> provider first.',
'models.no_providers_tts': 'No provider supports TTS yet. Add an <strong>OpenAI</strong> provider first.',
'models.list_empty_llm': 'No models configured yet.',
'models.list_empty_transcribe': 'No transcription models configured.',
'models.list_empty_image': 'No image generation models configured.',
'models.list_empty_tts': 'No TTS models configured.',
'models.list_empty_add_hint': 'Click <strong>Add</strong> to add a cloud model.',
'models.list_empty_whisper': 'Activate the <strong>Whisper Local</strong> plugin for on-device transcription.',
'models.source': 'Source',
'models.source_plugin': 'Plugin',
'models.source_cloud': 'Cloud',
'models.name_col': 'Name',
'models.provider_col': 'Provider',
'models.model_id_col': 'Model ID',
'models.language_col': 'Language',
'models.language_auto': 'auto',
'models.choose_provider': 'Choose Provider',
'models.add_model_title': 'Add Model',
'models.model_label': 'Model',
'models.add_model_provider': 'Add {type} Model — Choose Provider',
'models.add_model_type': 'Add {type} Model',
'models.priority_hint': 'Lower number = tried first. Default: 100.',
'models.priority_hint_short': 'Lower number = used first. Default: 100.',
'models.status_healthy': 'Healthy',
'models.status_degraded': 'Degraded',
'models.status_down': 'Down',
'models.llm.title': 'LLM Models',
'models.transcribe.title': 'Transcription Models',
'models.image.title': 'Image Generation Models',
'models.tts.title': 'Text-to-Speech Models',
'models.confirm_delete': 'Delete {type} model "{name}"?',
'models.error.save_order': 'Failed to save order: {msg}',
'models.error.load_models': 'Failed to load models: {msg}',
'models.error.invalid_json': 'Extra params: invalid JSON',
'models.error.select_model': 'Select a model',
'models.label.sent_to_api': '(sent to API)',
'models.label.optional': '(optional)',
'models.label.bcp47': '(BCP-47, optional)',
'models.label.required_elevenlabs': '(optional — required for ElevenLabs)',
'models.label.shown_to_llm': '(optional — shown to LLM)',
'models.label.response_fmt': 'Response format',
'models.label.response_fmt_hint': '(optional)',
'models.label.description': 'Description',
'models.label.description_hint': '(optional)',
'models.label.instructions': 'Instructions',
'models.label.instructions_hint': '(optional — shown to LLM)',
'models.label.voice_id': 'Voice ID',
'models.label.voice_id_hint': '(optional — required for ElevenLabs)',
'models.label.max_output': 'Max output tokens',
'models.label.max_output_hint': '(optional)',
'models.ph.model_id': 'e.g. gpt-4o',
'models.ph.model_id_transcribe': 'e.g. openai/whisper-1',
'models.ph.model_id_tts': 'e.g. tts-1-hd',
'models.ph.model_id_image': 'e.g. x-ai/grok-2-vision',
'models.ph.name_alias': 'same as model ID',
'models.ph.language': 'e.g. it, en — leave blank for auto-detect',
'models.ph.voice_id': 'e.g. alloy, Kore, 21m00Tcm4TlvDq8ikWAM',
'models.ph.description': 'e.g. High quality, slow — best for long responses',
'models.ph.instructions': 'e.g. Speak in a calm, neutral tone. Pause slightly between sentences.',
'models.ph.max_tokens': 'up to {n}',
'models.form.model_lock': 'Model ID cannot be changed after creation.',
'models.form.voice_hint': 'Speaker voice. OpenAI: <code>alloy</code>/<code>echo</code>/<code>nova</code>… (default <code>alloy</code> if empty); Gemini: <code>Kore</code>/<code>Puck</code>/<code>Zephyr</code>…; ElevenLabs: the voice ID.',
'models.form.instructions_hint': 'Voice/tone guidance injected into the LLM system prompt when this model is active.',
'models.form.response_hint': 'Audio format requested from the provider. Leave empty unless the model requires a specific one — e.g. Gemini TTS only accepts <code>pcm</code>.',
'models.form.response_default': 'Provider default (mp3)',
'models.form.priority_img': 'Lower number = tried first. Default: 100.',
'models.form.name_as_provider': 'Name / Alias <span class="text-muted fw-normal">(used as provider_id in the LLM tool)</span>',
'models.tts.cost_multiplier': 'Cost multiplier relative to base rate',
'models.llm.price_tooltip': 'Input/Output per 1M tokens',
// ── Approval rules ─────────────────────────────────────────────────────────
'approval.action.require': 'Require',
'approval.action.allow': 'Allow',
'approval.action.deny': 'Deny',
'approval.chip.unset': '—',
'approval.chip.req': 'Req',
'approval.category.filesystem': 'File System',
'approval.category.shell': 'Shell',
'approval.category.subagent': 'Agents',
'approval.category.introspection': 'Introspection',
'approval.category.config': 'Config',
'approval.category.dynamic': 'Dynamic',
'approval.fs.allow_read': 'Allow read',
'approval.fs.allow_write': 'Allow write',
'approval.fs.deny': 'Deny',
'approval.fs.require': 'Require',
'approval.fs.default': 'Require (system default)',
'approval.error.enter_path': 'Enter a directory path.',
'approval.error.tool_required': 'Tool pattern is required.',
'approval.error.override_prio': 'Override rules must have priority < 0.',
'approval.error.lowprio_range': 'Low priority rules must have priority between 1 and {max}.',
'approval.tool.any': 'Any tool',
'approval.tool.any_mcp': 'Any MCP tool',
'approval.tool.search': 'Search tools…',
'approval.tool.no_results': 'No results',
'approval.tool.group_builtin': 'Built-in',
'approval.tool.group_glob': 'Glob',
'approval.tool.group_mcp': 'MCP · {server}',
'approval.form.new_override': 'New override rule',
'approval.form.new_lowprio': 'New low priority rule',
'approval.form.edit': 'Edit rule',
'approval.form.tool_pattern': 'Tool pattern',
'approval.form.tool_pattern_ph': 'e.g. mcp__whatsapp__* or execute_cmd',
'approval.form.tool_pattern_hint': 'Use <code>*</code> as a trailing wildcard, e.g. <code>mcp__whatsapp__*</code>',
'approval.form.select_tool': 'Select tool',
'approval.form.path_pattern': 'Path pattern',
'approval.form.path_pattern_ph': 'e.g. data/* or data/notes/*',
'approval.form.path_pattern_hint': 'Filter by file path. Use <code>*</code> as a wildcard.',
'approval.form.action': 'Action',
'approval.form.priority': 'Priority',
'approval.form.priority_override_hint': 'Must be <strong>&lt; 0</strong> (e.g. 10)',
'approval.form.priority_lowprio_hint': 'Must be <strong>1 {max}</strong>',
'approval.form.source': 'Source',
'approval.form.source_any': 'Any',
'approval.form.agent_id': 'Agent ID',
'approval.form.agent_id_ph': 'main (empty = any)',
'approval.form.note': 'Note',
'approval.form.note_ph': 'Short description…',
'approval.form.cancel': 'Cancel',
'approval.form.saving': 'Saving…',
'approval.form.save': 'Save',
'approval.card.priority': 'Priority',
'approval.card.edit': 'Edit',
'approval.card.delete': 'Delete',
'approval.card.remove': 'Remove',
'approval.matrix.title': 'Per-tool',
'approval.matrix.subtitle': 'priority = 0 · exact tool name · no path/source filters',
'approval.matrix.loading': 'Loading tools…',
'approval.fs.title': 'File System',
'approval.fs.subtitle': 'path-scoped read / write access',
'approval.fs.empty': 'No path rules yet — add one below.',
'approval.fs.add_ph': 'Add directory path, e.g. docs',
'approval.fs.default_label': 'Default',
'approval.fs.default_hint': 'unmatched paths',
'approval.sidebar.overrides': 'Overrides',
'approval.sidebar.overrides_sub': 'priority < 0 · evaluated first',
'approval.sidebar.lowprio': 'Low Priority',
'approval.sidebar.lowprio_sub': 'priority 1999998 · evaluated after per-tool',
'approval.sidebar.add': 'Add',
'approval.sidebar.empty': 'No rules yet.',
'approval.default_bar.title': 'Default action',
'approval.default_bar.hint': 'if no rule matches',
'approval.default_bar.unset': 'system default: allow',
'approval.header.default_badge': 'Default',
'approval.header.rule_count': '{n} rule',
'approval.header.rule_count_plural': '{n} rules',
'approval.confirm.delete_fs': 'Remove File System rule for "{path}"?',
'approval.confirm.delete_rule': 'Delete rule for "{pattern}"?',
'approval.label.optional': '(optional)',
// ── Security (groups) ───────────────────────────────────────────────────────
'security.title': 'Security',
'security.group_count': '{n} group',
'security.group_count_plural': '{n} groups',
'security.new_group': 'New group',
'security.rename_group': 'Rename group',
'security.duplicate': 'Duplicate',
'security.duplicate_title': 'Duplicate {name}',
'security.duplicating': 'Duplicating…',
'security.create_first': 'Create first group',
'security.form.id': 'ID',
'security.form.id_ph': 'e.g. cron_strict',
'security.form.id_hint': 'Lowercase slug, no spaces. Cannot be changed later.',
'security.form.name': 'Name',
'security.form.name_ph': 'e.g. Cron strict',
'security.form.description': 'Description',
'security.form.description_ph': 'Short description…',
'security.form.new_name': 'New name',
'security.form.new_id': 'New ID',
'security.form.copy_info': 'All <strong>{n}</strong> rule{s} from <em>{name}</em> will be copied.',
'security.form.cancel': 'Cancel',
'security.form.saving': 'Saving…',
'security.form.save': 'Save',
'security.card.default_badge': 'Default',
'security.card.rule_count': '{n} rule',
'security.card.rule_count_plural': '{n} rules',
'security.card.duplicate': 'Duplicate',
'security.card.rename': 'Rename',
'security.card.delete_disabled': 'Cannot delete the default group',
'security.card.delete': 'Delete group',
'security.confirm.delete': 'Delete group "{name}"?',
'security.confirm.delete_with_rules': 'Delete group "{name}" and its {n} rule{s}?',
'security.banner.text1': '<strong>Permission groups</strong> are named sets of approval rules. A session\'s active <strong>Agent Profile</strong> determines which group applies — that group\'s rules are evaluated first, with the <strong>Default</strong> group as fallback.',
'security.banner.text2': 'Click a group to view and manage its rules. The <strong>Default</strong> group cannot be deleted, but its rules can be edited freely.',
'security.empty.title': 'No groups yet.',
'security.error.name_required': 'Name is required.',
'security.error.id_required': 'ID is required.',
'security.error.group_name_required': 'Group name is required.',
'security.error.group_id_required': 'Group ID is required.',
// ── Roles ───────────────────────────────────────────────────────────────────
'roles.title': 'Roles',
'roles.count': '{n} role',
'roles.count_plural': '{n} roles',
'roles.new_role': 'New role',
'roles.loading': 'Loading…',
'roles.empty': 'No roles.',
'roles.col.id': 'ID',
'roles.col.label': 'Label',
'roles.col.group': 'Permission group',
'roles.col.interface': 'Interface',
'roles.badge.simple': 'Simple',
'roles.badge.full': 'Full',
'roles.form.new': 'New role',
'roles.form.edit': 'Edit {name}',
'roles.form.id': 'ID',
'roles.form.id_hint': '(slug)',
'roles.form.id_ph': 'e.g. editor',
'roles.form.id_desc': 'Lowercase, no spaces. Cannot be changed later.',
'roles.form.label': 'Label',
'roles.form.group': 'Default security group',
'roles.form.allowed': 'Additional security groups',
'roles.form.allowed_hint': 'Groups this role may also switch to at runtime, on top of the default. Users pick from these in chat.',
'roles.form.interface': 'Interface',
'roles.form.interface_full': 'Full — all pages',
'roles.form.interface_simple': 'Simple — chat only',
'roles.form.interface_hint': 'Members with the simple interface see only chat and inbox. Stored as <code>ui_mode</code> in the attrs JSON below.',
'roles.form.attrs': 'Attrs',
'roles.form.attrs_hint': '(JSON, optional)',
'roles.form.attrs_ph': '{}',
'roles.form.cancel': 'Cancel',
'roles.form.create': 'Create',
'roles.form.save': 'Save',
'roles.error.id_label': 'ID and label are required.',
'roles.error.label': 'Label is required.',
'roles.tooltip.locked': 'Built-in role — locked',
'roles.tooltip.edit': 'Edit',
'roles.tooltip.delete': 'Delete',
'roles.confirm.delete': 'Delete role "{name}"?',
// ── Agents ──────────────────────────────────────────────────────────────────
'agents.title': 'Agents',
'agents.loading': 'Loading…',
'agents.empty': 'No agents found.',
'agents.back': 'Agents',
'agents.section.chat': 'Chat',
'agents.section.task': 'Task Executors',
'agents.section.system': 'System',
'agents.strength.very_high': 'Very High',
'agents.strength.high': 'High',
'agents.strength.average': 'Average',
'agents.strength.low': 'Low',
'agents.strength.very_low': 'Very Low',
'agents.detail.meta': 'Metadata',
'agents.detail.id': 'ID',
'agents.detail.strength': 'Strength',
'agents.detail.scope': 'Scope',
'agents.detail.pinned_model': 'Pinned model',
'agents.detail.memory_files': 'Memory files',
'agents.detail.model_order': 'Model resolution order',
'agents.detail.model_order_desc': 'Models sorted by how well they match this agent\'s requirements. The system uses the first available model from the top.',
'agents.detail.no_models': 'No models configured.',
'agents.detail.prompt': 'System prompt',
'agents.detail.default': 'default',
'agents.table.rank': '#',
'agents.table.strength': 'Strength',
'agents.table.name': 'Name',
'agents.table.model_id': 'Model ID',
'agents.table.scope': 'Scope',
'agents.banner.title': '<strong>Read-only view.</strong> Agents are defined by files in <code>agents/</code> — to add, remove, or modify an agent, edit the corresponding <code>AGENT.md</code> file in that directory.',
'agents.banner.text': 'You can also ask <strong>Copilot</strong> (top bar) to create a new agent for you — just describe what it should do and it will set up all the files automatically.',
// ── Connectors ──────────────────────────────────────────────────────────────
'connectors.title': 'Connectors',
'connectors.loading': 'Loading…',
'connectors.search': 'Search connectors…',
'connectors.btn.signin_providers': 'Sign-in providers',
'connectors.btn.catalog': 'Catalog',
'connectors.btn.marketplace': 'Marketplace',
'connectors.empty.installed': 'No connectors installed yet.',
'connectors.empty.available': 'Nothing available to you yet.',
'connectors.empty.install_hint': 'Install one from the Marketplace to get started.',
'connectors.empty.ask_admin': 'Ask an admin to make one available.',
'connectors.empty.match': 'No connector matches "{query}".',
'connectors.chip.global': 'global',
'connectors.chip.per_user': 'per-user',
'connectors.chip.local_script': 'local script',
'connectors.status.active': 'active',
'connectors.status.needs_fix': 'needs fix',
'connectors.status.needs_signin': 'needs sign-in',
'connectors.status.enabled': 'enabled',
'connectors.status.off': 'off',
'connectors.status.available': 'available',
'connectors.providers.title': 'Sign-in providers',
'connectors.providers.desc': 'OAuth apps that per-user connectors sign in through. One app (e.g. Google) covers all of its services. The client secret is stored on this box and never shown again.',
'connectors.providers.empty': 'No sign-in providers yet.',
'connectors.providers.secret_set': 'secret set',
'connectors.providers.no_secret': 'no secret',
'connectors.providers.no_client_id': '(no client id)',
'connectors.providers.add_google': 'Add Google',
'connectors.providers.add_other': 'Add other',
'connectors.providers.save': 'Save',
'connectors.providers.cancel': 'Cancel',
'connectors.providers.delete_confirm': 'Delete the "{name}" sign-in provider?\n\nConnectors that use it will no longer be able to sign in.',
'connectors.providers.error.name_client': 'Name and client id are required.',
'connectors.providers.error.secret': 'A client secret is required for a new provider.',
'connectors.providers.field.name': 'Provider id',
'connectors.providers.field.name_help': 'The slug a connector references (must match the manifest\'s auth.provider).',
'connectors.providers.field.display': 'Display name',
'connectors.providers.field.client_id': 'Client id',
'connectors.providers.field.client_secret': 'Client secret',
'connectors.providers.field.secret_help_new': 'Required.',
'connectors.providers.field.secret_help_edit': 'Leave blank to keep the stored secret.',
'connectors.providers.field.auth_url': 'Authorization URL',
'connectors.providers.field.token_url': 'Token URL',
'connectors.providers.field.redirect': 'Redirect URI',
'connectors.providers.field.redirect_help': 'The copy-paste page. Must be registered as an authorized redirect in the provider\'s console.',
'connectors.providers.field.extra': 'Extra params (JSON)',
'connectors.providers.field.extra_help': 'Merged into the consent URL. Google needs these two to return a refresh token.',
'connectors.detail.back': 'Back',
'connectors.detail.global_note': 'Runs once for the household, on the host. Nobody reaches it until they are granted access.',
'connectors.detail.managed.title': 'This connector is managed for you.',
'connectors.detail.managed.desc': 'It is enabled by an admin and granted to you — there is nothing to configure.',
'connectors.detail.config.title_active': 'Configuration',
'connectors.detail.config.title_setup': 'Set up',
'connectors.detail.config.already_global': 'Already enabled. Re-submitting replaces the stored credentials.',
'connectors.detail.config.already_user': 'Already active. Re-submitting replaces the stored credentials.',
'connectors.detail.config.api_key': 'API key',
'connectors.detail.config.btn_test': 'Test credentials',
'connectors.detail.config.btn_testing': 'Testing…',
'connectors.detail.config.btn_enable_global': 'Enable globally',
'connectors.detail.config.btn_save_restart': 'Save & restart',
'connectors.detail.config.btn_disable': 'Disable',
'connectors.detail.config.btn_activate': 'Activate',
'connectors.detail.config.btn_deactivate': 'Deactivate',
'connectors.detail.detail_scope_global': 'global',
'connectors.detail.scope_local': 'runs code on this box',
'connectors.detail.status.active': 'active',
'connectors.detail.status.needs_fix': 'needs fixing',
'connectors.detail.status.needs_signin': 'needs sign-in',
'connectors.detail.confirm.deactivate': 'Deactivate "{name}"?',
'connectors.detail.confirm.disable_global': 'Disable "{name}"?\n\nIt stops for everyone who can use it.',
'connectors.detail.oauth.title': 'Sign in',
'connectors.detail.oauth.desc': 'Signs in with {provider}. You approve access in a browser tab, then paste back the code the page shows you — nothing is stored on this box until you do.',
'connectors.detail.oauth.scopes': 'It will request access to:',
'connectors.detail.oauth.signed_in': 'Signed in and active.',
'connectors.detail.oauth.btn_signin': 'Sign in with {provider}',
'connectors.detail.oauth.btn_signin_again':'Sign in again',
'connectors.detail.oauth.btn_finish': 'Finish sign-in',
'connectors.detail.oauth.btn_complete': 'Complete sign-in',
'connectors.detail.oauth.step1': 'A tab opened for {provider}. Approve access there.',
'connectors.detail.oauth.step1_link': 'Re-open the sign-in page',
'connectors.detail.oauth.step2': 'Paste the code the page gave you:',
'connectors.detail.oauth.cancel': 'Cancel',
'connectors.detail.oauth.deactivate': 'Deactivate',
'connectors.detail.qr.title': 'Link your phone',
'connectors.detail.qr.desc': 'Scan a QR code with your phone to link this device. The session stays on this box — no password is stored.',
'connectors.detail.qr.connected': 'Connected and active.',
'connectors.detail.qr.scan': 'Scan this code with your phone:',
'connectors.detail.qr.hint': 'WhatsApp → Settings → Linked Devices → Link a Device.',
'connectors.detail.qr.connecting': 'Connecting…',
'connectors.detail.qr.btn_start': 'Start sign-in',
'connectors.detail.qr.btn_starting': 'Preparing… (this can take a minute the first time)',
'connectors.detail.qr.btn_relink': 'Re-link (new QR)',
'connectors.detail.test.running': 'Testing credentials…',
'connectors.detail.test.skipped': 'No verification step for this connector.',
'connectors.detail.test.ok_label': 'OK',
'connectors.detail.test.fail_label': 'Failed',
'connectors.detail.test.error_saved': 'Saved, but the credentials did not check out — fix them and test again.',
'connectors.detail.test.error_verify': 'Verification failed — the connector stays disabled until the credentials are fixed.',
'connectors.detail.access.title': 'Who can use it',
'connectors.detail.access.desc': 'Ticking a box grants this connector\'s tools to that person\'s agent. Saving replaces the whole list.',
'connectors.detail.access.empty': 'No users.',
'connectors.detail.access.save': 'Save access',
'connectors.error.no_connector': 'No connector named "{name}" is available to you.',
// ── Plugins ─────────────────────────────────────────────────────────────────
'plugins.title': 'Plugins',
'plugins.loading': 'Loading…',
'plugins.section.mine': 'My plugins',
'plugins.section.manage': 'Manage plugins',
'plugins.empty.mine': 'No plugins available to you yet.',
'plugins.empty.ask_admin': 'Ask an admin to grant you access.',
'plugins.empty.manage': 'No plugins registered.',
'plugins.status.active': 'active',
'plugins.status.running': 'running',
'plugins.status.enabled': 'enabled',
'plugins.status.off': 'off',
'plugins.enabled': 'Enabled',
'plugins.save': 'Save',
'plugins.save_config': 'Save config',
'plugins.saved': 'Saved.',
'plugin_page.loading': 'Loading…',
'plugin_page.unavailable': 'This page is not available (plugin disabled or page not granted).',
'plugins.yes': 'yes',
'plugins.no': 'no',
'plugins.badge.user_config': 'per-user settings',
'plugins.access.btn': 'User access',
'plugins.access.desc': 'Tick a box to let that person see and configure this plugin. Saving replaces the whole list.',
'plugins.access.empty': 'No users.',
'plugins.access.save': 'Save access',
'plugins.error.required': '"{field}" is required.',
'plugins.catalog.title': 'Plugin Catalog',
'plugins.catalog.configure': 'Configure',
'plugins.health.ok': 'active',
'plugins.health.off': 'off',
'plugins.health.needs_config': 'needs configuration',
'plugins.health.not_running': 'not running',
'plugins.badge.instance_config': 'instance settings',
'plugins.detail.back': 'Back to catalog',
'plugins.detail.config.title': 'Instance configuration',
'plugins.detail.config.empty': 'This plugin has no instance settings.',
'plugins.detail.access.title': 'User access',
'plugins.detail.not_found': 'No plugin named "{id}".',
// ── Providers ───────────────────────────────────────────────────────────────
'providers.title': 'Providers',
'providers.add': 'Add',
'providers.add_first': 'Add your first provider',
'providers.empty': 'No providers configured yet.',
'providers.count': '{n}',
'providers.card.models_title': 'Models using this provider',
'providers.card.api_key_configured': 'API key configured',
'providers.card.api_key_missing': 'API key missing',
'providers.card.edit': 'Edit',
'providers.card.delete': 'Delete',
'providers.card.base_url': 'Base URL',
'providers.modal.add': 'Add Provider',
'providers.modal.edit': 'Edit Provider',
'providers.modal.name': 'Name',
'providers.modal.name_ph': 'e.g. My Anthropic',
'providers.modal.type': 'Type',
'providers.modal.api_key': 'API Key',
'providers.modal.api_key_ph': 'Leave blank to keep existing key',
'providers.modal.base_url': 'Base URL',
'providers.modal.base_url_ollama': 'http://localhost:11434',
'providers.modal.base_url_oai': 'http://localhost:1234/v1',
'providers.modal.description': 'Description',
'providers.modal.description_optional': '(optional)',
'providers.modal.cancel': 'Cancel',
'providers.modal.saving': 'Saving…',
'providers.modal.save_changes': 'Save changes',
'providers.modal.add_provider': 'Add provider',
'providers.confirm.delete': 'Delete provider "{name}"? All associated models will be deleted too.',
// ── TIC Sessions ────────────────────────────────────────────────────────────
'tic.title': 'TIC Sessions',
'tic.loading': 'Loading…',
'tic.empty': 'No TIC sessions found.',
'tic.total': '{n} total',
'tic.refresh': 'Refresh',
'tic.table.agent': 'Agent',
'tic.table.started': 'Started',
'tic.table.messages': 'Messages',
'tic.table.last_activity':'Last activity',
'tic.pagination': 'Page {cur} of {pages} — {total} sessions',
// ── File viewer ─────────────────────────────────────────────────────────────
'fv.back': 'Back',
'fv.download': 'Download',
'fv.mode_preview': 'Show preview',
'fv.mode_source': 'Show source',
'fv.binary_unavailable': 'Preview not available for this file type.',
'fv.latex_failed': 'LaTeX compilation failed — showing source instead',
// ── Marketplace ─────────────────────────────────────────────────────────────
'marketplace.title': 'Marketplace',
'marketplace.btn.catalog': 'Catalog',
'marketplace.action.refetch': 'Refetch the feed',
'marketplace.not_admin': 'The marketplace is managed by the admin.',
'marketplace.not_admin_link': 'Connectors the admin has installed appear on the <a href="#connectors">Connectors</a> page.',
'marketplace.desc': 'Vetted connectors you can add to this box\'s catalog. Installing does not activate anything — it makes a connector <em>available</em>.',
'marketplace.feed_unreachable': 'Marketplace unreachable — {error}',
'marketplace.loading': 'Loading feed…',
'marketplace.filter.search': 'Search connectors…',
'marketplace.filter.scope': 'Scope',
'marketplace.filter.type': 'Type',
'marketplace.filter.all': 'All',
'marketplace.filter.global': 'Global',
'marketplace.filter.per_user': 'Per-user',
'marketplace.filter.remote': 'Remote',
'marketplace.filter.local': 'Local',
'marketplace.grid.empty_feed': 'The feed is empty.',
'marketplace.grid.no_match': 'No connector matches these filters.',
'marketplace.card.installed': 'installed',
'marketplace.card.update_available': 'update available',
'marketplace.card.installed_version': 'installed v{v}',
'marketplace.card.update': 'Update',
'marketplace.card.scope_global': 'global',
'marketplace.card.scope_per_user': 'per-user',
'marketplace.card.type_script': 'local script',
'marketplace.card.type_remote': 'remote',
'marketplace.card.files_one': '{n} file, SHA-256 verified on install',
'marketplace.card.files_other': '{n} files, SHA-256 verified on install',
'marketplace.card.oauth_scopes_one': 'Requests {n} OAuth scope',
'marketplace.card.oauth_scopes_other': 'Requests {n} OAuth scopes',
'marketplace.card.installing': 'Installing…',
'marketplace.card.reinstall': 'Reinstall',
'marketplace.card.install': 'Install',
'marketplace.card.homepage': 'Homepage',
'marketplace.confirm.install_warn': 'This puts code on this box:\n • {n} file(s), each verified against its SHA-256\n • installed into ./connectors/{id}/',
'marketplace.confirm.install_body':'Install "{name}" into the catalog?\n\nInstalling does not activate it.',
// ── Users ───────────────────────────────────────────────────────────────────
'users.title': 'Users',
'users.loading': 'Loading…',
'users.empty': 'No users.',
'users.count_one': '{n} user',
'users.count_other': '{n} users',
'users.btn.new': 'New user',
'users.table.username': 'Username',
'users.table.display_name': 'Display name',
'users.table.role': 'Role',
'users.table.db': 'DB',
'users.table.status': 'Status',
'users.badge.encrypted': 'Encrypted',
'users.badge.cleartext': 'Cleartext',
'users.badge.active': 'Active',
'users.badge.inactive': 'Inactive',
'users.action.reset_pw': 'Reset password',
'users.action.edit': 'Edit',
'users.action.delete': 'Delete',
'users.modal.create_title': 'New user',
'users.modal.edit_title': 'Edit {username}',
'users.modal.reset_title': 'Reset password — {username}',
'users.modal.username': 'Username',
'users.modal.display_name': 'Display name',
'users.modal.optional': '(optional)',
'users.modal.role': 'Role',
'users.modal.birthdate': 'Date of birth',
'users.modal.sex': 'Sex',
'users.modal.notes': 'Notes',
'users.modal.notes_hint': 'Included in the profile shown to agents.',
'users.modal.password': 'Password',
'users.modal.new_password': 'New password',
'users.modal.encrypt': 'Encrypt conversation history',
'users.modal.encrypt_warn': '<strong>Warning:</strong> if the password is lost, the conversation history is permanently unrecoverable.',
'users.modal.active': 'Active',
'users.modal.only_cleartext': 'Only works for cleartext (non-encrypted) users.',
'users.modal.cancel': 'Cancel',
'users.modal.create_btn': 'Create',
'users.modal.save_btn': 'Save',
'users.modal.reset_btn': 'Reset',
'users.error.required_username_pw': 'Username and password are required.',
'users.error.required_username': 'Username is required.',
'users.error.password_empty': 'Password must not be empty.',
'users.confirm.delete': 'Delete user "{username}"? This permanently erases their database and all conversation history.',
// ── Catalog ─────────────────────────────────────────────────────────────────
'catalog.title': 'Connector Catalog',
'catalog.loading': 'Loading…',
'catalog.not_admin': 'The catalog is managed by the admin.',
'catalog.not_admin_link': 'What you can activate is on the <a href="#connectors">Connectors</a> page.',
'catalog.desc': 'What this box offers. Nothing here is running — a global entry still needs enabling, a per-user one still needs each user to activate it, both on the <a href="#connectors">Connectors</a> page.',
'catalog.empty.title': 'The catalog is empty.',
'catalog.empty.hint': 'Add a connector from the marketplace to get started.',
'catalog.empty.action': 'Browse the marketplace',
'catalog.btn.add': 'Add connector',
'catalog.dropdown.marketplace': 'From the marketplace',
'catalog.dropdown.marketplace_desc': 'Vetted connectors, files verified by SHA-256.',
'catalog.dropdown.manual': 'Manually',
'catalog.dropdown.manual_desc': 'You supply the config, and vouch for it yourself.',
'catalog.table.connector': 'Connector',
'catalog.table.scope': 'Scope',
'catalog.table.type': 'Type',
'catalog.table.auth': 'Auth',
'catalog.badge.global': 'global',
'catalog.badge.per_user': 'per-user',
'catalog.badge.local_script':'local script',
'catalog.badge.remote': 'remote',
'catalog.action.remove': 'Remove from catalog',
'catalog.new.back': 'Back',
'catalog.new.title': 'Add connector manually',
'catalog.new.script_warn': '<i class="bi bi-exclamation-triangle me-1"></i>A local script runs code on this box. Nothing verifies it — unlike the marketplace path, there is no digest to check.',
'catalog.new.name': 'Name',
'catalog.new.name_hint': 'slug',
'catalog.new.scope': 'Scope',
'catalog.new.type': 'Type',
'catalog.new.transport': 'Transport',
'catalog.new.command': 'Command',
'catalog.new.command_ph': 'python3',
'catalog.new.script_path': 'Script path',
'catalog.new.script_path_hint': 'as <connector>/<file>, under ./connectors',
'catalog.new.url': 'URL',
'catalog.new.args': 'Args',
'catalog.new.args_hint': 'one per line',
'catalog.new.config_schema': 'Required secret/env keys',
'catalog.new.config_schema_hint': 'comma/newline',
'catalog.new.auth': 'Auth',
'catalog.new.friendly': 'Friendly name',
'catalog.new.desc': 'Description',
'catalog.new.desc_hint': 'the LLM reads this when deciding to activate the connector',
'catalog.new.cancel': 'Cancel',
'catalog.new.save': 'Add to catalog',
'catalog.error.name': 'Name is required.',
'catalog.confirm.delete': 'Remove "{name}" from the catalog?\n\nAnything already activated from it keeps running.',
// ── Cron ────────────────────────────────────────────────────────────────────
'cron.title': 'Cron Jobs',
'cron.count_one': '{n} job',
'cron.count_other': '{n} jobs',
'cron.empty.title': 'No recurring cron jobs.',
'cron.empty.hint': 'Ask the agent to create one with <code>execute_task</code>.',
'cron.badge.running': 'running',
'cron.badge.disabled': 'disabled',
'cron.badge.idle': 'idle',
'cron.action.delete': 'Delete',
'cron.card.label_agent': 'Agent',
'cron.card.label_last_run': 'Last run',
'cron.card.label_next_run': 'Next run',
'cron.card.enabled': 'Enabled',
'cron.card.disabled': 'Disabled',
'cron.confirm.delete': 'Delete job "{title}"?',
// ── Common ─────────────────────────────────────────────────────────────────
'common.save': 'Save',
'common.saving': 'Saving…',
'common.cancel': 'Cancel',
'common.loading': 'Loading…',
'common.saved': 'Saved',
// ── Shared Folders (blueprint §6) ────────────────────────────────────────────
'nav.shared_folders': 'Shared Folders',
'sf.title': 'Shared Folders',
'sf.count': '{n} folder',
'sf.count_plural': '{n} folders',
'sf.new': 'New folder',
'sf.loading': 'Loading…',
'sf.empty': 'No shared folders yet.',
'sf.empty_hint': 'Create one to share files with other members.',
'sf.note.propagation': 'Adding or removing a member is applied to their workspace right away.',
'sf.members': 'Members',
'sf.no_members': 'No members yet — only you (admin) can reach this folder.',
'sf.no_desc': 'No description yet — add one so the assistant knows what to keep here.',
'sf.all_added': 'Everyone available is already a member.',
'sf.choose_user': 'Choose a member…',
'sf.add': 'Add',
'sf.remove': 'Remove',
'sf.edit_desc': 'Edit description',
'sf.delete': 'Delete',
'sf.access.label': 'Access',
'sf.access.read': 'Read',
'sf.access.write': 'Write',
'sf.access.readonly': 'Read only',
'sf.access.readwrite': 'Read & write',
'sf.confirm.delete': 'Delete the shared folder “{name}”?\n\nMembers lose access. The files on disk are left untouched.',
'sf.confirm.remove_member': 'Remove {name} from “{folder}”?',
'sf.error.name': 'A folder name is required.',
'sf.form.new': 'New shared folder',
'sf.form.edit': 'Edit “{name}”',
'sf.form.name': 'Folder name',
'sf.form.name_hint': '(letters, numbers, dashes — no slashes)',
'sf.form.name_ph': 'documents',
'sf.form.name_desc': 'Becomes shared/<name> in every members workspace. It cant be renamed later.',
'sf.form.desc': 'Whats it for?',
'sf.form.desc_desc': 'The assistant reads this to decide what to store here and when to look. Write it as instructions to the assistant.',
'sf.form.desc_ph': 'Household bills, contracts and warranties. Save utility PDFs and deadlines here; check here when asked about an invoice or a warranty.',
'sf.form.create': 'Create',
'sf.form.save': 'Save',
'sf.form.cancel': 'Cancel',
};