Compare commits

...

13 Commits

Author SHA1 Message Date
Zamitto
59bc23bbd8 Merge pull request #1367 from hydralauncher/fix/issues
fix: issues
2025-01-01 20:32:05 -03:00
Zamitto
16b50fc22b feat: remove launch options temporarily 2025-01-01 20:19:57 -03:00
Zamitto
720a7aa2a0 chore: bump version 2025-01-01 19:53:48 -03:00
Zamitto
5c2bafcfe8 Merge pull request #1371 from hydralauncher/feature/adding-sentry
Feature/adding sentry
2025-01-01 19:48:17 -03:00
Chubby Granny Chaser
c30c685ee4 fix: fixing translation 2025-01-01 21:50:26 +00:00
Chubby Granny Chaser
fba86002d1 feat: adding translation for button 2025-01-01 21:38:28 +00:00
Chubby Granny Chaser
a121ef77c0 feat: adding translation for button 2025-01-01 21:32:22 +00:00
Chubby Granny Chaser
bd653be071 Merge branch 'main' into fix/issues 2025-01-01 21:31:36 +00:00
Zamitto
297ca5a190 Merge pull request #1369 from 7ROBE/patch-6
Update ar translation.json
2025-01-01 10:31:04 -03:00
7ROBE
6278600b98 Update translation.json 2025-01-01 11:11:41 +03:00
Zamitto
1226483deb fix: open game with parameters 2024-12-31 19:38:17 -03:00
Zamitto
0661cbd661 fix: steamGenres 2024-12-31 19:32:41 -03:00
Zamitto
ad204e3879 fix: issues 2024-12-31 14:06:44 -03:00
31 changed files with 574 additions and 466 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "hydralauncher",
"version": "3.1.4",
"version": "3.1.5",
"description": "Hydra",
"main": "./out/main/index.js",
"author": "Los Broxas",
@@ -47,13 +47,13 @@
"auto-launch": "^5.0.6",
"axios": "^1.7.9",
"better-sqlite3": "^11.7.0",
"check-disk-space": "^3.4.0",
"classnames": "^2.5.1",
"color": "^4.2.3",
"color.js": "^1.2.0",
"create-desktop-shortcuts": "^1.11.0",
"date-fns": "^3.6.0",
"dexie": "^4.0.10",
"diskusage": "^1.2.0",
"electron-log": "^5.2.4",
"electron-updater": "^6.3.9",
"file-type": "^19.6.0",

View File

