From 89e25e3504b2e76ff24803ea96914893a595bd1a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9C=88=E6=9C=88?= <3600911665@qq.com>
Date: Tue, 17 Jun 2025 14:29:33 +0800
Subject: [PATCH] Add translation management tool suite and update Chinese
translations
- Introduced a comprehensive guide for the translation management tool suite, detailing components, usage, and best practices.
- Added `translation-manager.py`, `translation-cleaner.py`, and `manage-translations.sh` scripts for managing translations.
- Updated the Chinese translation file (`zh_CN.json`) to improve existing translations and remove unused keys.
- Enhanced documentation with examples and troubleshooting tips for better user experience.
---
.config/quickshell/translations/en_US.json | 332 +--------------
.../quickshell/translations/tools/README.md | 111 +++++
.../translations/tools/manage-translations.sh | 149 +++++++
.../translations/tools/translation-cleaner.py | 196 +++++++++
.../translations/tools/translation-manager.py | 290 +++++++++++++
.../tools/translation-tools-guide.md | 246 +++++++++++
.../translations/tools/翻译管理脚本说明.md | 287 +++++++++++++
.config/quickshell/translations/zh_CN.json | 398 +++---------------
8 files changed, 1348 insertions(+), 661 deletions(-)
create mode 100644 .config/quickshell/translations/tools/README.md
create mode 100755 .config/quickshell/translations/tools/manage-translations.sh
create mode 100755 .config/quickshell/translations/tools/translation-cleaner.py
create mode 100755 .config/quickshell/translations/tools/translation-manager.py
create mode 100644 .config/quickshell/translations/tools/translation-tools-guide.md
create mode 100644 .config/quickshell/translations/tools/翻译管理脚本说明.md
diff --git a/.config/quickshell/translations/en_US.json b/.config/quickshell/translations/en_US.json
index 6f7c8ec50..34887b99b 100644
--- a/.config/quickshell/translations/en_US.json
+++ b/.config/quickshell/translations/en_US.json
@@ -35,7 +35,6 @@
"Closes right sidebar on press": "Closes right sidebar on press",
"Copy": "Copy",
"Copy code": "Copy code",
- "Ctrl+O to expand the sidebar\nCtrl+P to detach sidebar into a window": "Ctrl+O to expand the sidebar\nCtrl+P to detach sidebar into a window",
"Current API endpoint: {0}\nSet it with {1}mode PROVIDER": "Current API endpoint: {0}\nSet it with {1}mode PROVIDER",
"Current model: {0}\nSet it with {1}model MODEL": "Current model: {0}\nSet it with {1}model MODEL",
"Decrease brightness": "Decrease brightness",
@@ -48,7 +47,6 @@
"Download complete": "Download complete",
"Edit": "Edit",
"Enter text to translate...": "Enter text to translate...",
- "Experimental | Online | Google's model\nCan do a little more but doesn't search quickly": "Experimental | Online | Google's model\nCan do a little more but doesn't search quickly",
"Finished tasks will go here": "Finished tasks will go here",
"For desktop wallpapers | Good quality": "For desktop wallpapers | Good quality",
"For storing API keys and other sensitive information": "For storing API keys and other sensitive information",
@@ -63,10 +61,7 @@
"Input": "Input",
"Intelligence": "Intelligence",
"Interface": "Interface",
- "Interrupts possibility of overview being toggled on release. ": "Interrupts possibility of overview being toggled on release. ",
- "Invalid API provider. Supported: \n- ": "Invalid API provider. Supported: \n- ",
"Invalid arguments. Must provide `key` and `value`.": "Invalid arguments. Must provide `key` and `value`.",
- "Invalid model. Supported: \n```\n": "Invalid model. Supported: \n```\n",
"Jump to current month": "Jump to current month",
"Keep system awake": "Keep system awake",
"Large images | God tier quality, no NSFW.": "Large images | God tier quality, no NSFW.",
@@ -86,8 +81,6 @@
"Nothing here!": "Nothing here!",
"Notifications": "Notifications",
"OK": "OK",
- "Online via {0} | {1}'s model": "Online via {0} | {1}'s model",
- "Online | Google's model\nGives up-to-date information with search.": "Online | Google's model\nGives up-to-date information with search.",
"Open file link": "Open file link",
"Opens cheatsheet on press": "Opens cheatsheet on press",
"Opens left sidebar on press": "Opens left sidebar on press",
@@ -98,7 +91,6 @@
"Output": "Output",
"Page {0}": "Page {0}",
"Plasma Settings": "Plasma Settings",
- "Provider set to ": "Provider set to ",
"Reboot": "Reboot",
"Reboot to firmware settings": "Reboot to firmware settings",
"Reload Hyprland & Quickshell": "Reload Hyprland & Quickshell",
@@ -122,19 +114,15 @@
"Shutdown": "Shutdown",
"Silent": "Silent",
"Sleep": "Sleep",
- "Switched to search mode. Continue with the user's request.": "Switched to search mode. Continue with the user's request.",
"System": "System",
"Task Manager": "Task Manager",
"Task description": "Task description",
"Temperature must be between 0 and 2": "Temperature must be between 0 and 2",
"Temperature set to {0}": "Temperature set to {0}",
"Temperature: {0}": "Temperature: {0}",
- "That didn't work. Tips:\n- Check your tags and NSFW settings\n- If you don't have a tag in mind, type a page number": "That didn't work. Tips:\n- Check your tags and NSFW settings\n- If you don't have a tag in mind, type a page number",
- "The current API used. Endpoint: ": "The current API used. Endpoint: ",
"The hentai one | Great quantity, a lot of NSFW, quality varies wildly": "The hentai one | Great quantity, a lot of NSFW, quality varies wildly",
"The popular one | Best quantity, but quality can vary wildly": "The popular one | Best quantity, but quality can vary wildly",
"Thinking": "Thinking",
- "This is necessary because GlobalShortcut.onReleased in quickshell triggers whether or not you press something else while holding the key. ": "This is necessary because GlobalShortcut.onReleased in quickshell triggers whether or not you press something else while holding the key. ",
"To make sure this works consistently, use binditn = MODKEYS, catchall in an automatically triggered submap that includes everything.": "To make sure this works consistently, use binditn = MODKEYS, catchall in an automatically triggered submap that includes everything.",
"Toggle clipboard query on overview widget": "Toggle clipboard query on overview widget",
"Toggle emoji query on overview widget": "Toggle emoji query on overview widget",
@@ -155,318 +143,34 @@
"Unknown Album": "Unknown Album",
"Unknown Artist": "Unknown Artist",
"Unknown Title": "Unknown Title",
- "Unknown command: ": "Unknown command: ",
"Unknown function call: {0}": "Unknown function call: {0}",
"Uptime: {0}": "Uptime: {0}",
- "Use casual tone. No user knowledge is to be assumed except basic Linux literacy. Be brief and concise: When explaining concepts, use bullet points (prefer minus sign (-) over asterisk (*)) and highlight keywords in **bold** to pinpoint the main concepts instead of long paragraphs. You are also encouraged to split your response with h2 headers, each header title beginning with an emoji, like `## 🐧 Linux`. When making changes to the user's config, you must get the config to know what values there are before setting.": "Use casual tone. No user knowledge is to be assumed except basic Linux literacy. Be brief and concise: When explaining concepts, use bullet points (prefer minus sign (-) over asterisk (*)) and highlight keywords in **bold** to pinpoint the main concepts instead of long paragraphs. You are also encouraged to split your response with h2 headers, each header title beginning with an emoji, like `## 🐧 Linux`. When making changes to the user's config, you must get the config to know what values there are before setting.",
"View Markdown source": "View Markdown source",
"Volume": "Volume",
"Volume mixer": "Volume mixer",
"Waifus only | Excellent quality, limited quantity": "Waifus only | Excellent quality, limited quantity",
"Waiting for response...": "Waiting for response...",
"Workspace": "Workspace",
- "\nSet with /mode PROVIDER": "\nSet with /mode PROVIDER",
- "about": "About",
- "accessed": "Accessed",
- "account": "Account",
- "active": "Active",
- "active_state": "Active",
- "addon": "Add-on",
- "addons": "Add-ons",
- "address": "Address",
- "admin": "Administrator",
- "align": "Align",
- "always_on_top": "Always on Top",
- "animate": "Animate",
- "app": "App",
- "appearance": "Appearance",
- "application": "Application",
- "applications": "Applications",
- "apply": "Apply",
- "apps": "Apps",
- "auto": "Auto",
- "background": "Background",
- "balanced": "Balanced",
- "bar": "Bar",
- "bars": "Bars",
- "battery": "Battery",
- "bluetooth": "Bluetooth",
- "blur": "Blur",
- "border": "Border",
- "bottom": "Bottom",
- "brightness": "Brightness",
- "bring_to_front": "Bring to Front",
- "bytes": "{0} bytes",
- "cancel": "Cancel",
- "center": "Center",
- "characters": "{0} characters",
- "charging": "Charging",
- "clear_all": "Clear All",
- "clicked": "Clicked",
- "close": "Close",
- "collapse": "Collapse",
- "color": "Color",
- "command": "Command",
- "connected": "Connected",
- "connecting": "Connecting...",
- "context_menu": "Context Menu",
- "copy": "Copy",
- "cpu": "CPU",
- "created": "Created",
- "critical": "Critical",
- "customize": "Customize",
- "cut": "Cut",
- "dark": "Dark",
- "dashboard": "Dashboard",
- "date": "Date",
- "debug": "Debug",
- "default": "Default",
- "degrees": "{0}°",
- "delete": "Delete",
- "demo": "Demo",
- "desktop": "Desktop",
- "dialog": "Dialog",
- "disabled": "Disabled",
- "discharging": "Discharging",
- "disconnected": "Disconnected",
- "disk": "Disk",
- "display": "Display",
- "distribute": "Distribute",
- "dock": "Dock",
- "documents": "Documents",
- "double_clicked": "Double Clicked",
- "downloads": "Downloads",
- "dragged": "Dragged",
- "dropdown": "Dropdown",
- "dropped": "Dropped",
- "effect": "Effect",
- "email": "Email",
- "enabled": "Enabled",
- "error": "Error",
- "ethernet": "Ethernet",
- "example": "Example",
- "execute": "Execute",
- "exit": "Exit",
- "expand": "Expand",
- "extension": "Extension",
- "extensions": "Extensions",
- "fan": "Fan",
- "favorites": "Favorites",
- "file": "File",
- "files": "Files",
- "filter": "Filter",
- "flip": "Flip",
- "floating": "Floating",
- "focus": "Focus",
- "folder": "Folder",
- "folders": "Folders",
- "foreground": "Foreground",
- "format": "Format",
- "full": "Full",
- "fullscreen": "Fullscreen",
- "gigabytes": "{0} GB",
- "gigahertz": "{0} GHz",
- "glow": "Glow",
- "group": "Group",
- "guest": "Guest",
- "headphones": "Headphones",
- "help": "Help",
- "hertz": "{0} Hz",
- "hibernate": "Hibernate",
- "hidden": "Hidden",
- "hide": "Hide",
- "highlight": "Highlight",
- "hint": "Hint",
- "home": "Home",
- "hour": "Hour",
- "hours": "Hours",
- "hover": "Hover",
- "inactive": "Inactive",
- "info": "Info",
- "input": "Input",
- "install": "Install",
- "justify": "Justify",
- "keybinds": "Key Bindings",
- "keyboard": "Keyboard",
- "kilobytes": "{0} KB",
- "kilohertz": "{0} kHz",
- "landscape": "Landscape",
- "language": "Language",
- "launcher": "Launcher",
- "left": "Left",
- "light": "Light",
- "loading": "Loading...",
- "lock": "Lock",
- "log": "Log",
- "logout": "Logout",
- "long_pressed": "Long Pressed",
- "low": "Low",
- "manual": "Manual",
- "margin": "Margin",
- "maximize": "Maximize",
- "megabytes": "{0} MB",
- "megahertz": "{0} MHz",
- "memory": "Memory",
- "menu": "Menu",
- "menubar": "Menu Bar",
- "microphone": "Microphone",
- "minimize": "Minimize",
- "minute": "Minute",
- "minutes": "Minutes",
- "mirror": "Mirror",
- "modal": "Modal",
- "modified": "Modified",
- "monitor": "Monitor",
- "mouse": "Mouse",
- "move": "Move",
- "music": "Music",
- "mute": "Mute",
- "network": "Network",
- "next": "Next",
- "no": "No",
- "no_notifications": "No notifications",
- "notifications": "Notifications",
- "off": "Off",
- "ok": "OK",
- "on": "On",
- "opacity": "Opacity",
- "open": "Open",
- "orientation": "Orientation",
- "outline": "Outline",
- "output": "Output",
- "overview": "Overview",
- "owner": "Owner",
- "package": "Package",
- "packages": "Packages",
- "padding": "Padding",
- "panel": "Panel",
- "panels": "Panels",
- "panned": "Panned",
- "password": "Password",
- "paste": "Paste",
- "pause": "Pause",
- "percent": "{0}%",
- "performance": "Performance",
- "permissions": "Permissions",
- "phone": "Phone",
- "pictures": "Pictures",
- "pinched": "Pinched",
- "pinned": "Pinned",
- "pixels": "{0}px",
- "placeholder": "Placeholder",
- "play": "Play",
- "plugin": "Plugin",
- "plugins": "Plugins",
- "popup": "Popup",
- "portrait": "Portrait",
- "power": "Power",
- "power_saver": "Power Saver",
- "pressed": "Pressed",
- "previous": "Previous",
- "profile": "Profile",
- "properties": "Properties",
- "quiet": "Quiet",
- "quit": "Quit",
- "read": "Read",
- "recent": "Recent",
- "recording": "Recording",
- "refresh": "Refresh",
- "refresh_rate": "Refresh Rate",
- "reload": "Reload",
- "rename": "Rename",
- "reset": "Reset",
- "resize": "Resize",
- "resolution": "Resolution",
- "restart": "Restart",
- "restore": "Restore",
- "right": "Right",
- "right_clicked": "Right Clicked",
- "rotate": "Rotate",
- "rotated": "Rotated",
- "sample": "Sample",
- "save": "Save",
- "scale": "Scale",
- "screenshot": "Screenshot",
- "scrolled": "Scrolled",
- "search": "Search",
- "second": "Second",
- "seconds": "Seconds",
- "selection": "Selection",
- "send_to_back": "Send to Back",
- "settings": "Settings",
- "shadow": "Shadow",
- "shortcuts": "Shortcuts",
- "show": "Show",
- "shutdown": "Shutdown",
- "sidebar": "Sidebar",
- "silent": "Silent",
- "size": "Size",
- "snapped": "Snapped",
- "software": "Software",
- "space": "Space",
- "speaker": "Speaker",
- "statusbar": "Status Bar",
- "sticky": "Sticky",
- "stop": "Stop",
- "style": "Style",
- "success": "Success",
- "suspend": "Suspend",
- "swiped": "Swiped",
- "systray": "System Tray",
- "tapped": "Tapped",
- "taskbar": "Taskbar",
- "temperature": "Temperature",
- "terabytes": "{0} TB",
- "terminal": "Terminal",
- "test": "Test",
- "theme": "Theme",
- "tiled": "Tiled",
- "time": "Time",
- "tips": "Tips",
- "today": "Today",
- "tomorrow": "Tomorrow",
- "toolbar": "Toolbar",
- "tooltip": "Tooltip",
- "top": "Top",
- "touchpad": "Touchpad",
- "trace": "Trace",
- "transform": "Transform",
- "transition": "Transition",
- "transparency": "Transparency",
- "trash": "Trash",
- "tutorial": "Tutorial",
- "type": "Type",
- "uninstall": "Uninstall",
- "unlock": "Unlock",
- "unmute": "Unmute",
- "unpinned": "Unpinned",
- "unsticky": "Unsticky",
- "update": "Update",
- "upgrade": "Upgrade",
- "user": "User",
- "username": "Username",
- "verbose": "Verbose",
- "version": "Version",
- "videos": "Videos",
- "visible": "Visible",
- "volume": "Volume",
- "warning": "Warning",
- "welcome": "Welcome",
- "widget": "Widget",
- "widgets": "Widgets",
- "wifi": "Wi-Fi",
- "window": "Window",
- "windowed": "Windowed",
- "windows": "Windows",
- "workspace": "Workspace",
- "workspaces": "Workspaces",
- "write": "Write",
- "yes": "Yes",
- "yesterday": "Yesterday",
- "zoomed": "Zoomed",
"{0} (copied)": "{0} (copied)",
"{0} Safe Storage": "{0} Safe Storage",
"{0} does not require an API key": "{0} does not require an API key",
"{0} queries pending": "{0} queries pending",
- "{0} | Right-click to configure": "{0} | Right-click to configure"
+ "{0} | Right-click to configure": "{0} | Right-click to configure",
+ "Set with /mode PROVIDER": "Set with /mode PROVIDER",
+ "Invalid API provider. Supported: \n-": "Invalid API provider. Supported: \n-",
+ "Unknown command:": "Unknown command:",
+ "Type /key to get started with online models\nCtrl+O to expand the sidebar\nCtrl+P to detach sidebar into a window": "Type /key to get started with online models\nCtrl+O to expand the sidebar\nCtrl+P to detach sidebar into a window",
+ "This is necessary because GlobalShortcut.onReleased in quickshell triggers whether or not you press something else while holding the key.": "This is necessary because GlobalShortcut.onReleased in quickshell triggers whether or not you press something else while holding the key.",
+ "The current API used. Endpoint:": "The current API used. Endpoint:",
+ "Provider set to": "Provider set to",
+ "Invalid model. Supported: \n```": "Invalid model. Supported: \n```",
+ "Interrupts possibility of overview being toggled on release.": "Interrupts possibility of overview being toggled on release.",
+ "Enter tags, or \"{0}\" for commands": "Enter tags, or \"{0}\" for commands",
+ "That didn't work. Tips:\n- Check your tags and NSFW settings\n- If you don't have a tag in mind, type a page number": "That didn't work. Tips:\n- Check your tags and NSFW settings\n- If you don't have a tag in mind, type a page number",
+ "Online | Google's model\nGives up-to-date information with search.": "Online | Google's model\nGives up-to-date information with search.",
+ "Online via {0} | {1}'s model": "Online via {0} | {1}'s model",
+ "Switched to search mode. Continue with the user's request.": "Switched to search mode. Continue with the user's request.",
+ "Experimental | Online | Google's model\nCan do a little more but doesn't search quickly": "Experimental | Online | Google's model\nCan do a little more but doesn't search quickly",
+ "Message the model... \"{0}\" for commands": "Message the model... \"{0}\" for commands",
+ "To set an API key, pass it with the command\n\nTo view the key, pass \"get\" with the command
\n\n### For {0}:\n\n**Link**: {1}\n\n{2}": "To set an API key, pass it with the command\n\nTo view the key, pass \"get\" with the command
\n\n### For {0}:\n\n**Link**: {1}\n\n{2}"
}
\ No newline at end of file
diff --git a/.config/quickshell/translations/tools/README.md b/.config/quickshell/translations/tools/README.md
new file mode 100644
index 000000000..1840f6c3d
--- /dev/null
+++ b/.config/quickshell/translations/tools/README.md
@@ -0,0 +1,111 @@
+# Translation Management Tools
+
+This directory contains a toolset for managing project translation files.
+
+## Directory Structure
+
+```
+translations/
+├── tools/ # Translation management tools directory
+│ ├── translation-manager.py # Main translation manager
+│ ├── translation-cleaner.py # Translation maintenance tool
+│ ├── manage-translations.sh # Convenient wrapper script
+│ ├── translation-tools-guide.md # Detailed usage documentation
+│ └── README.md # This file
+├── en_US.json # English translation file
+├── zh_CN.json # Chinese translation file
+└── ... # Other language files
+```
+
+## Quick Start
+
+### Running from tools directory
+
+```bash
+# Enter tools directory
+cd .config/quickshell/translations/tools
+
+# Check current translation status
+./manage-translations.sh status
+
+# Update all translation files
+./manage-translations.sh update
+
+# Update specific language
+./manage-translations.sh update -l zh_CN
+
+# Clean unused keys
+./manage-translations.sh clean
+
+# Sync all language files
+./manage-translations.sh sync
+```
+
+### Running from project root directory
+
+```bash
+# Run from project root directory (recommended to use relative paths)
+.config/quickshell/translations/tools/manage-translations.sh status
+.config/quickshell/translations/tools/manage-translations.sh update
+```
+
+## Tool Description
+
+### 🛠️ `manage-translations.sh` - Main Entry Point
+Convenient command-line interface that integrates all translation management functions.
+
+### 🔍 `translation-manager.py` - Core Manager
+- Extract translatable texts
+- Compare translation file differences
+- Interactive translation updates
+
+### 🧹 `translation-cleaner.py` - Maintenance Tool
+- Clean unused translation keys
+- Sync language file structure
+- Create backup files
+
+## Common Workflows
+
+### After adding new translatable texts
+```bash
+./manage-translations.sh update
+```
+
+### Clean up after code refactoring
+```bash
+./manage-translations.sh clean
+```
+
+### Add new language
+```bash
+./manage-translations.sh update -l new_language_code
+```
+
+### Check translation status
+```bash
+./manage-translations.sh status
+```
+
+## Documentation
+
+- 📖 [Detailed Usage Guide](./translation-tools-guide.md)
+
+## Important Notes
+
+1. **Running Location**: Tools automatically detect relative paths, can be run from tools directory or project root
+2. **Backup**: Cleanup operations automatically create backup files
+3. **Encoding**: All files use UTF-8 encoding
+4. **Permissions**: Ensure scripts have execution permissions
+
+## Supported Translation Formats
+
+The tool recognizes translatable texts in the following formats:
+```qml
+qsTr("Your text here")
+qsTr('Single quotes work too')
+i18n.t("JavaScript translations")
+```
+
+---
+
+If you have any issues, please refer to the detailed documentation or check error messages in script output.
diff --git a/.config/quickshell/translations/tools/manage-translations.sh b/.config/quickshell/translations/tools/manage-translations.sh
new file mode 100755
index 000000000..c20896a93
--- /dev/null
+++ b/.config/quickshell/translations/tools/manage-translations.sh
@@ -0,0 +1,149 @@
+#!/bin/bash
+# Translation management script - convenient wrapper
+
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+TRANSLATIONS_DIR="$(dirname "$SCRIPT_DIR")"
+SOURCE_DIR="$(dirname "$(dirname "$TRANSLATIONS_DIR")")"
+
+show_help() {
+ echo "Translation Management Tool - Convenient Wrapper"
+ echo ""
+ echo "Usage: $0 [options] "
+ echo ""
+ echo "Commands:"
+ echo " extract Extract translatable texts to temporary file"
+ echo " update Update translation files (add missing/remove extra keys)"
+ echo " clean Clean unused translation keys"
+ echo " sync Sync keys across all language files"
+ echo " status Show translation status"
+ echo ""
+ echo "Options:"
+ echo " -l, --lang LANG Specify language (e.g.: zh_CN)"
+ echo " -t, --trans-dir DIR Translation files directory (default: $TRANSLATIONS_DIR)"
+ echo " -s, --source-dir DIR Source code directory (default: $SOURCE_DIR)"
+ echo " -h, --help Show this help message"
+ echo ""
+ echo "Examples:"
+ echo " $0 extract # Extract translatable texts"
+ echo " $0 update -l zh_CN # Update Chinese translations"
+ echo " $0 update # Update all translations"
+ echo " $0 clean # Clean unused keys"
+ echo " $0 sync # Sync keys across all languages"
+ echo " $0 status # Show translation status"
+}
+
+show_status() {
+ echo "Analyzing translation status..."
+
+ # Extract current text count
+ echo "=== Current Project Status ==="
+ python3 "$SCRIPT_DIR/translation-manager.py" \
+ --translations-dir "$TRANSLATIONS_DIR" \
+ --source-dir "$SOURCE_DIR" \
+ --extract-only | grep "Extracted"
+
+ echo ""
+ echo "=== Translation File Status ==="
+
+ if [ -d "$TRANSLATIONS_DIR" ]; then
+ for file in "$TRANSLATIONS_DIR"/*.json; do
+ if [ -f "$file" ]; then
+ lang=$(basename "$file" .json)
+ count=$(jq 'length' "$file" 2>/dev/null || echo "error")
+ echo " $lang: $count keys"
+ fi
+ done
+ else
+ echo " Translation directory does not exist: $TRANSLATIONS_DIR"
+ fi
+}
+
+# Parse command line arguments
+LANG_CODE=""
+COMMAND=""
+
+while [[ $# -gt 0 ]]; do
+ case $1 in
+ -l|--lang)
+ LANG_CODE="$2"
+ shift 2
+ ;;
+ -t|--trans-dir)
+ TRANSLATIONS_DIR="$2"
+ shift 2
+ ;;
+ -s|--source-dir)
+ SOURCE_DIR="$2"
+ shift 2
+ ;;
+ -h|--help)
+ show_help
+ exit 0
+ ;;
+ extract|update|clean|sync|status)
+ if [ -n "$COMMAND" ]; then
+ echo "Error: Only one command can be specified"
+ exit 1
+ fi
+ COMMAND="$1"
+ shift
+ ;;
+ *)
+ echo "Unknown option: $1"
+ show_help
+ exit 1
+ ;;
+ esac
+done
+
+if [ -z "$COMMAND" ]; then
+ echo "Error: A command must be specified"
+ show_help
+ exit 1
+fi
+
+# Check dependencies
+if ! command -v python3 >/dev/null 2>&1; then
+ echo "Error: python3 is required"
+ exit 1
+fi
+
+if [ "$COMMAND" = "status" ] && ! command -v jq >/dev/null 2>&1; then
+ echo "Warning: jq is not installed, status display may be incomplete"
+fi
+
+# Build base arguments
+BASE_ARGS="--translations-dir $TRANSLATIONS_DIR --source-dir $SOURCE_DIR"
+
+case $COMMAND in
+ extract)
+ echo "Extracting translatable texts..."
+ python3 "$SCRIPT_DIR/translation-manager.py" $BASE_ARGS --extract-only --show-temp
+ ;;
+ update)
+ echo "Updating translation files..."
+ if [ -n "$LANG_CODE" ]; then
+ python3 "$SCRIPT_DIR/translation-manager.py" $BASE_ARGS --language "$LANG_CODE"
+ else
+ python3 "$SCRIPT_DIR/translation-manager.py" $BASE_ARGS
+ fi
+ ;;
+ clean)
+ echo "Cleaning unused translation keys..."
+ python3 "$SCRIPT_DIR/translation-cleaner.py" $BASE_ARGS --clean
+ ;;
+ sync)
+ echo "Syncing translation keys..."
+ python3 "$SCRIPT_DIR/translation-cleaner.py" $BASE_ARGS --sync
+ ;;
+ status)
+ show_status
+ ;;
+ *)
+ echo "Unknown command: $COMMAND"
+ show_help
+ exit 1
+ ;;
+esac
diff --git a/.config/quickshell/translations/tools/translation-cleaner.py b/.config/quickshell/translations/tools/translation-cleaner.py
new file mode 100755
index 000000000..e53082fda
--- /dev/null
+++ b/.config/quickshell/translations/tools/translation-cleaner.py
@@ -0,0 +1,196 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+Translation File Maintenance Helper
+Used to clean and organize translation files, removing unused keys
+"""
+
+import os
+import sys
+import json
+import argparse
+import importlib.util
+from pathlib import Path
+from typing import Dict, Set, List
+
+# Import from the same directory using importlib
+current_dir = os.path.dirname(os.path.abspath(__file__))
+manager_path = os.path.join(current_dir, 'translation-manager.py')
+spec = importlib.util.spec_from_file_location("translation_manager", manager_path)
+translation_manager = importlib.util.module_from_spec(spec)
+spec.loader.exec_module(translation_manager)
+TranslationManager = translation_manager.TranslationManager
+
+def clean_translation_files(translations_dir: str, source_dir: str, backup: bool = True):
+ """Clean translation files by removing unused keys"""
+ print("Starting translation file cleanup...")
+
+ # Create manager
+ manager = TranslationManager(translations_dir, source_dir)
+
+ # Extract currently used texts
+ print("Extracting currently used translatable texts...")
+ current_texts = manager.extract_translatable_texts()
+ print(f"Extracted {len(current_texts)} currently used texts")
+
+ # Get all language files
+ languages = manager.get_available_languages()
+ if not languages:
+ print("No translation files found")
+ return
+
+ print(f"Found language files: {', '.join(languages)}")
+
+ total_removed = 0
+
+ for lang in languages:
+ print(f"\nProcessing language: {lang}")
+
+ # Load translation file
+ translations = manager.load_translation_file(lang)
+ original_count = len(translations)
+
+ if backup:
+ # Create backup
+ backup_file = Path(translations_dir) / f"{lang}.json.backup"
+ with open(backup_file, 'w', encoding='utf-8') as f:
+ json.dump(translations, f, ensure_ascii=False, indent=2)
+ print(f"Created backup: {backup_file}")
+
+ # Find unused keys
+ unused_keys = set(translations.keys()) - current_texts
+
+ if unused_keys:
+ print(f"Found {len(unused_keys)} unused keys:")
+ for i, key in enumerate(sorted(unused_keys)[:10], 1): # Only show first 10
+ print(f" {i}. \"{key[:50]}{'...' if len(key) > 50 else ''}\"")
+ if len(unused_keys) > 10:
+ print(f" ... and {len(unused_keys) - 10} more keys")
+
+ response = input(f"Delete these {len(unused_keys)} unused keys? (y/n): ")
+ if response.lower().strip() in ['y', 'yes']:
+ # Delete unused keys
+ for key in unused_keys:
+ del translations[key]
+
+ # Save cleaned file
+ manager.save_translation_file(lang, translations)
+ removed_count = len(unused_keys)
+ total_removed += removed_count
+ print(f"Deleted {removed_count} keys")
+ else:
+ print("Skipped deletion")
+ else:
+ print("No unused keys found")
+
+ new_count = len(translations)
+ print(f"Original key count: {original_count}, after cleanup: {new_count}")
+
+ print(f"\nCleanup completed! Total deleted {total_removed} unused keys.")
+
+def sync_translations(translations_dir: str, source_lang: str = "en_US", target_langs: List[str] = None):
+ """Sync translation keys to ensure all language files have the same keys"""
+ print(f"Starting translation key sync using {source_lang} as reference...")
+
+ translations_path = Path(translations_dir)
+
+ # Load source language file
+ source_file = translations_path / f"{source_lang}.json"
+ if not source_file.exists():
+ print(f"Error: Source language file does not exist: {source_file}")
+ return
+
+ with open(source_file, 'r', encoding='utf-8') as f:
+ source_translations = json.load(f)
+
+ source_keys = set(source_translations.keys())
+ print(f"Source language {source_lang} has {len(source_keys)} keys")
+
+ # Get target language list
+ if target_langs is None:
+ target_langs = []
+ for file_path in translations_path.glob("*.json"):
+ lang_code = file_path.stem
+ if lang_code != source_lang:
+ target_langs.append(lang_code)
+
+ if not target_langs:
+ print("No target language files found")
+ return
+
+ print(f"Target languages: {', '.join(target_langs)}")
+
+ for target_lang in target_langs:
+ print(f"\nSyncing language: {target_lang}")
+
+ target_file = translations_path / f"{target_lang}.json"
+ if target_file.exists():
+ with open(target_file, 'r', encoding='utf-8') as f:
+ target_translations = json.load(f)
+ else:
+ target_translations = {}
+
+ target_keys = set(target_translations.keys())
+
+ # Find missing and extra keys
+ missing_keys = source_keys - target_keys
+ extra_keys = target_keys - source_keys
+
+ print(f" Missing keys: {len(missing_keys)}")
+ print(f" Extra keys: {len(extra_keys)}")
+
+ # Add missing keys
+ if missing_keys:
+ for key in missing_keys:
+ # Use source language value as placeholder by default
+ target_translations[key] = source_translations[key]
+ print(f" Added {len(missing_keys)} missing keys")
+
+ # Ask whether to delete extra keys
+ if extra_keys:
+ response = input(f" Delete {len(extra_keys)} extra keys? (y/n): ")
+ if response.lower().strip() in ['y', 'yes']:
+ for key in extra_keys:
+ del target_translations[key]
+ print(f" Deleted {len(extra_keys)} extra keys")
+
+ # Save file
+ with open(target_file, 'w', encoding='utf-8') as f:
+ json.dump(target_translations, f, ensure_ascii=False, indent=2)
+
+ print(f" Saved: {target_file}")
+
+def main():
+ parser = argparse.ArgumentParser(description="Translation File Maintenance Helper")
+ parser.add_argument("--translations-dir", "-t",
+ default=".config/quickshell/translations",
+ help="Translation files directory")
+ parser.add_argument("--source-dir", "-s",
+ default=".config/quickshell",
+ help="Source code directory")
+ parser.add_argument("--clean", "-c", action="store_true",
+ help="Clean unused translation keys")
+ parser.add_argument("--sync", action="store_true",
+ help="Sync translation keys")
+ parser.add_argument("--source-lang", default="en_US",
+ help="Source language for syncing (default: en_US)")
+ parser.add_argument("--no-backup", action="store_true",
+ help="Do not create backup files when cleaning")
+
+ args = parser.parse_args()
+
+ # Convert to absolute paths
+ translations_dir = os.path.abspath(args.translations_dir)
+ source_dir = os.path.abspath(args.source_dir)
+
+ if args.clean:
+ clean_translation_files(translations_dir, source_dir, backup=not args.no_backup)
+ elif args.sync:
+ sync_translations(translations_dir, args.source_lang)
+ else:
+ print("Please specify an operation:")
+ print(" --clean: Clean unused translation keys")
+ print(" --sync: Sync translation keys")
+
+if __name__ == "__main__":
+ main()
diff --git a/.config/quickshell/translations/tools/translation-manager.py b/.config/quickshell/translations/tools/translation-manager.py
new file mode 100755
index 000000000..ffcb26092
--- /dev/null
+++ b/.config/quickshell/translations/tools/translation-manager.py
@@ -0,0 +1,290 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+Translation File Management Script
+Used to update and extract translatable texts, manage JSON translation file key comparison
+"""
+
+import os
+import json
+import re
+import sys
+import argparse
+from pathlib import Path
+from typing import Dict, Set, List, Tuple
+import tempfile
+import subprocess
+
+class TranslationManager:
+ def __init__(self, translations_dir: str, source_dir: str):
+ self.translations_dir = Path(translations_dir)
+ self.source_dir = Path(source_dir)
+ self.temp_extracted_file = None
+
+ # Ensure translation directory exists
+ self.translations_dir.mkdir(parents=True, exist_ok=True)
+
+ def extract_translatable_texts(self) -> Set[str]:
+ """Extract translatable texts from source code"""
+ translatable_texts = set()
+
+ # Search patterns: Translation.tr("text") or Translation.tr('text')
+ # Improved regex that handles nested quotes correctly
+ patterns = [
+ r'Translation\.tr\s*\(\s*(["\'])(((?!\1)[^\\]|\\.)*)(\1)\s*\)', # Double or single quotes with escape support
+ r'Translation\.tr\s*\(\s*`([^`]*(?:\\.[^`]*)*?)`\s*\)', # Backticks (template strings)
+ ]
+
+ # Search all .qml and .js files
+ file_extensions = ['*.qml', '*.js']
+
+ for ext in file_extensions:
+ for file_path in self.source_dir.rglob(ext):
+ try:
+ with open(file_path, 'r', encoding='utf-8') as f:
+ content = f.read()
+
+ for pattern in patterns:
+ matches = re.findall(pattern, content, re.MULTILINE | re.DOTALL)
+ for match in matches:
+ # Handle different match group structures
+ if isinstance(match, tuple):
+ # For improved regex, text is in the second group
+ if len(match) >= 3:
+ text = match[1] # Second group is the text content
+ else:
+ text = match[0] if match else ""
+ else:
+ text = match
+
+ # Decode escape characters
+ try:
+ clean_text = text.encode().decode('unicode_escape')
+ except:
+ clean_text = text
+
+ # Clean text (remove extra whitespace)
+ clean_text = clean_text.strip()
+ if clean_text:
+ translatable_texts.add(clean_text)
+
+ except (UnicodeDecodeError, IOError) as e:
+ print(f"Warning: Cannot read file {file_path}: {e}")
+
+ return translatable_texts
+
+ def create_temp_translation_file(self, texts: Set[str]) -> str:
+ """Create temporary JSON file containing extracted texts"""
+ temp_data = {}
+ for text in sorted(texts):
+ temp_data[text] = text # Key and value are the same, indicating untranslated
+
+ # Create temporary file
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False, encoding='utf-8') as f:
+ json.dump(temp_data, f, ensure_ascii=False, indent=2)
+ self.temp_extracted_file = f.name
+
+ return self.temp_extracted_file
+
+ def load_translation_file(self, lang_code: str) -> Dict[str, str]:
+ """Load translation file for specified language"""
+ file_path = self.translations_dir / f"{lang_code}.json"
+ if file_path.exists():
+ try:
+ with open(file_path, 'r', encoding='utf-8') as f:
+ return json.load(f)
+ except (json.JSONDecodeError, IOError) as e:
+ print(f"Warning: Cannot load translation file {file_path}: {e}")
+ return {}
+ return {}
+
+ def save_translation_file(self, lang_code: str, translations: Dict[str, str]):
+ """Save translation file"""
+ file_path = self.translations_dir / f"{lang_code}.json"
+ try:
+ with open(file_path, 'w', encoding='utf-8') as f:
+ json.dump(translations, f, ensure_ascii=False, indent=2)
+ print(f"Translation file saved: {file_path}")
+ except IOError as e:
+ print(f"Error: Cannot save translation file {file_path}: {e}")
+
+ def get_available_languages(self) -> List[str]:
+ """Get list of available languages"""
+ languages = []
+ for file_path in self.translations_dir.glob("*.json"):
+ lang_code = file_path.stem
+ languages.append(lang_code)
+ return sorted(languages)
+
+ def compare_translations(self, extracted_texts: Set[str], target_lang: str) -> Tuple[Set[str], Set[str]]:
+ """Compare extracted texts with existing translation file"""
+ existing_translations = self.load_translation_file(target_lang)
+ existing_keys = set(existing_translations.keys())
+
+ missing_keys = extracted_texts - existing_keys # Missing keys
+ extra_keys = existing_keys - extracted_texts # Extra keys
+
+ return missing_keys, extra_keys
+
+ def interactive_update(self, lang_code: str, missing_keys: Set[str], extra_keys: Set[str]):
+ """Interactively update translation file"""
+ translations = self.load_translation_file(lang_code)
+ modified = False
+
+ # Handle missing keys
+ if missing_keys:
+ print(f"\nFound {len(missing_keys)} missing translation keys:")
+ for i, key in enumerate(sorted(missing_keys), 1):
+ print(f"{i}. \"{key}\"")
+
+ if self.ask_yes_no(f"\nAdd these {len(missing_keys)} missing keys?"):
+ for key in missing_keys:
+ translations[key] = key # Default value is the key itself
+ modified = True
+ print(f"Added {len(missing_keys)} keys")
+
+ # Handle extra keys
+ if extra_keys:
+ print(f"\nFound {len(extra_keys)} extra translation keys:")
+ for i, key in enumerate(sorted(extra_keys), 1):
+ print(f"{i}. \"{key}\" -> \"{translations.get(key, '')}\"")
+
+ if self.ask_yes_no(f"\nDelete these {len(extra_keys)} extra keys?"):
+ for key in extra_keys:
+ if key in translations:
+ del translations[key]
+ modified = True
+ print(f"Deleted {len(extra_keys)} keys")
+
+ # Save changes
+ if modified:
+ self.save_translation_file(lang_code, translations)
+ else:
+ print("No changes made")
+
+ def ask_yes_no(self, question: str) -> bool:
+ """Ask user for confirmation"""
+ while True:
+ response = input(f"{question} (y/n): ").lower().strip()
+ if response in ['y', 'yes']:
+ return True
+ elif response in ['n', 'no']:
+ return False
+ else:
+ print("Please enter y/yes or n/no")
+
+ def cleanup(self):
+ """Clean up temporary files"""
+ if self.temp_extracted_file and os.path.exists(self.temp_extracted_file):
+ os.unlink(self.temp_extracted_file)
+
+def main():
+ parser = argparse.ArgumentParser(description="Translation file management tool")
+ parser.add_argument("--translations-dir", "-t",
+ default=".config/quickshell/translations",
+ help="Translation files directory (default: .config/quickshell/translations)")
+ parser.add_argument("--source-dir", "-s",
+ default=".config/quickshell",
+ help="Source code directory (default: .config/quickshell)")
+ parser.add_argument("--language", "-l",
+ help="Specify language code to process (e.g., zh_CN)")
+ parser.add_argument("--extract-only", "-e", action="store_true",
+ help="Only extract translatable texts to temporary file")
+ parser.add_argument("--show-temp", action="store_true",
+ help="Show temporary extracted file content")
+
+ args = parser.parse_args()
+
+ # Convert to absolute paths
+ translations_dir = os.path.abspath(args.translations_dir)
+ source_dir = os.path.abspath(args.source_dir)
+
+ print(f"Translation directory: {translations_dir}")
+ print(f"Source code directory: {source_dir}")
+
+ # Check if directories exist
+ if not os.path.exists(source_dir):
+ print(f"Error: Source code directory does not exist: {source_dir}")
+ sys.exit(1)
+
+ # Create manager
+ manager = TranslationManager(translations_dir, source_dir)
+
+ try:
+ # Extract translatable texts
+ print("\nExtracting translatable texts...")
+ extracted_texts = manager.extract_translatable_texts()
+ print(f"Extracted {len(extracted_texts)} translatable texts")
+
+ # Create temporary file
+ temp_file = manager.create_temp_translation_file(extracted_texts)
+ print(f"Created temporary file: {temp_file}")
+
+ if args.show_temp:
+ print("\nTemporary file contents:")
+ with open(temp_file, 'r', encoding='utf-8') as f:
+ print(f.read())
+
+ if args.extract_only:
+ print("Extract-only mode, program finished")
+ return
+
+ # Get available languages
+ available_languages = manager.get_available_languages()
+
+ if args.language:
+ target_languages = [args.language]
+ else:
+ print(f"\nAvailable languages: {', '.join(available_languages) if available_languages else 'None'}")
+
+ if not available_languages:
+ print("No existing translation files found")
+ lang_input = input("Enter language code to create (e.g.: zh_CN): ").strip()
+ if lang_input:
+ target_languages = [lang_input]
+ else:
+ print("No language specified, program finished")
+ return
+ else:
+ print("Choose language to process:")
+ for i, lang in enumerate(available_languages, 1):
+ print(f"{i}. {lang}")
+ print("a. Process all languages")
+
+ choice = input("Please choose (enter number, language code, or 'a'): ").strip()
+
+ if choice.lower() == 'a':
+ target_languages = available_languages
+ elif choice.isdigit() and 1 <= int(choice) <= len(available_languages):
+ target_languages = [available_languages[int(choice) - 1]]
+ elif choice in available_languages:
+ target_languages = [choice]
+ else:
+ print("Invalid choice, program finished")
+ return
+
+ # Process each language
+ for lang in target_languages:
+ print(f"\n{'='*50}")
+ print(f"Processing language: {lang}")
+ print('='*50)
+
+ missing_keys, extra_keys = manager.compare_translations(extracted_texts, lang)
+
+ if not missing_keys and not extra_keys:
+ print(f"Translation file for language {lang} is already up to date")
+ continue
+
+ print(f"Analysis results:")
+ print(f" Missing keys: {len(missing_keys)}")
+ print(f" Extra keys: {len(extra_keys)}")
+
+ if missing_keys or extra_keys:
+ manager.interactive_update(lang, missing_keys, extra_keys)
+
+ finally:
+ # Clean up temporary files
+ manager.cleanup()
+
+if __name__ == "__main__":
+ main()
diff --git a/.config/quickshell/translations/tools/translation-tools-guide.md b/.config/quickshell/translations/tools/translation-tools-guide.md
new file mode 100644
index 000000000..527576329
--- /dev/null
+++ b/.config/quickshell/translations/tools/translation-tools-guide.md
@@ -0,0 +1,246 @@
+# Translation Management Tool Suite
+
+This tool suite is used to manage project translation files, automatically extract translatable texts, compare differences between different language files, and provide maintenance functions.
+
+## Tool Components
+
+### 1. `translation-manager.py` - Main Translation Manager
+- Extract translatable texts
+- Compare and update translation files
+- Interactive adding/removing translation keys
+
+### 2. `translation-cleaner.py` - Translation File Maintenance Tool
+- Clean unused translation keys
+- Sync key structure across different language files
+
+### 3. `manage-translations.sh` - Convenient Wrapper Script
+- Provide unified command-line interface
+- Display translation status
+- Simplify common operations
+
+## Quick Start
+
+### Check Translation Status
+```bash
+./manage-translations.sh status
+```
+
+### Extract Translatable Texts
+```bash
+./manage-translations.sh extract
+```
+
+### Update Translation Files
+```bash
+# Update all languages
+./manage-translations.sh update
+
+# Update specific language
+./manage-translations.sh update -l zh_CN
+```
+
+### Clean Unused Keys
+```bash
+./manage-translations.sh clean
+```
+
+### Sync Keys Across Languages
+```bash
+./manage-translations.sh sync
+```
+
+## Detailed Usage
+
+### translation-manager.py
+
+The main translation management tool that extracts translatable texts from source code and manages translation files.
+
+#### Command Line Options
+```bash
+python3 translation-manager.py [options]
+
+Options:
+ -h, --help Show help message
+ -t, --translations-dir DIR Translation files directory (default: .config/quickshell/translations)
+ -s, --source-dir DIR Source code directory (default: .config/quickshell)
+ -l, --language LANG Specify language code to process (e.g., zh_CN)
+ -e, --extract-only Only extract translatable texts to temporary file
+ --show-temp Show temporary extracted file content
+```
+
+#### Features
+1. **Text Extraction**: Uses regex patterns to extract translatable texts from QML and JavaScript files
+2. **Smart Filtering**: Automatically removes duplicates and cleans up extracted texts
+3. **Interactive Updates**: Guides users through adding missing keys and removing extra ones
+4. **Backup Support**: Creates backups before making changes
+
+#### Supported Text Patterns
+- `qsTr("text")` and `qsTr('text')`
+- `i18n.t("text")` and `i18n.t('text')`
+- Supports nested quotes and escape characters
+- Handles multiline strings
+
+### translation-cleaner.py
+
+A maintenance tool for cleaning up and synchronizing translation files.
+
+#### Command Line Options
+```bash
+python3 translation-cleaner.py [options]
+
+Options:
+ -h, --help Show help message
+ -t, --translations-dir DIR Translation files directory
+ -s, --source-dir DIR Source code directory
+ -c, --clean Clean unused translation keys
+ --sync Sync translation keys
+ --source-lang LANG Source language for syncing (default: en_US)
+ --no-backup Do not create backup files when cleaning
+```
+
+#### Features
+1. **Unused Key Cleanup**: Identifies and removes translation keys that are no longer used in the source code
+2. **Key Synchronization**: Ensures all language files have the same set of keys
+3. **Backup Protection**: Creates backup files before making destructive changes
+4. **Interactive Confirmation**: Asks for user confirmation before deleting keys
+
+### manage-translations.sh
+
+A convenient wrapper script that provides a unified interface to all translation tools.
+
+#### Commands
+```bash
+./manage-translations.sh [options]
+
+Commands:
+ extract Extract translatable texts to temporary file
+ update Update translation files (add missing/remove extra keys)
+ clean Clean unused translation keys
+ sync Sync keys across all language files
+ status Show translation status
+
+Options:
+ -l, --lang LANG Specify language (e.g.: zh_CN)
+ -t, --trans-dir DIR Translation files directory
+ -s, --source-dir DIR Source code directory
+ -h, --help Show help message
+```
+
+## Workflow Examples
+
+### Initial Setup
+1. Create translation directory structure
+2. Extract all translatable texts: `./manage-translations.sh extract`
+3. Create initial translation files: `./manage-translations.sh update`
+
+### Regular Maintenance
+1. Check status: `./manage-translations.sh status`
+2. Update translations after code changes: `./manage-translations.sh update`
+3. Clean up unused keys periodically: `./manage-translations.sh clean`
+
+### Adding New Language
+1. Create new language file: `./manage-translations.sh update -l new_lang`
+2. Sync keys if needed: `./manage-translations.sh sync`
+
+## File Structure
+
+```
+translations/
+├── tools/ # Translation management tools
+│ ├── translation-manager.py # Main extraction and update tool
+│ ├── translation-cleaner.py # Cleanup and sync tool
+│ ├── manage-translations.sh # Wrapper script
+│ └── translation-tools-guide.md # This documentation
+├── en_US.json # English translations (reference)
+├── zh_CN.json # Chinese translations
+└── [other_lang].json # Other language files
+```
+
+## Configuration
+
+### Text Extraction Patterns
+
+The tool uses regex patterns to identify translatable texts. Current patterns include:
+
+1. **QML qsTr patterns**:
+ - `qsTr("text")` and `qsTr('text')`
+ - Supports escaped quotes and nested quotes
+
+2. **JavaScript i18n patterns**:
+ - `i18n.t("text")` and `i18n.t('text')`
+ - Supports template literals and complex expressions
+
+3. **Custom patterns** can be added by modifying the patterns list in `translation-manager.py`
+
+### File Extensions
+
+By default, the tool processes:
+- `.qml` files (QML/QtQuick)
+- `.js` files (JavaScript)
+
+Additional file types can be added by modifying the file extension filters.
+
+## Best Practices
+
+1. **Regular Updates**: Run `./manage-translations.sh status` regularly to check for new translatable texts
+2. **Clean Periodically**: Use `./manage-translations.sh clean` to remove unused keys
+3. **Backup Important**: Always backup translation files before major changes
+4. **Consistent Patterns**: Use consistent function calls (`qsTr`, `i18n.t`) for translatable texts
+5. **Review Changes**: Always review the changes before confirming deletions or additions
+
+## Troubleshooting
+
+### Common Issues
+
+1. **Missing Texts**: If some translatable texts are not extracted, check if they match the supported patterns
+2. **Path Issues**: Ensure the source and translation directory paths are correct
+3. **Permission Errors**: Make sure the script has write permissions to the translation directory
+4. **Encoding Issues**: All files should be saved in UTF-8 encoding
+
+### Getting Help
+
+For additional help:
+- Use `--help` option with any tool
+- Check the console output for error messages
+- Verify file paths and permissions
+
+## Advanced Usage
+
+### Custom Regex Patterns
+
+To add support for new translation function patterns, modify the `patterns` list in `TranslationManager.extract_translatable_texts()`:
+
+```python
+patterns = [
+ # Existing patterns...
+ r'customTranslate\s*\(\s*(["\'])((?:\\.|(?!\1)[^\\])*?)\1\s*\)', # Custom pattern
+]
+```
+
+### Batch Processing
+
+For processing multiple projects or directories:
+
+```bash
+# Process multiple directories
+for dir in project1 project2 project3; do
+ ./manage-translations.sh -s "$dir" -t "$dir/translations" update
+done
+```
+
+### Integration with Build Systems
+
+The tools can be integrated into build systems to automatically update translations:
+
+```bash
+# In your build script
+./manage-translations.sh update --non-interactive
+```
+
+## Version History
+
+- **v1.0**: Initial version with basic extraction and update functionality
+- **v1.1**: Added improved regex patterns for better text extraction
+- **v1.2**: Added cleaning and synchronization tools
+- **v1.3**: Added English output and improved user interface
+- **v1.4**: Moved all tools to dedicated tools directory and improved documentation
diff --git a/.config/quickshell/translations/tools/翻译管理脚本说明.md b/.config/quickshell/translations/tools/翻译管理脚本说明.md
new file mode 100644
index 000000000..fa9850cf8
--- /dev/null
+++ b/.config/quickshell/translations/tools/翻译管理脚本说明.md
@@ -0,0 +1,287 @@
+# 翻译管理工具套件
+
+这套工具用于管理项目的翻译文件,自动提取可翻译文本,比较不同语言文件之间的差异,并提供维护功能。
+
+## 工具组成
+
+### 1. `translation-manager.py` - 主要翻译管理器
+- 提取可翻译文本
+- 比较和更新翻译文件
+- 交互式添加/删除翻译键
+
+### 2. `translation-cleaner.py` - 翻译文件维护工具
+- 清理不再使用的翻译键
+- 同步不同语言文件的键结构
+
+### 3. `manage-translations.sh` - 便捷包装脚本
+- 提供统一的命令行界面
+- 显示翻译状态
+- 简化常用操作
+
+## 快速开始
+
+### 使用便捷脚本(推荐)
+
+```bash
+# 进入工具目录
+cd .config/quickshell/translations/tools
+
+# 查看帮助
+./manage-translations.sh --help
+
+# 显示当前翻译状态
+./manage-translations.sh status
+
+# 提取可翻译文本
+./manage-translations.sh extract
+
+# 更新所有翻译文件
+./manage-translations.sh update
+
+# 更新特定语言
+./manage-translations.sh update -l zh_CN
+
+# 清理不再使用的键
+./manage-translations.sh clean
+
+# 同步所有语言文件的键
+./manage-translations.sh sync
+```
+
+或者从项目根目录运行:
+```bash
+# 从项目根目录运行
+.config/quickshell/translations/tools/manage-translations.sh status
+.config/quickshell/translations/tools/manage-translations.sh update
+```
+
+## 详细使用说明
+
+### 翻译管理器 (`translation-manager.py`)
+
+基本用法:
+```bash
+# 处理所有语言
+./translation-manager.py
+
+# 指定特定语言
+./translation-manager.py --language zh_CN
+
+# 仅提取可翻译文本
+./translation-manager.py --extract-only
+
+# 显示提取的文本
+./translation-manager.py --extract-only --show-temp
+```
+
+参数说明:
+- `--translations-dir`, `-t`: 翻译文件目录(默认:`.config/quickshell/translations`)
+- `--source-dir`, `-s`: 源代码目录(默认:`.config/quickshell`)
+- `--language`, `-l`: 指定要处理的语言代码
+- `--extract-only`, `-e`: 仅提取可翻译文本
+- `--show-temp`: 显示临时提取文件的内容
+
+### 翻译清理器 (`translation-cleaner.py`)
+
+```bash
+# 清理不再使用的翻译键
+./translation-cleaner.py --clean
+
+# 同步翻译键(以 en_US 为基准)
+./translation-cleaner.py --sync
+
+# 指定不同的源语言进行同步
+./translation-cleaner.py --sync --source-lang zh_CN
+
+# 清理时不创建备份
+./translation-cleaner.py --clean --no-backup
+```
+
+## 工作流程
+
+### 日常翻译更新流程
+
+1. **检查状态**:
+ ```bash
+ ./manage-translations.sh status
+ ```
+
+2. **更新翻译**:
+ ```bash
+ ./manage-translations.sh update
+ ```
+
+3. **清理无用键**(可选):
+ ```bash
+ ./manage-translations.sh clean
+ ```
+
+### 新增语言流程
+
+1. **创建新语言文件**:
+ ```bash
+ ./manage-translations.sh update -l new_lang
+ ```
+
+2. **同步键结构**:
+ ```bash
+ ./manage-translations.sh sync
+ ```
+
+### 大规模重构后的清理流程
+
+1. **备份翻译文件**:
+ ```bash
+ cp -r .config/quickshell/translations .config/quickshell/translations.backup
+ ```
+
+2. **清理无用键**:
+ ```bash
+ ./manage-translations.sh clean
+ ```
+
+3. **同步所有语言**:
+ ```bash
+ ./manage-translations.sh sync
+ ```
+
+## 支持的翻译文本格式
+
+工具可以识别以下格式的可翻译文本:
+
+```qml
+// 基本格式
+Translation.tr("Hello, world!")
+Translation.tr('Hello, world!')
+Translation.tr(`Hello, world!`)
+
+// 带换行符
+Translation.tr("Line 1\nLine 2")
+
+// 带转义字符
+Translation.tr("Say \"Hello\"")
+
+// 带参数占位符
+Translation.tr("Hello, %1!").arg(name)
+Translation.tr("{0} files selected").arg(count)
+```
+
+## 示例输出
+
+### 状态显示
+```
+$ ./manage-translations.sh status
+正在分析翻译状态...
+=== 当前项目状态 ===
+提取到 166 个可翻译文本
+
+=== 翻译文件状态 ===
+ en_US: 470 个键
+ zh_CN: 470 个键
+```
+
+### 更新翻译
+```
+$ ./manage-translations.sh update -l zh_CN
+更新翻译文件...
+==================================================
+处理语言: zh_CN
+==================================================
+分析结果:
+ 缺少的键: 5
+ 多余的键: 20
+
+发现 5 个缺少的翻译键:
+1. "New feature text"
+2. "Another new text"
+...
+
+是否添加这 5 个缺少的键? (y/n): y
+已添加 5 个键
+
+发现 20 个多余的翻译键:
+1. "Removed old text" -> "已删除的旧文本"
+...
+
+是否删除这 20 个多余的键? (y/n): y
+已删除 20 个键
+
+已保存翻译文件
+```
+
+### 清理无用键
+```
+$ ./manage-translations.sh clean
+清理不再使用的翻译键...
+处理语言: zh_CN
+发现 50 个不再使用的键:
+ 1. "old_unused_text"
+ 2. "deprecated_message"
+ ...
+
+是否删除这 50 个不再使用的键? (y/n): y
+已删除 50 个键
+原始键数: 470, 清理后: 420
+```
+
+## 高级功能
+
+### 自定义目录结构
+
+```bash
+# 使用自定义目录
+./translation-manager.py \
+ --translations-dir /path/to/translations \
+ --source-dir /path/to/source
+```
+
+### 批量处理
+
+```bash
+# 创建处理脚本
+cat > update-all-translations.sh << 'EOF'
+#!/bin/bash
+for lang in zh_CN ja_JP ko_KR; do
+ echo "Processing $lang..."
+ ./manage-translations.sh update -l $lang
+done
+EOF
+
+chmod +x update-all-translations.sh
+./update-all-translations.sh
+```
+
+## 注意事项
+
+1. **备份重要**:在执行清理操作前,工具会自动创建备份,但建议手动备份重要文件
+
+2. **文本提取限制**:
+ - 只支持静态字符串,不支持动态构建的字符串
+ - 必须使用 `Translation.tr()` 格式
+
+3. **文件编码**:所有文件必须使用 UTF-8 编码
+
+4. **键名规范**:建议使用英文作为键名,避免使用特殊字符
+
+## 故障排除
+
+### 常见问题
+
+**Q: 提取的文本数量与预期不符?**
+A: 检查是否所有可翻译文本都使用了 `Translation.tr()` 格式,确保没有动态构建的字符串。
+
+**Q: 同步后某些翻译丢失?**
+A: 检查源语言文件是否包含所有必要的键,考虑使用不同的源语言进行同步。
+
+**Q: 清理操作删除了需要的键?**
+A: 从自动创建的备份文件中恢复,检查源代码中是否正确使用了 `Translation.tr()`。
+
+### 恢复备份
+
+```bash
+# 恢复单个文件
+cp .config/quickshell/translations/zh_CN.json.backup .config/quickshell/translations/zh_CN.json
+
+# 恢复所有文件
+cp .config/quickshell/translations.backup/* .config/quickshell/translations/
+```
diff --git a/.config/quickshell/translations/zh_CN.json b/.config/quickshell/translations/zh_CN.json
index f73a6949f..a0d099397 100644
--- a/.config/quickshell/translations/zh_CN.json
+++ b/.config/quickshell/translations/zh_CN.json
@@ -27,28 +27,26 @@
"Clear chat history": "清除聊天记录",
"Clear the current list of images": "清除当前图片列表",
"Close": "关闭",
- "Closes cheatsheet on press": "Closes cheatsheet on press",
- "Closes left sidebar on press": "Closes left sidebar on press",
- "Closes media controls on press": "Closes media controls on press",
- "Closes on screen keyboard on press": "Closes on screen keyboard on press",
- "Closes overview": "Closes overview",
- "Closes right sidebar on press": "Closes right sidebar on press",
+ "Closes cheatsheet on press": "按下时关闭快捷键表",
+ "Closes left sidebar on press": "按下时关闭左侧边栏",
+ "Closes media controls on press": "按下时关闭媒体控制",
+ "Closes on screen keyboard on press": "按下时关闭屏幕键盘",
+ "Closes overview": "关闭概览",
+ "Closes right sidebar on press": "按下时关闭右侧边栏",
"Copy": "复制",
"Copy code": "复制代码",
- "Ctrl+O to expand the sidebar\nCtrl+P to detach sidebar into a window": "Ctrl+O 展开侧边栏\nCtrl+P 将侧边栏分离为窗口",
"Current API endpoint: {0}\nSet it with {1}mode PROVIDER": "当前 API 端点:{0}\n使用 {1}mode PROVIDER 设置",
"Current model: {0}\nSet it with {1}model MODEL": "当前模型:{0}\n使用 {1}model MODEL 设置",
- "Decrease brightness": "Decrease brightness",
+ "Decrease brightness": "降低亮度",
"Delete": "删除",
"Desktop": "桌面",
- "Detach left sidebar into a window/Attach it back": "Detach left sidebar into a window/Attach it back",
+ "Detach left sidebar into a window/Attach it back": "将左侧边栏分离为窗口/重新附加",
"Disable NSFW content": "禁用 NSFW 内容",
"Done": "完成",
"Download": "下载",
"Download complete": "下载完成",
"Edit": "编辑",
"Enter text to translate...": "输入要翻译的文本...",
- "Experimental | Online | Google's model\nCan do a little more but doesn't search quickly": "实验性 | 在线 | Google 模型\n功能更多但搜索速度较慢",
"Finished tasks will go here": "已完成的任务将显示在这里",
"For desktop wallpapers | Good quality": "桌面壁纸专用 | 质量好",
"For storing API keys and other sensitive information": "用于存储 API 密钥和其他敏感信息",
@@ -56,17 +54,14 @@
"Get the next page of results": "获取下一页结果",
"Go to source ({0})": "转到源 ({0})",
"Hibernate": "休眠",
- "Hides brightness OSD on press": "Hides brightness OSD on press",
- "Hides volume OSD on press": "Hides volume OSD on press",
- "Hold to show workspace numbers, release to show icons": "Hold to show workspace numbers, release to show icons",
- "Increase brightness": "Increase brightness",
+ "Hides brightness OSD on press": "按下时隐藏亮度显示",
+ "Hides volume OSD on press": "按下时隐藏音量显示",
+ "Hold to show workspace numbers, release to show icons": "按住显示工作区编号,松开显示图标",
+ "Increase brightness": "提高亮度",
"Input": "输入",
"Intelligence": "智能",
"Interface": "界面",
- "Interrupts possibility of overview being toggled on release. ": "Interrupts possibility of overview being toggled on release. ",
- "Invalid API provider. Supported: \n- ": "无效的 API 提供商。支持的:\n- ",
"Invalid arguments. Must provide `key` and `value`.": "参数无效。必须提供 `key` 和 `value`。",
- "Invalid model. Supported: \n```\n": "无效模型。支持的:\n```\n",
"Jump to current month": "跳转到当前月份",
"Keep system awake": "保持系统唤醒",
"Large images | God tier quality, no NSFW.": "大尺寸图片 | 顶级质量,无 NSFW",
@@ -86,24 +81,21 @@
"Nothing here!": "这里什么都没有!",
"Notifications": "通知",
"OK": "确定",
- "Online via {0} | {1}'s model": "通过 {0} 在线 | {1} 模型",
- "Online | Google's model\nGives up-to-date information with search.": "在线 | Google 模型\n通过搜索提供最新信息。",
"Open file link": "打开文件链接",
- "Opens cheatsheet on press": "Opens cheatsheet on press",
- "Opens left sidebar on press": "Opens left sidebar on press",
- "Opens media controls on press": "Opens media controls on press",
- "Opens on screen keyboard on press": "Opens on screen keyboard on press",
- "Opens right sidebar on press": "Opens right sidebar on press",
- "Opens session screen on press": "Opens session screen on press",
+ "Opens cheatsheet on press": "按下时打开快捷键表",
+ "Opens left sidebar on press": "按下时打开左侧边栏",
+ "Opens media controls on press": "按下时打开媒体控制",
+ "Opens on screen keyboard on press": "按下时打开屏幕键盘",
+ "Opens right sidebar on press": "按下时打开右侧边栏",
+ "Opens session screen on press": "按下时打开会话屏幕",
"Output": "输出",
"Page {0}": "第 {0} 页",
"Plasma Settings": "Plasma 设置",
- "Provider set to ": "提供商设置为",
"Reboot": "重启",
- "Reboot to firmware settings": "Reboot to firmware settings",
+ "Reboot to firmware settings": "重启到固件设置",
"Reload Hyprland & Quickshell": "重新加载 Hyprland 和 Quickshell",
"Run": "运行",
- "Run command": "Run command",
+ "Run command": "运行命令",
"Save": "保存",
"Save to Downloads": "保存到下载文件夹",
"Scroll to change brightness": "滚动调节亮度",
@@ -122,351 +114,63 @@
"Shutdown": "关机",
"Silent": "静音",
"Sleep": "睡眠",
- "Switched to search mode. Continue with the user's request.": "已切换到搜索模式。继续处理用户请求。",
"System": "系统",
"Task Manager": "任务管理器",
"Task description": "任务描述",
"Temperature must be between 0 and 2": "温度必须在 0 到 2 之间",
"Temperature set to {0}": "温度设置为 {0}",
"Temperature: {0}": "温度:{0}",
- "That didn't work. Tips:\n- Check your tags and NSFW settings\n- If you don't have a tag in mind, type a page number": "没有找到结果。提示:\n- 检查您的标签和 NSFW 设置\n- 如果没有想到标签,请输入页码",
- "The current API used. Endpoint: ": "当前使用的 API。端点:",
"The hentai one | Great quantity, a lot of NSFW, quality varies wildly": "成人向 | 数量巨大,大量 NSFW,质量参差不齐",
"The popular one | Best quantity, but quality can vary wildly": "最受欢迎 | 数量最多,但质量参差不齐",
"Thinking": "思考中",
- "This is necessary because GlobalShortcut.onReleased in quickshell triggers whether or not you press something else while holding the key. ": "This is necessary because GlobalShortcut.onReleased in quickshell triggers whether or not you press something else while holding the key. ",
- "To make sure this works consistently, use binditn = MODKEYS, catchall in an automatically triggered submap that includes everything.": "To make sure this works consistently, use binditn = MODKEYS, catchall in an automatically triggered submap that includes everything.",
- "Toggle clipboard query on overview widget": "Toggle clipboard query on overview widget",
- "Toggle emoji query on overview widget": "Toggle emoji query on overview widget",
- "Toggles cheatsheet on press": "Toggles cheatsheet on press",
- "Toggles left sidebar on press": "Toggles left sidebar on press",
- "Toggles media controls on press": "Toggles media controls on press",
- "Toggles on screen keyboard on press": "Toggles on screen keyboard on press",
- "Toggles overview on press": "Toggles overview on press",
- "Toggles overview on release": "Toggles overview on release",
- "Toggles right sidebar on press": "Toggles right sidebar on press",
- "Toggles session screen on press": "Toggles session screen on press",
+ "To make sure this works consistently, use binditn = MODKEYS, catchall in an automatically triggered submap that includes everything.": "为确保此功能正常工作,请在自动触发的子映射中使用 binditn = MODKEYS, catchall,该子映射包含所有内容。",
+ "Toggle clipboard query on overview widget": "在概览组件中切换剪贴板查询",
+ "Toggle emoji query on overview widget": "在概览组件中切换表情符号查询",
+ "Toggles cheatsheet on press": "按下时切换快捷键表",
+ "Toggles left sidebar on press": "按下时切换左侧边栏",
+ "Toggles media controls on press": "按下时切换媒体控制",
+ "Toggles on screen keyboard on press": "按下时切换屏幕键盘",
+ "Toggles overview on press": "按下时切换概览",
+ "Toggles overview on release": "松开时切换概览",
+ "Toggles right sidebar on press": "按下时切换右侧边栏",
+ "Toggles session screen on press": "按下时切换会话屏幕",
"Translation goes here...": "翻译结果会显示在这里...",
"Translator": "翻译器",
- "Triggers brightness OSD on press": "Triggers brightness OSD on press",
- "Triggers volume OSD on press": "Triggers volume OSD on press",
+ "Triggers brightness OSD on press": "按下时触发亮度显示",
+ "Triggers volume OSD on press": "按下时触发音量显示",
"Unfinished": "未完成",
"Unknown": "未知",
"Unknown Album": "未知专辑",
"Unknown Artist": "未知艺术家",
"Unknown Title": "未知标题",
- "Unknown command: ": "未知命令:",
"Unknown function call: {0}": "未知函数调用:{0}",
"Uptime: {0}": "运行时间:{0}",
- "Use casual tone. No user knowledge is to be assumed except basic Linux literacy. Be brief and concise: When explaining concepts, use bullet points (prefer minus sign (-) over asterisk (*)) and highlight keywords in **bold** to pinpoint the main concepts instead of long paragraphs. You are also encouraged to split your response with h2 headers, each header title beginning with an emoji, like `## 🐧 Linux`. When making changes to the user's config, you must get the config to know what values there are before setting.": "Use casual tone. No user knowledge is to be assumed except basic Linux literacy. Be brief and concise: When explaining concepts, use bullet points (prefer minus sign (-) over asterisk (*)) and highlight keywords in **bold** to pinpoint the main concepts instead of long paragraphs. You are also encouraged to split your response with h2 headers, each header title beginning with an emoji, like `## 🐧 Linux`. When making changes to the user's config, you must get the config to know what values there are before setting.",
"View Markdown source": "查看 Markdown 源码",
"Volume": "音量",
"Volume mixer": "音量混合器",
"Waifus only | Excellent quality, limited quantity": "仅限角色 | 优秀质量,数量有限",
"Waiting for response...": "等待响应...",
"Workspace": "工作区",
- "\nSet with /mode PROVIDER": "\n使用 /mode PROVIDER 设置",
- "about": "关于",
- "accessed": "访问时间",
- "account": "账户",
- "active": "活动",
- "active_state": "活动状态",
- "addon": "附加组件",
- "addons": "附加组件",
- "address": "地址",
- "admin": "管理员",
- "align": "对齐",
- "always_on_top": "总在最前",
- "animate": "动画",
- "app": "应用",
- "appearance": "外观",
- "application": "应用程序",
- "applications": "应用程序",
- "apply": "应用",
- "apps": "应用",
- "auto": "自动",
- "background": "背景",
- "balanced": "平衡",
- "bar": "栏",
- "bars": "栏",
- "battery": "电池",
- "bluetooth": "蓝牙",
- "blur": "模糊",
- "border": "边框",
- "bottom": "底部",
- "brightness": "亮度",
- "bring_to_front": "置于顶层",
- "bytes": "{0} 字节",
- "cancel": "取消",
- "center": "居中",
- "characters": "{0} 个字符",
- "charging": "充电中",
- "clear_all": "清除全部",
- "clicked": "点击",
- "close": "关闭",
- "collapse": "折叠",
- "color": "颜色",
- "command": "命令",
- "connected": "已连接",
- "connecting": "连接中...",
- "context_menu": "右键菜单",
- "copy": "复制",
- "cpu": "处理器",
- "created": "创建时间",
- "critical": "电量危险",
- "customize": "自定义",
- "cut": "剪切",
- "dark": "深色",
- "dashboard": "仪表板",
- "date": "日期",
- "debug": "调试",
- "default": "默认",
- "degrees": "{0}°",
- "delete": "删除",
- "demo": "演示",
- "desktop": "桌面",
- "dialog": "对话框",
- "disabled": "已禁用",
- "discharging": "放电中",
- "disconnected": "已断开",
- "disk": "磁盘",
- "display": "显示",
- "distribute": "分布",
- "dock": "停靠栏",
- "documents": "文档",
- "double_clicked": "双击",
- "downloads": "下载",
- "dragged": "拖拽",
- "dropdown": "下拉菜单",
- "dropped": "拖放",
- "effect": "效果",
- "email": "邮箱",
- "enabled": "已启用",
- "error": "错误",
- "ethernet": "以太网",
- "example": "示例",
- "execute": "执行",
- "exit": "退出",
- "expand": "展开",
- "extension": "扩展",
- "extensions": "扩展",
- "fan": "风扇",
- "favorites": "收藏夹",
- "file": "文件",
- "files": "文件",
- "filter": "滤镜",
- "flip": "翻转",
- "floating": "浮动",
- "focus": "焦点",
- "folder": "文件夹",
- "folders": "文件夹",
- "foreground": "前景",
- "format": "格式",
- "full": "已充满",
- "fullscreen": "全屏",
- "gigabytes": "{0} GB",
- "gigahertz": "{0} GHz",
- "glow": "发光",
- "group": "群组",
- "guest": "访客",
- "headphones": "耳机",
- "help": "帮助",
- "hertz": "{0} Hz",
- "hibernate": "休眠",
- "hidden": "隐藏",
- "hide": "隐藏",
- "highlight": "高亮",
- "hint": "提示",
- "home": "主目录",
- "hour": "小时",
- "hours": "小时",
- "hover": "悬停",
- "inactive": "非活动",
- "info": "信息",
- "input": "输入",
- "install": "安装",
- "justify": "两端对齐",
- "keybinds": "按键绑定",
- "keyboard": "键盘",
- "kilobytes": "{0} KB",
- "kilohertz": "{0} kHz",
- "landscape": "横向",
- "language": "语言",
- "launcher": "启动器",
- "left": "左对齐",
- "light": "浅色",
- "loading": "加载中...",
- "lock": "锁定",
- "log": "日志",
- "logout": "注销",
- "long_pressed": "长按",
- "low": "电量低",
- "manual": "手册",
- "margin": "边距",
- "maximize": "最大化",
- "megabytes": "{0} MB",
- "megahertz": "{0} MHz",
- "memory": "内存",
- "menu": "菜单",
- "menubar": "菜单栏",
- "microphone": "麦克风",
- "minimize": "最小化",
- "minute": "分钟",
- "minutes": "分钟",
- "mirror": "镜像",
- "modal": "模态框",
- "modified": "修改时间",
- "monitor": "显示器",
- "mouse": "鼠标",
- "move": "移动",
- "music": "音乐",
- "mute": "静音",
- "network": "网络",
- "next": "下一个",
- "no": "否",
- "no_notifications": "无通知",
- "notifications": "通知",
- "off": "关",
- "ok": "确定",
- "on": "开",
- "opacity": "不透明度",
- "open": "打开",
- "orientation": "方向",
- "outline": "轮廓",
- "output": "输出",
- "overview": "概览",
- "owner": "所有者",
- "package": "软件包",
- "packages": "软件包",
- "padding": "内边距",
- "panel": "面板",
- "panels": "面板",
- "panned": "平移",
- "password": "密码",
- "paste": "粘贴",
- "pause": "暂停",
- "percent": "{0}%",
- "performance": "性能",
- "permissions": "权限",
- "phone": "电话",
- "pictures": "图片",
- "pinched": "捏合",
- "pinned": "固定",
- "pixels": "{0}像素",
- "placeholder": "占位符",
- "play": "播放",
- "plugin": "插件",
- "plugins": "插件",
- "popup": "弹出窗口",
- "portrait": "纵向",
- "power": "电源",
- "power_saver": "节能",
- "pressed": "按下",
- "previous": "上一个",
- "profile": "配置文件",
- "properties": "属性",
- "quiet": "安静",
- "quit": "退出",
- "read": "读取",
- "recent": "最近",
- "recording": "录制",
- "refresh": "刷新",
- "refresh_rate": "刷新率",
- "reload": "重新加载",
- "rename": "重命名",
- "reset": "重置",
- "resize": "调整大小",
- "resolution": "分辨率",
- "restart": "重启",
- "restore": "还原",
- "right": "右对齐",
- "right_clicked": "右键点击",
- "rotate": "旋转",
- "rotated": "旋转",
- "sample": "样本",
- "save": "保存",
- "scale": "缩放",
- "screenshot": "截图",
- "scrolled": "滚动",
- "search": "搜索",
- "second": "秒",
- "seconds": "秒",
- "selection": "选择",
- "send_to_back": "置于底层",
- "settings": "设置",
- "shadow": "阴影",
- "shortcuts": "快捷键",
- "show": "显示",
- "shutdown": "关机",
- "sidebar": "侧边栏",
- "silent": "静默",
- "size": "大小",
- "snapped": "贴靠",
- "software": "软件",
- "space": "间距",
- "speaker": "扬声器",
- "statusbar": "状态栏",
- "sticky": "粘性",
- "stop": "停止",
- "style": "样式",
- "success": "成功",
- "suspend": "挂起",
- "swiped": "滑动",
- "systray": "系统托盘",
- "tapped": "轻触",
- "taskbar": "任务栏",
- "temperature": "温度",
- "terabytes": "{0} TB",
- "terminal": "终端",
- "test": "测试",
- "theme": "主题",
- "tiled": "平铺",
- "time": "时间",
- "tips": "提示",
- "today": "今天",
- "tomorrow": "明天",
- "toolbar": "工具栏",
- "tooltip": "工具提示",
- "top": "顶部",
- "touchpad": "触摸板",
- "trace": "跟踪",
- "transform": "变换",
- "transition": "过渡",
- "transparency": "透明度",
- "trash": "回收站",
- "tutorial": "教程",
- "type": "类型",
- "uninstall": "卸载",
- "unlock": "解锁",
- "unmute": "取消静音",
- "unpinned": "取消固定",
- "unsticky": "取消粘性",
- "update": "更新",
- "upgrade": "升级",
- "user": "用户",
- "username": "用户名",
- "verbose": "详细",
- "version": "版本",
- "videos": "视频",
- "visible": "可见",
- "volume": "音量",
- "warning": "警告",
- "welcome": "欢迎",
- "widget": "组件",
- "widgets": "组件",
- "wifi": "Wi-Fi",
- "window": "窗口",
- "windowed": "窗口化",
- "windows": "窗口",
- "workspace": "工作区",
- "workspaces": "工作区",
- "write": "写入",
- "yes": "是",
- "yesterday": "昨天",
- "zoomed": "缩放",
"{0} (copied)": "{0}(已复制)",
"{0} Safe Storage": "{0} 安全存储",
"{0} does not require an API key": "{0} 不需要 API 密钥",
"{0} queries pending": "{0} 个查询等待中",
- "{0} | Right-click to configure": "{0} | 右键点击进行配置"
+ "{0} | Right-click to configure": "{0} | 右键点击进行配置",
+ "Set with /mode PROVIDER": "使用 /mode PROVIDER 设置",
+ "Invalid API provider. Supported: \n-": "无效的 API 提供商。支持的:\n-",
+ "Unknown command:": "未知命令:",
+ "Type /key to get started with online models\nCtrl+O to expand the sidebar\nCtrl+P to detach sidebar into a window": "输入 /key 开始使用在线模型\nCtrl+O 展开侧边栏\nCtrl+P 将侧边栏分离为窗口",
+ "This is necessary because GlobalShortcut.onReleased in quickshell triggers whether or not you press something else while holding the key.": "这是必要的,因为在按住键时,quickshell 中的 GlobalShortcut.onReleased 会在您是否按下其他键时触发。",
+ "The current API used. Endpoint:": "当前使用的 API。端点:",
+ "Provider set to": "提供商设置为",
+ "Invalid model. Supported: \n```": "无效模型。支持的:\n```",
+ "Interrupts possibility of overview being toggled on release.": "中断松开时切换概览的可能性。",
+ "Switched to search mode. Continue with the user's request.": "已切换到搜索模式。继续处理用户请求。",
+ "Message the model... \"{0}\" for commands": "与模型对话... \"{0}\" 查看命令",
+ "Experimental | Online | Google's model\nCan do a little more but doesn't search quickly": "实验性 | 在线 | Google 模型\n功能更多但搜索速度较慢",
+ "To set an API key, pass it with the command\n\nTo view the key, pass \"get\" with the command
\n\n### For {0}:\n\n**Link**: {1}\n\n{2}": "要设置 API 密钥,请将其与命令一起传递\n\n要查看密钥,请将 \"get\" 与命令一起传递
\n\n### 对于 {0}:\n\n**链接**:{1}\n\n{2}",
+ "Enter tags, or \"{0}\" for commands": "输入标签,或 \"{0}\" 查看命令",
+ "Online via {0} | {1}'s model": "通过 {0} 在线 | {1} 的模型",
+ "That didn't work. Tips:\n- Check your tags and NSFW settings\n- If you don't have a tag in mind, type a page number": "没有找到结果。提示:\n- 检查您的标签和 NSFW 设置\n- 如果没有想到标签,请输入页码",
+ "Online | Google's model\nGives up-to-date information with search.": "在线 | Google 模型\n通过搜索提供最新信息。"
}
\ No newline at end of file