@@ -873,7 +873,7 @@ function updateUsbMuxButton() {
if (!usbMuxConfigured) {
if (targetEl) targetEl.textContent = '未配置';
if (btn) {
- btn.className = 'btn btn-small';
+ btn.className = 'btn btn-small btn-gray';
btn.disabled = true;
}
return;
@@ -886,7 +886,7 @@ function updateUsbMuxButton() {
if (btn) {
btn.disabled = false;
const colorClass = USB_MUX_COLORS[usbMuxTarget] || '';
- btn.className = 'btn btn-small ' + colorClass;
+ btn.className = 'btn btn-small btn-gray ' + colorClass.trim();
}
}
@@ -2068,7 +2068,7 @@ async function loadVariableBindStatus() {
if (!optionExists) {
const tempOpt = document.createElement('option');
tempOpt.value = boundVar;
- tempOpt.textContent = `📊 ${boundVar} (当前)`;
+ tempOpt.textContent = `${boundVar} (当前)`;
selectEl.appendChild(tempOpt);
}
selectEl.value = boundVar;
@@ -2096,7 +2096,7 @@ async function loadVariableBindStatus() {
if (priorityVars.length > 0) {
const group1 = document.createElement('optgroup');
- group1.label = '🌡️ 温度变量';
+ group1.label = '温度变量';
priorityVars.forEach(v => {
const opt = document.createElement('option');
opt.value = v.name;
@@ -2108,7 +2108,7 @@ async function loadVariableBindStatus() {
if (otherVars.length > 0) {
const group2 = document.createElement('optgroup');
- group2.label = '📊 其他数值变量';
+ group2.label = '其他数值变量';
otherVars.forEach(v => {
const opt = document.createElement('option');
opt.value = v.name;
@@ -2506,7 +2506,7 @@ async function refreshSystemLeds() {
} else {
container.innerHTML = `
@@ -2570,7 +2570,7 @@ const WIDGET_TYPES = {
name: '图标状态',
icon: '
',
description: '根据值显示不同图标',
- defaultConfig: { icons: { '0': '❌', '1': '✅', 'default': '❓' } }
+ defaultConfig: { icons: { '0': '
' } }
},
dual: {
name: '双数值',
@@ -2923,7 +2923,7 @@ function renderWidgetHtml(widget) {
case 'icon':
contentHtml = `
`;
break;
@@ -3119,9 +3119,9 @@ function updateWidgetValue(widget, value) {
case 'icon': {
const iconEl = document.getElementById(`dw-${id}-icon`);
const valueEl = document.getElementById(`dw-${id}-value`);
- const iconMap = icons || { '0': '❌', '1': '✅', 'default': '❓' };
- const displayIcon = iconMap[String(value)] || iconMap['default'] || '❓';
- if (iconEl) iconEl.textContent = displayIcon;
+ const iconMap = icons || { '0': '
' };
+ const displayIcon = iconMap[String(value)] || iconMap['default'] || '
';
+ if (iconEl) iconEl.innerHTML = displayIcon;
if (valueEl) valueEl.textContent = value;
break;
}
@@ -3652,7 +3652,7 @@ function createNewWidget(type) {
widget.colors = defaults.colors || ['#40c057', '#fab005', '#fa5252'];
}
if (type === 'icon') {
- widget.icons = defaults.icons || { '0': '❌', '1': '✅', 'default': '❓' };
+ widget.icons = defaults.icons || { '0': '
' };
}
if (type === 'log') {
widget.maxLines = defaults.maxLines || 15;
@@ -4056,7 +4056,7 @@ async function refreshQuickActions() {
} else {
container.innerHTML = `
@@ -4145,7 +4145,7 @@ async function triggerQuickAction(ruleId) {
const card = event?.currentTarget || document.getElementById(`quick-action-${ruleId}`);
if (!card) {
console.error('triggerQuickAction: card not found for ruleId=', ruleId);
- showToast('❌ 无法找到操作卡片', 'error');
+ showToast('无法找到操作卡片', 'error');
return;
}
@@ -4411,7 +4411,7 @@ function startQuickLogTail(logFile, hostId, intervalMs = 5000) {
const status = document.getElementById('quick-log-status');
if (btn) {
- btn.textContent = '⏹️ 停止跟踪';
+ btn.innerHTML = '
停止跟踪';
btn.classList.remove('btn-service-style');
btn.classList.add('btn-danger');
}
@@ -4468,7 +4468,7 @@ function stopQuickLogTail() {
const status = document.getElementById('quick-log-status');
if (btn) {
- btn.textContent = '▶️ 开始跟踪';
+ btn.innerHTML = '
开始跟踪';
btn.classList.remove('btn-danger');
btn.classList.add('btn-service-style');
}
@@ -4587,7 +4587,7 @@ function showTimezoneModal() {
modal.innerHTML = `
-
⚙️ 设置时区
+
设置时区
diff --git a/components/ts_webui/web/js/lang/en-US.js b/components/ts_webui/web/js/lang/en-US.js
index 802229b..af59759 100644
--- a/components/ts_webui/web/js/lang/en-US.js
+++ b/components/ts_webui/web/js/lang/en-US.js
@@ -738,8 +738,8 @@ i18n.registerLanguage('en-US', {
// Service
serviceSuccess: 'Service {name} {action} successful',
// Voltage protection
- voltageProtectionEnabled: '✅ Voltage protection enabled',
- voltageProtectionDisabled: '⚠️ Voltage protection disabled',
+ voltageProtectionEnabled: 'Voltage protection enabled',
+ voltageProtectionDisabled: 'Voltage protection disabled',
switchFailed: 'Switch failed',
// USB switch
usbSwitching: 'Switching USB to {target}...',
@@ -752,7 +752,7 @@ i18n.registerLanguage('en-US', {
widgetBound: 'Bound {widget} → {var}',
// Quick actions
processRunning: 'Process is running, please stop it first',
- cardNotFound: '❌ Action card not found',
+ cardNotFound: 'Action card not found',
executionFailed: 'Execution failed',
processTerminated: 'Process terminated',
processNotExist: 'Process does not exist',
@@ -809,7 +809,7 @@ i18n.registerLanguage('en-US', {
rollbackFailed: 'Rollback failed',
upgradeAborted: 'Upgrade aborted',
abortFailed: 'Abort failed',
- otaServerSaved: '✅ OTA server URL saved',
+ otaServerSaved: 'OTA server URL saved',
otaServerCleared: 'OTA server URL cleared',
enterOtaServer: 'Please enter OTA server URL first',
upgradeFailed: 'Upgrade failed',
@@ -830,8 +830,8 @@ i18n.registerLanguage('en-US', {
deleteActionResult: 'Delete action {id}',
deleteSourceResult: 'Delete source {id}',
deleteSourceFailed: 'Failed to delete source',
- shutdownSettingsSaved: '✅ Shutdown settings saved',
- defaultsRestored: '✅ Defaults restored',
+ shutdownSettingsSaved: 'Shutdown settings saved',
+ defaultsRestored: 'Defaults restored',
restoreFailed: 'Restore failed',
deleteRuleResult: 'Delete rule {id}',
deleteRuleFailed: 'Failed to delete rule',
@@ -916,8 +916,8 @@ i18n.registerLanguage('en-US', {
hostInfoEmpty: 'Host information is empty',
testingConnection: 'Testing connection to {host}...',
cannotGetHostInfo: 'Cannot get host information',
- connectionSuccess: '✅ Connection to {host} successful!',
- testConnectionFailed: '❌ Test failed',
+ connectionSuccess: 'Connection to {host} successful!',
+ testConnectionFailed: 'Test failed',
hostConfigExported: 'Host config exported: {filename}',
sshHostRemoved: 'SSH host {id} removed from list',
removeFailed: 'Remove failed',
@@ -938,9 +938,9 @@ i18n.registerLanguage('en-US', {
clearFailed: 'Clear failed',
certCopiedToClipboard: 'Certificate copied to clipboard',
// PKI config
- applyingConfig: '🔄 Applying config...',
- configApplied: '✅ Config applied\nModules: {modules}',
- applyFailed: '❌ Apply failed',
+ applyingConfig: 'Applying config...',
+ configApplied: 'Config applied\nModules: {modules}',
+ applyFailed: 'Apply failed',
onlyDeveloperCanExport: 'Only Developer devices can export config packs',
selectedJsonFiles: 'Selected all JSON files in current directory',
configPackCopied: 'Config pack copied to clipboard',
@@ -952,12 +952,12 @@ i18n.registerLanguage('en-US', {
},
// Device Control
device: {
- agxRunning: '🟢 AGX Running',
- agxStopped: '🔴 AGX Stopped',
- lpmuRunning: '🟢 LPMU Running',
- lpmuStopped: '🔴 LPMU Stopped',
- lpmuDetecting: '⏳ Detecting Status',
- lpmuUnknown: '⚠️ LPMU Status Unknown',
+ agxRunning: 'AGX Running',
+ agxStopped: 'AGX Stopped',
+ lpmuRunning: 'LPMU Running',
+ lpmuStopped: 'LPMU Stopped',
+ lpmuDetecting: 'Detecting Status',
+ lpmuUnknown: 'LPMU Status Unknown',
lpmuOnlineHint: 'LPMU online (ping 10.10.99.99 reachable)\nClick to trigger power button',
lpmuOfflineHint: 'LPMU offline (ping 10.10.99.99 unreachable)\nClick to trigger power button',
lpmuDetectingHint: 'Detecting LPMU status...\nMax wait 80 seconds',
@@ -1053,12 +1053,12 @@ i18n.registerLanguage('en-US', {
filePage: {
dirNotExist: 'Directory does not exist',
createDir: 'Create Directory',
- emptyFolder: '📂 Empty Folder',
- noImages: '📂 No image files',
+ emptyFolder: 'Empty Folder',
+ noImages: 'No image files',
noFonts: 'No available fonts',
uploading: 'Uploading...',
- uploadComplete: '✓ Complete',
- uploadError: '✕ Failed',
+ uploadComplete: 'Complete',
+ uploadError: 'Failed',
confirmDelete: 'Are you sure you want to delete this file?',
// Dialogs
uploadFiles: 'Upload Files',
@@ -1149,12 +1149,12 @@ i18n.registerLanguage('en-US', {
// SSH/Commands Page
sshPage: {
// Service status labels
- statusReady: '✅ Ready',
- statusChecking: '🔄 Checking',
- statusTimeout: '⚠️ Timeout',
- statusFailed: '❌ Failed',
- statusIdle: '⏸️ Idle',
- statusStopped: '⏹️ Stopped',
+ statusReady: 'Ready',
+ statusChecking: 'Checking',
+ statusTimeout: 'Timeout',
+ statusFailed: 'Failed',
+ statusIdle: 'Idle',
+ statusStopped: 'Stopped',
// Error messages
hostNotFound: 'Host not found',
cmdNotFound: 'Command not found',
@@ -1222,31 +1222,31 @@ i18n.registerLanguage('en-US', {
exitCode: 'Exit Code',
waitingOutput: 'Waiting for output...',
sessionId: 'Session ID',
- commandSubmitted: '✅ Command submitted to server background',
- useButtonsAbove: '💡 Use buttons above to view logs, track output or check process status',
- logFile: '📄 Log File',
- processKeyword: '🔍 Process Keyword',
- startTailLog: '📡 Start Real-time Tracking',
+ commandSubmitted: 'Command submitted to server background',
+ useButtonsAbove: 'Use buttons above to view logs, track output or check process status',
+ logFile: 'Log File',
+ processKeyword: 'Process Keyword',
+ startTailLog: 'Start Real-time Tracking',
clickToExit: '(Click "Stop Tracking" button to exit)',
- stoppedTailLog: '⏹️ Stopped Real-time Tracking',
- viewServiceLog: '📄 View Service Log',
+ stoppedTailLog: 'Stopped Real-time Tracking',
+ viewServiceLog: 'View Service Log',
file: 'File',
- stopService: '🛑 Stop Service',
+ stopService: 'Stop Service',
processRunningPid: 'Process running (PID: {pid}), stopping...',
- serviceStopped: '✅ Service stopped',
- tryForceKill: '⚠️ Process may still be running, trying force kill...',
- forceKilled: '✅ Force killed',
- processAlreadyStopped: '⚠️ Process already stopped',
- pidFileNotExist: '⚠️ PID file not exist, service may not have started',
+ serviceStopped: 'Service stopped',
+ tryForceKill: 'Process may still be running, trying force kill...',
+ forceKilled: 'Force killed',
+ processAlreadyStopped: 'Process already stopped',
+ pidFileNotExist: 'PID file not exist, service may not have started',
stopServiceFailed: 'Failed to stop service',
executionFailed: 'Execution failed',
getLogFailed: 'Failed to get log',
- patternMatchSuccess: '🎯 Pattern Match Success!',
- expectPatternMatch: '✅ Expect pattern matched: Yes',
- failPatternMatch: '❌ Fail pattern matched: Yes',
- extractedContent: '📋 Extracted Content',
- cancelledExecution: '⏹️ Execution cancelled',
- error: '❌ Error',
+ patternMatchSuccess: 'Pattern Match Success!',
+ expectPatternMatch: 'Expect pattern matched: Yes',
+ failPatternMatch: 'Fail pattern matched: Yes',
+ extractedContent: 'Extracted Content',
+ cancelledExecution: 'Execution cancelled',
+ error: 'Error',
// nohup quick actions
tailLog: 'Tail Log',
stopTail: 'Stop Tail',
@@ -1259,20 +1259,20 @@ i18n.registerLanguage('en-US', {
commandLabel: 'Command',
storeVar: 'Store Variable',
// Config pack related
- generatingConfigPack: '🔄 Generating config pack...',
- exportSuccess: '✅ Export successful!',
- verifyingConfigPack: '🔄 Verifying config pack...',
- signatureVerified: '✅ Signature verified',
- savingConfig: '🔄 Saving config...',
- configExists: '⚠️ Config {id} already exists, please check "Overwrite"',
- configSaved: '✅ Config saved',
+ generatingConfigPack: 'Generating config pack...',
+ exportSuccess: 'Export successful!',
+ verifyingConfigPack: 'Verifying config pack...',
+ signatureVerified: 'Signature verified',
+ savingConfig: 'Saving config...',
+ configExists: 'Config {id} already exists, please check "Overwrite"',
+ configSaved: 'Config saved',
// SSH import/export modals
exportSshCmdTitle: 'Export SSH Command Config',
exportSshCmdDesc: 'Export command
{cmdId} as encrypted config pack',
includeHostConfig: 'Include dependent host config',
- includeHostRecommend: '💡 Recommended for complete import on target device',
+ includeHostRecommend: 'Recommended for complete import on target device',
targetCert: 'Target Device Certificate (PEM)',
- targetCertHint: '💡 Paste target device certificate. Leave empty to use local certificate (self-encrypt)',
+ targetCertHint: 'Paste target device certificate. Leave empty to use local certificate (self-encrypt)',
importSshCmdTitle: 'Import SSH Command Config',
importSshCmdDesc: 'Select .tscfg config pack file to import SSH commands',
selectFile: 'Select File',
@@ -1287,14 +1287,14 @@ i18n.registerLanguage('en-US', {
exportedWithoutHost: 'Exported command config: {filename}',
importCommand: 'Import Command',
// Deploy/Revoke
- deployingKey: '🔄 Deploying key...',
- deploySuccess: '✅ Deploy successful! Now you can use key "{keyId}" for passwordless login to {target}',
- authVerified: '✓ Public key auth verified',
- authSkipped: '⚠ Public key auth verification skipped',
- revokingKey: '🔄 Revoking key...',
- revokeSuccess: '✅ Revoke successful! Removed {count} matching public keys from {target}',
- keyNotFound: '⚠️ Public key not found on {target}',
- removeLocalOnly: '🗑️ Remove Local Record Only',
+ deployingKey: 'Deploying key...',
+ deploySuccess: 'Deploy successful! Now you can use key "{keyId}" for passwordless login to {target}',
+ authVerified: 'Public key auth verified',
+ authSkipped: 'Public key auth verification skipped',
+ revokingKey: 'Revoking key...',
+ revokeSuccess: 'Revoke successful! Removed {count} matching public keys from {target}',
+ keyNotFound: 'Public key not found on {target}',
+ removeLocalOnly: 'Remove Local Record Only',
// Command editor placeholders
cmdIdPlaceholder: 'e.g.: restart_nginx, check_status',
cmdNamePlaceholder: 'e.g.: Restart Service',
@@ -1378,7 +1378,7 @@ i18n.registerLanguage('en-US', {
readyTimeoutHint: 'Mark as timeout if ready pattern not matched within this time',
readyIntervalLabel: 'Check Interval (ms)',
readyIntervalHint: 'How often to check the log file',
- serviceLogHint: '💡 After service starts, system will monitor log file:',
+ serviceLogHint: 'After service starts, system will monitor log file:',
serviceLogPath: '/tmp/ts_nohup_[cmd_name].log',
serviceStatusHint: 'Variable [var_name].status will auto-update based on log matching',
varNameLabel: 'Store Variable Name',
@@ -1407,7 +1407,7 @@ i18n.registerLanguage('en-US', {
connectingWaitingEvent: 'Connecting and waiting for event: {event}',
connectingAutoDiscover: 'Connecting and auto-discovering events...',
unknownEvent: '(Unknown event)',
- sioConnectionSuccess: '✅ Connection successful',
+ sioConnectionSuccess: 'Connection successful',
eventLabel: 'Event',
timeout: 'Timeout',
reconnectInterval: 'Reconnect Interval',
@@ -1424,7 +1424,7 @@ i18n.registerLanguage('en-US', {
deleteHttpsKeyAndCert: 'Delete HTTPS Key and Certificate',
keyNotGenerated: 'Key not generated',
generateHttpsKey: 'Generate HTTPS Key Pair',
- generateKey: '🔑 Generate Key',
+ generateKey: 'Generate Key',
// Certificate details
subjectCN: 'Subject CN',
issuer: 'Issuer',
@@ -1459,18 +1459,18 @@ i18n.registerLanguage('en-US', {
configFiles: 'config files',
savedTo: 'Saved to',
// Config pack export
- configPackExport: '📦 Export Config Pack',
+ configPackExport: 'Export Config Pack',
selectConfigFiles: 'Select Config Files',
configName: 'Config Name',
configNamePlaceholder: 'Auto-filled from filename',
configDescPlaceholder: 'LED effect config',
targetDeviceCert: 'Target Device Certificate (PEM)',
certPlaceholder: '-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----',
- certHint: '💡 Paste certificate exported from target device',
- generateConfigPack: '📦 Generate Config Pack',
+ certHint: 'Paste certificate exported from target device',
+ generateConfigPack: 'Generate Config Pack',
generatedConfigPack: 'Generated Config Pack (.tscfg)',
configPackPlaceholder: 'Config pack will be displayed here...',
- copyToClipboard: '📋 Copy to Clipboard',
+ copyToClipboard: 'Copy to Clipboard',
downloadToLocal: '💾 Download',
// File selection status
selectedFiles: '{count} file(s) selected',
@@ -1494,21 +1494,21 @@ i18n.registerLanguage('en-US', {
keysTableCreated: 'Created',
keysTableExportable: 'Exportable',
keysTableActions: 'Actions',
- hostsHint: '💡 After deploying public key via the "Deploy" button above, host will appear in this list',
+ hostsHint: 'After deploying public key via the "Deploy" button above, host will appear in this list',
importHost: '📥 Import Host',
hostId: 'Host ID',
address: 'Address',
port: 'Port',
username: 'Username',
deployKey: 'Deploy Key',
- fingerprintHint: '💡 Server fingerprints recorded during SSH connection to prevent man-in-the-middle attacks. Update if server is reinstalled.',
+ fingerprintHint: 'Server fingerprints recorded during SSH connection to prevent man-in-the-middle attacks. Update if server is reinstalled.',
keyType: 'Key Type',
fingerprintSha256: 'Fingerprint (SHA256)',
addedTime: 'Added',
// SSH host import/export
- exportSshHostTitle: '📤 Export SSH Host Config',
+ exportSshHostTitle: 'Export SSH Host Config',
exportSshHostDesc: 'Export host {hostId} config as encrypted config package',
- exportSshHostCertHint: '💡 Paste target device certificate. Leave empty to use local certificate (self-encrypt)',
+ exportSshHostCertHint: 'Paste target device certificate. Leave empty to use local certificate (self-encrypt)',
importSshHostTitle: '📥 Import SSH Host Config',
importSshHostDesc: 'Select .tscfg config package file to import SSH host config',
confirmImport: '📥 Confirm Import',
@@ -1517,29 +1517,29 @@ i18n.registerLanguage('en-US', {
deployKeyDesc: 'Deploy public key {keyId} to remote server authorized_keys',
targetHost: 'Target Host',
authPassword: 'Auth Password (required for first deploy)',
- deployHint: '💡 After successful deployment, host will be added to "Deployed Hosts" list for passwordless login',
+ deployHint: 'After successful deployment, host will be added to "Deployed Hosts" list for passwordless login',
startDeploy: '🚀 Start Deploy',
// Revoke key modal
- revokeKeyTitle: '⚠️ Revoke Public Key',
+ revokeKeyTitle: 'Revoke Public Key',
revokeKeyDesc: 'Remove public key {keyId} from remote server',
- revokeWarning: '⚠️ Warning: After revocation, passwordless login with this key will be disabled',
- revokePublicKey: '⚠️ Revoke Public Key',
+ revokeWarning: 'Warning: After revocation, passwordless login with this key will be disabled',
+ revokePublicKey: 'Revoke Public Key',
// Host key mismatch warning
- hostMismatchTitle: '⚠️ Security Warning: Host Key Mismatch!',
+ hostMismatchTitle: 'Security Warning: Host Key Mismatch!',
hostMismatchDesc: 'Host key has changed! This may indicate:',
hostMismatchReason1: 'Server has been reinstalled',
hostMismatchReason2: 'Man-in-the-middle attack',
hostMismatchReason3: 'Server IP assigned to different device',
hostMismatchAdvice: 'Suggestion: If you confirm the server was reinstalled or key was updated, click "Update Host Key" to remove old record, then reconnect to trust new key.',
- updateHostKey: '🔄 Update Host Key',
- abortOperation: '❌ Abort Operation',
+ updateHostKey: 'Update Host Key',
+ abortOperation: 'Abort Operation',
storedFingerprint: 'Stored Fingerprint',
currentFingerprint: 'Current Fingerprint',
// HTTPS certificate modals
- genHttpsKeyPairTitle: '🔑 Generate HTTPS Key Pair',
+ genHttpsKeyPairTitle: 'Generate HTTPS Key Pair',
genHttpsKeyPairDesc: 'Generate ECDSA P-256 key pair for mTLS authentication',
- existingKeyWarning: '⚠️ Key pair already exists, continuing will overwrite!',
- generate: '🔑 Generate',
+ existingKeyWarning: 'Key pair already exists, continuing will overwrite!',
+ generate: 'Generate',
csrTitle: 'Certificate Signing Request (CSR)',
deviceId: 'Device ID (CN)',
deviceIdHint: 'Leave empty for default config',
@@ -1553,25 +1553,25 @@ i18n.registerLanguage('en-US', {
installCaTitle: 'Install CA Certificate Chain',
installCaDesc: 'Paste root and intermediate certificates (PEM format, can concatenate)',
caCertPem: 'CA Certificate Chain PEM',
- deleteCredentialsTitle: '🗑️ Delete HTTPS Credentials',
+ deleteCredentialsTitle: 'Delete HTTPS Credentials',
deleteCredentialsDesc: 'This will delete key pair and certificate, regeneration required after',
- deleteCredentialsWarning: '⚠️ Warning: Device cannot perform mTLS auth after deletion until reconfigured',
- confirmDelete: '⚠️ Confirm Delete',
+ deleteCredentialsWarning: 'Warning: Device cannot perform mTLS auth after deletion until reconfigured',
+ confirmDelete: 'Confirm Delete',
viewCertTitle: 'View Certificate Details',
close: 'Close',
// Config pack verification
configId: 'Config ID',
type: 'Type',
- sshCommandType: '📋 SSH Command',
+ sshCommandType: 'SSH Command',
signerLabel: 'Signer',
official: 'Official',
noteLabel: 'Note',
autoLoadAfterRestart: 'Auto-load after restart',
- configExistsWarning: '⚠️ Config already exists, import will overwrite',
+ configExistsWarning: 'Config already exists, import will overwrite',
typeWithComment: 'Type: {type} | Note: {comment}',
// Config Pack UI
configPack: 'Config Pack',
- configPackDesc: '💡 Config pack system allows secure encryption and signing of config files for device-to-device distribution',
+ configPackDesc: 'Config pack system allows secure encryption and signing of config files for device-to-device distribution',
exportDeviceCert: 'Export Device Cert',
importConfigPack: 'Import Config Pack',
exportConfigPack: 'Export Config Pack',
@@ -1618,7 +1618,7 @@ i18n.registerLanguage('en-US', {
otaServer: 'OTA Server',
saveToDevice: 'Save to Device',
save: 'Save',
- checkUpdate: '🔍 Check Update',
+ checkUpdate: 'Check Update',
preparing: 'Preparing...',
valid: 'Valid',
invalid: 'Invalid',
@@ -1746,12 +1746,12 @@ i18n.registerLanguage('en-US', {
loadingOptions: '-- Loading --',
sourceNoData: 'No variable data for this source',
configSourceFirst: 'Please configure and enable data source first',
- testRequesting: '🔄 Requesting...',
- testSuccess: '✅ Connection successful',
- testFailed: '❌ Request failed',
- testError: '❌ Error',
- testConnecting: '🔄 Connecting...',
- testConnected: '✅ Connected, data received',
+ testRequesting: 'Requesting...',
+ testSuccess: 'Connection successful',
+ testFailed: 'Request failed',
+ testError: 'Error',
+ testConnecting: 'Connecting...',
+ testConnected: 'Connected, data received',
noExtraParams: 'No extra parameters for this filter',
selectCmdHint: 'Select command to monitor (created in SSH page)',
selectHostFirst: '-- Select host first --',
@@ -1764,7 +1764,7 @@ i18n.registerLanguage('en-US', {
// SSH command reference preview
selectCommand: 'Select Command',
selectCommandHint: 'Select a command configured in SSH management page',
- commandDetails: '📋 Command Details',
+ commandDetails: 'Command Details',
previewHost: 'Host',
previewCommand: 'Command',
previewVariable: 'Variable',
@@ -1776,17 +1776,17 @@ i18n.registerLanguage('en-US', {
selectDevice: '-- Select Device --',
selectDeviceHint: 'Select LED device to control',
controlType: 'Control Type',
- colorFill: '🎨 Color Fill',
+ colorFill: 'Color Fill',
effectAnim: '🎬 Effect Animation',
- brightnessOnly: '☀️ Brightness Only',
- turnOff: '⏹ Turn Off',
+ brightnessOnly: 'Brightness Only',
+ turnOff: 'Turn Off',
textDisplay: '📝 Text Display',
imageDisplay: '📷 Display Image',
qrcodeDisplay: '📱 Display QR Code',
- filterDisplay: '🎨 Post Filter',
- filterStop: '⏹ Stop Filter',
- textStop: '⏹ Stop Text',
- turnOffDevice: '⏹ Turn Off Device',
+ filterDisplay: 'Post Filter',
+ filterStop: 'Stop Filter',
+ textStop: 'Stop Text',
+ turnOffDevice: 'Turn Off Device',
logConfig: 'Log Config',
logLevel: 'Level',
logMessage: 'Message',
@@ -1838,10 +1838,10 @@ i18n.registerLanguage('en-US', {
viewLog: 'View Log',
stopProcess: 'Stop',
// Log viewer
- logTitle: '📄 Log',
+ logTitle: 'Log',
loading: 'Loading...',
- stopTracking: '⏹️ Stop Tracking',
- startTracking: '▶️ Start Tracking',
+ stopTracking: 'Stop Tracking',
+ startTracking: 'Start Tracking',
interval: 'Interval',
realTimeUpdating: '● Real-time updating',
trackingStopped: 'Tracking stopped',
@@ -1953,23 +1953,23 @@ i18n.registerLanguage('en-US', {
filterLabel: 'Filter',
filterPulse: '💓 Pulse',
filterBreathing: '💨 Breathing',
- filterBlink: '💡 Blink',
+ filterBlink: 'Blink',
filterWave: '🌊 Wave',
filterScanline: '📺 Scanline',
filterGlitch: '⚡ Glitch',
filterRainbow: '🌈 Rainbow',
filterSparkle: '✨ Sparkle',
filterPlasma: '🎆 Plasma',
- filterSepia: '🖼️ Sepia',
- filterPosterize: '🎨 Posterize',
- filterContrast: '🔆 Contrast',
- filterInvert: '🔄 Invert',
- filterGrayscale: '⬜ Grayscale',
+ filterSepia: 'Sepia',
+ filterPosterize: 'Posterize',
+ filterContrast: 'Contrast',
+ filterInvert: 'Invert',
+ filterGrayscale: 'Grayscale',
// Variable action placeholders
varValuePlaceholder: 'Supports expressions and variable references',
varValueHint: 'Example: true, 123, ${other_var}',
// Search
- searchVariablePlaceholder: '🔍 Search variables...'
+ searchVariablePlaceholder: 'Search variables...'
},
// Fan Control
@@ -1987,24 +1987,24 @@ i18n.registerLanguage('en-US', {
cleared: 'Cleared',
noWidgets: 'No widgets',
// Fan card
- fanTitle: '🌀 Fan {id}',
+ fanTitle: 'Fan {id}',
modeOff: 'Off',
modeManual: 'Manual',
modeAuto: 'Auto',
modeCurve: 'Curve',
speedAdjust: 'Speed Adjust',
- editTempCurve: '⚙️ Edit Temperature Curve',
+ editTempCurve: 'Edit Temperature Curve',
manualModeHint: 'Switch to manual mode to adjust',
// Curve management modal
curveManagement: '📈 Fan Curve Management',
selectFan: 'Select Fan',
fanN: 'Fan {id}',
- bindTempVar: '🌡️ Bind Temperature Variable',
+ bindTempVar: 'Bind Temperature Variable',
unbound: 'Unbound',
bound: 'Bound',
selectVariableHint: 'Select a float variable as temperature source (e.g. agx.cpu_temp)',
bind: '💾 Bind',
- unbind: '🗑️ Unbind',
+ unbind: 'Unbind',
tempSpeedCurve: '📊 Temperature-Speed Curve',
addPoint: '➕ Add Point',
curveHint: 'Uses min speed below lowest point, max speed above highest point',
@@ -2018,7 +2018,7 @@ i18n.registerLanguage('en-US', {
minInterval: 'Min Interval (ms)',
intervalHint: 'Minimum time between adjustments',
cancel: 'Cancel',
- applyCurve: '✅ Apply Curve',
+ applyCurve: 'Apply Curve',
// Curve points
tempPlaceholder: 'Temp',
speedPlaceholder: 'Speed'
@@ -2075,7 +2075,7 @@ i18n.registerLanguage('en-US', {
presetLog: 'Log Stream',
// Management interface
management: 'Data Component Management',
- panelSettings: '⚙️ Panel Settings',
+ panelSettings: 'Panel Settings',
autoRefreshInterval: 'Auto Refresh Interval',
disabled: 'Disabled',
second: 's',
@@ -2086,7 +2086,7 @@ i18n.registerLanguage('en-US', {
seconds10: '10 sec',
seconds30: '30 sec',
minute1: '1 min',
- addedWidgets: '📦 Added Widgets',
+ addedWidgets: 'Added Widgets',
addNewWidget: '➕ Add New Widget',
selectWidgetHint: 'Select a widget to edit
or add a new one',
moveUp: 'Move Up',
@@ -2130,7 +2130,7 @@ i18n.registerLanguage('en-US', {
statusAttention: 'Attention',
statusWarning: 'Warning',
// Temperature variable selection
- tempVariables: '🌡️ Temperature Variables',
+ tempVariables: 'Temperature Variables',
otherNumericVariables: '📊 Other Numeric Variables',
// Error messages
setDutyLimitFailed: 'Failed to set duty cycle limit',
@@ -2153,8 +2153,8 @@ i18n.registerLanguage('en-US', {
fillColor: 'Fill Color',
quickColors: 'Quick Colors',
// Original
- on: '🔆 On',
- off: '💡 Off',
+ on: 'On',
+ off: 'Off',
defaultFont: 'Default',
quickActionsLoadFailed: 'Failed to load quick actions',
realTimeUpdating: '● Real-time updating',
@@ -2294,14 +2294,14 @@ i18n.registerLanguage('en-US', {
// PKI/Security Config
pkiPage: {
- signatureVerified: '✅ Signature verified',
- configImported: '✅ Config package imported',
+ signatureVerified: 'Signature verified',
+ configImported: 'Config package imported',
savedTo: 'Saved to',
- loadingFiles: '🔄 Loading...',
- noConfigFiles: '📁 No config files (.json)',
- loadError: '❌ Load failed',
+ loadingFiles: 'Loading...',
+ noConfigFiles: 'No config files (.json)',
+ loadError: 'Load failed',
noTscfgFiles: 'No .tscfg files in directory',
- contentEmpty: '⚠️ Warning: Config package content is empty',
+ contentEmpty: 'Warning: Config package content is empty',
// PKI Status
statusNotInit: 'Not Initialized',
statusKeyGenerated: 'Key Generated, Awaiting CSR',
@@ -2311,26 +2311,26 @@ i18n.registerLanguage('en-US', {
statusError: 'Error',
statusLoadFailed: 'Load Failed',
deviceType: '{type} Device',
- certValid: '✅ Valid',
- certInvalid: '❌ Invalid',
+ certValid: 'Valid',
+ certInvalid: 'Invalid',
expiredDays: 'Expired {days} days ago',
expiresInDays: 'Expires in {days} days',
remainingDays: '{days} days remaining',
- generatingKeyPair: '🔄 Generating key pair...',
- generatingCsr: '🔄 Generating CSR...',
- installFailed: '❌ Install failed',
+ generatingKeyPair: 'Generating key pair...',
+ generatingCsr: 'Generating CSR...',
+ installFailed: 'Install failed',
// Config Pack
enterConfigName: 'Please enter config name',
selectConfigFile: 'Please select config file',
pasteTargetCert: 'Please paste target device certificate',
invalidJsonConfig: 'Config file is not valid JSON',
- generatingPack: '🔄 Generating config pack',
- savedToDevice: '✅ Saved to device',
- generationFailed: '❌ Generation failed',
- verifying: '🔄 Verifying...',
- verifyFailed: '❌ Verification failed',
- importing: '🔄 Importing...',
- importFailed: '❌ Import failed',
+ generatingPack: 'Generating config pack',
+ savedToDevice: 'Saved to device',
+ generationFailed: 'Generation failed',
+ verifying: 'Verifying...',
+ verifyFailed: 'Verification failed',
+ importing: 'Importing...',
+ importFailed: 'Import failed',
uploadOrPasteContent: 'Please upload file or paste config pack content'
},
@@ -2341,10 +2341,10 @@ i18n.registerLanguage('en-US', {
english: 'EN',
notLoggedIn: 'Not Logged In',
// Button States
- stopTracking: '⏹️ Stop Tracking',
- startTracking: '▶️ Start Tracking',
- testing: '⏳ Testing...',
- connecting: '⏳ Connecting...',
+ stopTracking: 'Stop Tracking',
+ startTracking: 'Start Tracking',
+ testing: 'Testing...',
+ connecting: 'Connecting...',
cancelling: 'Cancelling...',
// Hints
noOutput: '(No output)',
@@ -2357,9 +2357,9 @@ i18n.registerLanguage('en-US', {
colorSettings: 'Color Settings',
turnOffLight: 'Turn Off',
// OTA
- firmwareUpgradeComplete: '✅ Firmware upgrade complete, preparing WebUI upgrade...',
- allUpgradeComplete: '✅ All upgrades complete',
- preparingUpgrade: '⏳ Preparing upgrade...',
+ firmwareUpgradeComplete: 'Firmware upgrade complete, preparing WebUI upgrade...',
+ allUpgradeComplete: 'All upgrades complete',
+ preparingUpgrade: 'Preparing upgrade...',
initializing: 'Initializing...',
downloadingFromServer: 'Downloading from OTA server',
connectingServer: 'Connecting to server...',
@@ -2367,11 +2367,11 @@ i18n.registerLanguage('en-US', {
writingFlash: 'Writing to Flash (this may take 1-2 minutes)...',
webuiSize: 'WebUI size',
writingSpiffs: 'Writing to SPIFFS...',
- upgradeFailed: '❌ Upgrade failed',
+ upgradeFailed: 'Upgrade failed',
downloading: 'Downloading...',
waitedSeconds: 'Waited {elapsed} seconds...',
step2Webui: '[2/2] Starting WebUI upgrade...',
- firmwareOnlyComplete: '✅ Firmware upgrade complete (WebUI skipped)',
+ firmwareOnlyComplete: 'Firmware upgrade complete (WebUI skipped)',
updateTime: 'Update time',
// System
psramUnavailable: 'Unavailable',
@@ -2384,10 +2384,10 @@ i18n.registerLanguage('en-US', {
displayStats: 'Showing {filtered}/{total} entries',
// Modal Titles
newCommand: '➕ New Command',
- editCommand: '✏️ Edit Command',
+ editCommand: 'Edit Command',
commandVariables: '📊 Command Variables',
sourceVariables: '📊 {source} Variables',
- editActionTemplate: '✏️ Edit Action Template',
+ editActionTemplate: 'Edit Action Template',
// Actions
updateAction: '💾 Update',
// Validation Errors
@@ -2403,7 +2403,7 @@ i18n.registerLanguage('en-US', {
configNotSet: '(Not configured)',
// Pattern Match Results
expectPatternConfigured: 'Not configured',
- failPatternDetected: '⚠️ true (Error detected)',
+ failPatternDetected: 'true (Error detected)',
extractedNone: 'None',
extracting: 'Extracting...',
// Status Mapping
@@ -2411,10 +2411,10 @@ i18n.registerLanguage('en-US', {
statusFailed: 'Failed',
statusRunning: 'Running',
statusTimeout: 'Timeout',
- expectMatchYes: '✅ Yes',
- expectMatchNo: '❌ No',
- failMatchYes: '⚠️ Yes',
- failMatchNo: '✅ No',
+ expectMatchYes: 'Yes',
+ expectMatchNo: 'No',
+ failMatchYes: 'Yes',
+ failMatchNo: 'No',
// innerHTML related translation keys
loadFailed: 'Load Failed',
noVariableData: 'No variable data for this command, please execute once first',
@@ -2470,10 +2470,10 @@ i18n.registerLanguage('en-US', {
confirmRemoveHostLocal: 'Are you sure you want to remove host "{id}" from the list?\n\nNote: This only removes the local record, not the public key deployed on the server. To revoke the key, use the "Revoke" button.',
confirmRemoveHostLocal2: 'Are you sure you want to remove host "{id}" from the list?\n\nNote: This only removes the local record, not the public key deployed on the server. To revoke the key, use the "Revoke" function in Key Management.',
confirmDeleteKey: 'Are you sure you want to delete key "{id}"? This action cannot be undone!',
- confirmExportPrivateKey: '⚠️ Security Warning\n\nYou are about to export private key "{id}".\n\nPrivate keys are highly sensitive credentials. Please ensure:\n• Do not transmit over public networks\n• Do not share with others\n• Store securely locally\n\nAre you sure you want to continue?',
+ confirmExportPrivateKey: 'Security Warning\n\nYou are about to export private key "{id}".\n\nPrivate keys are highly sensitive credentials. Please ensure:\n• Do not transmit over public networks\n• Do not share with others\n• Store securely locally\n\nAre you sure you want to continue?',
confirmRemoveKnownHost: 'Are you sure you want to remove the record for "{host}:{port}"?',
confirmClearKnownHosts: 'Are you sure you want to clear all known host records? This action cannot be undone!',
- confirmDeletePKI: '⚠️ Are you sure you want to delete all PKI credentials?\n\nThis will delete:\n• Private key\n• Device certificate\n• CA certificate chain\n\nThis action cannot be undone!',
+ confirmDeletePKI: 'Are you sure you want to delete all PKI credentials?\n\nThis will delete:\n• Private key\n• Device certificate\n• CA certificate chain\n\nThis action cannot be undone!',
// Alert dialogs and other prompts
alertHostFingerprint: 'Host: {host}:{port}\nType: {type}\nFingerprint (SHA256):\n{fingerprint}',
alertEnterWsAddress: 'Please enter WebSocket address',
diff --git a/components/ts_webui/web/js/lang/zh-CN.js b/components/ts_webui/web/js/lang/zh-CN.js
index 27e3e5c..a2616f2 100644
--- a/components/ts_webui/web/js/lang/zh-CN.js
+++ b/components/ts_webui/web/js/lang/zh-CN.js
@@ -702,8 +702,8 @@ i18n.registerLanguage('zh-CN', {
// 服务
serviceSuccess: '服务 {name} {action} 成功',
// 电压保护
- voltageProtectionEnabled: '✅ 电压保护已启用',
- voltageProtectionDisabled: '⚠️ 电压保护已禁用',
+ voltageProtectionEnabled: '电压保护已启用',
+ voltageProtectionDisabled: '电压保护已禁用',
switchFailed: '切换失败',
// USB 切换
usbSwitching: '切换 USB 到 {target}...',
@@ -716,7 +716,7 @@ i18n.registerLanguage('zh-CN', {
widgetBound: '已绑定 {widget} → {var}',
// 快捷操作
processRunning: '进程正在运行中,请先停止',
- cardNotFound: '❌ 无法找到操作卡片',
+ cardNotFound: '无法找到操作卡片',
executionFailed: '执行失败',
processTerminated: '已终止进程',
processNotExist: '进程已不存在',
@@ -776,7 +776,7 @@ i18n.registerLanguage('zh-CN', {
rollbackFailed: '回滚失败',
upgradeAborted: '升级已中止',
abortFailed: '中止失败',
- otaServerSaved: '✅ OTA 服务器地址已保存',
+ otaServerSaved: 'OTA 服务器地址已保存',
otaServerCleared: 'OTA 服务器地址已清除',
enterOtaServer: '请先输入 OTA 服务器地址',
upgradeFailed: '升级失败',
@@ -797,8 +797,8 @@ i18n.registerLanguage('zh-CN', {
deleteActionResult: '删除动作 {id}',
deleteSourceResult: '删除数据源 {id}',
deleteSourceFailed: '删除数据源失败',
- shutdownSettingsSaved: '✅ 关机设置已保存',
- defaultsRestored: '✅ 已恢复默认设置',
+ shutdownSettingsSaved: '关机设置已保存',
+ defaultsRestored: '已恢复默认设置',
restoreFailed: '恢复失败',
deleteRuleResult: '删除规则 {id}',
deleteRuleFailed: '删除规则失败',
@@ -916,8 +916,8 @@ i18n.registerLanguage('zh-CN', {
hostInfoEmpty: '主机信息为空',
testingConnection: '正在测试连接 {host}...',
cannotGetHostInfo: '无法获取主机信息',
- connectionSuccess: '✅ 连接 {host} 成功!',
- testConnectionFailed: '❌ 测试失败',
+ connectionSuccess: '连接 {host} 成功!',
+ testConnectionFailed: '测试失败',
hostConfigExported: '已导出主机配置: {filename}',
sshHostRemoved: 'SSH 主机 {id} 已从列表移除',
removeFailed: '移除失败',
@@ -938,9 +938,9 @@ i18n.registerLanguage('zh-CN', {
clearFailed: '清除失败',
certCopiedToClipboard: '证书已复制到剪贴板',
// PKI 配置
- applyingConfig: '🔄 正在应用配置...',
- configApplied: '✅ 配置已应用\n模块: {modules}',
- applyFailed: '❌ 应用失败',
+ applyingConfig: '正在应用配置...',
+ configApplied: '配置已应用\n模块: {modules}',
+ applyFailed: '应用失败',
onlyDeveloperCanExport: '仅 Developer 设备可导出配置包',
selectedJsonFiles: '已选择当前目录下的所有 JSON 文件',
configPackCopied: '配置包已复制到剪贴板',
@@ -953,12 +953,12 @@ i18n.registerLanguage('zh-CN', {
// 设备控制
device: {
- agxRunning: '🟢 AGX 运行中',
- agxStopped: '🔴 AGX 已关闭',
- lpmuRunning: '🟢 LPMU 运行中',
- lpmuStopped: '🔴 LPMU 已关闭',
- lpmuDetecting: '⏳ 状态获取中',
- lpmuUnknown: '⚠️ LPMU 状态未知',
+ agxRunning: 'AGX 运行中',
+ agxStopped: 'AGX 已关闭',
+ lpmuRunning: 'LPMU 运行中',
+ lpmuStopped: 'LPMU 已关闭',
+ lpmuDetecting: '状态获取中',
+ lpmuUnknown: 'LPMU 状态未知',
lpmuOnlineHint: 'LPMU 在线 (ping 10.10.99.99 可达)\n点击触发电源按钮',
lpmuOfflineHint: 'LPMU 离线 (ping 10.10.99.99 不可达)\n点击触发电源按钮',
lpmuDetectingHint: '正在检测 LPMU 状态...\n最多等待 80 秒',
@@ -1054,12 +1054,12 @@ i18n.registerLanguage('zh-CN', {
filePage: {
dirNotExist: '目录不存在',
createDir: '创建目录',
- emptyFolder: '📂 空文件夹',
- noImages: '📂 无图片文件',
+ emptyFolder: '空文件夹',
+ noImages: '无图片文件',
noFonts: '无可用字体',
uploading: '上传中...',
- uploadComplete: '✓ 完成',
- uploadError: '✕ 失败',
+ uploadComplete: '完成',
+ uploadError: '失败',
confirmDelete: '确定要删除这个文件吗?',
// 对话框
uploadFiles: '上传文件',
@@ -1150,12 +1150,12 @@ i18n.registerLanguage('zh-CN', {
// SSH/Commands 页面
sshPage: {
// 服务状态标签
- statusReady: '✅ 就绪',
- statusChecking: '🔄 检测中',
- statusTimeout: '⚠️ 超时',
- statusFailed: '❌ 失败',
+ statusReady: '就绪',
+ statusChecking: '检测中',
+ statusTimeout: '超时',
+ statusFailed: '失败',
statusIdle: '⏸️ 未启动',
- statusStopped: '⏹️ 已停止',
+ statusStopped: '已停止',
// 错误消息
hostNotFound: '主机信息不存在',
cmdNotFound: '命令不存在',
@@ -1223,31 +1223,31 @@ i18n.registerLanguage('zh-CN', {
exitCode: '退出码',
waitingOutput: '等待输出...',
sessionId: '会话 ID',
- commandSubmitted: '✅ 命令已提交到服务器后台',
- useButtonsAbove: '💡 使用上方按钮查看日志、跟踪输出或检查进程状态',
- logFile: '📄 日志文件',
- processKeyword: '🔍 进程关键词',
- startTailLog: '📡 开始实时跟踪',
+ commandSubmitted: '命令已提交到服务器后台',
+ useButtonsAbove: '使用上方按钮查看日志、跟踪输出或检查进程状态',
+ logFile: '日志文件',
+ processKeyword: '进程关键词',
+ startTailLog: '开始实时跟踪',
clickToExit: '(点击"停止跟踪"按钮退出)',
- stoppedTailLog: '⏹️ 已停止实时跟踪',
- viewServiceLog: '📄 查看服务日志',
+ stoppedTailLog: '已停止实时跟踪',
+ viewServiceLog: '查看服务日志',
file: '文件',
- stopService: '🛑 停止服务',
+ stopService: '停止服务',
processRunningPid: '进程运行中 (PID: {pid}),正在停止...',
- serviceStopped: '✅ 服务已停止',
- tryForceKill: '⚠️ 进程可能仍在运行,尝试强制终止...',
- forceKilled: '✅ 已强制终止',
- processAlreadyStopped: '⚠️ 进程已经停止',
- pidFileNotExist: '⚠️ PID 文件不存在,服务可能未启动',
+ serviceStopped: '服务已停止',
+ tryForceKill: '进程可能仍在运行,尝试强制终止...',
+ forceKilled: '已强制终止',
+ processAlreadyStopped: '进程已经停止',
+ pidFileNotExist: 'PID 文件不存在,服务可能未启动',
stopServiceFailed: '停止服务失败',
executionFailed: '执行失败',
getLogFailed: '获取日志失败',
- patternMatchSuccess: '🎯 模式匹配成功!',
- expectPatternMatch: '✅ 期望模式匹配: 是',
- failPatternMatch: '❌ 失败模式匹配: 是',
- extractedContent: '📋 提取内容',
- cancelledExecution: '⏹️ 已取消执行',
- error: '❌ 错误',
+ patternMatchSuccess: '模式匹配成功!',
+ expectPatternMatch: '期望模式匹配: 是',
+ failPatternMatch: '失败模式匹配: 是',
+ extractedContent: '提取内容',
+ cancelledExecution: '已取消执行',
+ error: '错误',
// nohup 快捷操作
tailLog: '实时跟踪',
stopTail: '停止跟踪',
@@ -1260,20 +1260,20 @@ i18n.registerLanguage('zh-CN', {
commandLabel: '命令',
storeVar: '存储变量',
// 配置包相关
- generatingConfigPack: '🔄 正在生成配置包...',
- exportSuccess: '✅ 导出成功!',
- verifyingConfigPack: '🔄 正在验证配置包...',
- signatureVerified: '✅ 签名验证通过',
- savingConfig: '🔄 正在保存配置...',
- configExists: '⚠️ 配置 {id} 已存在,请勾选「覆盖」选项',
- configSaved: '✅ 已保存配置',
+ generatingConfigPack: '正在生成配置包...',
+ exportSuccess: '导出成功!',
+ verifyingConfigPack: '正在验证配置包...',
+ signatureVerified: '签名验证通过',
+ savingConfig: '正在保存配置...',
+ configExists: '配置 {id} 已存在,请勾选「覆盖」选项',
+ configSaved: '已保存配置',
// SSH 导入导出弹窗
exportSshCmdTitle: '导出 SSH 指令配置',
exportSshCmdDesc: '导出指令
{cmdId} 的配置为加密配置包',
includeHostConfig: '同时导出依赖的主机配置',
- includeHostRecommend: '💡 推荐勾选,便于在目标设备完整导入',
+ includeHostRecommend: '推荐勾选,便于在目标设备完整导入',
targetCert: '目标设备证书 (PEM)',
- targetCertHint: '💡 粘贴目标设备的证书。留空则使用本机证书(自加密)',
+ targetCertHint: '粘贴目标设备的证书。留空则使用本机证书(自加密)',
importSshCmdTitle: '导入 SSH 指令配置',
importSshCmdDesc: '选择 .tscfg 配置包文件以导入 SSH 指令',
selectFile: '选择文件',
@@ -1288,14 +1288,14 @@ i18n.registerLanguage('zh-CN', {
exportedWithoutHost: '已导出指令配置: {filename}',
importCommand: '导入指令',
// 部署/撤销
- deployingKey: '🔄 正在部署密钥...',
- deploySuccess: '✅ 部署成功!现在可以使用密钥 "{keyId}" 免密登录 {target}',
- authVerified: '✓ 公钥认证已验证',
+ deployingKey: '正在部署密钥...',
+ deploySuccess: '部署成功!现在可以使用密钥 "{keyId}" 免密登录 {target}',
+ authVerified: '公钥认证已验证',
authSkipped: '⚠ 公钥认证验证跳过',
- revokingKey: '🔄 正在撤销密钥...',
- revokeSuccess: '✅ 撤销成功!已从 {target} 移除 {count} 个匹配的公钥',
- keyNotFound: '⚠️ 该公钥未在 {target} 上找到',
- removeLocalOnly: '🗑️ 仅移除本地记录',
+ revokingKey: '正在撤销密钥...',
+ revokeSuccess: '撤销成功!已从 {target} 移除 {count} 个匹配的公钥',
+ keyNotFound: '该公钥未在 {target} 上找到',
+ removeLocalOnly: '仅移除本地记录',
// 命令编辑器 placeholder
cmdIdPlaceholder: '例如:restart_nginx, check_status',
cmdNamePlaceholder: '例如:重启服务',
@@ -1379,7 +1379,7 @@ i18n.registerLanguage('zh-CN', {
readyTimeoutHint: '超过此时间未匹配到就绪模式则标记为 timeout',
readyIntervalLabel: '检测间隔(毫秒)',
readyIntervalHint: '每隔多久检测一次日志文件',
- serviceLogHint: '💡 服务启动后,系统将监测日志文件:',
+ serviceLogHint: '服务启动后,系统将监测日志文件:',
serviceLogPath: '/tmp/ts_nohup_[命令名].log',
serviceStatusHint: '变量 [变量名].status 会根据日志匹配自动更新状态',
varNameLabel: '存储变量名',
@@ -1408,7 +1408,7 @@ i18n.registerLanguage('zh-CN', {
connectingWaitingEvent: '正在连接并等待事件: {event}',
connectingAutoDiscover: '正在连接并自动发现事件...',
unknownEvent: '(未知事件)',
- sioConnectionSuccess: '✅ 连接成功',
+ sioConnectionSuccess: '连接成功',
eventLabel: '事件',
timeout: '超时时间',
reconnectInterval: '断线重连间隔',
@@ -1467,11 +1467,11 @@ i18n.registerLanguage('zh-CN', {
configDescPlaceholder: 'LED 特效配置',
targetDeviceCert: '目标设备证书 (PEM)',
certPlaceholder: '-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----',
- certHint: '💡 粘贴目标设备导出的证书',
+ certHint: '粘贴目标设备导出的证书',
generateConfigPack: '📦 生成配置包',
generatedConfigPack: '生成的配置包 (.tscfg)',
configPackPlaceholder: '配置包将在此显示...',
- copyToClipboard: '📋 复制到剪贴板',
+ copyToClipboard: '复制到剪贴板',
downloadToLocal: '💾 下载到本地',
// 文件选择状态
selectedFiles: '已选择 {count} 个文件',
@@ -1495,21 +1495,21 @@ i18n.registerLanguage('zh-CN', {
keysTableCreated: '创建时间',
keysTableExportable: '可导出',
keysTableActions: '操作',
- hostsHint: '💡 通过上方密钥的「部署」按钮将公钥部署到远程服务器后,主机将自动出现在此列表',
+ hostsHint: '通过上方密钥的「部署」按钮将公钥部署到远程服务器后,主机将自动出现在此列表',
importHost: '📥 导入主机',
hostId: '主机 ID',
address: '地址',
port: '端口',
username: '用户名',
deployKey: '部署密钥',
- fingerprintHint: '💡 SSH 连接时自动记录的服务器指纹,用于防止中间人攻击。如果服务器重装需要更新指纹。',
+ fingerprintHint: 'SSH 连接时自动记录的服务器指纹,用于防止中间人攻击。如果服务器重装需要更新指纹。',
keyType: '密钥类型',
fingerprintSha256: '指纹 (SHA256)',
addedTime: '添加时间',
// SSH 主机导入/导出
- exportSshHostTitle: '📤 导出 SSH 主机配置',
+ exportSshHostTitle: '导出 SSH 主机配置',
exportSshHostDesc: '导出主机 {hostId} 的配置为加密配置包',
- exportSshHostCertHint: '💡 粘贴目标设备的证书。留空则使用本机证书(自加密)',
+ exportSshHostCertHint: '粘贴目标设备的证书。留空则使用本机证书(自加密)',
importSshHostTitle: '📥 导入 SSH 主机配置',
importSshHostDesc: '选择 .tscfg 配置包文件以导入 SSH 主机配置',
confirmImport: '📥 确认导入',
@@ -1518,28 +1518,28 @@ i18n.registerLanguage('zh-CN', {
deployKeyDesc: '将公钥 {keyId} 部署到远程服务器的 authorized_keys',
targetHost: '目标主机',
authPassword: '认证密码 (首次部署需要)',
- deployHint: '💡 部署成功后,该主机将自动添加到「已部署主机」列表,之后可使用此密钥免密登录',
+ deployHint: '部署成功后,该主机将自动添加到「已部署主机」列表,之后可使用此密钥免密登录',
startDeploy: '🚀 开始部署',
// 撤销密钥弹窗
- revokeKeyTitle: '⚠️ 撤销公钥',
+ revokeKeyTitle: '撤销公钥',
revokeKeyDesc: '从远程服务器移除公钥 {keyId}',
- revokeWarning: '⚠️ 警告:撤销后将无法使用此密钥免密登录该服务器',
- revokePublicKey: '⚠️ 撤销公钥',
+ revokeWarning: '警告:撤销后将无法使用此密钥免密登录该服务器',
+ revokePublicKey: '撤销公钥',
// 主机指纹不匹配警告
- hostMismatchTitle: '⚠️ 安全警告:主机指纹不匹配!',
+ hostMismatchTitle: '安全警告:主机指纹不匹配!',
hostMismatchDesc: '主机密钥已更改!这可能表明:',
hostMismatchReason1: '服务器已重装系统',
hostMismatchReason2: '存在中间人攻击',
hostMismatchReason3: '服务器 IP 已分配给其他设备',
hostMismatchAdvice: '建议:如果您确认服务器已重装或密钥已更新,可以点击"更新主机密钥"移除旧记录,然后重新连接以信任新密钥。',
- updateHostKey: '🔄 更新主机密钥',
- abortOperation: '❌ 中止操作',
+ updateHostKey: '更新主机密钥',
+ abortOperation: '中止操作',
storedFingerprint: '存储的指纹',
currentFingerprint: '当前指纹',
// HTTPS 证书弹窗
genHttpsKeyPairTitle: '🔑 生成 HTTPS 密钥对',
genHttpsKeyPairDesc: '为设备生成 ECDSA P-256 密钥对,用于 mTLS 身份验证',
- existingKeyWarning: '⚠️ 已存在密钥对,继续将覆盖现有密钥!',
+ existingKeyWarning: '已存在密钥对,继续将覆盖现有密钥!',
generate: '🔑 生成',
csrTitle: '证书签名请求 (CSR)',
deviceId: '设备 ID (CN)',
@@ -1554,25 +1554,25 @@ i18n.registerLanguage('zh-CN', {
installCaTitle: '安装 CA 证书链',
installCaDesc: '粘贴根证书和中间证书(PEM 格式,可拼接多个)',
caCertPem: 'CA 证书链 PEM',
- deleteCredentialsTitle: '🗑️ 删除 HTTPS 凭证',
+ deleteCredentialsTitle: '删除 HTTPS 凭证',
deleteCredentialsDesc: '此操作将删除密钥对和证书,删除后需要重新生成',
- deleteCredentialsWarning: '⚠️ 警告:删除后设备将无法进行 mTLS 认证,直到重新配置',
- confirmDelete: '⚠️ 确认删除',
+ deleteCredentialsWarning: '警告:删除后设备将无法进行 mTLS 认证,直到重新配置',
+ confirmDelete: '确认删除',
viewCertTitle: '查看证书详情',
close: '关闭',
// 配置包验证
configId: '配置 ID',
type: '类型',
- sshCommandType: '📋 SSH 指令',
+ sshCommandType: 'SSH 指令',
signerLabel: '签名者',
official: '官方',
noteLabel: '备注',
autoLoadAfterRestart: '重启后自动加载',
- configExistsWarning: '⚠️ 该配置已存在,导入将覆盖现有文件',
+ configExistsWarning: '该配置已存在,导入将覆盖现有文件',
typeWithComment: '类型: {type} | 备注: {comment}',
// 配置包 UI
configPack: '配置包 (Config Pack)',
- configPackDesc: '💡 配置包系统允许安全地加密和签名配置文件,用于设备间配置分发',
+ configPackDesc: '配置包系统允许安全地加密和签名配置文件,用于设备间配置分发',
exportDeviceCert: '导出设备证书',
importConfigPack: '导入配置包',
exportConfigPack: '导出配置包',
@@ -1619,7 +1619,7 @@ i18n.registerLanguage('zh-CN', {
otaServer: 'OTA 服务器',
saveToDevice: '保存到设备',
save: '保存',
- checkUpdate: '🔍 检查更新',
+ checkUpdate: '检查更新',
preparing: '准备中...',
valid: '有效',
invalid: '无效',
@@ -1747,12 +1747,12 @@ i18n.registerLanguage('zh-CN', {
loadingOptions: '-- 加载中 --',
sourceNoData: '该数据源暂无变量数据',
configSourceFirst: '请先配置数据源并启用',
- testRequesting: '🔄 正在请求...',
- testSuccess: '✅ 连接成功',
- testFailed: '❌ 请求失败',
- testError: '❌ 错误',
- testConnecting: '🔄 正在连接...',
- testConnected: '✅ 连接成功,已收到数据',
+ testRequesting: '正在请求...',
+ testSuccess: '连接成功',
+ testFailed: '请求失败',
+ testError: '错误',
+ testConnecting: '正在连接...',
+ testConnected: '连接成功,已收到数据',
noExtraParams: '此滤镜无额外参数',
selectCmdHint: '选择要监视的指令(在 SSH 页面创建)',
selectHostFirst: '-- 先选择主机 --',
@@ -1765,7 +1765,7 @@ i18n.registerLanguage('zh-CN', {
// SSH 命令引用预览
selectCommand: '选择命令',
selectCommandHint: '选择已在 SSH 管理页面配置的命令',
- commandDetails: '📋 命令详情',
+ commandDetails: '命令详情',
previewHost: '主机',
previewCommand: '命令',
previewVariable: '变量',
@@ -1839,9 +1839,9 @@ i18n.registerLanguage('zh-CN', {
viewLog: '查看日志',
stopProcess: '停止',
// 日志查看
- logTitle: '📄 日志',
+ logTitle: '日志',
loading: '加载中...',
- stopTracking: '⏹️ 停止跟踪',
+ stopTracking: '停止跟踪',
startTracking: '▶️ 开始跟踪',
interval: '间隔',
realTimeUpdating: '● 实时更新中',
@@ -1954,7 +1954,7 @@ i18n.registerLanguage('zh-CN', {
filterLabel: '滤镜',
filterPulse: '💓 脉冲',
filterBreathing: '💨 呼吸',
- filterBlink: '💡 闪烁',
+ filterBlink: '闪烁',
filterWave: '🌊 波浪',
filterScanline: '📺 扫描线',
filterGlitch: '⚡ 故障艺术',
@@ -1964,13 +1964,13 @@ i18n.registerLanguage('zh-CN', {
filterSepia: '🖼️ 怀旧',
filterPosterize: '🎨 色阶分离',
filterContrast: '🔆 对比度',
- filterInvert: '🔄 反色',
+ filterInvert: '反色',
filterGrayscale: '⬜ 灰度',
// 变量动作 placeholder
varValuePlaceholder: '支持表达式和变量引用',
varValueHint: '示例: true, 123, ${other_var}',
// 搜索
- searchVariablePlaceholder: '🔍 搜索变量...'
+ searchVariablePlaceholder: '搜索变量...'
},
// 风扇控制
@@ -1988,13 +1988,13 @@ i18n.registerLanguage('zh-CN', {
cleared: '已清空',
noWidgets: '暂无组件',
// 风扇卡片
- fanTitle: '🌀 风扇 {id}',
+ fanTitle: '风扇 {id}',
modeOff: '关闭',
modeManual: '手动',
modeAuto: '自动',
modeCurve: '曲线',
speedAdjust: '转速调节',
- editTempCurve: '⚙️ 编辑温度曲线',
+ editTempCurve: '编辑温度曲线',
manualModeHint: '切换到手动模式后可调节',
// 曲线管理模态框
curveManagement: '📈 风扇曲线管理',
@@ -2005,7 +2005,7 @@ i18n.registerLanguage('zh-CN', {
bound: '已绑定',
selectVariableHint: '选择一个浮点类型变量作为温度源(如 agx.cpu_temp)',
bind: '💾 绑定',
- unbind: '🗑️ 解绑',
+ unbind: '解绑',
tempSpeedCurve: '📊 温度-转速曲线',
addPoint: '➕ 添加点',
curveHint: '温度低于最小点时使用最小转速,高于最大点时使用最大转速',
@@ -2019,7 +2019,7 @@ i18n.registerLanguage('zh-CN', {
minInterval: '最小间隔 (ms)',
intervalHint: '调速最小时间间隔',
cancel: '取消',
- applyCurve: '✅ 应用曲线',
+ applyCurve: '应用曲线',
// 曲线点
tempPlaceholder: '温度',
speedPlaceholder: '转速'
@@ -2076,7 +2076,7 @@ i18n.registerLanguage('zh-CN', {
presetLog: '日志流',
// 管理界面
management: '数据组件管理',
- panelSettings: '⚙️ 面板设置',
+ panelSettings: '面板设置',
autoRefreshInterval: '自动刷新间隔',
disabled: '禁用',
second: '秒',
@@ -2155,7 +2155,7 @@ i18n.registerLanguage('zh-CN', {
quickColors: '快捷颜色',
// 原有
on: '🔆 已开启',
- off: '💡 已关闭',
+ off: '已关闭',
defaultFont: '默认',
quickActionsLoadFailed: '无法加载快捷操作',
realTimeUpdating: '● 实时更新中',
@@ -2295,14 +2295,14 @@ i18n.registerLanguage('zh-CN', {
// PKI/安全配置
pkiPage: {
- signatureVerified: '✅ 签名验证通过',
- configImported: '✅ 配置包已导入',
+ signatureVerified: '签名验证通过',
+ configImported: '配置包已导入',
savedTo: '保存至',
- loadingFiles: '🔄 加载中...',
- noConfigFiles: '📁 没有配置文件 (.json)',
- loadError: '❌ 加载失败',
+ loadingFiles: '加载中...',
+ noConfigFiles: '没有配置文件 (.json)',
+ loadError: '加载失败',
noTscfgFiles: '目录中没有 .tscfg 文件',
- contentEmpty: '⚠️ 警告: 配置包内容为空',
+ contentEmpty: '警告: 配置包内容为空',
// PKI 状态
statusNotInit: '未初始化',
statusKeyGenerated: '密钥已生成,等待 CSR',
@@ -2312,26 +2312,26 @@ i18n.registerLanguage('zh-CN', {
statusError: '错误',
statusLoadFailed: '加载失败',
deviceType: '{type} 设备',
- certValid: '✅ 有效',
- certInvalid: '❌ 无效',
+ certValid: '有效',
+ certInvalid: '无效',
expiredDays: '已过期 {days} 天',
expiresInDays: '{days} 天后过期',
remainingDays: '剩余 {days} 天',
- generatingKeyPair: '🔄 正在生成密钥对...',
- generatingCsr: '🔄 正在生成 CSR...',
- installFailed: '❌ 安装失败',
+ generatingKeyPair: '正在生成密钥对...',
+ generatingCsr: '正在生成 CSR...',
+ installFailed: '安装失败',
// 配置包
enterConfigName: '请输入配置名称',
selectConfigFile: '请选择配置文件',
pasteTargetCert: '请粘贴目标设备证书',
invalidJsonConfig: '配置文件不是有效的 JSON',
- generatingPack: '🔄 生成配置包中',
- savedToDevice: '✅ 已保存到设备',
- generationFailed: '❌ 生成失败',
- verifying: '🔄 验证中...',
- verifyFailed: '❌ 验证失败',
- importing: '🔄 导入中...',
- importFailed: '❌ 导入失败',
+ generatingPack: '生成配置包中',
+ savedToDevice: '已保存到设备',
+ generationFailed: '生成失败',
+ verifying: '验证中...',
+ verifyFailed: '验证失败',
+ importing: '导入中...',
+ importFailed: '导入失败',
uploadOrPasteContent: '请上传文件或粘贴配置包内容'
},
@@ -2342,10 +2342,10 @@ i18n.registerLanguage('zh-CN', {
english: 'EN',
notLoggedIn: '未登录',
// 按钮状态
- stopTracking: '⏹️ 停止跟踪',
+ stopTracking: '停止跟踪',
startTracking: '▶️ 开始跟踪',
- testing: '⏳ 测试中...',
- connecting: '⏳ 连接中...',
+ testing: '测试中...',
+ connecting: '连接中...',
cancelling: '取消中...',
// 提示
noOutput: '(无输出)',
@@ -2358,9 +2358,9 @@ i18n.registerLanguage('zh-CN', {
colorSettings: '颜色设置',
turnOffLight: '关灯',
// OTA
- firmwareUpgradeComplete: '✅ 固件升级完成,准备升级 WebUI...',
- allUpgradeComplete: '✅ 全部升级完成',
- preparingUpgrade: '⏳ 准备升级...',
+ firmwareUpgradeComplete: '固件升级完成,准备升级 WebUI...',
+ allUpgradeComplete: '全部升级完成',
+ preparingUpgrade: '准备升级...',
initializing: '正在初始化...',
downloadingFromServer: '从 OTA 服务器下载',
connectingServer: '正在连接服务器...',
@@ -2368,11 +2368,11 @@ i18n.registerLanguage('zh-CN', {
writingFlash: '正在写入 Flash(这可能需要1-2分钟)...',
webuiSize: 'WebUI 大小',
writingSpiffs: '正在写入 SPIFFS...',
- upgradeFailed: '❌ 升级失败',
+ upgradeFailed: '升级失败',
downloading: '下载中...',
waitedSeconds: '已等待 {elapsed} 秒...',
step2Webui: '[2/2] 开始升级 WebUI...',
- firmwareOnlyComplete: '✅ 固件升级完成(WebUI 跳过)',
+ firmwareOnlyComplete: '固件升级完成(WebUI 跳过)',
updateTime: '更新时间',
// 系统
psramUnavailable: '不可用',
@@ -2385,10 +2385,10 @@ i18n.registerLanguage('zh-CN', {
displayStats: '显示 {filtered}/{total} 条',
// 弹窗标题
newCommand: '➕ 新建指令',
- editCommand: '✏️ 编辑指令',
+ editCommand: '编辑指令',
commandVariables: '📊 指令变量',
sourceVariables: '📊 {source} 变量',
- editActionTemplate: '✏️ 编辑动作模板',
+ editActionTemplate: '编辑动作模板',
// 动作
updateAction: '💾 更新',
// 验证错误
@@ -2404,7 +2404,7 @@ i18n.registerLanguage('zh-CN', {
configNotSet: '(未配置)',
// 模式匹配结果
expectPatternConfigured: '未配置',
- failPatternDetected: '⚠️ true (检测到错误)',
+ failPatternDetected: 'true (检测到错误)',
extractedNone: '无',
extracting: '提取中...',
// 状态映射
@@ -2412,10 +2412,10 @@ i18n.registerLanguage('zh-CN', {
statusFailed: '失败',
statusRunning: '运行中',
statusTimeout: '超时',
- expectMatchYes: '✅ 是',
- expectMatchNo: '❌ 否',
- failMatchYes: '⚠️ 是',
- failMatchNo: '✅ 否',
+ expectMatchYes: '是',
+ expectMatchNo: '否',
+ failMatchYes: '是',
+ failMatchNo: '否',
// innerHTML 相关翻译键
loadFailed: '加载失败',
noVariableData: '该指令暂无变量数据,请先执行一次',
@@ -2471,10 +2471,10 @@ i18n.registerLanguage('zh-CN', {
confirmRemoveHostLocal: '确定要从列表中移除主机 "{id}" 吗?\n\n注意:这只会移除本地记录,不会删除已部署到服务器上的公钥。如需撤销公钥,请点击「撤销」按钮。',
confirmRemoveHostLocal2: '确定要从列表中移除主机 "{id}" 吗?\n\n注意:这只会移除本地记录,不会删除已部署到服务器上的公钥。如需撤销公钥,请使用密钥管理中的「撤销」功能。',
confirmDeleteKey: '确定要删除密钥 "{id}" 吗?此操作不可撤销!',
- confirmExportPrivateKey: '⚠️ 安全警告\n\n您正在导出私钥 "{id}"。\n\n私钥是高度敏感的安全凭证,请确保:\n• 不要在公共网络传输\n• 不要分享给他人\n• 安全存储在本地\n\n确定要继续吗?',
+ confirmExportPrivateKey: '安全警告\n\n您正在导出私钥 "{id}"。\n\n私钥是高度敏感的安全凭证,请确保:\n• 不要在公共网络传输\n• 不要分享给他人\n• 安全存储在本地\n\n确定要继续吗?',
confirmRemoveKnownHost: '确定要移除主机 "{host}:{port}" 的记录吗?',
confirmClearKnownHosts: '确定要清除所有已知主机记录吗?此操作不可撤销!',
- confirmDeletePKI: '⚠️ 确定要删除所有 PKI 凭证吗?\n\n这将删除:\n• 私钥\n• 设备证书\n• CA 证书链\n\n此操作不可撤销!',
+ confirmDeletePKI: '确定要删除所有 PKI 凭证吗?\n\n这将删除:\n• 私钥\n• 设备证书\n• CA 证书链\n\n此操作不可撤销!',
// Alert 对话框和其他提示
alertHostFingerprint: '主机: {host}:{port}\n类型: {type}\n指纹 (SHA256):\n{fingerprint}',
alertEnterWsAddress: '请输入 WebSocket 地址',
diff --git a/tools/ota_server/README.md b/tools/ota_server/README.md
index 08689d7..5fefc79 100644
--- a/tools/ota_server/README.md
+++ b/tools/ota_server/README.md
@@ -46,6 +46,16 @@ http://<服务器IP>:57807
然后点击"检查更新"按钮。
+### 4. 发布前编译(让设备能检测到新固件)
+
+版本号仅在 **CMake 重新配置** 时更新。若只做增量编译(`idf.py build`),固件版本不变,设备上会显示「已是最新版本」。发布 OTA 前请用:
+
+```bash
+./tools/build.sh --fresh
+```
+
+或 `rm -f build/CMakeCache.txt && idf.py build`,再用 `--build-dir build` 启动 OTA 服务器。
+
## API 端点
| 端点 | 方法 | 说明 |