/* ═══════════════════════════════════════════════ Crank — i18n Reads `crank_lang` from localStorage ('en'|'ru') ═══════════════════════════════════════════════ */ var TRANSLATIONS = { en: { // Nav 'nav.operations': 'Operations', 'nav.agents': 'Agents', 'nav.apikeys': 'API Keys', 'nav.logs': 'Logs', 'nav.usage': 'Usage', 'nav.settings': 'Settings', 'nav.logout': 'Log out', // Operations page 'ops.title': 'Operations', 'ops.subtitle': 'Tool contracts that expose your upstream APIs as MCP tools', 'ops.new': 'New operation', 'ops.loading': 'Loading operations…', 'ops.empty.title': 'No operations found', 'ops.empty.sub': 'Try adjusting your search or filters.', // 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.protocol': 'Protocol', 'filter.status': 'Status', 'filter.category': 'Category', 'filter.showing': 'Showing', 'filter.of': 'of', 'filter.clear': 'Clear 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': 'API Keys', 'apikeys.subtitle': 'Manage access tokens for external integrations', 'apikeys.new': 'Create key', 'apikeys.th.name': 'NAME', 'apikeys.th.scope': 'SCOPE', 'apikeys.th.created':'CREATED', 'apikeys.th.last': 'LAST USED', // Logs page 'logs.title': 'Logs', 'logs.subtitle': 'Real-time request and event log', 'logs.search': 'Search logs...', 'logs.level.all': 'All', 'logs.level.info': 'Info', 'logs.level.warn': 'Warn', 'logs.level.error': 'Error', 'logs.level.debug': 'Debug', // Usage page 'usage.title': 'Usage', 'usage.subtitle': 'Request volume and performance metrics', // Settings sidebar 'settings.title': 'Settings', 'settings.nav.workspace': 'Workspace', 'settings.nav.profile': 'Profile', 'settings.nav.members': 'Members', 'settings.nav.security': 'Security', 'settings.nav.notif': 'Notifications', '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.ws.tz': 'Timezone', 'settings.ws.protocol': 'Default protocol', // 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', // Common buttons 'btn.save': 'Save changes', 'btn.cancel': 'Cancel', 'btn.create': 'Create', 'btn.delete': 'Delete', 'btn.revoke': 'Revoke', 'btn.copy': 'Copy', // Login 'login.title': 'Sign in', 'login.subtitle': 'Welcome back to your workspace', 'login.email': 'Email', 'login.password': 'Password', 'login.submit': 'Sign in', 'login.sso': 'Continue with Google', }, ru: { // Nav 'nav.operations': 'Операции', 'nav.agents': 'Агенты', 'nav.apikeys': 'API Ключи', 'nav.logs': 'Логи', 'nav.usage': 'Использование', 'nav.settings': 'Настройки', 'nav.logout': 'Выйти', // Operations page 'ops.title': 'Операции', 'ops.subtitle': 'Контракты инструментов, открывающие ваши API как MCP-инструменты', 'ops.new': 'Новая операция', 'ops.loading': 'Загрузка операций…', 'ops.empty.title': 'Операции не найдены', 'ops.empty.sub': 'Попробуйте изменить поисковый запрос или фильтры.', // 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.protocol': 'Протокол', 'filter.status': 'Статус', 'filter.category': 'Категория', 'filter.showing': 'Показано', 'filter.of': 'из', 'filter.clear': 'Сбросить', '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': 'API Ключи', 'apikeys.subtitle': 'Управление токенами доступа для внешних интеграций', 'apikeys.new': 'Создать ключ', 'apikeys.th.name': 'НАЗВАНИЕ', 'apikeys.th.scope': 'ОБЛАСТЬ', 'apikeys.th.created':'СОЗДАН', 'apikeys.th.last': 'ПОСЛЕДНЕЕ ИСПОЛЬЗОВАНИЕ', // 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', // Usage page 'usage.title': 'Использование', 'usage.subtitle': 'Объём запросов и метрики производительности', // Settings sidebar 'settings.title': 'Настройки', 'settings.nav.workspace': 'Воркспейс', 'settings.nav.profile': 'Профиль', 'settings.nav.members': 'Участники', 'settings.nav.security': 'Безопасность', 'settings.nav.notif': 'Уведомления', 'settings.nav.danger': 'Опасная зона', // Settings — workspace section 'settings.ws.title': 'Настройки воркспейса', 'settings.ws.subtitle': 'Общая информация о вашем воркспейсе', 'settings.ws.name': 'Имя воркспейса', 'settings.ws.display': 'Отображаемое имя', 'settings.ws.desc': 'Описание', 'settings.ws.tz': 'Часовой пояс', 'settings.ws.protocol': 'Протокол по умолчанию', // 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': 'Роль', // Common buttons 'btn.save': 'Сохранить', 'btn.cancel': 'Отмена', 'btn.create': 'Создать', 'btn.delete': 'Удалить', 'btn.revoke': 'Отозвать', 'btn.copy': 'Копировать', // Login 'login.title': 'Войти', 'login.subtitle': 'Добро пожаловать обратно', 'login.email': 'Email', 'login.password': 'Пароль', 'login.submit': 'Войти', 'login.sso': 'Войти через Google', } }; 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 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')); }); // 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);