/* ═══════════════════════════════════════════════ Crank — i18n Reads `crank_lang` from localStorage ('en'|'ru') ═══════════════════════════════════════════════ */ var TRANSLATIONS = { en: { // Nav 'nav.operations': 'Operations', 'nav.agents': 'Agents', 'nav.apikeys': 'API Keys', 'nav.secrets': 'Secrets', 'nav.logs': 'Logs', 'nav.usage': 'Usage', 'nav.settings': 'Settings', 'nav.logout': 'Log out', 'nav.workspaces': 'Your workspaces', 'nav.menu': 'Menu', 'nav.account': 'Account', 'nav.user_fallback': 'Crank', 'nav.workspace_fallback': 'workspace', 'onboarding.title': 'Getting Started', 'onboarding.subtitle': 'A resumable path to your first real MCP tool call.', 'onboarding.loading': 'Checking authoritative progress…', 'onboarding.progress': '{count}/7 steps complete', 'onboarding.error': 'Getting Started progress is unavailable.', 'onboarding.retry': 'Retry', 'onboarding.refresh': 'Refresh progress', 'onboarding.dismiss': 'Dismiss', 'onboarding.resume': 'Resume Getting Started', 'onboarding.collapse': 'Collapse Getting Started checklist', 'onboarding.request_id': 'Request ID', 'onboarding.trace_id': 'Trace ID', 'onboarding.error_code': 'Error code', 'onboarding.progress_label': 'Getting Started progress', 'onboarding.action_needed': 'This is the next actionable step.', 'onboarding.regressed': 'The referenced object changed. Review and continue again.', 'onboarding.completed': 'Your first public MCP tool call is complete.', 'onboarding.open_invocation': 'Open invocation history', 'onboarding.tool': 'Tool', 'onboarding.timestamp': 'Timestamp', 'onboarding.deep_link_stale': 'This onboarding link references a changed Operation or Agent. Reset it and reselect the current published revision.', 'onboarding.reselect': 'Reset and reselect', 'onboarding.step.operation': 'Create an Operation', 'onboarding.step.test': 'Test the Operation', 'onboarding.step.publish_operation': 'Publish the Operation', 'onboarding.step.agent': 'Create and publish an Agent', 'onboarding.step.key': 'Create an MCP client key', 'onboarding.step.mcp_connection': 'Connect an MCP client', 'onboarding.step.first_call': 'Make the first tool call', 'onboarding.action.operation': 'Create Operation', 'onboarding.action.test': 'Open test', 'onboarding.action.publish_operation': 'Open publication', 'onboarding.action.agent': 'Create Agent', 'onboarding.action.key': 'Create key', 'onboarding.action.mcp_connection': 'Show connection', 'onboarding.action.first_call': 'Open Logs', // Operations page 'ops.title': 'Operations', 'ops.subtitle': 'Catalog of tools. List of created MCP tools for API endpoints.', 'ops.new': 'New operation', 'ops.loading': 'Loading operations…', 'ops.empty.title': 'No operations found', 'ops.empty.sub': 'Try adjusting your search or filters.', 'ops.empty.initial.title': 'No operations yet', 'ops.empty.initial.sub': 'Create the first operation in this workspace to expose a live MCP tool.', 'ops.error.title': 'Backend connection failed', 'ops.delete.confirm': 'Delete this operation? This cannot be undone.', 'ops.delete.success.title': 'Operation deleted', 'ops.delete.success.message': '{name} was deleted.', 'ops.delete.error.title': 'Delete failed', 'ops.delete.error.message': 'Failed to delete operation', 'ops.action.edit': 'Edit operation', 'ops.action.delete':'Delete operation', 'ops.action.archive': 'Archive operation', 'ops.archive.confirm': 'Archive this operation? Existing published Agent snapshots remain available, but new publications and bindings will be blocked.', 'ops.archive.success.title': 'Operation archived', 'ops.archive.success.message': '{name} was archived.', 'ops.archive.error.title': 'Archive failed', 'ops.archive.error.message': 'Failed to archive operation', 'ops.stats.synced': 'Catalog synced with backend', 'ops.stats.none': 'No operations yet', 'ops.stats.share': '{value}% of total', 'ops.stats.no_published': 'No published tools yet', 'ops.stats.requests_rollup': 'Summed from operation usage', 'ops.stats.no_traffic': 'No traffic recorded today', 'ops.stats.latency_weighted': "Weighted by today's calls", 'ops.stats.latency_waiting': 'Waiting for runtime samples', 'ops.results': 'Showing {shown} of {total}', 'ops.range': 'Showing {from}–{to} of {total} operations', 'ops.filter.category': 'Category: {value}', 'ops.filter.agent': 'Agent: {value}', 'ops.no_active_agents': 'No active agents', // Stats 'stats.total': 'Total operations', 'stats.active': 'Active', 'stats.requests': 'Requests today', 'stats.latency': 'Avg. latency', // Tabs 'tab.all': 'All', 'tab.active': 'Active', 'tab.draft': 'Draft', 'tab.error': 'Error', 'tab.inactive': 'Inactive', // Filters & sort 'filter.search': 'Search operations...', 'filter.status': 'Status', 'filter.category': 'Category', 'filter.agent': 'Agent', 'filter.showing': 'Showing', 'filter.of': 'of', 'filter.clear': 'Clear filter', 'filter.clear_all': 'Clear all', 'filter.remove': 'Remove filter', 'sort.created_desc':'Sort: Last created', 'sort.created_asc': 'Sort: Oldest first', 'sort.name_asc': 'Sort: Name A–Z', 'sort.name_desc': 'Sort: Name Z–A', // Table headers 'th.name': 'NAME', 'th.protocol': 'PROTOCOL', 'th.status': 'STATUS', 'th.created': 'CREATED', 'th.url': 'TARGET URL', // Pagination 'page.showing': 'Showing', 'page.of': 'of', 'page.ops': 'operations', // API Keys page 'apikeys.title': 'Agent Keys', 'apikeys.subtitle': 'These keys connect an MCP client to the MCP server and are issued for a specific agent.', 'apikeys.new': 'Create key', 'apikeys.new_mcp': 'Create MCP client key', 'apikeys.new_approval': 'Create approval key', 'apikeys.kind.mcp': 'MCP clients', 'apikeys.kind.approval': 'Approvals', 'apikeys.kind.mcp_hint': 'MCP client keys connect an agent to tools/list and tools/call.', 'apikeys.kind.approval_hint': 'Approval keys are used only by an external human confirmation interface.', 'apikeys.agent.title': 'Agent selection', 'apikeys.agent.subtitle': 'Select the AI agent this key is issued for.', 'apikeys.agent.label': 'AI agent', 'apikeys.agent.empty': 'No agents available', 'apikeys.agent.empty_hint': 'Create an AI agent first, then issue machine access keys for its MCP endpoint.', 'apikeys.agent.endpoint': 'MCP endpoint: {endpoint}', 'apikeys.agent.endpoint_missing': 'The selected agent does not have a published MCP endpoint yet.', 'apikeys.th.name': 'NAME', 'apikeys.th.scope': 'ACCESS', 'apikeys.th.created':'CREATED', 'apikeys.th.last': 'LAST USED', 'apikeys.callout.title': 'Keys are only shown once.', 'apikeys.callout.body': 'Copy and store it securely right after creation — Crank stores only a hash. Last used updates after a successful MCP call.', 'apikeys.active.title': 'Active keys', 'apikeys.active.subtitle': '{active} active · {revoked} revoked', 'apikeys.search': 'Filter keys…', 'apikeys.th.prefix': 'KEY PREFIX', 'apikeys.th.scopes': 'ACCESS', 'apikeys.th.status': 'STATUS', 'apikeys.scope_ref': 'Access reference', 'apikeys.scope.read': 'Initialize MCP sessions, ping the server, and list tools for the selected AI agent.', 'apikeys.scope.write': 'Execute `tools/call` requests against published agent toolsets.', 'apikeys.scope.deploy': 'Reserved for deploy-scoped automation. Today it also permits MCP read/write flows.', 'apikeys.scope.approve': 'Confirm a pending human approval request for this agent.', 'apikeys.scope.deny': 'Reject a pending human approval request for this agent.', 'apikeys.scope.read_pending': 'Read pending human approval requests for this agent.', 'apikeys.modal.title': 'Create agent key', 'apikeys.modal.title_mcp': 'Create MCP client key', 'apikeys.modal.title_approval': 'Create approval key', 'apikeys.modal.name': 'Key name', 'apikeys.modal.name_hint': 'A descriptive label to identify the key. Only visible to admins.', 'apikeys.modal.name_placeholder': 'e.g. Production, CI pipeline', 'apikeys.modal.scopes': 'Access', 'apikeys.modal.reveal_title': 'Copy this key now.', 'apikeys.modal.reveal_body': "It won't be shown again.", 'apikeys.modal.copy': 'Copy to clipboard', 'apikeys.modal.copy_config': 'Copy configuration', 'apikeys.modal.connection_title': 'MCP connection configuration', 'apikeys.modal.clipboard_warning': 'Your operating system clipboard is outside Crank control. Clear it after saving the key.', 'apikeys.onboarding.key_lost': 'The key cannot be shown again. Create a new key and revoke the old one if its value was not saved.', 'apikeys.modal.cancel': 'Cancel', 'apikeys.modal.create': 'Create key', 'apikeys.modal.done': "Done — I've copied the key", 'apikeys.status.active': 'Active', 'apikeys.status.revoked': 'Revoked', 'apikeys.status.deleted': 'Deleted', 'apikeys.last_used.never': 'Never', 'apikeys.empty.none': 'No API keys yet', 'apikeys.empty.approval': 'No approval keys yet. Create one only if this agent has tools that require human confirmation.', 'apikeys.empty.search': 'No keys match your search', 'apikeys.loading': 'Loading…', 'apikeys.error.api': 'Workspace or API is unavailable', 'apikeys.error.load': 'Failed to load API keys', 'apikeys.confirm.revoke': 'Revoke this key? All requests using it will fail immediately.', 'apikeys.confirm.delete': 'Delete this key? This cannot be undone.', 'apikeys.toast.revoke_title': 'Key revoked', 'apikeys.toast.revoke_message': '{name} was revoked.', 'apikeys.toast.revoke_error_title': 'Revoke failed', 'apikeys.toast.revoke_error_message': 'Failed to revoke key', 'apikeys.toast.delete_title': 'Key deleted', 'apikeys.toast.delete_message': '{name} was deleted.', 'apikeys.toast.delete_error_title': 'Delete failed', 'apikeys.toast.delete_error_message': 'Failed to delete key', 'apikeys.toast.scope_missing_title': 'No access selected', 'apikeys.toast.scope_missing_message': 'Select at least one access level before creating a key.', 'apikeys.toast.create_title': 'Agent key created', 'apikeys.toast.create_message': 'Copy the key now. It will not be shown again.', 'apikeys.toast.create_error_title': 'Key creation failed', 'apikeys.toast.create_error_message': 'Failed to create key', 'apikeys.toast.copy_title': 'Agent key copied', 'apikeys.toast.copy_message': 'Store the raw key securely. It cannot be revealed again.', 'apikeys.toast.copy_error_title': 'Clipboard write failed', 'apikeys.toast.copy_error_message': 'The one-time value is still visible. Copy it manually before closing this page.', // community-scope: allow=one-time-token 'apikeys.toast.prefix_title': 'Key prefix copied', 'apikeys.action.copy_prefix': 'Copy key prefix', 'apikeys.action.revoke': 'Revoke key', 'apikeys.action.delete': 'Delete', 'apikeys.creating': 'Creating…', 'apikeys.approval.warning': 'Do not pass this key to an LLM or MCP client. It is only for an external interface where a human confirms an action.', 'apikeys.ambiguous.title': 'Creation result is uncertain.', 'apikeys.ambiguous.body': 'Key metadata was refreshed. Review the list before deliberately creating another key.', 'apikeys.ambiguous.retry': 'Refresh metadata and allow another attempt', 'apikeys.ambiguous.blocked': 'Review metadata before retrying', // Secrets page 'secrets.title': 'Secrets', 'secrets.subtitle': 'Credentials for authorization on target API hosts.', 'secrets.new': 'Create secret', 'secrets.callout.title': 'Secret values are protected.', 'secrets.callout.body': 'After saving, secrets are encrypted with the workspace key and cannot be read back. A secret can be rotated or deleted.', 'secrets.active.title': 'Workspace secrets', 'secrets.active.subtitle': '{active} active · {total} total', 'secrets.search': 'Filter secrets…', 'secrets.th.name': 'NAME', 'secrets.th.kind': 'KIND', 'secrets.th.version': 'VERSION', 'secrets.th.last_used': 'LAST USED', 'secrets.th.used_by': 'USED BY', 'secrets.th.status': 'STATUS', 'secrets.kind.token': 'Token', 'secrets.kind.username_password': 'Username/password', 'secrets.kind.header': 'Header value', 'secrets.kind.generic': 'Generic JSON', 'secrets.status.active': 'Active', 'secrets.status.disabled': 'Disabled', 'secrets.last_used.never': 'Never', 'secrets.used_by_count.one': '{count} binding', 'secrets.used_by_count.other': '{count} bindings', 'secrets.loading': 'Loading…', 'secrets.empty.none': 'No secrets yet', 'secrets.empty.search': 'No secrets match your search', 'secrets.error.workspace': 'Workspace is not selected', 'secrets.error.load': 'Failed to load secrets', 'secrets.action.rotate': 'Rotate', 'secrets.action.delete': 'Delete', 'secrets.confirm.delete': 'Delete secret {name}? This cannot be undone while the secret is still used by an operation.', 'secrets.toast.create_title': 'Secret created', 'secrets.toast.create_message': 'The secret was stored encrypted and cannot be viewed again.', 'secrets.toast.create_error_title': 'Secret creation failed', 'secrets.toast.create_error_message': 'Failed to create secret', 'secrets.toast.rotate_title': 'Secret rotated', 'secrets.toast.rotate_message': 'A new secret version is now active.', 'secrets.toast.rotate_error_title': 'Secret rotation failed', 'secrets.toast.rotate_error_message': 'Failed to rotate secret', 'secrets.toast.delete_title': 'Secret deleted', 'secrets.toast.delete_message': '{name} was deleted.', 'secrets.toast.delete_error_title': 'Secret deletion failed', 'secrets.toast.delete_error_message': 'Failed to delete secret', 'secrets.modal.create_title': 'Create secret', 'secrets.modal.rotate_title': 'Rotate secret', 'secrets.modal.name': 'Secret name', 'secrets.modal.name_hint': 'Use a clear name so you can select this secret in operation settings later.', 'secrets.modal.kind': 'Secret kind', 'secrets.modal.value': 'Token value', 'secrets.modal.header_value': 'Header value', 'secrets.modal.username': 'Username', 'secrets.modal.password': 'Password', 'secrets.modal.json_payload': 'JSON', 'secrets.modal.json_hint': 'Enter valid JSON. Use this type when an API needs several related values.', 'secrets.modal.create_note': 'After saving, the value is encrypted and will no longer be displayed.', 'secrets.modal.rotate_note': 'Rotation replaces the stored value with a new encrypted version.', 'secrets.modal.cancel': 'Cancel', 'secrets.modal.create_action': 'Create secret', 'secrets.modal.rotate_action': 'Rotate secret', 'secrets.modal.creating': 'Creating…', 'secrets.modal.rotating': 'Rotating…', 'secrets.hint.token': 'For bearer tokens, API keys, or another single token value.', 'secrets.hint.username_password': 'For username and password authorization.', 'secrets.hint.header': 'For a value passed in an HTTP header.', 'secrets.hint.generic': 'For structured JSON credentials.', 'secrets.validation.name_required': 'Secret name is required.', 'secrets.validation.value_required': 'Secret value is required.', 'secrets.validation.username_password_required': 'Username and password are both required.', 'secrets.validation.json_invalid': 'The JSON value must be valid.', // Logs page 'logs.title': 'Logs', 'logs.subtitle': 'Invocation log for all operations in this workspace.', 'logs.search': 'Search logs...', 'logs.level.all': 'All', 'logs.level.info': 'Info', 'logs.level.warn': 'Warn', 'logs.level.error': 'Error', 'logs.level.debug': 'Debug', 'logs.live': 'Live', 'logs.paused': 'Paused', 'logs.refresh': 'Refresh', 'logs.export': 'Export CSV', 'logs.load_more': 'Load more', 'logs.status_filter': 'Status', 'logs.status.all': 'All statuses', 'logs.status.ok': 'Success', 'logs.status.error': 'Error', 'logs.outcome_filter': 'Outcome', 'logs.outcome.all': 'All outcomes', 'logs.filter.operation': 'Operation ID', 'logs.filter.agent': 'Agent ID', 'logs.range.30m': 'Last 30 min', 'logs.range.1h': 'Last hour', 'logs.range.6h': 'Last 6 hours', 'logs.range.24h': 'Last 24 hours', 'logs.range.7d': 'Last 7 days', 'logs.search_messages': 'Search messages…', 'logs.detail.agent': 'Agent', 'logs.detail.request': 'Request preview', 'logs.detail.response': 'Response preview', 'logs.detail.meta': 'Metadata', 'logs.loading.title': 'Loading logs…', 'logs.loading.sub': 'Fetching invocation history for the current workspace.', 'logs.error.title': 'Unable to load logs', 'logs.error.api': 'Admin API is not available', 'logs.error.workspace': 'Workspace is not selected', 'logs.error.load': 'Failed to load logs', 'logs.empty.title': 'No log entries found', 'logs.empty.filtered': 'Try widening the period or clearing the current search and level filters.', 'logs.empty.initial': 'Run tests or published MCP tools to start collecting invocation history.', 'logs.live.on.title': 'Live mode enabled', 'logs.live.on.body': 'Polling logs every 4 seconds.', 'logs.live.off.title': 'Live mode paused', 'logs.live.off.body': 'Automatic polling is paused.', 'logs.refresh.title': 'Logs refreshed', 'logs.refresh.body': 'The latest invocation records were loaded for the current workspace.', 'logs.export.done_title': 'Logs exported', 'logs.export.done_body': 'The filtered invocation history was exported as CSV.', 'logs.export.error_title': 'Export failed', 'logs.export.error_body': 'Failed to export invocation history.', 'approvals.title': 'Human confirmations', 'approvals.subtitle': 'Requests waiting for an external user decision and recent results.', 'approvals.refresh': 'Refresh', 'approvals.refresh.title': 'Confirmations refreshed', 'approvals.refresh.body': 'The latest confirmation requests were loaded.', 'approvals.loading': 'Loading confirmation requests…', 'approvals.empty': 'There are no confirmation requests yet.', 'approvals.error.load': 'Failed to load confirmation requests', 'approvals.error.decision': 'Failed to submit confirmation decision', 'approvals.untitled': 'Confirmation request', 'approvals.operation': 'Operation', 'approvals.agent': 'Agent', 'approvals.expires_at': 'Expires', 'approvals.updated_at': 'Updated', 'approvals.request': 'Request', 'approvals.response': 'Result', 'approvals.request_id': 'Request ID', 'approvals.trace_id': 'Trace ID', 'approvals.action.approve': 'Approve', 'approvals.action.deny': 'Deny', 'approvals.action.busy': 'Submitting…', 'approvals.confirm.approve': 'Approve this pending confirmation request?', 'approvals.confirm.deny': 'Deny this pending confirmation request?', 'approvals.status.pending': 'Pending', 'approvals.status.approved': 'Approved', 'approvals.status.denied': 'Denied', 'approvals.status.expired': 'Expired', 'approvals.status.completed': 'Completed', 'approvals.status.failed': 'Failed', // Usage page 'usage.title': 'Usage', 'usage.subtitle': 'Invocation metrics for all operations in your workspace.', 'usage.export': 'Export CSV', 'usage.period.7d': 'Last 7 days', 'usage.period.30d': 'Last 30 days', 'usage.period.90d': 'Last 90 days', 'usage.period.this_month': 'This month', 'usage.period.label.7d': 'last 7 days', 'usage.period.label.30d': 'last 30 days', 'usage.period.label.90d': 'last 90 days', 'usage.period.label.this_month': 'this month', 'usage.stats.total': 'Total invocations', 'usage.stats.success': 'Success rate', 'usage.stats.p50': 'Median latency (p50)', 'usage.stats.p99': 'p99 latency', 'usage.stats.across': 'Across {period}', 'usage.stats.success_calls': '{count} successful calls', 'usage.stats.median': 'Median latency for selected period', 'usage.stats.error_calls': '{count} error calls', 'usage.chart.title': 'Invocations over time', 'usage.chart.success': 'Success', 'usage.chart.error': 'Error', 'usage.chart.empty.title': 'No usage data yet', 'usage.chart.empty.sub': 'Invocation metrics will appear here after tests or published tool calls in the selected period.', 'usage.outcomes.title': 'Outcomes', 'usage.outcomes.subtitle': 'Grouped by safe execution outcome.', 'usage.outcomes.empty.title': 'No outcome breakdown yet', 'usage.outcomes.empty.sub': 'Outcome groups will appear after invocations are recorded.', 'usage.outcomes.p50': 'p50', 'usage.outcomes.p95': 'p95', 'usage.outcomes.p99': 'p99', 'usage.outcome.success': 'Success', 'usage.outcome.upstream': 'Upstream', 'usage.outcome.client': 'Client', 'usage.outcome.schema': 'Schema', 'usage.outcome.crank': 'Crank', 'usage.outcome.no_error_code': 'No error code', 'usage.table.title': 'By operation', 'usage.table.subtitle': 'Breakdown for {period}', 'usage.table.th.operation': 'Operation', 'usage.table.th.protocol': 'Protocol', 'usage.table.th.calls': 'Calls', 'usage.table.th.errors': 'Errors', 'usage.table.th.error_rate': 'Error rate', 'usage.table.th.latency': 'Latency (p50 / p95 / p99)', 'usage.table.th.share': 'Traffic share', 'usage.table.empty.title': 'No operation breakdown yet', 'usage.table.empty.sub': 'The selected period has no invocation samples to break down by operation.', 'usage.table.share': '{value}% of workspace traffic', 'usage.loading.title': 'Loading usage…', 'usage.loading.sub': 'Aggregating invocation metrics for the selected workspace.', 'usage.error.title': 'Unable to load usage', 'usage.error.api': 'Admin API is not available', 'usage.error.workspace': 'Workspace is not selected', 'usage.error.load': 'Failed to load usage', 'usage.export.empty.title': 'No usage data loaded', 'usage.export.empty.body': 'Load usage data before exporting the CSV snapshot.', 'usage.export.done.title': 'Usage exported', 'usage.export.done.body': 'The filtered usage dataset was exported as CSV.', 'usage.export.error.title': 'Export failed', 'usage.export.error.body': 'Failed to export usage data.', 'usage.chart.ok': '{count} ok', 'usage.chart.errors': '{count} errors', 'usage.chart.week': 'Wk {index}', 'usage.csv.header': 'Operation,Protocol,Calls,Errors,Error Rate (%),p50 (ms),p95 (ms),p99 (ms)', // Settings sidebar 'settings.title': 'Settings', 'settings.nav.workspace': 'Workspace', 'settings.nav.profile': 'Profile', 'settings.nav.security': 'Security', 'settings.nav.danger': 'Danger zone', // Settings — workspace section 'settings.ws.title': 'Workspace settings', 'settings.ws.subtitle': 'General information about your workspace', 'settings.ws.name': 'Workspace name', 'settings.ws.display': 'Display name', 'settings.ws.desc': 'Description', // Settings — language 'settings.lang.title': 'Language', 'settings.lang.subtitle': 'Interface display language', 'settings.lang.en': 'English', 'settings.lang.ru': 'Русский', // Settings — profile section 'settings.profile.title': 'Profile', 'settings.profile.name': 'Full name', 'settings.profile.email': 'Email', 'settings.profile.role': 'Role', 'settings.page.title': 'Account settings', 'settings.ws.slug_hint': 'Used in API endpoints and in the interface. Only lowercase English letters, numbers and hyphens are allowed.', 'settings.ws.description_optional': 'Description (optional)', 'settings.ws.description_placeholder': 'What tasks does this workspace perform?', 'settings.profile.avatar_hint': 'Your avatar is generated from your display name and email.', 'settings.profile.first_name': 'First name', 'settings.profile.last_name': 'Last name', 'settings.profile.last_name_placeholder': 'Optional', 'settings.profile.email_label': 'Email address', 'settings.profile.email_hint': 'Changing email updates the login identity for the current account.', 'settings.profile.save': 'Save profile', 'settings.profile.saving': 'Saving…', 'settings.profile.saved': 'Saved ✓', 'settings.profile.saved_status': 'Profile saved.', 'settings.profile.save_error': 'Failed to save profile', 'settings.security.title': 'Security', 'settings.security.current_password': 'Current password', 'settings.security.new_password': 'New password', 'settings.security.new_password_placeholder': 'min. 12 characters', 'settings.security.confirm_password': 'Confirm new password', 'settings.security.change_password': 'Change password', 'settings.security.mismatch': 'New password and confirmation do not match.', 'settings.security.saved': 'Password updated.', 'settings.security.saved_relogin': 'Password updated. Please sign in again.', 'settings.security.save_error': 'Failed to change password', 'settings.capability.rest': 'REST / HTTP', 'settings.capability.standard': 'standard', 'settings.capability.elevated': 'elevated', 'settings.capability.strict': 'strict', 'settings.capability.static_agent_key': 'static agent keys', 'settings.capability.unlimited': 'unlimited', 'settings.capability.none': 'none', 'settings.session.title': 'Current session', 'settings.session.browser': 'Browser session', 'settings.session.current': 'current', 'settings.session.loading': 'Loading current session details…', 'settings.session.unavailable': 'Session details are unavailable. Use Log out to revoke the current browser session.', 'settings.session.current_workspace': 'current workspace', 'settings.session.summary': '{email} · {role} in {workspace}. Use Log out to revoke the current browser session.', 'settings.planned_badge': 'Planned', 'settings.workspace.saving': 'Saving…', 'settings.workspace.saved': 'Saved ✓', 'settings.workspace.save_error': 'Failed to save workspace settings', 'settings.workspace.save_error_title': 'Workspace save failed', // Workspace setup 'workspace_setup.title': 'Workspace settings', 'workspace_setup.page_subtitle': 'Configure the identity of your self-hosted workspace.', 'workspace_setup.back': 'Back', 'workspace_setup.identity.title': 'Workspace identity', 'workspace_setup.identity.avatar_hint': 'Avatar is derived from your workspace name.', 'workspace_setup.name': 'Workspace name', 'workspace_setup.slug': 'Slug', 'workspace_setup.required': 'required', 'workspace_setup.optional': '(optional)', 'workspace_setup.slug_hint': 'Only lowercase letters, numbers, and hyphens. Used in MCP endpoint URLs.', 'workspace_setup.description': 'Description', 'workspace_setup.description_placeholder': 'What tasks does this workspace perform?', 'workspace_setup.actions.save': 'Save changes', 'workspace_setup.create.title': 'Create a new workspace', 'workspace_setup.create.subtitle': 'This Community installation uses one workspace for MCP operations and agents.', 'workspace_setup.create.footer': 'This Community installation uses one workspace.', 'workspace_setup.danger.title': 'Danger zone', 'workspace_setup.danger.export_title': 'Export workspace catalog', 'workspace_setup.danger.export_body': 'Download a non-restorable JSON catalog of workspace settings, operation summaries, agent summaries and API key metadata.', 'workspace_setup.export': 'Export', 'workspace_setup.role.owner': 'Owner', 'workspace_setup.role.admin': 'Admin', 'workspace_setup.role.operator': 'Developer', 'workspace_setup.role.viewer': 'Viewer', 'workspace_setup.saving_create': 'Creating…', 'workspace_setup.saving_update': 'Saving…', 'workspace_setup.saved': 'Saved ✓', 'workspace_setup.save_error': 'Failed to save workspace', 'workspace_setup.save_error_title': 'Save failed', 'workspace_setup.export_error': 'Failed to export workspace', 'workspace_setup.export_error_title': 'Export failed', 'workspace.switch_error': 'Failed to switch workspace', 'workspace.switch_error_title': 'Workspace switch failed', 'workspace_setup.custom_protocol.rest': 'REST', // Wizard 'wizard.back_catalog': 'Operations', 'wizard.progress.create': 'Create operation', 'wizard.progress.edit': 'Edit operation', 'wizard.exit': 'Exit wizard', 'wizard.step_of': 'Step {step} of {total}', 'wizard.step_short': 'Step {step}', 'wizard.status.completed': 'Completed', 'wizard.status.in_progress': 'In progress', 'wizard.status.not_started': 'Not started', 'wizard.help.title': 'Need help?', 'wizard.help.body': 'Unsure which protocol to choose? Read the', 'wizard.help.link': 'protocol comparison guide →', 'wizard.progress.section': 'Progress', 'wizard.step_name.protocol': 'Protocol', 'wizard.step_name.upstream': 'Upstream target', 'wizard.step_name.tool': 'Tool config', 'wizard.step_name.mapping': 'Mapping', 'wizard.button.back': 'Back', 'wizard.button.continue': 'Continue', 'wizard.button.save_draft': 'Save draft', 'wizard.button.create': 'Create operation', 'wizard.button.save_changes': 'Save changes', 'wizard.sidebar.brand.create': 'Create operation', 'wizard.sidebar.brand.edit': 'Edit operation', 'wizard.step1.title': 'Choose a protocol', 'wizard.step1.subtitle': 'Select the transport protocol your upstream service uses. This determines how Crank will communicate with your API and which configuration options are available in subsequent steps.', 'wizard.step1.rest_name': 'REST / HTTP', 'wizard.step1.rest_tagline': 'Standard HTTP verbs over a RESTful endpoint. The most broadly supported option.', 'wizard.step1.query': 'Query', 'wizard.step1.mutation': 'Mutation', 'wizard.step1.unary': 'Unary', 'wizard.step1.tip_title': 'You can change this later', 'wizard.step1.tip_body': 'Switching protocol after configuring subsequent steps will clear schema and mapping data. Save your operation as a draft before experimenting. See protocol migration guide for details.', 'wizard.step1.community_protocol_title': 'Community protocol scope', 'wizard.step5.streaming_title': 'Streaming execution in Community', 'wizard.step2.title': 'Select upstream & endpoint', 'wizard.step2.subtitle': 'Choose an existing upstream or register a new one. Then define the specific endpoint path this operation will call.', 'wizard.required': 'Required', 'wizard.optional': 'Optional', 'wizard.step2.upstream_title': 'API host', 'wizard.step2.upstream_subtitle': 'Base URL and authorization', 'wizard.step2.upstream_placeholder': 'Select an API host…', 'wizard.step2.search_placeholder': 'Search by name or URL…', 'wizard.step2.change': 'Change', 'wizard.step2.auth_none': 'No auth', 'wizard.step2.auth_bearer': 'Bearer token', 'wizard.step2.auth_basic': 'Basic auth', 'wizard.step2.auth_apikey': 'API key', 'wizard.step2.register_new': 'Add new API host', 'wizard.step2.name': 'Name', 'wizard.step2.base_url': 'Base URL', 'wizard.step2.unique_hint': 'Unique name for this API host.', 'wizard.step2.base_url_hint': 'Root URL without a trailing slash. Authorization is configured below.', 'wizard.step2.auth_selector': 'API host authorization', 'wizard.step2.auth_selector_hint': 'Use secrets so tokens and passwords are not stored directly in API host settings.', 'wizard.step2.auth_mode.none': 'No auth', 'wizard.step2.auth_mode.existing': 'Use existing authorization profile', 'wizard.step2.auth_mode.create': 'Create authorization profile now', 'wizard.step2.auth_profile': 'Authorization profile', 'wizard.step2.auth_profile_hint': 'The selected profile is applied automatically on every tool call.', 'wizard.step2.auth_profile_empty': 'No authorization profiles yet. Create one below.', 'wizard.step2.create_profile_title': 'Create authorization profile', 'wizard.step2.create_profile_subtitle': 'Create a reusable profile that reads values from encrypted workspace secrets.', 'wizard.step2.profile_name': 'Profile name', 'wizard.step2.profile_kind': 'Authorization type', 'wizard.step2.auth_kind.bearer': 'Bearer token', 'wizard.step2.auth_kind.basic': 'Basic auth', 'wizard.step2.auth_kind.api_key_header': 'API key in header', 'wizard.step2.auth_kind.api_key_query': 'API key in query parameter', 'wizard.step2.header_name': 'Header name', 'wizard.step2.query_param': 'Query parameter', 'wizard.step2.username_secret': 'Username secret', 'wizard.step2.password_secret': 'Password secret', 'wizard.step2.secret_value': 'Secret', 'wizard.step2.quick_secret': 'Quick create secret', 'wizard.step2.manage_secrets': 'Open secrets page', 'wizard.step2.static_headers': 'Static headers (optional)', 'wizard.step2.static_headers_hint': 'Optional headers without secret values. Store tokens, passwords and keys through an authorization profile.', 'wizard.step2.quick_secret_title': 'Quick create secret', 'wizard.step2.quick_secret_name': 'Secret name', 'wizard.step2.quick_secret_kind': 'Secret kind', 'wizard.step2.quick_secret_value': 'Secret value', 'wizard.step2.quick_secret_hint': 'The value is encrypted immediately and will not be shown again.', 'wizard.step2.quick_secret_submit': 'Create secret', 'wizard.step2.save_upstream': 'Save API host', 'wizard.step2.endpoint_title': 'Endpoint', 'wizard.step2.endpoint_subtitle': 'Path and HTTP method for this specific operation', 'wizard.step2.path_template': 'Path template', 'wizard.step2.path_hint': 'Appended to the API host Base URL. Use {param} for path parameters.', 'wizard.step3.rest.label': 'Request config', 'wizard.step3.rest.title': 'HTTP method & format', 'wizard.step3.rest.subtitle': 'Choose the HTTP method and request format. Crank converts MCP tool parameters into the API request body.', 'wizard.step3.rest.method_title': 'HTTP method', 'wizard.step3.rest.method_subtitle': 'Method sent to the API on every tool call', 'wizard.step3.rest.read': 'Read', 'wizard.step3.rest.create': 'Create', 'wizard.step3.rest.replace': 'Replace', 'wizard.step3.rest.update': 'Update', 'wizard.step3.rest.remove': 'Remove', 'wizard.step3.rest.format_title': 'Request format', 'wizard.step3.rest.format_subtitle': 'Request body format and expected response', 'wizard.step3.rest.content_type': 'Content-Type', 'wizard.step3.rest.content_type_hint': 'How the request body is encoded before sending it to the API.', 'wizard.step3.rest.accept': 'Accept', 'wizard.step3.rest.accept_hint': 'Response types accepted from the API server.', 'wizard.step4.title': 'Tool config', 'wizard.step4.subtitle': 'Name your tool, write the LLM-facing description, and define the input/output schemas. The description is the primary signal the model uses when deciding whether to call this tool.', 'wizard.step4.identity_title': 'Tool parameters', 'wizard.step4.identity_subtitle': 'Tool name and purpose description', 'wizard.step4.tool_name': 'Tool name', 'wizard.step4.tool_name_hint': 'Technical name for calling the MCP tool. Only lowercase English letters, numbers and underscores are allowed. Cannot be changed after publishing.', 'wizard.step4.display_name': 'Display name', 'wizard.step4.display_name_hint': 'Readable name shown in the interface and logs.', 'wizard.step4.tool_title': 'Short description', 'wizard.step4.tool_title_hint': 'Short phrase shown to the MCP client in the tool description.', 'wizard.step4.description': 'Description', 'wizard.step4.description_hint': 'Description for the model. Be precise: the model uses this text to decide when to call the tool.', 'wizard.step4.description_title': 'Writing effective descriptions', 'wizard.step4.description_body': 'Start with a verb: creates, fetches, updates. Mention the required input data and describe the successful result. Avoid vague wording like “handles” or “manages”.', 'wizard.step4.input_schema_title': 'Input schema', 'wizard.step4.input_schema_subtitle': 'Parameters the LLM passes when calling this tool', 'wizard.step4.output_schema_title': 'Output schema', 'wizard.step4.output_schema_subtitle': 'Shape of the data returned to the LLM after a successful call', 'wizard.step4.schema_draft': 'JSON Schema draft-07', 'wizard.step4.protocol_agnostic_title': 'Schemas describe the tool', 'wizard.step4.protocol_agnostic_body': 'The input schema describes what the MCP client sends to the tool. The output schema describes what the tool returns. On the next step, connect these fields to the real API request and response.', 'wizard.step5.title': 'Field bindings and launch', 'wizard.step5.subtitle': 'Connect MCP tool parameters to API request fields and connect the API response to the tool result. Authorization is configured on step 2.', 'wizard.step5.input_request': 'Tool input → API request', 'wizard.step5.output_response': 'API response → Tool output', 'wizard.step5.execution': 'Execution settings', 'wizard.step5.exec_title': 'Request execution', 'wizard.step5.exec_subtitle': 'Timeout, retry count and authorization profile', 'wizard.approval.title': 'Human confirmation', 'wizard.approval.subtitle': 'Enable this for actions that must not run without an explicit user decision.', 'wizard.approval.required_label': 'Require confirmation before execution', 'wizard.approval.required_desc': 'The MCP client receives a pending request, and the action runs only after confirmation through a separate approval endpoint.', 'wizard.approval.mode': 'Confirmation mechanism', 'wizard.approval.mode.custom': 'Custom MCP Approval', 'wizard.approval.mode.elicitation': 'MCP Elicitation', 'wizard.approval.custom_title': 'Custom MCP Approval', 'wizard.approval.custom_body': 'Crank returns approval_required to the MCP client with approval_id, approval_url and approve/deny links. Your MCP client must handle this response, show confirmation to the user and send the decision to the approval endpoint. The approval endpoint requires a separate agent approval key.', 'wizard.approval.elicitation_title': 'MCP Elicitation', 'wizard.approval.elicitation_body': 'Crank asks for confirmation through standard MCP Elicitation. The MCP client must support the elicitation capability. No separate approval key is used: the user decision returns through the current MCP session.', 'wizard.approval.elicitation_message': 'Message for the MCP client', 'wizard.approval.elicitation_message_placeholder': 'Confirm operation execution.', 'wizard.approval.elicitation_message_hint': 'Short protocol message. The MCP client still controls the confirmation UI.', 'wizard.approval.ttl': 'How long to wait for confirmation', 'wizard.approval.show_payload': 'Send call parameters to the confirmation flow', 'wizard.approval.payload_title': 'Confirmation parameters', 'wizard.approval.payload_body': 'When enabled, Crank sends call parameters into the approval flow so the external UI or MCP client can show the user what action is being confirmed. Disable this option if parameters contain sensitive data.', 'wizard.step5.security_level_title': 'Operation security', 'wizard.step5.community_security_note': '', 'wizard.step5.live_title': 'Check and publish', 'wizard.step5.draft_actions': 'Action result', 'wizard.step5.live_save_title': 'Saving before action', 'wizard.step5.live_save_body': 'Crank saves the current settings before running checks or publishing.', 'wizard.step5.agent_preview_title': 'How the MCP client sees this tool', 'wizard.step5.agent_preview_subtitle': 'Check the name, description, input schema and examples before publication.', 'wizard.step5.copy_agent_preview': 'Copy schema', 'wizard.step5.preview_tool_name': 'Tool name', 'wizard.step5.preview_tool_title': 'Short description', 'wizard.step5.preview_tool_description': 'Description for the model', 'wizard.step5.preview_input_schema': 'Input schema', 'wizard.step5.preview_tool_call': 'Example tools/call', 'wizard.step5.preview_success_response': 'Successful response example', 'wizard.step5.preview_error_response': 'Error example', 'wizard.step5.samples_title': 'Examples and automatic setup', 'wizard.step5.samples_subtitle': 'Save example input and output data, then let Crank rebuild schemas and field bindings from them.', 'wizard.step5.input_sample': 'Input example', 'wizard.step5.output_sample': 'Output example', 'wizard.step5.save_input_sample': 'Save input example', 'wizard.step5.save_output_sample': 'Save output example', 'wizard.step5.generate_draft': 'Rebuild from examples', 'wizard.step5.test_title': 'Operation testing', 'wizard.step5.test_subtitle': 'Run the tool against the real API before publishing it.', 'wizard.step5.test_input_payload': 'Input data for the test', 'wizard.step5.run_test': 'Run test', 'wizard.step5.use_response_output': 'Use response as output example', 'wizard.step5.request_preview': 'API request preview', 'wizard.step5.response_preview': 'API response preview', 'wizard.step5.errors': 'Errors', 'wizard.step5.choose_descriptor': 'Choose descriptor set', 'wizard.step5.upload_discover': 'Upload and discover services', 'wizard.step5.no_descriptor': 'No descriptor set selected', 'wizard.step5.yaml_title': 'YAML import and export', 'wizard.step5.yaml_subtitle': 'Export the operation to a file or import a prepared YAML configuration.', 'wizard.step5.export_yaml': 'Export YAML', 'wizard.step5.load_yaml_file': 'Load YAML file', 'wizard.step5.import_yaml': 'Import YAML', 'wizard.step5.yaml_document': 'YAML configuration', 'wizard.step5.yaml_placeholder': 'Paste YAML here to create or update an operation.', 'wizard.step5.publish_title': 'Publication', 'wizard.step5.publish_subtitle': 'Publish the operation so it can be added to agents.', 'wizard.step5.publish_hint': 'Before publication, Crank saves the current settings from this wizard.', 'wizard.step5.publish_action': 'Publish operation', 'wizard.step5.editable_title': 'Operation stays editable in this wizard', 'wizard.step5.editable_body': 'Saving updates the operation settings in this wizard.', 'wizard.live.failed_title': 'Action failed', 'wizard.live.failed_body': 'The request failed. Check the operation settings and try again.', 'wizard.error.no_workspace': 'No workspace selected', 'wizard.error.tool_name': 'Tool name is required', 'wizard.error.parser_unavailable': 'YAML parser is not available', 'wizard.error.select_upstream': 'Select or add an API host first', 'wizard.error.auth_profile_required': 'Select an authorization profile or switch API host authorization to No auth.', 'wizard.error.auth_profile_name': 'Authorization profile name is required.', 'wizard.error.secret_required': 'Select the secret required by this authorization profile.', 'wizard.error.basic_secrets_required': 'Select both username and password secrets.', 'wizard.error.header_name_required': 'Header name is required for this authorization profile.', 'wizard.error.query_param_required': 'Query parameter name is required for this authorization profile.', 'wizard.error.secret_name_required': 'Secret name is required.', 'wizard.error.secret_value_required': 'Secret value is required.', 'wizard.error.save_upstream_first': 'Save the API host after creating a new authorization profile before continuing.', 'wizard.toast.auth_profile_created_title': 'Authorization profile created', 'wizard.toast.auth_profile_created_body': 'New authorization profile is ready and selected.', 'wizard.toast.auth_profile_error_title': 'Authorization profile creation failed', 'wizard.toast.quick_secret_created_title': 'Secret created', 'wizard.toast.quick_secret_created_body': 'The new secret is now available in the authorization selector.', 'wizard.toast.quick_secret_error_title': 'Secret creation failed', 'wizard.error.save': 'Failed to save operation', 'wizard.error.save_title': 'Save failed', 'wizard.save.created': 'Draft created', 'wizard.save.updated': 'Draft updated', 'wizard.save.body': 'The current operation settings have been saved.', 'wizard.save.saved': 'Saved ✓', 'wizard.busy.input_sample': 'Saving input example…', 'wizard.busy.output_sample': 'Saving output example…', 'wizard.busy.generate': 'Rebuilding settings…', 'wizard.busy.test': 'Running test…', 'wizard.busy.quality': 'Checking quality…', 'wizard.busy.export_yaml': 'Exporting YAML…', 'wizard.busy.import_yaml': 'Importing YAML…', 'wizard.busy.publish': 'Publishing operation…', 'wizard.busy.descriptor': 'Uploading descriptor set…', 'wizard.busy.wsdl': 'Inspecting WSDL…', 'wizard.sample.input_saved': 'Input example saved', 'wizard.sample.input_saved_body': 'The input example has been saved for this operation.', 'wizard.sample.output_saved': 'Output example saved', 'wizard.sample.output_saved_body': 'The output example has been saved for this operation.', 'wizard.sample.generated': 'Settings rebuilt', 'wizard.sample.generated_body': 'Schemas and field bindings were rebuilt from the saved examples.', 'wizard.test.completed': 'Operation test completed', 'wizard.test.failed': 'Operation test returned errors', 'wizard.test.completed_body': 'The operation was executed successfully against the API.', 'wizard.test.failed_body': 'The operation was executed, but the API or validation returned errors.', 'execution.error.authorization_denied': 'Operation execution is denied.', 'execution.error.auth_profile_not_found': 'Authorization profile was not found.', 'execution.error.secret_not_found': 'Authorization secret was not found.', 'execution.error.secret_invalid': 'Authorization secret has an invalid format.', 'execution.error.input_schema_invalid': 'Input does not satisfy the operation schema.', 'execution.error.input_mapping_invalid': 'Input parameters could not be mapped.', 'execution.error.prepared_request_invalid': 'A valid upstream request could not be prepared.', 'execution.error.execution_overloaded': 'The service is temporarily overloaded.', 'execution.error.safety_store_unavailable': 'A mandatory safety store is unavailable.', 'execution.error.protocol_unsupported': 'The operation protocol is unsupported.', 'execution.error.execution_mode_unsupported': 'The execution mode is unsupported.', 'execution.error.adapter_configuration_invalid': 'The adapter configuration is invalid.', 'execution.error.outbound_target_rejected': 'The target was rejected by the safety policy.', 'execution.error.upstream_auth_error': 'The upstream API rejected authorization.', 'execution.error.upstream_not_found': 'The upstream resource was not found.', 'execution.error.upstream_rate_limited': 'The upstream API rate-limited the request.', 'execution.error.upstream_server_error': 'The upstream API is temporarily unavailable.', 'execution.error.upstream_status_error': 'The upstream API returned an error status.', 'execution.error.upstream_timeout': 'The upstream API timed out.', 'execution.error.upstream_transport_error': 'The upstream API could not be reached.', 'execution.error.upstream_response_too_large': 'The upstream response exceeded its limit.', 'execution.error.output_mapping_invalid': 'The upstream response could not be mapped.', 'execution.error.output_schema_invalid': 'The output does not satisfy the operation schema.', 'execution.error.persistence_unavailable': 'Mandatory result persistence is unavailable.', 'execution.error.runtime_internal': 'Internal execution failure.', 'execution.error.confirmation_required': 'The operation requires confirmation.', 'execution.error.confirmation_invalid': 'The confirmation is invalid or expired.', 'execution.error.idempotency_in_progress': 'The operation is already running for this key.', 'execution.error.idempotency_conflict': 'The idempotency key was used with different input.', 'execution.error.idempotency_outcome_unknown': 'The previous outcome is unknown; automatic retry is unsafe.', 'wizard.test.window_completed': 'Window test completed', 'wizard.test.window_completed_body': 'Collected a bounded result window.', 'wizard.test.window_truncated_note': 'Results were truncated.', 'wizard.test.window_more_note': 'More data is available if you continue from the streaming views.', 'wizard.test.window_incomplete_note': 'The upstream stream ended before the configured window was fully collected.', 'wizard.test.no_response': 'No test response yet', 'wizard.test.no_response_body': 'Run a test first, then copy the response into the output example.', 'wizard.test.response_copied': 'Response copied', 'wizard.test.response_copied_body': 'The latest test response was copied into the output example.', 'wizard.agent_preview.copied': 'Schema copied', 'wizard.agent_preview.copied_body': 'The MCP tool schema was copied to the clipboard.', 'wizard.quality.title': 'Tool quality check', 'wizard.quality.subtitle': 'Check the name, description, schemas and the result visible to the agent.', 'wizard.quality.action': 'Check quality', 'wizard.quality.empty': 'Quality check has not run yet.', 'wizard.quality.no_findings': 'No issues found.', 'wizard.quality.checked_title': 'Quality check completed', 'wizard.quality.checked_body': 'Review the recommendations before publishing.', 'wizard.quality.blocked_title': 'Quality check found blocking issues', 'wizard.quality.blocked_body': 'Fix error-level findings before publishing.', 'wizard.quality.blocking_error': 'Fix blocking quality findings before publishing.', 'wizard.quality.import_findings_hint': 'These findings came from OpenAPI import. Run quality analysis to recalculate them for the current Draft.', 'wizard.quality.severity_error': 'Error', 'wizard.quality.severity_warning': 'Warning', 'wizard.quality.severity_info': 'Info', 'wizard.boolean.yes': 'yes', 'wizard.boolean.no': 'no', 'wizard.yaml.exported': 'YAML exported', 'wizard.yaml.exported_body': 'The current operation configuration was downloaded as YAML.', 'wizard.yaml.none': 'No YAML provided', 'wizard.yaml.none_body': 'Paste a YAML document or load it from a file before importing.', 'wizard.yaml.imported': 'YAML imported', 'wizard.yaml.imported_with_warnings': 'YAML imported with recommendations', 'wizard.yaml.imported_body': 'The imported operation was saved. The wizard will reopen it now.', 'wizard.yaml.loaded': 'YAML loaded', 'wizard.yaml.loaded_body': 'The YAML configuration was loaded.', 'wizard.publish.done': 'Operation published', 'wizard.publish.done_body': 'Version {version} is now published and can be bound into agents.', 'wizard.publish.confirm': 'Publish the saved Draft as a new immutable version?', 'wizard.stale.title': 'Draft changed elsewhere', 'wizard.stale.body': 'Your edits are preserved in this browser. Reload the latest saved Draft before retrying.', 'wizard.test.correlation': 'Request ID: {requestId}\nTrace ID: {traceId}', 'wizard.test.request_id': 'Request ID', 'wizard.test.trace_id': 'Trace ID', 'wizard.test.copy_request_id': 'Copy Request ID', 'wizard.test.copy_trace_id': 'Copy Trace ID', 'wizard.test.id_copied': 'Support ID copied', 'wizard.test.id_copied_body': 'The identifier was copied without request or response payload.', // Common buttons 'btn.save': 'Save changes', 'btn.cancel': 'Cancel', 'btn.create': 'Create', 'btn.delete': 'Delete', 'btn.revoke': 'Revoke', 'btn.copy': 'Copy', // Agents page 'agents.title': 'Agents', 'agents.subtitle': 'Group your MCP tools by AI agent.', 'agents.subtitle.community': 'Group your MCP tools by AI agent.', 'agents.new': 'New agent', 'agents.limit.title': 'Agent limit reached', 'agents.limit.message': 'This edition allows up to {limit} AI agent. Remove an existing agent to add another one.', 'agents.stats.total': 'Total agents', 'agents.stats.total_sub': 'across this workspace', 'agents.stats.published': 'Published', 'agents.stats.published_sub': '{value}% of total', 'agents.stats.tools': 'Operations exposed', 'agents.stats.tools_sub': 'across {count} agents', 'agents.stats.calls': 'Calls today', 'agents.stats.calls_sub': 'all agents combined', 'agents.search': 'Search agents...', 'agents.results': '{shown} of {total} agents', 'agents.callout.default': 'Group MCP tools around concrete tasks for a concrete agent. Do not give one LLM too many tools at once: it can increase mistakes and hallucinations. Each agent has its own API keys.', 'agents.callout.community': 'Group MCP tools around concrete tasks for a concrete agent. Do not give one LLM too many tools at once: it can increase mistakes and hallucinations. Each agent has its own API keys.', 'agents.loading': 'Loading agents…', 'agents.error.title': 'Failed to load agents', 'agents.error.api': 'Workspace or API is unavailable', 'agents.error.load': 'Failed to load agents', 'agents.empty.initial.title': 'No agents yet', 'agents.empty.initial.sub': 'Create your first agent to get a dedicated MCP endpoint with a curated set of tools.', 'agents.empty.initial.sub_community': 'Create your first agent to get a dedicated MCP endpoint with a focused toolset.', 'agents.empty.initial.next_step': 'After creating an agent, issue an API key for it on the API Keys page.', 'agents.empty.search.title': 'No agents match "{query}"', 'agents.empty.search.sub': 'Try a different search term.', 'agents.card.tools': 'tools', 'agents.card.keys': 'keys', 'agents.card.calls_today': 'calls today', 'agents.card.created': 'Created {date}', 'agents.card.revision': 'Draft v{draft} · Published v{published} · Catalog rev {revision}', 'agents.card.copy_endpoint': 'Copy endpoint', 'agents.card.endpoint_help': 'Set this endpoint in the MCP client together with the API key.', 'agents.card.endpoint_help_community': 'Set this endpoint in the MCP client together with the API key.', 'agents.action.edit': 'Edit', 'agents.action.archive': 'Archive', 'agents.action.delete': 'Delete', 'agents.lifecycle.publish': 'Publish', 'agents.lifecycle.unpublish': 'Unpublish', 'agents.lifecycle.restore_draft': 'Restore draft', 'agents.lifecycle.published': 'Published', 'agents.lifecycle.archived': 'Archived', 'agents.lifecycle.draft': 'Draft', 'agents.drawer.new_title': 'New agent', 'agents.drawer.edit_title': 'Edit agent', 'agents.drawer.new_sub': 'Describe the agent and select the MCP tools available to it.', 'agents.drawer.new_sub_community': 'Describe the agent and select the MCP tools available to it.', 'agents.drawer.edit_sub': 'Update agent settings and tool selection', 'agents.drawer.identity': 'Identity', 'agents.drawer.display_name': 'Display name', 'agents.drawer.slug': 'Slug', 'agents.drawer.description': 'Description', 'agents.drawer.optional': '(optional)', 'agents.drawer.required': 'required', 'agents.drawer.status': 'Status', 'agents.drawer.revision': 'Draft v{draft} · Published v{published} · Catalog rev {revision}', 'agents.drawer.endpoint': 'MCP endpoint', 'agents.drawer.slug_hint': 'Slug is used as part of the endpoint to identify the agent.', 'agents.drawer.placeholder.name': 'Customer Support', 'agents.drawer.placeholder.slug': 'customer-support', 'agents.drawer.placeholder.description': 'What does this agent do? What scenario is it for?', 'agents.drawer.operations': 'Operations', 'agents.drawer.selected': '{count} selected', 'agents.drawer.operations_sub': 'Select the MCP tools available to this agent.', 'agents.drawer.operations_sub_community': 'Select the MCP tools available to this agent.', 'agents.drawer.finding.title': 'Recommendation', 'agents.drawer.finding.too_many_tools': 'This agent has many tools. Use on-demand selection or keep only the tools needed for one concrete task.', 'agents.drawer.finding.similar_tools': 'Tools “{left}” and “{right}” look similar. Rename them more precisely or keep one of them.', 'agents.drawer.filter_ops': 'Filter operations…', 'agents.drawer.ops_no_match': 'No operations match "{query}"', 'agents.drawer.ops_selected': '{count} operations selected', 'agents.drawer.clear_all': 'Clear all', 'agents.drawer.recommendation': "You've selected {count} tools. Switch to on-demand selection so the model receives only relevant schemas.", 'agents.drawer.access.title': 'Tool access', 'agents.drawer.access.subtitle': "Choose how the model receives this agent's tool catalog.", 'agents.drawer.access.direct': 'Show tools immediately', 'agents.drawer.access.direct_hint': 'Best for a small curated catalog. MCP clients receive every tool in tools/list.', 'agents.drawer.access.search': 'Select tools on demand', 'agents.drawer.access.search_hint': 'The model sees search_tools and call_tool, then discovers only relevant schemas.', 'agents.drawer.groups.title': 'Catalog sections', 'agents.drawer.groups.subtitle': 'Sections help the model narrow a search without blocking catalog-wide discovery.', 'agents.drawer.groups.add': 'Add section', 'agents.drawer.groups.empty': 'No sections yet. Search will use the entire selected catalog.', 'agents.drawer.groups.untitled': 'Untitled section', 'agents.drawer.groups.remove': 'Remove section', 'agents.drawer.groups.name': 'Name', 'agents.drawer.groups.name_placeholder': 'Finance', 'agents.drawer.groups.id': 'Identifier', 'agents.drawer.groups.description': 'Description for the model', 'agents.drawer.groups.description_placeholder': 'Invoices, payments and refunds', 'agents.drawer.groups.assign': 'Assign tools to sections', 'agents.drawer.search.limit': 'Maximum results per search', 'agents.drawer.search.preview_title': 'Test tool selection', 'agents.drawer.search.preview_subtitle': 'Enter a task and verify which tools the model will receive.', 'agents.drawer.search.query_placeholder': 'Create an invoice for a customer', 'agents.drawer.search.all_groups': 'All sections', 'agents.drawer.search.test': 'Test', 'agents.drawer.search.testing': 'Testing…', 'agents.drawer.search.no_results': 'No preview results yet.', 'agents.drawer.search.preview_error': 'Failed to test tool selection', 'agents.drawer.search.preview_error_title': 'Tool selection test failed', 'agents.drawer.cancel': 'Cancel', 'agents.drawer.create': 'Create agent', 'agents.drawer.save': 'Save changes', 'agents.toast.saved_title_create': 'Agent created', 'agents.toast.saved_title_update': 'Agent updated', 'agents.toast.saved_message': '{name} was saved with {count} tool bindings.', 'agents.toast.save_error_title': 'Agent update failed', 'agents.toast.save_error_message': 'Failed to save agent', 'agents.toast.delete_confirm': 'Delete this agent? This cannot be undone.', 'agents.toast.delete_title': 'Agent deleted', 'agents.toast.delete_message': '{name} was deleted.', 'agents.toast.delete_error_title': 'Delete failed', 'agents.toast.delete_error_message': 'Failed to delete agent', 'agents.toast.delete_forbidden_message': 'Published agents cannot be deleted. Archive or unpublish the agent first.', 'agents.toast.lifecycle_title': 'Agent lifecycle updated', 'agents.toast.lifecycle_publish_confirm': 'Publish {name}? The published MCP catalog will change.', 'agents.toast.lifecycle_unpublish_confirm': 'Unpublish {name}? Existing MCP clients will no longer see this agent catalog.', 'agents.toast.lifecycle_archive_confirm': 'Archive {name}? New publications and bindings will be blocked.', 'agents.toast.lifecycle_publish': '{name} was published.', 'agents.toast.lifecycle_unpublish': '{name} was returned to draft.', 'agents.toast.lifecycle_archive': '{name} was archived.', 'agents.toast.lifecycle_error_title': 'Lifecycle update failed', 'agents.toast.lifecycle_error_message': 'Failed to update agent lifecycle', 'agents.toast.stale_message': 'Agent changed in another request. Reload the drawer and retry.', 'agents.toast.endpoint_title': 'MCP endpoint copied', // Demo content 'demo.agent.currency-rates.display_name': 'Currency rates', 'demo.operation.frankfurter_latest_rate.display_name': 'Latest currency rate', 'demo.operation.frankfurter_latest_rate.description': 'Returns the latest available exchange rate through Frankfurter.', // Login 'login.title': 'Sign in', 'login.subtitle': 'Welcome back to your workspace', 'login.email': 'Email', 'login.password': 'Password', 'login.submit': 'Sign in', 'login.email_label': 'Email address', 'login.email_placeholder': 'you@acme.com', 'login.password_only': 'Sign in with email and password.', 'login.bootstrap.title': 'Create admin account', 'login.bootstrap.subtitle': 'Complete local first-run bootstrap', 'login.bootstrap.note': 'Enter the one-time token generated by crank-migrate and choose the first admin password.', // community-scope: allow=one-time-token 'login.bootstrap.token_label': 'Bootstrap token', 'login.bootstrap.token_placeholder': 'Paste one-time bootstrap token', // community-scope: allow=one-time-token 'login.bootstrap.submit': 'Create admin', 'login.loading': 'Signing in…', 'login.success': 'Signed in. Redirecting…', 'login.bootstrap.loading': 'Creating admin…', 'login.bootstrap.success': 'Admin account created. Redirecting…', 'login.error.required': 'Please enter your email and password.', 'login.bootstrap.error.required': 'Please enter the bootstrap token and password.', 'login.error.invalid': 'Invalid email or password. Please try again.', 'login.error.throttled': 'Too many attempts. Please wait and try again.', 'login.error.expired_session': 'Your session expired. Please sign in again.', 'login.error.generic': 'Unable to sign in right now. Please try again.', 'login.error.request_id': 'Request ID', 'login.error.trace_id': 'Trace ID', }, ru: { // Nav 'nav.operations': 'Операции', 'nav.agents': 'Агенты', 'nav.apikeys': 'API Ключи', 'nav.secrets': 'Секреты', 'nav.logs': 'Логи', 'nav.usage': 'Использование', 'nav.settings': 'Настройки', 'nav.logout': 'Выйти', 'nav.workspaces': 'Ваши воркспейсы', 'nav.menu': 'Меню', 'nav.account': 'Аккаунт', 'nav.user_fallback': 'Crank', 'nav.workspace_fallback': 'workspace', 'onboarding.title': 'Начало работы', 'onboarding.subtitle': 'Возобновляемый путь к первому реальному вызову MCP-инструмента.', 'onboarding.loading': 'Проверяем подтверждённый прогресс…', 'onboarding.progress': 'Выполнено шагов: {count}/7', 'onboarding.error': 'Прогресс начала работы недоступен.', 'onboarding.retry': 'Повторить', 'onboarding.refresh': 'Обновить прогресс', 'onboarding.dismiss': 'Скрыть', 'onboarding.resume': 'Продолжить начало работы', 'onboarding.collapse': 'Свернуть чек-лист начала работы', 'onboarding.request_id': 'Request ID', 'onboarding.trace_id': 'Trace ID', 'onboarding.error_code': 'Код ошибки', 'onboarding.progress_label': 'Прогресс начала работы', 'onboarding.action_needed': 'Это следующий доступный шаг.', 'onboarding.regressed': 'Связанный объект изменился. Проверьте его и продолжите снова.', 'onboarding.completed': 'Первый публичный вызов MCP-инструмента выполнен.', 'onboarding.open_invocation': 'Открыть историю вызова', 'onboarding.tool': 'Инструмент', 'onboarding.timestamp': 'Время вызова', 'onboarding.deep_link_stale': 'Эта ссылка начала работы относится к изменённой операции или агенту. Сбросьте её и выберите актуальную опубликованную ревизию.', 'onboarding.reselect': 'Сбросить и выбрать заново', 'onboarding.step.operation': 'Создать операцию', 'onboarding.step.test': 'Протестировать операцию', 'onboarding.step.publish_operation': 'Опубликовать операцию', 'onboarding.step.agent': 'Создать и опубликовать агента', 'onboarding.step.key': 'Создать ключ MCP-клиента', 'onboarding.step.mcp_connection': 'Подключить MCP-клиент', 'onboarding.step.first_call': 'Выполнить первый вызов', 'onboarding.action.operation': 'Создать операцию', 'onboarding.action.test': 'Открыть тест', 'onboarding.action.publish_operation': 'Открыть публикацию', 'onboarding.action.agent': 'Создать агента', 'onboarding.action.key': 'Создать ключ', 'onboarding.action.mcp_connection': 'Показать подключение', 'onboarding.action.first_call': 'Открыть логи', // Operations page 'ops.title': 'Операции', 'ops.subtitle': 'Каталог инструментов. Список созданных MCP инструментов на API эндпоинты.', 'ops.new': 'Новая операция', 'ops.loading': 'Загрузка операций…', 'ops.empty.title': 'Операции не найдены', 'ops.empty.sub': 'Попробуйте изменить поисковый запрос или фильтры.', 'ops.empty.initial.title': 'Операций пока нет', 'ops.empty.initial.sub': 'Создайте первую операцию в этом воркспейсе, чтобы открыть живой MCP-инструмент.', 'ops.error.title': 'Не удалось подключиться к серверу', 'ops.delete.confirm': 'Удалить эту операцию? Действие нельзя отменить.', 'ops.delete.success.title': 'Операция удалена', 'ops.delete.success.message': 'Операция {name} удалена.', 'ops.delete.error.title': 'Не удалось удалить', 'ops.delete.error.message': 'Не удалось удалить операцию', 'ops.action.edit': 'Редактировать операцию', 'ops.action.delete':'Удалить операцию', 'ops.action.archive': 'Архивировать операцию', 'ops.archive.confirm': 'Архивировать операцию? Существующие опубликованные снимки агентов останутся доступны, но новые публикации и привязки будут запрещены.', 'ops.archive.success.title': 'Операция архивирована', 'ops.archive.success.message': 'Операция {name} архивирована.', 'ops.archive.error.title': 'Не удалось архивировать', 'ops.archive.error.message': 'Не удалось архивировать операцию', 'ops.stats.synced': 'Каталог синхронизирован с сервером', 'ops.stats.none': 'Операций пока нет', 'ops.stats.share': '{value}% от общего числа', 'ops.stats.no_published': 'Опубликованных инструментов пока нет', 'ops.stats.requests_rollup': 'Сумма по статистике операций', 'ops.stats.no_traffic': 'Трафик сегодня не зафиксирован', 'ops.stats.latency_weighted': 'Взвешено по сегодняшним вызовам', 'ops.stats.latency_waiting': 'Ожидание runtime-метрик', 'ops.results': 'Показано {shown} из {total}', 'ops.range': 'Показано {from}–{to} из {total} операций', 'ops.filter.category': 'Категория: {value}', 'ops.filter.agent': 'Агент: {value}', 'ops.no_active_agents': 'Нет активных агентов', // Stats 'stats.total': 'Всего операций', 'stats.active': 'Активные', 'stats.requests': 'Запросов сегодня', 'stats.latency': 'Ср. задержка', // Tabs 'tab.all': 'Все', 'tab.active': 'Активные', 'tab.draft': 'Черновик', 'tab.error': 'Ошибка', 'tab.inactive': 'Неактивные', // Filters & sort 'filter.search': 'Поиск операций...', 'filter.status': 'Статус', 'filter.category': 'Категория', 'filter.agent': 'Агент', 'filter.showing': 'Показано', 'filter.of': 'из', 'filter.clear': 'Сбросить', 'filter.clear_all': 'Сбросить все', 'filter.remove': 'Убрать фильтр', 'sort.created_desc':'Сначала новые', 'sort.created_asc': 'Сначала старые', 'sort.name_asc': 'Название А–Я', 'sort.name_desc': 'Название Я–А', // Table headers 'th.name': 'НАЗВАНИЕ', 'th.protocol': 'ПРОТОКОЛ', 'th.status': 'СТАТУС', 'th.created': 'СОЗДАН', 'th.url': 'ЦЕЛЕВОЙ URL', // Pagination 'page.showing': 'Показано', 'page.of': 'из', 'page.ops': 'операций', // API Keys page 'apikeys.title': 'Ключи агентов', 'apikeys.subtitle': 'Эти ключи используются для подключения MCP клиента к MCP серверу и выдаются на конкретного агента.', 'apikeys.new': 'Создать ключ', 'apikeys.new_mcp': 'Создать ключ MCP-клиента', 'apikeys.new_approval': 'Создать ключ подтверждения', 'apikeys.kind.mcp': 'MCP-клиенты', 'apikeys.kind.approval': 'Подтверждения', 'apikeys.kind.mcp_hint': 'Ключи MCP-клиентов используются для подключения к tools/list и tools/call агента.', 'apikeys.kind.approval_hint': 'Ключи подтверждения используются только внешним интерфейсом, где человек подтверждает действие.', 'apikeys.agent.title': 'Выбор агента', 'apikeys.agent.subtitle': 'Выберите AI-агента для которого выпускается ключ.', 'apikeys.agent.label': 'AI-агент', 'apikeys.agent.empty': 'Агенты отсутствуют', 'apikeys.agent.empty_hint': 'Сначала создайте AI-агента, затем выпустите машинный ключ для его MCP endpoint.', 'apikeys.agent.endpoint': 'MCP endpoint: {endpoint}', 'apikeys.agent.endpoint_missing': 'У выбранного агента пока нет опубликованного MCP endpoint.', 'apikeys.th.name': 'НАЗВАНИЕ', 'apikeys.th.scope': 'ДОСТУП', 'apikeys.th.created':'СОЗДАН', 'apikeys.th.last': 'ПОСЛЕДНЕЕ ИСПОЛЬЗОВАНИЕ', 'apikeys.callout.title': 'Ключ показывается только один раз.', 'apikeys.callout.body': 'Скопируйте и сохраните ключ сразу после создания — Crank хранит только хэш. Поле «Последнее использование» обновляется после успешного MCP-вызова.', 'apikeys.active.title': 'Активные ключи', 'apikeys.active.subtitle': '{active} активных · {revoked} отозванных', 'apikeys.search': 'Фильтр ключей…', 'apikeys.th.prefix': 'ПРЕФИКС КЛЮЧА', 'apikeys.th.scopes': 'ДОСТУПЫ', 'apikeys.th.status': 'СТАТУС', 'apikeys.scope_ref': 'Справка по доступам', 'apikeys.scope.read': 'Инициализация MCP-сессий, ping сервера и получение списка инструментов для выбранного AI-агента.', 'apikeys.scope.write': 'Выполнение `tools/call` для опубликованных наборов инструментов агента.', 'apikeys.scope.deploy': 'Зарезервировано для deploy-автоматизации. Сейчас также разрешает MCP read/write сценарии.', 'apikeys.scope.approve': 'Подтверждение ожидающего запроса для этого агента.', 'apikeys.scope.deny': 'Отклонение ожидающего запроса для этого агента.', 'apikeys.scope.read_pending': 'Получение списка запросов, ожидающих подтверждения для этого агента.', 'apikeys.modal.title': 'Создать ключ агента', 'apikeys.modal.title_mcp': 'Создать ключ MCP-клиента', 'apikeys.modal.title_approval': 'Создать ключ подтверждения', 'apikeys.modal.name': 'Имя ключа', 'apikeys.modal.name_hint': 'Понятная метка для идентификации ключа. Видна только администраторам.', 'apikeys.modal.name_placeholder': 'например, Production, CI pipeline', 'apikeys.modal.scopes': 'Доступы', 'apikeys.modal.reveal_title': 'Скопируйте ключ сейчас.', 'apikeys.modal.reveal_body': 'Повторно он не будет показан.', 'apikeys.modal.copy': 'Скопировать', 'apikeys.modal.copy_config': 'Скопировать конфигурацию', 'apikeys.modal.connection_title': 'Конфигурация MCP-подключения', 'apikeys.modal.clipboard_warning': 'Системный буфер обмена находится вне контроля Crank. Очистите его после сохранения ключа.', 'apikeys.onboarding.key_lost': 'Ключ нельзя показать повторно. Создайте новый ключ и отзовите старый, если значение не было сохранено.', 'apikeys.modal.cancel': 'Отмена', 'apikeys.modal.create': 'Создать ключ', 'apikeys.modal.done': 'Готово — ключ скопирован', 'apikeys.status.active': 'Активен', 'apikeys.status.revoked': 'Отозван', 'apikeys.status.deleted': 'Удален', 'apikeys.last_used.never': 'Никогда', 'apikeys.empty.none': 'API-ключей пока нет', 'apikeys.empty.approval': 'Ключей подтверждения пока нет. Они нужны только агентам с инструментами, требующими подтверждения человеком.', 'apikeys.empty.search': 'Нет ключей по текущему поиску', 'apikeys.loading': 'Загрузка…', 'apikeys.error.api': 'Воркспейс или API недоступен', 'apikeys.error.load': 'Не удалось загрузить API-ключи', 'apikeys.confirm.revoke': 'Отозвать этот ключ? Все запросы с ним сразу начнут падать.', 'apikeys.confirm.delete': 'Удалить этот ключ? Действие нельзя отменить.', 'apikeys.toast.revoke_title': 'Ключ отозван', 'apikeys.toast.revoke_message': 'Ключ {name} отозван.', 'apikeys.toast.revoke_error_title': 'Не удалось отозвать', 'apikeys.toast.revoke_error_message': 'Не удалось отозвать ключ', 'apikeys.toast.delete_title': 'Ключ удален', 'apikeys.toast.delete_message': 'Ключ {name} удален.', 'apikeys.toast.delete_error_title': 'Не удалось удалить', 'apikeys.toast.delete_error_message': 'Не удалось удалить ключ', 'apikeys.toast.scope_missing_title': 'Не выбран доступ', 'apikeys.toast.scope_missing_message': 'Выберите хотя бы один доступ перед созданием ключа.', 'apikeys.toast.create_title': 'Ключ агента создан', 'apikeys.toast.create_message': 'Скопируйте ключ сейчас. Повторно он не будет показан.', 'apikeys.toast.create_error_title': 'Не удалось создать ключ', 'apikeys.toast.create_error_message': 'Не удалось создать ключ', 'apikeys.toast.copy_title': 'Ключ агента скопирован', 'apikeys.toast.copy_message': 'Сохраните исходный ключ в надежном месте. Повторно показать его нельзя.', 'apikeys.toast.copy_error_title': 'Не удалось записать в буфер обмена', 'apikeys.toast.copy_error_message': 'Одноразовое значение всё ещё показано. Скопируйте его вручную до закрытия страницы.', 'apikeys.toast.prefix_title': 'Префикс ключа скопирован', 'apikeys.action.copy_prefix': 'Скопировать префикс ключа', 'apikeys.action.revoke': 'Отозвать ключ', 'apikeys.action.delete': 'Удалить', 'apikeys.creating': 'Создание…', 'apikeys.approval.warning': 'Не передавайте этот ключ LLM или MCP-клиенту. Он нужен только внешнему интерфейсу, где человек подтверждает действие.', 'apikeys.ambiguous.title': 'Результат создания неизвестен.', 'apikeys.ambiguous.body': 'Метаданные ключей обновлены. Проверьте список перед осознанным созданием ещё одного ключа.', 'apikeys.ambiguous.retry': 'Обновить метаданные и разрешить новую попытку', 'apikeys.ambiguous.blocked': 'Проверьте метаданные перед повтором', // Secrets page 'secrets.title': 'Секреты', 'secrets.subtitle': 'Данные для авторизации на конечных API хостах.', 'secrets.new': 'Создать секрет', 'secrets.callout.title': 'Значения секретов защищены.', 'secrets.callout.body': 'После сохранения секреты шифруются ключом воркспейса и недоступны для чтения. Секрет можно ротировать или удалить.', 'secrets.active.title': 'Секреты воркспейса', 'secrets.active.subtitle': '{active} активных · {total} всего', 'secrets.search': 'Фильтр секретов…', 'secrets.th.name': 'НАЗВАНИЕ', 'secrets.th.kind': 'ТИП', 'secrets.th.version': 'ВЕРСИЯ', 'secrets.th.last_used': 'ПОСЛЕДНЕЕ ИСПОЛЬЗОВАНИЕ', 'secrets.th.used_by': 'ИСПОЛЬЗУЕТСЯ В', 'secrets.th.status': 'СТАТУС', 'secrets.kind.token': 'Токен', 'secrets.kind.username_password': 'Логин/пароль', 'secrets.kind.header': 'Значение заголовка', 'secrets.kind.generic': 'Общий JSON', 'secrets.status.active': 'Активен', 'secrets.status.disabled': 'Отключен', 'secrets.last_used.never': 'Никогда', 'secrets.used_by_count.one': '{count} привязка', 'secrets.used_by_count.few': '{count} привязки', 'secrets.used_by_count.many': '{count} привязок', 'secrets.used_by_count.other': '{count} привязки', 'secrets.loading': 'Загрузка…', 'secrets.empty.none': 'Секретов пока нет', 'secrets.empty.search': 'Нет секретов по текущему поиску', 'secrets.error.workspace': 'Воркспейс не выбран', 'secrets.error.load': 'Не удалось загрузить секреты', 'secrets.action.rotate': 'Ротировать', 'secrets.action.delete': 'Удалить', 'secrets.confirm.delete': 'Удалить секрет {name}? Это нельзя сделать, пока секрет используется в операции.', 'secrets.toast.create_title': 'Секрет создан', 'secrets.toast.create_message': 'Секрет сохранен в зашифрованном виде. Повторно посмотреть значение нельзя.', 'secrets.toast.create_error_title': 'Не удалось создать секрет', 'secrets.toast.create_error_message': 'Не удалось создать секрет', 'secrets.toast.rotate_title': 'Секрет ротирован', 'secrets.toast.rotate_message': 'Новая версия секрета теперь активна.', 'secrets.toast.rotate_error_title': 'Не удалось ротировать секрет', 'secrets.toast.rotate_error_message': 'Не удалось ротировать секрет', 'secrets.toast.delete_title': 'Секрет удален', 'secrets.toast.delete_message': 'Секрет {name} удален.', 'secrets.toast.delete_error_title': 'Не удалось удалить секрет', 'secrets.toast.delete_error_message': 'Не удалось удалить секрет', 'secrets.modal.create_title': 'Создать секрет', 'secrets.modal.rotate_title': 'Ротировать секрет', 'secrets.modal.name': 'Имя секрета', 'secrets.modal.name_hint': 'Укажите понятное имя, чтобы потом выбрать этот секрет в настройках операции.', 'secrets.modal.kind': 'Тип секрета', 'secrets.modal.value': 'Значение токена', 'secrets.modal.header_value': 'Значение заголовка', 'secrets.modal.username': 'Логин', 'secrets.modal.password': 'Пароль', 'secrets.modal.json_payload': 'JSON', 'secrets.modal.json_hint': 'Введите валидный JSON. Используйте этот тип, если API требует несколько связанных значений.', 'secrets.modal.create_note': 'После сохранения значение будет зашифровано и больше не будет отображаться.', 'secrets.modal.rotate_note': 'Ротация заменит сохраненное значение новой зашифрованной версией.', 'secrets.modal.cancel': 'Отмена', 'secrets.modal.create_action': 'Создать секрет', 'secrets.modal.rotate_action': 'Ротировать секрет', 'secrets.modal.creating': 'Создание…', 'secrets.modal.rotating': 'Ротация…', 'secrets.hint.token': 'Для bearer token, API key или другого одиночного токена.', 'secrets.hint.username_password': 'Для авторизации по логину и паролю.', 'secrets.hint.header': 'Для значения, которое будет передаваться в HTTP-заголовке.', 'secrets.hint.generic': 'Для структурированных данных в JSON.', 'secrets.validation.name_required': 'Нужно указать имя секрета.', 'secrets.validation.value_required': 'Нужно указать значение секрета.', 'secrets.validation.username_password_required': 'Нужно указать и логин, и пароль.', 'secrets.validation.json_invalid': 'Значение JSON должно быть валидным.', // Logs page 'logs.title': 'Логи', 'logs.subtitle': 'Журнал вызовов по всем операциям этого воркспейса.', 'logs.search': 'Поиск в логах...', 'logs.level.all': 'Все', 'logs.level.info': 'Info', 'logs.level.warn': 'Warn', 'logs.level.error': 'Error', 'logs.level.debug': 'Debug', 'logs.live': 'Live', 'logs.paused': 'Пауза', 'logs.refresh': 'Обновить', 'logs.export': 'Экспорт CSV', 'logs.load_more': 'Загрузить ещё', 'logs.status_filter': 'Статус', 'logs.status.all': 'Все статусы', 'logs.status.ok': 'Успех', 'logs.status.error': 'Ошибка', 'logs.outcome_filter': 'Результат', 'logs.outcome.all': 'Все результаты', 'logs.filter.operation': 'ID операции', 'logs.filter.agent': 'ID агента', 'logs.range.30m': 'Последние 30 мин', 'logs.range.1h': 'Последний час', 'logs.range.6h': 'Последние 6 часов', 'logs.range.24h': 'Последние 24 часа', 'logs.range.7d': 'Последние 7 дней', 'logs.search_messages': 'Поиск по сообщениям…', 'logs.detail.agent': 'Агент', 'logs.detail.request': 'Предпросмотр запроса', 'logs.detail.response': 'Предпросмотр ответа', 'logs.detail.meta': 'Метаданные', 'logs.loading.title': 'Загрузка логов…', 'logs.loading.sub': 'Получаем историю вызовов для текущего воркспейса.', 'logs.error.title': 'Не удалось загрузить логи', 'logs.error.api': 'Admin API недоступен', 'logs.error.workspace': 'Воркспейс не выбран', 'logs.error.load': 'Не удалось загрузить логи', 'logs.empty.title': 'Записей логов не найдено', 'logs.empty.filtered': 'Попробуйте расширить период или сбросить текущий поиск и фильтры уровня.', 'logs.empty.initial': 'Запустите тесты или опубликованные MCP-инструменты, чтобы начать собирать историю вызовов.', 'logs.live.on.title': 'Live режим включен', 'logs.live.on.body': 'Логи опрашиваются каждые 4 секунды.', 'logs.live.off.title': 'Live режим на паузе', 'logs.live.off.body': 'Автоматический опрос остановлен.', 'logs.refresh.title': 'Логи обновлены', 'logs.refresh.body': 'Получены последние записи вызовов для текущего воркспейса.', 'logs.export.done_title': 'Логи экспортированы', 'logs.export.done_body': 'Отфильтрованная история вызовов экспортирована в CSV.', 'logs.export.error_title': 'Не удалось экспортировать', 'logs.export.error_body': 'Не удалось экспортировать историю вызовов.', 'approvals.title': 'Подтверждения человеком', 'approvals.subtitle': 'Заявки, которые ожидают решения пользователя, и последние результаты.', 'approvals.refresh': 'Обновить', 'approvals.refresh.title': 'Подтверждения обновлены', 'approvals.refresh.body': 'Получены последние заявки на подтверждение.', 'approvals.loading': 'Загрузка заявок на подтверждение…', 'approvals.empty': 'Заявок на подтверждение пока нет.', 'approvals.error.load': 'Не удалось загрузить заявки на подтверждение', 'approvals.error.decision': 'Не удалось отправить решение по заявке', 'approvals.untitled': 'Заявка на подтверждение', 'approvals.operation': 'Операция', 'approvals.agent': 'Агент', 'approvals.expires_at': 'Истекает', 'approvals.updated_at': 'Обновлено', 'approvals.request': 'Запрос', 'approvals.response': 'Результат', 'approvals.request_id': 'Request ID', 'approvals.trace_id': 'Trace ID', 'approvals.action.approve': 'Подтвердить', 'approvals.action.deny': 'Отклонить', 'approvals.action.busy': 'Отправка…', 'approvals.confirm.approve': 'Подтвердить эту заявку?', 'approvals.confirm.deny': 'Отклонить эту заявку?', 'approvals.status.pending': 'Ожидает', 'approvals.status.approved': 'Подтверждено', 'approvals.status.denied': 'Отклонено', 'approvals.status.expired': 'Истекло', 'approvals.status.completed': 'Выполнено', 'approvals.status.failed': 'Ошибка', // Usage page 'usage.title': 'Использование', 'usage.subtitle': 'Метрики вызовов по всем операциям этого воркспейса.', 'usage.export': 'Экспорт CSV', 'usage.period.7d': 'Последние 7 дней', 'usage.period.30d': 'Последние 30 дней', 'usage.period.90d': 'Последние 90 дней', 'usage.period.this_month': 'Этот месяц', 'usage.period.label.7d': 'последние 7 дней', 'usage.period.label.30d': 'последние 30 дней', 'usage.period.label.90d': 'последние 90 дней', 'usage.period.label.this_month': 'этот месяц', 'usage.stats.total': 'Всего вызовов', 'usage.stats.success': 'Доля успешных', 'usage.stats.p50': 'Медианная задержка (p50)', 'usage.stats.p99': 'Задержка p99', 'usage.stats.across': 'За период: {period}', 'usage.stats.success_calls': 'Успешных вызовов: {count}', 'usage.stats.median': 'Медианная задержка за выбранный период', 'usage.stats.error_calls': 'Ошибочных вызовов: {count}', 'usage.chart.title': 'Вызовы во времени', 'usage.chart.success': 'Успех', 'usage.chart.error': 'Ошибка', 'usage.chart.empty.title': 'Данных по использованию пока нет', 'usage.chart.empty.sub': 'Метрики появятся здесь после тестов или вызовов опубликованных инструментов за выбранный период.', 'usage.outcomes.title': 'Исходы', 'usage.outcomes.subtitle': 'Группировка по безопасному исходу выполнения.', 'usage.outcomes.empty.title': 'Разбивки по исходам пока нет', 'usage.outcomes.empty.sub': 'Группы исходов появятся после записи вызовов.', 'usage.outcomes.p50': 'p50', 'usage.outcomes.p95': 'p95', 'usage.outcomes.p99': 'p99', 'usage.outcome.success': 'Успех', 'usage.outcome.upstream': 'Upstream', 'usage.outcome.client': 'Клиент', 'usage.outcome.schema': 'Схема', 'usage.outcome.crank': 'Crank', 'usage.outcome.no_error_code': 'Без error code', 'usage.table.title': 'По операциям', 'usage.table.subtitle': 'Разбивка за период: {period}', 'usage.table.th.operation': 'Операция', 'usage.table.th.protocol': 'Протокол', 'usage.table.th.calls': 'Вызовы', 'usage.table.th.errors': 'Ошибки', 'usage.table.th.error_rate': 'Доля ошибок', 'usage.table.th.latency': 'Задержка (p50 / p95 / p99)', 'usage.table.th.share': 'Доля трафика', 'usage.table.empty.title': 'Разбивки по операциям пока нет', 'usage.table.empty.sub': 'За выбранный период нет вызовов, которые можно разложить по операциям.', 'usage.table.share': '{value}% трафика воркспейса', 'usage.loading.title': 'Загрузка использования…', 'usage.loading.sub': 'Собираем метрики вызовов для выбранного воркспейса.', 'usage.error.title': 'Не удалось загрузить использование', 'usage.error.api': 'Admin API недоступен', 'usage.error.workspace': 'Воркспейс не выбран', 'usage.error.load': 'Не удалось загрузить метрики использования', 'usage.export.empty.title': 'Данные по использованию не загружены', 'usage.export.empty.body': 'Сначала загрузите данные использования, а потом экспортируйте снимок CSV.', 'usage.export.done.title': 'Использование экспортировано', 'usage.export.done.body': 'Отфильтрованный набор использования экспортирован в CSV.', 'usage.export.error.title': 'Не удалось экспортировать', 'usage.export.error.body': 'Не удалось экспортировать данные использования.', 'usage.chart.ok': 'Успешных: {count}', 'usage.chart.errors': 'Ошибок: {count}', 'usage.chart.week': 'Нед. {index}', 'usage.csv.header': 'Операция,Протокол,Вызовы,Ошибки,Доля ошибок (%),p50 (мс),p95 (мс),p99 (мс)', // Settings sidebar 'settings.title': 'Настройки', 'settings.nav.workspace': 'Воркспейс', 'settings.nav.profile': 'Профиль', 'settings.nav.security': 'Безопасность', 'settings.nav.danger': 'Опасная зона', // Settings — workspace section 'settings.ws.title': 'Настройки воркспейса', 'settings.ws.subtitle': 'Общая информация о вашем воркспейсе', 'settings.ws.name': 'Имя воркспейса', 'settings.ws.display': 'Отображаемое имя', 'settings.ws.desc': 'Описание', // Settings — language 'settings.lang.title': 'Язык', 'settings.lang.subtitle': 'Язык отображения интерфейса', 'settings.lang.en': 'English', 'settings.lang.ru': 'Русский', // Settings — profile section 'settings.profile.title': 'Профиль', 'settings.profile.name': 'Полное имя', 'settings.profile.email': 'Email', 'settings.profile.role': 'Роль', 'settings.page.title': 'Настройки аккаунта', 'settings.ws.slug_hint': 'Используется в API endpoint-ах и в интерфейсе. Допустимы только английские строчные буквы, цифры и дефисы.', 'settings.ws.description_optional': 'Описание (необязательно)', 'settings.ws.description_placeholder': 'Какие задачи выполняет воркспейс?', 'settings.profile.avatar_hint': 'Аватар строится из отображаемого имени и email.', 'settings.profile.first_name': 'Имя', 'settings.profile.last_name': 'Фамилия', 'settings.profile.last_name_placeholder': 'Необязательно', 'settings.profile.email_label': 'Email адрес', 'settings.profile.email_hint': 'Изменение email обновляет логин для текущего аккаунта.', 'settings.profile.save': 'Сохранить профиль', 'settings.profile.saving': 'Сохранение…', 'settings.profile.saved': 'Сохранено ✓', 'settings.profile.saved_status': 'Профиль сохранен.', 'settings.profile.save_error': 'Не удалось сохранить профиль', 'settings.security.title': 'Безопасность', 'settings.security.current_password': 'Текущий пароль', 'settings.security.new_password': 'Новый пароль', 'settings.security.new_password_placeholder': 'минимум 12 символов', 'settings.security.confirm_password': 'Подтвердите новый пароль', 'settings.security.change_password': 'Сменить пароль', 'settings.security.mismatch': 'Новый пароль и подтверждение не совпадают.', 'settings.security.saved': 'Пароль обновлен.', 'settings.security.saved_relogin': 'Пароль обновлен. Войдите снова.', 'settings.security.save_error': 'Не удалось изменить пароль', 'settings.capability.rest': 'REST / HTTP', 'settings.capability.standard': 'standard', 'settings.capability.elevated': 'elevated', 'settings.capability.strict': 'strict', 'settings.capability.static_agent_key': 'статические ключи агентов', 'settings.capability.unlimited': 'без лимита', 'settings.capability.none': 'нет', 'settings.session.title': 'Текущая сессия', 'settings.session.browser': 'Сессия браузера', 'settings.session.current': 'текущая', 'settings.session.loading': 'Загрузка деталей текущей сессии…', 'settings.session.unavailable': 'Детали сессии недоступны. Используйте «Выйти», чтобы отозвать текущую browser session.', 'settings.session.current_workspace': 'текущий воркспейс', 'settings.session.summary': '{email} · {role} в {workspace}. Используйте «Выйти», чтобы отозвать текущую browser session.', 'settings.planned_badge': 'Запланировано', 'settings.workspace.saving': 'Сохранение…', 'settings.workspace.saved': 'Сохранено ✓', 'settings.workspace.save_error': 'Не удалось сохранить настройки воркспейса', 'settings.workspace.save_error_title': 'Не удалось сохранить воркспейс', // Workspace setup 'workspace_setup.title': 'Настройки воркспейса', 'workspace_setup.page_subtitle': 'Настройте идентичность вашего self-hosted воркспейса.', 'workspace_setup.back': 'Назад', 'workspace_setup.identity.title': 'Идентичность воркспейса', 'workspace_setup.identity.avatar_hint': 'Аватар формируется из имени воркспейса.', 'workspace_setup.name': 'Имя воркспейса', 'workspace_setup.slug': 'Slug', 'workspace_setup.required': 'обязательно', 'workspace_setup.optional': '(необязательно)', 'workspace_setup.slug_hint': 'Только строчные буквы, цифры и дефисы. Используется в URL MCP endpoint-ов.', 'workspace_setup.description': 'Описание', 'workspace_setup.description_placeholder': 'Какие задачи выполняет воркспейс?', 'workspace_setup.actions.save': 'Сохранить изменения', 'workspace_setup.create.title': 'Создать новый воркспейс', 'workspace_setup.create.subtitle': 'В Community используется один воркспейс для MCP-операций и агентов.', 'workspace_setup.create.footer': 'В Community используется один воркспейс.', 'workspace_setup.danger.title': 'Опасная зона', 'workspace_setup.danger.export_title': 'Экспорт каталога рабочего пространства', 'workspace_setup.danger.export_body': 'Скачать невосстанавливаемый JSON-каталог настроек рабочего пространства, сводок операций и агентов, а также метаданных ключей API.', 'workspace_setup.export': 'Экспорт', 'workspace_setup.role.owner': 'Владелец', 'workspace_setup.role.admin': 'Администратор', 'workspace_setup.role.operator': 'Разработчик', 'workspace_setup.role.viewer': 'Наблюдатель', 'workspace_setup.saving_create': 'Создание…', 'workspace_setup.saving_update': 'Сохранение…', 'workspace_setup.saved': 'Сохранено ✓', 'workspace_setup.save_error': 'Не удалось сохранить воркспейс', 'workspace_setup.save_error_title': 'Не удалось сохранить', 'workspace_setup.export_error': 'Не удалось экспортировать воркспейс', 'workspace_setup.export_error_title': 'Не удалось экспортировать', 'workspace.switch_error': 'Не удалось переключить воркспейс', 'workspace.switch_error_title': 'Не удалось переключить воркспейс', 'workspace_setup.custom_protocol.rest': 'REST', // Wizard 'wizard.back_catalog': 'Операции', 'wizard.progress.create': 'Создать операцию', 'wizard.progress.edit': 'Редактировать операцию', 'wizard.exit': 'Выйти из мастера', 'wizard.step_of': 'Шаг {step} из {total}', 'wizard.step_short': 'Шаг {step}', 'wizard.status.completed': 'Завершено', 'wizard.status.in_progress': 'В процессе', 'wizard.status.not_started': 'Не начато', 'wizard.help.title': 'Нужна помощь?', 'wizard.help.body': 'Не уверены, какой протокол выбрать? Откройте', 'wizard.help.link': 'гайд по сравнению протоколов →', 'wizard.progress.section': 'Прогресс', 'wizard.step_name.protocol': 'Протокол', 'wizard.step_name.upstream': 'API-хост', 'wizard.step_name.tool': 'Настройки инструмента', 'wizard.step_name.mapping': 'Связи полей', 'wizard.button.back': 'Назад', 'wizard.button.continue': 'Продолжить', 'wizard.button.save_draft': 'Сохранить черновик', 'wizard.button.create': 'Создать операцию', 'wizard.button.save_changes': 'Сохранить изменения', 'wizard.sidebar.brand.create': 'Создать операцию', 'wizard.sidebar.brand.edit': 'Редактировать операцию', 'wizard.step1.title': 'Выберите протокол', 'wizard.step1.subtitle': 'Выберите протокол вашего API. От этого зависит, как Crank будет выполнять запросы и какие настройки будут доступны на следующих шагах.', 'wizard.step1.rest_name': 'REST / HTTP', 'wizard.step1.rest_tagline': 'Стандартные HTTP-методы для REST API. Самый универсальный вариант.', 'wizard.step1.query': 'Query', 'wizard.step1.mutation': 'Mutation', 'wizard.step1.unary': 'Unary', 'wizard.step1.tip_title': 'Это можно изменить позже', 'wizard.step1.tip_body': 'Если сменить протокол после настройки следующих шагов, схемы и связи полей будут очищены. Перед экспериментами сохраните операцию.', 'wizard.step1.community_protocol_title': 'Граница протоколов Community', 'wizard.step5.streaming_title': 'Потоковое выполнение', 'wizard.step2.title': 'Выберите API-хост и путь', 'wizard.step2.subtitle': 'Выберите существующий API-хост или добавьте новый. Затем задайте путь, который будет вызывать эта операция.', 'wizard.required': 'Обязательно', 'wizard.optional': 'Необязательно', 'wizard.step2.upstream_title': 'API-хост', 'wizard.step2.upstream_subtitle': 'Базовый URL и способ авторизации', 'wizard.step2.upstream_placeholder': 'Выберите API-хост…', 'wizard.step2.search_placeholder': 'Поиск по имени или URL…', 'wizard.step2.change': 'Изменить', 'wizard.step2.auth_none': 'Без авторизации', 'wizard.step2.auth_bearer': 'Bearer-токен', 'wizard.step2.auth_basic': 'Логин и пароль', 'wizard.step2.auth_apikey': 'API-ключ', 'wizard.step2.register_new': 'Добавить новый API-хост', 'wizard.step2.name': 'Имя', 'wizard.step2.base_url': 'Базовый URL', 'wizard.step2.unique_hint': 'Уникальное имя этого API-хоста.', 'wizard.step2.base_url_hint': 'Корневой URL без завершающего слеша. Авторизация настраивается ниже.', 'wizard.step2.auth_selector': 'Авторизация API-хоста', 'wizard.step2.auth_selector_hint': 'Используйте секреты, чтобы не хранить токены и пароли прямо в настройках API-хоста.', 'wizard.step2.auth_mode.none': 'Без авторизации', 'wizard.step2.auth_mode.existing': 'Использовать существующий профиль авторизации', 'wizard.step2.auth_mode.create': 'Создать профиль авторизации сейчас', 'wizard.step2.auth_profile': 'Профиль авторизации', 'wizard.step2.auth_profile_hint': 'Выбранный профиль применяется автоматически при каждом вызове инструмента.', 'wizard.step2.auth_profile_empty': 'Профилей авторизации пока нет. Создайте профиль ниже.', 'wizard.step2.create_profile_title': 'Создать профиль авторизации', 'wizard.step2.create_profile_subtitle': 'Профиль можно переиспользовать в нескольких API-хостах. Значения берутся из зашифрованных секретов воркспейса.', 'wizard.step2.profile_name': 'Имя профиля', 'wizard.step2.profile_kind': 'Тип авторизации', 'wizard.step2.auth_kind.bearer': 'Bearer-токен', 'wizard.step2.auth_kind.basic': 'Логин и пароль', 'wizard.step2.auth_kind.api_key_header': 'API-ключ в заголовке', 'wizard.step2.auth_kind.api_key_query': 'API-ключ в параметре запроса', 'wizard.step2.header_name': 'Имя заголовка', 'wizard.step2.query_param': 'Параметр запроса', 'wizard.step2.username_secret': 'Секрет логина', 'wizard.step2.password_secret': 'Секрет пароля', 'wizard.step2.secret_value': 'Секрет', 'wizard.step2.quick_secret': 'Быстро создать секрет', 'wizard.step2.manage_secrets': 'Открыть страницу секретов', 'wizard.step2.static_headers': 'Статические заголовки (опционально)', 'wizard.step2.static_headers_hint': 'Необязательные заголовки без секретных значений. Токены, пароли и ключи храните через профиль авторизации.', 'wizard.step2.quick_secret_title': 'Быстро создать секрет', 'wizard.step2.quick_secret_name': 'Имя секрета', 'wizard.step2.quick_secret_kind': 'Тип секрета', 'wizard.step2.quick_secret_value': 'Значение секрета', 'wizard.step2.quick_secret_hint': 'Значение сразу шифруется и больше не отображается.', 'wizard.step2.quick_secret_submit': 'Создать секрет', 'wizard.step2.save_upstream': 'Сохранить API-хост', 'wizard.step2.endpoint_title': 'Путь API', 'wizard.step2.endpoint_subtitle': 'Путь и HTTP-метод для конкретной операции', 'wizard.step2.path_template': 'Шаблон пути', 'wizard.step2.path_hint': 'Добавляется к базовому URL API-хоста. Используйте {param} для параметров пути.', 'wizard.step3.rest.label': 'Настройки запроса', 'wizard.step3.rest.title': 'HTTP метод и формат', 'wizard.step3.rest.subtitle': 'Выберите HTTP-метод и формат запроса. Crank подставит параметры MCP инструмента в запрос к API.', 'wizard.step3.rest.method_title': 'HTTP метод', 'wizard.step3.rest.method_subtitle': 'Метод, который отправляется в API при каждом вызове инструмента', 'wizard.step3.rest.read': 'Чтение', 'wizard.step3.rest.create': 'Создание', 'wizard.step3.rest.replace': 'Замена', 'wizard.step3.rest.update': 'Обновление', 'wizard.step3.rest.remove': 'Удаление', 'wizard.step3.rest.format_title': 'Формат запроса', 'wizard.step3.rest.format_subtitle': 'Формат тела запроса и ожидаемого ответа', 'wizard.step3.rest.content_type': 'Content-Type', 'wizard.step3.rest.content_type_hint': 'В каком формате отправлять данные в API.', 'wizard.step3.rest.accept': 'Accept', 'wizard.step3.rest.accept_hint': 'Какой формат ответа ожидать от API.', 'wizard.step4.title': 'Настройки инструмента', 'wizard.step4.subtitle': 'Задайте имя инструмента, описание для LLM и определите входную/выходную схему. Описание — главный сигнал, по которому модель решает, вызывать ли этот инструмент.', 'wizard.step4.identity_title': 'Параметры инструмента', 'wizard.step4.identity_subtitle': 'Имя инструмента и описание его назначения', 'wizard.step4.tool_name': 'Имя инструмента', 'wizard.step4.tool_name_hint': 'Техническое имя для вызова MCP инструмента. Допустимы только строчные английские буквы, цифры и подчеркивания. После публикации изменить нельзя.', 'wizard.step4.display_name': 'Отображаемое имя', 'wizard.step4.display_name_hint': 'Понятное название, которое отображается в интерфейсе и логах.', 'wizard.step4.tool_title': 'Короткое описание', 'wizard.step4.tool_title_hint': 'Короткая фраза, которая будет показана MCP клиенту в описании инструмента.', 'wizard.step4.description': 'Описание', 'wizard.step4.description_hint': 'Описание для модели. Пишите точно: по этому тексту модель решает, когда нужно вызвать инструмент.', 'wizard.step4.description_title': 'Как писать хорошие описания', 'wizard.step4.description_body': 'Начинайте с глагола: создает, получает, обновляет. Укажите обязательные входные данные и опишите успешный результат. Избегайте расплывчатых формулировок вроде “обрабатывает” или “управляет”.', 'wizard.step4.input_schema_title': 'Входная схема', 'wizard.step4.input_schema_subtitle': 'Параметры, которые LLM передает при вызове инструмента', 'wizard.step4.output_schema_title': 'Выходная схема', 'wizard.step4.output_schema_subtitle': 'Форма данных, которые LLM получает после успешного вызова', 'wizard.step4.schema_draft': 'JSON Schema draft-07', 'wizard.step4.protocol_agnostic_title': 'Схемы описывают инструмент', 'wizard.step4.protocol_agnostic_body': 'Входная схема описывает данные, которые MCP клиент передает инструменту. Выходная схема описывает результат работы инструмента. На следующем шаге эти поля связываются с реальным API-запросом и ответом.', 'wizard.step5.title': 'Связи полей и запуск', 'wizard.step5.subtitle': 'Свяжите параметры MCP инструмента с полями API-запроса, а ответ API с результатом инструмента. Авторизация настраивается на шаге 2.', 'wizard.step5.input_request': 'Вход инструмента → API-запрос', 'wizard.step5.output_response': 'Ответ API → результат инструмента', 'wizard.step5.execution': 'Параметры выполнения', 'wizard.step5.exec_title': 'Выполнение запроса', 'wizard.step5.exec_subtitle': 'Время ожидания, повторные попытки и профиль авторизации', 'wizard.approval.title': 'Подтверждение человеком', 'wizard.approval.subtitle': 'Включайте для действий, которые нельзя выполнять без явного решения пользователя.', 'wizard.approval.required_label': 'Требовать подтверждение перед выполнением', 'wizard.approval.required_desc': 'Инструмент не выполнится сразу. Crank сначала запросит подтверждение выбранным способом.', 'wizard.approval.mode': 'Механизм подтверждения', 'wizard.approval.mode.custom': 'Custom MCP Approval', 'wizard.approval.mode.elicitation': 'MCP Elicitation', 'wizard.approval.custom_title': 'Custom MCP Approval', 'wizard.approval.custom_body': 'Crank вернёт MCP-клиенту ответ о необходимости подтверждения, идентификатор заявки и адреса для подтверждения или отказа. Ваш MCP-клиент должен распознать такой ответ, показать пользователю окно подтверждения и отправить решение на адрес подтверждения. Для этого адреса нужен отдельный ключ подтверждения агента.', 'wizard.approval.elicitation_title': 'MCP Elicitation', 'wizard.approval.elicitation_body': 'Crank запросит подтверждение стандартным способом MCP Elicitation. MCP-клиент должен поддерживать эту возможность. Отдельный ключ подтверждения не используется: решение пользователя возвращается по текущему MCP-подключению.', 'wizard.approval.elicitation_message': 'Сообщение для MCP-клиента', 'wizard.approval.elicitation_message_placeholder': 'Подтвердите выполнение операции.', 'wizard.approval.elicitation_message_hint': 'Короткое сообщение для MCP-клиента. Внешний вид окна подтверждения определяет сам клиент.', 'wizard.approval.ttl': 'Сколько ждать подтверждение', 'wizard.approval.show_payload': 'Передавать параметры вызова в подтверждение', 'wizard.approval.payload_title': 'Параметры подтверждения', 'wizard.approval.payload_body': 'Если включено, Crank передаст параметры вызова вместе с запросом подтверждения. Так внешний интерфейс или MCP-клиент сможет показать пользователю, какое действие он подтверждает. Если параметры содержат чувствительные данные, выключите эту опцию.', 'wizard.step5.security_level_title': 'Защита операции', 'wizard.step5.community_security_note': '', 'wizard.step5.live_title': 'Проверка и публикация', 'wizard.step5.draft_actions': 'Результат действия', 'wizard.step5.live_save_title': 'Сохранение перед действием', 'wizard.step5.live_save_body': 'Перед проверкой или публикацией Crank сохраняет текущие настройки.', 'wizard.step5.agent_preview_title': 'Как инструмент увидит MCP клиент', 'wizard.step5.agent_preview_subtitle': 'Проверьте имя, описание, входную схему и примеры до публикации.', 'wizard.step5.copy_agent_preview': 'Копировать схему', 'wizard.step5.preview_tool_name': 'Имя инструмента', 'wizard.step5.preview_tool_title': 'Короткое описание', 'wizard.step5.preview_tool_description': 'Описание для модели', 'wizard.step5.preview_input_schema': 'Входная схема', 'wizard.step5.preview_tool_call': 'Пример вызова tools/call', 'wizard.step5.preview_success_response': 'Пример успешного ответа', 'wizard.step5.preview_error_response': 'Пример ошибки', 'wizard.step5.samples_title': 'Примеры и автоматическая настройка', 'wizard.step5.samples_subtitle': 'Сохраните пример входных и выходных данных, затем Crank сможет пересобрать схемы и связи полей на их основе.', 'wizard.step5.input_sample': 'Пример входных данных', 'wizard.step5.output_sample': 'Пример ответа', 'wizard.step5.save_input_sample': 'Сохранить входной пример', 'wizard.step5.save_output_sample': 'Сохранить выходной пример', 'wizard.step5.generate_draft': 'Пересобрать по примерам', 'wizard.step5.test_title': 'Тестирование операции', 'wizard.step5.test_subtitle': 'Выполните инструмент на реальном API перед публикацией.', 'wizard.step5.test_input_payload': 'Входные данные для теста', 'wizard.step5.run_test': 'Запустить тест', 'wizard.step5.use_response_output': 'Использовать ответ как выходной пример', 'wizard.step5.request_preview': 'Предпросмотр API-запроса', 'wizard.step5.response_preview': 'Предпросмотр ответа API', 'wizard.step5.errors': 'Ошибки', 'wizard.step5.choose_descriptor': 'Выбрать descriptor set', 'wizard.step5.upload_discover': 'Загрузить и открыть сервисы', 'wizard.step5.no_descriptor': 'Descriptor set не выбран', 'wizard.step5.yaml_title': 'Импорт и экспорт YAML', 'wizard.step5.yaml_subtitle': 'Экспортируйте операцию в файл или импортируйте подготовленную YAML-конфигурацию.', 'wizard.step5.export_yaml': 'Экспорт YAML', 'wizard.step5.load_yaml_file': 'Загрузить YAML-файл', 'wizard.step5.import_yaml': 'Импорт YAML', 'wizard.step5.yaml_document': 'YAML-конфигурация', 'wizard.step5.yaml_placeholder': 'Вставьте YAML сюда, чтобы создать или обновить операцию.', 'wizard.step5.publish_title': 'Публикация', 'wizard.step5.publish_subtitle': 'Опубликуйте операцию, чтобы ее можно было добавить агентам.', 'wizard.step5.publish_hint': 'Перед публикацией Crank сохраняет текущие настройки из мастера.', 'wizard.step5.publish_action': 'Опубликовать операцию', 'wizard.step5.editable_title': 'Настройки можно изменить позже', 'wizard.step5.editable_body': 'Сохранение обновляет настройки операции в этом мастере.', 'wizard.live.failed_title': 'Не удалось выполнить действие', 'wizard.live.failed_body': 'Запрос завершился ошибкой. Проверьте настройки операции и попробуйте еще раз.', 'wizard.error.no_workspace': 'Воркспейс не выбран', 'wizard.error.tool_name': 'Имя инструмента обязательно', 'wizard.error.parser_unavailable': 'YAML parser недоступен', 'wizard.error.select_upstream': 'Сначала выберите или добавьте API-хост', 'wizard.error.auth_profile_required': 'Выберите профиль авторизации или переключите авторизацию API-хоста в режим «Без авторизации».', 'wizard.error.auth_profile_name': 'Нужно указать имя профиля авторизации.', 'wizard.error.secret_required': 'Выберите секрет для этого профиля авторизации.', 'wizard.error.basic_secrets_required': 'Выберите секреты и для логина, и для пароля.', 'wizard.error.header_name_required': 'Для этого профиля авторизации нужно указать имя заголовка.', 'wizard.error.query_param_required': 'Для этого профиля авторизации нужно указать имя query-параметра.', 'wizard.error.secret_name_required': 'Нужно указать имя секрета.', 'wizard.error.secret_value_required': 'Нужно указать значение секрета.', 'wizard.error.save_upstream_first': 'Сначала сохраните API-хост после создания нового профиля авторизации.', 'wizard.toast.auth_profile_created_title': 'Профиль авторизации создан', 'wizard.toast.auth_profile_created_body': 'Новый профиль авторизации готов и уже выбран.', 'wizard.toast.auth_profile_error_title': 'Не удалось создать профиль авторизации', 'wizard.toast.quick_secret_created_title': 'Секрет создан', 'wizard.toast.quick_secret_created_body': 'Новый секрет уже доступен в выборе авторизации.', 'wizard.toast.quick_secret_error_title': 'Не удалось создать секрет', 'wizard.error.save': 'Не удалось сохранить операцию', 'wizard.error.save_title': 'Не удалось сохранить', 'wizard.save.created': 'Черновик создан', 'wizard.save.updated': 'Черновик обновлен', 'wizard.save.body': 'Текущие настройки операции сохранены.', 'wizard.save.saved': 'Сохранено ✓', 'wizard.busy.input_sample': 'Сохранение входного примера…', 'wizard.busy.output_sample': 'Сохранение выходного примера…', 'wizard.busy.generate': 'Пересборка настроек…', 'wizard.busy.test': 'Запуск теста…', 'wizard.busy.quality': 'Проверка качества…', 'wizard.busy.export_yaml': 'Экспорт YAML…', 'wizard.busy.import_yaml': 'Импорт YAML…', 'wizard.busy.publish': 'Публикация операции…', 'wizard.busy.descriptor': 'Загрузка descriptor set…', 'wizard.busy.wsdl': 'Проверка WSDL…', 'wizard.sample.input_saved': 'Входной пример сохранен', 'wizard.sample.input_saved_body': 'Входной пример сохранен для этой операции.', 'wizard.sample.output_saved': 'Выходной пример сохранен', 'wizard.sample.output_saved_body': 'Выходной пример сохранен для этой операции.', 'wizard.sample.generated': 'Настройки пересобраны', 'wizard.sample.generated_body': 'Схемы и связи полей пересобраны по сохраненным примерам.', 'wizard.test.completed': 'Тестирование операции завершено', 'wizard.test.failed': 'Тестирование операции вернуло ошибки', 'wizard.test.completed_body': 'Операция успешно выполнилась на API.', 'wizard.test.failed_body': 'Операция выполнилась, но API или валидация вернули ошибки.', 'wizard.test.window_completed': 'Оконный тест завершен', 'wizard.test.window_completed_body': 'Собран ограниченный результат окна.', 'wizard.test.window_truncated_note': 'Результат был усечен.', 'wizard.test.window_more_note': 'Доступно продолжение, если перейти к streaming-представлениям.', 'wizard.test.window_incomplete_note': 'Upstream-поток завершился раньше, чем удалось собрать всё окно.', 'wizard.test.no_response': 'Тестового ответа пока нет', 'wizard.test.no_response_body': 'Сначала выполните тест, затем скопируйте ответ в выходной пример.', 'wizard.test.response_copied': 'Ответ скопирован', 'wizard.test.response_copied_body': 'Последний тестовый ответ скопирован в выходной пример.', 'wizard.agent_preview.copied': 'Схема скопирована', 'wizard.agent_preview.copied_body': 'Схема MCP инструмента скопирована в буфер обмена.', 'wizard.quality.title': 'Проверка качества инструмента', 'wizard.quality.subtitle': 'Проверьте имя, описание, схемы и результат, который увидит агент.', 'wizard.quality.action': 'Проверить качество', 'wizard.quality.empty': 'Проверка еще не запускалась.', 'wizard.quality.no_findings': 'Замечаний нет.', 'wizard.quality.checked_title': 'Проверка качества завершена', 'wizard.quality.checked_body': 'Посмотрите рекомендации перед публикацией.', 'wizard.quality.blocked_title': 'Проверка нашла блокирующие ошибки', 'wizard.quality.blocked_body': 'Исправьте замечания уровня «Ошибка» перед публикацией.', 'wizard.quality.blocking_error': 'Исправьте блокирующие замечания качества перед публикацией.', 'wizard.quality.import_findings_hint': 'Эти замечания получены при импорте OpenAPI. Запустите проверку качества, чтобы пересчитать их для текущего черновика.', 'wizard.quality.severity_error': 'Ошибка', 'wizard.quality.severity_warning': 'Предупреждение', 'wizard.quality.severity_info': 'Информация', 'wizard.boolean.yes': 'да', 'wizard.boolean.no': 'нет', 'wizard.yaml.exported': 'YAML экспортирован', 'wizard.yaml.exported_body': 'Текущая конфигурация операции скачана в YAML.', 'wizard.yaml.none': 'YAML не предоставлен', 'wizard.yaml.none_body': 'Вставьте YAML-документ или загрузите файл перед импортом.', 'wizard.yaml.imported': 'YAML импортирован', 'wizard.yaml.imported_with_warnings': 'YAML импортирован с рекомендациями', 'wizard.yaml.imported_body': 'Импортированная операция сохранена. Мастер сейчас откроет ее заново.', 'wizard.yaml.loaded': 'YAML загружен', 'wizard.yaml.loaded_body': 'YAML-конфигурация загружена.', 'wizard.publish.done': 'Операция опубликована', 'wizard.publish.done_body': 'Версия {version} опубликована и теперь может быть привязана к агентам.', 'wizard.publish.confirm': 'Опубликовать сохранённый черновик как новую неизменяемую версию?', 'wizard.stale.title': 'Черновик изменён в другом окне', 'wizard.stale.body': 'Ваши правки сохранены в этом браузере. Перезагрузите последнюю сохранённую версию перед повторной попыткой.', 'wizard.test.correlation': 'Request ID: {requestId}\nTrace ID: {traceId}', 'wizard.test.request_id': 'Request ID', 'wizard.test.trace_id': 'Trace ID', 'wizard.test.copy_request_id': 'Копировать Request ID', 'wizard.test.copy_trace_id': 'Копировать Trace ID', 'wizard.test.id_copied': 'Идентификатор поддержки скопирован', 'wizard.test.id_copied_body': 'Идентификатор скопирован без содержимого запроса или ответа.', // Common buttons 'btn.save': 'Сохранить', 'btn.cancel': 'Отмена', 'btn.create': 'Создать', 'btn.delete': 'Удалить', 'btn.revoke': 'Отозвать', 'btn.copy': 'Копировать', // Agents page 'agents.title': 'Агенты', 'agents.subtitle': 'Здесь можно сгруппировать ваши MCP инструменты по AI-агентам.', 'agents.subtitle.community': 'Здесь можно сгруппировать ваши MCP инструменты по AI-агентам.', 'agents.new': 'Новый агент', 'agents.limit.title': 'Достигнут лимит агентов', 'agents.limit.message': 'В этой редакции доступно не более {limit} AI-агента. Чтобы добавить еще одного, удалите существующего агента.', 'agents.stats.total': 'Всего агентов', 'agents.stats.total_sub': 'в этом воркспейсе', 'agents.stats.published': 'Опубликованы', 'agents.stats.published_sub': '{value}% от общего числа', 'agents.stats.tools': 'Открытых операций', 'agents.stats.tools_sub': 'в {count} агентах', 'agents.stats.calls': 'Вызовов сегодня', 'agents.stats.calls_sub': 'по всем агентам', 'agents.search': 'Поиск агентов...', 'agents.results': '{shown} из {total} агентов', 'agents.callout.default': 'Старайтесь группировать MCP инструменты под конкретные задачи конкретного агента, не давайте одной LLM большое количество инструментов разом, это может приводить к ошибкам и галлюцинациям. Для каждого агента задаются свои API ключи.', 'agents.callout.community': 'Старайтесь группировать MCP инструменты под конкретные задачи конкретного агента, не давайте одной LLM большое количество инструментов разом, это может приводить к ошибкам и галлюцинациям. Для каждого агента задаются свои API ключи.', 'agents.loading': 'Загрузка агентов…', 'agents.error.title': 'Не удалось загрузить агентов', 'agents.error.api': 'Воркспейс или API недоступен', 'agents.error.load': 'Не удалось загрузить агентов', 'agents.empty.initial.title': 'Агентов пока нет', 'agents.empty.initial.sub': 'Создайте первого агента, чтобы получить отдельный MCP endpoint с нужным набором инструментов.', 'agents.empty.initial.sub_community': 'Создайте первого агента, чтобы получить один отдельный MCP endpoint и его статические машинные ключи для конкретного набора инструментов.', 'agents.empty.initial.next_step': 'После создания выпустите отдельные машинные ключи для этого endpoint на странице API Keys.', 'agents.empty.search.title': 'Нет агентов по запросу "{query}"', 'agents.empty.search.sub': 'Попробуйте другой поисковый запрос.', 'agents.card.tools': 'инструментов', 'agents.card.keys': 'ключей', 'agents.card.calls_today': 'вызовов сегодня', 'agents.card.created': 'Создан {date}', 'agents.card.revision': 'Черновик v{draft} · Опубликована v{published} · Ревизия каталога {revision}', 'agents.card.copy_endpoint': 'Скопировать endpoint', 'agents.card.endpoint_help': 'Данный эндпоинт требуется указать на стороне MCP клиента вместе с API ключом.', 'agents.card.endpoint_help_community': 'Данный эндпоинт требуется указать на стороне MCP клиента вместе с API ключом.', 'agents.action.edit': 'Редактировать', 'agents.action.archive': 'Архивировать', 'agents.action.delete': 'Удалить', 'agents.lifecycle.publish': 'Опубликовать', 'agents.lifecycle.unpublish': 'Снять с публикации', 'agents.lifecycle.restore_draft': 'Вернуть в черновик', 'agents.lifecycle.published': 'Опубликован', 'agents.lifecycle.archived': 'Архивирован', 'agents.lifecycle.draft': 'Черновик', 'agents.drawer.new_title': 'Новый агент', 'agents.drawer.edit_title': 'Редактировать агента', 'agents.drawer.new_sub': 'Опишите агента и выберите доступные для него MCP инструменты.', 'agents.drawer.new_sub_community': 'Опишите агента и выберите доступные для него MCP инструменты.', 'agents.drawer.edit_sub': 'Обновите настройки агента и выбор инструментов', 'agents.drawer.identity': 'Идентичность', 'agents.drawer.display_name': 'Отображаемое имя', 'agents.drawer.slug': 'Slug', 'agents.drawer.description': 'Описание', 'agents.drawer.optional': '(необязательно)', 'agents.drawer.required': 'обязательно', 'agents.drawer.status': 'Статус', 'agents.drawer.revision': 'Черновик v{draft} · Опубликована v{published} · Ревизия каталога {revision}', 'agents.drawer.endpoint': 'MCP endpoint', 'agents.drawer.slug_hint': 'Slug используется как часть endpoint-а для идентификации агента.', 'agents.drawer.placeholder.name': 'Customer Support', 'agents.drawer.placeholder.slug': 'customer-support', 'agents.drawer.placeholder.description': 'Что делает этот агент? Для какого сценария он нужен?', 'agents.drawer.operations': 'Операции', 'agents.drawer.selected': 'Выбрано: {count}', 'agents.drawer.operations_sub': 'Выберите MCP инструменты, которые будут доступны для этого агента.', 'agents.drawer.operations_sub_community': 'Выберите MCP инструменты, которые будут доступны для этого агента.', 'agents.drawer.finding.title': 'Рекомендация', 'agents.drawer.finding.too_many_tools': 'У агента выбрано много инструментов. Включите подбор по запросу или оставьте только инструменты для одной конкретной задачи.', 'agents.drawer.finding.similar_tools': 'Инструменты «{left}» и «{right}» похожи. Переименуйте их точнее или оставьте один вариант.', 'agents.drawer.filter_ops': 'Фильтр операций…', 'agents.drawer.ops_no_match': 'Нет операций по запросу "{query}"', 'agents.drawer.ops_selected': 'Выбрано операций: {count}', 'agents.drawer.clear_all': 'Очистить все', 'agents.drawer.recommendation': 'Сейчас выбрано {count} инструментов. Включите подбор по запросу, чтобы модель получала только подходящие схемы.', 'agents.drawer.access.title': 'Доступ к инструментам', 'agents.drawer.access.subtitle': 'Выберите, как модель будет получать каталог инструментов этого агента.', 'agents.drawer.access.direct': 'Показывать сразу', 'agents.drawer.access.direct_hint': 'Для небольшого отобранного каталога. MCP-клиент получает все инструменты через tools/list.', 'agents.drawer.access.search': 'Подбирать по запросу', 'agents.drawer.access.search_hint': 'Модель видит search_tools и call_tool, а затем получает только подходящие схемы.', 'agents.drawer.groups.title': 'Разделы каталога', 'agents.drawer.groups.subtitle': 'Разделы сужают область поиска, но не мешают искать по всему каталогу.', 'agents.drawer.groups.add': 'Добавить раздел', 'agents.drawer.groups.empty': 'Разделов пока нет. Поиск будет выполняться по всему выбранному каталогу.', 'agents.drawer.groups.untitled': 'Раздел без названия', 'agents.drawer.groups.remove': 'Удалить раздел', 'agents.drawer.groups.name': 'Название', 'agents.drawer.groups.name_placeholder': 'Расчёты', 'agents.drawer.groups.id': 'Идентификатор', 'agents.drawer.groups.description': 'Описание для модели', 'agents.drawer.groups.description_placeholder': 'Счета, платежи и возвраты', 'agents.drawer.groups.assign': 'Распределение инструментов по разделам', 'agents.drawer.search.limit': 'Максимум результатов за один поиск', 'agents.drawer.search.preview_title': 'Проверка подбора', 'agents.drawer.search.preview_subtitle': 'Введите задачу и проверьте, какие инструменты получит модель.', 'agents.drawer.search.query_placeholder': 'Создать счёт для клиента', 'agents.drawer.search.all_groups': 'Все разделы', 'agents.drawer.search.test': 'Проверить', 'agents.drawer.search.testing': 'Проверяем…', 'agents.drawer.search.no_results': 'Результатов проверки пока нет.', 'agents.drawer.search.preview_error': 'Не удалось проверить подбор инструментов', 'agents.drawer.search.preview_error_title': 'Ошибка проверки подбора', 'agents.drawer.cancel': 'Отмена', 'agents.drawer.create': 'Создать агента', 'agents.drawer.save': 'Сохранить изменения', 'agents.toast.saved_title_create': 'Агент создан', 'agents.toast.saved_title_update': 'Агент обновлен', 'agents.toast.saved_message': '{name} сохранен, привязано инструментов: {count}.', 'agents.toast.save_error_title': 'Не удалось обновить агента', 'agents.toast.save_error_message': 'Не удалось сохранить агента', 'agents.toast.delete_confirm': 'Удалить этого агента? Действие нельзя отменить.', 'agents.toast.delete_title': 'Агент удален', 'agents.toast.delete_message': 'Агент {name} удален.', 'agents.toast.delete_error_title': 'Не удалось удалить', 'agents.toast.delete_error_message': 'Не удалось удалить агента', 'agents.toast.delete_forbidden_message': 'Опубликованных агентов нельзя удалить. Сначала архивируйте или снимите агента с публикации.', 'agents.toast.lifecycle_title': 'Жизненный цикл агента обновлен', 'agents.toast.lifecycle_publish_confirm': 'Опубликовать {name}? Опубликованный MCP-каталог изменится.', 'agents.toast.lifecycle_unpublish_confirm': 'Снять {name} с публикации? Текущие MCP-клиенты больше не увидят этот каталог агента.', 'agents.toast.lifecycle_archive_confirm': 'Архивировать {name}? Новые публикации и привязки будут заблокированы.', 'agents.toast.lifecycle_publish': '{name} опубликован.', 'agents.toast.lifecycle_unpublish': '{name} возвращен в черновик.', 'agents.toast.lifecycle_archive': '{name} архивирован.', 'agents.toast.lifecycle_error_title': 'Не удалось обновить жизненный цикл', 'agents.toast.lifecycle_error_message': 'Не удалось обновить состояние агента', 'agents.toast.stale_message': 'Агент изменился в другом запросе. Перезагрузите форму и повторите действие.', 'agents.toast.endpoint_title': 'MCP endpoint скопирован', // Demo content 'demo.agent.currency-rates.display_name': 'Курсы валют', 'demo.operation.frankfurter_latest_rate.display_name': 'Последний курс валюты', 'demo.operation.frankfurter_latest_rate.description': 'Возвращает последний доступный курс валюты через Frankfurter.', // Login 'login.title': 'Войти', 'login.subtitle': 'Добро пожаловать обратно', 'login.email': 'Email', 'login.password': 'Пароль', 'login.submit': 'Войти', 'login.email_label': 'Email адрес', 'login.email_placeholder': 'you@acme.com', 'login.password_only': 'Войдите с помощью email и пароля.', 'login.bootstrap.title': 'Создать администратора', 'login.bootstrap.subtitle': 'Завершите локальную первичную настройку', 'login.bootstrap.note': 'Введите одноразовый токен из crank-migrate и задайте первый пароль администратора.', 'login.bootstrap.token_label': 'Bootstrap token', 'login.bootstrap.token_placeholder': 'Вставьте одноразовый bootstrap token', 'login.bootstrap.submit': 'Создать администратора', 'login.loading': 'Входим…', 'login.success': 'Вход выполнен. Перенаправляем…', 'login.bootstrap.loading': 'Создаем администратора…', 'login.bootstrap.success': 'Администратор создан. Перенаправляем…', 'login.error.required': 'Введите email и пароль.', 'login.bootstrap.error.required': 'Введите bootstrap token и пароль.', 'login.error.invalid': 'Неверный email или пароль. Попробуйте еще раз.', 'login.error.throttled': 'Слишком много попыток. Подождите и попробуйте снова.', 'login.error.expired_session': 'Сессия истекла. Войдите снова.', 'login.error.generic': 'Сейчас не удается войти. Попробуйте еще раз.', 'login.error.request_id': 'Request ID', 'login.error.trace_id': 'Trace ID', } }; Object.assign(TRANSLATIONS.en, { }); Object.assign(TRANSLATIONS.ru, { 'execution.error.authorization_denied': 'Выполнение операции запрещено.', 'execution.error.auth_profile_not_found': 'Профиль авторизации не найден.', 'execution.error.secret_not_found': 'Секрет авторизации не найден.', 'execution.error.secret_invalid': 'Секрет авторизации имеет неподходящий формат.', 'execution.error.input_schema_invalid': 'Входные параметры не прошли проверку схемы.', 'execution.error.input_mapping_invalid': 'Не удалось сопоставить входные параметры.', 'execution.error.prepared_request_invalid': 'Не удалось подготовить корректный API-запрос.', 'execution.error.execution_overloaded': 'Сервис временно перегружен.', 'execution.error.safety_store_unavailable': 'Обязательное хранилище безопасности недоступно.', 'execution.error.protocol_unsupported': 'Протокол операции не поддерживается.', 'execution.error.execution_mode_unsupported': 'Режим выполнения не поддерживается.', 'execution.error.adapter_configuration_invalid': 'Конфигурация адаптера некорректна.', 'execution.error.outbound_target_rejected': 'Целевой адрес отклонён политикой безопасности.', 'execution.error.upstream_auth_error': 'Внешний API отклонил авторизацию.', 'execution.error.upstream_not_found': 'Ресурс внешнего API не найден.', 'execution.error.upstream_rate_limited': 'Внешний API ограничил частоту запросов.', 'execution.error.upstream_server_error': 'Внешний API временно недоступен.', 'execution.error.upstream_status_error': 'Внешний API вернул ошибочный статус.', 'execution.error.upstream_timeout': 'Истекло время ожидания внешнего API.', 'execution.error.upstream_transport_error': 'Не удалось подключиться к внешнему API.', 'execution.error.upstream_response_too_large': 'Ответ внешнего API превышает лимит.', 'execution.error.output_mapping_invalid': 'Не удалось сопоставить ответ внешнего API.', 'execution.error.output_schema_invalid': 'Ответ не прошёл проверку схемы.', 'execution.error.persistence_unavailable': 'Обязательное сохранение результата недоступно.', 'execution.error.runtime_internal': 'Внутренняя ошибка выполнения.', 'execution.error.confirmation_required': 'Операция требует подтверждения.', 'execution.error.confirmation_invalid': 'Подтверждение недействительно или истекло.', 'execution.error.idempotency_in_progress': 'Операция с этим ключом уже выполняется.', 'execution.error.idempotency_conflict': 'Ключ идемпотентности использован с другими параметрами.', 'execution.error.idempotency_outcome_unknown': 'Результат предыдущего выполнения неизвестен; автоматический повтор запрещён.', }); function t(key) { var lang = localStorage.getItem('crank_lang') || 'en'; var tr = TRANSLATIONS[lang] || TRANSLATIONS.en; return tr[key] !== undefined ? tr[key] : (TRANSLATIONS.en[key] !== undefined ? TRANSLATIONS.en[key] : key); } function tf(key, vars) { return Object.keys(vars || {}).reduce(function(result, name) { return result.replaceAll('{' + name + '}', vars[name]); }, t(key)); } function pluralForm(lang, count) { if (typeof Intl !== 'undefined' && typeof Intl.PluralRules === 'function') { return new Intl.PluralRules(lang).select(Number(count) || 0); } return Number(count) === 1 ? 'one' : 'other'; } function tPlural(key, count, vars) { var lang = localStorage.getItem('crank_lang') || 'en'; var tr = TRANSLATIONS[lang] || TRANSLATIONS.en; var form = pluralForm(lang, count); var fallbackForm = pluralForm('en', count); var resolvedKey = tr[key + '.' + form] !== undefined ? key + '.' + form : tr[key + '.other'] !== undefined ? key + '.other' : TRANSLATIONS.en[key + '.' + fallbackForm] !== undefined ? key + '.' + fallbackForm : TRANSLATIONS.en[key + '.other'] !== undefined ? key + '.other' : key; var payload = Object.assign({ count: count }, vars || {}); return Object.keys(payload).reduce(function(result, name) { return result.replaceAll('{' + name + '}', payload[name]); }, t(resolvedKey)); } function hasTranslation(key) { return t(key) !== key; } function localizeDemoAgent(agent) { if (!agent || !agent.slug) { return agent; } var displayNameKey = 'demo.agent.' + agent.slug + '.display_name'; var descriptionKey = 'demo.agent.' + agent.slug + '.description'; if (!hasTranslation(displayNameKey) && !hasTranslation(descriptionKey)) { return agent; } return Object.assign({}, agent, { display_name: hasTranslation(displayNameKey) ? t(displayNameKey) : agent.display_name, description: hasTranslation(descriptionKey) ? t(descriptionKey) : agent.description, }); } function localizeDemoOperation(operation) { if (!operation || !operation.name) { return operation; } var displayNameKey = 'demo.operation.' + operation.name + '.display_name'; var descriptionKey = 'demo.operation.' + operation.name + '.description'; if (!hasTranslation(displayNameKey) && !hasTranslation(descriptionKey)) { return operation; } var next = Object.assign({}, operation); if (hasTranslation(displayNameKey)) { next.display_name = t(displayNameKey); if (Object.prototype.hasOwnProperty.call(operation, 'operation_display_name')) { next.operation_display_name = t(displayNameKey); } } if (hasTranslation(descriptionKey)) { if (Object.prototype.hasOwnProperty.call(operation, 'description')) { next.description = t(descriptionKey); } if (Object.prototype.hasOwnProperty.call(operation, 'tool_description')) { next.tool_description = t(descriptionKey); } } return next; } window.localizeDemoAgent = localizeDemoAgent; window.localizeDemoOperation = localizeDemoOperation; window.tPlural = tPlural; function applyLang() { // text content document.querySelectorAll('[data-i18n]').forEach(function(el) { el.textContent = t(el.getAttribute('data-i18n')); }); // placeholder document.querySelectorAll('[data-i18n-ph]').forEach(function(el) { el.placeholder = t(el.getAttribute('data-i18n-ph')); }); // title document.querySelectorAll('[data-i18n-title]').forEach(function(el) { el.title = t(el.getAttribute('data-i18n-title')); }); // aria-label document.querySelectorAll('[data-i18n-aria-label]').forEach(function(el) { el.setAttribute('aria-label', t(el.getAttribute('data-i18n-aria-label'))); }); // highlight active language button in settings var lang = localStorage.getItem('crank_lang') || 'en'; document.querySelectorAll('.lang-btn').forEach(function(btn) { btn.classList.toggle('active', btn.dataset.lang === lang); }); } function setLang(lang) { localStorage.setItem('crank_lang', lang); applyLang(); // Notify Alpine components to re-render reactive getters window.dispatchEvent(new CustomEvent('crank:langchange', { detail: { lang: lang } })); } document.addEventListener('DOMContentLoaded', applyLang);