From 63e4e72ec7e9bc8bd69f8e08eedcdf109a740613 Mon Sep 17 00:00:00 2001 From: TranMC Date: Wed, 23 Apr 2025 10:57:50 +0700 Subject: [PATCH 1/6] Add language config saved --- config.py | 8 ++- main.py | 176 ++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 165 insertions(+), 19 deletions(-) diff --git a/config.py b/config.py index 38cc332..1d59a21 100644 --- a/config.py +++ b/config.py @@ -105,6 +105,12 @@ def setup_config(translator=None): 'Token': { 'refresh_server': 'https://token.cursorpro.com.cn', 'enable_refresh': True + }, + 'Language': { + 'current_language': '', # Set by local system detection if empty + 'fallback_language': 'en', + 'auto_update_languages': 'True', + 'language_cache_dir': os.path.join(config_dir, "language_cache") } } @@ -364,4 +370,4 @@ def get_config(translator=None): global _config_cache if _config_cache is None: _config_cache = setup_config(translator) - return _config_cache \ No newline at end of file + return _config_cache \ No newline at end of file diff --git a/main.py b/main.py index e42698f..f2b6465 100644 --- a/main.py +++ b/main.py @@ -12,6 +12,7 @@ import subprocess from config import get_config, force_update_config import shutil import re +from utils import get_user_documents_path # Only import windll on Windows systems if platform.system() == 'Windows': @@ -79,8 +80,37 @@ def run_as_admin(): class Translator: def __init__(self): self.translations = {} - self.current_language = self.detect_system_language() # Use correct method name - self.fallback_language = 'en' # Fallback language if translation is missing + self.config = get_config() + + # Create language cache directory if it doesn't exist + if self.config and self.config.has_section('Language'): + self.language_cache_dir = self.config.get('Language', 'language_cache_dir') + os.makedirs(self.language_cache_dir, exist_ok=True) + else: + self.language_cache_dir = None + + # Set fallback language from config if available + self.fallback_language = 'en' + if self.config and self.config.has_section('Language') and self.config.has_option('Language', 'fallback_language'): + self.fallback_language = self.config.get('Language', 'fallback_language') + + # Load saved language from config if available, otherwise detect system language + if self.config and self.config.has_section('Language') and self.config.has_option('Language', 'current_language'): + saved_language = self.config.get('Language', 'current_language') + if saved_language and saved_language.strip(): + self.current_language = saved_language + else: + self.current_language = self.detect_system_language() + # Save detected language to config + if self.config.has_section('Language'): + self.config.set('Language', 'current_language', self.current_language) + config_dir = os.path.join(get_user_documents_path(), ".cursor-free-vip") + config_file = os.path.join(config_dir, "config.ini") + with open(config_file, 'w', encoding='utf-8') as f: + self.config.write(f) + else: + self.current_language = self.detect_system_language() + self.load_translations() def detect_system_language(self): @@ -195,28 +225,120 @@ class Translator: except: return 'en' - def load_translations(self): - """Load all available translations""" + def download_language_file(self, lang_code): + """Download language file from GitHub and save to cache""" try: + if not self.language_cache_dir: + print(f"{Fore.RED}{EMOJI['ERROR']} Language cache directory not configured{Style.RESET_ALL}") + return False + + # Create the cache directory if it doesn't exist + os.makedirs(self.language_cache_dir, exist_ok=True) + + # GitHub raw content URL for language file + github_url = f"https://raw.githubusercontent.com/yeongpin/cursor-free-vip/main/locales/{lang_code}.json" + + print(f"{Fore.CYAN}{EMOJI['INFO']} Downloading language file: {lang_code}.json...{Style.RESET_ALL}") + + # Set up proper headers for GitHub API + headers = { + 'Accept': 'application/vnd.github.v3.raw', + 'User-Agent': 'Cursor-Free-VIP-App' + } + + # Request the file with timeout + response = requests.get(github_url, headers=headers, timeout=10) + + # Check if successful + if response.status_code == 200: + # Save the content to the cache file + cache_file_path = os.path.join(self.language_cache_dir, f"{lang_code}.json") + with open(cache_file_path, 'wb') as f: + f.write(response.content) + + # Load the data into translations dictionary + try: + self.translations[lang_code] = json.loads(response.content) + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Successfully downloaded and loaded: {lang_code}.json{Style.RESET_ALL}") + return True + except json.JSONDecodeError: + print(f"{Fore.RED}{EMOJI['ERROR']} Downloaded file is not valid JSON: {lang_code}.json{Style.RESET_ALL}") + return False + else: + print(f"{Fore.RED}{EMOJI['ERROR']} Failed to download language file: {lang_code}.json (Status code: {response.status_code}){Style.RESET_ALL}") + return False + + except Exception as e: + print(f"{Fore.RED}{EMOJI['ERROR']} Error downloading language file: {e}{Style.RESET_ALL}") + return False + + def load_translations(self): + """Load all available translations with GitHub fallback""" + try: + # Collection of languages we've successfully loaded + loaded_languages = set() + + # First try to load from local directory locales_dir = os.path.join(os.path.dirname(__file__), 'locales') if hasattr(sys, '_MEIPASS'): locales_dir = os.path.join(sys._MEIPASS, 'locales') - if not os.path.exists(locales_dir): - print(f"{Fore.RED}{EMOJI['ERROR']} Locales directory not found{Style.RESET_ALL}") - return - - for file in os.listdir(locales_dir): - if file.endswith('.json'): - lang_code = file[:-5] # Remove .json - try: - with open(os.path.join(locales_dir, file), 'r', encoding='utf-8') as f: - self.translations[lang_code] = json.load(f) - except (json.JSONDecodeError, UnicodeDecodeError) as e: - print(f"{Fore.RED}{EMOJI['ERROR']} Error loading {file}: {e}{Style.RESET_ALL}") - continue + # Check if local directory exists + if os.path.exists(locales_dir): + for file in os.listdir(locales_dir): + if file.endswith('.json'): + lang_code = file[:-5] # Remove .json + try: + with open(os.path.join(locales_dir, file), 'r', encoding='utf-8') as f: + self.translations[lang_code] = json.load(f) + loaded_languages.add(lang_code) + except (json.JSONDecodeError, UnicodeDecodeError) as e: + print(f"{Fore.RED}{EMOJI['ERROR']} Error loading {file}: {e}{Style.RESET_ALL}") + continue + else: + print(f"{Fore.YELLOW}{EMOJI['WARNING']} Locales directory not found, checking cache and GitHub...{Style.RESET_ALL}") + + # Next, check for cached files + if self.language_cache_dir and os.path.exists(self.language_cache_dir): + for file in os.listdir(self.language_cache_dir): + if file.endswith('.json'): + lang_code = file[:-5] # Remove .json + + # Skip if we already loaded this language + if lang_code in loaded_languages: + continue + + try: + with open(os.path.join(self.language_cache_dir, file), 'r', encoding='utf-8') as f: + self.translations[lang_code] = json.load(f) + loaded_languages.add(lang_code) + except (json.JSONDecodeError, UnicodeDecodeError) as e: + print(f"{Fore.RED}{EMOJI['ERROR']} Error loading cached {file}: {e}{Style.RESET_ALL}") + continue + + # Finally, if we're missing essential languages, try to download them + if self.config and self.config.has_section('Language') and self.config.getboolean('Language', 'auto_update_languages', fallback=True): + essential_languages = ['en', 'zh_cn', 'zh_tw', 'vi'] + + # Add current language and fallback language to essential list if they're not already in + if self.current_language and self.current_language not in essential_languages: + essential_languages.append(self.current_language) + if self.fallback_language and self.fallback_language not in essential_languages: + essential_languages.append(self.fallback_language) + + for lang_code in essential_languages: + if lang_code not in loaded_languages: + print(f"{Fore.YELLOW}{EMOJI['INFO']} Missing essential language: {lang_code}, attempting to download...{Style.RESET_ALL}") + self.download_language_file(lang_code) + + # If we have no translations at all, it's a critical error + if not self.translations: + print(f"{Fore.RED}{EMOJI['ERROR']} Failed to load any translations! The application may not function correctly.{Style.RESET_ALL}") + except Exception as e: print(f"{Fore.RED}{EMOJI['ERROR']} Failed to load translations: {e}{Style.RESET_ALL}") + # Create at least minimal English translations for basic functionality + self.translations['en'] = {"menu": {"title": "Menu", "exit": "Exit", "invalid_choice": "Invalid choice"}} def get(self, key, **kwargs): """Get translated text with fallback support""" @@ -378,7 +500,25 @@ def select_language(): try: choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}{translator.get('menu.input_choice', choices=f'0-{len(languages)-1}')}: {Style.RESET_ALL}") if choice.isdigit() and 0 <= int(choice) < len(languages): - translator.set_language(languages[int(choice)]) + selected_language = languages[int(choice)] + translator.set_language(selected_language) + + # Save selected language to config + config = get_config() + if config and config.has_section('Language'): + config.set('Language', 'current_language', selected_language) + + # Get config path from user documents + from utils import get_user_documents_path + config_dir = os.path.join(get_user_documents_path(), ".cursor-free-vip") + config_file = os.path.join(config_dir, "config.ini") + + # Write updated config + with open(config_file, 'w', encoding='utf-8') as f: + config.write(f) + + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('Language config saved', language=translator.get(f'languages.{selected_language}'))}{Style.RESET_ALL}") + return True else: print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}") From 31bf75e4def4d369b3b827b0ba57ee257ed3fcd2 Mon Sep 17 00:00:00 2001 From: TranMC Date: Wed, 23 Apr 2025 11:38:17 +0700 Subject: [PATCH 2/6] Update language configuration --- locales/en.json | 4 ++- locales/vi.json | 4 ++- main.py | 69 ++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 65 insertions(+), 12 deletions(-) diff --git a/locales/en.json b/locales/en.json index 4e40521..bbf35a9 100644 --- a/locales/en.json +++ b/locales/en.json @@ -32,7 +32,9 @@ "exiting": "Exiting ……", "bypass_version_check": "Bypass Cursor Version Check", "check_user_authorized": "Check User Authorized", - "bypass_token_limit": "Bypass Token Limit" + "bypass_token_limit": "Bypass Token Limit", + "language_config_saved": "Language configuration saved successfully", + "lang_invalid_choice": "Invalid choice. Please enter one of the following options: ({lang_choices})" }, "languages": { "en": "English", diff --git a/locales/vi.json b/locales/vi.json index 5a67f65..14d0198 100644 --- a/locales/vi.json +++ b/locales/vi.json @@ -31,7 +31,9 @@ "operation_cancelled_by_user": "Thao tác đã bị người dùng hủy", "exiting": "Đang thoát ……", "bypass_version_check": "Bỏ qua Kiểm tra Phiên bản Cursor", - "check_user_authorized": "Kiểm tra Quyền Người dùng" + "check_user_authorized": "Kiểm tra Quyền Người dùng", + "language_config_saved": "Đổi ngôn ngữ thành công", + "lang_invalid_choice": "Lựa chọn không hợp lệ. Vui lòng nhập một số từ ({lang_choices})" }, "languages": { "en": "Tiếng Anh", diff --git a/main.py b/main.py index f2b6465..1a37095 100644 --- a/main.py +++ b/main.py @@ -374,8 +374,51 @@ class Translator: return False def get_available_languages(self): - """Get list of available languages""" - return list(self.translations.keys()) + """Get list of available languages, checking GitHub for updates if configured""" + # Get currently loaded languages + available_languages = list(self.translations.keys()) + + # Check if automatic language updates are enabled + if (self.config and self.config.has_section('Language') and + self.config.getboolean('Language', 'auto_update_languages', fallback=True)): + + try: + # GitHub API URL to get directory listing of language files + github_url = "https://api.github.com/repos/yeongpin/cursor-free-vip/contents/locales" + + # Set up proper headers for GitHub API + headers = { + 'Accept': 'application/vnd.github.v3+json', + 'User-Agent': 'Cursor-Free-VIP-App' + } + + # Request the directory listing with timeout + response = requests.get(github_url, headers=headers, timeout=10) + + # Check if successful + if response.status_code == 200: + github_files = response.json() + + # Extract language codes from JSON files in the repository + github_languages = [] + for file_info in github_files: + if file_info.get('type') == 'file' and file_info.get('name', '').endswith('.json'): + lang_code = file_info.get('name')[:-5] # Remove .json extension + github_languages.append(lang_code) + + # Check for languages available on GitHub but not loaded locally + for lang_code in github_languages: + if lang_code not in available_languages: + # Download the missing language file + if self.download_language_file(lang_code): + available_languages.append(lang_code) + + except Exception as e: + # Just log the error but continue with local languages + print(f"{Fore.YELLOW}{EMOJI['INFO']} Could not check for additional languages from GitHub: {e}{Style.RESET_ALL}") + + # Sort languages alphabetically for better display + return sorted(available_languages) # Create translator instance translator = Translator() @@ -492,14 +535,20 @@ def select_language(): print(f"\n{Fore.CYAN}{EMOJI['LANG']} {translator.get('menu.select_language')}:{Style.RESET_ALL}") print(f"{Fore.YELLOW}{'─' * 40}{Style.RESET_ALL}") + # Get available languages either from local directory or GitHub languages = translator.get_available_languages() + languages_count = len(languages) + + # Display all available languages with proper indices for i, lang in enumerate(languages): - lang_name = translator.get(f"languages.{lang}") + lang_name = translator.get(f"languages.{lang}", fallback=lang) print(f"{Fore.GREEN}{i}{Style.RESET_ALL}. {lang_name}") try: - choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}{translator.get('menu.input_choice', choices=f'0-{len(languages)-1}')}: {Style.RESET_ALL}") - if choice.isdigit() and 0 <= int(choice) < len(languages): + # Use the actual number of languages in the prompt + choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}{translator.get('menu.input_choice', choices=f'0-{languages_count-1}')}: {Style.RESET_ALL}") + + if choice.isdigit() and 0 <= int(choice) < languages_count: selected_language = languages[int(choice)] translator.set_language(selected_language) @@ -509,7 +558,6 @@ def select_language(): config.set('Language', 'current_language', selected_language) # Get config path from user documents - from utils import get_user_documents_path config_dir = os.path.join(get_user_documents_path(), ".cursor-free-vip") config_file = os.path.join(config_dir, "config.ini") @@ -517,14 +565,15 @@ def select_language(): with open(config_file, 'w', encoding='utf-8') as f: config.write(f) - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('Language config saved', language=translator.get(f'languages.{selected_language}'))}{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('menu.language_saved', language=translator.get(f'languages.{selected_language}', fallback=selected_language))}{Style.RESET_ALL}") return True else: - print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}") + # Show invalid choice message with the correct range + print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.lang_invalid_choice', lang_choices=f'0-{languages_count-1}')}{Style.RESET_ALL}") return False - except (ValueError, IndexError): - print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}") + except (ValueError, IndexError) as e: + print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.lang_invalid_choice', lang_choices=f'0-{languages_count-1}')}{Style.RESET_ALL}") return False def check_latest_version(): From ef17ba8803f9fff20ab5b82dcf4e9c24a55dfe8c Mon Sep 17 00:00:00 2001 From: TranMC Date: Wed, 23 Apr 2025 12:04:03 +0700 Subject: [PATCH 3/6] Small language change --- locales/zh_cn.json | 4 +++- locales/zh_tw.json | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/locales/zh_cn.json b/locales/zh_cn.json index 07d15d5..df7d316 100644 --- a/locales/zh_cn.json +++ b/locales/zh_cn.json @@ -32,7 +32,9 @@ "exiting": "退出中 ……", "bypass_version_check": "绕过 Cursor 版本检查", "check_user_authorized": "检查用户授权", - "bypass_token_limit": "绕过 Token 限制" + "bypass_token_limit": "绕过 Token 限制", + "language_config_saved": "语言配置保存成功", + "lang_invalid_choice": "选择无效。请输入以下选项之一:({lang_choices})" }, "languages": { "en": "英语", diff --git a/locales/zh_tw.json b/locales/zh_tw.json index 9b9573a..e1e559b 100644 --- a/locales/zh_tw.json +++ b/locales/zh_tw.json @@ -32,8 +32,10 @@ "exiting": "退出中 ……", "bypass_version_check": "繞過 Cursor 版本檢查", "check_user_authorized": "檢查用戶授權", - "bypass_token_limit": "繞過 Token 限制" - }, + "bypass_token_limit": "繞過 Token 限制", + "language_config_saved": "語言設定已成功儲存", + "lang_invalid_choice": "選擇無效。請輸入以下選項之一:({lang_choices})" + }, "languages": { "en": "英文", "zh_cn": "簡體中文", From 0b547c0542c2af4f8be02ea8c8be1c966ffea2a6 Mon Sep 17 00:00:00 2001 From: TranMC Date: Wed, 23 Apr 2025 12:09:02 +0700 Subject: [PATCH 4/6] Fix nofitication --- main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.py b/main.py index 1a37095..ad8093e 100644 --- a/main.py +++ b/main.py @@ -565,7 +565,7 @@ def select_language(): with open(config_file, 'w', encoding='utf-8') as f: config.write(f) - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('menu.language_saved', language=translator.get(f'languages.{selected_language}', fallback=selected_language))}{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('menu.language_config_saved', language=translator.get(f'languages.{selected_language}', fallback=selected_language))}{Style.RESET_ALL}") return True else: From 8c497d7639ccb7bc22afa213d50f0edf3ac3bf69 Mon Sep 17 00:00:00 2001 From: TranMC Date: Wed, 23 Apr 2025 12:48:58 +0700 Subject: [PATCH 5/6] Commit vui vui --- locales/ar.json | 769 ++++++++++++++++++++++++++++++++++++++++++++++++ locales/en.json | 3 +- locales/vi.json | 3 +- main.py | 196 ++++-------- 4 files changed, 828 insertions(+), 143 deletions(-) create mode 100644 locales/ar.json diff --git a/locales/ar.json b/locales/ar.json new file mode 100644 index 0000000..e0b02b4 --- /dev/null +++ b/locales/ar.json @@ -0,0 +1,769 @@ +{ + "menu": { + "title": "الخيارات المتاحة", + "exit": "خروج من البرنامج", + "reset": "إعادة تعيين معرف الجهاز", + "register": "تسجيل حساب Cursor جديد", + "register_google": "تسجيل باستخدام حساب جوجل", + "register_github": "تسجيل باستخدام حساب GitHub", + "register_manual": "تسجيل Cursor باستخدام بريد إلكتروني مخصص", + "quit": "إغلاق تطبيق Cursor", + "select_language": "تغيير اللغة", + "select_chrome_profile": "اختيار ملف تعريف Chrome", + "input_choice": "الرجاء إدخال اختيارك ({choices})", + "invalid_choice": "اختيار غير صالح. الرجاء إدخال رقم من {choices}", + "program_terminated": "تم إنهاء البرنامج بواسطة المستخدم", + "error_occurred": "حدث خطأ: {error}. يرجى المحاولة مرة أخرى", + "press_enter": "اضغط Enter للخروج", + "disable_auto_update": "تعطيل التحديث التلقائي لـ Cursor", + "lifetime_access_enabled": "تم تفعيل الوصول مدى الحياة", + "totally_reset": "إعادة تعيين Cursor بالكامل", + "outdate": "قديم", + "temp_github_register": "تسجيل GitHub مؤقت", + "admin_required": "يجب تشغيل البرنامج كمسؤول عند التنفيذ.", + "admin_required_continue": "المتابعة بدون صلاحيات المسؤول.", + "coming_soon": "قريباً", + "fixed_soon": "سيتم إصلاحه قريباً", + "contribute": "المساهمة في المشروع", + "config": "عرض الإعدادات", + "delete_google_account": "حذف حساب Cursor المرتبط بجوجل", + "continue_prompt": "المتابعة؟ (y/N): ", + "operation_cancelled_by_user": "تم إلغاء العملية بواسطة المستخدم", + "exiting": "جاري الخروج ……", + "bypass_version_check": "تجاوز فحص إصدار Cursor", + "check_user_authorized": "فحص صلاحية المستخدم", + "bypass_token_limit": "تجاوز حد الرمز المميز (Token)" + }, + "languages": { + "en": "الإنجليزية", + "zh_cn": "الصينية المبسطة", + "zh_tw": "الصينية التقليدية", + "vi": "الفيتنامية", + "nl": "الهولندية", + "de": "الألمانية", + "fr": "الفرنسية", + "pt": "البرتغالية", + "ru": "الروسية", + "tr": "التركية", + "bg": "البلغارية", + "es": "الإسبانية", + "ar": "العربية" + }, + "quit_cursor": { + "start": "بدء إغلاق Cursor", + "no_process": "لا توجد عمليات Cursor قيد التشغيل", + "terminating": "إنهاء العملية {pid}", + "waiting": "في انتظار إنهاء العملية", + "success": "تم إغلاق جميع عمليات Cursor", + "timeout": "انتهت مهلة العملية: {pids}", + "error": "حدث خطأ: {error}" + }, + "reset": { + "title": "أداة إعادة تعيين معرف جهاز Cursor", + "checking": "جارٍ فحص ملف الإعدادات", + "not_found": "لم يتم العثور على ملف الإعدادات", + "no_permission": "لا يمكن قراءة أو كتابة ملف الإعدادات، يرجى التحقق من صلاحيات الملف", + "reading": "جارٍ قراءة الإعدادات الحالية", + "creating_backup": "جارٍ إنشاء نسخة احتياطية للإعدادات", + "backup_exists": "النسخة الاحتياطية موجودة بالفعل، تخطي خطوة النسخ الاحتياطي", + "generating": "جارٍ إنشاء معرف جهاز جديد", + "saving_json": "جارٍ حفظ الإعدادات الجديدة في JSON", + "success": "تم إعادة تعيين معرف الجهاز بنجاح", + "new_id": "معرف الجهاز الجديد", + "permission_error": "خطأ في الصلاحيات: {error}", + "run_as_admin": "يرجى محاولة تشغيل هذا البرنامج كمسؤول", + "process_error": "خطأ في عملية الإعادة: {error}", + "updating_sqlite": "جارٍ تحديث قاعدة بيانات SQLite", + "updating_pair": "جارٍ تحديث زوج المفتاح-القيمة", + "sqlite_success": "تم تحديث قاعدة بيانات SQLite بنجاح", + "sqlite_error": "فشل تحديث قاعدة بيانات SQLite: {error}", + "press_enter": "اضغط Enter للخروج", + "unsupported_os": "نظام تشغيل غير مدعوم: {os}", + "linux_path_not_found": "لم يتم العثور على مسار Linux", + "updating_system_ids": "جارٍ تحديث معرفات النظام", + "system_ids_updated": "تم تحديث معرفات النظام بنجاح", + "system_ids_update_failed": "فشل تحديث معرفات النظام: {error}", + "windows_guid_updated": "تم تحديث Windows GUID بنجاح", + "windows_permission_denied": "تم رفض الصلاحية في Windows", + "windows_guid_update_failed": "فشل تحديث Windows GUID", + "macos_uuid_updated": "تم تحديث macOS UUID بنجاح", + "plutil_command_failed": "فشل أمر plutil", + "start_patching": "بدء تصحيح getMachineId", + "macos_uuid_update_failed": "فشل تحديث macOS UUID", + "current_version": "إصدار Cursor الحالي: {version}", + "patch_completed": "تم تصحيح getMachineId بنجاح", + "patch_failed": "فشل تصحيح getMachineId: {error}", + "version_check_passed": "تم اجتياز فحص إصدار Cursor", + "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", + "permission_denied": "تم رفض الصلاحية: {error}", + "backup_created": "تم إنشاء نسخة احتياطية", + "update_success": "تم التحديث بنجاح", + "update_failed": "فشل التحديث: {error}", + "windows_machine_guid_updated": "تم تحديث Windows Machine GUID بنجاح", + "reading_package_json": "جارٍ قراءة package.json {path}", + "invalid_json_object": "كائن JSON غير صالح", + "no_version_field": "لم يتم العثور على حقل الإصدار في package.json", + "version_field_empty": "حقل الإصدار فارغ", + "invalid_version_format": "تنسيق إصدار غير صالح: {version}", + "found_version": "تم العثور على الإصدار: {version}", + "version_parse_error": "خطأ في تحليل الإصدار: {error}", + "package_not_found": "لم يتم العثور على package.json: {path}", + "check_version_failed": "فشل فحص الإصدار: {error}", + "stack_trace": "تتبع المكدس", + "version_too_low": "إصدار Cursor منخفض جداً: {version} < 0.45.0", + "no_write_permission": "لا توجد صلاحيات كتابة: {path}", + "path_not_found": "لم يتم العثور على المسار: {path}", + "modify_file_failed": "فشل تعديل الملف: {error}", + "windows_machine_id_updated": "تم تحديث Windows Machine ID بنجاح", + "update_windows_machine_id_failed": "فشل تحديث Windows Machine ID: {error}", + "update_windows_machine_guid_failed": "فشل تحديث Windows Machine GUID: {error}", + "file_not_found": "لم يتم العثور على الملف: {path}" + }, + "register": { + "title": "أداة تسجيل Cursor", + "start": "بدء عملية التسجيل...", + "handling_turnstile": "جارٍ معالجة التحقق الأمني...", + "retry_verification": "إعادة محاولة التحقق...", + "detect_turnstile": "جارٍ التحقق من الأمان...", + "verification_success": "تم التحقق الأمني بنجاح", + "starting_browser": "جارٍ فتح المتصفح...", + "form_success": "تم إرسال النموذج بنجاح", + "browser_started": "تم فتح المتصفح بنجاح", + "waiting_for_second_verification": "في انتظار التحقق عبر البريد الإلكتروني...", + "waiting_for_verification_code": "في انتظار رمز التحقق...", + "password_success": "تم تعيين كلمة المرور بنجاح", + "password_error": "تعذر تعيين كلمة المرور: {error}. يرجى المحاولة مرة أخرى", + "waiting_for_page_load": "جارٍ تحميل الصفحة...", + "first_verification_passed": "تم اجتياز التحقق الأولي بنجاح", + "mailbox": "تم الوصول إلى صندوق البريد بنجاح", + "register_start": "بدء التسجيل", + "form_submitted": "تم إرسال النموذج، بدء التحقق...", + "filling_form": "تعبئة النموذج", + "visiting_url": "جارٍ زيارة الرابط", + "basic_info": "تم إرسال المعلومات الأساسية", + "handle_turnstile": "معالجة Turnstile", + "no_turnstile": "لم يتم اكتشاف Turnstile", + "turnstile_passed": "تم اجتياز Turnstile", + "verification_start": "بدء الحصول على رمز التحقق", + "verification_timeout": "انتهت مهلة الحصول على رمز التحقق", + "verification_not_found": "لم يتم العثور على رمز تحقق", + "try_get_code": "محاولة | {attempt} الحصول على رمز التحقق | الوقت المتبقي: {time}ثانية", + "get_account": "جارٍ الحصول على معلومات الحساب", + "get_token": "الحصول على رمز جلسة Cursor", + "token_success": "تم الحصول على الرمز بنجاح", + "token_attempt": "محاولة | {attempt} مرات للحصول على الرمز | سيتم إعادة المحاولة بعد {time}ثانية", + "token_max_attempts": "تم الوصول إلى الحد الأقصى للمحاولات ({max}) | فشل الحصول على الرمز", + "token_failed": "فشل الحصول على الرمز: {error}", + "account_error": "فشل الحصول على معلومات الحساب: {error}", + "press_enter": "اضغط Enter للخروج", + "browser_start": "بدء تشغيل المتصفح", + "open_mailbox": "جارٍ فتح صندوق البريد", + "email_error": "فشل الحصول على عنوان البريد الإلكتروني", + "setup_error": "خطأ في إعداد البريد الإلكتروني: {error}", + "start_getting_verification_code": "بدء الحصول على رمز التحقق، سيتم المحاولة خلال 60 ثانية", + "get_verification_code_timeout": "انتهت مهلة الحصول على رمز التحقق", + "get_verification_code_success": "تم الحصول على رمز التحقق بنجاح", + "try_get_verification_code": "محاولة | {attempt} الحصول على رمز التحقق | الوقت المتبقي: {remaining_time}ثانية", + "verification_code_filled": "تم تعبئة رمز التحقق", + "login_success_and_jump_to_settings_page": "تم تسجيل الدخول بنجاح والانتقال إلى صفحة الإعدادات", + "detect_login_page": "تم اكتشاف صفحة تسجيل الدخول، بدء التسجيل...", + "cursor_registration_completed": "تم تسجيل Cursor بنجاح!", + "set_password": "تعيين كلمة المرور", + "basic_info_submitted": "تم إرسال المعلومات الأساسية", + "cursor_auth_info_updated": "تم تحديث معلومات مصادقة Cursor", + "cursor_auth_info_update_failed": "فشل تحديث معلومات مصادقة Cursor", + "reset_machine_id": "إعادة تعيين معرف الجهاز", + "account_info_saved": "تم حفظ معلومات الحساب", + "save_account_info_failed": "فشل حفظ معلومات الحساب", + "get_email_address": "الحصول على عنوان البريد الإلكتروني", + "update_cursor_auth_info": "تحديث معلومات مصادقة Cursor", + "register_process_error": "خطأ في عملية التسجيل: {error}", + "setting_password": "جارٍ تعيين كلمة المرور", + "manual_code_input": "إدخال الرمز يدوياً", + "manual_email_input": "إدخال البريد الإلكتروني يدوياً", + "password": "كلمة المرور", + "first_name": "الاسم الأول", + "last_name": "الاسم الأخير", + "exit_signal": "إشارة خروج", + "email_address": "عنوان البريد الإلكتروني", + "config_created": "تم إنشاء الإعدادات", + "verification_failed": "فشل التحقق", + "verification_error": "خطأ في التحقق: {error}", + "config_option_added": "تمت إضافة خيار الإعدادات: {option}", + "config_updated": "تم تحديث الإعدادات", + "password_submitted": "تم إرسال كلمة المرور", + "total_usage": "إجمالي الاستخدام: {usage}", + "setting_on_password": "جارٍ تعيين كلمة المرور", + "getting_code": "جارٍ الحصول على رمز التحقق، سيتم المحاولة خلال 60 ثانية", + "human_verify_error": "تعذر التحقق من أن المستخدم بشري. جارٍ إعادة المحاولة...", + "max_retries_reached": "تم الوصول إلى الحد الأقصى للمحاولات. فشل التسجيل.", + "browser_path_invalid": "مسار {browser} غير صالح، جارٍ استخدام المسار الافتراضي", + "using_browser": "جارٍ استخدام متصفح {browser}: {path}", + "using_browser_profile": "جارٍ استخدام ملف تعريف {browser} من: {user_data_dir}", + "make_sure_browser_is_properly_installed": "تأكد من تثبيت {browser} بشكل صحيح", + "try_install_browser": "حاول تثبيت المتصفح باستخدام مدير الحزم الخاص بك", + "tracking_processes": "جارٍ تتبع {count} عمليات {browser}", + "no_new_processes_detected": "لم يتم اكتشاف عمليات {browser} جديدة للتتبع", + "could_not_track_processes": "تعذر تتبع عمليات {browser}: {error}" + }, + "auth": { + "title": "مدير مصادقة Cursor", + "checking_auth": "جارٍ فحص ملف المصادقة", + "auth_not_found": "لم يتم العثور على ملف المصادقة", + "auth_file_error": "خطأ في ملف المصادقة: {error}", + "reading_auth": "جارٍ قراءة ملف المصادقة", + "updating_auth": "جارٍ تحديث معلومات المصادقة", + "auth_updated": "تم تحديث معلومات المصادقة بنجاح", + "auth_update_failed": "فشل تحديث معلومات المصادقة: {error}", + "auth_file_created": "تم إنشاء ملف المصادقة", + "auth_file_create_failed": "فشل إنشاء ملف المصادقة: {error}", + "press_enter": "اضغط Enter للخروج", + "reset_machine_id": "إعادة تعيين معرف الجهاز", + "database_connection_closed": "تم إغلاق اتصال قاعدة البيانات", + "database_updated_successfully": "تم تحديث قاعدة البيانات بنجاح", + "connected_to_database": "تم الاتصال بقاعدة البيانات", + "updating_pair": "جارٍ تحديث زوج المفتاح-القيمة", + "db_not_found": "لم يتم العثور على ملف قاعدة البيانات في: {path}", + "db_permission_error": "لا يمكن الوصول إلى ملف قاعدة البيانات. يرجى التحقق من الصلاحيات", + "db_connection_error": "فشل الاتصال بقاعدة البيانات: {error}" + }, + "control": { + "generate_email": "جارٍ إنشاء بريد إلكتروني جديد", + "blocked_domain": "نطاق محظور", + "select_domain": "جارٍ اختيار نطاق عشوائي", + "copy_email": "جارٍ نسخ عنوان البريد الإلكتروني", + "enter_mailbox": "جارٍ الدخول إلى صندوق البريد", + "refresh_mailbox": "جارٍ تحديث صندوق البريد", + "check_verification": "جارٍ التحقق من رمز التحقق", + "verification_found": "تم العثور على رمز التحقق", + "verification_not_found": "لم يتم العثور على رمز تحقق", + "browser_error": "خطأ في التحكم بالمتصفح: {error}", + "navigation_error": "خطأ في التنقل: {error}", + "email_copy_error": "خطأ في نسخ البريد الإلكتروني: {error}", + "mailbox_error": "خطأ في صندوق البريد: {error}", + "token_saved_to_file": "تم حفظ الرمز في ملف cursor_tokens.txt", + "navigate_to": "جارٍ الانتقال إلى {url}", + "generate_email_success": "تم إنشاء البريد الإلكتروني بنجاح", + "select_email_domain": "اختيار نطاق البريد الإلكتروني", + "select_email_domain_success": "تم اختيار نطاق البريد الإلكتروني بنجاح", + "get_email_name": "الحصول على اسم البريد الإلكتروني", + "get_email_name_success": "تم الحصول على اسم البريد الإلكتروني بنجاح", + "get_email_address": "الحصول على عنوان البريد الإلكتروني", + "get_email_address_success": "تم الحصول على عنوان البريد الإلكتروني بنجاح", + "enter_mailbox_success": "تم الدخول إلى صندوق البريد بنجاح", + "found_verification_code": "تم العثور على رمز التحقق", + "get_cursor_session_token": "الحصول على رمز جلسة Cursor", + "get_cursor_session_token_success": "تم الحصول على رمز جلسة Cursor بنجاح", + "get_cursor_session_token_failed": "فشل الحصول على رمز جلسة Cursor", + "save_token_failed": "فشل حفظ الرمز", + "database_updated_successfully": "تم تحديث قاعدة البيانات بنجاح", + "database_connection_closed": "تم إغلاق اتصال قاعدة البيانات", + "no_valid_verification_code": "لا يوجد رمز تحقق صالح" + }, + "email": { + "starting_browser": "جارٍ بدء تشغيل المتصفح", + "visiting_site": "جارٍ زيارة نطاقات البريد", + "create_success": "تم إنشاء البريد الإلكتروني بنجاح", + "create_failed": "فشل إنشاء البريد الإلكتروني", + "create_error": "خطأ في إنشاء البريد الإلكتروني: {error}", + "refreshing": "جارٍ تحديث البريد الإلكتروني", + "refresh_success": "تم تحديث البريد الإلكتروني بنجاح", + "refresh_error": "خطأ في تحديث البريد الإلكتروني: {error}", + "refresh_button_not_found": "لم يتم العثور على زر التحديث", + "verification_found": "تم العثور على التحقق", + "verification_not_found": "لم يتم العثور على التحقق", + "verification_error": "خطأ في التحقق: {error}", + "verification_code_found": "تم العثور على رمز التحقق", + "verification_code_not_found": "لم يتم العثور على رمز تحقق", + "verification_code_error": "خطأ في رمز التحقق: {error}", + "address": "عنوان البريد الإلكتروني", + "all_domains_blocked": "جميع النطاقات محظورة، جارٍ التحويل إلى خدمة أخرى", + "no_available_domains_after_filtering": "لا توجد نطاقات متاحة بعد التصفية", + "switching_service": "جارٍ التحويل إلى خدمة {service}", + "domains_list_error": "فشل الحصول على قائمة النطاقات: {error}", + "failed_to_get_available_domains": "فشل الحصول على نطاقات متاحة", + "domains_excluded": "النطاقات المستثناة: {domains}", + "failed_to_create_account": "فشل إنشاء الحساب", + "account_creation_error": "خطأ في إنشاء الحساب: {error}", + "blocked_domains": "النطاقات المحظورة: {domains}", + "blocked_domains_loaded": "تم تحميل النطاقات المحظورة: {count}", + "blocked_domains_loaded_error": "خطأ في تحميل النطاقات المحظورة: {error}", + "blocked_domains_loaded_success": "تم تحميل النطاقات المحظورة بنجاح", + "blocked_domains_loaded_timeout": "انتهت مهلة تحميل النطاقات المحظورة: {timeout}ثانية", + "blocked_domains_loaded_timeout_error": "خطأ في مهلة تحميل النطاقات المحظورة: {error}", + "available_domains_loaded": "تم تحميل النطاقات المتاحة: {count}", + "domains_filtered": "تم تصفية النطاقات: {count}", + "trying_to_create_email": "جارٍ محاولة إنشاء بريد إلكتروني: {email}", + "domain_blocked": "النطاق محظور: {domain}", + "using_chrome_profile": "جارٍ استخدام ملف تعريف Chrome من: {user_data_dir}", + "no_display_found": "لم يتم العثور على شاشة. تأكد من تشغيل خادم X.", + "try_export_display": "حاول: export DISPLAY=:0", + "extension_load_error": "خطأ في تحميل الامتداد: {error}", + "make_sure_chrome_chromium_is_properly_installed": "تأكد من تثبيت Chrome/Chromium بشكل صحيح", + "try_install_chromium": "حاول: sudo apt install chromium-browser" + }, + "update": { + "title": "تعطيل التحديث التلقائي لـ Cursor", + "disable_success": "تم تعطيل التحديث التلقائي بنجاح", + "disable_failed": "فشل تعطيل التحديث التلقائي: {error}", + "press_enter": "اضغط Enter للخروج", + "start_disable": "بدء تعطيل التحديث التلقائي", + "killing_processes": "جارٍ إنهاء العمليات", + "processes_killed": "تم إنهاء العمليات", + "removing_directory": "جارٍ إزالة الدليل", + "directory_removed": "تمت إزالة الدليل", + "creating_block_file": "جارٍ إنشاء ملف حظر", + "block_file_created": "تم إنشاء ملف الحظر", + "clearing_update_yml": "جارٍ مسح ملف update.yml", + "update_yml_cleared": "تم مسح ملف update.yml", + "update_yml_not_found": "لم يتم العثور على ملف update.yml", + "clear_update_yml_failed": "فشل مسح ملف update.yml: {error}", + "unsupported_os": "نظام تشغيل غير مدعوم: {system}", + "remove_directory_failed": "فشل إزالة الدليل: {error}", + "create_block_file_failed": "فشل إنشاء ملف الحظر: {error}", + "directory_locked": "الدليل مقفل: {path}", + "yml_locked": "ملف update.yml مقفل", + "block_file_locked": "ملف الحظر مقفل", + "yml_already_locked": "ملف update.yml مقفل بالفعل", + "block_file_already_locked": "ملف الحظر مقفل بالفعل", + "block_file_locked_error": "خطأ في قفل ملف الحظر: {error}", + "yml_locked_error": "خطأ في قفل ملف update.yml: {error}", + "block_file_already_locked_error": "خطأ في قفل ملف الحظر الموجود بالفعل: {error}", + "yml_already_locked_error": "خطأ في قفل ملف update.yml الموجود بالفعل: {error}" + }, + "updater": { + "checking": "جارٍ التحقق من التحديثات...", + "new_version_available": "يتوفر إصدار جديد! (الحالي: {current}, الأحدث: {latest})", + "updating": "جارٍ التحديث إلى أحدث إصدار. سيعيد البرنامج التشغيل تلقائياً.", + "up_to_date": "أنت تستخدم أحدث إصدار.", + "check_failed": "فشل التحقق من التحديثات: {error}", + "continue_anyway": "المتابعة باستخدام الإصدار الحالي...", + "update_confirm": "هل تريد التحديث إلى أحدث إصدار؟ (Y/n)", + "update_skipped": "تخطي التحديث.", + "invalid_choice": "اختيار غير صالح. الرجاء إدخال 'Y' أو 'n'.", + "development_version": "إصدار التطوير {current} > {latest}", + "changelog_title": "سجل التغييرات", + "rate_limit_exceeded": "تم تجاوز حد معدل GitHub API. تخطي فحص التحديث." + }, + "totally_reset": { + "title": "إعادة تعيين Cursor بالكامل", + "checking_config": "جارٍ فحص ملف الإعدادات", + "config_not_found": "لم يتم العثور على ملف الإعدادات", + "no_permission": "لا يمكن قراءة أو كتابة ملف الإعدادات، يرجى التحقق من صلاحيات الملف", + "reading_config": "جارٍ قراءة الإعدادات الحالية", + "creating_backup": "جارٍ إنشاء نسخة احتياطية للإعدادات", + "backup_exists": "النسخة الاحتياطية موجودة بالفعل، تخطي خطوة النسخ الاحتياطي", + "generating_new_machine_id": "جارٍ إنشاء معرف جهاز جديد", + "saving_new_config": "جارٍ حفظ الإعدادات الجديدة في JSON", + "success": "تم إعادة تعيين Cursor بنجاح", + "error": "فشل إعادة تعيين Cursor: {error}", + "press_enter": "اضغط Enter للخروج", + "reset_machine_id": "إعادة تعيين معرف الجهاز", + "database_connection_closed": "تم إغلاق اتصال قاعدة البيانات", + "database_updated_successfully": "تم تحديث قاعدة البيانات بنجاح", + "connected_to_database": "تم الاتصال بقاعدة البيانات", + "updating_pair": "جارٍ تحديث زوج المفتاح-القيمة", + "db_not_found": "لم يتم العثور على ملف قاعدة البيانات في: {path}", + "db_permission_error": "لا يمكن الوصول إلى ملف قاعدة البيانات. يرجى التحقق من الصلاحيات", + "db_connection_error": "فشل الاتصال بقاعدة البيانات: {error}", + "feature_title": "الميزات", + "feature_1": "إزالة كاملة لإعدادات وتكوينات Cursor AI", + "feature_2": "مسح جميع البيانات المخزنة مؤقتاً بما في ذلك سجل الذكاء الاصطناعي", + "feature_3": "إعادة تعيين معرف الجهاز لتجاوز كشف الفترة التجريبية", + "feature_4": "إنشاء معرفات أجهزة جديدة عشوائية", + "feature_5": "إزالة الامتدادات المخصصة والتفضيلات", + "feature_6": "إعادة تعيين معلومات الفترة التجريبية وبيانات التفعيل", + "feature_7": "فحص عميق لملفات الرخصة والملفات المتعلقة بالفترة التجريبية المخفية", + "feature_8": "الحفاظ على الملفات والتطبيقات غير المتعلقة بـ Cursor بأمان", + "feature_9": "متوافق مع Windows وmacOS وLinux", + "disclaimer_title": "تنبيه", + "disclaimer_1": "ستقوم هذه الأداة بحذف جميع إعدادات Cursor AI،", + "disclaimer_2": "والتكوينات والبيانات المخزنة مؤقتاً بشكل دائم. لا يمكن التراجع عن هذا الإجراء.", + "disclaimer_3": "لن تتأثر ملفات الكود الخاصة بك، وقد صممت الأداة", + "disclaimer_4": "للاستهداف فقط ملفات محرر Cursor AI وآليات كشف الفترة التجريبية.", + "disclaimer_5": "لن تتأثر التطبيقات الأخرى على نظامك.", + "disclaimer_6": "ستحتاج إلى إعداد Cursor AI مرة أخرى بعد تشغيل هذه الأداة.", + "disclaimer_7": "استخدمها على مسؤوليتك الخاصة", + "confirm_title": "هل أنت متأكد أنك تريد المتابعة؟", + "confirm_1": "سيؤدي هذا الإجراء إلى حذف جميع إعدادات Cursor AI،", + "confirm_2": "والتكوينات والبيانات المخزنة مؤقتاً. لا يمكن التراجع عن هذا الإجراء.", + "confirm_3": "لن تتأثر ملفات الكود الخاصة بك، وقد صممت الأداة", + "confirm_4": "للاستهداف فقط ملفات محرر Cursor AI وآليات كشف الفترة التجريبية.", + "confirm_5": "لن تتأثر التطبيقات الأخرى على نظامك.", + "confirm_6": "ستحتاج إلى إعداد Cursor AI مرة أخرى بعد تشغيل هذه الأداة.", + "confirm_7": "استخدمها على مسؤوليتك الخاصة", + "invalid_choice": "الرجاء إدخال 'Y' أو 'n'", + "skipped_for_safety": "تم تخطيه لأسباب أمنية (غير متعلق بـ Cursor): {path}", + "deleted": "تم الحذف: {path}", + "error_deleting": "خطأ في حذف {path}: {error}", + "not_found": "لم يتم العثور على الملف: {path}", + "resetting_machine_id": "جارٍ إعادة تعيين معرفات الجهاز لتجاوز كشف الفترة التجريبية...", + "created_machine_id": "تم إنشاء معرف جهاز جديد: {path}", + "error_creating_machine_id": "خطأ في إنشاء ملف معرف الجهاز {path}: {error}", + "error_searching": "خطأ في البحث عن الملفات في {path}: {error}", + "created_extended_trial_info": "تم إنشاء معلومات الفترة التجريبية الممتدة: {path}", + "error_creating_trial_info": "خطأ في إنشاء ملف معلومات الفترة التجريبية {path}: {error}", + "resetting_cursor_ai_editor": "جارٍ إعادة تعيين محرر Cursor AI... يرجى الانتظار.", + "reset_cancelled": "تم إلغاء الإعادة. الخروج دون إجراء أي تغييرات.", + "windows_machine_id_modification_skipped": "تم تخطي تعديل معرف جهاز Windows: {error}", + "linux_machine_id_modification_skipped": "تم تخطي تعديل machine-id في Linux: {error}", + "note_complete_machine_id_reset_may_require_running_as_administrator": "ملاحظة: قد تتطلب إعادة تعيين معرف الجهاز الكامل تشغيل البرنامج كمسؤول", + "note_complete_system_machine_id_reset_may_require_sudo_privileges": "ملاحظة: قد تتطلب إعادة تعيين معرف الجهاز الكامل صلاحيات sudo", + "windows_registry_instructions": "📝 ملاحظة: للإعادة الكاملة على Windows، قد تحتاج أيضاً إلى تنظيف إدخالات التسجيل.", + "windows_registry_instructions_2": " قم بتشغيل 'regedit' وابحث عن المفاتيح التي تحتوي على 'Cursor' أو 'CursorAI' تحت HKEY_CURRENT_USER\\Software\\ واحذفها.\n", + "reset_log_1": "تمت إعادة تعيين Cursor AI بالكامل وتجاوز كشف الفترة التجريبية!", + "reset_log_2": "يرجى إعادة تشغيل النظام لتفعيل التغييرات.", + "reset_log_3": "ستحتاج إلى إعادة تثبيت Cursor AI ويجب أن تحصل الآن على فترة تجريبية جديدة.", + "reset_log_4": "للحصول على أفضل النتائج، ضع في الاعتبار أيضاً:", + "reset_log_5": "استخدم عنوان بريد إلكتروني مختلف عند التسجيل للحصول على فترة تجريبية جديدة", + "reset_log_6": "استخدم شبكة VPN لتغيير عنوان IP الخاص بك إذا كان ذلك متاحًا", + "reset_log_7": "قم بمسح ملفات تعريف الارتباط وذاكرة التخزين المؤقت للمتصفح قبل زيارة موقع Cursor AI", + "reset_log_8": "إذا استمرت المشكلات، حاول تثبيت Cursor AI في موقع مختلف", + "reset_log_9": "إذا واجهتك أي مشكلات، انتقل إلى متتبع المشكلات على Github وقم بإنشاء مشكلة جديدة على https://github.com/yeongpin/cursor-free-vip/issues", + "unexpected_error": "حدث خطأ غير متوقع: {error}", + "report_issue": "يرجى الإبلاغ عن هذه المشكلة على متتبع المشكلات في Github على https://github.com/yeongpin/cursor-free-vip/issues", + "keyboard_interrupt": "تمت مقاطعة العملية بواسطة المستخدم. جارٍ الخروج...", + "return_to_main_menu": "جارٍ العودة إلى القائمة الرئيسية...", + "process_interrupted": "تمت مقاطعة العملية. جارٍ الخروج...", + "press_enter_to_return_to_main_menu": "اضغط على Enter للعودة إلى القائمة الرئيسية...", + "removing_known": "جارٍ إزالة ملفات الفترة التجريبية/الترخيص المعروفة", + "performing_deep_scan": "جارٍ إجراء فحص عميق للبحث عن ملفات ترخيص/تجريبية إضافية", + "found_additional_potential_license_trial_files": "تم العثور على {count} ملفات محتملة إضافية للترخيص/الفترة التجريبية", + "checking_for_electron_localstorage_files": "جارٍ التحقق من وجود ملفات التخزين المحلي لـ Electron", + "no_additional_license_trial_files_found_in_deep_scan": "لم يتم العثور على ملفات ترخيص/تجريبية إضافية في الفحص العميق", + "removing_electron_localstorage_files": "جارٍ إزالة ملفات التخزين المحلي لـ Electron", + "electron_localstorage_files_removed": "تمت إزالة ملفات التخزين المحلي لـ Electron", + "electron_localstorage_files_removal_error": "خطأ في إزالة ملفات التخزين المحلي لـ Electron: {error}", + "removing_electron_localstorage_files_completed": "اكتملت إزالة ملفات التخزين المحلي لـ Electron", + "warning_title": "تحذير", + "warning_1": "هذا الإجراء سيحذف جميع إعدادات Cursor AI،", + "warning_2": "والتكوينات والبيانات المخزنة مؤقتاً. لا يمكن التراجع عن هذا الإجراء.", + "warning_3": "لن تتأثر ملفات الكود الخاصة بك، وقد صممت الأداة", + "warning_4": "لاستهداف ملفات محرر Cursor AI وآليات اكتشاف الفترة التجريبية فقط.", + "warning_5": "لن تتأثر التطبيقات الأخرى على نظامك.", + "warning_6": "ستحتاج إلى إعداد Cursor AI مرة أخرى بعد تشغيل هذه الأداة.", + "warning_7": "استخدم على مسؤوليتك الخاصة", + "removed": "تمت الإزالة: {path}", + "failed_to_reset_machine_guid": "فشل إعادة تعيين معرّف الجهاز", + "failed_to_remove": "فشل في الإزالة: {path}", + "failed_to_delete_file": "فشل في حذف الملف: {path}", + "failed_to_delete_directory": "فشل في حذف المجلد: {path}", + "failed_to_delete_file_or_directory": "فشل في حذف الملف أو المجلد: {path}", + "deep_scanning": "جارٍ إجراء فحص عميق للبحث عن ملفات ترخيص/تجريبية إضافية", + "resetting_cursor": "جارٍ إعادة تعيين محرر Cursor AI... يرجى الانتظار.", + "completed_in": "اكتمل في {time} ثانية", + "cursor_reset_completed": "تمت إعادة تعيين محرر Cursor AI بالكامل وتجاوز اكتشاف الفترة التجريبية!", + "cursor_reset_failed": "فشلت إعادة تعيين محرر Cursor AI: {error}", + "cursor_reset_cancelled": "تم إلغاء إعادة تعيين محرر Cursor AI. جارٍ الخروج دون إجراء أي تغييرات.", + "operation_cancelled": "تم إلغاء العملية. جارٍ الخروج دون إجراء أي تغييرات.", + "navigating_to_settings": "جارٍ الانتقال إلى صفحة الإعدادات...", + "already_on_settings": "أنت بالفعل في صفحة الإعدادات", + "login_redirect_failed": "فشلت إعادة توجيه تسجيل الدخول، جارٍ محاولة التنقل المباشر...", + "advanced_tab_not_found": "لم يتم العثور على علامة التبويب المتقدمة بعد عدة محاولات", + "advanced_tab_retry": "لم يتم العثور على علامة التبويب المتقدمة، المحاولة {attempt}/{max_attempts}", + "advanced_tab_error": "خطأ في العثور على علامة التبويب المتقدمة: {error}", + "advanced_tab_clicked": "تم النقر على علامة التبويب المتقدمة", + "direct_advanced_navigation": "جارٍ محاولة التنقل المباشر إلى علامة التبويب المتقدمة", + "delete_button_not_found": "لم يتم العثور على زر حذف الحساب بعد عدة محاولات", + "delete_button_retry": "لم يتم العثور على زر الحذف، المحاولة {attempt}/{max_attempts}", + "delete_button_error": "خطأ في العثور على زر الحذف: {error}", + "delete_button_clicked": "تم النقر على زر حذف الحساب", + "found_danger_zone": "تم العثور على قسم المنطقة الخطرة", + "delete_input_not_found": "لم يتم العثور على حقل تأكيد الحذف بعد عدة محاولات", + "delete_input_retry": "لم يتم العثور على حقل الحذف، المحاولة {attempt}/{max_attempts}", + "delete_input_error": "خطأ في العثور على حقل الحذف: {error}", + "delete_input_not_found_continuing": "لم يتم العثور على حقل تأكيد الحذف، جارٍ محاولة المتابعة على أي حال" + }, + "github_register": { + "title": "أتمتة تسجيل GitHub و Cursor AI", + "features_header": "الميزات", + "feature1": "ينشئ بريدًا إلكترونيًا مؤقتًا باستخدام 1secmail.", + "feature2": "يسجل حساب GitHub جديد ببيانات اعتماد عشوائية.", + "feature3": "يتحقق من بريد GitHub تلقائيًا.", + "feature4": "يسجل الدخول إلى Cursor AI باستخدام مصادقة GitHub.", + "feature5": "يعيد تعيين معرف الجهاز لتجاوز اكتشاف الفترة التجريبية.", + "feature6": "يحفظ جميع بيانات الاعتماد في ملف.", + "warnings_header": "تحذيرات", + "warning1": "تقوم هذه الأداة بأتمتة إنشاء الحساب، مما قد ينتهك شروط خدمة GitHub/Cursor.", + "warning2": "تتطلب وصولاً إلى الإنترنت وامتيازات المسؤول.", + "warning3": "قد تتعارض CAPTCHA أو عمليات التحقق الإضافية مع الأتمتة.", + "warning4": "استخدمها بمسؤولية وعلى مسؤوليتك الخاصة.", + "confirm": "هل أنت متأكد أنك تريد المتابعة؟", + "invalid_choice": "اختيار غير صالح. الرجاء إدخال 'yes' أو 'no'", + "cancelled": "تم إلغاء العملية", + "program_terminated": "تم إنهاء البرنامج بواسطة المستخدم", + "starting_automation": "جارٍ بدء الأتمتة...", + "github_username": "اسم مستخدم GitHub", + "github_password": "كلمة مرور GitHub", + "email_address": "عنوان البريد الإلكتروني", + "credentials_saved": "تم حفظ بيانات الاعتماد هذه في ملف github_cursor_accounts.txt", + "completed_successfully": "اكتمل تسجيل GitHub و Cursor بنجاح!", + "registration_encountered_issues": "واجه تسجيل GitHub و Cursor مشكلات.", + "check_browser_windows_for_manual_intervention_or_try_again_later": "تحقق من نوافذ المتصفح للتدخل اليدوي أو حاول مرة أخرى لاحقًا." + }, + "account_info": { + "subscription": "الاشتراك", + "trial_remaining": "المتبقي من الفترة التجريبية Pro", + "days": "أيام", + "subscription_not_found": "لم يتم العثور على معلومات الاشتراك", + "email_not_found": "لم يتم العثور على البريد الإلكتروني", + "failed_to_get_account": "فشل في الحصول على معلومات الحساب", + "config_not_found": "لم يتم العثور على الإعدادات.", + "failed_to_get_usage": "فشل في الحصول على معلومات الاستخدام", + "failed_to_get_subscription": "فشل في الحصول على معلومات الاشتراك", + "failed_to_get_email": "فشل في الحصول على عنوان البريد الإلكتروني", + "failed_to_get_token": "فشل في الحصول على الرمز", + "failed_to_get_account_info": "فشل في الحصول على معلومات الحساب", + "title": "معلومات الحساب", + "email": "البريد الإلكتروني", + "token": "الرمز", + "usage": "الاستخدام", + "subscription_type": "نوع الاشتراك", + "remaining_trial": "الفترة التجريبية المتبقية", + "days_remaining": "الأيام المتبقية", + "premium": "مميز", + "pro": "محترف", + "pro_trial": "تجريبي محترف", + "team": "فريق", + "enterprise": "مؤسسة", + "free": "مجاني", + "active": "نشط", + "inactive": "غير نشط", + "premium_usage": "استخدام مميز", + "basic_usage": "استخدام أساسي", + "usage_not_found": "لم يتم العثور على الاستخدام", + "lifetime_access_enabled": "تم تمكين الوصول مدى الحياة", + "token_not_found": "لم يتم العثور على الرمز" + }, + "config": { + "config_not_available": "الإعدادات غير متاحة", + "configuration": "الإعدادات", + "enabled": "ممكّن", + "disabled": "معطّل", + "config_directory": "دليل الإعدادات", + "neither_cursor_nor_cursor_directory_found": "لم يتم العثور على Cursor أو دليل Cursor في {config_base}", + "please_make_sure_cursor_is_installed_and_has_been_run_at_least_once": "يرجى التأكد من تثبيت Cursor وتشغيله مرة واحدة على الأقل", + "storage_directory_not_found": "لم يتم العثور على دليل التخزين: {storage_dir}", + "storage_file_found": "تم العثور على ملف التخزين: {storage_path}", + "file_size": "حجم الملف: {size} بايت", + "file_permissions": "صلاحيات الملف: {permissions}", + "file_owner": "مالك الملف: {owner}", + "file_group": "مجموعة الملف: {group}", + "error_getting_file_stats": "خطأ في الحصول على إحصائيات الملف: {error}", + "permission_denied": "تم رفض الإذن: {storage_path}", + "try_running": "حاول تشغيل: {command}", + "and": "و", + "storage_file_is_empty": "ملف التخزين فارغ: {storage_path}", + "the_file_might_be_corrupted_please_reinstall_cursor": "قد يكون الملف تالفًا، يرجى إعادة تثبيت Cursor", + "storage_file_not_found": "لم يتم العثور على ملف التخزين: {storage_path}", + "error_checking_linux_paths": "خطأ في فحص مسارات Linux: {error}", + "config_option_added": "تمت إضافة خيار الإعدادات: {option}", + "config_updated": "تم تحديث الإعدادات", + "config_created": "تم إنشاء الإعدادات: {config_file}", + "config_setup_error": "خطأ في إعداد الإعدادات: {error}", + "storage_file_is_valid_and_contains_data": "ملف التخزين صالح ويحتوي على بيانات", + "error_reading_storage_file": "خطأ في قراءة ملف التخزين: {error}", + "also_checked": "تم فحص {path} أيضًا", + "backup_created": "تم إنشاء نسخة احتياطية: {path}", + "config_removed": "تمت إزالة ملف الإعدادات للتحديث القسري", + "backup_failed": "فشل نسخ الإعدادات احتياطيًا: {error}", + "force_update_failed": "فشل تحديث الإعدادات القسري: {error}", + "config_force_update_disabled": "تم تعطيل التحديث القسري لملف الإعدادات، جارٍ تخطي التحديث القسري", + "config_force_update_enabled": "تم تمكين التحديث القسري لملف الإعدادات، جارٍ إجراء التحديث القسري", + "documents_path_not_found": "لم يتم العثور على مسار المستندات، جارٍ استخدام الدليل الحالي", + "config_dir_created": "تم إنشاء دليل الإعدادات: {path}", + "using_temp_dir": "جارٍ استخدام دليل مؤقت بسبب خطأ: {path} (الخطأ: {error})" + }, + "oauth": { + "authentication_button_not_found": "لم يتم العثور على زر المصادقة", + "authentication_failed": "فشلت المصادقة: {error}", + "found_cookies": "تم العثور على {count} من ملفات تعريف الارتباط", + "token_extraction_error": "خطأ في استخراج الرمز: {error}", + "authentication_successful": "تمت المصادقة بنجاح - البريد الإلكتروني: {email}", + "missing_authentication_data": "بيانات المصادقة مفقودة: {data}", + "failed_to_delete_account": "فشل حذف الحساب: {error}", + "invalid_authentication_type": "نوع المصادقة غير صالح", + "auth_update_success": "تم تحديث المصادقة بنجاح", + "browser_closed": "تم إغلاق المتصفح", + "auth_update_failed": "فشل تحديث المصادقة", + "google_start": "بدء Google", + "github_start": "بدء Github", + "usage_count": "عدد مرات الاستخدام: {usage}", + "account_has_reached_maximum_usage": "وصل الحساب إلى الحد الأقصى للاستخدام، {deleting}", + "starting_new_authentication_process": "جارٍ بدء عملية مصادقة جديدة...", + "failed_to_delete_expired_account": "فشل حذف الحساب المنتهي", + "could_not_check_usage_count": "تعذر التحقق من عدد مرات الاستخدام: {error}", + "found_email": "تم العثور على البريد الإلكتروني: {email}", + "could_not_find_email": "تعذر العثور على البريد الإلكتروني: {error}", + "could_not_find_usage_count": "تعذر العثور على عدد مرات الاستخدام: {error}", + "already_on_settings_page": "أنت بالفعل في صفحة الإعدادات!", + "failed_to_extract_auth_info": "فشل استخراج معلومات المصادقة: {error}", + "no_chrome_profiles_found": "لم يتم العثور على ملفات تعريف Chrome، جارٍ استخدام الملف الافتراضي", + "found_default_chrome_profile": "تم العثور على ملف تعريف Chrome الافتراضي", + "using_first_available_chrome_profile": "جارٍ استخدام أول ملف تعريف Chrome متاح: {profile}", + "error_finding_chrome_profile": "خطأ في العثور على ملف تعريف Chrome، جارٍ استخدام الملف الافتراضي: {error}", + "initializing_browser_setup": "جارٍ تهيئة إعداد المتصفح...", + "detected_platform": "تم اكتشاف النظام: {platform}", + "running_as_root_warning": "التشغيل كمستخدم جذر غير مستحسن لأتمتة المتصفح", + "consider_running_without_sudo": "فكر في تشغيل البرنامج بدون sudo", + "no_compatible_browser_found": "لم يتم العثور على متصفح متوافق. يرجى تثبيت Google Chrome أو Chromium.", + "supported_browsers": "المتصفحات المدعومة لـ {platform}", + "using_browser_profile": "جارٍ استخدام ملف تعريف المتصفح: {profile}", + "starting_browser": "جارٍ بدء المتصفح في: {path}", + "browser_setup_completed": "تم إكمال إعداد المتصفح بنجاح", + "browser_setup_failed": "فشل إعداد المتصفح: {error}", + "try_running_without_sudo_admin": "حاول التشغيل بدون امتيازات sudo/المسؤول", + "redirecting_to_authenticator_cursor_sh": "جارٍ إعادة التوجيه إلى authenticator.cursor.sh...", + "starting_google_authentication": "جارٍ بدء مصادقة Google...", + "starting_github_authentication": "جارٍ بدء مصادقة GitHub...", + "waiting_for_authentication": "في انتظار المصادقة...", + "page_changed_checking_auth": "تغيرت الصفحة، جارٍ التحقق من المصادقة...", + "status_check_error": "خطأ في فحص الحالة: {error}", + "authentication_timeout": "انتهت مهلة المصادقة", + "account_is_still_valid": "الحساب لا يزال صالحًا (الاستخدام: {usage})", + "starting_re_authentication_process": "جارٍ بدء عملية إعادة المصادقة...", + "starting_new_google_authentication": "جارٍ بدء مصادقة Google جديدة...", + "failed_to_delete_account_or_re_authenticate": "فشل حذف الحساب أو إعادة المصادقة: {error}", + "navigating_to_authentication_page": "جارٍ الانتقال إلى صفحة المصادقة...", + "please_select_your_google_account_to_continue": "يرجى اختيار حساب Google الخاص بك للمتابعة...", + "found_browser_data_directory": "تم العثور على دليل بيانات المتصفح: {path}", + "authentication_successful_getting_account_info": "تمت المصادقة بنجاح، جارٍ الحصول على معلومات الحساب...", + "warning_could_not_kill_existing_browser_processes": "تحذير: تعذر إنهاء عمليات المتصفح الحالية: {error}", + "browser_failed_to_start": "فشل بدء تشغيل المتصفح: {error}", + "browser_failed": "فشل بدء تشغيل المتصفح: {error}", + "browser_failed_to_start_fallback": "فشل بدء تشغيل المتصفح: {error}", + "user_data_dir_not_found": "لم يتم العثور على دليل بيانات مستخدم {browser} في {path}، سيتم تجربة Chrome بدلاً من ذلك", + "error_getting_user_data_directory": "خطأ في الحصول على دليل بيانات المستخدم: {error}", + "warning_browser_close": "تحذير: سيؤدي هذا إلى إغلاق جميع عمليات {browser} قيد التشغيل", + "killing_browser_processes": "جارٍ إنهاء عمليات {browser}...", + "profile_selection_error": "خطأ أثناء اختيار الملف الشخصي: {error}", + "using_configured_browser_path": "جارٍ استخدام مسار {browser} المُكوّن: {path}", + "browser_not_found_trying_chrome": "تعذر العثور على {browser}، جارٍ تجربة Chrome بدلاً من ذلك", + "found_chrome_at": "تم العثور على Chrome في: {path}", + "found_browser_user_data_dir": "تم العثور على دليل بيانات مستخدم {browser}: {path}" + }, + "browser_profile": { + "title": "اختيار ملف تعريف المتصفح", + "select_profile": "اختر ملف تعريف {browser} للاستخدام:", + "profile_list": "ملفات تعريف {browser} المتاحة:", + "default_profile": "ملف التعريف الافتراضي", + "profile": "ملف التعريف {number}", + "no_profiles": "لم يتم العثور على ملفات تعريف {browser}", + "error_loading": "خطأ في تحميل ملفات تعريف {browser}: {error}", + "profile_selected": "ملف التعريف المحدد: {profile}", + "invalid_selection": "اختيار غير صالح. يرجى المحاولة مرة أخرى." + }, + "account_delete": { + "title": "أداة حذف حساب Cursor المرتبط بـ Google", + "warning": "تحذير: سيؤدي هذا إلى حذف حساب Cursor الخاص بك بشكل دائم. لا يمكن التراجع عن هذا الإجراء.", + "cancelled": "تم إلغاء حذف الحساب.", + "starting_process": "جارٍ بدء عملية حذف الحساب...", + "google_button_not_found": "لم يتم العثور على زر تسجيل الدخول بـ Google", + "logging_in": "جارٍ تسجيل الدخول باستخدام Google...", + "waiting_for_auth": "في انتظار مصادقة Google...", + "login_successful": "تم تسجيل الدخول بنجاح", + "unexpected_page": "صفحة غير متوقعة بعد تسجيل الدخول: {url}", + "trying_settings": "جارٍ محاولة الانتقال إلى صفحة الإعدادات...", + "select_google_account": "يرجى اختيار حساب Google الخاص بك...", + "auth_timeout": "انتهت مهلة المصادقة، جارٍ المتابعة على أي حال...", + "navigating_to_settings": "جارٍ الانتقال إلى صفحة الإعدادات...", + "already_on_settings": "أنت بالفعل في صفحة الإعدادات", + "login_redirect_failed": "فشلت إعادة توجيه تسجيل الدخول، جارٍ محاولة التنقل المباشر...", + "advanced_tab_not_found": "لم يتم العثور على علامة التبويب المتقدمة بعد عدة محاولات", + "advanced_tab_retry": "لم يتم العثور على علامة التبويب المتقدمة، المحاولة {attempt}/{max_attempts}", + "advanced_tab_error": "خطأ في العثور على علامة التبويب المتقدمة: {error}", + "advanced_tab_clicked": "تم النقر على علامة التبويب المتقدمة", + "direct_advanced_navigation": "جارٍ محاولة التنقل المباشر إلى علامة التبويب المتقدمة", + "delete_button_not_found": "لم يتم العثور على زر حذف الحساب بعد عدة محاولات", + "delete_button_retry": "لم يتم العثور على زر الحذف، المحاولة {attempt}/{max_attempts}", + "delete_button_error": "خطأ في العثور على زر الحذف: {error}", + "delete_button_clicked": "تم النقر على زر حذف الحساب", + "found_danger_zone": "تم العثور على قسم المنطقة الخطرة", + "delete_input_not_found": "لم يتم العثور على حقل تأكيد الحذف بعد عدة محاولات", + "delete_input_retry": "لم يتم العثور على حقل الحذف، المحاولة {attempt}/{max_attempts}", + "delete_input_error": "خطأ في العثور على حقل الحذف: {error}", + "delete_input_not_found_continuing": "لم يتم العثور على حقل تأكيد الحذف، جارٍ محاولة المتابعة على أي حال", + "typed_delete": "تم كتابة \"Delete\" في مربع التأكيد", + "confirm_button_not_found": "لم يتم العثور على زر التأكيد بعد عدة محاولات", + "confirm_button_retry": "لم يتم العثور على زر التأكيد، المحاولة {attempt}/{max_attempts}", + "confirm_button_error": "خطأ في العثور على زر التأكيد: {error}", + "account_deleted": "تم حذف الحساب بنجاح!", + "error": "خطأ أثناء حذف الحساب: {error}", + "success": "تم حذف حساب Cursor الخاص بك بنجاح!", + "failed": "فشلت عملية حذف الحساب أو تم إلغاؤها.", + "interrupted": "تمت مقاطعة عملية حذف الحساب بواسطة المستخدم.", + "unexpected_error": "خطأ غير متوقع: {error}", + "found_email": "تم العثور على البريد الإلكتروني: {email}", + "email_not_found": "لم يتم العثور على البريد الإلكتروني: {error}", + "confirm_prompt": "هل أنت متأكد أنك تريد المتابعة؟ (y/N): " + }, + "bypass": { + "starting": "جارٍ بدء تجاوز إصدار Cursor...", + "found_product_json": "تم العثور على product.json: {path}", + "no_write_permission": "لا توجد صلاحية كتابة للملف: {path}", + "read_failed": "فشلت قراءة product.json: {error}", + "current_version": "الإصدار الحالي: {version}", + "backup_created": "تم إنشاء نسخة احتياطية: {path}", + "version_updated": "تم تحديث الإصدار من {old} إلى {new}", + "write_failed": "فشلت كتابة product.json: {error}", + "no_update_needed": "لا يلزم التحديث. الإصدار الحالي {version} بالفعل >= 0.46.0", + "bypass_failed": "فشل تجاوز الإصدار: {error}", + "stack_trace": "تتبع المكدس", + "localappdata_not_found": "لم يتم العثور على متغير بيئة LOCALAPPDATA", + "product_json_not_found": "لم يتم العثور على product.json في مسارات Linux الشائعة", + "unsupported_os": "نظام تشغيل غير مدعوم: {system}", + "file_not_found": "لم يتم العثور على الملف: {path}", + "title": "أداة تجاوز إصدار Cursor", + "description": "تقوم هذه الأداة بتعديل ملف product.json الخاص بـ Cursor لتجاوز قيود الإصدار", + "menu_option": "تجاوز فحص إصدار Cursor" + }, + "auth_check": { + "checking_authorization": "جارٍ التحقق من التصريح...", + "token_source": "الحصول على الرمز من قاعدة البيانات أو إدخاله يدوياً؟ (d/m، الافتراضي: d)", + "getting_token_from_db": "جارٍ الحصول على الرمز من قاعدة البيانات...", + "token_found_in_db": "تم العثور على الرمز في قاعدة البيانات", + "token_not_found_in_db": "لم يتم العثور على الرمز في قاعدة البيانات", + "cursor_acc_info_not_found": "لم يتم العثور على cursor_acc_info.py", + "error_getting_token_from_db": "خطأ في الحصول على الرمز من قاعدة البيانات: {error}", + "enter_token": "أدخل رمز Cursor الخاص بك: ", + "token_length": "طول الرمز: {length} حرفاً", + "usage_response_status": "حالة استجابة الاستخدام: {response}", + "unexpected_status_code": "رمز حالة غير متوقع: {code}", + "jwt_token_warning": "يبدو أن الرمز بتنسيق JWT، لكن فحص API أعاد رمز حالة غير متوقع. قد يكون الرمز صالحاً ولكن الوصول إلى API مقيد.", + "invalid_token": "رمز غير صالح", + "user_authorized": "المستخدم مصرح له", + "user_unauthorized": "المستخدم غير مصرح له", + "request_timeout": "انتهت مهلة الطلب", + "connection_error": "خطأ في الاتصال", + "check_error": "خطأ في التحقق من التصريح: {error}", + "authorization_successful": "تم التصريح بنجاح!", + "authorization_failed": "فشل التصريح!", + "operation_cancelled": "تم إلغاء العملية بواسطة المستخدم", + "unexpected_error": "خطأ غير متوقع: {error}", + "error_generating_checksum": "خطأ في إنشاء المجموع الاختباري: {error}", + "checking_usage_information": "جارٍ التحقق من معلومات الاستخدام...", + "check_usage_response": "استجابة فحص الاستخدام: {response}", + "usage_response": "استجابة الاستخدام: {response}" + }, + "bypass_token_limit": { + "title": "أداة تجاوز حد الرمز", + "description": "تقوم هذه الأداة بتعديل ملف workbench.desktop.main.js لتجاوز حد الرمز", + "press_enter": "اضغط Enter للمتابعة..." + }, + "token": { + "refreshing": "جارٍ تحديث الرمز...", + "refresh_success": "تم تحديث الرمز بنجاح! صالح لمدة {days} يوماً (تاريخ انتهاء الصلاحية: {expire})", + "no_access_token": "لا يوجد رمز وصول في الاستجابة", + "refresh_failed": "فشل تحديث الرمز: {error}", + "invalid_response": "استجابة JSON غير صالحة من خادم التحديث", + "server_error": "خطأ في خادم التحديث: HTTP {status}", + "request_timeout": "انتهت مهلة طلب خادم التحديث", + "connection_error": "خطأ في الاتصال بخادم التحديث", + "unexpected_error": "خطأ غير متوقع أثناء تحديث الرمز: {error}", + "extraction_error": "خطأ في استخراج الرمز: {error}" + } +} \ No newline at end of file diff --git a/locales/en.json b/locales/en.json index bbf35a9..b91c396 100644 --- a/locales/en.json +++ b/locales/en.json @@ -48,7 +48,8 @@ "ru": "Russian", "tr": "Turkish", "bg": "Bulgarian", - "es": "Spanish" + "es": "Spanish", + "ar": "Arabic" }, "quit_cursor": { "start": "Start Quitting Cursor", diff --git a/locales/vi.json b/locales/vi.json index 14d0198..960f684 100644 --- a/locales/vi.json +++ b/locales/vi.json @@ -47,7 +47,8 @@ "fr": "Tiếng Pháp", "pt": "Tiếng Bồ Đào Nha", "ru": "Tiếng Nga", - "es": "Tiếng Tây Ban Nha" + "es": "Tiếng Tây Ban Nha", + "ar": "Tiếng Ả Rập" }, "quit_cursor": { "start": "Bắt Đầu Thoát Cursor", diff --git a/main.py b/main.py index ad8093e..f9dea55 100644 --- a/main.py +++ b/main.py @@ -14,6 +14,14 @@ import shutil import re from utils import get_user_documents_path +# Add these imports for Arabic support +try: + import arabic_reshaper + from bidi.algorithm import get_display +except ImportError: + arabic_reshaper = None + get_display = None + # Only import windll on Windows systems if platform.system() == 'Windows': import ctypes @@ -156,6 +164,8 @@ class Translator: return 'tr' # Turkish case 0x0402: return 'bg' # Bulgarian + case 0x0401: + return 'ar' # Arabic case _: return 'en' # Default to English except: @@ -196,6 +206,8 @@ class Translator: return 'tr' case s if s.startswith('bg'): return 'bg' + case s if s.startswith('ar'): + return 'ar' case _: # Try to get language from LANG environment variable as fallback env_lang = os.getenv('LANG', '').lower() @@ -220,126 +232,66 @@ class Translator: return 'tr' case s if 'bg' in s: return 'bg' + case s if 'ar' in s: + return 'ar' case _: return 'en' except: return 'en' def download_language_file(self, lang_code): - """Download language file from GitHub and save to cache""" - try: - if not self.language_cache_dir: - print(f"{Fore.RED}{EMOJI['ERROR']} Language cache directory not configured{Style.RESET_ALL}") - return False - - # Create the cache directory if it doesn't exist - os.makedirs(self.language_cache_dir, exist_ok=True) + """Method kept for compatibility but now returns False as language files are integrated""" + print(f"{Fore.YELLOW}{EMOJI['INFO']} Languages are now integrated into the package, no need to download.{Style.RESET_ALL}") + return False - # GitHub raw content URL for language file - github_url = f"https://raw.githubusercontent.com/yeongpin/cursor-free-vip/main/locales/{lang_code}.json" - - print(f"{Fore.CYAN}{EMOJI['INFO']} Downloading language file: {lang_code}.json...{Style.RESET_ALL}") - - # Set up proper headers for GitHub API - headers = { - 'Accept': 'application/vnd.github.v3.raw', - 'User-Agent': 'Cursor-Free-VIP-App' - } - - # Request the file with timeout - response = requests.get(github_url, headers=headers, timeout=10) - - # Check if successful - if response.status_code == 200: - # Save the content to the cache file - cache_file_path = os.path.join(self.language_cache_dir, f"{lang_code}.json") - with open(cache_file_path, 'wb') as f: - f.write(response.content) - - # Load the data into translations dictionary - try: - self.translations[lang_code] = json.loads(response.content) - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Successfully downloaded and loaded: {lang_code}.json{Style.RESET_ALL}") - return True - except json.JSONDecodeError: - print(f"{Fore.RED}{EMOJI['ERROR']} Downloaded file is not valid JSON: {lang_code}.json{Style.RESET_ALL}") - return False - else: - print(f"{Fore.RED}{EMOJI['ERROR']} Failed to download language file: {lang_code}.json (Status code: {response.status_code}){Style.RESET_ALL}") - return False - - except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} Error downloading language file: {e}{Style.RESET_ALL}") - return False - def load_translations(self): - """Load all available translations with GitHub fallback""" + """Load all available translations from the integrated package""" try: # Collection of languages we've successfully loaded loaded_languages = set() - # First try to load from local directory - locales_dir = os.path.join(os.path.dirname(__file__), 'locales') + locales_paths = [] + + # Check for PyInstaller bundle first if hasattr(sys, '_MEIPASS'): - locales_dir = os.path.join(sys._MEIPASS, 'locales') + locales_paths.append(os.path.join(sys._MEIPASS, 'locales')) - # Check if local directory exists - if os.path.exists(locales_dir): - for file in os.listdir(locales_dir): - if file.endswith('.json'): - lang_code = file[:-5] # Remove .json - try: - with open(os.path.join(locales_dir, file), 'r', encoding='utf-8') as f: - self.translations[lang_code] = json.load(f) - loaded_languages.add(lang_code) - except (json.JSONDecodeError, UnicodeDecodeError) as e: - print(f"{Fore.RED}{EMOJI['ERROR']} Error loading {file}: {e}{Style.RESET_ALL}") - continue - else: - print(f"{Fore.YELLOW}{EMOJI['WARNING']} Locales directory not found, checking cache and GitHub...{Style.RESET_ALL}") - - # Next, check for cached files - if self.language_cache_dir and os.path.exists(self.language_cache_dir): - for file in os.listdir(self.language_cache_dir): - if file.endswith('.json'): - lang_code = file[:-5] # Remove .json - - # Skip if we already loaded this language - if lang_code in loaded_languages: - continue - - try: - with open(os.path.join(self.language_cache_dir, file), 'r', encoding='utf-8') as f: - self.translations[lang_code] = json.load(f) - loaded_languages.add(lang_code) - except (json.JSONDecodeError, UnicodeDecodeError) as e: - print(f"{Fore.RED}{EMOJI['ERROR']} Error loading cached {file}: {e}{Style.RESET_ALL}") - continue - - # Finally, if we're missing essential languages, try to download them - if self.config and self.config.has_section('Language') and self.config.getboolean('Language', 'auto_update_languages', fallback=True): - essential_languages = ['en', 'zh_cn', 'zh_tw', 'vi'] - - # Add current language and fallback language to essential list if they're not already in - if self.current_language and self.current_language not in essential_languages: - essential_languages.append(self.current_language) - if self.fallback_language and self.fallback_language not in essential_languages: - essential_languages.append(self.fallback_language) - - for lang_code in essential_languages: - if lang_code not in loaded_languages: - print(f"{Fore.YELLOW}{EMOJI['INFO']} Missing essential language: {lang_code}, attempting to download...{Style.RESET_ALL}") - self.download_language_file(lang_code) + # Check script directory next + script_dir = os.path.dirname(os.path.abspath(__file__)) + locales_paths.append(os.path.join(script_dir, 'locales')) - # If we have no translations at all, it's a critical error - if not self.translations: - print(f"{Fore.RED}{EMOJI['ERROR']} Failed to load any translations! The application may not function correctly.{Style.RESET_ALL}") - + # Also check current working directory + locales_paths.append(os.path.join(os.getcwd(), 'locales')) + + for locales_dir in locales_paths: + if os.path.exists(locales_dir) and os.path.isdir(locales_dir): + for file in os.listdir(locales_dir): + if file.endswith('.json'): + lang_code = file[:-5] # Remove .json + try: + with open(os.path.join(locales_dir, file), 'r', encoding='utf-8') as f: + self.translations[lang_code] = json.load(f) + loaded_languages.add(lang_code) + loaded_any = True + except (json.JSONDecodeError, UnicodeDecodeError) as e: + print(f"{Fore.RED}{EMOJI['ERROR']} Error loading {file}: {e}{Style.RESET_ALL}") + continue + except Exception as e: print(f"{Fore.RED}{EMOJI['ERROR']} Failed to load translations: {e}{Style.RESET_ALL}") # Create at least minimal English translations for basic functionality self.translations['en'] = {"menu": {"title": "Menu", "exit": "Exit", "invalid_choice": "Invalid choice"}} + def fix_arabic(self, text): + if self.current_language == 'ar' and arabic_reshaper and get_display: + try: + reshaped_text = arabic_reshaper.reshape(text) + bidi_text = get_display(reshaped_text) + return bidi_text + except Exception: + return text + return text + def get(self, key, **kwargs): """Get translated text with fallback support""" try: @@ -348,7 +300,8 @@ class Translator: if result == key and self.current_language != self.fallback_language: # Try fallback language if translation not found result = self._get_translation(self.fallback_language, key) - return result.format(**kwargs) if kwargs else result + formatted = result.format(**kwargs) if kwargs else result + return self.fix_arabic(formatted) except Exception: return key @@ -374,49 +327,10 @@ class Translator: return False def get_available_languages(self): - """Get list of available languages, checking GitHub for updates if configured""" + """Get list of available languages""" # Get currently loaded languages available_languages = list(self.translations.keys()) - # Check if automatic language updates are enabled - if (self.config and self.config.has_section('Language') and - self.config.getboolean('Language', 'auto_update_languages', fallback=True)): - - try: - # GitHub API URL to get directory listing of language files - github_url = "https://api.github.com/repos/yeongpin/cursor-free-vip/contents/locales" - - # Set up proper headers for GitHub API - headers = { - 'Accept': 'application/vnd.github.v3+json', - 'User-Agent': 'Cursor-Free-VIP-App' - } - - # Request the directory listing with timeout - response = requests.get(github_url, headers=headers, timeout=10) - - # Check if successful - if response.status_code == 200: - github_files = response.json() - - # Extract language codes from JSON files in the repository - github_languages = [] - for file_info in github_files: - if file_info.get('type') == 'file' and file_info.get('name', '').endswith('.json'): - lang_code = file_info.get('name')[:-5] # Remove .json extension - github_languages.append(lang_code) - - # Check for languages available on GitHub but not loaded locally - for lang_code in github_languages: - if lang_code not in available_languages: - # Download the missing language file - if self.download_language_file(lang_code): - available_languages.append(lang_code) - - except Exception as e: - # Just log the error but continue with local languages - print(f"{Fore.YELLOW}{EMOJI['INFO']} Could not check for additional languages from GitHub: {e}{Style.RESET_ALL}") - # Sort languages alphabetically for better display return sorted(available_languages) From 9abf4f4899753784f64552ff689bc2443c7f6793 Mon Sep 17 00:00:00 2001 From: TranMC Date: Wed, 23 Apr 2025 12:58:24 +0700 Subject: [PATCH 6/6] Change something in language file --- locales/en.json | 3 +-- locales/vi.json | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/locales/en.json b/locales/en.json index 6ee2f7f..6aada5f 100644 --- a/locales/en.json +++ b/locales/en.json @@ -49,8 +49,7 @@ "ru": "Russian", "tr": "Turkish", "bg": "Bulgarian", - "es": "Spanish", - "ar": "Arabic" + "es": "Spanish" }, "quit_cursor": { "start": "Start Quitting Cursor", diff --git a/locales/vi.json b/locales/vi.json index eaab795..2962511 100644 --- a/locales/vi.json +++ b/locales/vi.json @@ -48,8 +48,7 @@ "fr": "Tiếng Pháp", "pt": "Tiếng Bồ Đào Nha", "ru": "Tiếng Nga", - "es": "Tiếng Tây Ban Nha", - "ar": "Tiếng Ả Rập" + "es": "Tiếng Tây Ban Nha" }, "quit_cursor": { "start": "Bắt Đầu Thoát Cursor",