290 lines
10 KiB
JavaScript
290 lines
10 KiB
JavaScript
/* ═══════════════════════════════════════════════
|
||
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);
|