From d852bcff502afa4325f1078a1d2b738f22cfca7a Mon Sep 17 00:00:00 2001 From: yeongpin Date: Tue, 25 Feb 2025 10:46:36 +0800 Subject: [PATCH] feat: Enhance Multilingual Support and System Language Detection - Add automatic system language detection for Windows and Unix-like systems - Update localization files with new translation keys - Improve language handling in various modules - Translate more UI messages to English - Add GitHub link to logo display - Bump version to 1.4.04 --- .env | 4 +-- .gitignore | 5 +++ CHANGELOG.md | 7 ++++ build.bat | 30 ++++++++--------- build.py | 26 +++++++-------- build.sh | 20 ++++++------ cursor_register_manual.py | 54 +++++++++++++++--------------- disable_auto_update.py | 30 ++++++++--------- locales/en.json | 6 +++- locales/zh_cn.json | 6 +++- locales/zh_tw.json | 7 ++-- logo.py | 12 ++++--- main.py | 69 ++++++++++++++++++++++++++++++++++++++- new_signup.py | 16 ++++----- new_tempemail.py | 8 ++--- quit_cursor.py | 20 ++++++------ reset_machine_manual.py | 68 +++++++++++++++++++------------------- 17 files changed, 240 insertions(+), 148 deletions(-) diff --git a/.env b/.env index f44a1bc..d551175 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ -version=1.4.03 -VERSION=1.4.03 +version=1.4.04 +VERSION=1.4.04 diff --git a/.gitignore b/.gitignore index 82438eb..5c78cd5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ cursor_accounts.txt /venv /__pycache__ +dist +build +install.bat +run.bat +temp_account_info.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index e02e194..dfa0b38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log +## v1.4.04 + +1. Change Some Language Info to English | 更改一些語言信息為英文 +2. Add Auto Detect System Language | 增加自動檢測系統語言 +3. Fixed Some Issues | 修復一些問題 + + ## v1.4.03 1. Switch to API-based Registration System | 改用API註冊系統替代瀏覽器操作 diff --git a/build.bat b/build.bat index 0cee642..3671444 100644 --- a/build.bat +++ b/build.bat @@ -2,28 +2,28 @@ chcp 65001 > nul cls -:: 檢查是否以管理員權限運行 +:: Check if running with administrator privileges net session >nul 2>&1 if %errorLevel% == 0 ( - :: 如果是管理員權限,只創建虛擬環境後就降權運行 + :: If running with administrator privileges, create virtual environment and then run with normal user privileges if not exist venv ( echo ℹ️ 正在創建虛擬環境... python -m venv venv ) - :: 降權運行剩餘的步驟 + :: Run remaining steps with normal user privileges echo ℹ️ 以普通用戶權限繼續... powershell -Command "Start-Process -FilePath '%comspec%' -ArgumentList '/c cd /d %cd% && %~f0 run' -Verb RunAs:NO" exit /b ) else ( - :: 檢查是否是第二階段運行 + :: Check if running in second stage if "%1"=="run" ( goto RUN_BUILD ) else ( - :: 如果是普通權限且需要創建虛擬環境,請求管理員權限 + :: If running with normal privileges and creating virtual environment is required, request administrator privileges if not exist venv ( - echo ⚠️ 需要管理員權限來創建虛擬環境 - echo ℹ️ 正在請求管理員權限... + echo ⚠️ Requires administrator privileges to create virtual environment + echo ℹ️ Requesting administrator privileges... powershell -Command "Start-Process -Verb RunAs -FilePath '%comspec%' -ArgumentList '/c cd /d %cd% && %~f0'" exit /b ) else ( @@ -33,30 +33,30 @@ if %errorLevel% == 0 ( ) :RUN_BUILD -echo ℹ️ 啟動虛擬環境... +echo ℹ️ Starting virtual environment... call venv\Scripts\activate.bat if errorlevel 1 ( - echo ❌ 啟動虛擬環境失敗 + echo ❌ Failed to start virtual environment pause exit /b 1 ) -:: 檢查並安裝缺失的依賴 -echo ℹ️ 檢查依賴... +:: Check and install missing dependencies +echo ℹ️ Checking dependencies... for /f "tokens=1" %%i in (requirements.txt) do ( pip show %%i >nul 2>&1 || ( - echo ℹ️ 安裝 %%i... + echo ℹ️ Installing %%i... pip install %%i ) ) -echo ℹ️ 開始構建... +echo ℹ️ Starting build... python build.py if errorlevel 1 ( - echo ❌ 構建失敗 + echo ❌ Build failed pause exit /b 1 ) -echo ✅ 完成! +echo ✅ Completed! pause \ No newline at end of file diff --git a/build.py b/build.py index e0588c3..46e04aa 100644 --- a/build.py +++ b/build.py @@ -8,7 +8,7 @@ import shutil from logo import print_logo from dotenv import load_dotenv -# 忽略特定警告 +# Ignore specific warnings warnings.filterwarnings("ignore", category=SyntaxWarning) class LoadingAnimation: @@ -50,21 +50,21 @@ def simulate_progress(message, duration=1.0, steps=20): progress_bar(i, steps, prefix="Progress:", length=40) def build(): - # 清理屏幕 + # Clean screen os.system("cls" if platform.system().lower() == "windows" else "clear") - # 顯示 logo + # Display logo print_logo() - # 清理 PyInstaller 緩存 - print("\033[93m🧹 清理構建緩存...\033[0m") + # Clean PyInstaller cache + print("\033[93m🧹 Cleaning build cache...\033[0m") if os.path.exists('build'): shutil.rmtree('build') - # 重新加載環境變量以確保獲取最新版本 + # Reload environment variables to ensure getting the latest version load_dotenv(override=True) version = os.getenv('VERSION', '1.0.0') - print(f"\033[93m📦 正在構建版本: v{version}\033[0m") + print(f"\033[93m📦 Building version: v{version}\033[0m") try: simulate_progress("Preparing build environment...", 0.5) @@ -72,7 +72,7 @@ def build(): loading = LoadingAnimation() loading.start("Building in progress") - # 根据系统类型设置输出名称 + # Set output name based on system type system = platform.system().lower() if system == "windows": os_type = "windows" @@ -86,7 +86,7 @@ def build(): output_name = f"CursorFreeVIP_{version}_{os_type}" - # 构建命令 + # Build command build_command = f'pyinstaller --clean --noconfirm build.spec' output_path = os.path.join('dist', f'{output_name}{ext}') @@ -95,16 +95,16 @@ def build(): loading.stop() if os.path.exists(output_path): - print(f"\n\033[92m✅ 構建完成!") - print(f"📦 可執行文件位於: {output_path}\033[0m") + print(f"\n\033[92m✅ Build completed!") + print(f"📦 Executable file located: {output_path}\033[0m") else: - print("\n\033[91m❌ 構建失敗:未找到輸出文件\033[0m") + print("\n\033[91m❌ Build failed: Output file not found\033[0m") return False except Exception as e: if loading: loading.stop() - print(f"\n\033[91m❌ 構建過程出錯: {str(e)}\033[0m") + print(f"\n\033[91m❌ Build process error: {str(e)}\033[0m") return False return True diff --git a/build.sh b/build.sh index 62a6e18..8a7b5e2 100644 --- a/build.sh +++ b/build.sh @@ -8,7 +8,7 @@ NC='\033[0m' # No Color # 检查并安装必要的依赖 check_dependencies() { - echo -e "${YELLOW}检查系统依赖...${NC}" + echo -e "${YELLOW}Checking system dependencies...${NC}" # 检查是否为 Ubuntu/Debian if [ -f /etc/debian_version ]; then @@ -16,42 +16,42 @@ check_dependencies() { PACKAGES="python3 python3-pip python3-venv" for pkg in $PACKAGES; do if ! dpkg -l | grep -q "^ii $pkg "; then - echo -e "${YELLOW}安装 $pkg...${NC}" + echo -e "${YELLOW}Installing $pkg...${NC}" sudo apt-get update sudo apt-get install -y $pkg fi done else - echo -e "${RED}不支持的系统,请手动安装 python3, pip3 和 python3-venv${NC}" + echo -e "${RED}Unsupported system, please install python3, pip3 and python3-venv manually${NC}" exit 1 fi } # 创建并激活虚拟环境 setup_venv() { - echo -e "${GREEN}正在创建虚拟环境...${NC}" + echo -e "${GREEN}Creating virtual environment...${NC}" python3 -m venv venv - echo -e "${GREEN}启动虚拟环境...${NC}" + echo -e "${GREEN}Starting virtual environment...${NC}" . ./venv/bin/activate || source ./venv/bin/activate } # 安装依赖 install_dependencies() { - echo -e "${GREEN}安装依赖...${NC}" + echo -e "${GREEN}Installing dependencies...${NC}" python3 -m pip install --upgrade pip pip3 install -r requirements.txt } # 构建程序 build_program() { - echo -e "${GREEN}开始构建...${NC}" + echo -e "${GREEN}Starting build...${NC}" python3 build.py } # 清理 cleanup() { - echo -e "${GREEN}清理虚拟环境...${NC}" + echo -e "${GREEN}Cleaning virtual environment...${NC}" deactivate 2>/dev/null || true rm -rf venv } @@ -73,8 +73,8 @@ main() { # 清理 cleanup - echo -e "${GREEN}完成!${NC}" - echo "按任意键退出..." + echo -e "${GREEN}Completed!${NC}" + echo "Press any key to exit..." # 使用兼容的方式读取输入 if [ "$(uname)" = "Linux" ]; then read dummy diff --git a/cursor_register_manual.py b/cursor_register_manual.py index 6a6d3d3..9a3029d 100644 --- a/cursor_register_manual.py +++ b/cursor_register_manual.py @@ -10,10 +10,10 @@ from reset_machine_manual import MachineIDResetter os.environ["PYTHONVERBOSE"] = "0" os.environ["PYINSTALLER_VERBOSE"] = "0" -# 初始化colorama +# Initialize colorama init() -# 定义emoji常量 +# Define emoji constants EMOJI = { 'START': '🚀', 'FORM': '📝', @@ -33,7 +33,7 @@ EMOJI = { class CursorRegistration: def __init__(self, translator=None): self.translator = translator - # 设置为显示模式 + # Set to display mode os.environ['BROWSER_HEADLESS'] = 'False' self.browser_manager = BrowserManager() self.browser = None @@ -44,7 +44,7 @@ class CursorRegistration: self.signup_tab = None self.email_tab = None - # 账号信息 + # Account information self.password = self._generate_password() self.first_name = self._generate_name() self.last_name = self._generate_name() @@ -61,9 +61,9 @@ class CursorRegistration: return first_letter + rest_letters def setup_email(self): - """设置邮箱""" + """Setup Email""" try: - print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.manual_email_input') if self.translator else '请输入邮箱地址:'}") + print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.manual_email_input') if self.translator else 'Please enter your email address:'}") self.email_address = input().strip() if '@' not in self.email_address: @@ -77,9 +77,9 @@ class CursorRegistration: return False def get_verification_code(self): - """手动获取验证码""" + """Manually Get Verification Code""" try: - print(f"{Fore.CYAN}{EMOJI['CODE']} {self.translator.get('register.manual_code_input') if self.translator else '请输入验证码:'}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['CODE']} {self.translator.get('register.manual_code_input') if self.translator else 'Please enter the verification code:'}") code = input().strip() if not code.isdigit() or len(code) != 6: @@ -93,31 +93,31 @@ class CursorRegistration: return None def register_cursor(self): - """注册 Cursor""" + """Register Cursor""" browser_tab = None try: print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.register_start')}...{Style.RESET_ALL}") - # 直接使用 new_signup.py 进行注册 + # Use new_signup.py directly for registration from new_signup import main as new_signup_main - # 执行新的注册流程,传入 translator + # Execute new registration process, passing translator result, browser_tab = new_signup_main( email=self.email_address, password=self.password, first_name=self.first_name, last_name=self.last_name, - email_tab=None, # 不需要邮箱标签页 - controller=self, # 传入 self 而不是 self.controller + email_tab=None, # No email tab needed + controller=self, # Pass self instead of self.controller translator=self.translator ) if result: - # 使用返回的浏览器实例获取账户信息 - self.signup_tab = browser_tab # 保存浏览器实例 + # Use the returned browser instance to get account information + self.signup_tab = browser_tab # Save browser instance success = self._get_account_info() - # 获取信息后关闭浏览器 + # Close browser after getting information if browser_tab: try: browser_tab.quit() @@ -132,7 +132,7 @@ class CursorRegistration: print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.register_process_error', error=str(e))}{Style.RESET_ALL}") return False finally: - # 确保在任何情况下都关闭浏览器 + # Ensure browser is closed in any case if browser_tab: try: browser_tab.quit() @@ -140,7 +140,7 @@ class CursorRegistration: pass def _get_account_info(self): - """获取账户信息和 Token""" + """Get Account Information and Token""" try: self.signup_tab.get(self.settings_url) time.sleep(2) @@ -191,22 +191,22 @@ class CursorRegistration: return False def _save_account_info(self, token, total_usage): - """保存账户信息到文件""" + """Save Account Information to File""" try: - # 先更新认证信息 + # Update authentication information first print(f"{Fore.CYAN}{EMOJI['KEY']} {self.translator.get('register.update_cursor_auth_info')}...{Style.RESET_ALL}") if self.update_cursor_auth(email=self.email_address, access_token=token, refresh_token=token): print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.cursor_auth_info_updated')}...{Style.RESET_ALL}") else: print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.cursor_auth_info_update_failed')}...{Style.RESET_ALL}") - # 重置机器ID + # Reset machine ID print(f"{Fore.CYAN}{EMOJI['UPDATE']} {self.translator.get('register.reset_machine_id')}...{Style.RESET_ALL}") - resetter = MachineIDResetter(self.translator) # 创建实例时传入translator - if not resetter.reset_machine_ids(): # 直接调用reset_machine_ids方法 + resetter = MachineIDResetter(self.translator) # Create instance with translator + if not resetter.reset_machine_ids(): # Call reset_machine_ids method directly raise Exception("Failed to reset machine ID") - # 保存账户信息到文件 + # Save account information to file with open('cursor_accounts.txt', 'a', encoding='utf-8') as f: f.write(f"\n{'='*50}\n") f.write(f"Email: {self.email_address}\n") @@ -223,7 +223,7 @@ class CursorRegistration: return False def start(self): - """启动注册流程""" + """Start Registration Process""" try: if self.setup_email(): if self.register_cursor(): @@ -231,7 +231,7 @@ class CursorRegistration: return True return False finally: - # 关闭邮箱标签页 + # Close email tab if hasattr(self, 'temp_email'): try: self.temp_email.close() @@ -239,7 +239,7 @@ class CursorRegistration: pass def update_cursor_auth(self, email=None, access_token=None, refresh_token=None): - """更新Cursor的认证信息的便捷函数""" + """Convenient function to update Cursor authentication information""" auth_manager = CursorAuth(translator=self.translator) return auth_manager.update_auth(email, access_token, refresh_token) diff --git a/disable_auto_update.py b/disable_auto_update.py index 7f46ae4..93cbff6 100644 --- a/disable_auto_update.py +++ b/disable_auto_update.py @@ -5,10 +5,10 @@ import shutil from colorama import Fore, Style, init import subprocess -# 初始化 colorama +# Initialize colorama init() -# 定义 emoji 常量 +# Define emoji constants EMOJI = { "PROCESS": "🔄", "SUCCESS": "✅", @@ -31,7 +31,7 @@ class AutoUpdateDisabler: } def _kill_cursor_processes(self): - """结束所有 Cursor 进程""" + """End all Cursor processes""" try: print(f"{Fore.CYAN}{EMOJI['PROCESS']} {self.translator.get('update.killing_processes') if self.translator else '正在结束 Cursor 进程...'}{Style.RESET_ALL}") @@ -48,7 +48,7 @@ class AutoUpdateDisabler: return False def _remove_updater_directory(self): - """删除更新程序目录""" + """Delete updater directory""" try: updater_path = self.updater_paths.get(self.system) if not updater_path: @@ -70,7 +70,7 @@ class AutoUpdateDisabler: return False def _create_blocking_file(self): - """创建阻止文件""" + """Create blocking file""" try: updater_path = self.updater_paths.get(self.system) if not updater_path: @@ -78,14 +78,14 @@ class AutoUpdateDisabler: print(f"{Fore.CYAN}{EMOJI['FILE']} {self.translator.get('update.creating_block_file') if self.translator else '正在创建阻止文件...'}{Style.RESET_ALL}") - # 创建空文件 + # Create empty file open(updater_path, 'w').close() - # 设置只读属性 + # Set read-only attribute if self.system == "Windows": os.system(f'attrib +r "{updater_path}"') else: - os.chmod(updater_path, 0o444) # 设置为只读 + os.chmod(updater_path, 0o444) # Set to read-only print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('update.block_file_created') if self.translator else '阻止文件已创建'}{Style.RESET_ALL}") return True @@ -95,19 +95,19 @@ class AutoUpdateDisabler: return False def disable_auto_update(self): - """禁用自动更新""" + """Disable auto update""" try: print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('update.start_disable') if self.translator else '开始禁用自动更新...'}{Style.RESET_ALL}") - # 1. 结束进程 + # 1. End processes if not self._kill_cursor_processes(): return False - # 2. 删除目录 + # 2. Delete directory if not self._remove_updater_directory(): return False - # 3. 创建阻止文件 + # 3. Create blocking file if not self._create_blocking_file(): return False @@ -119,16 +119,16 @@ class AutoUpdateDisabler: return False def run(translator=None): - """便捷函数,用于直接调用禁用功能""" + """Convenient function for directly calling the disable function""" print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}") - print(f"{Fore.CYAN}{EMOJI['STOP']} {translator.get('update.title') if translator else '禁用 Cursor 自动更新'}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['STOP']} {translator.get('update.title') if translator else 'Disable Cursor Auto Update'}{Style.RESET_ALL}") print(f"{Fore.CYAN}{'='*50}{Style.RESET_ALL}") disabler = AutoUpdateDisabler(translator) disabler.disable_auto_update() print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}") - input(f"{EMOJI['INFO']} {translator.get('update.press_enter') if translator else '按回车键继续...'}") + input(f"{EMOJI['INFO']} {translator.get('update.press_enter') if translator else 'Press Enter to Continue...'}") if __name__ == "__main__": from main import translator as main_translator diff --git a/locales/en.json b/locales/en.json index e0f8905..94078d6 100644 --- a/locales/en.json +++ b/locales/en.json @@ -64,7 +64,11 @@ "patch_completed": "Patching getMachineId Completed", "patch_failed": "Patching getMachineId Failed: {error}", "version_check_passed": "Cursor Version Check Passed", - "file_modified": "File Modified" + "file_modified": "File Modified", + "version_less_than_0_45": "Cursor Version < 0.45.0, Skip Patching getMachineId", + "detecting_version": "Detecting Cursor Version", + "patching_getmachineid": "Patching getMachineId", + "version_greater_than_0_45": "Cursor Version >= 0.45.0, Patching getMachineId" }, "register": { "title": "Cursor Registration Tool", diff --git a/locales/zh_cn.json b/locales/zh_cn.json index 422356a..fce485b 100644 --- a/locales/zh_cn.json +++ b/locales/zh_cn.json @@ -64,7 +64,11 @@ "patch_completed": "getMachineId修补完成", "patch_failed": "getMachineId修补失败: {error}", "version_check_passed": "Cursor版本检查通过", - "file_modified": "文件已修改" + "file_modified": "文件已修改", + "version_less_than_0_45": "Cursor版本 < 0.45.0,跳过getMachineId修补", + "detecting_version": "检测Cursor版本", + "patching_getmachineid": "修补getMachineId", + "version_greater_than_0_45": "Cursor版本 >= 0.45.0,修补getMachineId" }, "register": { "title": "Cursor 注册工具", diff --git a/locales/zh_tw.json b/locales/zh_tw.json index 5fc0883..8a79b1c 100644 --- a/locales/zh_tw.json +++ b/locales/zh_tw.json @@ -64,7 +64,11 @@ "patch_completed": "getMachineId修補完成", "patch_failed": "getMachineId修補失敗: {error}", "version_check_passed": "Cursor版本檢查通過", - "file_modified": "文件已修改" + "file_modified": "文件已修改", + "version_less_than_0_45": "Cursor版本 < 0.45.0,跳过getMachineId修补", + "detecting_version": "檢測Cursor版本", + "patching_getmachineid": "修補getMachineId", + "version_greater_than_0_45": "Cursor版本 >= 0.45.0,修補getMachineId" }, "register": { "title": "Cursor 註冊工具", @@ -92,7 +96,6 @@ "no_turnstile": "未檢測到 Turnstile 驗證", "turnstile_passed": "驗證通過", "verification_start": "開始獲取驗證碼", - "waiting_for_verification_code": "等待驗證碼", "verification_code_filled": "驗證碼填寫完成", "login_success_and_jump_to_settings_page": "成功登錄並跳轉到設置頁面", "detect_login_page": "檢測到登錄頁面,開始登錄...", diff --git a/logo.py b/logo.py index 648d7f2..9c25a5b 100644 --- a/logo.py +++ b/logo.py @@ -2,17 +2,17 @@ from colorama import Fore, Style, init from dotenv import load_dotenv import os -# 獲取當前腳本所在目錄 +# Get the current script directory current_dir = os.path.dirname(os.path.abspath(__file__)) -# 構建.env文件的完整路徑 +# Build the full path to the .env file env_path = os.path.join(current_dir, '.env') -# 加載環境變量,指定.env文件路徑 +# Load environment variables, specifying the .env file path load_dotenv(env_path) -# 獲取版本號,如果未找到則使用默認值 +# Get the version number, using the default value if not found version = os.getenv('VERSION', '1.0.0') -# 初始化 colorama +# Initialize colorama init() CURSOR_LOGO = f""" @@ -27,6 +27,8 @@ CURSOR_LOGO = f""" Pro Version Activator v{version} {Fore.GREEN} Author: Pin Studios | yeongpin + + Github: https://github.com/yeongpin/cursor-free-vip {Fore.RED} Press 5 to change language | 按下 5 键切换语言 {Style.RESET_ALL} diff --git a/main.py b/main.py index a2c8b31..3048e4e 100644 --- a/main.py +++ b/main.py @@ -5,6 +5,10 @@ import sys import json from logo import print_logo from colorama import Fore, Style, init +import ctypes +from ctypes import windll +import locale +import platform # 初始化colorama init() @@ -25,11 +29,74 @@ EMOJI = { class Translator: def __init__(self): - self.current_language = 'en' # Default language + self.current_language = self.detect_system_language() # Changed to use system language self.translations = {} self.fallback_language = 'en' # Fallback language if translation is missing self.load_translations() + def detect_system_language(self): + """Detect system language and return corresponding language code""" + try: + system = platform.system() + + if system == 'Windows': + return self._detect_windows_language() + else: + return self._detect_unix_language() + + except Exception as e: + print(f"{Fore.YELLOW}{EMOJI['INFO']} Failed to detect system language: {e}{Style.RESET_ALL}") + return 'en' + + def _detect_windows_language(self): + """Detect language on Windows systems""" + try: + # Get the keyboard layout + user32 = ctypes.WinDLL('user32', use_last_error=True) + hwnd = user32.GetForegroundWindow() + threadid = user32.GetWindowThreadProcessId(hwnd, 0) + layout_id = user32.GetKeyboardLayout(threadid) & 0xFFFF + + # Map language ID to our language codes + language_map = { + 0x0409: 'en', # English + 0x0404: 'zh_tw', # Traditional Chinese + 0x0804: 'zh_cn', # Simplified Chinese + } + + return language_map.get(layout_id, 'en') + except: + return self._detect_unix_language() + + def _detect_unix_language(self): + """Detect language on Unix-like systems (Linux, macOS)""" + try: + # Get the system locale + system_locale = locale.getdefaultlocale()[0] + if not system_locale: + return 'en' + + system_locale = system_locale.lower() + + # Map locale to our language codes + if system_locale.startswith('zh_tw') or system_locale.startswith('zh_hk'): + return 'zh_tw' + elif system_locale.startswith('zh_cn'): + return 'zh_cn' + elif system_locale.startswith('en'): + return 'en' + + # Try to get language from LANG environment variable as fallback + env_lang = os.getenv('LANG', '').lower() + if 'tw' in env_lang or 'hk' in env_lang: + return 'zh_tw' + elif 'cn' in env_lang: + return 'zh_cn' + + return 'en' + except: + return 'en' + def load_translations(self): """Load all available translations""" try: diff --git a/new_signup.py b/new_signup.py index f17969d..27b2561 100644 --- a/new_signup.py +++ b/new_signup.py @@ -243,7 +243,7 @@ def fill_password(page, password, translator=None): if translator: print(f"{Fore.CYAN}🔑 {translator.get('register.setting_password')}{Style.RESET_ALL}") else: - print("\n正在设置密码...") + print(f"\n{translator.get('register.setting_password')}") password_input = page.ele("@name=password") if password_input: password_input.input(password) @@ -257,14 +257,14 @@ def fill_password(page, password, translator=None): if translator: print(f"{Fore.GREEN}✅ {translator.get('register.password_success')}{Style.RESET_ALL}") else: - print(f"密码设置完成: {password}") + print(f"{translator.get('register.password_success')}: {password}") return True except Exception as e: if translator: print(f"{Fore.RED}❌ {translator.get('register.password_error', error=str(e))}{Style.RESET_ALL}") else: - print(f"设置密码时出错: {e}") + print(f"{translator.get('register.password_error')}: {e}") return False def handle_verification_code(browser_tab, email_tab, controller, email, password, translator=None): @@ -273,7 +273,7 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password if translator: print(f"\n{Fore.CYAN}{translator.get('register.waiting_for_verification_code')}{Style.RESET_ALL}") else: - print("\n等待并获取验证码...") + print(f"\n{translator.get('register.waiting_for_verification_code')}") # 检查是否使用手动输入验证码 if hasattr(controller, 'get_verification_code') and email_tab is None: # 手动模式 @@ -284,7 +284,7 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password browser_tab.ele(f"@data-index={i}").input(digit) time.sleep(random.uniform(0.1, 0.3)) - print("验证码填写完成") + print(f"{translator.get('register.verification_success')}") time.sleep(3) # 处理最后一次 Turnstile 验证 @@ -292,11 +292,11 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password if translator: print(f"{translator.get('register.verification_success')}") else: - print("最后一次验证通过!") + print(f"{translator.get('register.verification_success')}") time.sleep(2) # 访问设置页面 - print("访问设置页面...") + print(f"{translator.get('register.visiting_url')}: https://www.cursor.com/settings") browser_tab.get("https://www.cursor.com/settings") time.sleep(3) # 等待页面加载 return True, browser_tab @@ -305,7 +305,7 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password # 自动获取验证码逻辑 elif email_tab: - print("等待验证码邮件...") + print(f"{translator.get('register.waiting_for_verification_code')}") time.sleep(5) # 等待验证码邮件 # 使用已有的 email_tab 刷新邮箱 diff --git a/new_tempemail.py b/new_tempemail.py index 25c5b05..8f2a9f2 100644 --- a/new_tempemail.py +++ b/new_tempemail.py @@ -41,11 +41,11 @@ class NewTempEmail: # 获取可用域名列表 domains_response = requests.get(f"{self.api_url}/domains") if domains_response.status_code != 200: - raise Exception("Failed to get available domains") + raise Exception(f"{self.translator.get('email.failed_to_get_available_domains')}") domains = domains_response.json()["hydra:member"] if not domains: - raise Exception("No available domains") + raise Exception(f"{self.translator.get('email.no_available_domains')}") # 生成随机用户名和密码 username, password = self._generate_credentials() @@ -60,7 +60,7 @@ class NewTempEmail: create_response = requests.post(f"{self.api_url}/accounts", json=account_data) if create_response.status_code != 201: - raise Exception("Failed to create account") + raise Exception(f"{self.translator.get('email.failed_to_create_account')}") # 获取访问令牌 token_data = { @@ -70,7 +70,7 @@ class NewTempEmail: token_response = requests.post(f"{self.api_url}/token", json=token_data) if token_response.status_code != 200: - raise Exception("Failed to get access token") + raise Exception(f"{self.translator.get('email.failed_to_get_access_token')}") self.token = token_response.json()["token"] self.email = email diff --git a/quit_cursor.py b/quit_cursor.py index 40b54f5..117d86c 100644 --- a/quit_cursor.py +++ b/quit_cursor.py @@ -4,10 +4,10 @@ from colorama import Fore, Style, init import sys import os -# 初始化colorama +# Initialize colorama init() -# 定义emoji常量 +# Define emoji constants EMOJI = { "PROCESS": "⚙️", "SUCCESS": "✅", @@ -19,15 +19,15 @@ EMOJI = { class CursorQuitter: def __init__(self, timeout=5, translator=None): self.timeout = timeout - self.translator = translator # 使用传入的翻译器 + self.translator = translator # Use the passed translator def quit_cursor(self): - """温和地关闭 Cursor 进程""" + """Gently close Cursor processes""" try: print(f"{Fore.CYAN}{EMOJI['PROCESS']} {self.translator.get('quit_cursor.start')}...{Style.RESET_ALL}") cursor_processes = [] - # 收集所有 Cursor 进程 + # Collect all Cursor processes for proc in psutil.process_iter(['pid', 'name']): try: if proc.info['name'].lower() in ['cursor.exe', 'cursor']: @@ -39,7 +39,7 @@ class CursorQuitter: print(f"{Fore.GREEN}{EMOJI['INFO']} {self.translator.get('quit_cursor.no_process')}{Style.RESET_ALL}") return True - # 温和地请求进程终止 + # Gently request processes to terminate for proc in cursor_processes: try: if proc.is_running(): @@ -48,7 +48,7 @@ class CursorQuitter: except (psutil.NoSuchProcess, psutil.AccessDenied): continue - # 等待进程自然终止 + # Wait for processes to terminate naturally print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('quit_cursor.waiting')}...{Style.RESET_ALL}") start_time = time.time() while time.time() - start_time < self.timeout: @@ -66,7 +66,7 @@ class CursorQuitter: time.sleep(0.5) - # 如果超时后仍有进程在运行 + # If processes are still running after timeout if still_running: process_list = ", ".join([str(p.pid) for p in still_running]) print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('quit_cursor.timeout', pids=process_list)}{Style.RESET_ALL}") @@ -79,11 +79,11 @@ class CursorQuitter: return False def quit_cursor(translator=None, timeout=5): - """便捷函数,用于直接调用退出功能""" + """Convenient function for directly calling the quit function""" quitter = CursorQuitter(timeout, translator) return quitter.quit_cursor() if __name__ == "__main__": - # 如果直接运行,使用默认翻译器 + # If run directly, use the default translator from main import translator as main_translator quit_cursor(main_translator) \ No newline at end of file diff --git a/reset_machine_manual.py b/reset_machine_manual.py index 791ac31..420cae5 100644 --- a/reset_machine_manual.py +++ b/reset_machine_manual.py @@ -11,10 +11,10 @@ import tempfile from colorama import Fore, Style, init from typing import Tuple -# 初始化colorama +# Initialize colorama init() -# 定义emoji常量 +# Define emoji constants EMOJI = { "FILE": "📄", "BACKUP": "💾", @@ -25,7 +25,7 @@ EMOJI = { } def get_cursor_paths(translator=None) -> Tuple[str, str]: - """根据不同操作系统获取 Cursor 相关路径""" + """ Get Cursor related paths""" system = platform.system() paths_map = { @@ -65,7 +65,7 @@ def get_cursor_paths(translator=None) -> Tuple[str, str]: ) def version_check(version: str, min_version: str = "", max_version: str = "", translator=None) -> bool: - """版本号检查""" + """Version number check""" version_pattern = r"^\d+\.\d+\.\d+$" try: if not re.match(version_pattern, version): @@ -92,7 +92,7 @@ def version_check(version: str, min_version: str = "", max_version: str = "", tr return False def check_cursor_version(translator) -> bool: - """检查 Cursor 版本""" + """Check Cursor version""" try: pkg_path, _ = get_cursor_paths(translator) with open(pkg_path, "r", encoding="utf-8") as f: @@ -103,7 +103,7 @@ def check_cursor_version(translator) -> bool: return False def modify_main_js(main_path: str, translator) -> bool: - """修改 main.js 文件""" + """Modify main.js file""" try: original_stat = os.stat(main_path) original_mode = original_stat.st_mode @@ -142,14 +142,14 @@ def modify_main_js(main_path: str, translator) -> bool: return False def patch_cursor_get_machine_id(translator) -> bool: - """修补 Cursor getMachineId 函数""" + """Patch Cursor getMachineId function""" try: print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('reset.start_patching')}...{Style.RESET_ALL}") - # 获取路径 + # Get paths pkg_path, main_path = get_cursor_paths(translator) - # 检查文件权限 + # Check file permissions for file_path in [pkg_path, main_path]: if not os.path.isfile(file_path): print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.file_not_found', path=file_path)}{Style.RESET_ALL}") @@ -158,7 +158,7 @@ def patch_cursor_get_machine_id(translator) -> bool: print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.no_write_permission', path=file_path)}{Style.RESET_ALL}") return False - # 获取版本号 + # Get version number try: with open(pkg_path, "r", encoding="utf-8") as f: version = json.load(f)["version"] @@ -167,20 +167,20 @@ def patch_cursor_get_machine_id(translator) -> bool: print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.read_version_failed', error=str(e))}{Style.RESET_ALL}") return False - # 检查版本 + # Check version if not version_check(version, min_version="0.45.0", translator=translator): print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.version_not_supported')}{Style.RESET_ALL}") return False print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('reset.version_check_passed')}{Style.RESET_ALL}") - # 备份文件 + # Backup file backup_path = main_path + ".bak" if not os.path.exists(backup_path): shutil.copy2(main_path, backup_path) print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('reset.backup_created', path=backup_path)}{Style.RESET_ALL}") - # 修改文件 + # Modify file if not modify_main_js(main_path, translator): return False @@ -195,7 +195,7 @@ class MachineIDResetter: def __init__(self, translator=None): self.translator = translator - # 判断操作系统 + # Check operating system if sys.platform == "win32": # Windows appdata = os.getenv("APPDATA") if appdata is None: @@ -224,17 +224,17 @@ class MachineIDResetter: raise NotImplementedError(f"Not Supported OS: {sys.platform}") def generate_new_ids(self): - """生成新的机器ID""" - # 生成新的UUID + """Generate new machine ID""" + # Generate new UUID dev_device_id = str(uuid.uuid4()) - # 生成新的machineId (64个字符的十六进制) + # Generate new machineId (64 characters of hexadecimal) machine_id = hashlib.sha256(os.urandom(32)).hexdigest() - # 生成新的macMachineId (128个字符的十六进制) + # Generate new macMachineId (128 characters of hexadecimal) mac_machine_id = hashlib.sha512(os.urandom(64)).hexdigest() - # 生成新的sqmId + # Generate new sqmId sqm_id = "{" + str(uuid.uuid4()).upper() + "}" return { @@ -242,11 +242,11 @@ class MachineIDResetter: "telemetry.macMachineId": mac_machine_id, "telemetry.machineId": machine_id, "telemetry.sqmId": sqm_id, - "storage.serviceMachineId": dev_device_id, # 添加 storage.serviceMachineId + "storage.serviceMachineId": dev_device_id, # Add storage.serviceMachineId } def update_sqlite_db(self, new_ids): - """更新 SQLite 数据库中的机器ID""" + """Update machine ID in SQLite database""" try: print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('reset.updating_sqlite')}...{Style.RESET_ALL}") @@ -281,7 +281,7 @@ class MachineIDResetter: return False def update_system_ids(self, new_ids): - """更新系统级别的ID""" + """Update system-level IDs""" try: print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('reset.updating_system_ids')}...{Style.RESET_ALL}") @@ -297,7 +297,7 @@ class MachineIDResetter: return False def _update_windows_machine_guid(self): - """更新Windows MachineGuid""" + """Update Windows MachineGuid""" try: import winreg key = winreg.OpenKey( @@ -318,11 +318,11 @@ class MachineIDResetter: raise def _update_macos_platform_uuid(self, new_ids): - """更新macOS Platform UUID""" + """Update macOS Platform UUID""" try: uuid_file = "/var/root/Library/Preferences/SystemConfiguration/com.apple.platform.uuid.plist" if os.path.exists(uuid_file): - # 使用sudo来执行plutil命令 + # Use sudo to execute plutil command cmd = f'sudo plutil -replace "UUID" -string "{new_ids["telemetry.macMachineId"]}" "{uuid_file}"' result = os.system(cmd) if result == 0: @@ -334,7 +334,7 @@ class MachineIDResetter: raise def reset_machine_ids(self): - """重置机器ID并备份原文件""" + """Reset machine ID and backup original file""" try: print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('reset.checking')}...{Style.RESET_ALL}") @@ -360,26 +360,26 @@ class MachineIDResetter: print(f"{Fore.CYAN}{EMOJI['RESET']} {self.translator.get('reset.generating')}...{Style.RESET_ALL}") new_ids = self.generate_new_ids() - # 更新配置文件 + # Update configuration file config.update(new_ids) print(f"{Fore.CYAN}{EMOJI['FILE']} {self.translator.get('reset.saving_json')}...{Style.RESET_ALL}") with open(self.db_path, "w", encoding="utf-8") as f: json.dump(config, f, indent=4) - # 更新SQLite数据库 + # Update SQLite database self.update_sqlite_db(new_ids) - # 更新系统ID + # Update system IDs self.update_system_ids(new_ids) - # 检查 Cursor 版本并执行相应的操作 + # Check Cursor version and perform corresponding actions greater_than_0_45 = check_cursor_version(self.translator) if greater_than_0_45: - print(f"{Fore.CYAN}{EMOJI['INFO']} 检测到 Cursor 版本 >= 0.45.0,正在修补 getMachineId...{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('reset.detecting_version')} >= 0.45.0,{self.translator.get('reset.patching_getmachineid')}{Style.RESET_ALL}") patch_cursor_get_machine_id(self.translator) else: - print(f"{Fore.YELLOW}{EMOJI['INFO']} Cursor 版本 < 0.45.0,跳过 getMachineId 修补{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('reset.version_less_than_0_45')}{Style.RESET_ALL}") print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.success')}{Style.RESET_ALL}") print(f"\n{Fore.CYAN}{self.translator.get('reset.new_id')}:{Style.RESET_ALL}") @@ -397,12 +397,12 @@ class MachineIDResetter: return False def run(translator=None): - """便捷函数,用于直接调用重置功能""" + """Convenient function for directly calling the reset function""" print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}") print(f"{Fore.CYAN}{EMOJI['RESET']} {translator.get('reset.title')}{Style.RESET_ALL}") print(f"{Fore.CYAN}{'='*50}{Style.RESET_ALL}") - resetter = MachineIDResetter(translator) # 正確傳遞 translator + resetter = MachineIDResetter(translator) # Correctly pass translator resetter.reset_machine_ids() print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")