@@ -4,399 +4,414 @@
"successfully_signed_in": "تم تسجيل الدخول بنجاح"
},
"home": {
"featured": ميّز",
"surprise_me": "فاجئني",
"no_results": م يتم العثور على نتائج",
"start_typing": "بدء الكتابة للبحث...",
"hot": "الأكثر رواجا الآن",
"weekly": "📅 أفضل ألعاب الأسبوع",
"achievements": "🏆 ألعاب للتغلب عليها"
"featured": ُتَمَيِّز",
"surprise_me": َاجِئْنِي",
"no_results": َمْ يُعْثَرْ عَلَى نَتائِج",
"start_typing": "اِبْدَأْ بِالْكِتَابَةِ لِلْبَحْثِ...",
"hot": "اَلْأَكْثَرُ شُيُوعًا الْآن",
"weekly": "📅 أَفْضَلُ أَلْعَابِ الْأُسْبُوعِ",
"achievements": "🏆 أَلْعَابٌ لِلتَّغَلُّبِ عَلَيْهَا"
},
"sidebar": {
"catalogue": "قائمة الألعاب",
"downloads": "التنزيلات",
"settings": "إعدادات",
"my_library": كتبتي",
"downloading_metadata": "{{title}} (جارٍ تنزيل البيانات الوصفية...)",
"paused": "{{title}} (متوقف مؤقتًا)",
"downloading": "{{title}} ({{percentage}} - جاري التنزيل...)",
"filter": "بحث في المكتبة",
"home": "الرئيسية",
"queued": "{{title}} (في قائمة الانتظار)",
"game_has_no_executable": "لم يتم تحديد اللعبة القابلة للتنفيذ",
"sign_in": سجيل الدخول",
"friends": "أصدقاء",
"need_help": "بحاجة الى مساعدة؟"
"catalogue": "الْفِهْرِسُ",
"downloads": "التَّنْزِيلَاتُ",
"settings": "الإعْدَادَاتُ",
"my_library": َكْتَبَتِي",
"downloading_metadata": "{{title}} (جَارٍ تَنْزِيلُ الْبَيَانَاتِ الْوَصْفِيَّةِ...)",
"paused": "{{title}} (مُوْقَفٌ)",
"downloading": "{{title}} ({{percentage}} - جَارٍ التَّنْزِيلُ...)",
"filter": "تَصْفِيَةُ الْمَكْتَبَةِ",
"home": "الرَّئِيسِيَّةُ",
"queued": "{{title}} (فِي الْانْتِظَارِ)",
"game_has_no_executable": "اللُّعْبَةُ لَيْسَ لَدَيْهَا مِلَفٌّ تَنْفِيذِيٌّ مُحَدَّدٌ",
"sign_in": َسْجِيلُ الدُّخُولِ",
"friends": "الْأَصْدِقَاءُ",
"need_help": "هَلْ تَحْتَاجُ إِلَى مُسَاعَدَةٍ؟"
},
"header": {
"search": "ابحث عن الألعاب",
"home": "الرئيسية",
"catalogue": "قائمة الألعاب",
"downloads": "التنزيلات",
"search_results": "نتائج البحث",
"settings": "إعدادات",
"version_available_install": "إصدار {{version}} متاح. ",
"version_available_download": "إصدار {{version}} متاح. "
"search": "بَحْثُ الْأَلْعَابِ",
"home": "الرَّئِيسِيَّةُ",
"catalogue": "الْفِهْرِسُ",
"downloads": "التَّنْزِيلَاتُ",
"search_results": َتائِجُ الْبَحْثِ",
"settings": "الإعْدَادَاتُ",
"version_available_install": "الْإِصْدَارُ {{version}} مَتَوَفِّرٌ. انْقُرْ هُنَا لِإِعَادَةِ التَّشْغِيلِ وَالتَّثْبِيتِ.",
"version_available_download": "الْإِصْدَارُ {{version}} مَتَوَفِّرٌ. انْقُرْ هُنَا لِلتَّنْزِيلِ."
},
"bottom_panel": {
"no_downloads_in_progress": "لا توجد تنزيلات قيد التقدم",
"downloading_metadata": "جارٍ التنزيل {{title}} البيانات الوصفية...",
"downloading": "جارٍ التنزيل {{title}} ({{percentage}} مكتملة) - الانتهاء {{eta}} - {{speed}}",
"calculating_eta": "جارٍ التنزيل {{title}} ({{percentage}} مكتمل) - حساب الوقت المتبقي...",
"checking_files": "التحقق {{title}} ملفات…({{percentage}} مكتمل)"
"no_downloads_in_progress": َا تَوْجَدُ تَنْزِيلَاتٌ جَارِيَةٌ",
"downloading_metadata": َارٍ تَنْزِيلُ الْبَيَانَاتِ الْوَصْفِيَّةِ لِـ {{title}}...",
"downloading": َارٍ تَنْزِيلُ {{title}}... ({{percentage}} مَكْتُومٌ) - الِاكْتِمَالُ {{eta}} - {{speed}}",
"calculating_eta": َارٍ تَنْزِيلُ {{title}}... ({{percentage}} مَكْتُومٌ) - جَارٍ حِسَابُ الْوَقْتِ الْمُتَبَقِّي...",
"checking_files": "جَارٍ التَّحَقُّقُ مِنْ مَلَفَّاتِ {{title}}... ({{percentage}} مَكْتُومٌ)"
},
"catalogue": {
"next_page": "الصفحة التالية",
"previous_page": "الصفحة السابقة"
"search": "تَصْفِيَةٌ...",
"developers": "الْمُطَوِّرُونَ",
"genres": "الْأَنْوَاعُ",
"tags": "الْعَلَامَاتُ",
"publishers": "النَّاشِرُونَ",
"download_sources": "مَصَادِرُ التَّنْزِيلِ",
"result_count": "{{resultCount}} نَتائِجُ",
"filter_count": "{{filterCount}} مَتَوَفِّرٌ",
"clear_filters": "مَسْحُ {{filterCount}} الْمُخْتَارَةِ"
},
"game_details": {
"open_download_options": "افتح خيارات التنزيل",
"download_options_zero": "{{count}} خيارات التنزيل",
"updated_at": "تم التحديث {{updated_at}}",
"install": "ثَبَّتَ",
"resume": "استئناف",
"pause": "إيقاف",
"cancel": "إلغاء",
"remove": زالة",
"space_left_on_disk": "{{space}} متبقية على القرص",
"eta": "الوقت المتبقي {{eta}}",
"calculating_eta": "جارٍ حساب الوقت المتبقي…",
"downloading_metadata": "جارٍ تنزيل البيانات الوصفية…",
"filter": "إعادة حزم التصفية",
"requirements": "متطلبات النظام",
"minimum": "الحد الأدنى",
"recommended": "مُستَحسَن",
"paused": "متوقف مؤقتًا",
"release_date": "صدر بتاريخ {{date}}",
"publisher": "نشرت من قبل {{publisher}}",
"hours": "ساعات",
"minutes": "دقائق",
"amount_hours": "{{amount}} ساعات",
"amount_minutes": "{{amount}} دقائق",
"accuracy": "{{accuracy}}٪ دقة",
"add_to_library": "أضف إلى المكتبة",
"remove_from_library": "إزالة من المكتبة",
"no_downloads": "لا التنزيلات المتاحة",
"play_time": "تم اللعب لمدة {{amount}}",
"last_time_played": "لعبت آخر مرة {{period}}",
"not_played_yet": "أنت لم تلعب {{title}} حتى الآن",
"next_suggestion": "الاقتراح التالي",
"play": "لعب",
"deleting": "جارٍ حذف المثبت…",
"close": "إغلاق",
"playing_now": "قيداللعب الآن",
"change": "تغيير",
"repacks_modal_description": "اختر الحزمة التي تريد تنزيلها",
"select_folder_hint": "لتغيير المجلد الافتراضي، انتقل إلى <0>إعدادات</0>",
"download_now": "قم بالتنزيل الآن",
"no_shop_details": "لا يمكن استرداد تفاصيل المتجر.",
"download_options": "خيارات التنزيل",
"download_path": "مسار التحميل",
"previous_screenshot": "لقطة الشاشة السابقة",
"next_screenshot": "لقطة الشاشة التالية",
"screenshot": قطة الشاشة {{number}}",
"open_screenshot": "فتح لقطة الشاشة {{number}}",
"download_settings": "تحميل الإعدادات",
"downloader": "أداة التنزيل",
"select_executable": "يختار",
"no_executable_selected": "لم يتم تحديد أي ملف قابل للتنفيذ",
"open_folder": "افتح المجلد",
"open_download_location": "انظر الملفات التي تم تنزيلها",
"create_shortcut": "إنشاء اختصار سطح المكتب",
"clear": "واضح",
"remove_files": "إزالة الملفات",
"remove_from_library_title": "هل أنت متأكد؟",
"remove_from_library_description": "سيتم إزالة هذا {{game}} من مكتبتك",
"options": "خيارات",
"executable_section_title": "قابل للتنفيذ",
"executable_section_description": "مسار الملف الذي سيتم تنفيذه عند النقر فوق \"تشغيل\".",
"downloads_secion_title": "التنزيلات",
"downloads_section_description": "تحقق من التحديثات أو الإصدارات الأخرى من هذه اللعبة",
"danger_zone_section_title": "منطقة الخطر",
"danger_zone_section_description": "قم بإزالة هذه اللعبة من مكتبتك أو الملفات التي تم تنزيلها بواسطة Hydra",
"download_in_progress": "التنزيل قيد التقدم",
"download_paused": "تم إيقاف التنزيل مؤقتًا",
"last_downloaded_option": "آخر خيار تم تنزيله",
"create_shortcut_success": "تم إنشاء الاختصار بنجاح",
"create_shortcut_error": "حدث خطأ أثناء إنشاء الاختصار",
"nsfw_content_title": "تحتوي هذه اللعبة على محتوى غير مناسب",
"nsfw_content_description": "{{title}} يحتوي على محتوى قد لا يكون مناسبًا لجميع الأعمار. ",
"allow_nsfw_content": "اسمح",
"refuse_nsfw_content": "عُد",
"stats": "احصائيات",
"download_count": "التنزيلات",
"player_count": "اللاعبين النشطين",
"download_error": "خيار التنزيل هذا غير متوفر",
"download": "تحميل",
"executable_path_in_use": "قابل للتنفيذ قيد الاستخدام بالفعل بواسطة \"{{game}}\"",
"warning": حذير:",
"hydra_needs_to_remain_open": "لإجراء هذا التنزيل، يجب أن يظل Hydra مفتوحًا حتى اكتماله. ",
"achievements": "الإنجازات",
"achievements_count": "الإنجازات {{unlockedCount}}/{{achievementsCount}}",
"cloud_save": "حفظ السحابة",
"cloud_save_description": "احفظ تقدمك في السحابة واستمر في اللعب على أي جهاز",
"backups": "النسخ الاحتياطية",
"install_backup": "ثَبَّتَ",
"delete_backup": "يمسح",
"create_backup": "نسخة احتياطية جديدة",
"last_backup_date": "آخر نسخة احتياطية قيد التشغيل {{date}}",
"no_backup_preview": "لم يتم العثور على ألعاب محفوظة لهذا العنوان",
"restoring_backup": "استعادة النسخة الاحتياطية ({{progress}} مكتمل)…",
"uploading_backup": "جارٍ تحميل النسخة الاحتياطية…",
"no_backups": "لم تقم بإنشاء أي نسخ احتياطية لهذه اللعبة حتى الآن",
"backup_uploaded": "تم تحميل النسخة الاحتياطية",
"backup_deleted": "تم حذف النسخة الاحتياطية",
"backup_restored": مت استعادة النسخة الاحتياطية",
"see_all_achievements": "شاهد جميع الإنجازات",
"sign_in_to_see_achievements": "قم بتسجيل الدخول لرؤية الإنجازات",
"mapping_method_automatic": "تلقائي",
"mapping_method_manual": "يدوي",
"mapping_method_label": "طريقة رسم الخرائط",
"files_automatically_mapped": "تم تعيين الملفات تلقائيًا",
"no_backups_created": "لم يتم إنشاء نسخ احتياطية لهذه اللعبة",
"manage_files": "إدارة الملفات",
"loading_save_preview": "جارٍ البحث عن حفظ الألعاب...",
"wine_prefix": "بادئة النبيذ",
"wine_prefix_description": "بادئة Wine المستخدمة لتشغيل هذه اللعبة",
"no_download_option_info": "لا توجد معلومات متاحة",
"backup_deletion_failed": "فشل في حذف النسخة الاحتياطية",
"max_number_of_artifacts_reached": "تم الوصول إلى الحد الأقصى لعدد النسخ الاحتياطية لهذه اللعبة",
"achievements_not_sync": "لا تتم مزامنة إنجازاتك",
"manage_files_description": "إدارة الملفات التي سيتم نسخها احتياطيًا واستعادتها",
"select_folder": "حدد المجلد",
"backup_from": "نسخة احتياطية من {{date}}",
"custom_backup_location_set": "تعيين موقع النسخ الاحتياطي المخصص",
"no_directory_selected": "لم يتم تحديد أي دليل",
"download_options_one": "{{count}} خيار التنزيل",
"download_options_two": "{{count}} خيارات التنزيل",
"download_options_few": "{{count}} خيارات التنزيل",
"download_options_many": "{{count}} خيارات التنزيل",
"download_options_other": "{{count}} خيارات التنزيل"
"open_download_options": "فَتْحُ خِيَارَاتِ التَّنْزِيلِ",
"download_options_zero": "لَا تَوْجَدُ خِيَارَاتُ تَنْزِيلٍ",
"download_options_one": "{{count}} خِيَارُ تَنْزِيلٍ",
"download_options_other": "{{count}} خِيَارَاتُ تَنْزِيلٍ",
"updated_at": "تَمَّ التَّحْدِيثُ فِي {{updated_at}}",
"install": "تَثْبِيتٌ",
"resume": "اسْتِئْنَافٌ",
"pause": ِيقَافٌ",
"cancel": "إِلْغَاءٌ",
"remove": "إِزَالَةٌ",
"space_left_on_disk": "{{space}} مُتَبَقٍّ عَلَى الْقُرْصِ",
"eta": "الِاكْتِمَالُ {{eta}}",
"calculating_eta": "جَارٍ حِسَابُ الْوَقْتِ الْمُتَبَقِّي...",
"downloading_metadata": "جَارٍ تَنْزِيلُ الْبَيَانَاتِ الْوَصْفِيَّةِ...",
"filter": "تَصْفِيَةُ الْإِصْدَارَاتِ الْمُعَادِ تَغْلِيفُهَا",
"requirements": "مُتَطَلَّبَاتُ النِّظَامِ",
"minimum": "الْأَدْنَى",
"recommended": "الْمُوَصَّى بِهِ",
"paused": "مُوْقَفٌ",
"release_date": "تَمَّ الْإِصْدَارُ فِي {{date}}",
"publisher": "نُشِرَ بِوَاسِطَةِ {{publisher}}",
"hours": َاعَاتٌ",
"minutes": "دَقَائِقُ",
"amount_hours": "{{amount}} سَاعَاتٌ",
"amount_minutes": "{{amount}} دَقَائِقُ",
"accuracy": "دِقَّةٌ {{accuracy}}%",
"add_to_library": "إِضَافَةٌ إِلَى الْمَكْتَبَةِ",
"remove_from_library": "إِزَالَةٌ مِنَ الْمَكْتَبَةِ",
"no_downloads": "لَا تَوْجَدُ تَنْزِيلَاتٌ مَتَوَفِّرَةٌ",
"play_time": "لُعِبَ لِمُدَّةِ {{amount}}",
"last_time_played": "آخِرُ مَرَّةٍ لُعِبَتْ {{period}}",
"not_played_yet": "لَمْ تَلْعَبْ {{title}} بَعْدُ",
"next_suggestion": "الِاقْتِرَاحُ التَّالِي",
"play": "لَعِبٌ",
"deleting": "جَارٍ حَذْفُ الْمُثَبِّتِ...",
"close": "إِغْلَاقٌ",
"playing_now": "جَارِي اللَّعِبُ الْآن",
"change": "تَغْيِيرٌ",
"repacks_modal_description": "اخْتَرِ الْإِصْدَارَ الْمُعَادَ تَغْلِيفُهُ الَّذِي تُرِيدُ تَنْزِيلَهُ",
"select_folder_hint": "لِتَغْيِيرِ الْمَجَلَّدِ الافْتِرَاضِيِّ، اذْهَبْ إِلَى <0>الإعْدَادَاتِ</0>",
"download_now": "تَنْزِيلٌ الْآن",
"no_shop_details": "لَمْ يَتَمَكَّنْ مِنْ اسْتِرْدَادِ تَفَاصِيلِ الْمَتْجَرِ.",
"download_options": "خِيَارَاتُ التَّنْزِيلِ",
"download_path": "مَسَارُ التَّنْزِيلِ",
"previous_screenshot": َقْطَةُ الشَّاشَةِ السَّابِقَةُ",
"next_screenshot": "لَقْطَةُ الشَّاشَةِ التَّالِيَةُ",
"screenshot": "لَقْطَةُ الشَّاشَةِ {{number}}",
"open_screenshot": "فَتْحُ لَقْطَةِ الشَّاشَةِ {{number}}",
"download_settings": "إعْدَادَاتُ التَّنْزِيلِ",
"downloader": "الْمُنَزِّلُ",
"select_executable": "تَحْدِيدٌ",
"no_executable_selected": "لَمْ يُحَدَّدْ مِلَفٌّ تَنْفِيذِيٌّ",
"open_folder": "فَتْحُ الْمَجَلَّدِ",
"open_download_location": "مُشَاهَدَةُ الْمَلَفَّاتِ الْمُنَزَّلَةِ",
"create_shortcut": "إِنْشَاءُ طَرِيقٍ مُخْتَصَرٍ عَلَى سَطْحِ الْمَكْتَبِ",
"clear": "مَسْحٌ",
"remove_files": "إِزَالَةُ الْمَلَفَّاتِ",
"remove_from_library_title": "هَلْ أَنْتَ مُتَأَكِّدٌ؟",
"remove_from_library_description": "سَيُؤَدِّي هَذَا إِلَى إِزَالَةِ {{game}} مِنْ مَكْتَبَتِكَ",
"options": "خِيَارَاتٌ",
"executable_section_title": "الْمِلَفُّ التَّنْفِيذِيُّ",
"executable_section_description": "مَسَارُ الْمِلَفِّ الَّذِي سَيَتِمُّ تَنْفِيذُهُ عِنْدَ النَّقْرِ عَلَى \"لَعِبٌ\"",
"downloads_secion_title": "التَّنْزِيلَاتُ",
"downloads_section_description": "تَحَقَّقْ مِنَ التَّحْدِيثَاتِ أَوِ الْإِصْدَارَاتِ الْأُخْرَى لِهَذِهِ اللُّعْبَةِ",
"danger_zone_section_title": "مِنْطَقَةُ الْخَطَرِ",
"danger_zone_section_description": "إِزَالَةُ هَذِهِ اللُّعْبَةِ مِنْ مَكْتَبَتِكَ أَوِ الْمَلَفَّاتِ الْمُنَزَّلَةِ بِوَاسِطَةِ Hydra",
"download_in_progress": "جَارٍ التَّنْزِيلُ",
"download_paused": "التَّنْزِيلُ مُوْقَفٌ",
"last_downloaded_option": "خِيَارُ التَّنْزِيلِ الْأَخِيرُ",
"create_shortcut_success": "تَمَّ إِنْشَاءُ الطَّرِيقِ الْمُخْتَصَرِ بِنَجَاحٍ",
"create_shortcut_error": "خَطَأٌ فِي إِنْشَاءِ الطَّرِيقِ الْمُخْتَصَرِ",
"nsfw_content_title": "هَذِهِ اللُّعْبَةُ تَحْتَوِي عَلَى مُحْتَوًى غَيْرِ لَائِقٍ",
"nsfw_content_description": "{{title}} تَحْتَوِي عَلَى مُحْتَوًى قَدْ لَا يَكُونُ مُنَاسِبًا لِجَمِيعِ الْأَعْمَارِ. هَلْ أَنْتَ مُتَأَكِّدٌ مِنْ أَنَّكَ تُرِيدُ الْمُتَابَعَةَ؟",
"allow_nsfw_content": "الْمُتَابَعَةُ",
"refuse_nsfw_content": "الرُّجُوعُ",
"stats": "الإحْصَائِيَّاتُ",
"download_count": "التَّنْزِيلَاتُ",
"player_count": "اللَّاعِبُونَ النَّشِطُونَ",
"download_error": "هَذَا خِيَارُ التَّنْزِيلِ غَيْرُ مَتَوَفِّرٍ",
"download": َنْزِيلٌ",
"executable_path_in_use": "الْمِلَفُّ التَّنْفِيذِيُّ مُسْتَخْدَمٌ بِوَاسِطَةِ \"{{game}}\"",
"warning": "تَنْبِيهٌ:",
"hydra_needs_to_remain_open": "لِهَذَا التَّنْزِيلِ، يَجِبُ أَنْ يَبْقَى Hydra مَفْتُوحًا حَتَّى يَتِمَّ الِاكْتِمَالُ. إِذَا أُغْلِقَ Hydra قَبْلَ الِاكْتِمَالِ، سَتَفْقِدُ تَقَدُّمَكَ.",
"achievements": "الإِنْجَازَاتُ",
"achievements_count": "الإِنْجَازَاتُ {{unlockedCount}}/{{achievementsCount}}",
"cloud_save": "حِفْظٌ سَحَابِيٌّ",
"cloud_save_description": "احْفَظْ تَقَدُّمَكَ فِي السَّحَابَةِ وَاسْتَمِرَّ فِي اللَّعِبِ عَلَى أَيِّ جِهَازٍ",
"backups": "الْنُسَخُ الِاحْتِيَاطِيَّةُ",
"install_backup": "تَثْبِيتٌ",
"delete_backup": "حَذْفٌ",
"create_backup": "نُسْخَةٌ احْتِيَاطِيَّةٌ جَدِيدَةٌ",
"last_backup_date": "آخِرُ نُسْخَةٍ احْتِيَاطِيَّةٍ فِي {{date}}",
"no_backup_preview": "لَمْ يُعْثَرْ عَلَى أَيِّ أَلْعَابٍ مَحْفُوظَةٍ لِهَذَا الْعُنْوَانِ",
"restoring_backup": "جَارٍ اسْتِعَادَةُ النُّسْخَةِ الِاحْتِيَاطِيَّةِ ({{progress}} مَكْتُومٌ)...",
"uploading_backup": "جَارٍ رَفْعُ النُّسْخَةِ الِاحْتِيَاطِيَّةِ...",
"no_backups": "لَمْ تَقُمْ بِإِنْشَاءِ أَيِّ نُسَخٍ احْتِيَاطِيَّةٍ لِهَذِهِ اللُّعْبَةِ بَعْدُ",
"backup_uploaded": َمَّ رَفْعُ النُّسْخَةِ الِاحْتِيَاطِيَّةِ",
"backup_deleted": "تَمَّ حَذْفُ النُّسْخَةِ الِاحْتِيَاطِيَّةِ",
"backup_restored": "تَمَّ اسْتِعَادَةُ النُّسْخَةِ الِاحْتِيَاطِيَّةِ",
"see_all_achievements": "عَرْضُ جَمِيعِ الإِنْجَازَاتِ",
"sign_in_to_see_achievements": "سَجِّلِ الدُّخُولَ لِعَرْضِ الإِنْجَازَاتِ",
"mapping_method_automatic": "آلِيٌّ",
"mapping_method_manual": "يَدَوِيٌّ",
"mapping_method_label": "طَرِيقَةُ التَّحْدِيدِ",
"files_automatically_mapped": "تَمَّ تَحْدِيدُ الْمَلَفَّاتِ تِلْقَائِيًّا",
"no_backups_created": "لَمْ تُنْشَأْ أَيُّ نُسَخٍ احْتِيَاطِيَّةٍ لِهَذِهِ اللُّعْبَةِ",
"manage_files": "إِدَارَةُ الْمَلَفَّاتِ",
"loading_save_preview": "جَارٍ الْبَحْثُ عَنْ أَلْعَابٍ مَحْفُوظَةٍ...",
"wine_prefix": "بَادِئَةُ Wine",
"wine_prefix_description": "بَادِئَةُ Wine الْمُسْتَخْدَمَةُ لِتَشْغِيلِ هَذِهِ اللُّعْبَةِ",
"launch_options": "خِيَارَاتُ الْإِطْلَاقِ",
"launch_options_description": "يُمْكِنُ لِلْمُسْتَخْدِمِينَ الْمُتَقَدِّمِينَ إِدْخَالُ تَعْدِيلَاتٍ عَلَى خِيَارَاتِ الْإِطْلَاقِ",
"launch_options_placeholder": "لَمْ يُحَدَّدْ أَيُّ مُعَامِلٍ",
"no_download_option_info": "لَا تَوْجَدُ مَعْلُومَاتٌ مَتَوَفِّرَةٌ",
"backup_deletion_failed": "فَشَلَ فِي حَذْفِ النُّسْخَةِ الِاحْتِيَاطِيَّةِ",
"max_number_of_artifacts_reached": "تَمَّ بَلُوغُ الْعَدَدِ الْأَقْصَى لِلنُّسَخِ الِاحْتِيَاطِيَّةِ لِهَذِهِ اللُّعْبَةِ",
"achievements_not_sync": "تَعَرَّفْ عَلَى كَيْفِيَّةِ مَزْجِ إِنْجَازَاتِكَ",
"manage_files_description": "إِدَارَةُ الْمَلَفَّاتِ الَّتِي سَيَتِمُّ نَسْخُهَا احْتِيَاطِيًّا وَاسْتِعَادَتُهَا",
"select_folder": "تَحْدِيدُ الْمَجَلَّدِ",
"backup_from": "نُسْخَةٌ احْتِيَاطِيَّةٌ مِنْ {{date}}",
"custom_backup_location_set": "تَمَّ تَحْدِيدُ مَوْقِعِ النُّسْخَةِ الِاحْتِيَاطِيَّةِ الْمُخَصَّصِ",
"no_directory_selected": "لَمْ يُحَدَّدْ أَيُّ دَلِيلٍ"
},
"activation": {
"title": فعيل Hydra",
"installation_id": عرف التثبيت:",
"enter_activation_code": دخل رمز التفعيل الخاص بك",
"message": ذا كنت لا تعرف أين تطلب هذا، فلا ينبغي أن يكون لديك هذا.",
"activate": "فعل",
"loading": "تحميل…"
"title": َفْعِيلُ Hydra",
"installation_id": ُعَرِّفُ التَّثْبِيتِ:",
"enter_activation_code": َدْخِلْ رَمْزَ التَّفْعِيلِ",
"message": ِذَا كُنْتَ لَا تَعْرِفُ أَيْنَ تَطْلُبُ هَذَا، فَلا يَجِبُ أَنْ تَكُونَ لَدَيْكَ.",
"activate": "تَفْعِيلٌ",
"loading": "جَارٍ التَّحْمِيلُ..."
},
"downloads": {
"resume": "استئناف",
"pause": "إيقاف مؤقت",
"eta": "الوقت المتبقي {{eta}}",
"paused": توقف مؤقتًا",
"verifying": "جارٍ التحقق…",
"completed": كتمل",
"removed": م يتم تحميلها",
"cancel": لغاء",
"filter": صفية الألعاب التي تم تنزيلها",
"remove": زالة",
"downloading_metadata": "جارٍ تنزيل البيانات الوصفية…",
"deleting": "جارٍ حذف المثبت…",
"delete": "إزالة المثبت",
"delete_modal_title": "هل أنت متأكد؟",
"delete_modal_description": يؤدي هذا إلى إزالة كافة ملفات التثبيت من جهاز الكمبيوتر الخاص بك",
"install": "ثَبَّتَ",
"download_in_progress": "في تَقَدم",
"queued_downloads": "التنزيلات في قائمة الانتظار",
"downloads_completed": كتمل",
"queued": "في قائمة الانتظار",
"no_downloads_title": "هذا فارغ",
"no_downloads_description": م تقم بتنزيل أي شيء باستخدام Hydra بعد، ولكن لم يفت الأوان بعد للبدء.",
"checking_files": "جارٍ فحص الملفات…"
"resume": "اسْتِئْنَافٌ",
"pause": ِيقَافٌ",
"eta": "الِاكْتِمَالُ {{eta}}",
"paused": ُوْقَفٌ",
"verifying": َارٍ التَّحَقُّقُ...",
"completed": َكْتُومٌ",
"removed": َمْ يُنَزَّلْ",
"cancel": ِلْغَاءٌ",
"filter": َصْفِيَةُ الْأَلْعَابِ الْمُنَزَّلَةِ",
"remove": ِزَالَةٌ",
"downloading_metadata": َارٍ تَنْزِيلُ الْبَيَانَاتِ الْوَصْفِيَّةِ...",
"deleting": َارٍ حَذْفُ الْمُثَبِّتِ...",
"delete": "حَذْفُ الْمُثَبِّتِ",
"delete_modal_title": "هَلْ أَنْتَ مُتَأَكِّدٌ؟",
"delete_modal_description": َيُؤَدِّي هَذَا إِلَى إِزَالَةِ جَمِيعِ مَلَفَّاتِ التَّثْبِيتِ مِنْ حَاسُوبِكَ",
"install": "تَثْبِيتٌ",
"download_in_progress": "جَارٍ التَّنْفِيذُ",
"queued_downloads": "التَّنْزِيلَاتُ فِي الْانْتِظَارِ",
"downloads_completed": َكْتُومٌ",
"queued": ِي الْانْتِظَارِ",
"no_downloads_title": "فَرَاغٌ تَامٌ",
"no_downloads_description": َمْ تَقُمْ بِتَنْزِيلِ أَيِّ شَيْءٍ بِاسْتِخْدَامِ Hydra بَعْدُ، لَكِنَّهُ لَيْسَ مُتَأَخِّرًا لِلْبَدْءِ.",
"checking_files": َارٍ التَّحَقُّقُ مِنَ الْمَلَفَّاتِ...",
"seeding": "الْبَذْرُ",
"stop_seeding": "إِيقَافُ الْبَذْرِ",
"resume_seeding": "اسْتِئْنَافُ الْبَذْرِ",
"options": "إِدَارَةٌ"
},
"settings": {
"downloads_path": سار التنزيلات",
"change": حديث",
"notifications": "إشعارات",
"enable_download_notifications": ند اكتمال التنزيل",
"enable_repack_list_notifications": ند إضافة حزمة جديدة",
"real_debrid_api_token_label": مز Real-Debrid API",
"quit_app_instead_hiding": "لا تخفي Hydra عند الإغلاق",
"launch_with_system": "قم بتشغيل Hydra عند بدء تشغيل النظام",
"general": "عام",
"behavior": لوك",
"download_sources": "تحميل المصادر",
"language": "لغة",
"real_debrid_api_token": مز API",
"enable_real_debrid": مكين ريال ديبريد",
"real_debrid_description": "Real-Debrid هو برنامج تنزيل غير مقيد يسمح لك بتنزيل الملفات بسرعة، ولا يقتصر ذلك إلا على سرعة الإنترنت لديك.",
"real_debrid_invalid_token": مز API غير صالح",
"real_debrid_api_token_hint": مكنك الحصول على رمز API الخاص بك <0>هنا</0>",
"real_debrid_free_account_error": "الحساب \"{{username}}\" هو حساب مجاني. يرجى الاشتراك في Real-Debrid",
"real_debrid_linked_message": "حساب \"{{username}}\"مرتبط",
"save_changes": فظ التغييرات",
"changes_saved": م حفظ التغييرات بنجاح",
"download_sources_description": تقوم Hydra بجلب روابط التنزيل من هذه المصادر. ",
"validate_download_source": "التحقق من صحة",
"remove_download_source": زالة",
"add_download_source": "أضف المصدر",
"download_count_zero": "{{countFormatted}} خيارات التنزيل",
"download_source_url": "تنزيل عنوان URL المصدر",
"add_download_source_description": "أدخل عنوان URL لملف .json",
"download_source_up_to_date": "محدث",
"download_source_errored": "خطأ",
"sync_download_sources": "مصادر المزامنة",
"removed_download_source": "تمت إزالة مصدر التنزيل",
"added_download_source": "تمت إضافة مصدر التنزيل",
"download_sources_synced": تم مزامنة جميع مصادر التنزيل",
"insert_valid_json_url": "أدخل عنوان URL صالحًا لـ JSON",
"found_download_option_zero": "وجد {{countFormatted}} خيارات التنزيل",
"import": "يستورد",
"public": "عام",
"private": "خاص",
"friends_only": "الأصدقاء فقط",
"privacy": "خصوصية",
"profile_visibility": "رؤية الملف الشخصي",
"profile_visibility_description": "اختر من يمكنه رؤية ملفك الشخصي ومكتبتك",
"required_field": "هذه الخانة مطلوبه",
"source_already_exists": "تمت إضافة هذا المصدر بالفعل",
"must_be_valid_url": "يجب أن يكون المصدر عنوان URL صالحًا",
"blocked_users": "المستخدمين المحظورين",
"user_unblocked": "تم إلغاء حظر المستخدم",
"enable_achievement_notifications": "عندما يتم فتح الإنجاز",
"launch_minimized": "تم تصغير إطلاق Hydra",
"disable_nsfw_alert": "تعطيل تنبيه NSFW",
"show_hidden_achievement_description": "إظهار وصف الإنجازات المخفية قبل فتحها",
"download_count_one": "{{countFormatted}} خيار التنزيل",
"download_count_two": "{{countFormatted}} خيارات التنزيل",
"download_count_few": "{{countFormatted}} خيارات التنزيل",
"download_count_many": "{{countFormatted}} خيارات التنزيل",
"download_count_other": "{{countFormatted}} خيارات التنزيل",
"found_download_option_one": "وجد {{countFormatted}} خيار التنزيل",
"found_download_option_two": "وجد {{countFormatted}} خيارات التنزيل",
"found_download_option_few": "وجد {{countFormatted}} خيارات التنزيل",
"found_download_option_many": "وجد {{countFormatted}} خيارات التنزيل",
"found_download_option_other": "وجد {{countFormatted}} خيارات التنزيل"
"downloads_path": َسَارُ التَّنْزِيلَاتِ",
"change": َحْدِيثٌ",
"notifications": "الإِشْعَارَاتُ",
"enable_download_notifications": ِنْدَ اكْتِمَالِ التَّنْزِيلِ",
"enable_repack_list_notifications": ِنْدَ إِضَافَةِ إِصْدَارٍ مُعَادٍ تَغْلِيفِهِ جَدِيدٍ",
"real_debrid_api_token_label": َمْزُ واجهة برمجة التطبيقات Real-Debrid",
"quit_app_instead_hiding": "لا تُخْفِ Hydra عِنْدَ الإِغْلَاقِ",
"launch_with_system": "تَشْغِيلُ Hydra عِنْدَ بَدْءِ النِّظَامِ",
"general": َامٌ",
"behavior": ُلُوكٌ",
"download_sources": "مَصَادِرُ التَّنْزِيلِ",
"language": "اللُّغَةُ",
"real_debrid_api_token": َمْزُ واجهة برمجة التطبيقات",
"enable_real_debrid": َمْكِينُ Real-Debrid",
"real_debrid_description": "Real-Debrid هُوَ مُنَزِّلٌ غَيْرُ مَقْيُودٍ يَتِيحُ لَكَ تَنْزِيلَ الْمَلَفَّاتِ بِسُرْعَةٍ، مَحْدُودٌ فَقَطْ بِسُرْعَةِ الْإِنْتَرْنِتِ لَدَيْكَ.",
"real_debrid_invalid_token": َمْزُ واجهة برمجة التطبيقات غَيْرُ صَالِحٍ",
"real_debrid_api_token_hint": ُمْكِنُكَ الْحُصُولُ عَلَى رَمْزِ واجهة برمجة التطبيقات <0>هُنَا</0>",
"real_debrid_free_account_error": "الْحِسَابُ \"{{username}}\" هُوَ حِسَابٌ مَجَّانِيٌّ. يَرْجَى الِاشْتِرَاكُ فِي Real-Debrid",
"real_debrid_linked_message": "تَمَّ رَبْطُ الْحِسَابِ \"{{username}}\"",
"save_changes": ِفْظُ التَّغْيِيرَاتِ",
"changes_saved": َمَّ حِفْظُ التَّغْيِيرَاتِ بِنَجَاحٍ",
"download_sources_description": َتَقُومُ Hydra بِجَلْبِ رَوَابِطِ التَّنْزِيلِ مِنْ هَذِهِ الْمَصَادِرِ. يَجِبُ أَنْ يَكُونَ عُنْوَانُ URL لِلْمَصْدَرِ رَابِطًا مُبَاشِرًا إِلَى مِلَفٍّ .json يَحْتَوِي عَلَى رَوَابِطِ التَّنْزِيلِ.",
"validate_download_source": "تَصْدِيقٌ",
"remove_download_source": ِزَالَةٌ",
"add_download_source": "إِضَافَةُ مَصْدَرٍ",
"download_count_zero": "لَا تَوْجَدُ خِيَارَاتُ تَنْزِيلٍ",
"download_count_one": "{{countFormatted}} خِيَارُ تَنْزِيلٍ",
"download_count_other": "{{countFormatted}} خِيَارَاتُ تَنْزِيلٍ",
"download_source_url": "عُنْوَانُ مَصْدَرِ التَّنْزِيلِ",
"add_download_source_description": "أَدْخِلْ عُنْوَانَ URL لِمِلَفٍّ .json",
"download_source_up_to_date": "مُحَدَّثٌ",
"download_source_errored": "خَطَأٌ",
"sync_download_sources": "مَزْجُ الْمَصَادِرِ",
"removed_download_source": َمَّ إِزَالَةُ مَصْدَرِ التَّنْزِيلِ",
"added_download_source": "تَمَّتْ إِضَافَةُ مَصْدَرِ التَّنْزِيلِ",
"download_sources_synced": "تَمَّ مَزْجُ جَمِيعِ مَصَادِرِ التَّنْزِيلِ",
"insert_valid_json_url": "أَدْخِلْ عُنْوَانَ JSON صَالِحًا",
"found_download_option_zero": "لَمْ يُعْثَرْ عَلَى خِيَارِ تَنْزِيلٍ",
"found_download_option_one": "عُثِرَ عَلَى {{countFormatted}} خِيَارِ تَنْزِيلٍ",
"found_download_option_other": "عُثِرَ عَلَى {{countFormatted}} خِيَارَاتِ تَنْزِيلٍ",
"import": "اسْتِيرَادٌ",
"public": "عَامٌ",
"private": "خَاصٌ",
"friends_only": "الْأَصْدِقَاءُ فَقَطْ",
"privacy": "الْخُصُوصِيَّةُ",
"profile_visibility": "رُؤْيَةُ الْمَلَفِّ الشَّخْصِيِّ",
"profile_visibility_description": "اخْتَرْ مَنْ يُمْكِنُهُ رُؤْيَةُ مَلَفِّكَ الشَّخْصِيِّ وَمَكْتَبَتِكَ",
"required_field": "هَذَا الْحَقْلُ مَطْلُوبٌ",
"source_already_exists": "تَمَّتْ إِضَافَةُ هَذَا الْمَصْدَرِ مِنْ قَبْلُ",
"must_be_valid_url": "يَجِبُ أَنْ يَكُونَ الْمَصْدَرُ عُنْوَانَ URL صَالِحًا",
"blocked_users": "الْمُسْتَخْدِمُونَ الْمَحْظُورُونَ",
"user_unblocked": "تَمَّ إِزَالَةُ حَظْرِ الْمُسْتَخْدِمِ",
"enable_achievement_notifications": "عِنْدَ فَتْحِ إِنْجَازٍ",
"launch_minimized": "تَشْغِيلُ Hydra مُصَغَّرًا",
"disable_nsfw_alert": "تَعْطِيلُ تَنْبِيهِ الْمُحْتَوَى غَيْرِ اللَّائِقِ",
"seed_after_download_complete": "الْبَذْرُ بَعْدَ اكْتِمَالِ التَّنْزِيلِ",
"show_hidden_achievement_description": "إِظْهَارُ وَصْفِ الإِنْجَازَاتِ الْمَخْفِيَّةِ قَبْلَ فَتْحِهَا"
},
"notifications": {
"download_complete": "اكتمل التنزيل",
"game_ready_to_install": "{{title}} جاهز للتثبيت",
"repack_list_updated": م تحديث قائمة إعادة التعبئة",
"new_update_available": "إصدار {{version}} متاح",
"restart_to_install_update": "أعد تشغيل Hydra لتثبيت التحديث",
"notification_achievement_unlocked_title": "تم فتح الإنجاز لـ {{game}}",
"notification_achievement_unlocked_body": "{{achievement}} وغيرها {{count}} تم فتحها",
"repack_count_zero": "{{count}} تمت إضافة العبوات",
"repack_count_one": "{{count}} تمت إضافة أعد حزم",
"repack_count_two": "{{count}} تمت إضافة العبوات",
"repack_count_few": "{{count}} تمت إضافة العبوات",
"repack_count_many": "{{count}} تمت إضافة العبوات",
"repack_count_other": "{{count}} تمت إضافة العبوات"
"download_complete": "اكْتِمَالُ التَّنْزِيلِ",
"game_ready_to_install": "{{title}} جَاهِزٌ لِلتَّثْبِيتِ",
"repack_list_updated": َمَّ تَحْدِيثُ قَائِمَةِ الإِصْدَارَاتِ الْمُعَادَةِ تَغْلِيفُهَا",
"repack_count_one": "{{count}} إِصْدَارٌ مُعَادٌ تَغْلِيفُهُ أُضِيفَ",
"repack_count_other": "{{count}} إِصْدَارَاتٌ مُعَادَةٌ تَغْلِيفُهَا أُضِيفَتْ",
"new_update_available": "الْإِصْدَارُ {{version}} مَتَوَفِّرٌ",
"restart_to_install_update": "أَعِدْ تَشْغِيلَ Hydra لِتَثْبِيتِ التَّحْدِيثِ",
"notification_achievement_unlocked_title": "تَمَّ فَتْحُ إِنْجَازٍ لِـ {{game}}",
"notification_achievement_unlocked_body": "{{achievement}} وَ{{count}} أُخْرَى تَمَّ فَتْحُهَا"
},
"system_tray": {
"open": "افتح Hydra",
"quit": "خروج"
"open": "فَتْحُ Hydra",
"quit": "الْخُرُوجُ"
},
"game_card": {
"no_downloads": "لا توجد تنزيلات متاحة"
"no_downloads": َا تَوْجَدُ تَنْزِيلَاتٌ مَتَوَفِّرَةٌ"
},
"binary_not_found_modal": {
"title": "البرامج غير مثبتة",
"description": م يتم العثور على الملفات التنفيذية الخاصة بـ Wine أو Lutris على نظامك",
"instructions": حقق من الطريقة الصحيحة لتثبيت أي منها على توزيعة Linux لديك حتى تعمل اللعبة بشكل طبيعي"
"title": "الْبَرَامِجُ غَيْرُ مُثَبَّتَةٍ",
"description": َمْ يُعْثَرْ عَلَى مَلَفَّاتٍ تَنْفِيذِيَّةٍ لِـ Wine أَوْ Lutris عَلَى نِظَامِكَ",
"instructions": َحَقَّقْ مِنَ الطَّرِيقَةِ الصَّحِيحَةِ لِتَثْبِيتِ أَيٍّ مِنْهُمَا عَلَى تَوْزِيعَةِ Linux لَدَيْكَ لِتَعْمَلَ اللُّعْبَةُ بِشَكْلٍ طَبِيعِيٍّ"
},
"modal": {
"close": ر الإغلاق"
"close": ِرُّ الإِغْلَاقِ"
},
"forms": {
"toggle_password_visibility": بديل رؤية كلمة المرور"
"toggle_password_visibility": َبْدِيلُ رُؤْيَةِ كَلِمَةِ الْمَرُورِ"
},
"user_profile": {
"amount_hours": "{{amount}} ساعات",
"amount_minutes": "{{amount}} دقائق",
"last_time_played": "لعبت آخر مرة {{period}}",
"activity": "النشاط الأخير",
"library": "مكتبة",
"total_play_time": جمالي وقت اللعب",
"no_recent_activity_title": "هممم... لا شيء هنا",
"no_recent_activity_description": م تلعب أي مباراة مؤخرًا. ",
"display_name": "اسم العرض",
"saving": "توفير",
"save": "يحفظ",
"edit_profile": حرير الملف الشخصي",
"saved_successfully": م الحفظ بنجاح",
"try_again": "من فضلك، حاول مرة أخرى",
"sign_out_modal_title": "هل أنت متأكد؟",
"cancel": لغاء",
"successfully_signed_out": م تسجيل الخروج بنجاح",
"sign_out": سجيل الخروج",
"playing_for": "اللعب من أجل {{amount}}",
"sign_out_modal_text": كتبتك مرتبطة بحسابك الحالي. ",
"add_friends": "أضف أصدقاء",
"add": "يضيف",
"friend_code": مز الصديق",
"see_profile": "انظر الملف الشخصي",
"sending": "إرسال",
"friend_request_sent": م إرسال طلب الصداقة",
"friends": "أصدقاء",
"friends_list": "قائمة الأصدقاء",
"user_not_found": "لم يتم العثور على المستخدم",
"block_user": ظر المستخدم",
"add_friend": ضافة صديق",
"request_sent": م إرسال الطلب",
"request_received": م استلام الطلب",
"accept_request": بول الطلب",
"ignore_request": جاهل الطلب",
"cancel_request": لغاء الطلب",
"undo_friendship": "التراجع عن الصداقة",
"request_accepted": م قبول الطلب",
"user_blocked_successfully": م حظر المستخدم بنجاح",
"user_block_modal_text": "هذا سوف يمنع {{displayName}}",
"blocked_users": "المستخدمين المحظورين",
"unblock": لغاء الحظر",
"no_friends_added": يس لديك أي أصدقاء مضافين",
"pending": يد الانتظار",
"no_pending_invites": يس لديك أي دعوات معلقة",
"no_blocked_users": يس لديك أي مستخدمين محظورين",
"friend_code_copied": م نسخ رمز الصديق",
"undo_friendship_modal_text": يؤدي هذا إلى التراجع عن صداقتك معه {{displayName}}",
"privacy_hint": ضبط من يمكنه رؤية هذا، انتقل إلى <0>إعدادات</0>",
"locked_profile": "هذا الملف الشخصي خاص",
"image_process_failure": شل أثناء معالجة الصورة",
"required_field": "هذه الخانة مطلوبه",
"displayname_min_length": جب أن يتكون اسم العرض من 3 أحرف على الأقل",
"displayname_max_length": جب ألا يزيد طول اسم العرض عن 50 حرفًا",
"report_profile": "الإبلاغ عن هذا الملف الشخصي",
"report_reason": ماذا تقوم بالإبلاغ عن هذا الملف الشخصي؟",
"report_description": علومات إضافية",
"report_description_placeholder": علومات إضافية",
"report": قرير",
"report_reason_hate": طاب الكراهية",
"report_reason_sexual_content": "المحتوى الجنسي",
"report_reason_violence": نف",
"report_reason_spam": سائل إلكترونية مزعجة",
"profile_reported": "تم الإبلاغ عن الملف الشخصي",
"your_friend_code": "رمز صديقك:",
"upload_banner": "تحميل لافتة",
"uploading_banner": "جارٍ تحميل البانر…",
"background_image_updated": "تم تحديث صورة الخلفية",
"report_reason_zero": "آخر",
"report_reason_one": "لماذا تقوم بالإبلاغ عن هذا الملف الشخصي؟",
"report_reason_two": "آخر",
"report_reason_few": "آخر",
"report_reason_many": "آخر",
"report_reason_other": "آخر"
"amount_hours": "{{amount}} سَاعَاتٌ",
"amount_minutes": "{{amount}} دَقَائِقُ",
"last_time_played": "آخِرُ مَرَّةٍ لُعِبَتْ {{period}}",
"activity": "النَّشَاطُ الْأَخِيرُ",
"library": "الْمَكْتَبَةُ",
"total_play_time": ِجْمَالِيُّ وَقْتِ اللَّعِبِ",
"no_recent_activity_title": "هَمَمْ... لَا شَيْءَ هُنَا",
"no_recent_activity_description": َمْ تَلْعَبْ أَيَّ أَلْعَابٍ مُؤَخَّرًا. حَانَ الْوَقْتُ لِتَغْيِيرِ ذَلِكَ!",
"display_name": "اسْمُ الْعَرْضِ",
"saving": "جَارٍ الْحِفْظُ",
"save": "حِفْظٌ",
"edit_profile": َحْرِيرُ الْمَلَفِّ الشَّخْصِيِّ",
"saved_successfully": َمَّ الْحِفْظُ بِنَجَاحٍ",
"try_again": "الرَّجَاءُ الْمُحَاوَلَةُ مَرَّةً أُخْرَى",
"sign_out_modal_title": "هَلْ أَنْتَ مُتَأَكِّدٌ؟",
"cancel": ِلْغَاءٌ",
"successfully_signed_out": َمَّ تَسْجِيلُ الْخُرُوجِ بِنَجَاحٍ",
"sign_out": َسْجِيلُ الْخُرُوجِ",
"playing_for": "جَارِي اللَّعِبُ لِمُدَّةِ {{amount}}",
"sign_out_modal_text": َكْتَبَتُكَ مُرْتَبِطَةٌ بِحِسَابِكَ الْحَالِيِّ. عِنْدَ تَسْجِيلِ الْخُرُوجِ، لَنْ تَكُونَ مَكْتَبَتُكَ مَرْئِيَّةً بَعْدَ الْآنِ، وَلَنْ يَتِمَّ حِفْظُ أَيِّ تَقَدُّمٍ. هَلْ تُرِيدُ الْمُتَابَعَةَ مَعَ تَسْجِيلِ الْخُرُوجِ؟",
"add_friends": "إِضَافَةُ الْأَصْدِقَاءِ",
"add": "إِضَافَةٌ",
"friend_code": َمْزُ الصَّدِيقِ",
"see_profile": "رُؤْيَةُ الْمَلَفِّ الشَّخْصِيِّ",
"sending": "جَارٍ الْإِرْسَالُ",
"friend_request_sent": َمَّ إِرْسَالُ طَلَبِ الصَّدَاقَةِ",
"friends": "الْأَصْدِقَاءُ",
"friends_list": َائِمَةُ الْأَصْدِقَاءِ",
"user_not_found": "الْمُسْتَخْدِمُ غَيْرُ مَوْجُودٍ",
"block_user": َظْرُ الْمُسْتَخْدِمِ",
"add_friend": ِضَافَةُ صَدِيقٍ",
"request_sent": َمَّ إِرْسَالُ الطَّلَبِ",
"request_received": َمَّ اسْتِقْبَالُ الطَّلَبِ",
"accept_request": َبُولُ الطَّلَبِ",
"ignore_request": َجَاهُلُ الطَّلَبِ",
"cancel_request": ِلْغَاءُ الطَّلَبِ",
"undo_friendship": "إِلْغَاءُ الصَّدَاقَةِ",
"request_accepted": َمَّ قَبُولُ الطَّلَبِ",
"user_blocked_successfully": َمَّ حَظْرُ الْمُسْتَخْدِمِ بِنَجَاحٍ",
"user_block_modal_text": "سَيُؤَدِّي هَذَا إِلَى حَظْرِ {{displayName}}",
"blocked_users": "الْمُسْتَخْدِمُونَ الْمَحْظُورُونَ",
"unblock": ِزَالَةُ الْحَظْرِ",
"no_friends_added": َيْسَ لَدَيْكَ أَصْدِقَاءٌ مُضَافُونَ",
"pending": َيْدُ الْانْتِظَارِ",
"no_pending_invites": َيْسَ لَدَيْكَ دَعَوَاتٌ قَيْدُ الْانْتِظَارِ",
"no_blocked_users": َيْسَ لَدَيْكَ مُسْتَخْدِمُونَ مَحْظُورُونَ",
"friend_code_copied": َمَّ نَسْخُ رَمْزِ الصَّدِيقِ",
"undo_friendship_modal_text": َيُؤَدِّي هَذَا إِلَى إِلْغَاءِ صَدَاقَتِكَ مَعَ {{displayName}}",
"privacy_hint": ِتَعْدِيلِ مَنْ يُمْكِنُهُ رُؤْيَةُ هَذَا، اذْهَبْ إِلَى <0>الإعْدَادَاتِ</0>",
"locked_profile": "هَذَا الْمَلَفُّ الشَّخْصِيُّ خَاصٌّ",
"image_process_failure": َشَلَ أَثْنَاءَ مُعَالَجَةِ الصُّورَةِ",
"required_field": "هَذَا الْحَقْلُ مَطْلُوبٌ",
"displayname_min_length": َجِبُ أَنْ يَكُونَ اسْمُ الْعَرْضِ عَلَى الْأَقَلِّ 3 أَحْرُفٍ",
"displayname_max_length": َجِبُ أَنْ يَكُونَ اسْمُ الْعَرْضِ عَلَى الْأَكْثَرِ 50 حَرْفًا",
"report_profile": "تَقْرِيرٌ عَنْ هَذَا الْمَلَفِّ الشَّخْصِيِّ",
"report_reason": ِمَاذَا تُقَدِّمُ تَقْرِيرًا عَنْ هَذَا الْمَلَفِّ الشَّخْصِيِّ؟",
"report_description": َعْلُومَاتٌ إِضَافِيَّةٌ",
"report_description_placeholder": َعْلُومَاتٌ إِضَافِيَّةٌ",
"report": َقْرِيرٌ",
"report_reason_hate": ِطَابُ الْكُرْهِ",
"report_reason_sexual_content": "مُحْتَوًى جِنْسِيٌّ",
"report_reason_violence": ُنْفٌ",
"report_reason_spam": َاسِلَةٌ عَشْوَائِيَّةٌ",
"report_reason_other": "آخَرُ",
"profile_reported": "تَمَّ تَقْرِيرُ الْمَلَفِّ الشَّخْصِيِّ",
"your_friend_code": "رَمْزُ صَدِيقِكَ:",
"upload_banner": "رَفْعُ لَافِتَةٍ",
"uploading_banner": "جَارٍ رَفْعُ اللَّافِتَةِ...",
"background_image_updated": "تَمَّ تَحْدِيثُ صُورَةِ الْخَلْفِيَّةِ",
"stats": "الإحْصَائِيَّاتُ",
"achievements": "الإِنْجَازَاتُ",
"games": "الْأَلْعَابُ",
"top_percentile": "الْأَفْضَلُ {{percentile}}%",
"ranking_updated_weekly": "التَّرْتِيبُ يُحَدَّثُ أُسْبُوعِيًّا",
"playing": "جَارِي اللَّعِبُ {{game}}",
"achievements_unlocked": "الإِنْجَازَاتُ الْمَفْتُوحَةُ",
"earned_points": "النَّقَاطُ الْمَكْسُوبَةُ",
"show_achievements_on_profile": "عَرْضُ إِنْجَازَاتِكَ عَلَى مَلَفِّكَ الشَّخْصِيِّ",
"show_points_on_profile": "عَرْضُ النَّقَاطِ الْمَكْسُوبَةِ عَلَى مَلَفِّكَ الشَّخْصِيِّ"
},
"achievement": {
"achievement_unlocked": "تم فتح الإنجاز",
"user_achievements": "{{displayName}}إنجازات",
"your_achievements": نجازاتك",
"unlocked_at": "مقفلة في: {{date}}",
"subscription_needed": "مطلوب اشتراك Hydra Cloud لرؤية هذا المحتوى",
"new_achievements_unlocked": "مفتوح {{achievementCount}} انجازات جديدة من {{gameCount}} ألعاب",
"achievement_progress": "{{unlockedCount}}/{{totalCount}} الإنجازات",
"achievements_unlocked_for_game": "مفتوح {{achievementCount}} انجازات جديدة ل {{gameTitle}}"
"achievement_unlocked": "إِنْجَازٌ مَفْتُوحٌ",
"user_achievements": "إِنْجَازَاتُ {{displayName}}",
"your_achievements": ِنْجَازَاتُكَ",
"unlocked_at": "تَمَّ الْفَتْحُ فِي: {{date}}",
"subscription_needed": "يَحْتَاجُ اشْتِرَاكُ Hydra Cloud لِرُؤْيَةِ هَذَا الْمُحْتَوَى",
"new_achievements_unlocked": "تَمَّ فَتْحُ {{achievementCount}} إِنْجَازَاتٍ جَدِيدَةٍ مِنْ {{gameCount}} أَلْعَابٍ",
"achievement_progress": "{{unlockedCount}}/{{totalCount}} إِنْجَازَاتٍ",
"achievements_unlocked_for_game": "تَمَّ فَتْحُ {{achievementCount}} إِنْجَازَاتٍ جَدِيدَةٍ لِـ {{gameTitle}}",
"hidden_achievement_tooltip": "هَذَا إِنْجَازٌ مَخْفِيٌّ",
"achievement_earn_points": "اكْسِبْ {{points}} نَقَاطًا بِهَذَا الإِنْجَازِ",
"earned_points": "النَّقَاطُ الْمَكْسُوبَةُ:",
"available_points": "النَّقَاطُ الْمُتَوَفِّرَةُ:",
"how_to_earn_achievements_points": "كَيْفَ تَكْسِبُ نَقَاطَ الإِنْجَازَاتِ؟"
},
"hydra_cloud": {
"subscription_tour_title": "اشتراك Hydra كلاود",
"subscribe_now": "اشترك الآن",
"cloud_saving": "الحفظ السحابي",
"cloud_achievements": "احفظ إنجازاتك على السحابة",
"animated_profile_picture": "صور شخصية متحركة",
"premium_support": "دعم متميز",
"show_and_compare_achievements": رض ومقارنة إنجازاتك مع المستخدمين الآخرين",
"animated_profile_banner": "لافتة الملف الشخصي المتحركة"
"subscription_tour_title": "اشْتِرَاكُ Hydra Cloud",
"subscribe_now": "اشْتَرِكِ الْآنَ",
"cloud_saving": "حِفْظٌ سَحَابِيٌّ",
"cloud_achievements": "حِفْظُ إِنْجَازَاتِكَ فِي السَّحَابَةِ",
"animated_profile_picture": ُورُ الْمَلَفِّ الشَّخْصِيِّ الْمُتَحَرِّكَةِ",
"premium_support": "الدَّعْمُ الْمُتَقَدِّمُ",
"show_and_compare_achievements": َرْضٌ وَمُقَارَنَةُ إِنْجَازَاتِكَ مَعَ مُسْتَخْدِمِينَ آخَرِينَ",
"animated_profile_banner": َافِتَةُ الْمَلَفِّ الشَّخْصِيِّ الْمُتَحَرِّكَةِ",
"hydra_cloud": "Hydra Cloud",
"hydra_cloud_feature_found": "لَقَدْ اكْتَشَفْتَ مِيزَةً مِنْ Hydra Cloud!",
"learn_more": "تَعَلَّمْ أَكْثَرَ"
}
}

