feat: localize operations catalog

This commit is contained in:
a.tolmachev
2026-04-02 22:51:25 +03:00
parent 4113515d0f
commit a491c246e0
3 changed files with 117 additions and 35 deletions
+64
View File
@@ -21,6 +21,30 @@ var TRANSLATIONS = {
'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.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.protocol': 'Protocol: {value}',
'ops.filter.category': 'Category: {value}',
'ops.filter.agent': 'Agent: {value}',
'ops.no_active_agents': 'No active agents',
// Stats
'stats.total': 'Total operations',
@@ -40,9 +64,12 @@ var TRANSLATIONS = {
'filter.protocol': 'Protocol',
'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 AZ',
@@ -147,6 +174,30 @@ var TRANSLATIONS = {
'ops.loading': 'Загрузка операций…',
'ops.empty.title': 'Операции не найдены',
'ops.empty.sub': 'Попробуйте изменить поисковый запрос или фильтры.',
'ops.empty.initial.title': 'Операций пока нет',
'ops.empty.initial.sub': 'Создайте первую операцию в этом воркспейсе, чтобы открыть живой MCP-инструмент.',
'ops.error.title': 'Не удалось подключиться к backend',
'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.stats.synced': 'Каталог синхронизирован с backend',
'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.protocol': 'Протокол: {value}',
'ops.filter.category': 'Категория: {value}',
'ops.filter.agent': 'Агент: {value}',
'ops.no_active_agents': 'Нет активных агентов',
// Stats
'stats.total': 'Всего операций',
@@ -166,9 +217,12 @@ var TRANSLATIONS = {
'filter.protocol': 'Протокол',
'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': 'Название А–Я',
@@ -263,6 +317,12 @@ function t(key) {
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 applyLang() {
// text content
document.querySelectorAll('[data-i18n]').forEach(function(el) {
@@ -272,6 +332,10 @@ function applyLang() {
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'));
});
// highlight active language button in settings
var lang = localStorage.getItem('crank_lang') || 'en';
document.querySelectorAll('.lang-btn').forEach(function(btn) {