From 1c868c05fb4c4ffb5a6406853da18e87bf2c8019 Mon Sep 17 00:00:00 2001 From: Kuingsmile <96409857+Kuingsmile@users.noreply.github.com> Date: Thu, 3 Jul 2025 16:11:31 +0800 Subject: [PATCH] chore: add workflow to check unused i18n --- .github/workflows/i18n-check.yml | 213 +++++++++++++++++++++++ package.json | 2 + scripts/find-unused-i18n.js | 288 +++++++++++++++++++++++++++++++ src/i18n/locales/en.json | 155 +---------------- src/i18n/locales/zh.json | 157 +---------------- 5 files changed, 518 insertions(+), 297 deletions(-) create mode 100644 .github/workflows/i18n-check.yml create mode 100644 scripts/find-unused-i18n.js diff --git a/.github/workflows/i18n-check.yml b/.github/workflows/i18n-check.yml new file mode 100644 index 0000000..be9a332 --- /dev/null +++ b/.github/workflows/i18n-check.yml @@ -0,0 +1,213 @@ +name: 'I18n Check - Find Unused Translation Keys' + +on: + workflow_dispatch: + pull_request: + branches: [ main, dev ] + paths: + - 'src/**/*.vue' + - 'src/**/*.ts' + - 'src/**/*.js' + - 'src/i18n/**/*.json' + - 'scripts/find-unused-i18n.js' + - '.github/workflows/i18n-check.yml' + push: + branches: [ main, dev ] + paths: + - 'src/i18n/**/*.json' + +env: + NODE_OPTIONS: '--max-old-space-size=4096' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + i18n-check: + name: Check for Unused I18n Keys + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + cache: 'yarn' + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Run i18n unused keys check + id: i18n-check + run: | + echo "Running i18n unused keys analysis..." + + # Run the script and capture output + OUTPUT=$(node scripts/find-unused-i18n.js 2>&1) + EXIT_CODE=$? + + # Save the output to a file for the job summary + echo "$OUTPUT" > i18n-check-output.txt + + # Also output to console + echo "$OUTPUT" + + # Check if there are unused keys by looking for the specific pattern in output + if echo "$OUTPUT" | grep -q "🗑️ Unused I18n Keys:"; then + echo "unused_keys_found=true" >> $GITHUB_OUTPUT + echo "❌ Found unused i18n keys!" + exit 1 + else + echo "unused_keys_found=false" >> $GITHUB_OUTPUT + echo "✅ No unused i18n keys found!" + exit 0 + fi + + - name: Generate Job Summary + if: always() + run: | + echo "## 🌐 I18n Keys Analysis Report" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + if [ -f i18n-check-output.txt ]; then + echo "### 📊 Analysis Results" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + cat i18n-check-output.txt >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + fi + + if [ "${{ steps.i18n-check.outputs.unused_keys_found }}" = "true" ]; then + echo "### ❌ Action Required" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Unused i18n keys were found. Consider:" >> $GITHUB_STEP_SUMMARY + echo "- Removing unused keys from locale files" >> $GITHUB_STEP_SUMMARY + echo "- Verifying that the keys are actually unused" >> $GITHUB_STEP_SUMMARY + echo "- Adding usage for keys that should be kept" >> $GITHUB_STEP_SUMMARY + else + echo "### ✅ All Clear" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "No unused i18n keys found. Great job maintaining clean translations! 🎉" >> $GITHUB_STEP_SUMMARY + fi + + echo "" >> $GITHUB_STEP_SUMMARY + echo "### 💡 Tips" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- Run \`yarn i18n:check\` locally to check for unused keys" >> $GITHUB_STEP_SUMMARY + echo "- Run \`yarn i18n:check:verbose\` for detailed usage information" >> $GITHUB_STEP_SUMMARY + echo "- This check runs automatically on PRs that modify Vue, TS, JS, or i18n files" >> $GITHUB_STEP_SUMMARY + + - name: Upload analysis results + if: always() + uses: actions/upload-artifact@v4 + with: + name: i18n-analysis-results + path: i18n-check-output.txt + retention-days: 7 + + - name: Comment on PR (if unused keys found) + if: github.event_name == 'pull_request' && steps.i18n-check.outputs.unused_keys_found == 'true' + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + + let output = ''; + try { + output = fs.readFileSync('i18n-check-output.txt', 'utf8'); + } catch (error) { + output = 'Unable to read analysis output'; + } + + const body = `## 🌐 I18n Analysis Report + + ❌ **Unused i18n keys were found in this PR** + +
+ 📊 Click to view detailed analysis + + \`\`\` + ${output} + \`\`\` +
+ + ### 🔧 Action Required + + Please review the unused keys listed above and consider: + - **Removing** keys that are truly unused + - **Verifying** that the detection is correct (some dynamic key usage might not be detected) + - **Adding usage** for keys that should be kept + + ### 💡 Local Testing + + You can run this analysis locally using: + \`\`\`bash + yarn i18n:check # Basic check + yarn i18n:check:verbose # Detailed output with usage examples + \`\`\` + + --- + *This comment was automatically generated by the I18n Check workflow.*`; + + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: body + }); + + locale-consistency-check: + name: Check Locale File Consistency + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + + - name: Check locale files consistency + run: | + echo "Checking if all locale files have the same structure..." + + # Run the i18n script in verbose mode to also check for inconsistencies + node scripts/find-unused-i18n.js --verbose > locale-check.txt 2>&1 + + # Check if there are inconsistencies reported + if grep -q "⚠️ Locale Inconsistencies:" locale-check.txt; then + echo "❌ Found locale inconsistencies!" + cat locale-check.txt + exit 1 + else + echo "✅ All locale files are consistent!" + fi + + - name: Generate Consistency Report + if: always() + run: | + echo "## 🔄 Locale Consistency Check" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + if grep -q "⚠️ Locale Inconsistencies:" locale-check.txt 2>/dev/null; then + echo "### ❌ Inconsistencies Found" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Some keys exist in one locale but not others:" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + cat locale-check.txt >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + else + echo "### ✅ All Locale Files Consistent" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "All locale files have matching key structures. Perfect! 🎉" >> $GITHUB_STEP_SUMMARY + fi diff --git a/package.json b/package.json index 37e9933..423fb2b 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,8 @@ "nowatch": "tauri dev --no-watch", "lint": "eslint src/**/*.ts", "lint:fix": "eslint src/**/*.ts --fix", + "i18n:check": "node scripts/find-unused-i18n.js", + "i18n:check:verbose": "node scripts/find-unused-i18n.js --verbose", "cz": "git-cz", "release": "bump-version", "prebuild:dev": "node scripts/prepare.js", diff --git a/scripts/find-unused-i18n.js b/scripts/find-unused-i18n.js new file mode 100644 index 0000000..747b907 --- /dev/null +++ b/scripts/find-unused-i18n.js @@ -0,0 +1,288 @@ +#!/usr/bin/env node + +import { readdirSync, readFileSync } from 'node:fs' +import { basename, dirname, extname, join, relative } from 'node:path' +import { fileURLToPath } from 'node:url' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) + +const LOCALE_DIR = join(__dirname, '../src/i18n/locales') +const SRC_DIR = join(__dirname, '../src') + +console.log(`\n🔍 Analyzing i18n keys in ${LOCALE_DIR} and source files in ${SRC_DIR}\n`) + +const colors = { + reset: '\x1b[0m', + bright: '\x1b[1m', + red: '\x1b[31m', + green: '\x1b[32m', + yellow: '\x1b[33m', + blue: '\x1b[34m', + magenta: '\x1b[35m', + cyan: '\x1b[36m' +} + +function colorize(text, color) { + return `${colors[color]}${text}${colors.reset}` +} + +function flattenKeys(obj, prefix = '') { + const keys = [] + + for (const [key, value] of Object.entries(obj)) { + const fullKey = prefix ? `${prefix}.${key}` : key + + if (typeof value === 'object' && value !== null && !Array.isArray(value)) { + keys.push(...flattenKeys(value, fullKey)) + } else { + keys.push(fullKey) + } + } + + return keys +} + +function readLocaleFile(filePath) { + try { + const content = readFileSync(filePath, 'utf8') + return JSON.parse(content) + } catch (error) { + console.error(colorize(`Error reading ${filePath}: ${error.message}`, 'red')) + return {} + } +} + +function getAllI18nKeys() { + const localeFiles = readdirSync(LOCALE_DIR).filter(file => file.endsWith('.json')) + const allKeys = new Set() + const localeData = {} + + console.log(colorize('\n📁 Found locale files:', 'blue')) + + for (const file of localeFiles) { + const filePath = join(LOCALE_DIR, file) + const locale = basename(file, '.json') + const data = readLocaleFile(filePath) + const keys = flattenKeys(data) + + localeData[locale] = { + file: filePath, + keys, + data + } + + keys.forEach(key => allKeys.add(key)) + + console.log(` ${colorize('✓', 'green')} ${file} (${keys.length} keys)`) + } + + return { + allKeys: Array.from(allKeys).sort(), + localeData + } +} + +function findFiles(dir, extensions = ['.vue', '.ts', '.js']) { + const files = [] + + function walk(currentDir) { + const entries = readdirSync(currentDir, { withFileTypes: true }) + + for (const entry of entries) { + const fullPath = join(currentDir, entry.name) + + if (entry.isDirectory()) { + if (!['node_modules', '.git', 'dist', 'build', 'target'].includes(entry.name)) { + walk(fullPath) + } + } else if (entry.isFile()) { + const ext = extname(entry.name) + if (extensions.includes(ext)) { + files.push(fullPath) + } + } + } + } + + walk(dir) + return files +} + +function findKeyUsage(keys) { + const usage = {} + + keys.forEach(key => { + usage[key] = { + used: false, + files: [], + patterns: [] + } + }) + + console.log(colorize('\n🔍 Searching for key usage in source files...', 'blue')) + + const sourceFiles = findFiles(SRC_DIR) + + console.log(` Found ${sourceFiles.length} source files to analyze`) + + const searchPatterns = [ + /\$?t\s*\(\s*['"`]([^'"`]+)['"`]/g, + /(?:^|[^a-zA-Z])t\s*\(\s*['"`]([^'"`]+)['"`]/g, + /\{\{\s*\$?t\s*\(\s*['"`]([^'"`]+)['"`]/g + ] + + sourceFiles.forEach(filePath => { + try { + const content = readFileSync(filePath, 'utf8') + const relativePath = relative(join(__dirname, '..'), filePath) + + searchPatterns.forEach((pattern, patternIndex) => { + let match + while ((match = pattern.exec(content)) !== null) { + const key = match[1] + if (usage[key]) { + usage[key].used = true + if (!usage[key].files.includes(relativePath)) { + usage[key].files.push(relativePath) + } + if (!usage[key].patterns.includes(patternIndex)) { + usage[key].patterns.push(patternIndex) + } + } + } + }) + } catch (error) { + console.error(colorize(`Error reading ${filePath}: ${error.message}`, 'red')) + } + }) + + return usage +} + +function findLocaleInconsistencies(localeData) { + const locales = Object.keys(localeData) + const inconsistencies = {} + + if (locales.length < 2) { + return inconsistencies + } + + locales.forEach(locale => { + const currentKeys = new Set(localeData[locale].keys) + inconsistencies[locale] = { + missing: [], + extra: [] + } + + locales.forEach(otherLocale => { + if (locale !== otherLocale) { + localeData[otherLocale].keys.forEach(key => { + if (!currentKeys.has(key) && !inconsistencies[locale].missing.includes(key)) { + inconsistencies[locale].missing.push(key) + } + }) + } + }) + + localeData[locale].keys.forEach(key => { + const existsInOthers = locales.some( + otherLocale => locale !== otherLocale && localeData[otherLocale].keys.includes(key) + ) + if (!existsInOthers) { + inconsistencies[locale].extra.push(key) + } + }) + }) + + return inconsistencies +} + +function main() { + console.log(colorize('🌐 OpenList Desktop - I18n Usage Analyzer', 'cyan')) + console.log(colorize('==========================================', 'cyan')) + + const { allKeys, localeData } = getAllI18nKeys() + + console.log(colorize(`\n📊 Total unique keys found: ${allKeys.length}`, 'yellow')) + const usage = findKeyUsage(allKeys) + const usedKeys = allKeys.filter(key => usage[key].used) + const unusedKeys = allKeys.filter(key => !usage[key].used) + + const inconsistencies = findLocaleInconsistencies(localeData) + + console.log(colorize('\n📈 Usage Summary:', 'blue')) + console.log(` ${colorize('✓', 'green')} Used keys: ${usedKeys.length}`) + console.log(` ${colorize('✗', 'red')} Unused keys: ${unusedKeys.length}`) + console.log(` ${colorize('📊', 'yellow')} Usage rate: ${((usedKeys.length / allKeys.length) * 100).toFixed(1)}%`) + + if (unusedKeys.length > 0) { + console.log(colorize('\n🗑️ Unused I18n Keys:', 'red')) + console.log(colorize('====================', 'red')) + + const groupedUnused = {} + unusedKeys.forEach(key => { + const namespace = key.split('.')[0] + if (!groupedUnused[namespace]) { + groupedUnused[namespace] = [] + } + groupedUnused[namespace].push(key) + }) + + Object.entries(groupedUnused).forEach(([namespace, keys]) => { + console.log(colorize(`\n[${namespace}] - ${keys.length} unused keys:`, 'yellow')) + keys.forEach(key => { + console.log(` ${colorize('✗', 'red')} ${key}`) + }) + }) + } else { + console.log(colorize('\n🎉 No unused keys found! All i18n keys are being used.', 'green')) + } + + const hasInconsistencies = Object.values(inconsistencies).some(inc => inc.missing.length > 0 || inc.extra.length > 0) + + if (hasInconsistencies) { + console.log(colorize('\n⚠️ Locale Inconsistencies:', 'yellow')) + console.log(colorize('=========================', 'yellow')) + + Object.entries(inconsistencies).forEach(([locale, data]) => { + if (data.missing.length > 0 || data.extra.length > 0) { + console.log(colorize(`\n[${locale}.json]:`, 'cyan')) + + if (data.missing.length > 0) { + console.log(colorize(` Missing ${data.missing.length} keys:`, 'red')) + data.missing.forEach(key => { + console.log(` ${colorize('✗', 'red')} ${key}`) + }) + } + + if (data.extra.length > 0) { + console.log(colorize(` Extra ${data.extra.length} keys:`, 'blue')) + data.extra.forEach(key => { + console.log(` ${colorize('!', 'blue')} ${key}`) + }) + } + } + }) + } + + if (process.argv.includes('--verbose') || process.argv.includes('-v')) { + console.log(colorize('\n📋 Sample Used Keys (first 10):', 'blue')) + console.log(colorize('=================================', 'blue')) + + usedKeys.slice(0, 10).forEach(key => { + const files = usage[key].files.slice(0, 3) // Show first 3 files + const moreFiles = usage[key].files.length > 3 ? ` (+${usage[key].files.length - 3} more)` : '' + console.log(` ${colorize('✓', 'green')} ${key}`) + console.log(` Used in: ${files.join(', ')}${moreFiles}`) + }) + } + + console.log(colorize('\n✨ Analysis complete!', 'cyan')) + + if (unusedKeys.length > 0) { + console.log(colorize('\n💡 Tip: Run with --verbose (-v) flag to see usage details of used keys', 'blue')) + } +} + +main() diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index ef5ef5e..f1f16be 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -32,17 +32,13 @@ "stopRclone": "Stop RClone", "manageMounts": "Manage Mounts", "autoLaunch": "Auto Launch Core(not app)", - "autoMount": "Auto Mount", - "openSettings": "Open Settings", "processing": "Processing...", - "adminPassword": "Admin Password", "showAdminPassword": "Show/Copy admin password from logs" }, "coreMonitor": { "title": "Core Monitor", "online": "Online", "offline": "Offline", - "uptime": "Uptime", "responseTime": "Response Time", "healthy": "Healthy", "unhealthy": "Unhealthy" @@ -51,7 +47,6 @@ "title": "Version Manager", "openlist": "OpenList", "rclone": "Rclone", - "current": "Current", "selectVersion": "Select Version", "update": "Update" }, @@ -72,16 +67,10 @@ "serviceManagement": { "title": "Service Management", "serviceStatus": "OpenList Backend Service", - "uptime": "Uptime", - "port": "Port", - "version": "Version", "install": "Install", "start": "Start", "stop": "Stop", - "restart": "Restart", "uninstall": "Uninstall", - "recentLogs": "Recent Logs", - "noLogs": "No logs available", "status": { "running": "Running", "installed": "Installed", @@ -101,7 +90,6 @@ "subtitle": "Configure your OpenList Desktop application", "saveChanges": "Save Changes", "resetToDefaults": "Reset to defaults", - "unsavedChanges": "You have unsaved changes", "confirmReset": "Are you sure you want to reset all settings to defaults? This action cannot be undone.", "saved": "Settings saved successfully!", "saveFailed": "Failed to save settings. Please try again.", @@ -126,20 +114,13 @@ "title": "Network Configuration", "subtitle": "Configure the web interface and network settings" }, - "storage": { - "title": "Storage Configuration", - "subtitle": "Configure data directory and binary locations" - }, "startup": { "title": "Startup Options", "subtitle": "Configure automatic startup behavior" }, "service": { - "title": "Service Configuration", "subtitle": "Configure OpenList service settings", "network": { - "title": "Network Configuration", - "subtitle": "Configure the web interface and network settings", "port": { "label": "Listen Port", "placeholder": "5244", @@ -155,23 +136,7 @@ "description": "Use HTTPS for secure communication (requires SSL certificate configuration)" } }, - "storage": { - "title": "Storage Configuration", - "subtitle": "Configure data directory and binary locations", - "dataDir": { - "label": "Data Directory", - "placeholder": "./data", - "help": "Directory where OpenList stores its configuration and database" - }, - "binaryPath": { - "label": "OpenList Binary Path", - "placeholder": "./binary/openlist.exe", - "help": "Path to the OpenList executable file" - } - }, "startup": { - "title": "Startup Options", - "subtitle": "Configure automatic startup behavior", "autoLaunch": { "title": "Auto-launch on startup", "description": "Automatically start OpenList service when the application launches" @@ -179,48 +144,16 @@ } }, "rclone": { - "title": "Storage Configuration", "subtitle": "Configure remote storage connections", "config": { "title": "Remote Storage", "subtitle": "Configure rclone for remote storage access", "label": "Rclone Configuration (JSON)", "tips": "Enter your rclone configuration as JSON. This will be used to configure rclone remotes.", - "invalidJson": "Invalid JSON configuration. Please check your syntax.", - "binaryPath": { - "label": "Rclone Binary Path", - "placeholder": "./binary/rclone.exe", - "help": "Path to the rclone executable file" - }, - "configName": { - "label": "Configuration Name", - "placeholder": "remote", - "help": "Name of the rclone remote configuration" - } - }, - "mount": { - "title": "Mount Configuration", - "subtitle": "Configure local mount point for remote storage", - "mountPath": { - "label": "Mount Path", - "placeholder": "./mount", - "help": "Local directory where remote storage will be mounted" - }, - "autoMount": { - "title": "Auto-mount on startup", - "description": "Automatically mount remote storage when the service starts" - } - }, - "flags": { - "title": "Rclone Flags", - "subtitle": "Additional command-line flags for rclone", - "placeholder": "--flag-name=value", - "add": "Add Flag", - "remove": "Remove" + "invalidJson": "Invalid JSON configuration. Please check your syntax." } }, "app": { - "title": "Application Settings", "subtitle": "Configure application preferences and behavior", "theme": { "title": "Theme", @@ -228,8 +161,6 @@ "light": "Light", "dark": "Dark", "auto": "Auto", - "lightDesc": "Light theme", - "darkDesc": "Dark theme", "autoDesc": "Follow system" }, "monitor": { @@ -259,45 +190,10 @@ "title": "Auto-launch on startup(Immediate Effect)", "subtitle": "Automatically start OpenList Desktop application when the system starts", "description": "Automatically start OpenList service when the application launches" - }, - "service": { - "title": "Service Connection", - "subtitle": "Configure connection to the desktop service", - "port": { - "label": "Service Port", - "placeholder": "53211", - "help": "Port number for the desktop service communication" - }, - "apiToken": { - "label": "Service API Token", - "placeholder": "API token for service authentication", - "help": "Token used to authenticate with the desktop service" - } } - }, - "advanced": { - "title": "Advanced Settings", - "performance": { - "title": "Performance", - "subtitle": "Performance and optimization settings", - "coming": "Performance settings will be available in a future update" - }, - "logging": { - "title": "Logging", - "subtitle": "Configure application logging behavior", - "coming": "Logging configuration will be available in a future update" - } - }, - "dialogs": { - "selectOpenListBinary": "Select OpenList Binary", - "selectRcloneBinary": "Select Rclone Binary", - "selectDataDirectory": "Select Data Directory", - "selectMountDirectory": "Select Mount Directory" } }, "logs": { - "title": "Logs", - "clear": "Clear Logs", "search": { "placeholder": "Search logs... (Ctrl+F)" }, @@ -326,14 +222,10 @@ "selected": "{count} selected" }, "filters": { - "all": "All", - "openlist": "OpenList", - "rclone": "Rclone", "app": "App", "labels": { "level": "Level:", - "source": "Source:", - "search": "Search" + "source": "Source:" }, "levels": { "all": "All Levels", @@ -344,57 +236,36 @@ }, "sources": { "all": "All Sources", - "service": "Service", "rclone": "Rclone", - "system": "System", "openlist": "OpenList" }, "actions": { "selectAll": "Select All (Ctrl+A)", "clearSelection": "Clear Selection (Esc)", "autoScroll": "Auto-scroll" - }, - "searchPlaceholder": "Search logs...", - "clear": "Clear search" + } }, - "levels": { - "debug": "Debug", - "info": "Info", - "warn": "Warning", - "error": "Error" - }, - "empty": "No log entries", "viewer": { "noLogsFound": "No logs to display", "noLogsMatch": "No logs match your search criteria", - "tryAdjusting": "Try adjusting your search or filters", - "logsWillAppear": "Logs will appear here when services are running", - "scrollToBottom": "Scroll to bottom" + "logsWillAppear": "Logs will appear here when services are running" }, "settings": { "fontSize": "Font Size:", "maxLines": "Max Lines:", - "showTimestamp": "Show Timestamp", - "showSource": "Show Source", "compactMode": "Compact Mode", "stripAnsiColors": "Strip ANSI Colors" }, "messages": { - "confirmClear": "Are you sure you want to clear all logs?", - "exported": "Logs exported successfully", - "copied": "Logs copied to clipboard" + "confirmClear": "Are you sure you want to clear all logs?" }, "headers": { - "time": "Time", "timestamp": "Timestamp", "level": "Level", "source": "Source", "message": "Message" }, "status": { - "service": "Service:", - "running": "Running", - "stopped": "Stopped", "autoScroll": "Auto-scroll:", "updates": "Updates:", "paused": "Paused", @@ -425,7 +296,6 @@ "openInExplorer": "Open in Explorer" }, "status": { - "status": "Status", "mounted": "Mounted", "unmounted": "Unmounted", "error": "Error" @@ -462,11 +332,7 @@ "addFlag": "Add Flag", "removeFlag": "Remove Flag", "types": { - "webdav": "WebDAV", - "s3": "Amazon S3", - "gdrive": "Google Drive", - "onedrive": "OneDrive", - "dropbox": "Dropbox" + "webdav": "WebDAV" } }, "meta": { @@ -486,7 +352,6 @@ "failedToMount": "Failed to mount remote", "failedToUnmount": "Failed to unmount remote", "failedToDelete": "Failed to delete configuration", - "failedToRefresh": "Failed to refresh mount status", "failedToStartService": "Failed to start rclone service", "failedToStopService": "Failed to stop rclone service" }, @@ -500,11 +365,6 @@ "title": "OpenList", "loading": "Initializing OpenList Desktop..." }, - "language": { - "current": "Current Language", - "chinese": "中文", - "english": "English" - }, "tutorial": { "welcome": { "title": "Welcome to OpenList Desktop", @@ -533,8 +393,7 @@ "skip": "Skip Tutorial", "next": "Next", "previous": "Previous", - "complete": "Complete Tutorial", - "neverShow": "Don't show again" + "complete": "Complete Tutorial" }, "update": { "title": "App Updates", diff --git a/src/i18n/locales/zh.json b/src/i18n/locales/zh.json index cb307b6..83bff59 100644 --- a/src/i18n/locales/zh.json +++ b/src/i18n/locales/zh.json @@ -32,17 +32,13 @@ "stopRclone": "停止 RClone", "manageMounts": "管理挂载", "autoLaunch": "自动启动核心(非桌面app)", - "autoMount": "自动挂载", - "openSettings": "打开设置", "processing": "处理中...", - "adminPassword": "管理员密码", "showAdminPassword": "显示/复制日志中的管理员密码" }, "coreMonitor": { "title": "核心监控", "online": "在线", "offline": "离线", - "uptime": "运行时间", "responseTime": "响应时间", "healthy": "健康", "unhealthy": "不健康" @@ -51,7 +47,6 @@ "title": "版本管理", "openlist": "OpenList", "rclone": "Rclone", - "current": "当前", "selectVersion": "选择版本", "update": "更新" }, @@ -72,16 +67,10 @@ "serviceManagement": { "title": "服务管理", "serviceStatus": "OpenList 后端服务", - "uptime": "运行时间", - "port": "端口", - "version": "版本", "install": "安装", "start": "启动", "stop": "停止", - "restart": "重启", "uninstall": "卸载", - "recentLogs": "最近日志", - "noLogs": "无可用日志", "status": { "running": "运行中", "installed": "已安装", @@ -101,7 +90,6 @@ "subtitle": "配置您的 OpenList 桌面应用程序", "saveChanges": "保存更改", "resetToDefaults": "重置为默认值", - "unsavedChanges": "您有未保存的更改", "confirmReset": "您确定要将所有设置重置为默认值吗?此操作无法撤消。", "saved": "设置保存成功!", "saveFailed": "保存设置失败,请重试。", @@ -126,20 +114,13 @@ "title": "网络配置", "subtitle": "配置 Web 界面和网络设置" }, - "storage": { - "title": "存储配置", - "subtitle": "配置数据目录和二进制文件位置" - }, "startup": { "title": "启动选项", "subtitle": "配置自动启动行为" }, "service": { - "title": "服务配置", "subtitle": "配置 OpenList 服务设置", "network": { - "title": "网络配置", - "subtitle": "配置 Web 界面和网络设置", "port": { "label": "监听端口", "placeholder": "5244", @@ -155,23 +136,7 @@ "description": "使用 HTTPS 进行安全通信(需要配置 SSL 证书)" } }, - "storage": { - "title": "存储配置", - "subtitle": "配置数据目录和二进制文件位置", - "dataDir": { - "label": "数据目录", - "placeholder": "./data", - "help": "OpenList 存储配置和数据库的目录" - }, - "binaryPath": { - "label": "OpenList 二进制路径", - "placeholder": "./binary/openlist.exe", - "help": "OpenList 可执行文件的路径" - } - }, "startup": { - "title": "启动选项", - "subtitle": "配置自动启动行为", "autoLaunch": { "title": "开机自启", "description": "应用程序启动时自动启动 OpenList 服务" @@ -179,48 +144,16 @@ } }, "rclone": { - "title": "存储配置", "subtitle": "配置远程存储连接", "config": { "title": "远程存储", "subtitle": "配置 rclone 远程存储访问", - "label": "Rclone 配置(JSON)", + "label": "Rclone 配置 (JSON)", "invalidJson": "无效的 JSON 配置。请检查您的语法。", - "tips": "输入你的JSON配置", - "binaryPath": { - "label": "Rclone 二进制路径", - "placeholder": "./binary/rclone.exe", - "help": "rclone 可执行文件的路径" - }, - "configName": { - "label": "配置名称", - "placeholder": "remote", - "help": "rclone 远程配置的名称" - } - }, - "mount": { - "title": "挂载配置", - "subtitle": "配置远程存储的本地挂载点", - "mountPath": { - "label": "挂载路径", - "placeholder": "./mount", - "help": "远程存储将挂载到的本地目录" - }, - "autoMount": { - "title": "启动时自动挂载", - "description": "服务启动时自动挂载远程存储" - } - }, - "flags": { - "title": "Rclone 标志", - "subtitle": "rclone 的额外命令行标志", - "placeholder": "--flag-name=value", - "add": "添加标志", - "remove": "移除" + "tips": "输入你的JSON配置" } }, "app": { - "title": "应用设置", "subtitle": "配置应用程序首选项和行为", "theme": { "title": "主题", @@ -228,8 +161,6 @@ "light": "浅色", "dark": "深色", "auto": "自动", - "lightDesc": "浅色主题", - "darkDesc": "深色主题", "autoDesc": "跟随系统" }, "monitor": { @@ -259,45 +190,10 @@ "title": "开机自动启动应用(立即生效)", "subtitle": "在系统启动时自动启动 OpenList 桌面应用", "description": "在系统启动时自动启动 OpenList 桌面应用" - }, - "service": { - "title": "服务连接", - "subtitle": "配置与桌面服务的连接", - "port": { - "label": "服务端口", - "placeholder": "53211", - "help": "桌面服务通信的端口号" - }, - "apiToken": { - "label": "服务 API 令牌", - "placeholder": "API 令牌,用于服务身份验证", - "help": "用于身份验证的令牌" - } } - }, - "advanced": { - "title": "高级设置", - "performance": { - "title": "性能", - "subtitle": "性能和优化设置", - "coming": "性能设置将在未来版本中提供" - }, - "logging": { - "title": "日志", - "subtitle": "配置应用程序日志行为", - "coming": "日志配置将在未来版本中提供" - } - }, - "dialogs": { - "selectOpenListBinary": "选择 OpenList 二进制文件", - "selectRcloneBinary": "选择 Rclone 二进制文件", - "selectDataDirectory": "选择数据目录", - "selectMountDirectory": "选择挂载目录" } }, "logs": { - "title": "日志", - "clear": "清除日志", "search": { "placeholder": "搜索日志... (Ctrl+F)" }, @@ -326,14 +222,10 @@ "selected": "已选择 {count} 个" }, "filters": { - "all": "全部", - "openlist": "OpenList", - "rclone": "Rclone", "app": "应用程序", "labels": { "level": "级别:", - "source": "来源:", - "search": "搜索" + "source": "来源:" }, "levels": { "all": "所有级别", @@ -344,57 +236,36 @@ }, "sources": { "all": "所有来源", - "service": "服务", "rclone": "Rclone", - "system": "系统", "openlist": "OpenList" }, "actions": { "selectAll": "全选 (Ctrl+A)", "clearSelection": "清除选择 (Esc)", "autoScroll": "自动滚动" - }, - "searchPlaceholder": "搜索日志...", - "clear": "清除搜索" + } }, - "levels": { - "debug": "调试", - "info": "信息", - "warn": "警告", - "error": "错误" - }, - "empty": "没有日志条目", "viewer": { "noLogsFound": "没有日志显示", "noLogsMatch": "没有日志匹配您的搜索条件", - "tryAdjusting": "尝试调整您的搜索或过滤器", - "logsWillAppear": "服务运行时日志将在此处显示", - "scrollToBottom": "滚动到底部" + "logsWillAppear": "服务运行时日志将在此处显示" }, "settings": { "fontSize": "字体大小:", "maxLines": "最大行数:", - "showTimestamp": "显示时间戳", - "showSource": "显示来源", "compactMode": "紧凑模式", "stripAnsiColors": "去除 ANSI 颜色" }, "messages": { - "confirmClear": "您确定要清除所有日志吗?", - "exported": "日志导出成功", - "copied": "日志已复制到剪贴板" + "confirmClear": "您确定要清除所有日志吗?" }, "headers": { - "time": "时间", "timestamp": "时间", "level": "级别", "source": "来源", "message": "消息" }, "status": { - "service": "服务:", - "running": "运行中", - "stopped": "已停止", "autoScroll": "自动滚动:", "updates": "更新:", "paused": "已暂停", @@ -425,7 +296,6 @@ "openInExplorer": "在文件管理器中打开" }, "status": { - "status": "状态", "mounted": "已挂载", "unmounted": "未挂载", "error": "错误" @@ -462,11 +332,7 @@ "addFlag": "添加标志", "removeFlag": "移除标志", "types": { - "webdav": "WebDAV", - "s3": "Amazon S3", - "gdrive": "Google Drive", - "onedrive": "OneDrive", - "dropbox": "Dropbox" + "webdav": "WebDAV" } }, "meta": { @@ -486,7 +352,6 @@ "failedToMount": "挂载远程失败", "failedToUnmount": "卸载远程失败", "failedToDelete": "删除配置失败", - "failedToRefresh": "刷新挂载状态失败", "failedToStartService": "启动 rclone 服务失败", "failedToStopService": "停止 rclone 服务失败" }, @@ -500,11 +365,6 @@ "title": "OpenList", "loading": "正在初始化" }, - "language": { - "current": "当前语言", - "chinese": "中文", - "english": "English" - }, "tutorial": { "welcome": { "title": "欢迎使用 OpenList 桌面版", @@ -533,8 +393,7 @@ "skip": "跳过教程", "next": "下一步", "previous": "上一步", - "complete": "完成教程", - "neverShow": "不再显示" + "complete": "完成教程" }, "update": { "title": "应用更新",