View File

@@ -58,7 +58,7 @@
},
"game_details": {
"launch_options": "Опции за стартиране",
"launch_options_description": "Напредналите потребители могат да въведат модификации на своите опции за стартиране",
"launch_options_description": "Напредналите потребители могат да въведат модификации на своите опции за стартиране (экспериментальный)",
"launch_options_placeholder": "Няма зададен параметър",
"open_download_options": "Варианти за изтегляне",
"download_options_zero": "Няма варианти за изтегляне",

View File

@@ -168,7 +168,7 @@
"wine_prefix": "Wine Prefix",
"wine_prefix_description": "The Wine prefix used to run this game",
"launch_options": "Launch Options",
"launch_options_description": "Advanced users may choose to enter modifications to their launch options",
"launch_options_description": "Advanced users may choose to enter modifications to their launch options (experimental feature)",
"launch_options_placeholder": "No parameter specified",
"no_download_option_info": "No information available",
"backup_deletion_failed": "Failed to delete backup",
@@ -178,7 +178,8 @@
"select_folder": "Select folder",
"backup_from": "Backup from {{date}}",
"custom_backup_location_set": "Custom backup location set",
"no_directory_selected": "No directory selected"
"no_directory_selected": "No directory selected",
"no_write_permission": "Cannot download into this directory. Click here to learn more."
},
"activation": {
"title": "Activate Hydra",

View File

@@ -156,7 +156,7 @@
"wine_prefix": "Prefixo Wine",
"wine_prefix_description": "O prefixo Wine que foi utilizado para instalar o jogo",
"launch_options": "Opções de Inicialização",
"launch_options_description": "Usuários avançados podem adicionar opções de inicialização no jogo",
"launch_options_description": "Usuários avançados podem adicionar opções de inicialização no jogo (experimental)",
"launch_options_placeholder": "Nenhum parâmetro informado",
"no_download_option_info": "Sem informações disponíveis",
"backup_deletion_failed": "Falha ao apagar backup",
@@ -167,7 +167,8 @@
"select_folder": "Selecione a pasta",
"manage_files_description": "Gerencie quais arquivos serão feitos backup",
"clear": "Limpar",
"no_directory_selected": "Nenhum diretório selecionado"
"no_directory_selected": "Nenhum diretório selecionado",
"no_write_permission": "O download não pode ser feito neste diretório. Clique aqui para saber mais."
},
"activation": {
"title": "Ativação",

View File

@@ -9,6 +9,8 @@ const getSessionHash = async (_event: Electron.IpcMainInvokeEvent) => {
if (!auth) return null;
const payload = jwt.decode(auth.accessToken) as jwt.JwtPayload;
if (!payload) return null;
return payload.sessionId;
};

View File

@@ -1,7 +1,7 @@
import { HydraApi } from "@main/services";
import { registerEvent } from "../register-event";
import type { GameArtifact, GameShop } from "@types";
import { SubscriptionRequiredError } from "@shared";
import { SubscriptionRequiredError, UserNotLoggedInError } from "@shared";
const getGameArtifacts = async (
_event: Electron.IpcMainInvokeEvent,
@@ -22,6 +22,10 @@ const getGameArtifacts = async (
return [];
}
if (err instanceof UserNotLoggedInError) {
return [];
}
throw err;
});
};

