From 5e20b58766e346e170b129b7a02fd8ecfcc4486b Mon Sep 17 00:00:00 2001 From: "a.tolmachev" Date: Thu, 2 Apr 2026 23:06:25 +0300 Subject: [PATCH] feat: localize logs page --- apps/ui/html/logs.html | 26 +++++++++--------- apps/ui/js/i18n.js | 60 ++++++++++++++++++++++++++++++++++++++++-- apps/ui/js/logs.js | 36 ++++++++++++++----------- 3 files changed, 91 insertions(+), 31 deletions(-) diff --git a/apps/ui/html/logs.html b/apps/ui/html/logs.html index c80f73f..a4328c6 100644 --- a/apps/ui/html/logs.html +++ b/apps/ui/html/logs.html @@ -34,12 +34,12 @@ @@ -58,7 +58,7 @@ ⌘K - @@ -96,27 +96,27 @@
- Live + Live
- + @@ -129,12 +129,12 @@
diff --git a/apps/ui/js/i18n.js b/apps/ui/js/i18n.js index 5f77eea..e1b54c2 100644 --- a/apps/ui/js/i18n.js +++ b/apps/ui/js/i18n.js @@ -155,13 +155,41 @@ var TRANSLATIONS = { // Logs page 'logs.title': 'Logs', - 'logs.subtitle': 'Real-time request and event log', + 'logs.subtitle': 'Real-time 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.range.30m': 'Last 30 min', + 'logs.range.1h': 'Last 1 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.', // Usage page 'usage.title': 'Usage', @@ -446,13 +474,41 @@ var TRANSLATIONS = { // Logs page 'logs.title': 'Логи', - 'logs.subtitle': 'Журнал запросов и событий в реальном времени', + '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.range.30m': 'Последние 30 мин', + 'logs.range.1h': 'Последний 1 час', + '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': 'Получены последние записи вызовов для текущего воркспейса.', // Usage page 'usage.title': 'Использование', diff --git a/apps/ui/js/logs.js b/apps/ui/js/logs.js index 0ee9ae0..385e11c 100644 --- a/apps/ui/js/logs.js +++ b/apps/ui/js/logs.js @@ -20,6 +20,10 @@ document.addEventListener('DOMContentLoaded', function () { var liveDot = document.querySelector('.live-dot'); var liveLabel = document.querySelector('.live-label'); + function tKey(key) { + return window.t ? t(key) : key; + } + function currentWorkspaceId() { var workspace = window.getCurrentWorkspace ? window.getCurrentWorkspace() : null; return workspace ? workspace.id : null; @@ -98,21 +102,21 @@ document.addEventListener('DOMContentLoaded', function () { function renderLogs() { if (state.loading && state.logs.length === 0) { - renderEmpty('Loading logs…', 'Fetching invocation history for the current workspace.'); + renderEmpty(tKey('logs.loading.title'), tKey('logs.loading.sub')); return; } if (state.loadError) { - renderEmpty('Unable to load logs', state.loadError); + renderEmpty(tKey('logs.error.title'), state.loadError); return; } if (!state.logs.length) { renderEmpty( - 'No log entries found', + tKey('logs.empty.title'), state.search || state.level !== 'all' - ? 'Try widening the period or clearing the current search and level filters.' - : 'Run tests or published MCP tools to start collecting invocation history.' + ? tKey('logs.empty.filtered') + : tKey('logs.empty.initial') ); return; } @@ -172,7 +176,7 @@ document.addEventListener('DOMContentLoaded', function () { if (detail.agentDisplayName || detail.agentSlug) { var agentLabel = document.createElement('div'); agentLabel.className = 'log-detail-label'; - agentLabel.textContent = 'Agent'; + agentLabel.textContent = tKey('logs.detail.agent'); expanded.appendChild(agentLabel); var agentPre = document.createElement('pre'); @@ -183,7 +187,7 @@ document.addEventListener('DOMContentLoaded', function () { var requestLabel = document.createElement('div'); requestLabel.className = 'log-detail-label'; - requestLabel.textContent = 'Request preview'; + requestLabel.textContent = tKey('logs.detail.request'); expanded.appendChild(requestLabel); var requestPre = document.createElement('pre'); @@ -193,7 +197,7 @@ document.addEventListener('DOMContentLoaded', function () { var responseLabel = document.createElement('div'); responseLabel.className = 'log-detail-label'; - responseLabel.textContent = 'Response preview'; + responseLabel.textContent = tKey('logs.detail.response'); expanded.appendChild(responseLabel); var responsePre = document.createElement('pre'); @@ -204,7 +208,7 @@ document.addEventListener('DOMContentLoaded', function () { if (detail.errorKind || detail.requestId) { var metaLabel = document.createElement('div'); metaLabel.className = 'log-detail-label'; - metaLabel.textContent = 'Metadata'; + metaLabel.textContent = tKey('logs.detail.meta'); expanded.appendChild(metaLabel); var metaPre = document.createElement('pre'); @@ -253,14 +257,14 @@ document.addEventListener('DOMContentLoaded', function () { async function loadLogs() { if (!window.CrankApi) { - state.loadError = 'Admin API is not available'; + state.loadError = tKey('logs.error.api'); renderLogs(); return; } state.workspaceId = currentWorkspaceId(); if (!state.workspaceId) { - state.loadError = 'Workspace is not selected'; + state.loadError = tKey('logs.error.workspace'); renderLogs(); return; } @@ -276,7 +280,7 @@ document.addEventListener('DOMContentLoaded', function () { state.openId = null; } } catch (error) { - state.loadError = error.message || 'Failed to load logs'; + state.loadError = error.message || tKey('logs.error.load'); } finally { state.loading = false; renderLogs(); @@ -305,7 +309,7 @@ document.addEventListener('DOMContentLoaded', function () { liveDot.style.cursor = 'pointer'; } if (liveLabel) { - liveLabel.textContent = state.liveMode ? 'Live' : 'Paused'; + liveLabel.textContent = state.liveMode ? tKey('logs.live') : tKey('logs.paused'); liveLabel.style.color = state.liveMode ? '' : 'var(--text-muted)'; liveLabel.style.cursor = 'pointer'; } @@ -332,8 +336,8 @@ document.addEventListener('DOMContentLoaded', function () { startPolling(); if (window.CrankUi) { window.CrankUi.info( - state.liveMode ? 'Polling logs every 4 seconds.' : 'Automatic polling is paused.', - state.liveMode ? 'Live mode enabled' : 'Live mode paused' + state.liveMode ? tKey('logs.live.on.body') : tKey('logs.live.off.body'), + state.liveMode ? tKey('logs.live.on.title') : tKey('logs.live.off.title') ); } } @@ -360,7 +364,7 @@ document.addEventListener('DOMContentLoaded', function () { refreshBtn.addEventListener('click', function () { loadLogs().then(function () { if (!state.loadError && window.CrankUi) { - window.CrankUi.info('The latest invocation records were loaded for the current workspace.', 'Logs refreshed'); + window.CrankUi.info(tKey('logs.refresh.body'), tKey('logs.refresh.title')); } }); });