fix: localize plugin operation errors

This commit is contained in:
2026-07-14 22:00:24 +08:00
parent 1f03226378
commit a1b3c31d0d
37 changed files with 330 additions and 154 deletions
+20 -31
View File
@@ -28,11 +28,9 @@
const INPUT_STYLE = 'width:100%;background:#0f3460;border:1px solid #1a3a5c;color:#e0e0f0;padding:8px 10px;border-radius:4px;font-size:0.85rem;box-sizing:border-box;height:36px;'
const INPUT_FOCUS_STYLE = INPUT_STYLE + 'outline:none;border-color:#4ecca3;'
function sanitizeError(msg) {
if (!msg) return tr('ui.unknownError', null, 'Unknown error')
let s = String(msg).replace(/<[^>]+>/g, '')
if (s.length > 200) s = s.substring(0, 200) + '...'
return s
function reportError(key, fallback, error) {
console.warn('[verstak.sync] operation failed:', error)
return tr(key, null, fallback)
}
function syncAPI() {
@@ -51,15 +49,21 @@
syncInterval = saved.syncInterval || 5
}
}
} catch (_) {}
} catch (error) {
console.warn('[verstak.sync] settings load failed:', error)
}
try {
settings = await syncAPI().status()
if (settings) {
if (settings.serverUrl) serverUrl = settings.serverUrl
if (settings.syncInterval != null) syncInterval = settings.syncInterval
if (settings.syncInterval > 0) autoSync = true
if (settings.lastError) console.warn('[verstak.sync] last sync failed:', settings.lastError)
}
} catch (_) { settings = null }
} catch (error) {
console.warn('[verstak.sync] status load failed:', error)
settings = null
}
}
load()
@@ -80,7 +84,7 @@
resultMsg = tr('ui.settingsSaved', null, 'Settings saved.')
resultKind = ''
} catch (e) {
errorMsg = sanitizeError(e.message || e)
errorMsg = reportError('ui.saveFailed', 'Could not save sync settings. Please try again.', e)
}
loading = false
}
@@ -97,7 +101,7 @@
connectionResult = tr('ui.connectionSuccessful', null, 'Connection successful.')
} catch (e) {
connectionOk = false
connectionResult = tr('ui.connectionFailed', { error: sanitizeError(e.message || e) }, 'Connection failed: {error}')
connectionResult = reportError('ui.connectionFailed', 'Could not connect. Check the server address and credentials.', e)
}
loading = false
}
@@ -115,7 +119,7 @@
password = ''
await load()
} catch (e) {
errorMsg = sanitizeError(e.message || e)
errorMsg = reportError('ui.connectFailed', 'Could not connect this device. Please try again.', e)
}
loading = false
}
@@ -129,23 +133,8 @@
return parts.join(' · ')
}
function conflictField(conflict, keys) {
for (const key of keys) {
const value = conflict && conflict[key]
if (value != null && String(value).trim()) return String(value)
}
return ''
}
function formatSyncConflict(conflict) {
const entityType = conflictField(conflict, ['entity_type', 'entityType']) || 'item'
const entityId = conflictField(conflict, ['entity_id', 'entityId', 'path']) || 'unknown'
const opId = conflictField(conflict, ['op_id', 'opId'])
const reason = conflictField(conflict, ['reason', 'message'])
const parts = [entityType + ': ' + entityId]
if (opId) parts.push('op ' + opId)
if (reason) parts.push(reason)
return parts.join(' · ')
function formatSyncConflict() {
return tr('ui.syncConflictItem', null, 'A synchronization conflict needs attention.')
}
async function runSyncNow() {
@@ -163,7 +152,7 @@
resultKind = warning ? 'warning' : ''
await load()
} catch (e) {
errorMsg = sanitizeError(e.message || e)
errorMsg = reportError('ui.syncFailed', 'Could not synchronize. Please try again.', e)
}
loading = false
}
@@ -194,7 +183,7 @@
settings = null
await load()
} catch (e) {
errorMsg = sanitizeError(e.message || e)
errorMsg = reportError('ui.disconnectFailed', 'Could not disconnect from the server. Please try again.', e)
}
loading = false
}
@@ -209,7 +198,7 @@
resultKind = ''
await load()
} catch (e) {
errorMsg = sanitizeError(e.message || e)
errorMsg = reportError('ui.resetKeyFailed', 'Could not reset the sync key. Please try again.', e)
}
loading = false
}
@@ -243,7 +232,7 @@
{/if}
{#if settings && settings.lastError && !errorMsg}
<div style="padding:0.5rem 0.75rem;margin-bottom:0.75rem;background:rgba(255,107,107,0.1);border:1px solid rgba(255,107,107,0.3);border-radius:6px;color:#ff6b6b;font-size:0.85rem;">
{tr('ui.lastSyncError', { error: sanitizeError(settings.lastError) }, 'Last sync error: {error}')}
{tr('ui.lastSyncError', null, 'The last synchronization did not finish. Try again.')}
</div>
{/if}
+9 -3
View File
@@ -5,12 +5,17 @@
"ui.title": "Sync",
"ui.description": "Synchronize your vault across devices.",
"ui.unknownError": "Unknown error",
"ui.apiUnavailable": "Plugin API sync namespace not available",
"ui.apiUnavailable": "Synchronization is unavailable right now.",
"ui.intervalError": "Sync interval must be between 1 and 1440 minutes.",
"ui.settingsSaved": "Settings saved.",
"ui.serverRequired": "Server URL is required.",
"ui.connectionSuccessful": "Connection successful.",
"ui.connectionFailed": "Connection failed: {error}",
"ui.connectionFailed": "Could not connect. Check the server address and credentials.",
"ui.saveFailed": "Could not save sync settings. Please try again.",
"ui.connectFailed": "Could not connect this device. Please try again.",
"ui.syncFailed": "Could not synchronize. Please try again.",
"ui.disconnectFailed": "Could not disconnect from the server. Please try again.",
"ui.resetKeyFailed": "Could not reset the sync key. Please try again.",
"ui.connectedSuccessfully": "Connected successfully.",
"ui.conflictsCount": "{count} conflict(s)",
"ui.errorsCount": "{count} error(s)",
@@ -18,7 +23,8 @@
"ui.disconnected": "Disconnected from server.",
"ui.keyReset": "Sync key reset. Connect again to pair this device.",
"ui.syncConflicts": "Sync conflicts",
"ui.lastSyncError": "Last sync error: {error}",
"ui.lastSyncError": "The last synchronization did not finish. Try again.",
"ui.syncConflictItem": "A synchronization conflict needs attention.",
"ui.server": "Server",
"ui.serverUrl": "Server URL",
"ui.username": "Username",
+9 -3
View File
@@ -5,12 +5,17 @@
"ui.title": "Синхронизация",
"ui.description": "Синхронизируйте хранилище между устройствами.",
"ui.unknownError": "Неизвестная ошибка",
"ui.apiUnavailable": "API синхронизации плагина недоступен",
"ui.apiUnavailable": "Синхронизация сейчас недоступна.",
"ui.intervalError": "Интервал синхронизации должен быть от 1 до 1440 минут.",
"ui.settingsSaved": "Настройки сохранены.",
"ui.serverRequired": "Укажите URL сервера.",
"ui.connectionSuccessful": "Подключение успешно.",
"ui.connectionFailed": "Не удалось подключиться: {error}",
"ui.connectionFailed": "Не удалось подключиться. Проверьте адрес сервера и учётные данные.",
"ui.saveFailed": "Не удалось сохранить настройки синхронизации. Повторите попытку.",
"ui.connectFailed": "Не удалось подключить это устройство. Повторите попытку.",
"ui.syncFailed": "Не удалось синхронизировать данные. Повторите попытку.",
"ui.disconnectFailed": "Не удалось отключиться от сервера. Повторите попытку.",
"ui.resetKeyFailed": "Не удалось сбросить ключ синхронизации. Повторите попытку.",
"ui.connectedSuccessfully": "Подключение установлено.",
"ui.conflictsCount": "Конфликтов: {count}",
"ui.errorsCount": "Ошибок: {count}",
@@ -18,7 +23,8 @@
"ui.disconnected": "Сервер отключён.",
"ui.keyReset": "Ключ синхронизации сброшен. Подключитесь снова, чтобы связать устройство.",
"ui.syncConflicts": "Конфликты синхронизации",
"ui.lastSyncError": "Ошибка последней синхронизации: {error}",
"ui.lastSyncError": "Последняя синхронизация не завершилась. Повторите попытку.",
"ui.syncConflictItem": "Конфликт синхронизации требует внимания.",
"ui.server": "Сервер",
"ui.serverUrl": "URL сервера",
"ui.username": "Имя пользователя",