View File

@@ -0,0 +1,15 @@
import fs from "node:fs";
import { registerEvent } from "../register-event";
const checkFolderWritePermission = async (
_event: Electron.IpcMainInvokeEvent,
path: string
) =>
new Promise((resolve) => {
fs.access(path, fs.constants.W_OK, (err) => {
resolve(!err);
});
});
registerEvent("checkFolderWritePermission", checkFolderWritePermission);

View File

@@ -1,10 +1,10 @@
import checkDiskSpace from "check-disk-space";
import disk from "diskusage";
import { registerEvent } from "../register-event";
const getDiskFreeSpace = async (
_event: Electron.IpcMainInvokeEvent,
path: string
) => checkDiskSpace(path);
) => disk.check(path);
registerEvent("getDiskFreeSpace", getDiskFreeSpace);

View File

@@ -1,9 +0,0 @@
export const parseLaunchOptions = (params: string | null): string[] => {
if (params == null || params == "") {
return [];
}
const paramsSplit = params.split(" ");
return paramsSplit;
};

View File

@@ -11,6 +11,7 @@ import "./catalogue/get-trending-games";
import "./catalogue/get-publishers";
import "./catalogue/get-developers";
import "./hardware/get-disk-free-space";
import "./hardware/check-folder-write-permission";
import "./library/add-game-to-library";
import "./library/create-game-shortcut";
import "./library/close-game";
@@ -30,6 +31,8 @@ import "./library/select-game-wine-prefix";
import "./misc/open-checkout";
import "./misc/open-external";
import "./misc/show-open-dialog";
import "./misc/get-features";
import "./misc/show-item-in-folder";
import "./torrenting/cancel-game-download";
import "./torrenting/pause-game-download";
import "./torrenting/resume-game-download";
@@ -71,7 +74,6 @@ import "./cloud-save/delete-game-artifact";
import "./cloud-save/select-game-backup-path";
import "./notifications/publish-new-repacks-notification";
import { isPortableVersion } from "@main/helpers";
import "./misc/show-item-in-folder";
ipcMain.handle("ping", () => "pong");
ipcMain.handle("getVersion", () => appVersion);

View File

@@ -2,9 +2,7 @@ import { gameRepository } from "@main/repository";
import { registerEvent } from "../register-event";
import { shell } from "electron";
import { spawn } from "child_process";
import { parseExecutablePath } from "../helpers/parse-executable-path";
import { parseLaunchOptions } from "../helpers/parse-launch-options";
const openGame = async (
_event: Electron.IpcMainInvokeEvent,
@@ -12,21 +10,15 @@ const openGame = async (
executablePath: string,
launchOptions: string | null
) => {
// TODO: revisit this for launchOptions
const parsedPath = parseExecutablePath(executablePath);
const parsedParams = parseLaunchOptions(launchOptions);
await gameRepository.update(
{ id: gameId },
{ executablePath: parsedPath, launchOptions }
);
if (process.platform === "linux" || process.platform === "darwin") {
shell.openPath(parsedPath);
}
if (process.platform === "win32") {
spawn(parsedPath, parsedParams, { shell: false, detached: true });
}
shell.openPath(parsedPath);
};
registerEvent("openGame", openGame);

View File

@@ -0,0 +1,8 @@
import { registerEvent } from "../register-event";
import { HydraApi } from "@main/services";
const getFeatures = async (_event: Electron.IpcMainInvokeEvent) => {
return HydraApi.get<string[]>("/features", null, { needsAuth: false });
};
registerEvent("getFeatures", getFeatures);

View File

@@ -1,16 +1,10 @@
import { shell } from "electron";
import { registerEvent } from "../register-event";
import {
userAuthRepository,
userPreferencesRepository,
} from "@main/repository";
import { userAuthRepository } from "@main/repository";
import { HydraApi } from "@main/services";
const openCheckout = async (_event: Electron.IpcMainInvokeEvent) => {
const [userAuth, userPreferences] = await Promise.all([
userAuthRepository.findOne({ where: { id: 1 } }),
userPreferencesRepository.findOne({ where: { id: 1 } }),
]);
const userAuth = await userAuthRepository.findOne({ where: { id: 1 } });
if (!userAuth) {
return;
@@ -22,7 +16,6 @@ const openCheckout = async (_event: Electron.IpcMainInvokeEvent) => {
const params = new URLSearchParams({
token: paymentToken,
lng: userPreferences?.language || "en",
});
shell.openExternal(

View File

@@ -64,7 +64,10 @@ export class WindowManager {
this.mainWindow.webContents.session.webRequest.onBeforeSendHeaders(
(details, callback) => {
if (details.webContentsId !== this.mainWindow?.webContents.id) {
if (
details.webContentsId !== this.mainWindow?.webContents.id ||
details.url.includes("chatwoot")
) {
return callback(details);
}
@@ -81,15 +84,11 @@ export class WindowManager {
this.mainWindow.webContents.session.webRequest.onHeadersReceived(
(details, callback) => {
if (details.webContentsId !== this.mainWindow?.webContents.id) {
return callback(details);
}
if (details.url.includes("featurebase")) {
return callback(details);
}
if (details.url.includes("chatwoot")) {
if (
details.webContentsId !== this.mainWindow?.webContents.id ||
details.url.includes("featurebase") ||
details.url.includes("chatwoot")
) {
return callback(details);
}

View File

@@ -150,6 +150,8 @@ contextBridge.exposeInMainWorld("electron", {
/* Hardware */
getDiskFreeSpace: (path: string) =>
ipcRenderer.invoke("getDiskFreeSpace", path),
checkFolderWritePermission: (path: string) =>
ipcRenderer.invoke("checkFolderWritePermission", path),
/* Cloud save */
uploadSaveGame: (
@@ -226,6 +228,7 @@ contextBridge.exposeInMainWorld("electron", {
ipcRenderer.invoke("showOpenDialog", options),
showItemInFolder: (path: string) =>
ipcRenderer.invoke("showItemInFolder", path),
getFeatures: () => ipcRenderer.invoke("getFeatures"),
platform: process.platform,
/* Auto update */

View File

@@ -46,6 +46,12 @@ export function Modal({
}, [onClose]);
const isTopMostModal = () => {
if (
document.querySelector(
".featurebase-widget-overlay.featurebase-display-block"
)
)
return false;
const openModals = document.querySelectorAll("[role=dialog]");
return (

View File

@@ -1,6 +1,5 @@
import React, { useId, useMemo, useState } from "react";
import type { RecipeVariants } from "@vanilla-extract/recipes";
import type { FieldError, FieldErrorsImpl, Merge } from "react-hook-form";
import { EyeClosedIcon, EyeIcon } from "@primer/octicons-react";
import { useTranslation } from "react-i18next";
@@ -23,7 +22,7 @@ export interface TextFieldProps
HTMLDivElement
>;
rightContent?: React.ReactNode | null;
error?: FieldError | Merge<FieldError, FieldErrorsImpl<any>> | undefined;
error?: string | React.ReactNode;
}
export const TextField = React.forwardRef<HTMLInputElement, TextFieldProps>(
@@ -55,10 +54,7 @@ export const TextField = React.forwardRef<HTMLInputElement, TextFieldProps>(
}, [props.type, isPasswordVisible]);
const hintContent = useMemo(() => {
if (error && error.message)
return (
<small className={styles.errorLabel}>{error.message as string}</small>
);
if (error) return <small className={styles.errorLabel}>{error}</small>;
if (hint) return <small>{hint}</small>;
return null;

View File

@@ -117,11 +117,7 @@ export function GameDetailsContextProvider({
abortControllerRef.current = abortController;
window.electron
.getGameShopDetails(
objectId!,
shop as GameShop,
getSteamLanguage(i18n.language)
)
.getGameShopDetails(objectId, shop, getSteamLanguage(i18n.language))
.then((result) => {
if (abortController.signal.aborted) return;
@@ -140,14 +136,14 @@ export function GameDetailsContextProvider({
setIsLoading(false);
});
window.electron.getGameStats(objectId, shop as GameShop).then((result) => {
window.electron.getGameStats(objectId, shop).then((result) => {
if (abortController.signal.aborted) return;
setStats(result);
});
if (userDetails) {
window.electron
.getUnlockedAchievements(objectId, shop as GameShop)
.getUnlockedAchievements(objectId, shop)
.then((achievements) => {
if (abortController.signal.aborted) return;
setAchievements(achievements);

View File

@@ -31,7 +31,7 @@ import type {
CatalogueSearchPayload,
} from "@types";
import type { AxiosProgressEvent } from "axios";
import type { DiskSpace } from "check-disk-space";
import type disk from "diskusage";
declare global {
declare module "*.svg" {
@@ -140,7 +140,8 @@ declare global {
) => Promise<{ fingerprint: string }>;
/* Hardware */
getDiskFreeSpace: (path: string) => Promise<DiskSpace>;
getDiskFreeSpace: (path: string) => Promise<disk.DiskUsage>;
checkFolderWritePermission: (path: string) => Promise<boolean>;
/* Cloud save */
uploadSaveGame: (
@@ -195,6 +196,7 @@ declare global {
options: Electron.OpenDialogOptions
) => Promise<Electron.OpenDialogReturnValue>;
showItemInFolder: (path: string) => Promise<void>;
getFeatures: () => Promise<string[]>;
platform: NodeJS.Platform;
/* Auto update */

View File

@@ -6,3 +6,4 @@ export * from "./redux";
export * from "./use-user-details";
export * from "./use-format";
export * from "./use-repacks";
export * from "./use-feature";

View File

@@ -0,0 +1,23 @@
import { useEffect } from "react";
enum Feature {
CheckDownloadWritePermission = "CHECK_DOWNLOAD_WRITE_PERMISSION",
}
export function useFeature() {
useEffect(() => {
window.electron.getFeatures().then((features) => {
localStorage.setItem("features", JSON.stringify(features || []));
});
}, []);
const isFeatureEnabled = (feature: Feature) => {
const features = JSON.parse(localStorage.getItem("features") || "[]");
return features.includes(feature);
};
return {
isFeatureEnabled,
Feature,
};
}

View File

@@ -13,6 +13,7 @@ import type {
UpdateProfileRequest,
UserDetails,
} from "@types";
import * as Sentry from "@sentry/react";
import { UserFriendModalTab } from "@renderer/pages/shared-modals/user-friend-modal";
import { isFuture, isToday } from "date-fns";
@@ -30,6 +31,8 @@ export function useUserDetails() {
} = useAppSelector((state) => state.userDetails);
const clearUserDetails = useCallback(async () => {
Sentry.setUser(null);
dispatch(setUserDetails(null));
dispatch(setProfileBackground(null));
@@ -44,6 +47,12 @@ export function useUserDetails() {
const updateUserDetails = useCallback(
async (userDetails: UserDetails) => {
Sentry.setUser({
id: userDetails.id,
username: userDetails.username,
email: userDetails.email ?? undefined,
});
dispatch(setUserDetails(userDetails));
window.localStorage.setItem("userDetails", JSON.stringify(userDetails));
},

View File

@@ -31,11 +31,11 @@ export function GameItem({ game }: GameItemProps) {
const genres = useMemo(() => {
return game.genres?.map((genre) => {
const index = steamGenres["en"].findIndex(
const index = steamGenres["en"]?.findIndex(
(steamGenre) => steamGenre === genre
);
if (steamGenres[language] && steamGenres[language][index]) {
if (index && steamGenres[language] && steamGenres[language][index]) {
return steamGenres[language][index];
}

View File

@@ -36,3 +36,10 @@ export const downloaderIcon = style({
position: "absolute",
left: `${SPACING_UNIT * 2}px`,
});
export const pathError = style({
cursor: "pointer",
":hover": {
textDecoration: "underline",
},
});

View File

@@ -1,7 +1,6 @@
import { useEffect, useMemo, useState } from "react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { Trans, useTranslation } from "react-i18next";
import { DiskSpace } from "check-disk-space";
import * as styles from "./download-settings-modal.css";
import { Button, Link, Modal, TextField } from "@renderer/components";
import { CheckCircleFillIcon, DownloadIcon } from "@primer/octicons-react";
@@ -10,7 +9,7 @@ import { Downloader, formatBytes, getDownloadersForUris } from "@shared";
import type { GameRepack } from "@types";
import { SPACING_UNIT } from "@renderer/theme.css";
import { DOWNLOADER_NAME } from "@renderer/constants";
import { useAppSelector, useToast } from "@renderer/hooks";
import { useAppSelector, useFeature, useToast } from "@renderer/hooks";
export interface DownloadSettingsModalProps {
visible: boolean;
@@ -33,21 +32,45 @@ export function DownloadSettingsModal({
const { showErrorToast } = useToast();
const [diskFreeSpace, setDiskFreeSpace] = useState<DiskSpace | null>(null);
const [diskFreeSpace, setDiskFreeSpace] = useState<number | null>(null);
const [selectedPath, setSelectedPath] = useState("");
const [downloadStarting, setDownloadStarting] = useState(false);
const [selectedDownloader, setSelectedDownloader] =
useState<Downloader | null>(null);
const [hasWritePermission, setHasWritePermission] = useState<boolean | null>(
null
);
const { isFeatureEnabled, Feature } = useFeature();
const userPreferences = useAppSelector(
(state) => state.userPreferences.value
);
const getDiskFreeSpace = (path: string) => {
window.electron.getDiskFreeSpace(path).then((result) => {
setDiskFreeSpace(result.free);
});
};
const checkFolderWritePermission = useCallback(
async (path: string) => {
if (isFeatureEnabled(Feature.CheckDownloadWritePermission)) {
const result = await window.electron.checkFolderWritePermission(path);
setHasWritePermission(result);
} else {
setHasWritePermission(true);
}
},
[Feature, isFeatureEnabled]
);
useEffect(() => {
if (visible) {
getDiskFreeSpace(selectedPath);
checkFolderWritePermission(selectedPath);
}
}, [visible, selectedPath]);
}, [visible, checkFolderWritePermission, selectedPath]);
const downloaders = useMemo(() => {
return getDownloadersForUris(repack?.uris ?? []);
@@ -84,12 +107,6 @@ export function DownloadSettingsModal({
userPreferences?.realDebridApiToken,
]);
const getDiskFreeSpace = (path: string) => {
window.electron.getDiskFreeSpace(path).then((result) => {
setDiskFreeSpace(result);
});
};
const handleChooseDownloadsPath = async () => {
const { filePaths } = await window.electron.showOpenDialog({
defaultPath: selectedPath,
@@ -124,7 +141,7 @@ export function DownloadSettingsModal({
visible={visible}
title={t("download_settings")}
description={t("space_left_on_disk", {
space: formatBytes(diskFreeSpace?.free ?? 0),
space: formatBytes(diskFreeSpace ?? 0),
})}
onClose={onClose}
>
@@ -168,23 +185,32 @@ export function DownloadSettingsModal({
gap: `${SPACING_UNIT}px`,
}}
>
<div className={styles.downloadsPathField}>
<TextField
value={selectedPath}
readOnly
disabled
label={t("download_path")}
/>
<Button
style={{ alignSelf: "flex-end" }}
theme="outline"
onClick={handleChooseDownloadsPath}
disabled={downloadStarting}
>
{t("change")}
</Button>
</div>
<TextField
value={selectedPath}
readOnly
disabled
label={t("download_path")}
error={
hasWritePermission === false ? (
<span
className={styles.pathError}
data-open-article="cannot-write-directory"
>
{t("no_write_permission")}
</span>
) : undefined
}
rightContent={
<Button
style={{ alignSelf: "flex-end" }}
theme="outline"
onClick={handleChooseDownloadsPath}
disabled={downloadStarting}
>
{t("change")}
</Button>
}
/>
<p className={styles.hintText}>
<Trans i18nKey="select_folder_hint" ns="game_details">
@@ -195,7 +221,11 @@ export function DownloadSettingsModal({
<Button
onClick={handleStartClick}
disabled={downloadStarting || selectedDownloader === null}
disabled={
downloadStarting ||
selectedDownloader === null ||
!hasWritePermission
}
>
<DownloadIcon />
{t("download_now")}

View File

@@ -141,8 +141,7 @@ export function GameOptionsModal({
const shouldShowWinePrefixConfiguration =
window.electron.platform === "linux";
const shouldShowLaunchOptionsConfiguration =
window.electron.platform === "win32";
const shouldShowLaunchOptionsConfiguration = false;
return (
<>

View File

@@ -163,7 +163,7 @@ export function EditProfileModal(
minLength={3}
maxLength={50}
containerProps={{ style: { width: "100%" } }}
error={errors.displayName}
error={errors.displayName?.message}
/>
</div>

View File

@@ -105,7 +105,7 @@ export function ReportProfile() {
{...register("description")}
label={t("report_description")}
placeholder={t("report_description_placeholder")}
error={errors.description}
error={errors.description?.message}
/>
<Button

View File

@@ -150,7 +150,7 @@ export function AddDownloadSourceModal({
{...register("url")}
label={t("download_source_url")}
placeholder={t("insert_valid_json_url")}
error={errors.url}
error={errors.url?.message}
rightContent={
<Button
type="button"

View File

@@ -4381,11 +4381,6 @@ chalk@^5.3.0:
resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385"
integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==
check-disk-space@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/check-disk-space/-/check-disk-space-3.4.0.tgz#eb8e69eee7a378fd12e35281b8123a8b4c4a8ff7"
integrity sha512-drVkSqfwA+TvuEhFipiR1OC9boEGZL5RrWvVsOthdcvQNXyCCuKkEiTOTXZ7qxSf/GLwq4GvzfrQD/Wz325hgw==
chokidar@^3.5.3:
version "3.6.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
@@ -4921,6 +4916,14 @@ dir-glob@^3.0.1:
dependencies:
path-type "^4.0.0"
diskusage@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/diskusage/-/diskusage-1.2.0.tgz#3e8ae42333d5d7e0c7d93e055d7fea9ea841bc88"
integrity sha512-2u3OG3xuf5MFyzc4MctNRUKjjwK+UkovRYdD2ed/NZNZPrt0lqHnLKxGhlFVvAb4/oufIgQG3nWgwmeTbHOvXA==
dependencies:
es6-promise "^4.2.8"
nan "^2.18.0"
dmg-builder@25.1.8:
version "25.1.8"
resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-25.1.8.tgz#41f3b725edd896156e891016a44129e1bd580430"
@@ -5327,6 +5330,11 @@ es6-error@^4.1.1:
resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d"
integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==
es6-promise@^4.2.8:
version "4.2.8"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
esbuild@^0.21.3, esbuild@^0.21.5:
version "0.21.5"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d"
@@ -7425,6 +7433,11 @@ mz@^2.4.0:
object-assign "^4.0.1"
thenify-all "^1.0.0"
nan@^2.18.0:
version "2.22.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.22.0.tgz#31bc433fc33213c97bad36404bb68063de604de3"
integrity sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==
nanoid@^3.3.7:
version "3.3.7"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"