mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-11 22:06:17 +00:00
Compare commits
94 Commits
v3.5.0
...
fix/HYD-86
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3928770ef8 | ||
|
|
de1dfca57e | ||
|
|
bacf6804e4 | ||
|
|
c60584c613 | ||
|
|
e2482a6c8f | ||
|
|
27cbe755bf | ||
|
|
046debffa0 | ||
|
|
4b32015a73 | ||
|
|
4d950b30fb | ||
|
|
f50f1e51e4 | ||
|
|
97a414e77f | ||
|
|
46a6c8c987 | ||
|
|
5305e5ca18 | ||
|
|
6757ebe13c | ||
|
|
1dc91562ec | ||
|
|
2e2785c33c | ||
|
|
cf14f5a758 | ||
|
|
2ebd43d55c | ||
|
|
dac29767bd | ||
|
|
4571c7cf33 | ||
|
|
b8e3756dd9 | ||
|
|
df92852123 | ||
|
|
d6afcff5d2 | ||
|
|
9e9adfcc07 | ||
|
|
7c425eeccc | ||
|
|
b55e33f61a | ||
|
|
358c15163a | ||
|
|
0225e31947 | ||
|
|
d2b3508b5b | ||
|
|
1c6bc49ed0 | ||
|
|
e2ecfa3e3c | ||
|
|
875ef47938 | ||
|
|
550ac383e9 | ||
|
|
7a196e4315 | ||
|
|
8a6ed411ef | ||
|
|
4893d61ee3 | ||
|
|
a8482b2311 | ||
|
|
e734b6937a | ||
|
|
eab9f92b3e | ||
|
|
772aea69a9 | ||
|
|
f9d5cfce73 | ||
|
|
33cad40d5c | ||
|
|
ab7f29099d | ||
|
|
70d63934a6 | ||
|
|
61dae4cf84 | ||
|
|
022673322b | ||
|
|
9e321e9c69 | ||
|
|
0fc46236fc | ||
|
|
91c03ef5a5 | ||
|
|
ba6d04ced7 | ||
|
|
d26635784f | ||
|
|
12fc2fc1fb | ||
|
|
05e8d53783 | ||
|
|
ae77444b2d | ||
|
|
88dae597ea | ||
|
|
4dd11db8f4 | ||
|
|
4ac8f1f246 | ||
|
|
72f031b0ae | ||
|
|
c8c492bf1a | ||
|
|
eb3c1a0c8b | ||
|
|
c8ad04b065 | ||
|
|
efbdaab27b | ||
|
|
5f7b6158a2 | ||
|
|
51931df2d2 | ||
|
|
2b8fd61c16 | ||
|
|
7c2a847024 | ||
|
|
659f811c09 | ||
|
|
2224b00c57 | ||
|
|
b56ed48855 | ||
|
|
d3ed8dee7c | ||
|
|
54a40d0ccc | ||
|
|
186837d9f9 | ||
|
|
ec3920fc34 | ||
|
|
5a3aa7e8c6 | ||
|
|
7bb7d2e388 | ||
|
|
b1fc9073d6 | ||
|
|
a1a86c7045 | ||
|
|
81cecfe558 | ||
|
|
9a0e3bfc65 | ||
|
|
f7b88b6d31 | ||
|
|
a996519bd8 | ||
|
|
e85d08422e | ||
|
|
73de69b5a6 | ||
|
|
9172098027 | ||
|
|
f19391200c | ||
|
|
5e51877660 | ||
|
|
6bc2d83ffb | ||
|
|
75ac9e8281 | ||
|
|
650b02e673 | ||
|
|
93929ae15f | ||
|
|
95eecb7161 | ||
|
|
0b83554565 | ||
|
|
4485f62946 | ||
|
|
42c3671965 |
Binary file not shown.
19
package.json
19
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hydralauncher",
|
||||
"version": "3.5.0",
|
||||
"version": "3.6.0",
|
||||
"description": "Hydra",
|
||||
"main": "./out/main/index.js",
|
||||
"author": "Los Broxas",
|
||||
@@ -56,20 +56,22 @@
|
||||
"diskusage": "^1.2.0",
|
||||
"electron-log": "^5.2.4",
|
||||
"electron-updater": "^6.6.2",
|
||||
"file-type": "^19.6.0",
|
||||
"file-type": "^20.5.0",
|
||||
"framer-motion": "^12.15.0",
|
||||
"i18next": "^23.11.2",
|
||||
"i18next-browser-languagedetector": "^7.2.1",
|
||||
"jsdom": "^24.0.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"lodash-es": "^4.17.21",
|
||||
"parse-torrent": "^11.0.17",
|
||||
"rc-virtual-list": "^3.16.1",
|
||||
"parse-torrent": "^11.0.18",
|
||||
"rc-virtual-list": "^3.18.3",
|
||||
"react-hook-form": "^7.53.0",
|
||||
"react-i18next": "^14.1.0",
|
||||
"react-loading-skeleton": "^3.4.0",
|
||||
"react-redux": "^9.1.1",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"react-tooltip": "^5.28.0",
|
||||
"react-shadow": "^20.6.0",
|
||||
"react-tooltip": "^5.28.1",
|
||||
"sound-play": "^1.1.0",
|
||||
"steam-shortcut-editor": "https://github.com/hydralauncher/steam-shortcut-editor",
|
||||
"sudo-prompt": "^9.2.1",
|
||||
@@ -105,9 +107,9 @@
|
||||
"@types/winreg": "^1.2.36",
|
||||
"@types/ws": "^8.18.1",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"electron": "^31.7.7",
|
||||
"electron": "^32.3.3",
|
||||
"electron-builder": "^26.0.12",
|
||||
"electron-vite": "^2.3.0",
|
||||
"electron-vite": "^3.0.0",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||
"eslint-plugin-react": "^7.37.4",
|
||||
@@ -121,5 +123,6 @@
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.0.12",
|
||||
"vite-plugin-svgr": "^4.2.0"
|
||||
}
|
||||
},
|
||||
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ from torrent_downloader import TorrentDownloader
|
||||
from http_downloader import HttpDownloader
|
||||
from profile_image_processor import ProfileImageProcessor
|
||||
import libtorrent as lt
|
||||
import os
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@@ -102,8 +103,26 @@ def process_list():
|
||||
if auth_error:
|
||||
return auth_error
|
||||
|
||||
process_list = [proc.info for proc in psutil.process_iter(['exe', 'pid', 'name'])]
|
||||
return jsonify(process_list), 200
|
||||
processes = []
|
||||
|
||||
for proc in psutil.process_iter(['exe', 'cwd', 'pid', 'cmdline']):
|
||||
try:
|
||||
info = proc.info
|
||||
cmdline = info.get('cmdline') or []
|
||||
wine_launched_exe = None
|
||||
|
||||
for arg in cmdline:
|
||||
if isinstance(arg, str) and arg.lower().endswith(".exe"):
|
||||
wine_launched_exe = os.path.basename(arg)
|
||||
break
|
||||
|
||||
exe_path = info.get('exe') or ''
|
||||
info['name'] = wine_launched_exe or os.path.basename(exe_path)
|
||||
processes.append(info)
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
|
||||
continue
|
||||
|
||||
return jsonify(processes), 200
|
||||
|
||||
@app.route("/profile-image", methods=["POST"])
|
||||
def profile_image():
|
||||
|
||||
@@ -1,88 +1,88 @@
|
||||
{
|
||||
"language_name": "Български",
|
||||
"app": {
|
||||
"successfully_signed_in": "Успешно вписване"
|
||||
"successfully_signed_in": "Успешно влизане"
|
||||
},
|
||||
"home": {
|
||||
"featured": "Препоръчани",
|
||||
"surprise_me": "Изненадай ме",
|
||||
"no_results": "Не са намерени резултати",
|
||||
"start_typing": "Търсене...",
|
||||
"hot": "Актуално сега",
|
||||
"weekly": "📅 Най-доброто от седмицата",
|
||||
"achievements": "🏆 Игри, които да победите"
|
||||
"no_results": "Няма намерени резултати",
|
||||
"start_typing": "Започнете да пишете за търсене...",
|
||||
"hot": "Горещи сега",
|
||||
"weekly": "📅 Топ игри на седмицата",
|
||||
"achievements": "🏆 Игри които да победите"
|
||||
},
|
||||
"sidebar": {
|
||||
"catalogue": "Каталог",
|
||||
"downloads": "Изтегляния",
|
||||
"settings": "Настройки",
|
||||
"my_library": "Моята библиотека",
|
||||
"downloading_metadata": "{{title}} (Сваляне на метаданни…)",
|
||||
"paused": "{{title}} (Пауза)",
|
||||
"downloading_metadata": "{{title}} (Изтегляне на метаданни…)",
|
||||
"paused": "{{title}} (На пауза)",
|
||||
"downloading": "{{title}} ({{percentage}} - Изтегляне…)",
|
||||
"filter": "Търсене по име",
|
||||
"filter": "Филтрирай библиотеката",
|
||||
"home": "Начало",
|
||||
"queued": "{{title}} (Опашка)",
|
||||
"game_has_no_executable": "Играта няма избран изпълним файл",
|
||||
"sign_in": "Вписване",
|
||||
"queued": "{{title}} (В опашката)",
|
||||
"game_has_no_executable": "Няма избран изпълним файл за играта",
|
||||
"sign_in": "Вход",
|
||||
"friends": "Приятели",
|
||||
"need_help": "Имате нужда от помощ??",
|
||||
"favorites": "Любими игри"
|
||||
"need_help": "Нужда от помощ?",
|
||||
"favorites": "Любими"
|
||||
},
|
||||
"header": {
|
||||
"search": "Търсене",
|
||||
"search": "Търси игри",
|
||||
"home": "Начало",
|
||||
"catalogue": "Каталог",
|
||||
"downloads": "Изтегляния",
|
||||
"search_results": "Резултати от търсене",
|
||||
"search_results": "Резултати от търсенето",
|
||||
"settings": "Настройки",
|
||||
"version_available_install": "Версия {{version}} е налична. Кликни тук, за да рестартирате и инсталирате.",
|
||||
"version_available_download": "Версия {{version}} е налична. Кликни тук за изтегляне."
|
||||
"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}} завършено)",
|
||||
"installing_common_redist": "{{log}}…",
|
||||
"installation_complete": "Инсталацията завършена",
|
||||
"installation_complete_message": "Общите компоненти са инсталирани успешно"
|
||||
},
|
||||
"catalogue": {
|
||||
"search": "Филтър…",
|
||||
"search": "Филтрирай…",
|
||||
"developers": "Разработчици",
|
||||
"genres": "Жанрове",
|
||||
"tags": "Тагове",
|
||||
"publishers": "Издатели",
|
||||
"download_sources": "Източници за изтегляне",
|
||||
"result_count": "{{resultCount}} резултати",
|
||||
"result_count": "{{resultCount}} резултата",
|
||||
"filter_count": "{{filterCount}} налични",
|
||||
"clear_filters": "Изчисти {{filterCount}} избрани"
|
||||
},
|
||||
"game_details": {
|
||||
"launch_options": "Опции за стартиране",
|
||||
"launch_options_description": "Напредналите потребители могат да въведат модификации на своите опции за стартиране (экспериментальный)",
|
||||
"launch_options_placeholder": "Няма зададен параметър",
|
||||
"open_download_options": "Варианти за изтегляне",
|
||||
"download_options_zero": "Няма варианти за изтегляне",
|
||||
"download_options_one": "{{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": "Филтрирай repacks",
|
||||
"space_left_on_disk": "{{space}} свободно на диска",
|
||||
"eta": "Завършване {{eta}}",
|
||||
"calculating_eta": "Изчисляване на оставащо време…",
|
||||
"downloading_metadata": "Изтегляне на метаданни…",
|
||||
"filter": "Филтрирай репаковки",
|
||||
"requirements": "Системни изисквания",
|
||||
"minimum": "Минимални",
|
||||
"recommended": "Препоръчителни",
|
||||
"paused": "Паузирано",
|
||||
"release_date": "Издадено на {{date}}",
|
||||
"publisher": "Публикувано от {{publisher}}",
|
||||
"hours": "часове",
|
||||
"paused": "На пауза",
|
||||
"release_date": "Издадена на {{date}}",
|
||||
"publisher": "Издател: {{publisher}}",
|
||||
"hours": "часа",
|
||||
"minutes": "минути",
|
||||
"amount_hours": "{{amount}} часа",
|
||||
"amount_minutes": "{{amount}} минути",
|
||||
@@ -90,333 +90,425 @@
|
||||
"add_to_library": "Добави в библиотеката",
|
||||
"remove_from_library": "Премахни от библиотеката",
|
||||
"no_downloads": "Няма налични изтегляния",
|
||||
"play_time": "Игрално време {{amount}}",
|
||||
"last_time_played": "Последно пускане {{period}}",
|
||||
"not_played_yet": "Не сте играли {{title}} все още",
|
||||
"play_time": "Играно: {{amount}}",
|
||||
"last_time_played": "Последно играно: {{period}}",
|
||||
"not_played_yet": "Все още не сте играли {{title}}",
|
||||
"next_suggestion": "Следващо предложение",
|
||||
"play": "Пускане",
|
||||
"deleting": "Изтриване на инсталация…",
|
||||
"play": "Играй",
|
||||
"deleting": "Изтриване на инсталатора…",
|
||||
"close": "Затвори",
|
||||
"playing_now": "Играй сега",
|
||||
"change": "Промяна",
|
||||
"repacks_modal_description": "Избери repack който искаш да изтеглиш",
|
||||
"select_folder_hint": "За да промените стандартната папка отидете в <0>Настройки</0>",
|
||||
"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": "Downloader",
|
||||
"no_shop_details": "Неуспешно извличане на детайли от магазина.",
|
||||
"download_options": "Опции за изтегляне",
|
||||
"download_path": "Път за изтегляне",
|
||||
"previous_screenshot": "Предишен скрийншот",
|
||||
"next_screenshot": "Следващ скрийншот",
|
||||
"screenshot": "Скрийншот {{number}}",
|
||||
"open_screenshot": "Отвори скрийншот {{number}}",
|
||||
"download_settings": "Настройки за изтегляне",
|
||||
"downloader": "Изтегляч",
|
||||
"select_executable": "Избери",
|
||||
"no_executable_selected": "Няма избран стартиращ файл",
|
||||
"no_executable_selected": "Няма избран изпълним файл",
|
||||
"open_folder": "Отвори папка",
|
||||
"open_download_location": "Виж свалените файлове",
|
||||
"create_shortcut": "Пряк път на Десктопа",
|
||||
"open_download_location": "Виж изтеглените файлове",
|
||||
"create_shortcut": "Създай пряк път на работния плот",
|
||||
"clear": "Изчисти",
|
||||
"remove_files": "Премахни файловете",
|
||||
"remove_from_library_title": "Сигурен ли си?",
|
||||
"remove_from_library_description": "Това ще премахне {{game}} от Библиотеката",
|
||||
"remove_from_library_title": "Сигурни ли сте?",
|
||||
"remove_from_library_description": "Това ще премахне {{game}} от вашата библиотека",
|
||||
"options": "Опции",
|
||||
"executable_section_title": "Стартиращ файл",
|
||||
"executable_section_description": "Пътят на файла, който ще се изпълни, когато се щракне върху \"Пускане\"",
|
||||
"downloads_section_title": "Свалени",
|
||||
"downloads_section_description": "Вижте актуализации или други версии на тази игра",
|
||||
"executable_section_title": "Изпълним файл",
|
||||
"executable_section_description": "Пътят на файла, който ще се изпълни при \"Играй\"",
|
||||
"downloads_section_title": "Изтегляния",
|
||||
"downloads_section_description": "Вижте обновления или други версии на тази игра",
|
||||
"danger_zone_section_title": "Опасна зона",
|
||||
"danger_zone_section_description": "Премахнете тази игра от библиотеката си или от файловете, изтеглени от Hydra",
|
||||
"download_in_progress": "Изтегляне в ход",
|
||||
"download_paused": "Изтеглянето е паузирано",
|
||||
"last_downloaded_option": "Опция от последно изтегляне",
|
||||
"danger_zone_section_description": "Премахнете тази игра от библиотеката или файловете, изтеглени от Hydra",
|
||||
"download_in_progress": "Изтеглянето е в ход",
|
||||
"download_paused": "Изтеглянето е на пауза",
|
||||
"last_downloaded_option": "Последно изтеглена опция",
|
||||
"create_steam_shortcut": "Създай пряк път за Steam",
|
||||
"create_shortcut_success": "Прекият път е създаден успешно",
|
||||
"create_shortcut_error": "Грешка при създаването на пряк път",
|
||||
"you_might_need_to_restart_steam": "Може да е необходимо да рестартирате Steam, за да видите промените",
|
||||
"create_shortcut_error": "Грешка при създаване на пряк път",
|
||||
"nsfw_content_title": "Тази игра съдържа неподходящо съдържание",
|
||||
"nsfw_content_description": "{{title}} съдържа съдържание, което може да не е подходящо за всички възрасти. Сигурни ли сте, че искате да продължите?",
|
||||
"allow_nsfw_content": "Продължи",
|
||||
"refuse_nsfw_content": "Назад",
|
||||
"refuse_nsfw_content": "Върни се",
|
||||
"stats": "Статистики",
|
||||
"download_count": "Сваляния",
|
||||
"download_count": "Изтегляния",
|
||||
"player_count": "Активни играчи",
|
||||
"download_error": "Тази опция за изтегляне не е налична",
|
||||
"download": "Свали",
|
||||
"download": "Изтегли",
|
||||
"executable_path_in_use": "Изпълнимият файл вече се използва от \"{{game}}\"",
|
||||
"warning": "Внимание:",
|
||||
"hydra_needs_to_remain_open": "за това изтегляне, Hydra трябва да остане отворена, когато е завършено. Ако Hydra се затвори преди завършването, ще загубите напредъка си..",
|
||||
"hydra_needs_to_remain_open": "за това изтегляне, Hydra трябва да остане отворена до завършване. Ако затворите преди завършване, ще загубите прогреса.",
|
||||
"achievements": "Постижения",
|
||||
"achievements_count": "Постижения {{unlockedCount}}/{{achievementsCount}}",
|
||||
"cloud_save": "Запазване в облака",
|
||||
"cloud_save_description": "Запазете напредъка си в облака и продължете да играете на всяко устройство",
|
||||
"backups": "Резервни копия",
|
||||
"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": "Вижте всички постижения",
|
||||
"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": "Управление на файлове",
|
||||
"mapping_method_label": "Метод на съпоставяне",
|
||||
"files_automatically_mapped": "Файловете са съпоставени автоматично",
|
||||
"no_backups_created": "Няма създадени архиви за тази игра",
|
||||
"manage_files": "Управлявай файлове",
|
||||
"loading_save_preview": "Търсене на запазени игри…",
|
||||
"wine_prefix": "Wine Префикс",
|
||||
"wine_prefix_description": "Wine prefix използван за тази игра",
|
||||
"no_download_option_info": "Няма налични данни",
|
||||
"backup_deletion_failed": "Неуспешно изтриване на резервно копие",
|
||||
"max_number_of_artifacts_reached": "Достигнат максимален брой резервни копия за тази игра",
|
||||
"achievements_not_sync": "Постиженията не са синхронизирани",
|
||||
"manage_files_description": "Управлявайте кои файлове ще бъдат архивирани и възстановени",
|
||||
"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": "Задаване на персонализирано местоположение за архивиране"
|
||||
"backup_from": "Архив от {{date}}",
|
||||
"automatic_backup_from": "Автоматичен архив от {{date}}",
|
||||
"enable_automatic_cloud_sync": "Включи автоматична синхронизация с облака",
|
||||
"custom_backup_location_set": "Зададено е персонализирано място за архив",
|
||||
"no_directory_selected": "Няма избрана директория",
|
||||
"no_write_permission": "Не може да се изтегли в тази директория. Кликнете тук за повече информация.",
|
||||
"reset_achievements": "Нулирай постиженията",
|
||||
"reset_achievements_description": "Това ще нулира всички постижения за {{game}}",
|
||||
"reset_achievements_title": "Сигурни ли сте?",
|
||||
"reset_achievements_success": "Постиженията са нулирани успешно",
|
||||
"reset_achievements_error": "Неуспешно нулиране на постиженията",
|
||||
"download_error_gofile_quota_exceeded": "Превишихте месечната си квота в Gofile. Моля, изчакайте тя да се възстанови.",
|
||||
"download_error_real_debrid_account_not_authorized": "Вашият Real-Debrid акаунт не е упълномощен за нови изтегляния. Моля, проверете настройките на акаунта и опитайте отново.",
|
||||
"download_error_not_cached_on_real_debrid": "Това изтегляне не е налично в Real-Debrid и не може да се следи статуса.",
|
||||
"download_error_not_cached_on_torbox": "Това изтегляне не е налично в TorBox и не може да се следи статуса.",
|
||||
"download_error_not_cached_on_hydra": "Това изтегляне не е налично в Nimbus.",
|
||||
"game_removed_from_favorites": "Играта е премахната от любими",
|
||||
"game_added_to_favorites": "Играта е добавена в любими",
|
||||
"automatically_extract_downloaded_files": "Автоматично извличане на изтеглени файлове",
|
||||
"create_start_menu_shortcut": "Създай пряк път в старт менюто",
|
||||
"invalid_wine_prefix_path": "Невалиден път до Wine префикса",
|
||||
"invalid_wine_prefix_path_description": "Пътят до Wine префикса е невалиден. Моля, проверете го и опитайте отново.",
|
||||
"missing_wine_prefix": "Wine префикс е необходим за създаване на архив в Linux"
|
||||
},
|
||||
"activation": {
|
||||
"title": "Активирай Hydra",
|
||||
"installation_id": "Идентификатор на инсталацията:",
|
||||
"enter_activation_code": "Въведете кода за активиране",
|
||||
"message": "Ако не знаете къде да попитате за това, значи не трябва да го имате..",
|
||||
"installation_id": "Инсталационен ID:",
|
||||
"enter_activation_code": "Въведете активационен код",
|
||||
"message": "Ако не знаете къде да попитате за това, не бива да го имате.",
|
||||
"activate": "Активирай",
|
||||
"loading": "Зареждане…"
|
||||
},
|
||||
"downloads": {
|
||||
"seeding": "Сийдване",
|
||||
"stop_seeding": "Спри сийдването",
|
||||
"resume_seeding": "Продължи сийдването",
|
||||
"options": "Управление",
|
||||
"resume": "Продължи",
|
||||
"pause": "Пауза",
|
||||
"eta": "Conclusion {{eta}}",
|
||||
"paused": "Паузирано",
|
||||
"eta": "Завършване {{eta}}",
|
||||
"paused": "На пауза",
|
||||
"verifying": "Проверка…",
|
||||
"completed": "Готово",
|
||||
"removed": "Не е изтеглен",
|
||||
"completed": "Завършено",
|
||||
"removed": "Не е изтеглено",
|
||||
"cancel": "Отказ",
|
||||
"filter": "Филтриране на изтеглени игри",
|
||||
"filter": "Филтрирай изтеглените игри",
|
||||
"remove": "Премахни",
|
||||
"downloading_metadata": "Изтегляне на метаданни…",
|
||||
"deleting": "Изтриване на инсталатора…",
|
||||
"delete": "Премахване на инсталатора",
|
||||
"delete_modal_title": "Сигурени ли сте?",
|
||||
"delete_modal_description": "Това ще премахне всички инсталационни файлове от компютъра ви.",
|
||||
"delete": "Премахни инсталатора",
|
||||
"delete_modal_title": "Сигурни ли сте?",
|
||||
"delete_modal_description": "Това ще премахне всички инсталационни файлове от компютъра ви",
|
||||
"install": "Инсталирай",
|
||||
"download_in_progress": "В процес на изпълнение",
|
||||
"queued_downloads": "Изтеглени файлове в опашката",
|
||||
"downloads_completed": "Приключени",
|
||||
"queued": "В опашка",
|
||||
"download_in_progress": "В процес",
|
||||
"queued_downloads": "Изтегляния на опашка",
|
||||
"downloads_completed": "Завършени",
|
||||
"queued": "В опашката",
|
||||
"no_downloads_title": "Толкова е празно",
|
||||
"no_downloads_description": "Все още не сте изтеглили нищо с Hydra, но никога не е късно да започнете...",
|
||||
"checking_files": "Проверка на файлове…"
|
||||
"no_downloads_description": "Все още не сте изтеглили нищо с Hydra, но никога не е късно да започнете.",
|
||||
"checking_files": "Проверка на файлове…",
|
||||
"seeding": "Сийдване",
|
||||
"stop_seeding": "Спри сийдването",
|
||||
"resume_seeding": "Продължи сийдването",
|
||||
"options": "Управлявай",
|
||||
"extract": "Извлечи файловете",
|
||||
"extracting": "Извличане на файловете…"
|
||||
},
|
||||
"settings": {
|
||||
"seed_after_download_complete": "Сийд след завършване на изтеглянето",
|
||||
"show_hidden_achievement_description": "Показвай описанието на скритите постижения преди отключването им",
|
||||
"downloads_path": "Инсталационен път",
|
||||
"change": "Актуализиране",
|
||||
"downloads_path": "Път за изтегляния",
|
||||
"change": "Обнови",
|
||||
"notifications": "Известия",
|
||||
"enable_download_notifications": "Когато изтеглянето е завършено",
|
||||
"enable_repack_list_notifications": "Когато се добави нов repack",
|
||||
"enable_download_notifications": "Когато изтеглянето приключи",
|
||||
"enable_repack_list_notifications": "Когато бъде добавен нов репак",
|
||||
"real_debrid_api_token_label": "Real-Debrid API токен",
|
||||
"quit_app_instead_hiding": "Не скривайте Hydra при затваряне",
|
||||
"launch_with_system": "Стартиране на Hydra при стартиране на системата",
|
||||
"quit_app_instead_hiding": "Не скривай Hydra при затваряне",
|
||||
"launch_with_system": "Стартирай Hydra при стартиране на системата",
|
||||
"general": "Общи",
|
||||
"behavior": "Поведение",
|
||||
"download_sources": "Източници за изтегляне",
|
||||
"language": "Език",
|
||||
"api_token": "API Токен",
|
||||
"api_token": "API токен",
|
||||
"enable_real_debrid": "Включи Real-Debrid",
|
||||
"real_debrid_description": "Real-Debrid е неограничен даунлоудър, който ви позволява бързо да изтегляте файлове, ограничени само от скоростта на интернет..",
|
||||
"real_debrid_description": "Real-Debrid е неограничен изтегляч, който ви позволява да теглите бързо, ограничено само от интернет връзката ви.",
|
||||
"debrid_invalid_token": "Невалиден API токен",
|
||||
"debrid_api_token_hint": "Вземете своя API токен <0>тук</0>",
|
||||
"real_debrid_free_account_error": "Акаунтът \"{{username}}\" е безплатен акаунт. Моля абонирай се за Real-Debrid",
|
||||
"debrid_linked_message": "Акаунтът \"{{username}}\" е свързан",
|
||||
"debrid_api_token_hint": "Може да получите вашия API токен <0>тук</0>",
|
||||
"real_debrid_free_account_error": "Акаунтът \"{{username}}\" е безплатен. Моля, абонирайте се за Real-Debrid",
|
||||
"debrid_linked_message": "Акаунт \"{{username}}\" е свързан",
|
||||
"save_changes": "Запази промените",
|
||||
"changes_saved": "Промените са успешно запазни",
|
||||
"download_sources_description": "Hydra ще извлича връзките за изтегляне от тези източници. URL адресът на източника трябва да е директна връзка към .json файл, съдържащ връзките за изтегляне.",
|
||||
"validate_download_source": "Валидиране",
|
||||
"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": "URL адрес на източника за изтегляне",
|
||||
"add_download_source_description": "Вмъкнете URL адреса на файла .json",
|
||||
"download_source_up_to_date": "Актуален",
|
||||
"download_source_errored": "Сгрешен",
|
||||
"sync_download_sources": "Синхронизирай източниците",
|
||||
"removed_download_source": "Източника за сваляне е премахнат",
|
||||
"cancel_button_confirmation_delete_all_sources": "не",
|
||||
"confirm_button_confirmation_delete_all_sources": "Да, удалить все",
|
||||
"description_confirmation_delete_all_sources": "Вы удалите все источники загрузки",
|
||||
"title_confirmation_delete_all_sources": "Удалить все источники загрузки",
|
||||
"removed_download_sources": "Шрифты удалены",
|
||||
"button_delete_all_sources": "Удалить все источники загрузки",
|
||||
"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": "Личен",
|
||||
"download_count_zero": "Няма опции за изтегляне",
|
||||
"download_count_one": "{{countFormatted}} опция за изтегляне",
|
||||
"download_count_other": "{{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": "Източникът е премахнат",
|
||||
"removed_download_sources": "Източниците са премахнати",
|
||||
"cancel_button_confirmation_delete_all_sources": "Не",
|
||||
"confirm_button_confirmation_delete_all_sources": "Да, изтрий всичко",
|
||||
"title_confirmation_delete_all_sources": "Изтрий всички източници",
|
||||
"description_confirmation_delete_all_sources": "Ще изтриете всички източници",
|
||||
"button_delete_all_sources": "Премахни всички",
|
||||
"added_download_source": "Източникът е добавен",
|
||||
"download_sources_synced": "Всички източници са синхронизирани",
|
||||
"insert_valid_json_url": "Въведете валиден JSON url",
|
||||
"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 адрес.",
|
||||
"must_be_valid_url": "Източникът трябва да е валиден URL",
|
||||
"blocked_users": "Блокирани потребители",
|
||||
"user_unblocked": "Потребителят е бил деблокиран",
|
||||
"enable_achievement_notifications": "Когато е отключено постижение",
|
||||
"launch_minimized": "Стартиране на Hydra минимизирано",
|
||||
"disable_nsfw_alert": "Деактивиране на предупреждението NSFW"
|
||||
"user_unblocked": "Потребителят е деблокиран",
|
||||
"enable_achievement_notifications": "Когато бъде отключено постижение",
|
||||
"launch_minimized": "Стартирай Hydra минимизирано",
|
||||
"disable_nsfw_alert": "Изключи NSFW предупреждението",
|
||||
"seed_after_download_complete": "Сийдвай след завършване на изтеглянето",
|
||||
"show_hidden_achievement_description": "Показвай описанието на скритите постижения преди отключване",
|
||||
"account": "Акаунт",
|
||||
"no_users_blocked": "Нямате блокирани потребители",
|
||||
"subscription_active_until": "Hydra Cloud е активен до {{date}}",
|
||||
"manage_subscription": "Управлявай абонамента",
|
||||
"update_email": "Обнови имейл",
|
||||
"update_password": "Обнови парола",
|
||||
"current_email": "Текущ имейл:",
|
||||
"no_email_account": "Все още не сте задали имейл",
|
||||
"account_data_updated_successfully": "Данните на акаунта са обновени успешно",
|
||||
"renew_subscription": "Поднови Hydra Cloud",
|
||||
"subscription_expired_at": "Абонаментът изтече на {{date}}",
|
||||
"no_subscription": "Наслаждавайте се на Hydra по най-добрия начин",
|
||||
"become_subscriber": "Станете абонат на Hydra Cloud",
|
||||
"subscription_renew_cancelled": "Автоматичното подновяване е изключено",
|
||||
"subscription_renews_on": "Абонаментът се подновява на {{date}}",
|
||||
"bill_sent_until": "Следващата фактура ще бъде изпратена до този ден",
|
||||
"no_themes": "Изглежда, че все още нямате теми. Кликнете тук, за да създадете първата си.",
|
||||
"editor_tab_code": "Код",
|
||||
"editor_tab_info": "Информация",
|
||||
"editor_tab_save": "Запази",
|
||||
"web_store": "Уеб магазин",
|
||||
"clear_themes": "Изчисти",
|
||||
"create_theme": "Създай",
|
||||
"create_theme_modal_title": "Създай персонализирана тема",
|
||||
"create_theme_modal_description": "Създайте нова тема за персонализиране на външния вид на Hydra",
|
||||
"theme_name": "Име",
|
||||
"insert_theme_name": "Въведете име на тема",
|
||||
"set_theme": "Задай тема",
|
||||
"unset_theme": "Премахни тема",
|
||||
"delete_theme": "Изтрий тема",
|
||||
"edit_theme": "Редактирай тема",
|
||||
"delete_all_themes": "Изтрий всички теми",
|
||||
"delete_all_themes_description": "Това ще изтрие всички ваши персонализирани теми",
|
||||
"delete_theme_description": "Това ще изтрие темата {{theme}}",
|
||||
"cancel": "Отказ",
|
||||
"appearance": "Външен вид",
|
||||
"enable_torbox": "Включи TorBox",
|
||||
"torbox_description": "TorBox е вашият премиум seedbox, съперничещ на най-добрите сървъри на пазара.",
|
||||
"torbox_account_linked": "TorBox акаунтът е свързан",
|
||||
"create_real_debrid_account": "Кликнете тук, ако все още нямате Real-Debrid акаунт",
|
||||
"create_torbox_account": "Кликнете тук, ако все още нямате TorBox акаунт",
|
||||
"real_debrid_account_linked": "Real-Debrid акаунтът е свързан",
|
||||
"name_min_length": "Името на темата трябва да е поне 3 символа",
|
||||
"import_theme": "Импортирай тема",
|
||||
"import_theme_description": "Ще импортирате {{theme}} от магазина с теми",
|
||||
"error_importing_theme": "Грешка при импортиране на тема",
|
||||
"theme_imported": "Темата е импортирана успешно",
|
||||
"enable_friend_request_notifications": "Когато получите заявка за приятелство",
|
||||
"enable_auto_install": "Автоматично изтегляй обновления",
|
||||
"common_redist": "Общи компоненти",
|
||||
"common_redist_description": "Общите компоненти са нужни за някои игри. Препоръчва се инсталация.",
|
||||
"install_common_redist": "Инсталирай",
|
||||
"installing_common_redist": "Инсталиране…",
|
||||
"show_download_speed_in_megabytes": "Показвай скоростта на изтегляне в MB/s",
|
||||
"extract_files_by_default": "Извличай файловете по подразбиране след изтегляне"
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "Изтеглянето е завършено",
|
||||
"game_ready_to_install": "{{title}} е готово за инсталиране",
|
||||
"repack_list_updated": "Repack лист е обновен",
|
||||
"repack_count_one": "{{count}} repack е добавен",
|
||||
"repack_count_other": "{{count}} repacks добавени",
|
||||
"new_update_available": "Версия {{version}} е налична",
|
||||
"restart_to_install_update": "Рестартирайте Hydra, за да инсталирате актуализацията",
|
||||
"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}} са отклщчени"
|
||||
"notification_achievement_unlocked_body": "{{achievement}} и още {{count}} бяха отключени",
|
||||
"new_friend_request_description": "{{displayName}} ви изпрати заявка за приятелство",
|
||||
"new_friend_request_title": "Нова заявка за приятелство",
|
||||
"extraction_complete": "Извличането завърши",
|
||||
"game_extracted": "{{title}} е извлечена успешно",
|
||||
"friend_started_playing_game": "{{displayName}} започна да играе игра"
|
||||
},
|
||||
"system_tray": {
|
||||
"open": "Отвори Hydra",
|
||||
"quit": "Изход"
|
||||
},
|
||||
"game_card": {
|
||||
"available_one": "Налично",
|
||||
"available_other": "Налично",
|
||||
"no_downloads": "Няма налични изтегляния"
|
||||
},
|
||||
"binary_not_found_modal": {
|
||||
"title": "Не инсталирани програми",
|
||||
"description": "Wine или Lutris изпълними файлове не бяха открити на вашата система",
|
||||
"instructions": "Проверете правилния начин за инсталиране на някоя от тях на вашата дистрибуция на Linux, за да може играта да работи нормално"
|
||||
"title": "Програмите не са инсталирани",
|
||||
"description": "Wine или Lutris не са открити на вашата система",
|
||||
"instructions": "Проверете как да инсталирате някоя от тях за вашата Linux дистрибуция, за да може играта да работи."
|
||||
},
|
||||
"modal": {
|
||||
"close": "Бутон за затваряне"
|
||||
},
|
||||
"forms": {
|
||||
"toggle_password_visibility": "Превключване на видимостта на паролата"
|
||||
"toggle_password_visibility": "Показване/скриване на паролата"
|
||||
},
|
||||
"user_profile": {
|
||||
"stats": "Статистики",
|
||||
"achievements": "Постижения",
|
||||
"games": "Игри",
|
||||
"top_percentile": "Топ {{percentile}}%",
|
||||
"ranking_updated_weekly": "Класацията се актуализира седмично",
|
||||
"playing": "Играе {{game}}",
|
||||
"achievements_unlocked": "Отключени постижения",
|
||||
"earned_points": "Спечелени точки",
|
||||
"show_achievements_on_profile": "Показвай своите постижения в профила",
|
||||
"show_points_on_profile": "Показвай спечелените точки в профила",
|
||||
"amount_hours": "{{amount}} часове",
|
||||
"amount_hours": "{{amount}} часа",
|
||||
"amount_minutes": "{{amount}} минути",
|
||||
"last_time_played": "Последно играно {{period}}",
|
||||
"activity": "Скорошна активност",
|
||||
"last_time_played": "Последно играно: {{period}}",
|
||||
"activity": "Последна активност",
|
||||
"library": "Библиотека",
|
||||
"total_play_time": "Общо време за игра",
|
||||
"no_recent_activity_title": "Хмм… няма нищо тук",
|
||||
"no_recent_activity_description": "Не сте играли игри напоследък. Време е да промените това.!",
|
||||
"display_name": "Показване на името",
|
||||
"no_recent_activity_title": "Хммм… няма нищо тук",
|
||||
"no_recent_activity_description": "Не сте играли игри наскоро. Време е да го промените!",
|
||||
"display_name": "Показвано име",
|
||||
"saving": "Запазване",
|
||||
"save": "Запис",
|
||||
"edit_profile": "Редактиране на профила",
|
||||
"saved_successfully": "Запазено успешно",
|
||||
"try_again": "Моля, опитайте пак",
|
||||
"save": "Запази",
|
||||
"edit_profile": "Редактирай профил",
|
||||
"saved_successfully": "Успешно запазено",
|
||||
"try_again": "Моля, опитайте отново",
|
||||
"sign_out_modal_title": "Сигурни ли сте?",
|
||||
"cancel": "Отказ",
|
||||
"successfully_signed_out": "Успешно се отписахте",
|
||||
"sign_out": "Отписване",
|
||||
"playing_for": "В игра от {{amount}}",
|
||||
"sign_out_modal_text": "Вашата библиотека е свързана с текущата ви сметка. Когато се отпишете, библиотеката ви вече няма да е видима и напредъкът няма да бъде запазен. Продължете с отписването?",
|
||||
"successfully_signed_out": "Успешно излязохте",
|
||||
"sign_out": "Изход",
|
||||
"playing_for": "Играе се от {{amount}}",
|
||||
"sign_out_modal_text": "Библиотеката ви е свързана с този акаунт. При изход, тя няма да е видима, а прогресът няма да се запази. Продължавате ли?",
|
||||
"add_friends": "Добави приятели",
|
||||
"add": "Добави",
|
||||
"friend_code": "Приятелски код",
|
||||
"friend_code": "Код за приятелство",
|
||||
"see_profile": "Виж профила",
|
||||
"sending": "Изпращане",
|
||||
"friend_request_sent": "Изпратена покана за приятелство",
|
||||
"friend_request_sent": "Заявката е изпратена",
|
||||
"friends": "Приятели",
|
||||
"friends_list": "Списък с приятели",
|
||||
"user_not_found": "Не е намерен потребител",
|
||||
"user_not_found": "Потребителят не е намерен",
|
||||
"block_user": "Блокирай потребител",
|
||||
"add_friend": "Добави приятел",
|
||||
"request_sent": "Изпратена покана",
|
||||
"request_received": "Получена покана",
|
||||
"accept_request": "Приеми поканата",
|
||||
"ignore_request": "Игнирирай поканата",
|
||||
"cancel_request": "Откажи поканата",
|
||||
"undo_friendship": "Отмяна на приятелството",
|
||||
"request_accepted": "Поканата е приета",
|
||||
"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": "Не сте добавили приятели",
|
||||
"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": "Грешка при обработката на изображението",
|
||||
"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 символа.",
|
||||
"displayname_min_length": "Показваното име трябва да съдържа поне 3 символа",
|
||||
"displayname_max_length": "Показваното име трябва да съдържа най-много 50 символа",
|
||||
"report_profile": "Докладвай този профил",
|
||||
"report_reason": "Защо докладвате този профил?",
|
||||
"report_description": "Допълнителна информация",
|
||||
"report_description_placeholder": "Допълнителна информация",
|
||||
"report": "Докладвай",
|
||||
"report_reason_hate": "Омразна реч",
|
||||
"report_reason_hate": "Реч на омразата",
|
||||
"report_reason_sexual_content": "Сексуално съдържание",
|
||||
"report_reason_violence": "Насилия",
|
||||
"report_reason_violence": "Насилие",
|
||||
"report_reason_spam": "Спам",
|
||||
"report_reason_other": "Друго",
|
||||
"profile_reported": "Профилът е докладван",
|
||||
"your_friend_code": "Вашия приятелски код:",
|
||||
"your_friend_code": "Вашият код за приятелство:",
|
||||
"upload_banner": "Качи банер",
|
||||
"uploading_banner": "Качване на банер…",
|
||||
"background_image_updated": "Обновено фоново изображение"
|
||||
"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}}",
|
||||
"hidden_achievement_tooltip": "Това е скрито постижение",
|
||||
"achievement_earn_points": "Спечели {{points}} точки с това постижение",
|
||||
"achievement_earn_points": "Спечелете {{points}} точки с това постижение",
|
||||
"earned_points": "Спечелени точки:",
|
||||
"available_points": "Налични точки:",
|
||||
"how_to_earn_achievements_points": "Как да спечелиш точки за постижения?",
|
||||
"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}}"
|
||||
"how_to_earn_achievements_points": "Как се печелят точки от постижения?"
|
||||
},
|
||||
"hydra_cloud": {
|
||||
"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": "Научете повече",
|
||||
"subscription_tour_title": "Hydra Cloud Абонамент",
|
||||
"subscribe_now": "Абонирай се сега",
|
||||
"cloud_saving": "Запазване в облака",
|
||||
"cloud_achievements": "Запазете постиженията си в облака",
|
||||
"animated_profile_picture": "Анимирана профилна снимка",
|
||||
"premium_support": "Премиум поддръжка",
|
||||
"show_and_compare_achievements": "Показвайте и сравнявайте постиженията си с тези на други потребители",
|
||||
"animated_profile_banner": "Анимиран профилен банер"
|
||||
"debrid_description": "Изтегляйте до 4 пъти по-бързо с Nimbus"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,11 @@
|
||||
"home": {
|
||||
"featured": "Empfohlen",
|
||||
"surprise_me": "Überrasche mich",
|
||||
"no_results": "Keine Ergebnisse gefunden"
|
||||
"no_results": "Keine Ergebnisse gefunden",
|
||||
"start_typing": "Tippe, um zu suchen...",
|
||||
"hot": "Jetzt beliebt",
|
||||
"weekly": "📅 Top-Spiele der Woche",
|
||||
"achievements": "🏆 Spiele zum Meistern"
|
||||
},
|
||||
"sidebar": {
|
||||
"catalogue": "Katalog",
|
||||
@@ -21,11 +25,13 @@
|
||||
"queued": "{{title}} (In Warteschlange)",
|
||||
"game_has_no_executable": "Spiel hat keine ausführbare Datei gewählt",
|
||||
"sign_in": "Anmelden",
|
||||
"favorites": "Favoriten"
|
||||
"friends": "Freunde",
|
||||
"need_help": "Brauchst du Hilfe?",
|
||||
"favorites": "Favoriten",
|
||||
"playable_button_title": "Nur Spiele anzeigen, die du jetzt spielen kannst"
|
||||
},
|
||||
"header": {
|
||||
"search": "Spiele suchen",
|
||||
|
||||
"home": "Home",
|
||||
"catalogue": "Katalog",
|
||||
"downloads": "Downloads",
|
||||
@@ -39,9 +45,21 @@
|
||||
"downloading_metadata": "Metadaten von {{title}} werden heruntergeladen…",
|
||||
"downloading": "{{title}} wird heruntergeladen… ({{percentage}} abgeschlossen) - Abschluss {{eta}} - {{speed}}",
|
||||
"calculating_eta": "{{title}} wird heruntergeladen… ({{percentage}} abgeschlossen) - Verbleibende Zeit wird berechnet…",
|
||||
"checking_files": "Prüfe Dateien von {{title}}… ({{percentage}} abgeschlossen)"
|
||||
"checking_files": "Prüfe Dateien von {{title}}… ({{percentage}} abgeschlossen)",
|
||||
"installing_common_redist": "{{log}}…",
|
||||
"installation_complete": "Installation abgeschlossen",
|
||||
"installation_complete_message": "Allgemeine Redistributables erfolgreich installiert"
|
||||
},
|
||||
"catalogue": {
|
||||
"search": "Filtern…",
|
||||
"developers": "Entwickler",
|
||||
"genres": "Genres",
|
||||
"tags": "Tags",
|
||||
"publishers": "Publisher",
|
||||
"download_sources": "Download-Quellen",
|
||||
"result_count": "{{resultCount}} Ergebnisse",
|
||||
"filter_count": "{{filterCount}} verfügbar",
|
||||
"clear_filters": "{{filterCount}} ausgewählte löschen",
|
||||
"next_page": "Nächste Seite",
|
||||
"previous_page": "Vorherige Seite"
|
||||
},
|
||||
@@ -101,6 +119,7 @@
|
||||
"open_folder": "Verzeichnis öffnen",
|
||||
"open_download_location": "Heruntergeladene Dateien anzeigen",
|
||||
"create_shortcut": "Desktop-Verknüpfung erstellen",
|
||||
"clear": "Löschen",
|
||||
"remove_files": "Dateien entfernen",
|
||||
"remove_from_library_title": "Bist du dir sicher?",
|
||||
"remove_from_library_description": "Dies wird {{game}} aus deiner Bibliothek entfernen",
|
||||
@@ -114,8 +133,81 @@
|
||||
"download_in_progress": "Download erfolgt",
|
||||
"download_paused": "Download ist pausiert",
|
||||
"last_downloaded_option": "Letzte Download-Option",
|
||||
"create_steam_shortcut": "Steam-Verknüpfung erstellen",
|
||||
"create_shortcut_success": "Verknüpfung erfolgreich erstellt",
|
||||
"create_shortcut_error": "Fehler bei Erstellung von Verknüpfung"
|
||||
"you_might_need_to_restart_steam": "Möglicherweise musst du Steam neu starten, um die Änderungen zu sehen",
|
||||
"create_shortcut_error": "Fehler bei Erstellung von Verknüpfung",
|
||||
"nsfw_content_title": "Dieses Spiel enthält unangemessene Inhalte",
|
||||
"nsfw_content_description": "{{title}} enthält Inhalte, die möglicherweise nicht für alle Altersgruppen geeignet sind. Bist du sicher, dass du fortfahren möchtest?",
|
||||
"allow_nsfw_content": "Fortfahren",
|
||||
"refuse_nsfw_content": "Zurück",
|
||||
"stats": "Statistiken",
|
||||
"download_count": "Downloads",
|
||||
"player_count": "Aktive Spieler",
|
||||
"download_error": "Diese Download-Option ist nicht verfügbar",
|
||||
"download": "Download",
|
||||
"executable_path_in_use": "Ausführbare Datei wird bereits von \"{{game}}\" verwendet",
|
||||
"warning": "Warnung:",
|
||||
"hydra_needs_to_remain_open": "Für diesen Download muss Hydra geöffnet bleiben, bis er abgeschlossen ist. Wenn Hydra vor Abschluss geschlossen wird, verlierst du deinen Fortschritt.",
|
||||
"achievements": "Erfolge",
|
||||
"achievements_count": "Erfolge {{unlockedCount}}/{{achievementsCount}}",
|
||||
"cloud_save": "Cloud-Speicherstand",
|
||||
"cloud_save_description": "Speichere deinen Fortschritt in der Cloud und spiele auf jedem Gerät weiter",
|
||||
"backups": "Sicherungen",
|
||||
"install_backup": "Installieren",
|
||||
"delete_backup": "Löschen",
|
||||
"create_backup": "Neue Sicherung",
|
||||
"last_backup_date": "Letzte Sicherung am {{date}}",
|
||||
"no_backup_preview": "Keine Spielstände für diesen Titel gefunden",
|
||||
"restoring_backup": "Sicherung wird wiederhergestellt ({{progress}} abgeschlossen)…",
|
||||
"uploading_backup": "Sicherung wird hochgeladen…",
|
||||
"no_backups": "Du hast noch keine Sicherungen für dieses Spiel erstellt",
|
||||
"backup_uploaded": "Sicherung hochgeladen",
|
||||
"backup_deleted": "Sicherung gelöscht",
|
||||
"backup_restored": "Sicherung wiederhergestellt",
|
||||
"see_all_achievements": "Alle Erfolge anzeigen",
|
||||
"sign_in_to_see_achievements": "Anmelden, um Erfolge zu sehen",
|
||||
"mapping_method_automatic": "Automatisch",
|
||||
"mapping_method_manual": "Manuell",
|
||||
"mapping_method_label": "Zuordnungsmethode",
|
||||
"files_automatically_mapped": "Dateien automatisch zugeordnet",
|
||||
"no_backups_created": "Keine Sicherungen für dieses Spiel erstellt",
|
||||
"manage_files": "Dateien verwalten",
|
||||
"loading_save_preview": "Suche nach Spielständen…",
|
||||
"wine_prefix": "Wine-Präfix",
|
||||
"wine_prefix_description": "Das Wine-Präfix, das zum Ausführen dieses Spiels verwendet wird",
|
||||
"launch_options": "Startoptionen",
|
||||
"launch_options_description": "Fortgeschrittene Benutzer können Modifikationen ihrer Startoptionen eingeben (experimentelle Funktion)",
|
||||
"launch_options_placeholder": "Kein Parameter angegeben",
|
||||
"no_download_option_info": "Keine Informationen verfügbar",
|
||||
"backup_deletion_failed": "Sicherung konnte nicht gelöscht werden",
|
||||
"max_number_of_artifacts_reached": "Maximale Anzahl von Sicherungen für dieses Spiel erreicht",
|
||||
"achievements_not_sync": "Sieh, wie du deine Erfolge synchronisieren kannst",
|
||||
"manage_files_description": "Verwalte, welche Dateien gesichert und wiederhergestellt werden",
|
||||
"select_folder": "Ordner auswählen",
|
||||
"backup_from": "Sicherung vom {{date}}",
|
||||
"automatic_backup_from": "Automatische Sicherung vom {{date}}",
|
||||
"enable_automatic_cloud_sync": "Automatische Cloud-Synchronisierung aktivieren",
|
||||
"custom_backup_location_set": "Benutzerdefinierter Sicherungsort festgelegt",
|
||||
"no_directory_selected": "Kein Verzeichnis ausgewählt",
|
||||
"no_write_permission": "Kann nicht in dieses Verzeichnis herunterladen. Klicke hier, um mehr zu erfahren.",
|
||||
"reset_achievements": "Erfolge zurücksetzen",
|
||||
"reset_achievements_description": "Dies wird alle Erfolge für {{game}} zurücksetzen",
|
||||
"reset_achievements_title": "Bist du dir sicher?",
|
||||
"reset_achievements_success": "Erfolge erfolgreich zurückgesetzt",
|
||||
"reset_achievements_error": "Fehler beim Zurücksetzen der Erfolge",
|
||||
"download_error_gofile_quota_exceeded": "Du hast dein monatliches Gofile-Kontingent überschritten. Bitte warte, bis das Kontingent zurückgesetzt wird.",
|
||||
"download_error_real_debrid_account_not_authorized": "Dein Real-Debrid-Konto ist nicht für neue Downloads autorisiert. Bitte überprüfe deine Kontoeinstellungen und versuche es erneut.",
|
||||
"download_error_not_cached_on_real_debrid": "Dieser Download ist nicht auf Real-Debrid verfügbar und das Abrufen des Download-Status von Real-Debrid ist noch nicht verfügbar.",
|
||||
"download_error_not_cached_on_torbox": "Dieser Download ist nicht auf TorBox verfügbar und das Abrufen des Download-Status von TorBox ist noch nicht verfügbar.",
|
||||
"download_error_not_cached_on_hydra": "Dieser Download ist nicht auf Nimbus verfügbar.",
|
||||
"game_removed_from_favorites": "Spiel aus Favoriten entfernt",
|
||||
"game_added_to_favorites": "Spiel zu Favoriten hinzugefügt",
|
||||
"automatically_extract_downloaded_files": "Heruntergeladene Dateien automatisch entpacken",
|
||||
"create_start_menu_shortcut": "Startmenü-Verknüpfung erstellen",
|
||||
"invalid_wine_prefix_path": "Ungültiger Wine-Präfix-Pfad",
|
||||
"invalid_wine_prefix_path_description": "Der Pfad zum Wine-Präfix ist ungültig. Bitte überprüfe den Pfad und versuche es erneut.",
|
||||
"missing_wine_prefix": "Wine-Präfix ist erforderlich, um eine Sicherung unter Linux zu erstellen"
|
||||
},
|
||||
"activation": {
|
||||
"title": "Hydra aktivieren",
|
||||
@@ -148,7 +240,13 @@
|
||||
"queued": "In Warteschlange",
|
||||
"no_downloads_title": "Welch Leere",
|
||||
"no_downloads_description": "Du hast mit Hydra noch nichts heruntergeladen, aber es ist nie zu spät anzufangen.",
|
||||
"checking_files": "Dateien werden überprüft…"
|
||||
"checking_files": "Dateien werden überprüft…",
|
||||
"seeding": "Seeding",
|
||||
"stop_seeding": "Seeding stoppen",
|
||||
"resume_seeding": "Seeding fortsetzen",
|
||||
"options": "Verwalten",
|
||||
"extract": "Dateien entpacken",
|
||||
"extracting": "Dateien werden entpackt…"
|
||||
},
|
||||
"settings": {
|
||||
"downloads_path": "Download-Pfad",
|
||||
@@ -185,11 +283,11 @@
|
||||
"download_source_errored": "Fehlgeschlagen",
|
||||
"sync_download_sources": "Quellen synchronisieren",
|
||||
"removed_download_source": "Download-Quelle entfernt",
|
||||
"removed_download_sources": "Download-Quellen entfernt",
|
||||
"cancel_button_confirmation_delete_all_sources": "Nein",
|
||||
"confirm_button_confirmation_delete_all_sources": "Ja, alles löschen",
|
||||
"description_confirmation_delete_all_sources": "Du löschen alle Downloadquellen",
|
||||
"title_confirmation_delete_all_sources": "Löschen du alle Downloadquellen",
|
||||
"removed_download_sources": "Download-Quellen entfernt",
|
||||
"title_confirmation_delete_all_sources": "Möchtest du alle Downloadquellen löschen",
|
||||
"description_confirmation_delete_all_sources": "Möchtest du alle Downloadquellen löschen",
|
||||
"button_delete_all_sources": "Entfernen Sie alle Downloadquellen",
|
||||
"added_download_source": "Download-Quelle hinzugefügt",
|
||||
"download_sources_synced": "Alle Download-Quellen sind synchronisiert",
|
||||
@@ -197,7 +295,95 @@
|
||||
"found_download_option_zero": "Keine Download-Option gefunden",
|
||||
"found_download_option_one": "{{countFormatted}} Download-Option gefunden",
|
||||
"found_download_option_other": "{{countFormatted}} Download-Optionen gefunden",
|
||||
"import": "Importieren"
|
||||
"import": "Importieren",
|
||||
"public": "Öffentlich",
|
||||
"private": "Privat",
|
||||
"friends_only": "Nur Freunde",
|
||||
"privacy": "Privatsphäre",
|
||||
"profile_visibility": "Profilsichtbarkeit",
|
||||
"profile_visibility_description": "Wähle, wer dein Profil und deine Bibliothek sehen kann",
|
||||
"required_field": "Dieses Feld ist erforderlich",
|
||||
"source_already_exists": "Diese Quelle wurde bereits hinzugefügt",
|
||||
"must_be_valid_url": "Die Quelle muss eine gültige URL sein",
|
||||
"blocked_users": "Blockierte Benutzer",
|
||||
"user_unblocked": "Benutzer wurde freigegeben",
|
||||
"enable_achievement_notifications": "Wenn ein Erfolg freigeschaltet wird",
|
||||
"launch_minimized": "Hydra minimiert starten",
|
||||
"disable_nsfw_alert": "NSFW-Warnung deaktivieren",
|
||||
"seed_after_download_complete": "Nach Download-Abschluss seeden",
|
||||
"show_hidden_achievement_description": "Versteckte Erfolgsbeschreibungen vor dem Freischalten anzeigen",
|
||||
"account": "Konto",
|
||||
"no_users_blocked": "Du hast keine blockierten Benutzer",
|
||||
"subscription_active_until": "Deine Hydra Cloud ist aktiv bis {{date}}",
|
||||
"manage_subscription": "Abonnement verwalten",
|
||||
"update_email": "E-Mail aktualisieren",
|
||||
"update_password": "Passwort aktualisieren",
|
||||
"current_email": "Aktuelle E-Mail:",
|
||||
"no_email_account": "Du hast noch keine E-Mail festgelegt",
|
||||
"account_data_updated_successfully": "Kontodaten erfolgreich aktualisiert",
|
||||
"renew_subscription": "Hydra Cloud erneuern",
|
||||
"subscription_expired_at": "Dein Abonnement ist am {{date}} abgelaufen",
|
||||
"no_subscription": "Genieße Hydra auf die bestmögliche Weise",
|
||||
"become_subscriber": "Werde Hydra Cloud",
|
||||
"subscription_renew_cancelled": "Automatische Verlängerung ist deaktiviert",
|
||||
"subscription_renews_on": "Dein Abonnement verlängert sich am {{date}}",
|
||||
"bill_sent_until": "Deine nächste Rechnung wird bis zu diesem Tag gesendet",
|
||||
"no_themes": "Scheint, als hättest du noch keine Themes, aber keine Sorge, klicke hier, um dein erstes Meisterwerk zu erstellen.",
|
||||
"editor_tab_code": "Code",
|
||||
"editor_tab_info": "Info",
|
||||
"editor_tab_save": "Speichern",
|
||||
"web_store": "Web Store",
|
||||
"clear_themes": "Löschen",
|
||||
"create_theme": "Erstellen",
|
||||
"create_theme_modal_title": "Benutzerdefiniertes Theme erstellen",
|
||||
"create_theme_modal_description": "Erstelle ein neues Theme, um das Aussehen von Hydra anzupassen",
|
||||
"theme_name": "Name",
|
||||
"insert_theme_name": "Theme-Namen eingeben",
|
||||
"set_theme": "Theme festlegen",
|
||||
"unset_theme": "Theme entfernen",
|
||||
"delete_theme": "Theme löschen",
|
||||
"edit_theme": "Theme bearbeiten",
|
||||
"delete_all_themes": "Alle Themes löschen",
|
||||
"delete_all_themes_description": "Dies wird alle deine benutzerdefinierten Themes löschen",
|
||||
"delete_theme_description": "Dies wird das Theme {{theme}} löschen",
|
||||
"cancel": "Abbrechen",
|
||||
"appearance": "Erscheinungsbild",
|
||||
"enable_torbox": "TorBox aktivieren",
|
||||
"torbox_description": "TorBox ist dein Premium-Seedbox-Service, der sogar mit den besten Servern auf dem Markt konkurriert.",
|
||||
"torbox_account_linked": "TorBox-Konto verknüpft",
|
||||
"create_real_debrid_account": "Klicke hier, wenn du noch kein Real-Debrid-Konto hast",
|
||||
"create_torbox_account": "Klicke hier, wenn du noch kein TorBox-Konto hast",
|
||||
"real_debrid_account_linked": "Real-Debrid-Konto verknüpft",
|
||||
"name_min_length": "Theme-Name muss mindestens 3 Zeichen lang sein",
|
||||
"import_theme": "Theme importieren",
|
||||
"import_theme_description": "Du wirst {{theme}} aus dem Theme Store importieren",
|
||||
"error_importing_theme": "Fehler beim Importieren des Themes",
|
||||
"theme_imported": "Theme erfolgreich importiert",
|
||||
"enable_friend_request_notifications": "Wenn eine Freundschaftsanfrage empfangen wird",
|
||||
"enable_auto_install": "Updates automatisch herunterladen",
|
||||
"common_redist": "Allgemeine Redistributables",
|
||||
"common_redist_description": "Allgemeine Redistributables sind erforderlich, um einige Spiele auszuführen. Es wird empfohlen, sie zu installieren, um Probleme zu vermeiden.",
|
||||
"install_common_redist": "Installieren",
|
||||
"installing_common_redist": "Installiere…",
|
||||
"show_download_speed_in_megabytes": "Download-Geschwindigkeit in Megabyte pro Sekunde anzeigen",
|
||||
"extract_files_by_default": "Dateien nach dem Download standardmäßig entpacken",
|
||||
"achievement_custom_notification_position": "Position der benutzerdefinierten Erfolgsbenachrichtigung",
|
||||
"top-left": "Oben links",
|
||||
"top-center": "Oben mittig",
|
||||
"top-right": "Oben rechts",
|
||||
"bottom-left": "Unten links",
|
||||
"bottom-center": "Unten mittig",
|
||||
"bottom-right": "Unten rechts",
|
||||
"enable_achievement_custom_notifications": "Benutzerdefinierte Erfolgsbenachrichtigungen aktivieren",
|
||||
"alignment": "Ausrichtung",
|
||||
"variation": "Variation",
|
||||
"default": "Standard",
|
||||
"rare": "Selten",
|
||||
"platinum": "Platin",
|
||||
"hidden": "Versteckt",
|
||||
"test_notification": "Testbenachrichtigung",
|
||||
"notification_preview": "Vorschau der Erfolgsbenachrichtigung",
|
||||
"enable_friend_start_game_notifications": "Wenn ein Freund ein Spiel startet"
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "Download abgeschlossen",
|
||||
@@ -206,13 +392,24 @@
|
||||
"repack_count_one": "{{count}} Repack hinzugefügt",
|
||||
"repack_count_other": "{{count}} Repacks hinzugefügt",
|
||||
"new_update_available": "Version {{version}} verfügbar",
|
||||
"restart_to_install_update": "Um das Update zu installieren, starte Hydra neu"
|
||||
"restart_to_install_update": "Um das Update zu installieren, starte Hydra neu",
|
||||
"notification_achievement_unlocked_title": "Erfolg für {{game}} freigeschaltet",
|
||||
"notification_achievement_unlocked_body": "{{achievement}} und {{count}} weitere wurden freigeschaltet",
|
||||
"new_friend_request_description": "{{displayName}} hat dir eine Freundschaftsanfrage gesendet",
|
||||
"new_friend_request_title": "Neue Freundschaftsanfrage",
|
||||
"extraction_complete": "Entpacken abgeschlossen",
|
||||
"game_extracted": "{{title}} erfolgreich entpackt",
|
||||
"friend_started_playing_game": "{{displayName}} hat begonnen, ein Spiel zu spielen",
|
||||
"test_achievement_notification_title": "Dies ist eine Testbenachrichtigung",
|
||||
"test_achievement_notification_description": "Ziemlich cool, oder?"
|
||||
},
|
||||
"system_tray": {
|
||||
"open": "Hydra öffnen",
|
||||
"quit": "Schließen"
|
||||
},
|
||||
"game_card": {
|
||||
"available_one": "Verfügbar",
|
||||
"available_other": "Verfügbar",
|
||||
"no_downloads": "Keine Downloads verfügbar"
|
||||
},
|
||||
"binary_not_found_modal": {
|
||||
@@ -274,6 +471,66 @@
|
||||
"no_pending_invites": "Du hast keine ausstehenden Einladungen",
|
||||
"no_blocked_users": "Du hast keine blockierten Nutzer",
|
||||
"friend_code_copied": "Freundescode kopiert",
|
||||
"undo_friendship_modal_text": "Freundschaft mit {{displayName}} wird dadurch gekündigt"
|
||||
"undo_friendship_modal_text": "Freundschaft mit {{displayName}} wird dadurch gekündigt",
|
||||
"privacy_hint": "Um anzupassen, wer dies sehen kann, gehe zu den <0>Einstellungen</0>",
|
||||
"locked_profile": "Dieses Profil ist privat",
|
||||
"image_process_failure": "Fehler bei der Bildverarbeitung",
|
||||
"required_field": "Dieses Feld ist erforderlich",
|
||||
"displayname_min_length": "Anzeigename muss mindestens 3 Zeichen lang sein",
|
||||
"displayname_max_length": "Anzeigename darf maximal 50 Zeichen lang sein",
|
||||
"report_profile": "Dieses Profil melden",
|
||||
"report_reason": "Warum meldest du dieses Profil?",
|
||||
"report_description": "Zusätzliche Informationen",
|
||||
"report_description_placeholder": "Zusätzliche Informationen",
|
||||
"report": "Melden",
|
||||
"report_reason_hate": "Hassrede",
|
||||
"report_reason_sexual_content": "Sexuelle Inhalte",
|
||||
"report_reason_violence": "Gewalt",
|
||||
"report_reason_spam": "Spam",
|
||||
"report_reason_other": "Sonstiges",
|
||||
"profile_reported": "Profil gemeldet",
|
||||
"your_friend_code": "Dein Freundescode:",
|
||||
"upload_banner": "Banner hochladen",
|
||||
"uploading_banner": "Banner wird hochgeladen…",
|
||||
"background_image_updated": "Hintergrundbild aktualisiert",
|
||||
"stats": "Statistiken",
|
||||
"achievements": "Erfolge",
|
||||
"games": "Spiele",
|
||||
"top_percentile": "Top {{percentile}}%",
|
||||
"ranking_updated_weekly": "Rangliste wird wöchentlich aktualisiert",
|
||||
"playing": "Spielt {{game}}",
|
||||
"achievements_unlocked": "Erfolge freigeschaltet",
|
||||
"earned_points": "Verdiente Punkte",
|
||||
"show_achievements_on_profile": "Zeige deine Erfolge auf deinem Profil",
|
||||
"show_points_on_profile": "Zeige deine verdienten Punkte auf deinem Profil"
|
||||
},
|
||||
"achievement": {
|
||||
"achievement_unlocked": "Erfolg freigeschaltet",
|
||||
"user_achievements": "{{displayName}}'s Erfolge",
|
||||
"your_achievements": "Deine Erfolge",
|
||||
"unlocked_at": "Freigeschaltet am: {{date}}",
|
||||
"subscription_needed": "Ein Hydra Cloud-Abonnement ist erforderlich, um diesen Inhalt zu sehen",
|
||||
"new_achievements_unlocked": "{{achievementCount}} neue Erfolge von {{gameCount}} Spielen freigeschaltet",
|
||||
"achievement_progress": "{{unlockedCount}}/{{totalCount}} Erfolge",
|
||||
"achievements_unlocked_for_game": "{{achievementCount}} neue Erfolge für {{gameTitle}} freigeschaltet",
|
||||
"hidden_achievement_tooltip": "Dies ist ein versteckter Erfolg",
|
||||
"achievement_earn_points": "Verdiene {{points}} Punkte mit diesem Erfolg",
|
||||
"earned_points": "Verdiente Punkte:",
|
||||
"available_points": "Verfügbare Punkte:",
|
||||
"how_to_earn_achievements_points": "Wie verdient man Erfolgspunkte?"
|
||||
},
|
||||
"hydra_cloud": {
|
||||
"subscription_tour_title": "Hydra Cloud-Abonnement",
|
||||
"subscribe_now": "Jetzt abonnieren",
|
||||
"cloud_saving": "Cloud-Speicherung",
|
||||
"cloud_achievements": "Speichere deine Erfolge in der Cloud",
|
||||
"animated_profile_picture": "Animierte Profilbilder",
|
||||
"premium_support": "Premium-Support",
|
||||
"show_and_compare_achievements": "Zeige und vergleiche deine Erfolge mit anderen Nutzern",
|
||||
"animated_profile_banner": "Animiertes Profilbanner",
|
||||
"hydra_cloud": "Hydra Cloud",
|
||||
"hydra_cloud_feature_found": "Du hast gerade eine Hydra Cloud-Funktion entdeckt!",
|
||||
"learn_more": "Mehr erfahren",
|
||||
"debrid_description": "Lade bis zu 4x schneller mit Nimbus herunter"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
"sign_in": "Sign in",
|
||||
"friends": "Friends",
|
||||
"need_help": "Need help?",
|
||||
"favorites": "Favorites"
|
||||
"favorites": "Favorites",
|
||||
"playable_button_title": "Show only games you can play now"
|
||||
},
|
||||
"header": {
|
||||
"search": "Search games",
|
||||
@@ -204,7 +205,21 @@
|
||||
"create_start_menu_shortcut": "Create Start Menu shortcut",
|
||||
"invalid_wine_prefix_path": "Invalid Wine prefix path",
|
||||
"invalid_wine_prefix_path_description": "The path to the Wine prefix is invalid. Please check the path and try again.",
|
||||
"missing_wine_prefix": "Wine prefix is required to create a backup on Linux"
|
||||
"missing_wine_prefix": "Wine prefix is required to create a backup on Linux",
|
||||
"artifact_renamed": "Backup renamed successfully",
|
||||
"rename_artifact": "Rename Backup",
|
||||
"rename_artifact_description": "Rename the backup to a more descriptive name",
|
||||
"artifact_name_label": "Backup name",
|
||||
"artifact_name_placeholder": "Enter a name for the backup",
|
||||
"save_changes": "Save changes",
|
||||
"required_field": "This field is required",
|
||||
"max_length_field": "This field must be less than {{length}} characters",
|
||||
"freeze_backup": "Pin it so it's not overwritten by automatic backups",
|
||||
"unfreeze_backup": "Unpin it",
|
||||
"backup_frozen": "Backup pinned",
|
||||
"backup_unfrozen": "Backup unpinned",
|
||||
"backup_freeze_failed": "Failed to freeze backup",
|
||||
"backup_freeze_failed_description": "You must leave at least one free slot for automatic backups"
|
||||
},
|
||||
"activation": {
|
||||
"title": "Activate Hydra",
|
||||
@@ -379,7 +394,8 @@
|
||||
"platinum": "Platinum",
|
||||
"hidden": "Hidden",
|
||||
"test_notification": "Test notification",
|
||||
"notification_preview": "Achievement Notification Preview"
|
||||
"notification_preview": "Achievement Notification Preview",
|
||||
"enable_friend_start_game_notifications": "When a friend starts playing a game"
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "Download complete",
|
||||
@@ -498,7 +514,8 @@
|
||||
"achievements_unlocked": "Achievements Unlocked",
|
||||
"earned_points": "Earned points",
|
||||
"show_achievements_on_profile": "Show your achievements on your profile",
|
||||
"show_points_on_profile": "Show your earned points on your profile"
|
||||
"show_points_on_profile": "Show your earned points on your profile",
|
||||
"error_adding_friend": "Could not send friend request. Please check friend code"
|
||||
},
|
||||
"achievement": {
|
||||
"achievement_unlocked": "Achievement unlocked",
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
"sign_in": "Iniciar sesión",
|
||||
"friends": "Amigos",
|
||||
"need_help": "¿Necesitas ayuda?",
|
||||
"favorites": "Favoritos"
|
||||
"favorites": "Favoritos",
|
||||
"playable_button_title": "Mostrar solo juegos que puedes jugar ahora"
|
||||
},
|
||||
"header": {
|
||||
"search": "Buscar juegos",
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
"sign_in": "Se connecter",
|
||||
"friends": "Amis",
|
||||
"need_help": "Besoin d'aide ?",
|
||||
"favorites": "Favoris"
|
||||
"favorites": "Favoris",
|
||||
"playable_button_title": "Afficher uniquement les jeux que vous pouvez jouer maintenant"
|
||||
},
|
||||
"header": {
|
||||
"search": "Rechercher",
|
||||
@@ -356,7 +357,17 @@
|
||||
"common_redist_description": "Certains jeux nécessitent les redistribuables communs. L'installation est recommandée.",
|
||||
"install_common_redist": "Installer",
|
||||
"installing_common_redist": "Installation…",
|
||||
"show_download_speed_in_megabytes": "Afficher la vitesse de téléchargement en mégaoctets par seconde"
|
||||
"show_download_speed_in_megabytes": "Afficher la vitesse de téléchargement en mégaoctets par seconde",
|
||||
"extract_files_by_default": "Extraire les fichiers par défaut après le téléchargement",
|
||||
"enable_achievement_custom_notifications": "Activer les notifications personnalisées de succès",
|
||||
"achievement_custom_notification_position": "Position de la notification personnalisée de succès",
|
||||
"top-left": "En haut à gauche",
|
||||
"top-center": "En haut au centre",
|
||||
"top-right": "En haut à droite",
|
||||
"bottom-left": "En bas à gauche",
|
||||
"bottom-center": "En bas au centre",
|
||||
"bottom-right": "En bas à droite",
|
||||
"enable_friend_start_game_notifications": "Quand un ami commence à jouer à un jeu"
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "Téléchargement terminé",
|
||||
|
||||
@@ -26,6 +26,7 @@ import nb from "./nb/translation.json";
|
||||
import et from "./et/translation.json";
|
||||
import bg from "./bg/translation.json";
|
||||
import uz from "./uz/translation.json";
|
||||
import sv from "./sv/translation.json";
|
||||
|
||||
export default {
|
||||
"pt-BR": ptBR,
|
||||
@@ -56,4 +57,5 @@ export default {
|
||||
nb,
|
||||
et,
|
||||
uz,
|
||||
sv,
|
||||
};
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
"downloading": "{{title}} ({{percentage}} - Download…)",
|
||||
"filter": "Filtra libreria",
|
||||
"home": "Home",
|
||||
"favorites": "Preferiti"
|
||||
"favorites": "Preferiti",
|
||||
"playable_button_title": "Mostra solo i giochi che puoi giocare ora"
|
||||
},
|
||||
"header": {
|
||||
"search": "Cerca",
|
||||
|
||||
@@ -13,9 +13,10 @@
|
||||
"downloading_metadata": "{{title}} (Pobieranie metadata…)",
|
||||
"paused": "{{title}} (Zatrzymano)",
|
||||
"downloading": "{{title}} ({{percentage}} - Pobieranie…)",
|
||||
"filter": "Filtruj biblioteke",
|
||||
"filter": "Filtruj bibliotekę",
|
||||
"home": "Główna",
|
||||
"favorites": "Ulubione"
|
||||
"favorites": "Ulubione",
|
||||
"playable_button_title": "Pokaż tylko gry, w które możesz grać teraz"
|
||||
},
|
||||
"header": {
|
||||
"search": "Szukaj",
|
||||
|
||||
@@ -192,7 +192,21 @@
|
||||
"automatically_extract_downloaded_files": "Extrair automaticamente os arquivos baixados",
|
||||
"create_start_menu_shortcut": "Criar atalho no Menu Iniciar",
|
||||
"invalid_wine_prefix_path": "Caminho do prefixo Wine inválido",
|
||||
"invalid_wine_prefix_path_description": "O caminho para o prefixo Wine é inválido. Por favor, verifique o caminho e tente novamente."
|
||||
"invalid_wine_prefix_path_description": "O caminho para o prefixo Wine é inválido. Por favor, verifique o caminho e tente novamente.",
|
||||
"artifact_renamed": "Backup renomeado com sucesso",
|
||||
"rename_artifact": "Renomear Backup",
|
||||
"rename_artifact_description": "Renomeie o backup para um nome mais descritivo",
|
||||
"artifact_name_label": "Nome do backup",
|
||||
"artifact_name_placeholder": "Insira um nome para o backup",
|
||||
"save_changes": "Salvar mudanças",
|
||||
"required_field": "Este campo é obrigatório",
|
||||
"max_length_field": "Este campo deve ter menos de {{length}} caracteres",
|
||||
"freeze_backup": "Fixar para não ser apagado por backups automáticos",
|
||||
"unfreeze_backup": "Remover dos fixados",
|
||||
"backup_frozen": "Backup fixado",
|
||||
"backup_unfrozen": "Backup removido dos fixados",
|
||||
"backup_freeze_failed": "Falha ao fixar backup",
|
||||
"backup_freeze_failed_description": "Você deve deixar pelo menos um espaço livre para backups automáticos"
|
||||
},
|
||||
"activation": {
|
||||
"title": "Ativação",
|
||||
@@ -365,7 +379,8 @@
|
||||
"platinum": "Platina",
|
||||
"hidden": "Oculta",
|
||||
"test_notification": "Testar notificação",
|
||||
"notification_preview": "Prévia da Notificação de Conquistas"
|
||||
"notification_preview": "Prévia da Notificação de Conquistas",
|
||||
"enable_friend_start_game_notifications": "Quando um amigo iniciar um jogo"
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "Download concluído",
|
||||
@@ -492,7 +507,8 @@
|
||||
"achievements_unlocked": "Conquistas desbloqueadas",
|
||||
"earned_points": "Pontos ganhos",
|
||||
"show_achievements_on_profile": "Exiba suas conquistas no perfil",
|
||||
"show_points_on_profile": "Exiba seus pontos ganhos no perfil"
|
||||
"show_points_on_profile": "Exiba seus pontos ganhos no perfil",
|
||||
"error_adding_friend": "Não foi possível enviar o pedido de amizade. Verifique o código de amizade inserido"
|
||||
},
|
||||
"achievement": {
|
||||
"achievement_unlocked": "Conquista desbloqueada",
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
"sign_in": "Войти",
|
||||
"friends": "Друзья",
|
||||
"need_help": "Нужна помощь?",
|
||||
"favorites": "Избранное"
|
||||
"favorites": "Избранное",
|
||||
"playable_button_title": "Показать только игры, в которые можно играть сейчас"
|
||||
},
|
||||
"header": {
|
||||
"search": "Поиск",
|
||||
@@ -197,7 +198,14 @@
|
||||
"download_error_not_cached_on_torbox": "Эта загрузка недоступна на TorBox, и получить статус загрузки с TorBox пока невозможно.",
|
||||
"game_added_to_favorites": "Игра добавлена в избранное",
|
||||
"game_removed_from_favorites": "Игра удалена из избранного",
|
||||
"automatically_extract_downloaded_files": "Автоматическая распаковка загруженных файлов"
|
||||
"automatically_extract_downloaded_files": "Автоматическая распаковка загруженных файлов",
|
||||
"create_steam_shortcut": "Создать ярлык Steam",
|
||||
"you_might_need_to_restart_steam": "Возможно, вам потребуется перезапустить Steam, чтобы увидеть изменения",
|
||||
"create_start_menu_shortcut": "Создать ярлык в меню «Пуск»",
|
||||
"invalid_wine_prefix_path": "Недопустимый путь префикса Wine",
|
||||
"invalid_wine_prefix_path_description": "Путь к префиксу Wine недействителен. Пожалуйста, проверьте путь и попробуйте снова.",
|
||||
"missing_wine_prefix": "Префикс Wine необходим для создания резервной копии в Linux",
|
||||
"download_error_not_cached_on_hydra": "Эта загрузка недоступна на Nimbus."
|
||||
},
|
||||
"activation": {
|
||||
"title": "Активировать Hydra",
|
||||
@@ -355,7 +363,25 @@
|
||||
"common_redist_description": "Для запуска некоторых игр требуются библиотеки. Во избежание проблем рекомендуется установить их.",
|
||||
"install_common_redist": "Установить",
|
||||
"installing_common_redist": "Установка…",
|
||||
"show_download_speed_in_megabytes": "Показать скорость загрузки в мегабайтах в секунду"
|
||||
"show_download_speed_in_megabytes": "Показать скорость загрузки в мегабайтах в секунду",
|
||||
"extract_files_by_default": "Извлекать файлы по умолчанию после загрузки",
|
||||
"achievement_custom_notification_position": "Позиция настраиваемых уведомлений о достижениях",
|
||||
"top-left": "Верхний левый угол",
|
||||
"top-center": "Верхний центр",
|
||||
"top-right": "Верхний правый угол",
|
||||
"bottom-left": "Нижний левый угол",
|
||||
"bottom-center": "Нижний центр",
|
||||
"bottom-right": "Нижний правый угол",
|
||||
"enable_achievement_custom_notifications": "Включить настраиваемые уведомления о достижениях",
|
||||
"alignment": "Выравнивание",
|
||||
"variation": "Вариация",
|
||||
"default": "По умолчанию",
|
||||
"rare": "Редкое",
|
||||
"platinum": "Платиновый",
|
||||
"hidden": "Скрытый",
|
||||
"test_notification": "Тестовое уведомление",
|
||||
"notification_preview": "Предварительный просмотр уведомления о достижении",
|
||||
"enable_friend_start_game_notifications": "Когда друг начинает играть в игру"
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "Загрузка завершена",
|
||||
@@ -370,7 +396,10 @@
|
||||
"new_friend_request_title": "Новый запрос на добавление в друзья",
|
||||
"new_friend_request_description": "Вы получили новый запрос на добавление в друзья",
|
||||
"extraction_complete": "Распаковка завершена",
|
||||
"game_extracted": "{{title}} успешно распакован"
|
||||
"game_extracted": "{{title}} успешно распакован",
|
||||
"friend_started_playing_game": "{{displayName}} начал играть в игру",
|
||||
"test_achievement_notification_title": "Это тестовое уведомление",
|
||||
"test_achievement_notification_description": "Довольно круто, да?"
|
||||
},
|
||||
"system_tray": {
|
||||
"open": "Открыть Hydra",
|
||||
|
||||
533
src/locales/sv/translation.json
Normal file
533
src/locales/sv/translation.json
Normal file
@@ -0,0 +1,533 @@
|
||||
{
|
||||
"language_name": "Svenska",
|
||||
"app": {
|
||||
"successfully_signed_in": "Inloggningen lyckades"
|
||||
},
|
||||
"home": {
|
||||
"featured": "Utvalt",
|
||||
"surprise_me": "Överraska mig",
|
||||
"no_results": "Inga resultat hittades",
|
||||
"start_typing": "Börja skriva för att söka...",
|
||||
"hot": "Hetast just nu",
|
||||
"weekly": "📅 Veckans topplista",
|
||||
"achievements": "🏆 Spel att klara av"
|
||||
},
|
||||
"sidebar": {
|
||||
"catalogue": "Katalog",
|
||||
"downloads": "Nedladdningar",
|
||||
"settings": "Inställningar",
|
||||
"my_library": "Mitt bibliotek",
|
||||
"downloading_metadata": "{{title}} (Hämtar metadata…)",
|
||||
"paused": "{{title}} (Pausad)",
|
||||
"downloading": "{{title}} ({{percentage}} - Hämtar…)",
|
||||
"filter": "Filtrera bibliotek",
|
||||
"home": "Hem",
|
||||
"queued": "{{title}} (I kö)",
|
||||
"game_has_no_executable": "Spelet har ingen vald körbar fil",
|
||||
"sign_in": "Logga in",
|
||||
"friends": "Vänner",
|
||||
"need_help": "Behöver du hjälp?",
|
||||
"favorites": "Favoriter"
|
||||
},
|
||||
"header": {
|
||||
"search": "Sök spel",
|
||||
"home": "Hem",
|
||||
"catalogue": "Katalog",
|
||||
"downloads": "Nedladdningar",
|
||||
"search_results": "Sökresultat",
|
||||
"settings": "Inställningar",
|
||||
"version_available_install": "Version {{version}} är tillgänglig. Klicka här för att starta om och installera.",
|
||||
"version_available_download": "Version {{version}} är tillgänglig. Klicka här för att ladda ner."
|
||||
},
|
||||
"bottom_panel": {
|
||||
"no_downloads_in_progress": "Inga nedladdningar pågår",
|
||||
"downloading_metadata": "Laddar ner metadata för {{title}}…",
|
||||
"downloading": "Laddar ner {{title}}… ({{percentage}} klart) - Klart om {{eta}} - {{speed}}",
|
||||
"calculating_eta": "Laddar ner {{title}}… ({{percentage}} klart) - Beräknar återstående tid…",
|
||||
"checking_files": "Kontrollerar filer för {{title}}… ({{percentage}} klart)",
|
||||
"installing_common_redist": "{{log}}…",
|
||||
"installation_complete": "Installation klar",
|
||||
"installation_complete_message": "Nödvändiga systemkomponenter installerade framgångsrikt"
|
||||
},
|
||||
"catalogue": {
|
||||
"search": "Filter…",
|
||||
"developers": "Utvecklare",
|
||||
"genres": "Genrer",
|
||||
"tags": "Taggar",
|
||||
"publishers": "Utgivare",
|
||||
"download_sources": "Nedladdningskällor",
|
||||
"result_count": "{{resultCount}} resultat",
|
||||
"filter_count": "{{filterCount}} tillgängliga",
|
||||
"clear_filters": "Rensa {{filterCount}} valda"
|
||||
},
|
||||
"game_details": {
|
||||
"open_download_options": "Öppna nedladdningsalternativ",
|
||||
"download_options_zero": "Inget nedladdningsalternativ",
|
||||
"download_options_one": "{{count}} nedladdningsalternativ",
|
||||
"download_options_other": "{{count}} nedladdningsalternativ",
|
||||
"updated_at": "Uppdaterad {{updated_at}}",
|
||||
"install": "Installera",
|
||||
"resume": "Återuppta",
|
||||
"pause": "Pausa",
|
||||
"cancel": "Avbryt",
|
||||
"remove": "Ta bort",
|
||||
"space_left_on_disk": "{{space}} ledigt på disken",
|
||||
"eta": "Klart om {{eta}}",
|
||||
"calculating_eta": "Beräknar återstående tid…",
|
||||
"downloading_metadata": "Laddar ner metadata…",
|
||||
"filter": "Filtrera repacks",
|
||||
"requirements": "Systemkrav",
|
||||
"minimum": "Minimum",
|
||||
"recommended": "Rekommenderat",
|
||||
"paused": "Pausat",
|
||||
"release_date": "Släpptes den {{date}}",
|
||||
"publisher": "Utgiven av {{publisher}}",
|
||||
"hours": "timmar",
|
||||
"minutes": "minuter",
|
||||
"amount_hours": "{{amount}} timmar",
|
||||
"amount_minutes": "{{amount}} minuter",
|
||||
"accuracy": "{{accuracy}}% träffsäkerhet",
|
||||
"add_to_library": "Lägg till i biblioteket",
|
||||
"remove_from_library": "Ta bort från biblioteket",
|
||||
"no_downloads": "Inga nedladdningar tillgängliga",
|
||||
"play_time": "Spelad i {{amount}}",
|
||||
"last_time_played": "Senast spelad {{period}}",
|
||||
"not_played_yet": "Du har inte spelat {{title}} än",
|
||||
"next_suggestion": "Nästa förslag",
|
||||
"play": "Spela",
|
||||
"deleting": "Tar bort installationsfil…",
|
||||
"close": "Stäng",
|
||||
"playing_now": "Spelar nu",
|
||||
"change": "Byt",
|
||||
"repacks_modal_description": "Välj den repack du vill ladda ner",
|
||||
"select_folder_hint": "För att ändra standardmappen, gå till <0>Inställningar</0>",
|
||||
"download_now": "Ladda ner nu",
|
||||
"no_shop_details": "Kunde inte hämta butikens information.",
|
||||
"download_options": "Nedladdningsalternativ",
|
||||
"download_path": "Nedladdningsplats",
|
||||
"previous_screenshot": "Föregående skärmdump",
|
||||
"next_screenshot": "Nästa skärmdump",
|
||||
"screenshot": "Skärmdump {{number}}",
|
||||
"open_screenshot": "Öppna skärmdump {{number}}",
|
||||
"download_settings": "Nedladdningsinställningar",
|
||||
"downloader": "Nedladdare",
|
||||
"select_executable": "Välj",
|
||||
"no_executable_selected": "Ingen körbar fil vald",
|
||||
"open_folder": "Öppna mapp",
|
||||
"open_download_location": "Visa nedladdade filer",
|
||||
"create_shortcut": "Skapa genväg på skrivbordet",
|
||||
"clear": "Rensa",
|
||||
"remove_files": "Ta bort filer",
|
||||
"remove_from_library_title": "Är du säker?",
|
||||
"remove_from_library_description": "Detta kommer ta bort {{game}} från ditt bibliotek",
|
||||
"options": "Alternativ",
|
||||
"executable_section_title": "Körbar fil",
|
||||
"executable_section_description": "Sökväg till filen som körs när du klickar på \"Spela\"",
|
||||
"downloads_section_title": "Nedladdningar",
|
||||
"downloads_section_description": "Kolla uppdateringar eller andra versioner av detta spel",
|
||||
"danger_zone_section_title": "Danger zone",
|
||||
"danger_zone_section_description": "Ta bort detta spel från ditt bibliotek eller filer nedladdade av Hydra",
|
||||
"download_in_progress": "Nedladdning pågår",
|
||||
"download_paused": "Nedladdning pausad",
|
||||
"last_downloaded_option": "Senast nedladdade alternativ",
|
||||
"create_steam_shortcut": "Skapa Steam-genväg",
|
||||
"create_shortcut_success": "Genväg skapad",
|
||||
"you_might_need_to_restart_steam": "Du kan behöva starta om Steam för att se ändringarna",
|
||||
"create_shortcut_error": "Fel vid skapande av genväg",
|
||||
"nsfw_content_title": "Det här spelet innehåller olämpligt innehåll",
|
||||
"nsfw_content_description": "{{title}} innehåller innehåll som kanske inte är lämpligt för alla åldrar. Vill du fortsätta?",
|
||||
"allow_nsfw_content": "Fortsätt",
|
||||
"refuse_nsfw_content": "Gå tillbaka",
|
||||
"stats": "Statistik",
|
||||
"download_count": "Nedladdningar",
|
||||
"player_count": "Aktiva spelare",
|
||||
"download_error": "Det här nedladdningsalternativet är inte tillgängligt",
|
||||
"download": "Ladda ner",
|
||||
"executable_path_in_use": "Körbar fil används redan av \"{{game}}\"",
|
||||
"warning": "Varning:",
|
||||
"hydra_needs_to_remain_open": "för denna nedladdning behöver Hydra vara öppen tills den är klar. Om Hydra stängs innan nedladdningen är klar förlorar du dina framsteg.",
|
||||
"achievements": "Prestationer",
|
||||
"achievements_count": "Prestationer {{unlockedCount}}/{{achievementsCount}}",
|
||||
"cloud_save": "Molnspara",
|
||||
"cloud_save_description": "Spara dina framsteg i molnet och fortsätt spela på vilken enhet som helst",
|
||||
"backups": "Säkerhetskopior",
|
||||
"install_backup": "Installera",
|
||||
"delete_backup": "Ta bort",
|
||||
"create_backup": "Ny säkerhetskopia",
|
||||
"last_backup_date": "Senaste säkerhetskopia {{date}}",
|
||||
"no_backup_preview": "Inga sparfiler hittades för detta spel",
|
||||
"restoring_backup": "Återställer säkerhetskopia ({{progress}} klart)…",
|
||||
"uploading_backup": "Laddar upp säkerhetskopia…",
|
||||
"no_backups": "Du har inte skapat några säkerhetskopior för detta spel än",
|
||||
"backup_uploaded": "Säkerhetskopia uppladdad",
|
||||
"backup_deleted": "Säkerhetskopia borttagen",
|
||||
"backup_restored": "Säkerhetskopia återställd",
|
||||
"see_all_achievements": "Se alla prestationer",
|
||||
"sign_in_to_see_achievements": "Logga in för att se prestationer",
|
||||
"mapping_method_automatic": "Automatisk",
|
||||
"mapping_method_manual": "Manuell",
|
||||
"mapping_method_label": "Kartläggningsmetod",
|
||||
"files_automatically_mapped": "Filer kartlagda automatiskt",
|
||||
"no_backups_created": "Inga säkerhetskopior skapade för detta spel",
|
||||
"manage_files": "Hantera filer",
|
||||
"loading_save_preview": "Söker efter sparfiler…",
|
||||
"wine_prefix": "Wine-prefix",
|
||||
"wine_prefix_description": "Wine-prefixet som används för att köra detta spel",
|
||||
"launch_options": "Startalternativ",
|
||||
"launch_options_description": "Avancerade användare kan lägga till modifieringar till sina startalternativ (experimentell funktion)",
|
||||
"launch_options_placeholder": "Inga parametrar angivna",
|
||||
"no_download_option_info": "Ingen information tillgänglig",
|
||||
"backup_deletion_failed": "Misslyckades med att ta bort säkerhetskopian",
|
||||
"max_number_of_artifacts_reached": "Maximalt antal säkerhetskopior nått för detta spel",
|
||||
"achievements_not_sync": "Se hur du synkroniserar dina prestationer",
|
||||
"manage_files_description": "Hantera vilka filer som ska säkerhetskopieras och återställas",
|
||||
"select_folder": "Välj mapp",
|
||||
"backup_from": "Säkerhetskopia från {{date}}",
|
||||
"automatic_backup_from": "Automatisk säkerhetskopia från {{date}}",
|
||||
"enable_automatic_cloud_sync": "Aktivera automatisk molnsynkronisering",
|
||||
"custom_backup_location_set": "Anpassad plats för säkerhetskopior inställd",
|
||||
"no_directory_selected": "Ingen mapp vald",
|
||||
"no_write_permission": "Kan inte ladda ner till denna mapp. Klicka här för att läsa mer.",
|
||||
"reset_achievements": "Återställ prestationer",
|
||||
"reset_achievements_description": "Detta kommer att återställa alla prestationer för {{game}}",
|
||||
"reset_achievements_title": "Är du säker?",
|
||||
"reset_achievements_success": "Prestationer återställda",
|
||||
"reset_achievements_error": "Misslyckades med att återställa prestationer",
|
||||
"download_error_gofile_quota_exceeded": "Du har överskridit din månadsgräns för Gofile. Vänta tills kvoten återställs.",
|
||||
"download_error_real_debrid_account_not_authorized": "Ditt Real-Debrid-konto är inte auktoriserat att göra nya nedladdningar. Kontrollera dina kontoinställningar och försök igen.",
|
||||
"download_error_not_cached_on_real_debrid": "Denna nedladdning finns inte på Real-Debrid och statusövervakning från Real-Debrid är ännu inte tillgänglig.",
|
||||
"download_error_not_cached_on_torbox": "Denna nedladdning finns inte på TorBox och statusövervakning från TorBox är ännu inte tillgänglig.",
|
||||
"download_error_not_cached_on_hydra": "Denna nedladdning finns inte på Nimbus.",
|
||||
"game_removed_from_favorites": "Spelet togs bort från favoriter",
|
||||
"game_added_to_favorites": "Spelet lades till i favoriter",
|
||||
"automatically_extract_downloaded_files": "Extrahera nedladdade filer automatiskt",
|
||||
"create_start_menu_shortcut": "Skapa genväg i Startmenyn",
|
||||
"invalid_wine_prefix_path": "Ogiltig sökväg för Wine-prefix",
|
||||
"invalid_wine_prefix_path_description": "Sökvägen till Wine-prefixet är ogiltig. Kontrollera sökvägen och försök igen.",
|
||||
"missing_wine_prefix": "Wine-prefix krävs för att skapa en säkerhetskopia på Linux"
|
||||
},
|
||||
"activation": {
|
||||
"title": "Aktivera Hydra",
|
||||
"installation_id": "Installations ID:",
|
||||
"enter_activation_code": "Ange din aktiveringskod",
|
||||
"message": "Om du inte vet var du ska fråga efter denna, borde du inte ha den.",
|
||||
"activate": "Aktivera",
|
||||
"loading": "Laddar…"
|
||||
},
|
||||
"downloads": {
|
||||
"resume": "Fortsätt",
|
||||
"pause": "Pausa",
|
||||
"eta": "Slutförs {{eta}}",
|
||||
"paused": "Pausad",
|
||||
"verifying": "Verifierar…",
|
||||
"completed": "Slutförd",
|
||||
"removed": "Ej nedladdad",
|
||||
"cancel": "Avbryt",
|
||||
"filter": "Filtrera nedladdade spel",
|
||||
"remove": "Ta bort",
|
||||
"downloading_metadata": "Laddar metadata…",
|
||||
"deleting": "Tar bort installationsfil…",
|
||||
"delete": "Ta bort installationsfil",
|
||||
"delete_modal_title": "Är du säker?",
|
||||
"delete_modal_description": "Detta tar bort alla installationsfiler från din dator",
|
||||
"install": "Installera",
|
||||
"download_in_progress": "Pågår",
|
||||
"queued_downloads": "Köade nedladdningar",
|
||||
"downloads_completed": "Klart",
|
||||
"queued": "I kö",
|
||||
"no_downloads_title": "Så tomt",
|
||||
"no_downloads_description": "Du har inte laddat ner något med Hydra än, men det är aldrig för sent att börja.",
|
||||
"checking_files": "Kontrollerar filer…",
|
||||
"seeding": "Seedar",
|
||||
"stop_seeding": "Sluta seeda",
|
||||
"resume_seeding": "Fortsätt seeda",
|
||||
"options": "Hantera",
|
||||
"extract": "Packa upp filer",
|
||||
"extracting": "Packar upp filer…"
|
||||
},
|
||||
"settings": {
|
||||
"downloads_path": "Nedladdningssökväg",
|
||||
"change": "Uppdatera",
|
||||
"notifications": "Aviseringar",
|
||||
"enable_download_notifications": "När en nedladdning är klar",
|
||||
"enable_repack_list_notifications": "När en ny repack läggs till",
|
||||
"real_debrid_api_token_label": "Real-Debrid API-token",
|
||||
"quit_app_instead_hiding": "Stäng Hydra istället för att minimera",
|
||||
"launch_with_system": "Starta Hydra vid systemstart",
|
||||
"general": "Allmänt",
|
||||
"behavior": "Beteende",
|
||||
"download_sources": "Nedladdningskällor",
|
||||
"language": "Språk",
|
||||
"api_token": "API-token",
|
||||
"enable_real_debrid": "Aktivera Real-Debrid",
|
||||
"real_debrid_description": "Real-Debrid är en obegränsad nedladdningstjänst som låter dig ladda ner filer snabbt, endast begränsad av din internetanslutning.",
|
||||
"debrid_invalid_token": "Ogiltig API-token",
|
||||
"debrid_api_token_hint": "Du kan hämta din API-token <0>här</0>",
|
||||
"real_debrid_free_account_error": "Kontot \"{{username}}\" är ett gratiskonto. Prenumerera på Real-Debrid",
|
||||
"debrid_linked_message": "Kontot \"{{username}}\" kopplat",
|
||||
"save_changes": "Spara ändringar",
|
||||
"changes_saved": "Ändringar sparades",
|
||||
"download_sources_description": "Hydra hämtar nedladdningslänkar från dessa källor. Källans URL måste vara en direktlänk till en .json-fil med nedladdningslänkar.",
|
||||
"validate_download_source": "Validera",
|
||||
"remove_download_source": "Ta bort",
|
||||
"add_download_source": "Lägg till källa",
|
||||
"download_count_zero": "Inga nedladdningsalternativ",
|
||||
"download_count_one": "{{countFormatted}} nedladdningsalternativ",
|
||||
"download_count_other": "{{countFormatted}} nedladdningsalternativ",
|
||||
"download_source_url": "URL till nedladdningskälla",
|
||||
"add_download_source_description": "Ange URL:en till .json-filen",
|
||||
"download_source_up_to_date": "Uppdaterad",
|
||||
"download_source_errored": "Fel uppstod",
|
||||
"sync_download_sources": "Synkronisera källor",
|
||||
"removed_download_source": "Nedladdningskälla borttagen",
|
||||
"removed_download_sources": "Nedladdningskällor borttagna",
|
||||
"cancel_button_confirmation_delete_all_sources": "Nej",
|
||||
"confirm_button_confirmation_delete_all_sources": "Ja, ta bort allt",
|
||||
"title_confirmation_delete_all_sources": "Ta bort alla nedladdningskällor",
|
||||
"description_confirmation_delete_all_sources": "Du kommer att ta bort alla nedladdningskällor",
|
||||
"button_delete_all_sources": "Ta bort alla",
|
||||
"added_download_source": "Nedladdningskälla tillagd",
|
||||
"download_sources_synced": "Alla nedladdningskällor är synkroniserade",
|
||||
"insert_valid_json_url": "Ange en giltig JSON-URL",
|
||||
"found_download_option_zero": "Inga nedladdningsalternativ hittades",
|
||||
"found_download_option_one": "Hittade {{countFormatted}} nedladdningsalternativ",
|
||||
"found_download_option_other": "Hittade {{countFormatted}} nedladdningsalternativ",
|
||||
"import": "Importera",
|
||||
"public": "Offentlig",
|
||||
"private": "Privat",
|
||||
"friends_only": "Endast vänner",
|
||||
"privacy": "Integritet",
|
||||
"profile_visibility": "Profilens synlighet",
|
||||
"profile_visibility_description": "Välj vem som kan se din profil och ditt bibliotek",
|
||||
"required_field": "Detta fält är obligatoriskt",
|
||||
"source_already_exists": "Denna källa har redan lagts till",
|
||||
"must_be_valid_url": "Källan måste vara en giltig URL",
|
||||
"blocked_users": "Blockerade användare",
|
||||
"user_unblocked": "Användaren har avblockerats",
|
||||
"enable_achievement_notifications": "När en prestation låses upp",
|
||||
"launch_minimized": "Starta Hydra minimerad",
|
||||
"disable_nsfw_alert": "Inaktivera NSFW-varning",
|
||||
"seed_after_download_complete": "Seeda efter att nedladdningen är klar",
|
||||
"show_hidden_achievement_description": "Visa beskrivning av dolda prestationer innan de låses upp",
|
||||
"account": "Konto",
|
||||
"no_users_blocked": "Du har inga blockerade användare",
|
||||
"subscription_active_until": "Ditt Hydra Cloud är aktivt till {{date}}",
|
||||
"manage_subscription": "Hantera prenumeration",
|
||||
"update_email": "Uppdatera e-postadress",
|
||||
"update_password": "Uppdatera lösenord",
|
||||
"current_email": "Nuvarande e-postadress:",
|
||||
"no_email_account": "Du har ännu inte angett någon e-postadress",
|
||||
"account_data_updated_successfully": "Kontoinformationen har uppdaterats",
|
||||
"renew_subscription": "Förnya Hydra Cloud",
|
||||
"subscription_expired_at": "Din prenumeration gick ut den {{date}}",
|
||||
"no_subscription": "Njut av Hydra på bästa möjliga sätt",
|
||||
"become_subscriber": "Bli Hydra Cloud-prenumerant",
|
||||
"subscription_renew_cancelled": "Automatisk förnyelse är inaktiverad",
|
||||
"subscription_renews_on": "Din prenumeration förnyas den {{date}}",
|
||||
"bill_sent_until": "Din nästa faktura skickas senast detta datum",
|
||||
"no_themes": "Det verkar som att du inte har några teman ännu, men ingen fara – klicka här för att skapa ditt första mästerverk.",
|
||||
"editor_tab_code": "Kod",
|
||||
"editor_tab_info": "Info",
|
||||
"editor_tab_save": "Spara",
|
||||
"web_store": "Webbutik",
|
||||
"clear_themes": "Rensa",
|
||||
"create_theme": "Skapa",
|
||||
"create_theme_modal_title": "Skapa eget tema",
|
||||
"create_theme_modal_description": "Skapa ett nytt tema för att anpassa Hydras utseende",
|
||||
"theme_name": "Namn",
|
||||
"insert_theme_name": "Ange temats namn",
|
||||
"set_theme": "Aktivera tema",
|
||||
"unset_theme": "Avaktivera tema",
|
||||
"delete_theme": "Ta bort tema",
|
||||
"edit_theme": "Redigera tema",
|
||||
"delete_all_themes": "Ta bort alla teman",
|
||||
"delete_all_themes_description": "Detta kommer att ta bort alla dina egna teman",
|
||||
"delete_theme_description": "Detta kommer att ta bort temat {{theme}}",
|
||||
"cancel": "Avbryt",
|
||||
"appearance": "Utseende",
|
||||
"enable_torbox": "Aktivera TorBox",
|
||||
"torbox_description": "TorBox är din premium seedbox-tjänst som konkurrerar med de bästa servrarna på marknaden.",
|
||||
"torbox_account_linked": "TorBox-konto kopplat",
|
||||
"create_real_debrid_account": "Klicka här om du ännu inte har ett Real-Debrid-konto",
|
||||
"create_torbox_account": "Klicka här om du ännu inte har ett TorBox-konto",
|
||||
"real_debrid_account_linked": "Real-Debrid-konto kopplat",
|
||||
"name_min_length": "Temanamnet måste innehålla minst 3 tecken",
|
||||
"import_theme": "Importera tema",
|
||||
"import_theme_description": "Du kommer att importera {{theme}} från temabutiken",
|
||||
"error_importing_theme": "Fel vid import av tema",
|
||||
"theme_imported": "Temat har importerats",
|
||||
"enable_friend_request_notifications": "När en vänförfrågan tas emot",
|
||||
"enable_auto_install": "Ladda ner uppdateringar automatiskt",
|
||||
"common_redist": "Nödvändiga systemkomponenter",
|
||||
"common_redist_description": "Nödvändiga systemkomponenter krävs för att vissa spel ska fungera. Det rekommenderas att installera dem för att undvika problem.",
|
||||
"install_common_redist": "Installera",
|
||||
"installing_common_redist": "Installerar…",
|
||||
"show_download_speed_in_megabytes": "Visa nedladdningshastighet i megabyte per sekund",
|
||||
"extract_files_by_default": "Extrahera filer automatiskt efter nedladdning",
|
||||
"achievement_custom_notification_position": "Anpassad position för prestationmeddelande",
|
||||
"top-left": "Övre vänster",
|
||||
"top-center": "Övre mitten",
|
||||
"top-right": "Övre höger",
|
||||
"bottom-left": "Nedre vänster",
|
||||
"bottom-center": "Nedre mitten",
|
||||
"bottom-right": "Nedre höger",
|
||||
"enable_achievement_custom_notifications": "Aktivera anpassade prestationmeddelanden",
|
||||
"alignment": "Justering",
|
||||
"variation": "Variation",
|
||||
"default": "Standard",
|
||||
"rare": "Sällsynt",
|
||||
"platinum": "Platina",
|
||||
"hidden": "Dold",
|
||||
"test_notification": "Testa meddelande",
|
||||
"notification_preview": "Förhandsvisning av prestationmeddelande",
|
||||
"enable_friend_start_game_notifications": "När en vän börjar spela ett spel"
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "Nedladdning klar",
|
||||
"game_ready_to_install": "{{title}} är redo att installeras",
|
||||
"repack_list_updated": "Repack-listan har uppdaterats",
|
||||
"repack_count_one": "{{count}} repack tillagd",
|
||||
"repack_count_other": "{{count}} repacks tillagda",
|
||||
"new_update_available": "Version {{version}} tillgänglig",
|
||||
"restart_to_install_update": "Starta om Hydra för att installera uppdateringen",
|
||||
"notification_achievement_unlocked_title": "Prestation upplåst för {{game}}",
|
||||
"notification_achievement_unlocked_body": "{{achievement}} och {{count}} andra har låsts upp",
|
||||
"new_friend_request_description": "{{displayName}} har skickat en vänförfrågan",
|
||||
"new_friend_request_title": "Ny vänförfrågan",
|
||||
"extraction_complete": "Extrahering slutförd",
|
||||
"game_extracted": "{{title}} har extraherats",
|
||||
"friend_started_playing_game": "{{displayName}} började spela ett spel",
|
||||
"test_achievement_notification_title": "Detta är ett testmeddelande",
|
||||
"test_achievement_notification_description": "Ganska coolt, eller hur?"
|
||||
},
|
||||
"system_tray": {
|
||||
"open": "Öppna Hydra",
|
||||
"quit": "Avsluta"
|
||||
},
|
||||
"game_card": {
|
||||
"available_one": "Tillgänglig",
|
||||
"available_other": "Tillgänglig",
|
||||
"no_downloads": "Inga nedladdningar tillgängliga"
|
||||
},
|
||||
"binary_not_found_modal": {
|
||||
"title": "Program inte installerade",
|
||||
"description": "Wine- eller Lutris-körbara filer hittades inte på ditt system",
|
||||
"instructions": "Kontrollera hur du installerar dem korrekt på din Linux-distribution så att spelet kan köras normalt"
|
||||
},
|
||||
"modal": {
|
||||
"close": "Stäng-knapp"
|
||||
},
|
||||
"forms": {
|
||||
"toggle_password_visibility": "Visa/dölj lösenord"
|
||||
},
|
||||
"user_profile": {
|
||||
"amount_hours": "{{amount}} timmar",
|
||||
"amount_minutes": "{{amount}} minuter",
|
||||
"last_time_played": "Senast spelad {{period}}",
|
||||
"activity": "Senaste aktivitet",
|
||||
"library": "Bibliotek",
|
||||
"total_play_time": "Total speltid",
|
||||
"no_recent_activity_title": "Hmmm… ingenting här",
|
||||
"no_recent_activity_description": "Du har inte spelat några spel nyligen. Dags att ändra på det!",
|
||||
"display_name": "Visningsnamn",
|
||||
"saving": "Sparar",
|
||||
"save": "Spara",
|
||||
"edit_profile": "Redigera profil",
|
||||
"saved_successfully": "Sparat",
|
||||
"try_again": "Försök igen",
|
||||
"sign_out_modal_title": "Är du säker?",
|
||||
"cancel": "Avbryt",
|
||||
"successfully_signed_out": "Utloggningen lyckades",
|
||||
"sign_out": "Logga ut",
|
||||
"playing_for": "Spelar sedan {{amount}}",
|
||||
"sign_out_modal_text": "Ditt bibliotek är kopplat till det aktuella kontot. När du loggar ut kommer biblioteket inte längre vara synligt, och framstegen kommer inte att sparas. Vill du fortsätta logga ut?",
|
||||
"add_friends": "Lägg till vänner",
|
||||
"add": "Lägg till",
|
||||
"friend_code": "Vänkod",
|
||||
"see_profile": "Visa profil",
|
||||
"sending": "Skickar",
|
||||
"friend_request_sent": "Vänförfrågan skickad",
|
||||
"friends": "Vänner",
|
||||
"friends_list": "Vänlista",
|
||||
"user_not_found": "Användare hittades inte",
|
||||
"block_user": "Blockera användare",
|
||||
"add_friend": "Lägg till vän",
|
||||
"request_sent": "Förfrågan skickad",
|
||||
"request_received": "Förfrågan mottagen",
|
||||
"accept_request": "Acceptera förfrågan",
|
||||
"ignore_request": "Ignorera förfrågan",
|
||||
"cancel_request": "Avbryt förfrågan",
|
||||
"undo_friendship": "Ta bort vänskap",
|
||||
"request_accepted": "Förfrågan accepterad",
|
||||
"user_blocked_successfully": "Användaren har blockerats",
|
||||
"user_block_modal_text": "Detta kommer att blockera {{displayName}}",
|
||||
"blocked_users": "Blockerade användare",
|
||||
"unblock": "Avblockera",
|
||||
"no_friends_added": "Du har inte lagt till några vänner",
|
||||
"pending": "Väntande",
|
||||
"no_pending_invites": "Du har inga väntande inbjudningar",
|
||||
"no_blocked_users": "Du har inga blockerade användare",
|
||||
"friend_code_copied": "Vänkod kopierad",
|
||||
"undo_friendship_modal_text": "Detta kommer att ta bort din vänskap med {{displayName}}",
|
||||
"privacy_hint": "För att justera vem som kan se detta, gå till <0>Inställningar</0>",
|
||||
"locked_profile": "Denna profil är privat",
|
||||
"image_process_failure": "Fel vid bildbehandling",
|
||||
"required_field": "Detta fält är obligatoriskt",
|
||||
"displayname_min_length": "Visningsnamnet måste vara minst 3 tecken långt",
|
||||
"displayname_max_length": "Visningsnamnet får vara högst 50 tecken långt",
|
||||
"report_profile": "Anmäl denna profil",
|
||||
"report_reason": "Varför anmäler du denna profil?",
|
||||
"report_description": "Ytterligare information",
|
||||
"report_description_placeholder": "Ytterligare information",
|
||||
"report": "Anmäl",
|
||||
"report_reason_hate": "Hatretorik",
|
||||
"report_reason_sexual_content": "Sexuellt innehåll",
|
||||
"report_reason_violence": "Våld",
|
||||
"report_reason_spam": "Spam",
|
||||
"report_reason_other": "Annat",
|
||||
"profile_reported": "Profil anmäld",
|
||||
"your_friend_code": "Din vänkod:",
|
||||
"upload_banner": "Ladda upp banner",
|
||||
"uploading_banner": "Laddar upp banner…",
|
||||
"background_image_updated": "Bakgrundsbild uppdaterad",
|
||||
"stats": "Statistik",
|
||||
"achievements": "prestationer",
|
||||
"games": "Spel",
|
||||
"top_percentile": "Topp {{percentile}}%",
|
||||
"ranking_updated_weekly": "Rankingen uppdateras varje vecka",
|
||||
"playing": "Spelar {{game}}",
|
||||
"achievements_unlocked": "Prestationer upplåsta",
|
||||
"earned_points": "Intjänade poäng",
|
||||
"show_achievements_on_profile": "Visa dina prestationer på profilen",
|
||||
"show_points_on_profile": "Visa dina intjänade poäng på din profil"
|
||||
},
|
||||
"achievement": {
|
||||
"achievement_unlocked": "Prestationer upplåst",
|
||||
"user_achievements": "Prestationer för {{displayName}}",
|
||||
"your_achievements": "Dina prestationer",
|
||||
"unlocked_at": "Upplåst den: {{date}}",
|
||||
"subscription_needed": "Ett Hydra Cloud-abonnemang krävs för att se detta innehåll",
|
||||
"new_achievements_unlocked": "Upplåste {{achievementCount}} nya prestationer från {{gameCount}} spel",
|
||||
"achievement_progress": "{{unlockedCount}}/{{totalCount}} prestationer",
|
||||
"achievements_unlocked_for_game": "Upplåste {{achievementCount}} nya prestationer för {{gameTitle}}",
|
||||
"hidden_achievement_tooltip": "Detta är en dold prestation",
|
||||
"achievement_earn_points": "Tjäna {{points}} poäng med denna prestation",
|
||||
"earned_points": "Tjänade poäng:",
|
||||
"available_points": "Tillgängliga poäng:",
|
||||
"how_to_earn_achievements_points": "Hur tjänar man poäng på prestationer?"
|
||||
},
|
||||
"hydra_cloud": {
|
||||
"subscription_tour_title": "Hydra Cloud-abonnemang",
|
||||
"subscribe_now": "Prenumerera nu",
|
||||
"cloud_saving": "Spara i molnet",
|
||||
"cloud_achievements": "Spara dina prestationer i molnet",
|
||||
"animated_profile_picture": "Animerade profilbilder",
|
||||
"premium_support": "Premium-support",
|
||||
"show_and_compare_achievements": "Visa och jämför dina prestationer med andra användare",
|
||||
"animated_profile_banner": "Animerad profilbanner",
|
||||
"hydra_cloud": "Hydra Cloud",
|
||||
"hydra_cloud_feature_found": "Du har just upptäckt en Hydra Cloud-funktion!",
|
||||
"learn_more": "Läs mer",
|
||||
"debrid_description": "Ladda ner upp till 4x snabbare med Nimbus"
|
||||
}
|
||||
}
|
||||
@@ -8,46 +8,46 @@
|
||||
"surprise_me": "Beni Şaşırt",
|
||||
"no_results": "Sonuç bulunamadı",
|
||||
"start_typing": "Aramak için yazmaya başlayın...",
|
||||
"hot": "Şu anda popüler",
|
||||
"weekly": "📅 Haftanın en iyi oyunları",
|
||||
"achievements": "🏆 Tamamlanacak oyunlar"
|
||||
"hot": "Şu anda Popüler",
|
||||
"weekly": "📅 Haftanın En İyi Oyunları",
|
||||
"achievements": "🏆 Bitirilecek Oyunlar"
|
||||
},
|
||||
"sidebar": {
|
||||
"catalogue": "Katalog",
|
||||
"downloads": "İndirilenler",
|
||||
"settings": "Ayarlar",
|
||||
"my_library": "Kütüphane",
|
||||
"my_library": "Kütüphanem",
|
||||
"downloading_metadata": "{{title}} (Meta verileri indiriliyor…)",
|
||||
"paused": "{{title}} (Durduruldu)",
|
||||
"downloading": "{{title}} ({{percentage}} - İndiriliyor…)",
|
||||
"filter": "Kütüphaneyi filtrele",
|
||||
"paused": "{{title}} (Duraklatıldı)",
|
||||
"downloading": "{{title}} (%{{percentage}} - İndiriliyor…)",
|
||||
"filter": "Kütüphanede filtrele",
|
||||
"home": "Ana Sayfa",
|
||||
"queued": "{{title}} (Sırada)",
|
||||
"game_has_no_executable": "Oyun için bir çalıştırılabilir dosya seçilmedi",
|
||||
"sign_in": "Giriş yap",
|
||||
"game_has_no_executable": "Bu oyun için çalıştırılabilir dosya seçilmedi",
|
||||
"sign_in": "Giriş Yap",
|
||||
"friends": "Arkadaşlar",
|
||||
"need_help": "Yardıma mı ihtiyacınız var?",
|
||||
"favorites": "Favoriler"
|
||||
},
|
||||
"header": {
|
||||
"search": "Oyunları ara",
|
||||
"search": "Oyunlarda Ara",
|
||||
"home": "Ana Sayfa",
|
||||
"catalogue": "Katalog",
|
||||
"downloads": "İndirilenler",
|
||||
"search_results": "Arama sonuçları",
|
||||
"search_results": "Arama Sonuçları",
|
||||
"settings": "Ayarlar",
|
||||
"version_available_install": "{{version}} sürümü mevcut. Yüklemek ve yeniden başlatmak için buraya tıklayın.",
|
||||
"version_available_download": "{{version}} sürümü mevcut. İndirmek için buraya tıklayın."
|
||||
"version_available_install": "{{version}} sürümü mevcut. Yeniden başlatıp yüklemek için tıklayın.",
|
||||
"version_available_download": "{{version}} sürümü mevcut. İndirmek için tıklayın."
|
||||
},
|
||||
"bottom_panel": {
|
||||
"no_downloads_in_progress": "Devam eden indirme yok",
|
||||
"downloading_metadata": "{{title}} meta verileri indiriliyor…",
|
||||
"downloading": "{{title}} indiriliyor… ({{percentage}} tamamlandı) - Tamamlanma: {{eta}} - Hız: {{speed}}",
|
||||
"calculating_eta": "{{title}} indiriliyor… ({{percentage}} tamamlandı) - Kalan süre hesaplanıyor…",
|
||||
"checking_files": "{{title}} dosyaları kontrol ediliyor… ({{percentage}} tamamlandı)",
|
||||
"downloading": "{{title}} indiriliyor… (%{{percentage}} tamamlandı) - Bitiş: {{eta}} - Hız: {{speed}}",
|
||||
"calculating_eta": "{{title}} indiriliyor… (%{{percentage}} tamamlandı) - Kalan süre hesaplanıyor…",
|
||||
"checking_files": "{{title}} dosyaları kontrol ediliyor… (%{{percentage}} tamamlandı)",
|
||||
"installing_common_redist": "{{log}}…",
|
||||
"installation_complete": "İndirme tamamlandı",
|
||||
"installation_complete_message": "Genel bağımlılıklar başarıyla yüklendi."
|
||||
"installation_complete": "Kurulum tamamlandı",
|
||||
"installation_complete_message": "Gerekli paketler başarıyla yüklendi"
|
||||
},
|
||||
"catalogue": {
|
||||
"search": "Filtrele…",
|
||||
@@ -58,7 +58,7 @@
|
||||
"download_sources": "İndirme kaynakları",
|
||||
"result_count": "{{resultCount}} sonuç",
|
||||
"filter_count": "{{filterCount}} mevcut",
|
||||
"clear_filters": "{{filterCount}} seçili filtreyi temizle"
|
||||
"clear_filters": "{{filterCount}} seçiliyi temizle"
|
||||
},
|
||||
"game_details": {
|
||||
"open_download_options": "İndirme seçeneklerini aç",
|
||||
@@ -67,32 +67,32 @@
|
||||
"download_options_other": "{{count}} indirme seçeneği",
|
||||
"updated_at": "{{updated_at}} tarihinde güncellendi",
|
||||
"install": "Yükle",
|
||||
"resume": "Devam et",
|
||||
"pause": "Durdur",
|
||||
"cancel": "İptal et",
|
||||
"resume": "Devam Et",
|
||||
"pause": "Duraklat",
|
||||
"cancel": "İptal Et",
|
||||
"remove": "Kaldır",
|
||||
"space_left_on_disk": "Diskte {{space}} boş alan kaldı",
|
||||
"eta": "{{eta}} tahmini bitiş",
|
||||
"eta": "Bitiş: {{eta}}",
|
||||
"calculating_eta": "Kalan süre hesaplanıyor…",
|
||||
"downloading_metadata": "Meta veriler indiriliyor…",
|
||||
"filter": "Paketleri filtrele",
|
||||
"requirements": "Sistem gereksinimleri",
|
||||
"requirements": "Sistem Gereksinimleri",
|
||||
"minimum": "Minimum",
|
||||
"recommended": "Önerilen",
|
||||
"paused": "Durduruldu",
|
||||
"paused": "Duraklatıldı",
|
||||
"release_date": "{{date}} tarihinde yayımlandı",
|
||||
"publisher": "{{publisher}} tarafından yayımlandı",
|
||||
"hours": "saat",
|
||||
"minutes": "dakika",
|
||||
"amount_hours": "{{amount}} saat",
|
||||
"amount_minutes": "{{amount}} dakika",
|
||||
"accuracy": "{{accuracy}}% doğruluk",
|
||||
"accuracy": "%{{accuracy}} doğruluk",
|
||||
"add_to_library": "Kütüphaneye ekle",
|
||||
"remove_from_library": "Kütüphaneden kaldır",
|
||||
"no_downloads": "İndirilebilir içerik yok",
|
||||
"play_time": "{{amount}} süre oynandı",
|
||||
"last_time_played": "Son oynama {{period}} önce",
|
||||
"not_played_yet": "{{title}} henüz oynanmadı",
|
||||
"no_downloads": "İndirme mevcut değil",
|
||||
"play_time": "{{amount}} oynandı",
|
||||
"last_time_played": "Son oynanma: {{period}}",
|
||||
"not_played_yet": "{{title}} oyununu henüz oynamadınız",
|
||||
"next_suggestion": "Sonraki öneri",
|
||||
"play": "Oyna",
|
||||
"deleting": "Yükleyici siliniyor…",
|
||||
@@ -107,134 +107,140 @@
|
||||
"download_path": "İndirme yolu",
|
||||
"previous_screenshot": "Önceki ekran görüntüsü",
|
||||
"next_screenshot": "Sonraki ekran görüntüsü",
|
||||
"screenshot": "{{number}} ekran görüntüsü",
|
||||
"open_screenshot": "{{number}} ekran görüntüsünü aç",
|
||||
"screenshot": "Ekran görüntüsü {{number}}",
|
||||
"open_screenshot": "Ekran görüntüsünü aç ({{number}})",
|
||||
"download_settings": "İndirme ayarları",
|
||||
"downloader": "İndirici",
|
||||
"select_executable": "Seç",
|
||||
"no_executable_selected": "Hiçbir çalıştırılabilir dosya seçilmedi",
|
||||
"no_executable_selected": "Çalıştırılabilir dosya seçilmedi",
|
||||
"open_folder": "Klasörü aç",
|
||||
"open_download_location": "İndirilen dosyaları gör",
|
||||
"open_download_location": "İndirilen dosyaları görüntüle",
|
||||
"create_shortcut": "Masaüstü kısayolu oluştur",
|
||||
"clear": "Temizle",
|
||||
"remove_files": "Dosyaları kaldır",
|
||||
"remove_from_library_title": "Emin misiniz?",
|
||||
"remove_from_library_description": "Bu işlem sonrasında {{game}} oyunu kütüphanenizden kaldıracaktır",
|
||||
"remove_from_library_description": "{{game}} oyununu kütüphanenizden kaldıracaktır",
|
||||
"options": "Seçenekler",
|
||||
"executable_section_title": "Çalıştırılabilir dosya",
|
||||
"executable_section_description": "\"Oyna\" butonuna tıklandığında çalıştırılacak dosyanın yolu",
|
||||
"downloads_section_title": "İndirmeler",
|
||||
"downloads_section_description": "Bu oyun için güncellemeleri veya diğer sürümleri kontrol edin",
|
||||
"danger_zone_section_title": "Tehlike bölgesi",
|
||||
"danger_zone_section_description": "Bu oyunu kütüphanenizden kaldırın veya Hydra tarafından indirilen dosyaları silin.",
|
||||
"download_in_progress": "İndirme devam ediyor",
|
||||
"download_paused": "İndirme durduruldu",
|
||||
"executable_section_description": "\"Oyna\" seçildiğinde çalışacak dosyanın yolu",
|
||||
"downloads_section_title": "İndirilenler",
|
||||
"downloads_section_description": "Bu oyunun güncelleme veya diğer sürümlerine göz atın",
|
||||
"danger_zone_section_title": "Tehlikeli Alan",
|
||||
"danger_zone_section_description": "Bu oyunu kütüphanenizden veya Hydra tarafından indirilen dosyalardan kaldırın",
|
||||
"download_in_progress": "İndirme sürüyor",
|
||||
"download_paused": "İndirme duraklatıldı",
|
||||
"last_downloaded_option": "Son indirilen seçenek",
|
||||
"create_steam_shortcut": "Steam kısayolu oluştur",
|
||||
"create_shortcut_success": "Kısayol başarıyla oluşturuldu",
|
||||
"you_might_need_to_restart_steam": "Değişiklikleri görmek için Steam'i yeniden başlatmanız gerekebilir",
|
||||
"create_shortcut_error": "Kısayol oluşturulurken hata oluştu",
|
||||
"nsfw_content_title": "Bu oyun uygunsuz içerik içeriyor",
|
||||
"nsfw_content_description": "{{title}} her yaş için uygun olmayabilecek içeriklere sahiptir. Devam etmek istediğinizden emin misiniz?",
|
||||
"nsfw_content_title": "Bu oyun uygunsuz içerik barındırıyor",
|
||||
"nsfw_content_description": "{{title}} bazı kullanıcılar için uygun olmayabilecek içerik barındırıyor. Devam etmek istediğinizden emin misiniz?",
|
||||
"allow_nsfw_content": "Devam et",
|
||||
"refuse_nsfw_content": "Geri dön",
|
||||
"stats": "İstatistikler",
|
||||
"download_count": "İndirme sayısı",
|
||||
"download_count": "İndirme",
|
||||
"player_count": "Aktif oyuncular",
|
||||
"download_error": "Bu indirme seçeneği mevcut değil",
|
||||
"download_error": "Bu indirme seçeneği kullanılamıyor",
|
||||
"download": "İndir",
|
||||
"executable_path_in_use": "\"{{game}}\" tarafından kullanılan çalıştırılabilir dosya",
|
||||
"executable_path_in_use": "Çalıştırılabilir dosya zaten \"{{game}}\" tarafından kullanılıyor",
|
||||
"warning": "Uyarı:",
|
||||
"hydra_needs_to_remain_open": "Bu indirmenin tamamlanması için Hydra açık kalmalıdır. Eğer Hydra kapanırsa, ilerleme kaydedilmez.",
|
||||
"hydra_needs_to_remain_open": "Bu indirme için, Hydra programının tamamlanana kadar açık kalması gerekir. Hydra kapanırsa, ilerlemeniz kaybolacaktır.",
|
||||
"achievements": "Başarımlar",
|
||||
"achievements_count": "Başarımlar {{unlockedCount}}/{{achievementsCount}}",
|
||||
"cloud_save": "Bulut kaydı",
|
||||
"cloud_save_description": "İlerlemenizi buluta kaydedin ve herhangi bir cihazda oynamaya devam edin",
|
||||
"cloud_save": "Bulut Kaydı",
|
||||
"cloud_save_description": "İlerlemenizi buluta kaydedin ve herhangi bir cihazdan devam edin",
|
||||
"backups": "Yedekler",
|
||||
"install_backup": "Yükle",
|
||||
"delete_backup": "Sil",
|
||||
"create_backup": "Yeni yedek oluştur",
|
||||
"last_backup_date": "{{date}} tarihindeki son yedek",
|
||||
"no_backup_preview": "Bu oyun için bir kayıt dosyası bulunamadı",
|
||||
"restoring_backup": "Yedek geri yükleniyor ({{progress}} tamamlandı)…",
|
||||
"create_backup": "Yeni Yedek",
|
||||
"last_backup_date": "Son yedekleme: {{date}}",
|
||||
"no_backup_preview": "Bu başlık için kayıtlı oyun bulunamadı",
|
||||
"restoring_backup": "Yedek geri yükleniyor (%{{progress}} tamamlandı)…",
|
||||
"uploading_backup": "Yedek yükleniyor…",
|
||||
"no_backups": "Bu oyun için henüz bir yedek oluşturmadınız",
|
||||
"no_backups": "Bu oyun için henüz yedek oluşturmadınız",
|
||||
"backup_uploaded": "Yedek yüklendi",
|
||||
"backup_deleted": "Yedek silindi",
|
||||
"backup_restored": "Yedek geri yüklendi",
|
||||
"see_all_achievements": "Tüm başarımları gör",
|
||||
"sign_in_to_see_achievements": "Başarımları görmek için oturum açın",
|
||||
"see_all_achievements": "Tüm başarımları görüntüle",
|
||||
"sign_in_to_see_achievements": "Başarımları görmek için giriş yapın",
|
||||
"mapping_method_automatic": "Otomatik",
|
||||
"mapping_method_manual": "Manuel",
|
||||
"mapping_method_label": "Eşleme yöntemi",
|
||||
"files_automatically_mapped": "Dosyalar otomatik olarak eşlendi",
|
||||
"no_backups_created": "Bu oyun için yedek oluşturulmadı",
|
||||
"mapping_method_label": "Eşleme metodu",
|
||||
"files_automatically_mapped": "Dosyalar otomatik eşlendi",
|
||||
"no_backups_created": "Bu oyun için oluşturulmuş yedek yok",
|
||||
"manage_files": "Dosyaları yönet",
|
||||
"loading_save_preview": "Kayıtlı oyunlar aranıyor…",
|
||||
"wine_prefix": "Wine Prefix",
|
||||
"wine_prefix_description": "Bu oyunu çalıştırmak için kullanılan Wine Prefix",
|
||||
"wine_prefix": "Wine Ön Ek",
|
||||
"wine_prefix_description": "Bu oyunu çalıştırmak için kullanılan Wine ön eki",
|
||||
"launch_options": "Başlatma Seçenekleri",
|
||||
"launch_options_description": "İleri düzey kullanıcılar, başlatma seçeneklerine parametreler girebilir (deneysel özellik)",
|
||||
"launch_options_placeholder": "Belirtilen bir parametre yok",
|
||||
"launch_options_description": "Gelişmiş kullanıcılar için başlatma parametreleri tanımlayın (deneysel özellik)",
|
||||
"launch_options_placeholder": "Parametre belirtilmedi",
|
||||
"no_download_option_info": "Bilgi mevcut değil",
|
||||
"backup_deletion_failed": "Yedek silinemedi",
|
||||
"max_number_of_artifacts_reached": "Bu oyun için maksimum yedek sayısına ulaşıldı",
|
||||
"achievements_not_sync": "Başarımlarınızı senkronize etmeyi öğrenin",
|
||||
"manage_files_description": "Hangi dosyaların yedeklenip geri yükleneceğini yönetin",
|
||||
"backup_deletion_failed": "Yedek silme işlemi başarısız oldu",
|
||||
"max_number_of_artifacts_reached": "Bu oyun için azami yedekleme sayısına ulaşıldı",
|
||||
"achievements_not_sync": "Başarımlarını eşitlemeyi öğren",
|
||||
"manage_files_description": "Hangi dosyaların yedekleneceğini ve geri yükleneceğini yönetin",
|
||||
"select_folder": "Klasör seç",
|
||||
"backup_from": "{{date}} tarihinden yedek",
|
||||
"automatic_backup_from": "{{date}} tarihinden otomatik kayıt",
|
||||
"enable_automatic_cloud_sync": "Otomatik bulut kaydı senkronizasyonunu aktifleştir",
|
||||
"custom_backup_location_set": "Özel yedekleme konumu ayarlandı",
|
||||
"no_directory_selected": "Bir dizin seçilmedi",
|
||||
"no_write_permission": "Bu dizine indirme yapılamaz. Daha fazla bilgi için buraya tıklayın.",
|
||||
"backup_from": "{{date}} tarihli yedek",
|
||||
"automatic_backup_from": "{{date}} tarihli otomatik yedek",
|
||||
"enable_automatic_cloud_sync": "Otomatik bulut eşitlemesini etkinleştir",
|
||||
"custom_backup_location_set": "Özel yedekleme konumu belirlendi",
|
||||
"no_directory_selected": "Klasör seçilmedi",
|
||||
"no_write_permission": "Bu klasöre indirme yapılamıyor. Detaylar için buraya tıklayın.",
|
||||
"reset_achievements": "Başarımları sıfırla",
|
||||
"reset_achievements_description": "Bu işlem {{game}} için tüm başarımları sıfırlar",
|
||||
"reset_achievements_description": "{{game}} için tüm başarımlar sıfırlanacak",
|
||||
"reset_achievements_title": "Emin misiniz?",
|
||||
"reset_achievements_success": "Başarımlar başarıyla sıfırlandı",
|
||||
"reset_achievements_error": "Başarımlar sıfırlanamadı",
|
||||
"download_error_gofile_quota_exceeded": "Gofile aylık kotanızı doldurdunuz. Kotanın yenilenmesini bekleyin.",
|
||||
"download_error_real_debrid_account_not_authorized": "Real-Debrid hesabınız yeni indirme işlemleri yapmak için yetkilendirilmemiş. Lütfen hesap ayarlarınızı kontrol edip tekrar deneyin.",
|
||||
"download_error_not_cached_on_real_debrid": "Bu indirme Real-Debrid üzerinde mevcut değil ve Real-Debrid'den indirme durumu henüz sorgulanamıyor.",
|
||||
"download_error_not_cached_on_torbox": "Bu indirme TorBox'ta mevcut değil ve TorBox'tan indirme durumu henüz sorgulanamıyor.",
|
||||
"download_error_not_cached_on_hydra": "Bu indirme Nimbus'ta mevcut değil.",
|
||||
"game_removed_from_favorites": "Oyun favorilerden silindi",
|
||||
"download_error_gofile_quota_exceeded": "Gofile aylık kotanızı aştınız. Lütfen kotanın sıfırlanmasını bekleyin.",
|
||||
"download_error_real_debrid_account_not_authorized": "Real-Debrid hesabınız yeni indirmeler için yetkili değil. Hesap ayarlarınızı kontrol edip tekrar deneyin.",
|
||||
"download_error_not_cached_on_real_debrid": "Bu indirme Real-Debrid üzerinde mevcut değil ve durum sorgulanamıyor.",
|
||||
"download_error_not_cached_on_torbox": "Bu indirme TorBox üzerinde mevcut değil ve durum sorgulanamıyor.",
|
||||
"download_error_not_cached_on_hydra": "Bu indirme Nimbus üzerinde mevcut değil.",
|
||||
"game_removed_from_favorites": "Oyun favorilerden kaldırıldı",
|
||||
"game_added_to_favorites": "Oyun favorilere eklendi",
|
||||
"automatically_extract_downloaded_files": "Yüklenmiş dosyaları otomatik olarak çıkart"
|
||||
"automatically_extract_downloaded_files": "İndirilen dosyaları otomatik çıkart",
|
||||
"create_start_menu_shortcut": "Başlat Menüsüne kısayol oluştur",
|
||||
"invalid_wine_prefix_path": "Geçersiz Wine ön ek yolu",
|
||||
"invalid_wine_prefix_path_description": "Wine ön ek yolu hatalı. Lütfen yolu kontrol edin ve tekrar deneyin.",
|
||||
"missing_wine_prefix": "Linux'ta yedekleme oluşturmak için Wine ön eki gereklidir"
|
||||
},
|
||||
"activation": {
|
||||
"title": "Hydra'yı Aktive Et",
|
||||
"installation_id": "Kurulum Kimliği:",
|
||||
"enter_activation_code": "Aktivasyon kodunuzu girin",
|
||||
"message": "Bunu nasıl edineceğini bilmiyorsan, buna sahip olmamalısın.",
|
||||
"activate": "Aktive Et",
|
||||
"title": "Hydra'yı Etkinleştir",
|
||||
"installation_id": "Kurulum ID:",
|
||||
"enter_activation_code": "Etkinleştirme kodunu girin",
|
||||
"message": "Bu kodun nereden alınacağını bilmiyorsanız, zaten bu kodu kullanmamanız gerekir.",
|
||||
"activate": "Etkinleştir",
|
||||
"loading": "Yükleniyor…"
|
||||
},
|
||||
"downloads": {
|
||||
"resume": "Devam Et",
|
||||
"pause": "Duraklat",
|
||||
"eta": "Tamamlama {{eta}}",
|
||||
"eta": "Bitiş: {{eta}}",
|
||||
"paused": "Duraklatıldı",
|
||||
"verifying": "Doğrulanıyor…",
|
||||
"completed": "Tamamlandı",
|
||||
"removed": "İndirilmedi",
|
||||
"cancel": "İptal Et",
|
||||
"filter": "İndirilen oyunları filtrele",
|
||||
"filter": "İndirilen oyunlarda filtrele",
|
||||
"remove": "Kaldır",
|
||||
"downloading_metadata": "Meta verileri indiriliyor…",
|
||||
"deleting": "Yükleyici siliniyor…",
|
||||
"delete": "Yükleyiciyi kaldır",
|
||||
"delete_modal_title": "Emin misiniz?",
|
||||
"delete_modal_description": "Bu işlem, tüm kurulum dosyalarını bilgisayarınızdan kaldıracaktır",
|
||||
"install": "Kur",
|
||||
"delete_modal_description": "Tüm kurulum dosyaları bilgisayarınızdan kaldırılacaktır",
|
||||
"install": "Yükle",
|
||||
"download_in_progress": "Devam ediyor",
|
||||
"queued_downloads": "Sıradaki indirmeler",
|
||||
"downloads_completed": "Tamamlananlar",
|
||||
"queued": "Sırada",
|
||||
"no_downloads_title": "Bomboş",
|
||||
"no_downloads_description": "Henüz Hydra ile hiçbir şey indirmediniz, ancak başlamak için asla geç değil.",
|
||||
"no_downloads_title": "Çok boş görünüyor",
|
||||
"no_downloads_description": "Hydra ile henüz bir şey indirmediniz, başlamak için asla geç değildir.",
|
||||
"checking_files": "Dosyalar kontrol ediliyor…",
|
||||
"seeding": "Paylaşılıyor",
|
||||
"stop_seeding": "Paylaşımı durdur",
|
||||
"resume_seeding": "Paylaşımı sürdür",
|
||||
"seeding": "Seed yapılıyor",
|
||||
"stop_seeding": "Seed yapmayı durdur",
|
||||
"resume_seeding": "Seed yapmaya devam et",
|
||||
"options": "Yönet",
|
||||
"extract": "Dosyaları çıkart",
|
||||
"extracting": "Dosyalar çıkartılıyor…"
|
||||
@@ -243,181 +249,202 @@
|
||||
"downloads_path": "İndirme yolu",
|
||||
"change": "Güncelle",
|
||||
"notifications": "Bildirimler",
|
||||
"enable_download_notifications": "Bir indirme tamamlandığında",
|
||||
"enable_repack_list_notifications": "Yeni bir repack eklendiğinde",
|
||||
"enable_download_notifications": "İndirme tamamlandığında",
|
||||
"enable_repack_list_notifications": "Yeni bir paket eklendiğinde",
|
||||
"real_debrid_api_token_label": "Real-Debrid API anahtarı",
|
||||
"quit_app_instead_hiding": "Hydra'yı kapatınca sistem tepsisine gitmesin",
|
||||
"launch_with_system": "Hydra'yı sistem başlatıldığında çalıştır",
|
||||
"quit_app_instead_hiding": "Hydra kapatıldığında gizleme",
|
||||
"launch_with_system": "Sistem başlatıldığında Hydra'yı aç",
|
||||
"general": "Genel",
|
||||
"behavior": "Davranış",
|
||||
"download_sources": "İndirme kaynakları",
|
||||
"language": "Dil",
|
||||
"api_token": "API Anahtarı",
|
||||
"enable_real_debrid": "Real-Debrid'i Etkinleştir",
|
||||
"real_debrid_description": "Real-Debrid, yalnızca internet hızınızla sınırlı olarak hızlı dosya indirmenizi sağlayan sınırsız bir indirici.",
|
||||
"enable_real_debrid": "Real-Debrid’i etkinleştir",
|
||||
"real_debrid_description": "Real-Debrid, yalnızca internet hızınızla sınırlı olarak dosyaları hızlı indirmenizi sağlayan sınırsız bir indirme servisidir.",
|
||||
"debrid_invalid_token": "Geçersiz API anahtarı",
|
||||
"debrid_api_token_hint": "API anahtarınızı <0>buradan</0> alabilirsiniz",
|
||||
"real_debrid_free_account_error": "\"{{username}}\" hesabı ücretsiz bir hesaptır. Lütfen Real-Debrid abonesi olun",
|
||||
"real_debrid_free_account_error": "\"{{username}}\" hesabı ücretsizdir. Lütfen Real-Debrid’e abone olun",
|
||||
"debrid_linked_message": "\"{{username}}\" hesabı bağlandı",
|
||||
"save_changes": "Değişiklikleri Kaydet",
|
||||
"changes_saved": "Değişiklikler başarıyla kaydedildi",
|
||||
"download_sources_description": "Hydra, indirme bağlantılarını bu kaynaklardan alacak. Kaynak URL, indirme bağlantılarını içeren bir .json dosyasına doğrudan bir bağlantı olmalıdır.",
|
||||
"download_sources_description": "Hydra, indirme bağlantılarını bu kaynaklardan alacaktır. Kaynak URL’si, bağlantıların bulunduğu bir .json dosyasına doğrudan bağlantı olmalıdır.",
|
||||
"validate_download_source": "Doğrula",
|
||||
"remove_download_source": "Kaldır",
|
||||
"add_download_source": "Kaynak ekle",
|
||||
"cancel_button_confirmation_delete_all_sources": "Hayır",
|
||||
"confirm_button_confirmation_delete_all_sources": "Evet, her şeyi sil",
|
||||
"description_confirmation_delete_all_sources": "Tüm indirme kaynaklarını sileceksiniz",
|
||||
"title_confirmation_delete_all_sources": "Tüm indirme kaynaklarını sil",
|
||||
"removed_download_sources": "Yazı tipleri kaldırıldı",
|
||||
"button_delete_all_sources": "Tüm indirme kaynaklarını kaldır",
|
||||
"download_count_zero": "İndirme seçeneği yok",
|
||||
"download_count_one": "{{countFormatted}} indirme seçeneği",
|
||||
"download_count_other": "{{countFormatted}} indirme seçeneği",
|
||||
"download_source_url": "İndirme kaynağı URL'si",
|
||||
"add_download_source_description": ".json dosyasının URL'sini girin",
|
||||
"add_download_source_description": ".json dosyasının URL’sini girin",
|
||||
"download_source_up_to_date": "Güncel",
|
||||
"download_source_errored": "Hatalı",
|
||||
"sync_download_sources": "Kaynakları senkronize et",
|
||||
"sync_download_sources": "Kaynakları eşitle",
|
||||
"removed_download_source": "İndirme kaynağı kaldırıldı",
|
||||
"removed_download_sources": "İndirme kaynakları kaldırıldı",
|
||||
"cancel_button_confirmation_delete_all_sources": "Hayır",
|
||||
"confirm_button_confirmation_delete_all_sources": "Evet, hepsini sil",
|
||||
"title_confirmation_delete_all_sources": "Tüm indirme kaynaklarını sil",
|
||||
"description_confirmation_delete_all_sources": "Tüm indirme kaynaklarını sileceksiniz",
|
||||
"button_delete_all_sources": "Tümünü kaldır",
|
||||
"added_download_source": "İndirme kaynağı eklendi",
|
||||
"download_sources_synced": "Tüm indirme kaynakları senkronize edildi",
|
||||
"insert_valid_json_url": "Geçerli bir JSON URL'si girin",
|
||||
"found_download_option_zero": "Hiçbir indirme seçeneği bulunamadı",
|
||||
"download_sources_synced": "Tüm indirme kaynakları eşitlendi",
|
||||
"insert_valid_json_url": "Geçerli bir JSON URL’si girin",
|
||||
"found_download_option_zero": "İndirme seçeneği bulunamadı",
|
||||
"found_download_option_one": "{{countFormatted}} indirme seçeneği bulundu",
|
||||
"found_download_option_other": "{{countFormatted}} indirme seçeneği bulundu",
|
||||
"import": "İçe aktar",
|
||||
"public": "Herkese açık",
|
||||
"import": "İçe Aktar",
|
||||
"public": "Herkese Açık",
|
||||
"private": "Gizli",
|
||||
"friends_only": "Sadece arkadaşlar",
|
||||
"friends_only": "Yalnızca Arkadaşlar",
|
||||
"privacy": "Gizlilik",
|
||||
"profile_visibility": "Profil görünürlüğü",
|
||||
"profile_visibility": "Profil Görünürlüğü",
|
||||
"profile_visibility_description": "Profilinizi ve kütüphanenizi kimlerin görebileceğini seçin",
|
||||
"required_field": "Bu alan gereklidir",
|
||||
"source_already_exists": "Bu kaynak zaten eklenmiş",
|
||||
"must_be_valid_url": "Kaynak geçerli bir URL olmalıdır",
|
||||
"source_already_exists": "Bu kaynak zaten eklendi",
|
||||
"must_be_valid_url": "Kaynak geçerli bir URL olmalı",
|
||||
"blocked_users": "Engellenen kullanıcılar",
|
||||
"user_unblocked": "Kullanıcının engeli kaldırıldı",
|
||||
"enable_achievement_notifications": "Bir başarım kilidi açıldığında",
|
||||
"launch_minimized": "Hydra'yı küçültülmüş başlat",
|
||||
"user_unblocked": "Kullanıcı engeli kaldırıldı",
|
||||
"enable_achievement_notifications": "Bir başarı açıldığında",
|
||||
"launch_minimized": "Hydra'yı küçük aç",
|
||||
"disable_nsfw_alert": "NSFW uyarısını devre dışı bırak",
|
||||
"seed_after_download_complete": "İndirme tamamlandıktan sonra paylaş",
|
||||
"show_hidden_achievement_description": "Gizli başarım açıklamalarını kilitlenmeden önce göster",
|
||||
"seed_after_download_complete": "İndirme sonrası seed yap",
|
||||
"show_hidden_achievement_description": "Açılmadan önce gizli başarı açıklamasını göster",
|
||||
"account": "Hesap",
|
||||
"no_users_blocked": "Hiçbir kullanıcıyı engellemediniz",
|
||||
"subscription_active_until": "Hydra Cloud'unuz {{date}} tarihine kadar aktif",
|
||||
"subscription_active_until": "Hydra Cloud üyeliğiniz {{date}} tarihine kadar aktif",
|
||||
"manage_subscription": "Aboneliği yönet",
|
||||
"update_email": "E-posta'yı güncelle",
|
||||
"update_email": "E-postayı güncelle",
|
||||
"update_password": "Şifreyi güncelle",
|
||||
"current_email": "Aktif e-posta'nız",
|
||||
"no_email_account": "Henüz ayarlanmış bir e-postanız yok",
|
||||
"account_data_updated_successfully": "Hesap bilgileri başarıyla güncellendi",
|
||||
"current_email": "Mevcut e-posta:",
|
||||
"no_email_account": "Henüz bir e-posta tanımlanmadı",
|
||||
"account_data_updated_successfully": "Hesap verileri başarıyla güncellendi",
|
||||
"renew_subscription": "Hydra Cloud'u yenile",
|
||||
"subscription_expired_at": "Aboneliğiniz {{date}} tarihinde sona erdi",
|
||||
"no_subscription": "Hydra'yı en iyi şekilde deneyimleyin",
|
||||
"become_subscriber": "Hydra Cloud'lu ol",
|
||||
"subscription_renew_cancelled": "Otomatik yenileme devre dışı",
|
||||
"no_subscription": "Hydra'yı en iyi şekilde kullanın",
|
||||
"become_subscriber": "Hydra Cloud Ol",
|
||||
"subscription_renew_cancelled": "Otomatik yenileme devre dışı bırakıldı",
|
||||
"subscription_renews_on": "Aboneliğiniz {{date}} tarihinde yenilenecek",
|
||||
"bill_sent_until": "Bir sonraki faturanız bu tarihe kadar gönderilecek",
|
||||
"no_themes": "Henüz bir temanız yok gibi görünüyor, ama endişelenmeyin, ilk şaheserinizi oluşturmak için buraya tıklayın.",
|
||||
"bill_sent_until": "Sonraki fatura bu güne kadar gönderilecek",
|
||||
"no_themes": "Henüz bir temanız yok gibi görünüyor, endişelenmeyin, ilk şaheserinizi oluşturmak için buraya tıklayın.",
|
||||
"editor_tab_code": "Kod",
|
||||
"editor_tab_info": "Bilgi",
|
||||
"editor_tab_save": "Kaydet",
|
||||
"web_store": "İnternet mağazası",
|
||||
"web_store": "Web Mağaza",
|
||||
"clear_themes": "Temizle",
|
||||
"create_theme": "Oluştur",
|
||||
"create_theme_modal_title": "Tema oluştur",
|
||||
"create_theme_modal_description": "Hydra'nın görünümünü özelleştirmek için yeni bir tema oluştur",
|
||||
"theme_name": "İsim",
|
||||
"insert_theme_name": "Tema ismini gir",
|
||||
"set_theme": "Temayı seç",
|
||||
"unset_theme": "Tema seçimini kaldır",
|
||||
"create_theme_modal_title": "Özel tema oluştur",
|
||||
"create_theme_modal_description": "Hydra’nın görünümünü özelleştirmek için yeni bir tema oluşturun",
|
||||
"theme_name": "Tema adı",
|
||||
"insert_theme_name": "Tema adı girin",
|
||||
"set_theme": "Temayı ayarla",
|
||||
"unset_theme": "Temayı kaldır",
|
||||
"delete_theme": "Temayı sil",
|
||||
"edit_theme": "Temayı düzenle",
|
||||
"delete_all_themes": "Tüm temaları sil",
|
||||
"delete_all_themes_description": "Bu tüm temalarınızı silecektir",
|
||||
"delete_theme_description": "Bu {{theme}} temasını silecektir",
|
||||
"delete_all_themes_description": "Tüm özel temalarınız silinecek",
|
||||
"delete_theme_description": "{{theme}} teması silinecek",
|
||||
"cancel": "İptal",
|
||||
"appearance": "Görünüm",
|
||||
"enable_torbox": "TorBox'u etkinleştir",
|
||||
"torbox_description": "TorBox, piyasadaki en iyi sunucularla bile rekabet edebilen premium seedbox hizmetinizdir.",
|
||||
"enable_torbox": "TorBox'u Etkinleştir",
|
||||
"torbox_description": "TorBox, piyasadaki en iyi sunucularla yarışan premium seedbox hizmetinizdir.",
|
||||
"torbox_account_linked": "TorBox hesabı bağlandı",
|
||||
"create_real_debrid_account": "Henüz bir Real-Debrid hesabınız yoksa buraya tıklayın",
|
||||
"create_torbox_account": "Henüz bir TorBox hesabınız yoksa buraya tıklayın",
|
||||
"create_real_debrid_account": "Henüz Real Debrid hesabınız yoksa buraya tıklayın",
|
||||
"create_torbox_account": "Henüz TorBox hesabınız yoksa buraya tıklayın",
|
||||
"real_debrid_account_linked": "Real-Debrid hesabı bağlandı",
|
||||
"name_min_length": "Tema ismi en az 3 karakter uzunluğunda olmalıdır",
|
||||
"import_theme": "Temayı içe aktar",
|
||||
"import_theme_description": "{{theme}} teması, tema mağazasından içeri aktarılacak",
|
||||
"error_importing_theme": "Temayı içe aktarmada bir sorun oluştu",
|
||||
"name_min_length": "Tema adı en az 3 karakter olmalıdır",
|
||||
"import_theme": "Tema içe aktar",
|
||||
"import_theme_description": "{{theme}} temasını tema mağazasından içe aktaracaksınız",
|
||||
"error_importing_theme": "Tema içe aktarılırken hata oluştu",
|
||||
"theme_imported": "Tema başarıyla içe aktarıldı",
|
||||
"enable_friend_request_notifications": "Bir arkadaşlık isteği alındığında",
|
||||
"enable_auto_install": "Güncellemeleri otomatik yükle",
|
||||
"common_redist": "Ortak bağımlılıklar",
|
||||
"common_redist_description": "Bazı oyunların çalışabilmesi için genel bağımlılıklar gereklidir. Sorun yaşamamak için bunların yüklenmesi önerilir.",
|
||||
"install_common_redist": "Yükle",
|
||||
"installing_common_redist": "Yükleniyor…",
|
||||
"show_download_speed_in_megabytes": "İndirme hızını megabayt/saniye (MB/s) cinsinden göster"
|
||||
"enable_auto_install": "Güncellemeleri otomatik indir",
|
||||
"common_redist": "Gereksinim Paketleri",
|
||||
"common_redist_description": "Bazı oyunların çalışması için gereksinim paketleri gerekir. Sorun yaşamamak için kurulması önerilir.",
|
||||
"install_common_redist": "Kur",
|
||||
"installing_common_redist": "Kuruluyor…",
|
||||
"show_download_speed_in_megabytes": "İndirme hızını megabayt cinsinden göster",
|
||||
"extract_files_by_default": "İndirme sonrası varsayılan olarak dosyaları çıkar",
|
||||
"achievement_custom_notification_position": "Başarı özel bildirim konumu",
|
||||
"top-left": "Sol üst",
|
||||
"top-center": "Üst orta",
|
||||
"top-right": "Sağ üst",
|
||||
"bottom-left": "Sol alt",
|
||||
"bottom-center": "Alt orta",
|
||||
"bottom-right": "Sağ alt",
|
||||
"enable_achievement_custom_notifications": "Başarı özel bildirimlerini etkinleştir",
|
||||
"alignment": "Hizalama",
|
||||
"variation": "Çeşit",
|
||||
"default": "Varsayılan",
|
||||
"rare": "Nadir",
|
||||
"platinum": "Platin",
|
||||
"hidden": "Gizli",
|
||||
"test_notification": "Test bildirimi",
|
||||
"notification_preview": "Başarı Bildirimi Önizlemesi",
|
||||
"enable_friend_start_game_notifications": "Bir arkadaşınız oyun oynamaya başladığında"
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "İndirme tamamlandı",
|
||||
"game_ready_to_install": "{{title}} kurulmaya hazır",
|
||||
"repack_list_updated": "Repack listesi güncellendi",
|
||||
"repack_count_one": "{{count}} repack eklendi",
|
||||
"repack_count_other": "{{count}} repack eklendi",
|
||||
"game_ready_to_install": "{{title}} yüklenmeye hazır",
|
||||
"repack_list_updated": "Paket listesi güncellendi",
|
||||
"repack_count_one": "{{count}} paket eklendi",
|
||||
"repack_count_other": "{{count}} paket eklendi",
|
||||
"new_update_available": "{{version}} sürümü mevcut",
|
||||
"restart_to_install_update": "Güncellemeyi yüklemek için Hydra'yı yeniden başlatın",
|
||||
"notification_achievement_unlocked_title": "{{game}} için başarım kilidi açıldı",
|
||||
"notification_achievement_unlocked_body": "{{achievement}} ve diğer {{count}} başarım açıldı",
|
||||
"new_friend_request_description": "Yeni bir arkadaşlık isteğin var",
|
||||
"restart_to_install_update": "Güncellemeyi yüklemek için Hydra’yı yeniden başlatın",
|
||||
"notification_achievement_unlocked_title": "{{game}} için başarı açıldı",
|
||||
"notification_achievement_unlocked_body": "{{achievement}} ve {{count}} diğer başarı açıldı",
|
||||
"new_friend_request_description": "{{displayName}} size bir arkadaşlık isteği gönderdi",
|
||||
"new_friend_request_title": "Yeni arkadaşlık isteği",
|
||||
"extraction_complete": "Çıkartma tamamlandı",
|
||||
"game_extracted": "{{title}} başarıyla çıkartıldı"
|
||||
"extraction_complete": "Çıkarma tamamlandı",
|
||||
"game_extracted": "{{title}} başarıyla çıkarıldı",
|
||||
"friend_started_playing_game": "{{displayName}} bir oyun oynamaya başladı",
|
||||
"test_achievement_notification_title": "Bu bir test bildirimi",
|
||||
"test_achievement_notification_description": "Oldukça havalı, değil mi?"
|
||||
},
|
||||
"system_tray": {
|
||||
"open": "Hydra'yı Aç",
|
||||
"quit": "Çık"
|
||||
},
|
||||
"game_card": {
|
||||
"no_downloads": "İndirilebilir içerik bulunmuyor",
|
||||
"available_one": "Mevcut",
|
||||
"available_other": "Mevcut"
|
||||
"available_other": "Mevcut",
|
||||
"no_downloads": "İndirme mevcut değil"
|
||||
},
|
||||
"binary_not_found_modal": {
|
||||
"title": "Programlar Yüklü Değil",
|
||||
"description": "Wine veya Lutris çalıştırılabilir dosyaları sisteminizde bulunamadı",
|
||||
"instructions": "Oyunun normal çalışabilmesi için bunlardan herhangi birini Linux dağıtımınıza uygun şekilde nasıl kuracağınızı kontrol edin"
|
||||
"description": "Sisteminizde Wine veya Lutris çalıştırılabilir dosyaları bulunamadı",
|
||||
"instructions": "Oyunun sorunsuz çalışması için Linux dağıtımınızda bunların nasıl kurulacağını kontrol edin"
|
||||
},
|
||||
"modal": {
|
||||
"close": "Kapat düğmesi"
|
||||
},
|
||||
"forms": {
|
||||
"toggle_password_visibility": "Şifre görünürlüğünü değiştir"
|
||||
"toggle_password_visibility": "Şifreyi göster/gizle"
|
||||
},
|
||||
"user_profile": {
|
||||
"amount_hours": "{{amount}} saat",
|
||||
"amount_minutes": "{{amount}} dakika",
|
||||
"last_time_played": "Son oynanma {{period}}",
|
||||
"last_time_played": "Son oynanma: {{period}}",
|
||||
"activity": "Son Etkinlik",
|
||||
"library": "Kütüphane",
|
||||
"total_play_time": "Toplam oynama süresi",
|
||||
"no_recent_activity_title": "Hmmm… burada bir şey yok",
|
||||
"no_recent_activity_description": "Son zamanlarda hiç oyun oynamamışsınız. Bunu değiştirmenin zamanı geldi!",
|
||||
"display_name": "Görünen isim",
|
||||
"no_recent_activity_description": "Son zamanlarda hiç oyun oynamadınız. Bunu değiştirmenin zamanı geldi!",
|
||||
"display_name": "Kullanıcı adı",
|
||||
"saving": "Kaydediliyor",
|
||||
"save": "Kaydet",
|
||||
"edit_profile": "Profili Düzenle",
|
||||
"saved_successfully": "Başarıyla kaydedildi",
|
||||
"try_again": "Lütfen tekrar deneyin",
|
||||
"sign_out_modal_title": "Emin misiniz?",
|
||||
"sign_out_modal_title": "Çıkmak istediğinizden emin misiniz?",
|
||||
"cancel": "İptal",
|
||||
"successfully_signed_out": "Başarıyla çıkış yapıldı",
|
||||
"sign_out": "Çıkış yap",
|
||||
"playing_for": "{{amount}} oynanıyor",
|
||||
"sign_out_modal_text": "Kütüphaneniz mevcut hesabınıza bağlı. Oturumu kapattığınızda kütüphaneniz görünür olmayacak ve herhangi bir ilerleme kaydedilmeyecek. Oturumu kapatmaya devam etmek istiyor musunuz?",
|
||||
"sign_out_modal_text": "Kütüphaneniz mevcut hesabınıza bağlı. Çıkış yaparsanız, kütüphaneniz görünmeyecek ve ilerlemeniz kaydedilmeyecek. Yine de çıkış yapılsın mı?",
|
||||
"add_friends": "Arkadaş Ekle",
|
||||
"add": "Ekle",
|
||||
"friend_code": "Arkadaş kodu",
|
||||
"see_profile": "Profili gör",
|
||||
"see_profile": "Profili Görüntüle",
|
||||
"sending": "Gönderiliyor",
|
||||
"friend_request_sent": "Arkadaşlık isteği gönderildi",
|
||||
"friends": "Arkadaşlar",
|
||||
@@ -428,79 +455,79 @@
|
||||
"request_sent": "İstek gönderildi",
|
||||
"request_received": "İstek alındı",
|
||||
"accept_request": "İsteği kabul et",
|
||||
"ignore_request": "İsteği yok say",
|
||||
"ignore_request": "İsteği görmezden gel",
|
||||
"cancel_request": "İsteği iptal et",
|
||||
"undo_friendship": "Arkadaşlığı sonlandır",
|
||||
"undo_friendship": "Arkadaşlığı kaldır",
|
||||
"request_accepted": "İstek kabul edildi",
|
||||
"user_blocked_successfully": "Kullanıcı başarıyla engellendi",
|
||||
"user_block_modal_text": "Bu işlem {{displayName}} adlı kullanıcıyı engelleyecek",
|
||||
"user_block_modal_text": "{{displayName}} engellenecek",
|
||||
"blocked_users": "Engellenen kullanıcılar",
|
||||
"unblock": "Engeli kaldır",
|
||||
"no_friends_added": "Hiç arkadaş eklemediniz",
|
||||
"pending": "Bekliyor",
|
||||
"no_friends_added": "Hiç arkadaşınız yok",
|
||||
"pending": "Bekleyen",
|
||||
"no_pending_invites": "Bekleyen davetiniz yok",
|
||||
"no_blocked_users": "Engellenmiş kullanıcı yok",
|
||||
"no_blocked_users": "Engellenen kullanıcı yok",
|
||||
"friend_code_copied": "Arkadaş kodu kopyalandı",
|
||||
"undo_friendship_modal_text": "Bu işlem {{displayName}} ile arkadaşlığınızı sonlandıracak",
|
||||
"privacy_hint": "Bunu kimin görebileceğini ayarlamak için <0>Ayarlar</0> bölümüne gidin",
|
||||
"undo_friendship_modal_text": "Bu işlemle {{displayName}} ile arkadaşlığınız kaldırılacak",
|
||||
"privacy_hint": "Bunu kimlerin görebileceğini <0>Ayarlar</0> bölümünden değiştirebilirsiniz",
|
||||
"locked_profile": "Bu profil gizli",
|
||||
"image_process_failure": "Görüntü işleme başarısız oldu",
|
||||
"required_field": "Bu alan gerekli",
|
||||
"displayname_min_length": "Görünen isim en az 3 karakter uzunluğunda olmalıdır",
|
||||
"displayname_max_length": "Görünen isim en fazla 50 karakter uzunluğunda olabilir",
|
||||
"report_profile": "Bu profili bildir",
|
||||
"report_reason": "Bu profili neden bildiriyorsunuz?",
|
||||
"image_process_failure": "Resim işlenirken hata oluştu",
|
||||
"required_field": "Bu alan gereklidir",
|
||||
"displayname_min_length": "Kullanıcı adı en az 3 karakter olmalıdır",
|
||||
"displayname_max_length": "Kullanıcı adı en fazla 50 karakter olmalıdır",
|
||||
"report_profile": "Bu profili şikayet et",
|
||||
"report_reason": "Bu profili neden şikayet ediyorsunuz?",
|
||||
"report_description": "Ek bilgi",
|
||||
"report_description_placeholder": "Ek bilgi",
|
||||
"report": "Bildir",
|
||||
"report": "Şikayet et",
|
||||
"report_reason_hate": "Nefret söylemi",
|
||||
"report_reason_sexual_content": "Cinsel içerik",
|
||||
"report_reason_violence": "Şiddet",
|
||||
"report_reason_spam": "Spam",
|
||||
"report_reason_other": "Diğer",
|
||||
"profile_reported": "Profil bildirildi",
|
||||
"profile_reported": "Profil şikayet edildi",
|
||||
"your_friend_code": "Arkadaş kodunuz:",
|
||||
"upload_banner": "Afiş yükle",
|
||||
"uploading_banner": "Afiş yükleniyor…",
|
||||
"background_image_updated": "Arka plan görüntüsü güncellendi",
|
||||
"upload_banner": "Banner yükle",
|
||||
"uploading_banner": "Banner yükleniyor…",
|
||||
"background_image_updated": "Arka plan resmi güncellendi",
|
||||
"stats": "İstatistikler",
|
||||
"achievements": "Başarımlar",
|
||||
"games": "Oyunlar",
|
||||
"top_percentile": "En üst {{percentile}}%",
|
||||
"ranking_updated_weekly": "Sıralama haftalık olarak güncellenir",
|
||||
"top_percentile": "En iyi %{{percentile}}",
|
||||
"ranking_updated_weekly": "Sıralama haftalık güncellenir",
|
||||
"playing": "{{game}} oynanıyor",
|
||||
"achievements_unlocked": "Başarımlar açıldı",
|
||||
"achievements_unlocked": "Açılan başarımlar",
|
||||
"earned_points": "Kazanılan puanlar",
|
||||
"show_achievements_on_profile": "Başarımlarınızı profilinizde gösterin",
|
||||
"show_points_on_profile": "Kazandığınız puanları profilinizde gösterin"
|
||||
"show_achievements_on_profile": "Başarımlarını profilinde göster",
|
||||
"show_points_on_profile": "Kazanılan puanlarını profilinde göster"
|
||||
},
|
||||
"achievement": {
|
||||
"achievement_unlocked": "Başarım açıldı",
|
||||
"user_achievements": "{{displayName}} oyununun Başarımları",
|
||||
"user_achievements": "{{displayName}}'nın Başarımları",
|
||||
"your_achievements": "Başarımlarınız",
|
||||
"unlocked_at": "Açılma zamanı: {{date}}",
|
||||
"subscription_needed": "Bu içeriği görmek için bir Hydra Cloud aboneliği gereklidir",
|
||||
"new_achievements_unlocked": "{{gameCount}} oyundan {{achievementCount}} yeni başarım açıldı",
|
||||
"achievement_progress": "{{unlockedCount}}/{{totalCount}} başarım",
|
||||
"achievements_unlocked_for_game": "{{gameTitle}} oyunu için {{achievementCount}} yeni başarım açıldı",
|
||||
"hidden_achievement_tooltip": "Bu gizli bir başarımdır",
|
||||
"achievement_earn_points": "Bu başarım ile {{points}} puan kazanın",
|
||||
"unlocked_at": "Açıldığı tarih: {{date}}",
|
||||
"subscription_needed": "Bu içeriği görmek için Hydra Cloud aboneliği gereklidir",
|
||||
"new_achievements_unlocked": "{{gameCount}} oyunda {{achievementCount}} yeni başarı açıldı",
|
||||
"achievement_progress": "{{unlockedCount}}/{{totalCount}} başarı",
|
||||
"achievements_unlocked_for_game": "{{gameTitle}} için {{achievementCount}} yeni başarı açıldı",
|
||||
"hidden_achievement_tooltip": "Bu gizli bir başarıdır",
|
||||
"achievement_earn_points": "Bu başarı ile {{points}} puan kazan",
|
||||
"earned_points": "Kazanılan puanlar:",
|
||||
"available_points": "Mevcut puanlar:",
|
||||
"how_to_earn_achievements_points": "Başarım puanları nasıl kazanılır?"
|
||||
"how_to_earn_achievements_points": "Başarı puanları nasıl kazanılır?"
|
||||
},
|
||||
"hydra_cloud": {
|
||||
"subscription_tour_title": "Hydra Cloud Aboneliği",
|
||||
"subscribe_now": "Şimdi abone olun",
|
||||
"cloud_saving": "Bulut kaydetme",
|
||||
"cloud_achievements": "Başarımlarınızı buluta kaydedin",
|
||||
"subscribe_now": "Şimdi abone ol",
|
||||
"cloud_saving": "Bulut kaydı",
|
||||
"cloud_achievements": "Başarımlarınızı bulutta saklayın",
|
||||
"animated_profile_picture": "Animasyonlu profil resimleri",
|
||||
"premium_support": "Premium Destek",
|
||||
"premium_support": "Öncelikli Destek",
|
||||
"show_and_compare_achievements": "Başarımlarınızı diğer kullanıcılarla karşılaştırın ve gösterin",
|
||||
"animated_profile_banner": "Animasyonlu profil afişi",
|
||||
"hydra_cloud": "Hydra Cloud",
|
||||
"hydra_cloud_feature_found": "Bir Hydra Cloud özelliği keşfettiniz!",
|
||||
"learn_more": "Daha Fazla Bilgi Edinin",
|
||||
"hydra_cloud_feature_found": "Bir Hydra Cloud özelliğini keşfettiniz!",
|
||||
"learn_more": "Daha fazla bilgi al",
|
||||
"debrid_description": "Nimbus ile 4 kata kadar daha hızlı indirin"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
"sign_in": "Увійти",
|
||||
"favorites": "Улюблені",
|
||||
"friends": "Друзі",
|
||||
"need_help": "Потрібна допомога?"
|
||||
"need_help": "Потрібна допомога?",
|
||||
"playable_button_title": "Показати лише ігри, які можна грати зараз"
|
||||
},
|
||||
"header": {
|
||||
"search": "Пошук",
|
||||
|
||||
@@ -26,11 +26,10 @@ export const commonRedistPath = path.join(
|
||||
"CommonRedist"
|
||||
);
|
||||
|
||||
export const logsPath = path.join(SystemPath.getPath("userData"), "logs");
|
||||
|
||||
export const seedsPath = app.isPackaged
|
||||
? path.join(process.resourcesPath, "seeds")
|
||||
: path.join(__dirname, "..", "..", "seeds");
|
||||
export const logsPath = path.join(
|
||||
SystemPath.getPath("userData"),
|
||||
`logs${isStaging ? "-staging" : ""}`
|
||||
);
|
||||
|
||||
export const achievementSoundPath = app.isPackaged
|
||||
? path.join(process.resourcesPath, "achievement.wav")
|
||||
|
||||
14
src/main/events/cloud-save/rename-game-artifact.ts
Normal file
14
src/main/events/cloud-save/rename-game-artifact.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { HydraApi } from "@main/services";
|
||||
|
||||
const renameGameArtifact = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
gameArtifactId: string,
|
||||
label: string
|
||||
) => {
|
||||
await HydraApi.put(`/profile/games/artifacts/${gameArtifactId}`, {
|
||||
label,
|
||||
});
|
||||
};
|
||||
|
||||
registerEvent("renameGameArtifact", renameGameArtifact);
|
||||
16
src/main/events/cloud-save/toggle-artifact-freeze.ts
Normal file
16
src/main/events/cloud-save/toggle-artifact-freeze.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { HydraApi } from "@main/services";
|
||||
|
||||
const toggleArtifactFreeze = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
gameArtifactId: string,
|
||||
freeze: boolean
|
||||
) => {
|
||||
if (freeze) {
|
||||
await HydraApi.put(`/profile/games/artifacts/${gameArtifactId}/freeze`);
|
||||
} else {
|
||||
await HydraApi.put(`/profile/games/artifacts/${gameArtifactId}/unfreeze`);
|
||||
}
|
||||
};
|
||||
|
||||
registerEvent("toggleArtifactFreeze", toggleArtifactFreeze);
|
||||
@@ -20,6 +20,7 @@ import "./library/create-game-shortcut";
|
||||
import "./library/close-game";
|
||||
import "./library/delete-game-folder";
|
||||
import "./library/get-game-by-object-id";
|
||||
import "./library/sync-game-by-object-id";
|
||||
import "./library/get-library";
|
||||
import "./library/extract-game-download";
|
||||
import "./library/open-game";
|
||||
@@ -86,6 +87,8 @@ import "./cloud-save/get-game-backup-preview";
|
||||
import "./cloud-save/upload-save-game";
|
||||
import "./cloud-save/delete-game-artifact";
|
||||
import "./cloud-save/select-game-backup-path";
|
||||
import "./cloud-save/toggle-artifact-freeze";
|
||||
import "./cloud-save/rename-game-artifact";
|
||||
import "./notifications/publish-new-repacks-notification";
|
||||
import "./notifications/update-achievement-notification-window";
|
||||
import "./notifications/show-achievement-test-notification";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { gamesSublevel, levelKeys } from "@main/level";
|
||||
import { HydraApi } from "@main/services";
|
||||
import type { GameShop } from "@types";
|
||||
|
||||
const addGameToFavorites = async (
|
||||
@@ -12,6 +13,8 @@ const addGameToFavorites = async (
|
||||
const game = await gamesSublevel.get(gameKey);
|
||||
if (!game) return;
|
||||
|
||||
HydraApi.put(`/profile/games/${shop}/${objectId}/favorite`).catch(() => {});
|
||||
|
||||
try {
|
||||
await gamesSublevel.put(gameKey, {
|
||||
...game,
|
||||
|
||||
@@ -12,16 +12,14 @@ const openGameInstallerPath = async (
|
||||
) => {
|
||||
const download = await downloadsSublevel.get(levelKeys.game(shop, objectId));
|
||||
|
||||
if (!download || !download.folderName || !download.downloadPath) return true;
|
||||
if (!download?.folderName || !download.downloadPath) return;
|
||||
|
||||
const gamePath = path.join(
|
||||
download.downloadPath ?? (await getDownloadsPath()),
|
||||
download.folderName!
|
||||
download.folderName
|
||||
);
|
||||
|
||||
shell.showItemInFolder(gamePath);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
registerEvent("openGameInstallerPath", openGameInstallerPath);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { gamesSublevel, levelKeys } from "@main/level";
|
||||
import { HydraApi } from "@main/services";
|
||||
import type { GameShop } from "@types";
|
||||
|
||||
const removeGameFromFavorites = async (
|
||||
@@ -12,6 +13,8 @@ const removeGameFromFavorites = async (
|
||||
const game = await gamesSublevel.get(gameKey);
|
||||
if (!game) return;
|
||||
|
||||
HydraApi.put(`/profile/games/${shop}/${objectId}/unfavorite`).catch(() => {});
|
||||
|
||||
try {
|
||||
await gamesSublevel.put(gameKey, {
|
||||
...game,
|
||||
|
||||
32
src/main/events/library/sync-game-by-object-id.ts
Normal file
32
src/main/events/library/sync-game-by-object-id.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { gamesSublevel, levelKeys } from "@main/level";
|
||||
import { HydraApi } from "@main/services";
|
||||
import type { GameShop, UserGameDetails } from "@types";
|
||||
|
||||
const syncGameByObjectId = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
shop: GameShop,
|
||||
objectId: string
|
||||
) => {
|
||||
return HydraApi.get<UserGameDetails>(
|
||||
`/profile/games/${shop}/${objectId}`
|
||||
).then(async (res) => {
|
||||
const { id, playTimeInSeconds, isFavorite, ...rest } = res;
|
||||
|
||||
const gameKey = levelKeys.game(shop, objectId);
|
||||
|
||||
const currentData = await gamesSublevel.get(gameKey);
|
||||
|
||||
await gamesSublevel.put(gameKey, {
|
||||
...currentData,
|
||||
...rest,
|
||||
remoteId: id,
|
||||
playTimeInMilliseconds: playTimeInSeconds * 1000,
|
||||
favorite: isFavorite ?? currentData?.favorite,
|
||||
});
|
||||
|
||||
return res;
|
||||
});
|
||||
};
|
||||
|
||||
registerEvent("syncGameByObjectId", syncGameByObjectId);
|
||||
@@ -1,5 +1,6 @@
|
||||
import { themesSublevel } from "@main/level";
|
||||
import { registerEvent } from "../register-event";
|
||||
import { WindowManager } from "@main/services";
|
||||
|
||||
const toggleCustomTheme = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
@@ -17,6 +18,8 @@ const toggleCustomTheme = async (
|
||||
isActive,
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
WindowManager.notificationWindow?.webContents.send("on-custom-theme-updated");
|
||||
};
|
||||
|
||||
registerEvent("toggleCustomTheme", toggleCustomTheme);
|
||||
|
||||
@@ -20,8 +20,10 @@ const updateCustomTheme = async (
|
||||
});
|
||||
|
||||
if (theme.isActive) {
|
||||
WindowManager.mainWindow?.webContents.send("css-injected", code);
|
||||
WindowManager.notificationWindow?.webContents.send("css-injected", code);
|
||||
WindowManager.mainWindow?.webContents.send("on-custom-theme-updated");
|
||||
WindowManager.notificationWindow?.webContents.send(
|
||||
"on-custom-theme-updated"
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -4,7 +4,12 @@ import i18n from "i18next";
|
||||
import path from "node:path";
|
||||
import url from "node:url";
|
||||
import { electronApp, optimizer } from "@electron-toolkit/utils";
|
||||
import { logger, WindowManager } from "@main/services";
|
||||
import {
|
||||
logger,
|
||||
clearGamesPlaytime,
|
||||
WindowManager,
|
||||
Lock,
|
||||
} from "@main/services";
|
||||
import resources from "@locales";
|
||||
import { PythonRPC } from "./services/python-rpc";
|
||||
import { db, levelKeys } from "./level";
|
||||
@@ -143,9 +148,19 @@ app.on("window-all-closed", () => {
|
||||
WindowManager.mainWindow = null;
|
||||
});
|
||||
|
||||
app.on("before-quit", () => {
|
||||
/* Disconnects libtorrent */
|
||||
PythonRPC.kill();
|
||||
let canAppBeClosed = false;
|
||||
|
||||
app.on("before-quit", async (e) => {
|
||||
await Lock.releaseLock();
|
||||
|
||||
if (!canAppBeClosed) {
|
||||
e.preventDefault();
|
||||
/* Disconnects libtorrent */
|
||||
PythonRPC.kill();
|
||||
await clearGamesPlaytime();
|
||||
canAppBeClosed = true;
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
|
||||
app.on("activate", () => {
|
||||
|
||||
@@ -15,9 +15,12 @@ import {
|
||||
uploadGamesBatch,
|
||||
startMainLoop,
|
||||
Ludusavi,
|
||||
Lock,
|
||||
} from "@main/services";
|
||||
|
||||
export const loadState = async () => {
|
||||
await Lock.acquireLock();
|
||||
|
||||
const userPreferences = await db.get<string, UserPreferences | null>(
|
||||
levelKeys.userPreferences,
|
||||
{
|
||||
@@ -40,6 +43,7 @@ export const loadState = async () => {
|
||||
}
|
||||
|
||||
Ludusavi.copyConfigFileToUserData();
|
||||
Ludusavi.copyBinaryToUserData();
|
||||
|
||||
await HydraApi.setupApi().then(() => {
|
||||
uploadGamesBatch();
|
||||
|
||||
@@ -31,6 +31,8 @@ export interface ProcessPayload {
|
||||
exe: string | null;
|
||||
pid: number;
|
||||
name: string;
|
||||
environ: Record<string, string> | null;
|
||||
cwd: string | null;
|
||||
}
|
||||
|
||||
export interface PauseSeedingPayload {
|
||||
|
||||
@@ -16,3 +16,4 @@ export * from "./ws";
|
||||
export * from "./system-path";
|
||||
export * from "./library-sync";
|
||||
export * from "./wine";
|
||||
export * from "./lock";
|
||||
|
||||
@@ -6,6 +6,7 @@ type ProfileGame = {
|
||||
id: string;
|
||||
lastTimePlayed: Date | null;
|
||||
playTimeInMilliseconds: number;
|
||||
isFavorite?: boolean;
|
||||
} & ShopAssets;
|
||||
|
||||
export const mergeWithRemoteGames = async () => {
|
||||
@@ -34,6 +35,7 @@ export const mergeWithRemoteGames = async () => {
|
||||
remoteId: game.id,
|
||||
lastTimePlayed: updatedLastTimePlayed,
|
||||
playTimeInMilliseconds: updatedPlayTime,
|
||||
favorite: game.isFavorite ?? localGame.favorite,
|
||||
});
|
||||
} else {
|
||||
await gamesSublevel.put(levelKeys.game(game.shop, game.objectId), {
|
||||
@@ -45,6 +47,7 @@ export const mergeWithRemoteGames = async () => {
|
||||
lastTimePlayed: game.lastTimePlayed,
|
||||
playTimeInMilliseconds: game.playTimeInMilliseconds,
|
||||
isDeleted: false,
|
||||
favorite: game.isFavorite ?? false,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ export const uploadGamesBatch = async () => {
|
||||
playTimeInMilliseconds: Math.trunc(game.playTimeInMilliseconds),
|
||||
shop: game.shop,
|
||||
lastTimePlayed: game.lastTimePlayed,
|
||||
isFavorite: game.favorite,
|
||||
};
|
||||
})
|
||||
).catch(() => {});
|
||||
|
||||
39
src/main/services/lock.ts
Normal file
39
src/main/services/lock.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import path from "node:path";
|
||||
import fs from "node:fs";
|
||||
import { SystemPath } from "./system-path";
|
||||
import { logger } from "./logger";
|
||||
|
||||
export class Lock {
|
||||
private static lockFilePath = path.join(
|
||||
SystemPath.getPath("temp"),
|
||||
"hydra-launcher.lock"
|
||||
);
|
||||
|
||||
public static async acquireLock() {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
fs.writeFile(this.lockFilePath, "", (err) => {
|
||||
if (err) {
|
||||
logger.error("Error acquiring the lock", err);
|
||||
reject(err);
|
||||
}
|
||||
|
||||
logger.info("Acquired the lock");
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static async releaseLock() {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
fs.unlink(this.lockFilePath, (err) => {
|
||||
if (err) {
|
||||
logger.error("Error releasing the lock", err);
|
||||
reject(err);
|
||||
}
|
||||
|
||||
logger.info("Released the lock");
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -8,19 +8,22 @@ import cp from "node:child_process";
|
||||
import { SystemPath } from "./system-path";
|
||||
|
||||
export class Ludusavi {
|
||||
private static ludusaviPath = app.isPackaged
|
||||
private static ludusaviResourcesPath = app.isPackaged
|
||||
? path.join(process.resourcesPath, "ludusavi")
|
||||
: path.join(__dirname, "..", "..", "ludusavi");
|
||||
|
||||
private static binaryPath = path.join(this.ludusaviPath, "ludusavi");
|
||||
private static configPath = path.join(
|
||||
SystemPath.getPath("userData"),
|
||||
"ludusavi"
|
||||
);
|
||||
private static binaryName =
|
||||
process.platform === "win32" ? "ludusavi.exe" : "ludusavi";
|
||||
|
||||
private static binaryPath = path.join(this.configPath, this.binaryName);
|
||||
|
||||
public static async getConfig() {
|
||||
const config = YAML.parse(
|
||||
fs.readFileSync(path.join(this.ludusaviPath, "config.yaml"), "utf-8")
|
||||
fs.readFileSync(path.join(this.configPath, "config.yaml"), "utf-8")
|
||||
) as LudusaviConfig;
|
||||
|
||||
return config;
|
||||
@@ -29,13 +32,23 @@ export class Ludusavi {
|
||||
public static async copyConfigFileToUserData() {
|
||||
if (!fs.existsSync(this.configPath)) {
|
||||
fs.mkdirSync(this.configPath, { recursive: true });
|
||||
|
||||
fs.cpSync(
|
||||
path.join(this.ludusaviPath, "config.yaml"),
|
||||
path.join(this.ludusaviResourcesPath, "config.yaml"),
|
||||
path.join(this.configPath, "config.yaml")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static async copyBinaryToUserData() {
|
||||
if (!fs.existsSync(this.binaryPath)) {
|
||||
fs.cpSync(
|
||||
path.join(this.ludusaviResourcesPath, this.binaryName),
|
||||
this.binaryPath
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static async backupGame(
|
||||
_shop: GameShop,
|
||||
objectId: string,
|
||||
|
||||
@@ -3,15 +3,11 @@ import { createGame, updateGamePlaytime } from "./library-sync";
|
||||
import type { Game, GameRunning } from "@types";
|
||||
import { PythonRPC } from "./python-rpc";
|
||||
import axios from "axios";
|
||||
import { exec } from "child_process";
|
||||
import { ProcessPayload } from "./download/types";
|
||||
import { gamesSublevel, levelKeys } from "@main/level";
|
||||
import { CloudSync } from "./cloud-sync";
|
||||
|
||||
const commands = {
|
||||
findWineDir: `lsof -c wine 2>/dev/null | grep '/drive_c/windows$' | head -n 1 | awk '{for(i=9;i<=NF;i++) printf "%s ", $i; print ""}'`,
|
||||
findWineExecutables: `lsof -c wine 2>/dev/null | grep '\\.exe$' | awk '{for(i=9;i<=NF;i++) printf "%s ", $i; print ""}'`,
|
||||
};
|
||||
import { logger } from "./logger";
|
||||
import path from "path";
|
||||
|
||||
export const gamesPlaytime = new Map<
|
||||
string,
|
||||
@@ -28,11 +24,10 @@ interface GameExecutables {
|
||||
[key: string]: ExecutableInfo[];
|
||||
}
|
||||
|
||||
const TICKS_TO_UPDATE_API = 120;
|
||||
const TICKS_TO_UPDATE_API = 80;
|
||||
let currentTick = 1;
|
||||
|
||||
const isWindowsPlatform = process.platform === "win32";
|
||||
const isLinuxPlatform = process.platform === "linux";
|
||||
const platform = process.platform;
|
||||
|
||||
const getGameExecutables = async () => {
|
||||
const gameExecutables = (
|
||||
@@ -49,18 +44,20 @@ const getGameExecutables = async () => {
|
||||
Object.keys(gameExecutables).forEach((key) => {
|
||||
gameExecutables[key] = gameExecutables[key]
|
||||
.filter((executable) => {
|
||||
if (isWindowsPlatform) {
|
||||
if (platform === "win32") {
|
||||
return executable.os === "win32";
|
||||
} else if (isLinuxPlatform) {
|
||||
} else if (platform === "linux") {
|
||||
return executable.os === "linux" || executable.os === "win32";
|
||||
}
|
||||
|
||||
return false;
|
||||
})
|
||||
.map((executable) => {
|
||||
return {
|
||||
name: isWindowsPlatform
|
||||
? executable.name.replace(/\//g, "\\")
|
||||
: executable.name,
|
||||
name:
|
||||
platform === "win32"
|
||||
? executable.name.replace(/\//g, "\\")
|
||||
: executable.name,
|
||||
os: executable.os,
|
||||
exe: executable.name.slice(executable.name.lastIndexOf("/") + 1),
|
||||
};
|
||||
@@ -72,8 +69,9 @@ const getGameExecutables = async () => {
|
||||
|
||||
const gameExecutables = await getGameExecutables();
|
||||
|
||||
const findGamePathByProcess = (
|
||||
const findGamePathByProcess = async (
|
||||
processMap: Map<string, Set<string>>,
|
||||
winePrefixMap: Map<string, string>,
|
||||
gameId: string
|
||||
) => {
|
||||
const executables = gameExecutables[gameId];
|
||||
@@ -82,32 +80,26 @@ const findGamePathByProcess = (
|
||||
const pathSet = processMap.get(executable.exe);
|
||||
|
||||
if (pathSet) {
|
||||
pathSet.forEach(async (path) => {
|
||||
for (const path of pathSet) {
|
||||
if (path.toLowerCase().endsWith(executable.name)) {
|
||||
const gameKey = levelKeys.game("steam", gameId);
|
||||
const game = await gamesSublevel.get(gameKey);
|
||||
|
||||
if (game) {
|
||||
gamesSublevel.put(gameKey, {
|
||||
const updatedGame: Game = {
|
||||
...game,
|
||||
executablePath: path,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (isLinuxPlatform) {
|
||||
exec(commands.findWineDir, (err, out) => {
|
||||
if (err) return;
|
||||
if (process.platform === "linux" && winePrefixMap.has(path)) {
|
||||
updatedGame.winePrefixPath = winePrefixMap.get(path)!;
|
||||
}
|
||||
|
||||
if (game) {
|
||||
gamesSublevel.put(gameKey, {
|
||||
...game,
|
||||
winePrefixPath: out.trim().replace("/drive_c/windows", ""),
|
||||
});
|
||||
}
|
||||
});
|
||||
await gamesSublevel.put(gameKey, updatedGame);
|
||||
logger.info("Set game path", gameKey, path);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -117,50 +109,29 @@ const getSystemProcessMap = async () => {
|
||||
(await PythonRPC.rpc.get<ProcessPayload[] | null>("/process-list")).data ||
|
||||
[];
|
||||
|
||||
const map = new Map<string, Set<string>>();
|
||||
const processMap = new Map<string, Set<string>>();
|
||||
const winePrefixMap = new Map<string, string>();
|
||||
|
||||
processes.forEach((process) => {
|
||||
const key = process.name?.toLowerCase();
|
||||
const value = process.exe;
|
||||
const value =
|
||||
platform === "win32"
|
||||
? process.exe
|
||||
: path.join(process.cwd ?? "", process.name ?? "");
|
||||
|
||||
if (!key || !value) return;
|
||||
|
||||
const currentSet = map.get(key) ?? new Set();
|
||||
map.set(key, currentSet.add(value));
|
||||
const STEAM_COMPAT_DATA_PATH = process.environ?.STEAM_COMPAT_DATA_PATH;
|
||||
|
||||
if (STEAM_COMPAT_DATA_PATH) {
|
||||
winePrefixMap.set(value, STEAM_COMPAT_DATA_PATH);
|
||||
}
|
||||
|
||||
const currentSet = processMap.get(key) ?? new Set();
|
||||
processMap.set(key, currentSet.add(value));
|
||||
});
|
||||
|
||||
if (isLinuxPlatform) {
|
||||
await new Promise((res) => {
|
||||
exec(commands.findWineExecutables, (err, out) => {
|
||||
if (err) {
|
||||
res(null);
|
||||
return;
|
||||
}
|
||||
|
||||
const pathSet = new Set(
|
||||
out
|
||||
.trim()
|
||||
.split("\n")
|
||||
.map((path) => path.trim())
|
||||
);
|
||||
|
||||
pathSet.forEach((path) => {
|
||||
if (path.startsWith("/usr")) return;
|
||||
|
||||
const key = path.slice(path.lastIndexOf("/") + 1).toLowerCase();
|
||||
|
||||
if (!key || !path) return;
|
||||
|
||||
const currentSet = map.get(key) ?? new Set();
|
||||
map.set(key, currentSet.add(path));
|
||||
});
|
||||
|
||||
res(null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return map;
|
||||
return { processMap, winePrefixMap };
|
||||
};
|
||||
|
||||
export const watchProcesses = async () => {
|
||||
@@ -173,19 +144,20 @@ export const watchProcesses = async () => {
|
||||
|
||||
if (!games.length) return;
|
||||
|
||||
const processMap = await getSystemProcessMap();
|
||||
const { processMap, winePrefixMap } = await getSystemProcessMap();
|
||||
|
||||
for (const game of games) {
|
||||
const executablePath = game.executablePath;
|
||||
if (!executablePath) {
|
||||
if (gameExecutables[game.objectId]) {
|
||||
findGamePathByProcess(processMap, game.objectId);
|
||||
await findGamePathByProcess(processMap, winePrefixMap, game.objectId);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
const executable = executablePath
|
||||
.slice(executablePath.lastIndexOf(isWindowsPlatform ? "\\" : "/") + 1)
|
||||
.slice(executablePath.lastIndexOf(platform === "win32" ? "\\" : "/") + 1)
|
||||
.toLowerCase();
|
||||
|
||||
const hasProcess = processMap.get(executable)?.has(executablePath);
|
||||
@@ -225,7 +197,18 @@ function onOpenGame(game: Game) {
|
||||
});
|
||||
|
||||
if (game.remoteId) {
|
||||
updateGamePlaytime(game, 0, new Date()).catch(() => {});
|
||||
updateGamePlaytime(
|
||||
game,
|
||||
game.unsyncedDeltaPlayTimeInMilliseconds ?? 0,
|
||||
new Date()
|
||||
)
|
||||
.then(() => {
|
||||
gamesSublevel.put(levelKeys.game(game.shop, game.objectId), {
|
||||
...game,
|
||||
unsyncedDeltaPlayTimeInMilliseconds: 0,
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
|
||||
if (game.automaticCloudSync) {
|
||||
CloudSync.uploadSaveGame(
|
||||
@@ -250,13 +233,7 @@ function onTickGame(game: Game) {
|
||||
|
||||
gamesSublevel.put(levelKeys.game(game.shop, game.objectId), {
|
||||
...game,
|
||||
playTimeInMilliseconds: game.playTimeInMilliseconds + delta,
|
||||
lastTimePlayed: new Date(),
|
||||
});
|
||||
|
||||
gamesSublevel.put(levelKeys.game(game.shop, game.objectId), {
|
||||
...game,
|
||||
playTimeInMilliseconds: game.playTimeInMilliseconds + delta,
|
||||
playTimeInMilliseconds: (game.playTimeInMilliseconds ?? 0) + delta,
|
||||
lastTimePlayed: new Date(),
|
||||
});
|
||||
|
||||
@@ -266,22 +243,34 @@ function onTickGame(game: Game) {
|
||||
});
|
||||
|
||||
if (currentTick % TICKS_TO_UPDATE_API === 0) {
|
||||
const deltaToSync =
|
||||
now -
|
||||
gamePlaytime.lastSyncTick +
|
||||
(game.unsyncedDeltaPlayTimeInMilliseconds ?? 0);
|
||||
|
||||
const gamePromise = game.remoteId
|
||||
? updateGamePlaytime(
|
||||
game,
|
||||
now - gamePlaytime.lastSyncTick,
|
||||
game.lastTimePlayed!
|
||||
)
|
||||
? updateGamePlaytime(game, deltaToSync, game.lastTimePlayed!)
|
||||
: createGame(game);
|
||||
|
||||
gamePromise
|
||||
.then(() => {
|
||||
gamesSublevel.put(levelKeys.game(game.shop, game.objectId), {
|
||||
...game,
|
||||
unsyncedDeltaPlayTimeInMilliseconds: 0,
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
gamesSublevel.put(levelKeys.game(game.shop, game.objectId), {
|
||||
...game,
|
||||
unsyncedDeltaPlayTimeInMilliseconds: deltaToSync,
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
gamesPlaytime.set(levelKeys.game(game.shop, game.objectId), {
|
||||
...gamePlaytime,
|
||||
lastSyncTick: now,
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,12 +281,6 @@ const onCloseGame = (game: Game) => {
|
||||
gamesPlaytime.delete(levelKeys.game(game.shop, game.objectId));
|
||||
|
||||
if (game.remoteId) {
|
||||
updateGamePlaytime(
|
||||
game,
|
||||
performance.now() - gamePlaytime.lastSyncTick,
|
||||
game.lastTimePlayed!
|
||||
).catch(() => {});
|
||||
|
||||
if (game.automaticCloudSync) {
|
||||
CloudSync.uploadSaveGame(
|
||||
game.objectId,
|
||||
@@ -306,7 +289,38 @@ const onCloseGame = (game: Game) => {
|
||||
CloudSync.getBackupLabel(true)
|
||||
);
|
||||
}
|
||||
|
||||
const deltaToSync =
|
||||
performance.now() -
|
||||
gamePlaytime.lastSyncTick +
|
||||
(game.unsyncedDeltaPlayTimeInMilliseconds ?? 0);
|
||||
|
||||
return updateGamePlaytime(game, deltaToSync, game.lastTimePlayed!)
|
||||
.then(() => {
|
||||
return gamesSublevel.put(levelKeys.game(game.shop, game.objectId), {
|
||||
...game,
|
||||
unsyncedDeltaPlayTimeInMilliseconds: 0,
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
return gamesSublevel.put(levelKeys.game(game.shop, game.objectId), {
|
||||
...game,
|
||||
unsyncedDeltaPlayTimeInMilliseconds: deltaToSync,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
createGame(game).catch(() => {});
|
||||
return createGame(game).catch(() => {});
|
||||
}
|
||||
};
|
||||
|
||||
export const clearGamesPlaytime = async () => {
|
||||
for (const game of gamesPlaytime.keys()) {
|
||||
const gameData = await gamesSublevel.get(game);
|
||||
|
||||
if (gameData) {
|
||||
await onCloseGame(gameData);
|
||||
}
|
||||
}
|
||||
|
||||
gamesPlaytime.clear();
|
||||
};
|
||||
|
||||
@@ -17,18 +17,30 @@ export interface SteamAppDetailsResponse {
|
||||
};
|
||||
}
|
||||
|
||||
export const getSteamLocation = async () => {
|
||||
export const getSteamLocation = async (): Promise<string> => {
|
||||
const home = SystemPath.getPath("home");
|
||||
|
||||
if (process.platform === "linux") {
|
||||
return path.join(SystemPath.getPath("home"), ".local", "share", "Steam");
|
||||
const candidates = [
|
||||
path.join(home, ".local", "share", "Steam"),
|
||||
path.join(home, ".steam", "steam"),
|
||||
path.join(home, ".steam", "root"),
|
||||
];
|
||||
|
||||
for (const candidate of candidates) {
|
||||
try {
|
||||
fs.accessSync(candidate, fs.constants.F_OK);
|
||||
return candidate;
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error("Steam installation not found on Linux");
|
||||
}
|
||||
|
||||
if (process.platform === "darwin") {
|
||||
return path.join(
|
||||
SystemPath.getPath("home"),
|
||||
"Library",
|
||||
"Application Support",
|
||||
"Steam"
|
||||
);
|
||||
return path.join(home, "Library", "Application Support", "Steam");
|
||||
}
|
||||
|
||||
const regKey = new WinReg({
|
||||
@@ -39,7 +51,7 @@ export const getSteamLocation = async () => {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
regKey.get("SteamPath", (err, value) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
resolve(value.value);
|
||||
|
||||
@@ -289,6 +289,13 @@ export class WindowManager {
|
||||
const display = screen.getPrimaryDisplay();
|
||||
const { width, height } = display.workAreaSize;
|
||||
|
||||
if (position === "bottom-left") {
|
||||
return {
|
||||
x: 0,
|
||||
y: height - this.NOTIFICATION_WINDOW_HEIGHT,
|
||||
};
|
||||
}
|
||||
|
||||
if (position === "bottom-center") {
|
||||
return {
|
||||
x: (width - this.NOTIFICATION_WINDOW_WIDTH) / 2,
|
||||
@@ -310,13 +317,6 @@ export class WindowManager {
|
||||
};
|
||||
}
|
||||
|
||||
if (position === "bottom-left") {
|
||||
return {
|
||||
x: 0,
|
||||
y: height - this.NOTIFICATION_WINDOW_HEIGHT,
|
||||
};
|
||||
}
|
||||
|
||||
if (position === "top-right") {
|
||||
return {
|
||||
x: width - this.NOTIFICATION_WINDOW_WIDTH,
|
||||
@@ -356,6 +356,7 @@ export class WindowManager {
|
||||
maximizable: false,
|
||||
autoHideMenuBar: true,
|
||||
minimizable: false,
|
||||
backgroundColor: "#00000000",
|
||||
focusable: false,
|
||||
skipTaskbar: true,
|
||||
frame: false,
|
||||
@@ -372,8 +373,13 @@ export class WindowManager {
|
||||
// this.notificationWindow.setVisibleOnAllWorkspaces(true, {
|
||||
// visibleOnFullScreen: true,
|
||||
// });
|
||||
|
||||
this.notificationWindow.setAlwaysOnTop(true, "screen-saver", 1);
|
||||
this.loadNotificationWindowURL();
|
||||
|
||||
if (isStaging) {
|
||||
this.notificationWindow.webContents.openDevTools();
|
||||
}
|
||||
}
|
||||
|
||||
public static async showAchievementTestNotification() {
|
||||
@@ -389,7 +395,16 @@ export class WindowManager {
|
||||
this.notificationWindow?.webContents.send(
|
||||
"on-achievement-unlocked",
|
||||
userPreferences.achievementCustomNotificationPosition ?? "top-left",
|
||||
[generateAchievementCustomNotificationTest(t, language)]
|
||||
[
|
||||
generateAchievementCustomNotificationTest(t, language),
|
||||
generateAchievementCustomNotificationTest(t, language, {
|
||||
isRare: true,
|
||||
isHidden: true,
|
||||
}),
|
||||
generateAchievementCustomNotificationTest(t, language, {
|
||||
isPlatinum: true,
|
||||
}),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -454,9 +469,8 @@ export class WindowManager {
|
||||
}
|
||||
});
|
||||
|
||||
editorWindow.webContents.on("before-input-event", (event, input) => {
|
||||
editorWindow.webContents.on("before-input-event", (_event, input) => {
|
||||
if (input.key === "F12") {
|
||||
event.preventDefault();
|
||||
this.mainWindow?.webContents.toggleDevTools();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,15 +1,25 @@
|
||||
import type { FriendGameSession } from "@main/generated/envelope";
|
||||
import { db, levelKeys } from "@main/level";
|
||||
import { HydraApi } from "@main/services/hydra-api";
|
||||
import { publishFriendStartedPlayingGameNotification } from "@main/services/notifications";
|
||||
import { GameStats } from "@types";
|
||||
import type { GameStats, UserPreferences, UserProfile } from "@types";
|
||||
|
||||
export const friendGameSessionEvent = async (payload: FriendGameSession) => {
|
||||
const userPreferences = await db.get<string, UserPreferences | null>(
|
||||
levelKeys.userPreferences,
|
||||
{
|
||||
valueEncoding: "json",
|
||||
}
|
||||
);
|
||||
|
||||
if (userPreferences?.friendStartGameNotificationsEnabled === false) return;
|
||||
|
||||
const [friend, gameStats] = await Promise.all([
|
||||
HydraApi.get(`/users/${payload.friendId}`),
|
||||
HydraApi.get<UserProfile>(`/users/${payload.friendId}`),
|
||||
HydraApi.get<GameStats>(
|
||||
`/games/stats?objectId=${payload.objectId}&shop=steam`
|
||||
),
|
||||
]);
|
||||
]).catch(() => [null, null]);
|
||||
|
||||
if (friend && gameStats) {
|
||||
publishFriendStartedPlayingGameNotification(friend, gameStats);
|
||||
|
||||
@@ -34,6 +34,10 @@ export class WSClient {
|
||||
});
|
||||
|
||||
this.ws.on("message", (message) => {
|
||||
if (message.toString() === "PONG") {
|
||||
return;
|
||||
}
|
||||
|
||||
const envelope = Envelope.fromBinary(
|
||||
new Uint8Array(Buffer.from(message.toString()))
|
||||
);
|
||||
@@ -112,7 +116,7 @@ export class WSClient {
|
||||
private static startHeartbeat() {
|
||||
this.heartbeatInterval = setInterval(() => {
|
||||
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
||||
this.ws.ping();
|
||||
this.ws.send("PING");
|
||||
}
|
||||
}, 15_000);
|
||||
}
|
||||
|
||||
@@ -187,6 +187,8 @@ contextBridge.exposeInMainWorld("electron", {
|
||||
ipcRenderer.invoke("deleteGameFolder", shop, objectId),
|
||||
getGameByObjectId: (shop: GameShop, objectId: string) =>
|
||||
ipcRenderer.invoke("getGameByObjectId", shop, objectId),
|
||||
syncGameByObjectId: (shop: GameShop, objectId: string) =>
|
||||
ipcRenderer.invoke("syncGameByObjectId", shop, objectId),
|
||||
resetGameAchievements: (shop: GameShop, objectId: string) =>
|
||||
ipcRenderer.invoke("resetGameAchievements", shop, objectId),
|
||||
extractGameDownload: (shop: GameShop, objectId: string) =>
|
||||
@@ -234,6 +236,10 @@ contextBridge.exposeInMainWorld("electron", {
|
||||
downloadOptionTitle: string | null
|
||||
) =>
|
||||
ipcRenderer.invoke("uploadSaveGame", objectId, shop, downloadOptionTitle),
|
||||
toggleArtifactFreeze: (gameArtifactId: string, freeze: boolean) =>
|
||||
ipcRenderer.invoke("toggleArtifactFreeze", gameArtifactId, freeze),
|
||||
renameGameArtifact: (gameArtifactId: string, label: string) =>
|
||||
ipcRenderer.invoke("renameGameArtifact", gameArtifactId, label),
|
||||
downloadGameArtifact: (
|
||||
objectId: string,
|
||||
shop: GameShop,
|
||||
@@ -462,11 +468,11 @@ contextBridge.exposeInMainWorld("electron", {
|
||||
/* Editor */
|
||||
openEditorWindow: (themeId: string) =>
|
||||
ipcRenderer.invoke("openEditorWindow", themeId),
|
||||
onCssInjected: (cb: (cssString: string) => void) => {
|
||||
const listener = (_event: Electron.IpcRendererEvent, cssString: string) =>
|
||||
cb(cssString);
|
||||
ipcRenderer.on("css-injected", listener);
|
||||
return () => ipcRenderer.removeListener("css-injected", listener);
|
||||
onCustomThemeUpdated: (cb: () => void) => {
|
||||
const listener = (_event: Electron.IpcRendererEvent) => cb();
|
||||
ipcRenderer.on("on-custom-theme-updated", listener);
|
||||
return () =>
|
||||
ipcRenderer.removeListener("on-custom-theme-updated", listener);
|
||||
},
|
||||
closeEditorWindow: (themeId?: string) =>
|
||||
ipcRenderer.invoke("closeEditorWindow", themeId),
|
||||
|
||||
@@ -28,7 +28,7 @@ import { downloadSourcesTable } from "./dexie";
|
||||
import { useSubscription } from "./hooks/use-subscription";
|
||||
import { HydraCloudModal } from "./pages/shared-modals/hydra-cloud/hydra-cloud-modal";
|
||||
|
||||
import { injectCustomCss } from "./helpers";
|
||||
import { injectCustomCss, removeCustomCss } from "./helpers";
|
||||
import "./app.scss";
|
||||
|
||||
export interface AppProps {
|
||||
@@ -246,17 +246,27 @@ export function App() {
|
||||
};
|
||||
}, [updateRepacks]);
|
||||
|
||||
useEffect(() => {
|
||||
const loadAndApplyTheme = async () => {
|
||||
const activeTheme = await window.electron.getActiveCustomTheme();
|
||||
|
||||
if (activeTheme?.code) {
|
||||
injectCustomCss(activeTheme.code);
|
||||
}
|
||||
};
|
||||
loadAndApplyTheme();
|
||||
const loadAndApplyTheme = useCallback(async () => {
|
||||
const activeTheme = await window.electron.getActiveCustomTheme();
|
||||
if (activeTheme?.code) {
|
||||
injectCustomCss(activeTheme.code);
|
||||
} else {
|
||||
removeCustomCss();
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
loadAndApplyTheme();
|
||||
}, [loadAndApplyTheme]);
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribe = window.electron.onCustomThemeUpdated(() => {
|
||||
loadAndApplyTheme();
|
||||
});
|
||||
|
||||
return () => unsubscribe();
|
||||
}, [loadAndApplyTheme]);
|
||||
|
||||
const playAudio = useCallback(() => {
|
||||
const audio = new Audio(achievementSound);
|
||||
audio.volume = 0.2;
|
||||
@@ -273,14 +283,6 @@ export function App() {
|
||||
};
|
||||
}, [playAudio]);
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribe = window.electron.onCssInjected((cssString) => {
|
||||
injectCustomCss(cssString);
|
||||
});
|
||||
|
||||
return () => unsubscribe();
|
||||
}, []);
|
||||
|
||||
const handleToastClose = useCallback(() => {
|
||||
dispatch(closeToast());
|
||||
}, [dispatch]);
|
||||
|
||||
@@ -141,7 +141,7 @@ $margin-bottom: 28px;
|
||||
|
||||
.achievement-notification {
|
||||
width: 360px;
|
||||
height: 192px;
|
||||
height: 140px;
|
||||
display: flex;
|
||||
|
||||
&--top-left {
|
||||
|
||||
@@ -3,10 +3,10 @@ import {
|
||||
AchievementNotificationInfo,
|
||||
} from "@types";
|
||||
import cn from "classnames";
|
||||
import "./achievement-notification.scss";
|
||||
import HydraIcon from "@renderer/assets/icons/hydra.svg?react";
|
||||
import { EyeClosedIcon } from "@primer/octicons-react";
|
||||
import Ellipses from "@renderer/assets/icons/ellipses.png";
|
||||
import "./achievement-notification.scss";
|
||||
|
||||
interface AchievementNotificationProps {
|
||||
position: AchievementCustomNotificationPosition;
|
||||
@@ -31,7 +31,7 @@ export function AchievementNotificationItem({
|
||||
[`${baseClassName}--platinum`]: achievement.isPlatinum,
|
||||
})}
|
||||
>
|
||||
{achievement.points && (
|
||||
{achievement.points !== undefined && (
|
||||
<div className="achievement-notification__chip">
|
||||
<HydraIcon className="achievement-notification__chip__icon" />
|
||||
<span className="achievement-notification__chip__label">
|
||||
|
||||
@@ -98,6 +98,12 @@
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
&__section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__section-title {
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
@@ -133,7 +139,11 @@
|
||||
}
|
||||
|
||||
&__help-button-icon {
|
||||
background: linear-gradient(0deg, #16b195 50%, #3e62c0 100%);
|
||||
background: linear-gradient(
|
||||
0deg,
|
||||
globals.$brand-teal 50%,
|
||||
globals.$brand-blue 100%
|
||||
);
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
@@ -142,4 +152,24 @@
|
||||
color: #fff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
&__play-button {
|
||||
background: none;
|
||||
border: none;
|
||||
color: globals.$muted-color;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
|
||||
&:active {
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
&--active {
|
||||
color: globals.$brand-teal;
|
||||
}
|
||||
|
||||
svg {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import { buildGameDetailsPath } from "@renderer/helpers";
|
||||
import { SidebarProfile } from "./sidebar-profile";
|
||||
import { sortBy } from "lodash-es";
|
||||
import cn from "classnames";
|
||||
import { CommentDiscussionIcon } from "@primer/octicons-react";
|
||||
import { CommentDiscussionIcon, PlayIcon } from "@primer/octicons-react";
|
||||
import { SidebarGameItem } from "./sidebar-game-item";
|
||||
import { setFriendRequestCount } from "@renderer/features/user-details-slice";
|
||||
import { useDispatch } from "react-redux";
|
||||
@@ -32,6 +32,8 @@ const SIDEBAR_MAX_WIDTH = 450;
|
||||
|
||||
const initialSidebarWidth = window.localStorage.getItem("sidebarWidth");
|
||||
|
||||
const isGamePlayable = (game: LibraryGame) => Boolean(game.executablePath);
|
||||
|
||||
export function Sidebar() {
|
||||
const filterRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
@@ -60,6 +62,12 @@ export function Sidebar() {
|
||||
|
||||
const { showWarningToast } = useToast();
|
||||
|
||||
const [showPlayableOnly, setShowPlayableOnly] = useState(false);
|
||||
|
||||
const handlePlayButtonClick = () => {
|
||||
setShowPlayableOnly(!showPlayableOnly);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
updateLibrary();
|
||||
}, [lastPacket?.gameId, updateLibrary]);
|
||||
@@ -242,7 +250,20 @@ export function Sidebar() {
|
||||
)}
|
||||
|
||||
<section className="sidebar__section">
|
||||
<small className="sidebar__section-title">{t("my_library")}</small>
|
||||
<div className="sidebar__section-header">
|
||||
<small className="sidebar__section-title">
|
||||
{t("my_library")}
|
||||
</small>
|
||||
<button
|
||||
type="button"
|
||||
className={cn("sidebar__play-button", {
|
||||
"sidebar__play-button--active": showPlayableOnly,
|
||||
})}
|
||||
onClick={handlePlayButtonClick}
|
||||
>
|
||||
<PlayIcon size={16} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<TextField
|
||||
ref={filterRef}
|
||||
@@ -254,6 +275,7 @@ export function Sidebar() {
|
||||
<ul className="sidebar__menu">
|
||||
{filteredLibrary
|
||||
.filter((game) => !game.favorite)
|
||||
.filter((game) => !showPlayableOnly || isGamePlayable(game))
|
||||
.map((game) => (
|
||||
<SidebarGameItem
|
||||
key={game.id}
|
||||
|
||||
@@ -30,9 +30,14 @@ export interface CloudSyncContext {
|
||||
setShowCloudSyncFilesModal: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
getGameBackupPreview: () => Promise<void>;
|
||||
getGameArtifacts: () => Promise<void>;
|
||||
toggleArtifactFreeze: (
|
||||
gameArtifactId: string,
|
||||
freeze: boolean
|
||||
) => Promise<void>;
|
||||
restoringBackup: boolean;
|
||||
uploadingBackup: boolean;
|
||||
loadingPreview: boolean;
|
||||
freezingArtifact: boolean;
|
||||
}
|
||||
|
||||
export const cloudSyncContext = createContext<CloudSyncContext>({
|
||||
@@ -47,10 +52,12 @@ export const cloudSyncContext = createContext<CloudSyncContext>({
|
||||
showCloudSyncFilesModal: false,
|
||||
setShowCloudSyncFilesModal: () => {},
|
||||
getGameBackupPreview: async () => {},
|
||||
toggleArtifactFreeze: async () => {},
|
||||
getGameArtifacts: async () => {},
|
||||
restoringBackup: false,
|
||||
uploadingBackup: false,
|
||||
loadingPreview: false,
|
||||
freezingArtifact: false,
|
||||
});
|
||||
|
||||
const { Provider } = cloudSyncContext;
|
||||
@@ -78,6 +85,7 @@ export function CloudSyncContextProvider({
|
||||
const [uploadingBackup, setUploadingBackup] = useState(false);
|
||||
const [showCloudSyncFilesModal, setShowCloudSyncFilesModal] = useState(false);
|
||||
const [loadingPreview, setLoadingPreview] = useState(false);
|
||||
const [freezingArtifact, setFreezingArtifact] = useState(false);
|
||||
|
||||
const { showSuccessToast } = useToast();
|
||||
|
||||
@@ -119,6 +127,22 @@ export function CloudSyncContextProvider({
|
||||
[objectId, shop]
|
||||
);
|
||||
|
||||
const toggleArtifactFreeze = useCallback(
|
||||
async (gameArtifactId: string, freeze: boolean) => {
|
||||
setFreezingArtifact(true);
|
||||
try {
|
||||
await window.electron.toggleArtifactFreeze(gameArtifactId, freeze);
|
||||
getGameArtifacts();
|
||||
} catch (err) {
|
||||
logger.error("Failed to toggle artifact freeze", objectId, shop, err);
|
||||
throw err;
|
||||
} finally {
|
||||
setFreezingArtifact(false);
|
||||
}
|
||||
},
|
||||
[objectId, shop, getGameArtifacts]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const removeUploadCompleteListener = window.electron.onUploadComplete(
|
||||
objectId,
|
||||
@@ -192,6 +216,7 @@ export function CloudSyncContextProvider({
|
||||
uploadingBackup,
|
||||
showCloudSyncFilesModal,
|
||||
loadingPreview,
|
||||
freezingArtifact,
|
||||
setShowCloudSyncModal,
|
||||
uploadSaveGame,
|
||||
downloadGameArtifact,
|
||||
@@ -199,6 +224,7 @@ export function CloudSyncContextProvider({
|
||||
setShowCloudSyncFilesModal,
|
||||
getGameBackupPreview,
|
||||
getGameArtifacts,
|
||||
toggleArtifactFreeze,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -108,7 +108,7 @@ export function GameDetailsContextProvider({
|
||||
return window.electron
|
||||
.getGameByObjectId(shop, objectId)
|
||||
.then((result) => setGame(result));
|
||||
}, [setGame, shop, objectId]);
|
||||
}, [shop, objectId]);
|
||||
|
||||
const isGameDownloading =
|
||||
lastPacket?.gameId === game?.id && game?.download?.status === "active";
|
||||
@@ -183,11 +183,13 @@ export function GameDetailsContextProvider({
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
updateGame();
|
||||
window.electron.syncGameByObjectId(shop, objectId).then(() => {
|
||||
if (abortController.signal.aborted) return;
|
||||
updateGame();
|
||||
});
|
||||
}, [
|
||||
updateGame,
|
||||
dispatch,
|
||||
gameTitle,
|
||||
objectId,
|
||||
shop,
|
||||
i18n.language,
|
||||
|
||||
18
src/renderer/src/declaration.d.ts
vendored
18
src/renderer/src/declaration.d.ts
vendored
@@ -139,10 +139,7 @@ declare global {
|
||||
verifyExecutablePathInUse: (executablePath: string) => Promise<Game>;
|
||||
getLibrary: () => Promise<LibraryGame[]>;
|
||||
openGameInstaller: (shop: GameShop, objectId: string) => Promise<boolean>;
|
||||
openGameInstallerPath: (
|
||||
shop: GameShop,
|
||||
objectId: string
|
||||
) => Promise<boolean>;
|
||||
openGameInstallerPath: (shop: GameShop, objectId: string) => Promise<void>;
|
||||
openGameExecutablePath: (shop: GameShop, objectId: string) => Promise<void>;
|
||||
openGame: (
|
||||
shop: GameShop,
|
||||
@@ -158,6 +155,7 @@ declare global {
|
||||
shop: GameShop,
|
||||
objectId: string
|
||||
) => Promise<LibraryGame | null>;
|
||||
syncGameByObjectId: (shop: GameShop, objectId: string) => Promise<void>;
|
||||
onGamesRunning: (
|
||||
cb: (
|
||||
gamesRunning: Pick<GameRunning, "id" | "sessionDurationInMillis">[]
|
||||
@@ -203,6 +201,14 @@ declare global {
|
||||
shop: GameShop,
|
||||
downloadOptionTitle: string | null
|
||||
) => Promise<void>;
|
||||
toggleArtifactFreeze: (
|
||||
gameArtifactId: string,
|
||||
freeze: boolean
|
||||
) => Promise<void>;
|
||||
renameGameArtifact: (
|
||||
gameArtifactId: string,
|
||||
label: string
|
||||
) => Promise<void>;
|
||||
downloadGameArtifact: (
|
||||
objectId: string,
|
||||
shop: GameShop,
|
||||
@@ -352,9 +358,7 @@ declare global {
|
||||
|
||||
/* Editor */
|
||||
openEditorWindow: (themeId: string) => Promise<void>;
|
||||
onCssInjected: (
|
||||
cb: (cssString: string) => void
|
||||
) => () => Electron.IpcRenderer;
|
||||
onCustomThemeUpdated: (cb: () => void) => () => Electron.IpcRenderer;
|
||||
closeEditorWindow: (themeId?: string) => Promise<void>;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,35 +55,32 @@ export const buildGameAchievementPath = (
|
||||
export const darkenColor = (color: string, amount: number, alpha: number = 1) =>
|
||||
new Color(color).darken(amount).alpha(alpha).toString();
|
||||
|
||||
export const injectCustomCss = (css: string) => {
|
||||
export const injectCustomCss = (
|
||||
css: string,
|
||||
target: HTMLElement = document.head
|
||||
) => {
|
||||
try {
|
||||
const currentCustomCss = document.getElementById("custom-css");
|
||||
if (currentCustomCss) {
|
||||
currentCustomCss.remove();
|
||||
}
|
||||
target.querySelector("#custom-css")?.remove();
|
||||
|
||||
if (css.startsWith(THEME_WEB_STORE_URL)) {
|
||||
const link = document.createElement("link");
|
||||
link.id = "custom-css";
|
||||
link.rel = "stylesheet";
|
||||
link.href = css;
|
||||
document.head.appendChild(link);
|
||||
target.appendChild(link);
|
||||
} else {
|
||||
const style = document.createElement("style");
|
||||
style.id = "custom-css";
|
||||
style.textContent = `
|
||||
${css}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
target.appendChild(style);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("failed to inject custom css:", error);
|
||||
}
|
||||
};
|
||||
|
||||
export const removeCustomCss = () => {
|
||||
const currentCustomCss = document.getElementById("custom-css");
|
||||
if (currentCustomCss) {
|
||||
currentCustomCss.remove();
|
||||
}
|
||||
export const removeCustomCss = (target: HTMLElement = document.head) => {
|
||||
target.querySelector("#custom-css")?.remove();
|
||||
};
|
||||
|
||||
@@ -5,8 +5,11 @@ import {
|
||||
AchievementCustomNotificationPosition,
|
||||
AchievementNotificationInfo,
|
||||
} from "@types";
|
||||
import { injectCustomCss } from "@renderer/helpers";
|
||||
import { injectCustomCss, removeCustomCss } from "@renderer/helpers";
|
||||
import { AchievementNotificationItem } from "@renderer/components/achievements/notification/achievement-notification";
|
||||
import app from "../../../app.scss?inline";
|
||||
import styles from "../../../components/achievements/notification/achievement-notification.scss?inline";
|
||||
import root from "react-shadow";
|
||||
|
||||
const NOTIFICATION_TIMEOUT = 4000;
|
||||
|
||||
@@ -28,6 +31,8 @@ export function AchievementNotification() {
|
||||
const closingAnimation = useRef(-1);
|
||||
const visibleAnimation = useRef(-1);
|
||||
|
||||
const [shadowRootRef, setShadowRootRef] = useState<HTMLElement | null>(null);
|
||||
|
||||
const playAudio = useCallback(() => {
|
||||
const audio = new Audio(achievementSound);
|
||||
audio.volume = 0.1;
|
||||
@@ -132,31 +137,42 @@ export function AchievementNotification() {
|
||||
}
|
||||
}, [achievements]);
|
||||
|
||||
useEffect(() => {
|
||||
const loadAndApplyTheme = async () => {
|
||||
const activeTheme = await window.electron.getActiveCustomTheme();
|
||||
if (activeTheme?.code) {
|
||||
injectCustomCss(activeTheme.code);
|
||||
}
|
||||
};
|
||||
loadAndApplyTheme();
|
||||
}, []);
|
||||
const loadAndApplyTheme = useCallback(async () => {
|
||||
if (!shadowRootRef) return;
|
||||
const activeTheme = await window.electron.getActiveCustomTheme();
|
||||
if (activeTheme?.code) {
|
||||
injectCustomCss(activeTheme.code, shadowRootRef);
|
||||
} else {
|
||||
removeCustomCss(shadowRootRef);
|
||||
}
|
||||
}, [shadowRootRef]);
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribe = window.electron.onCssInjected((cssString) => {
|
||||
injectCustomCss(cssString);
|
||||
loadAndApplyTheme();
|
||||
}, [loadAndApplyTheme]);
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribe = window.electron.onCustomThemeUpdated(() => {
|
||||
loadAndApplyTheme();
|
||||
});
|
||||
|
||||
return () => unsubscribe();
|
||||
}, []);
|
||||
|
||||
if (!isVisible || !currentAchievement) return null;
|
||||
}, [loadAndApplyTheme]);
|
||||
|
||||
return (
|
||||
<AchievementNotificationItem
|
||||
achievement={currentAchievement}
|
||||
isClosing={isClosing}
|
||||
position={position}
|
||||
/>
|
||||
<root.div>
|
||||
<style type="text/css">
|
||||
{app} {styles}
|
||||
</style>
|
||||
<section ref={setShadowRootRef}>
|
||||
{isVisible && currentAchievement && (
|
||||
<AchievementNotificationItem
|
||||
achievement={currentAchievement}
|
||||
isClosing={isClosing}
|
||||
position={position}
|
||||
/>
|
||||
)}
|
||||
</section>
|
||||
</root.div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -77,6 +77,9 @@ export default function Catalogue() {
|
||||
}, 500)
|
||||
).current;
|
||||
|
||||
const decodeHTML = (s: string) =>
|
||||
s.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
||||
|
||||
useEffect(() => {
|
||||
setResults([]);
|
||||
setIsLoading(true);
|
||||
@@ -165,7 +168,7 @@ export default function Catalogue() {
|
||||
})),
|
||||
|
||||
...filters.publishers.map((publisher) => ({
|
||||
label: publisher,
|
||||
label: decodeHTML(publisher),
|
||||
orbColor: filterCategoryColors.publishers,
|
||||
key: "publishers",
|
||||
value: publisher,
|
||||
@@ -208,7 +211,7 @@ export default function Catalogue() {
|
||||
{
|
||||
title: t("publishers"),
|
||||
items: steamPublishers.map((publisher) => ({
|
||||
label: publisher,
|
||||
label: decodeHTML(publisher),
|
||||
value: publisher,
|
||||
checked: filters.publishers.includes(publisher),
|
||||
})),
|
||||
|
||||
@@ -31,6 +31,20 @@
|
||||
gap: globals.$spacing-unit;
|
||||
}
|
||||
|
||||
&__artifact-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: globals.$body-color;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
text-align: left;
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&__artifacts {
|
||||
display: flex;
|
||||
gap: globals.$spacing-unit;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Button, Modal, ModalProps } from "@renderer/components";
|
||||
import { useContext, useEffect, useMemo, useState } from "react";
|
||||
import { cloudSyncContext, gameDetailsContext } from "@renderer/context";
|
||||
|
||||
import "./cloud-sync-modal.scss";
|
||||
import { formatBytes } from "@shared";
|
||||
import {
|
||||
@@ -9,6 +8,9 @@ import {
|
||||
DeviceDesktopIcon,
|
||||
HistoryIcon,
|
||||
InfoIcon,
|
||||
PencilIcon,
|
||||
PinIcon,
|
||||
PinSlashIcon,
|
||||
SyncIcon,
|
||||
TrashIcon,
|
||||
UploadIcon,
|
||||
@@ -17,6 +19,10 @@ import { useAppSelector, useDate, useToast } from "@renderer/hooks";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { AxiosProgressEvent } from "axios";
|
||||
import { formatDownloadProgress } from "@renderer/helpers";
|
||||
import { CloudSyncRenameArtifactModal } from "../cloud-sync-rename-artifact-modal/cloud-sync-rename-artifact-modal";
|
||||
import { GameArtifact } from "@types";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { orderBy } from "lodash-es";
|
||||
|
||||
export interface CloudSyncModalProps
|
||||
extends Omit<ModalProps, "children" | "title"> {}
|
||||
@@ -25,9 +31,11 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
||||
const [deletingArtifact, setDeletingArtifact] = useState(false);
|
||||
const [backupDownloadProgress, setBackupDownloadProgress] =
|
||||
useState<AxiosProgressEvent | null>(null);
|
||||
const [artifactToRename, setArtifactToRename] = useState<GameArtifact | null>(
|
||||
null
|
||||
);
|
||||
|
||||
const { t } = useTranslation("game_details");
|
||||
|
||||
const { formatDate, formatDateTime } = useDate();
|
||||
|
||||
const {
|
||||
@@ -36,9 +44,11 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
||||
uploadingBackup,
|
||||
restoringBackup,
|
||||
loadingPreview,
|
||||
freezingArtifact,
|
||||
uploadSaveGame,
|
||||
downloadGameArtifact,
|
||||
deleteGameArtifact,
|
||||
toggleArtifactFreeze,
|
||||
setShowCloudSyncFilesModal,
|
||||
getGameBackupPreview,
|
||||
} = useContext(cloudSyncContext);
|
||||
@@ -50,10 +60,8 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
||||
|
||||
const handleDeleteArtifactClick = async (gameArtifactId: string) => {
|
||||
setDeletingArtifact(true);
|
||||
|
||||
try {
|
||||
await deleteGameArtifact(gameArtifactId);
|
||||
|
||||
showSuccessToast(t("backup_deleted"));
|
||||
} catch (err) {
|
||||
showErrorToast("backup_deletion_failed");
|
||||
@@ -71,7 +79,6 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
||||
setBackupDownloadProgress(progressEvent);
|
||||
}
|
||||
);
|
||||
|
||||
return () => {
|
||||
removeBackupDownloadProgressListener();
|
||||
};
|
||||
@@ -82,6 +89,21 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
||||
downloadGameArtifact(artifactId);
|
||||
};
|
||||
|
||||
const handleFreezeArtifactClick = async (
|
||||
artifactId: string,
|
||||
isFrozen: boolean
|
||||
) => {
|
||||
try {
|
||||
await toggleArtifactFreeze(artifactId, isFrozen);
|
||||
showSuccessToast(isFrozen ? t("backup_frozen") : t("backup_unfrozen"));
|
||||
} catch (err) {
|
||||
showErrorToast(
|
||||
t("backup_freeze_failed"),
|
||||
t("backup_freeze_failed_description")
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
getGameBackupPreview();
|
||||
@@ -100,7 +122,6 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
if (restoringBackup) {
|
||||
return (
|
||||
<span className="cloud-sync-modal__backup-state-label">
|
||||
@@ -113,7 +134,6 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
if (loadingPreview) {
|
||||
return (
|
||||
<span className="cloud-sync-modal__backup-state-label">
|
||||
@@ -122,19 +142,15 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
if (artifacts.length >= backupsPerGameLimit) {
|
||||
return t("max_number_of_artifacts_reached");
|
||||
}
|
||||
|
||||
if (!backupPreview) {
|
||||
return t("no_backup_preview");
|
||||
}
|
||||
|
||||
if (artifacts.length === 0) {
|
||||
return t("no_backups");
|
||||
}
|
||||
|
||||
return "";
|
||||
}, [
|
||||
uploadingBackup,
|
||||
@@ -147,121 +163,168 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
||||
t,
|
||||
]);
|
||||
|
||||
const disableActions = uploadingBackup || restoringBackup || deletingArtifact;
|
||||
const disableActions =
|
||||
uploadingBackup || restoringBackup || deletingArtifact || freezingArtifact;
|
||||
const isMissingWinePrefix =
|
||||
window.electron.platform === "linux" && !game?.winePrefixPath;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
visible={visible}
|
||||
title={t("cloud_save")}
|
||||
description={t("cloud_save_description")}
|
||||
onClose={onClose}
|
||||
large
|
||||
>
|
||||
<div className="cloud-sync-modal__header">
|
||||
<div className="cloud-sync-modal__title-container">
|
||||
<h2>{gameTitle}</h2>
|
||||
<p>{backupStateLabel}</p>
|
||||
<>
|
||||
<CloudSyncRenameArtifactModal
|
||||
visible={!!artifactToRename}
|
||||
onClose={() => setArtifactToRename(null)}
|
||||
artifact={artifactToRename}
|
||||
/>
|
||||
|
||||
<button
|
||||
<Modal
|
||||
visible={visible}
|
||||
title={t("cloud_save")}
|
||||
description={t("cloud_save_description")}
|
||||
onClose={onClose}
|
||||
large
|
||||
>
|
||||
<div className="cloud-sync-modal__header">
|
||||
<div className="cloud-sync-modal__title-container">
|
||||
<h2>{gameTitle}</h2>
|
||||
<p>{backupStateLabel}</p>
|
||||
<button
|
||||
type="button"
|
||||
className="cloud-sync-modal__manage-files-button"
|
||||
onClick={() => setShowCloudSyncFilesModal(true)}
|
||||
disabled={disableActions}
|
||||
>
|
||||
{t("manage_files")}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="button"
|
||||
className="cloud-sync-modal__manage-files-button"
|
||||
onClick={() => setShowCloudSyncFilesModal(true)}
|
||||
disabled={disableActions}
|
||||
onClick={() => uploadSaveGame(lastDownloadedOption?.title ?? null)}
|
||||
tooltip={isMissingWinePrefix ? t("missing_wine_prefix") : undefined}
|
||||
tooltipPlace="left"
|
||||
disabled={
|
||||
disableActions ||
|
||||
!backupPreview?.overall.totalGames ||
|
||||
artifacts.length >= backupsPerGameLimit ||
|
||||
isMissingWinePrefix
|
||||
}
|
||||
>
|
||||
{t("manage_files")}
|
||||
</button>
|
||||
{uploadingBackup ? (
|
||||
<SyncIcon className="cloud-sync-modal__sync-icon" />
|
||||
) : (
|
||||
<UploadIcon />
|
||||
)}
|
||||
{t("create_backup")}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => uploadSaveGame(lastDownloadedOption?.title ?? null)}
|
||||
tooltip={isMissingWinePrefix ? t("missing_wine_prefix") : undefined}
|
||||
tooltipPlace="left"
|
||||
disabled={
|
||||
disableActions ||
|
||||
!backupPreview?.overall.totalGames ||
|
||||
artifacts.length >= backupsPerGameLimit ||
|
||||
isMissingWinePrefix
|
||||
}
|
||||
>
|
||||
{uploadingBackup ? (
|
||||
<SyncIcon className="cloud-sync-modal__sync-icon" />
|
||||
) : (
|
||||
<UploadIcon />
|
||||
)}
|
||||
{t("create_backup")}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="cloud-sync-modal__backups-header">
|
||||
<h2>{t("backups")}</h2>
|
||||
<small>
|
||||
{artifacts.length} / {backupsPerGameLimit}
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div className="cloud-sync-modal__backups-header">
|
||||
<h2>{t("backups")}</h2>
|
||||
<small>
|
||||
{artifacts.length} / {backupsPerGameLimit}
|
||||
</small>
|
||||
</div>
|
||||
{artifacts.length > 0 ? (
|
||||
<ul className="cloud-sync-modal__artifacts">
|
||||
<AnimatePresence>
|
||||
{orderBy(artifacts, [(a) => !a.isFrozen], ["asc"]).map(
|
||||
(artifact) => (
|
||||
<motion.li
|
||||
key={artifact.id}
|
||||
className="cloud-sync-modal__artifact"
|
||||
layout
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: -10 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
>
|
||||
<div className="cloud-sync-modal__artifact-info">
|
||||
<div className="cloud-sync-modal__artifact-header">
|
||||
<button
|
||||
type="button"
|
||||
className="cloud-sync-modal__artifact-label"
|
||||
onClick={() => setArtifactToRename(artifact)}
|
||||
>
|
||||
{artifact.label ??
|
||||
t("backup_from", {
|
||||
date: formatDate(artifact.createdAt),
|
||||
})}
|
||||
<PencilIcon />
|
||||
</button>
|
||||
<small>
|
||||
{formatBytes(artifact.artifactLengthInBytes)}
|
||||
</small>
|
||||
</div>
|
||||
|
||||
{artifacts.length > 0 ? (
|
||||
<ul className="cloud-sync-modal__artifacts">
|
||||
{artifacts.map((artifact) => (
|
||||
<li key={artifact.id} className="cloud-sync-modal__artifact">
|
||||
<div className="cloud-sync-modal__artifact-info">
|
||||
<div className="cloud-sync-modal__artifact-header">
|
||||
<h3>
|
||||
{artifact.label ??
|
||||
t("backup_from", {
|
||||
date: formatDate(artifact.createdAt),
|
||||
})}
|
||||
</h3>
|
||||
<small>{formatBytes(artifact.artifactLengthInBytes)}</small>
|
||||
</div>
|
||||
<span className="cloud-sync-modal__artifact-meta">
|
||||
<DeviceDesktopIcon size={14} />
|
||||
{artifact.hostname}
|
||||
</span>
|
||||
|
||||
<span className="cloud-sync-modal__artifact-meta">
|
||||
<DeviceDesktopIcon size={14} />
|
||||
{artifact.hostname}
|
||||
</span>
|
||||
<span className="cloud-sync-modal__artifact-meta">
|
||||
<InfoIcon size={14} />
|
||||
{artifact.downloadOptionTitle ??
|
||||
t("no_download_option_info")}
|
||||
</span>
|
||||
|
||||
<span className="cloud-sync-modal__artifact-meta">
|
||||
<InfoIcon size={14} />
|
||||
{artifact.downloadOptionTitle ?? t("no_download_option_info")}
|
||||
</span>
|
||||
<span className="cloud-sync-modal__artifact-meta">
|
||||
<ClockIcon size={14} />
|
||||
{formatDateTime(artifact.createdAt)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span className="cloud-sync-modal__artifact-meta">
|
||||
<ClockIcon size={14} />
|
||||
{formatDateTime(artifact.createdAt)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="cloud-sync-modal__artifact-actions">
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => handleBackupInstallClick(artifact.id)}
|
||||
disabled={disableActions}
|
||||
>
|
||||
{restoringBackup ? (
|
||||
<SyncIcon className="cloud-sync-modal__sync-icon" />
|
||||
) : (
|
||||
<HistoryIcon />
|
||||
)}
|
||||
{t("install_backup")}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => handleDeleteArtifactClick(artifact.id)}
|
||||
theme="danger"
|
||||
disabled={disableActions}
|
||||
>
|
||||
<TrashIcon />
|
||||
{t("delete_backup")}
|
||||
</Button>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<p>{t("no_backups_created")}</p>
|
||||
)}
|
||||
</Modal>
|
||||
<div className="cloud-sync-modal__artifact-actions">
|
||||
<Button
|
||||
type="button"
|
||||
tooltip={
|
||||
artifact.isFrozen
|
||||
? t("unfreeze_backup")
|
||||
: t("freeze_backup")
|
||||
}
|
||||
theme={artifact.isFrozen ? "primary" : "outline"}
|
||||
onClick={() =>
|
||||
handleFreezeArtifactClick(
|
||||
artifact.id,
|
||||
!artifact.isFrozen
|
||||
)
|
||||
}
|
||||
disabled={disableActions}
|
||||
>
|
||||
{artifact.isFrozen ? <PinSlashIcon /> : <PinIcon />}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => handleBackupInstallClick(artifact.id)}
|
||||
disabled={disableActions}
|
||||
theme="outline"
|
||||
>
|
||||
{restoringBackup ? (
|
||||
<SyncIcon className="cloud-sync-modal__sync-icon" />
|
||||
) : (
|
||||
<HistoryIcon />
|
||||
)}
|
||||
{t("install_backup")}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => handleDeleteArtifactClick(artifact.id)}
|
||||
disabled={disableActions || artifact.isFrozen}
|
||||
theme="outline"
|
||||
tooltip={t("delete_backup")}
|
||||
>
|
||||
<TrashIcon />
|
||||
</Button>
|
||||
</div>
|
||||
</motion.li>
|
||||
)
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</ul>
|
||||
) : (
|
||||
<p>{t("no_backups_created")}</p>
|
||||
)}
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
.cloud-sync-rename-artifact-modal {
|
||||
&__form-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-top: 16px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
import { useCallback, useContext, useEffect } from "react";
|
||||
import { Button, Modal, ModalProps, TextField } from "@renderer/components";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import type { GameArtifact } from "@types";
|
||||
import { cloudSyncContext } from "@renderer/context";
|
||||
import { logger } from "@renderer/logger";
|
||||
import * as yup from "yup";
|
||||
import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import { InferType } from "yup";
|
||||
import { useToast } from "@renderer/hooks";
|
||||
|
||||
import "./cloud-sync-rename-artifact-modal.scss";
|
||||
|
||||
export interface CloudSyncRenameArtifactModalProps
|
||||
extends Omit<ModalProps, "children" | "title"> {
|
||||
artifact: GameArtifact | null;
|
||||
}
|
||||
|
||||
export function CloudSyncRenameArtifactModal({
|
||||
visible,
|
||||
onClose,
|
||||
artifact,
|
||||
}: Readonly<CloudSyncRenameArtifactModalProps>) {
|
||||
const { t } = useTranslation("game_details");
|
||||
|
||||
const validationSchema = yup.object({
|
||||
label: yup
|
||||
.string()
|
||||
.required(t("required_field"))
|
||||
.max(255, t("max_length_field", { length: 255 })),
|
||||
});
|
||||
|
||||
const { getGameArtifacts } = useContext(cloudSyncContext);
|
||||
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
formState: { errors, isSubmitting },
|
||||
} = useForm({
|
||||
defaultValues: {
|
||||
label: artifact?.label ?? "",
|
||||
},
|
||||
resolver: yupResolver(validationSchema),
|
||||
});
|
||||
|
||||
const { showSuccessToast } = useToast();
|
||||
|
||||
useEffect(() => {
|
||||
if (artifact) {
|
||||
setValue("label", artifact.label ?? "");
|
||||
}
|
||||
}, [artifact, setValue]);
|
||||
|
||||
const onSubmit = useCallback(
|
||||
async (data: InferType<typeof validationSchema>) => {
|
||||
try {
|
||||
if (!artifact) return;
|
||||
|
||||
await window.electron.renameGameArtifact(artifact.id, data.label);
|
||||
await getGameArtifacts();
|
||||
|
||||
showSuccessToast(t("artifact_renamed"));
|
||||
|
||||
onClose();
|
||||
} catch (err) {
|
||||
logger.error("Failed to rename artifact", err);
|
||||
}
|
||||
},
|
||||
[artifact, getGameArtifacts, onClose, showSuccessToast, t]
|
||||
);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
visible={visible}
|
||||
title={t("rename_artifact")}
|
||||
description={t("rename_artifact_description")}
|
||||
onClose={onClose}
|
||||
>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<TextField
|
||||
label={t("artifact_name_label")}
|
||||
placeholder={t("artifact_name_placeholder")}
|
||||
{...register("label")}
|
||||
error={errors.label?.message}
|
||||
/>
|
||||
|
||||
<div className="cloud-sync-rename-artifact-modal__form-actions">
|
||||
<Button theme="outline" onClick={onClose}>
|
||||
{t("cancel")}
|
||||
</Button>
|
||||
|
||||
<Button type="submit" disabled={isSubmitting}>
|
||||
{t("save_changes")}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -40,7 +40,7 @@ export function SettingsAppearance({
|
||||
}, [loadThemes]);
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribe = window.electron.onCssInjected(() => {
|
||||
const unsubscribe = window.electron.onCustomThemeUpdated(() => {
|
||||
loadThemes();
|
||||
});
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ export function SettingsGeneral() {
|
||||
downloadNotificationsEnabled: false,
|
||||
repackUpdatesNotificationsEnabled: false,
|
||||
friendRequestNotificationsEnabled: false,
|
||||
friendStartGameNotificationsEnabled: true,
|
||||
achievementNotificationsEnabled: true,
|
||||
achievementCustomNotificationsEnabled: true,
|
||||
achievementCustomNotificationPosition:
|
||||
@@ -111,6 +112,8 @@ export function SettingsGeneral() {
|
||||
userPreferences.achievementCustomNotificationPosition ?? "top-left",
|
||||
friendRequestNotificationsEnabled:
|
||||
userPreferences.friendRequestNotificationsEnabled ?? false,
|
||||
friendStartGameNotificationsEnabled:
|
||||
userPreferences.friendStartGameNotificationsEnabled ?? true,
|
||||
language: language ?? "en",
|
||||
}));
|
||||
}
|
||||
@@ -248,6 +251,17 @@ export function SettingsGeneral() {
|
||||
}
|
||||
/>
|
||||
|
||||
<CheckboxField
|
||||
label={t("enable_friend_start_game_notifications")}
|
||||
checked={form.friendStartGameNotificationsEnabled}
|
||||
onChange={() =>
|
||||
handleChange({
|
||||
friendStartGameNotificationsEnabled:
|
||||
!form.friendStartGameNotificationsEnabled,
|
||||
})
|
||||
}
|
||||
/>
|
||||
|
||||
<CheckboxField
|
||||
label={t("enable_achievement_notifications")}
|
||||
checked={form.achievementNotificationsEnabled}
|
||||
|
||||
@@ -29,11 +29,10 @@ export const UserFriendModalAddFriend = ({
|
||||
setIsAddingFriend(true);
|
||||
sendFriendRequest(friendCode)
|
||||
.then(() => {
|
||||
// TODO: add validation for this input?
|
||||
setFriendCode("");
|
||||
})
|
||||
.catch(() => {
|
||||
showErrorToast("Não foi possível enviar o pedido de amizade");
|
||||
showErrorToast(t("error_adding_friend"));
|
||||
})
|
||||
.finally(() => {
|
||||
setIsAddingFriend(false);
|
||||
@@ -46,8 +45,8 @@ export const UserFriendModalAddFriend = ({
|
||||
};
|
||||
|
||||
const handleClickSeeProfile = () => {
|
||||
closeModal();
|
||||
if (friendCode.length === 8) {
|
||||
closeModal();
|
||||
navigate(`/profile/${friendCode}`);
|
||||
}
|
||||
};
|
||||
@@ -74,16 +73,19 @@ export const UserFriendModalAddFriend = ({
|
||||
});
|
||||
};
|
||||
|
||||
const handleChangeFriendCode = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const friendCode = e.target.value.trim().slice(0, 8);
|
||||
setFriendCode(friendCode);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="user-friend-modal-add-friend__actions">
|
||||
<TextField
|
||||
label={t("friend_code")}
|
||||
value={friendCode}
|
||||
minLength={8}
|
||||
maxLength={8}
|
||||
containerProps={{ style: { width: "100%" } }}
|
||||
onChange={(e) => setFriendCode(e.target.value)}
|
||||
onChange={handleChangeFriendCode}
|
||||
/>
|
||||
<Button
|
||||
disabled={isAddingFriend}
|
||||
|
||||
@@ -11,6 +11,9 @@ import { injectCustomCss } from "@renderer/helpers";
|
||||
import { AchievementNotificationItem } from "@renderer/components/achievements/notification/achievement-notification";
|
||||
import { generateAchievementCustomNotificationTest } from "@shared";
|
||||
import { CollapsedMenu } from "@renderer/components/collapsed-menu/collapsed-menu";
|
||||
import app from "../../app.scss?inline";
|
||||
import styles from "../../components/achievements/notification/achievement-notification.scss?inline";
|
||||
import root from "react-shadow";
|
||||
|
||||
const notificationVariations = {
|
||||
default: "default",
|
||||
@@ -36,14 +39,15 @@ export default function ThemeEditor() {
|
||||
const [notificationAlignment, setNotificationAlignment] =
|
||||
useState<AchievementCustomNotificationPosition>("top-left");
|
||||
|
||||
const [shadowRootRef, setShadowRootRef] = useState<HTMLElement | null>(null);
|
||||
|
||||
const achievementPreview = useMemo(() => {
|
||||
return {
|
||||
achievement: {
|
||||
...generateAchievementCustomNotificationTest(t, i18n.language),
|
||||
achievement: generateAchievementCustomNotificationTest(t, i18n.language, {
|
||||
isRare: notificationVariation === "rare",
|
||||
isHidden: notificationVariation === "hidden",
|
||||
isPlatinum: notificationVariation === "platinum",
|
||||
},
|
||||
}),
|
||||
position: notificationAlignment,
|
||||
};
|
||||
}, [t, i18n.language, notificationVariation, notificationAlignment]);
|
||||
@@ -58,10 +62,13 @@ export default function ThemeEditor() {
|
||||
if (loadedTheme) {
|
||||
setTheme(loadedTheme);
|
||||
setCode(loadedTheme.code);
|
||||
if (shadowRootRef) {
|
||||
injectCustomCss(loadedTheme.code, shadowRootRef);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [themeId]);
|
||||
}, [themeId, shadowRootRef]);
|
||||
|
||||
const handleSave = useCallback(async () => {
|
||||
if (theme) {
|
||||
@@ -69,11 +76,14 @@ export default function ThemeEditor() {
|
||||
setHasUnsavedChanges(false);
|
||||
setIsClosingNotifications(true);
|
||||
setTimeout(() => {
|
||||
injectCustomCss(code);
|
||||
if (shadowRootRef) {
|
||||
injectCustomCss(code, shadowRootRef);
|
||||
}
|
||||
|
||||
setIsClosingNotifications(false);
|
||||
}, 450);
|
||||
}
|
||||
}, [code, theme]);
|
||||
}, [code, theme, shadowRootRef]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
@@ -185,11 +195,18 @@ export default function ThemeEditor() {
|
||||
/>
|
||||
|
||||
<div className="theme-editor__notification-preview-wrapper">
|
||||
<AchievementNotificationItem
|
||||
position={achievementPreview.position}
|
||||
achievement={achievementPreview.achievement}
|
||||
isClosing={isClosingNotifications}
|
||||
/>
|
||||
<root.div>
|
||||
<style type="text/css">
|
||||
{app} {styles}
|
||||
</style>
|
||||
<section ref={setShadowRootRef}>
|
||||
<AchievementNotificationItem
|
||||
position={achievementPreview.position}
|
||||
achievement={achievementPreview.achievement}
|
||||
isClosing={isClosingNotifications}
|
||||
/>
|
||||
</section>
|
||||
</root.div>
|
||||
</div>
|
||||
</div>
|
||||
</CollapsedMenu>
|
||||
|
||||
@@ -9,6 +9,9 @@ $success-color: #1c9749;
|
||||
$danger-color: #801d1e;
|
||||
$warning-color: #ffc107;
|
||||
|
||||
$brand-teal: #16b195;
|
||||
$brand-blue: #3e62c0;
|
||||
|
||||
$disabled-opacity: 0.5;
|
||||
$active-opacity: 0.7;
|
||||
|
||||
|
||||
@@ -179,7 +179,8 @@ export const formatDate = (
|
||||
|
||||
export const generateAchievementCustomNotificationTest = (
|
||||
t: any,
|
||||
language?: string
|
||||
language?: string,
|
||||
options: { isHidden?: boolean; isRare?: boolean; isPlatinum?: boolean } = {}
|
||||
): AchievementNotificationInfo => {
|
||||
return {
|
||||
title: t("test_achievement_notification_title", {
|
||||
@@ -192,8 +193,8 @@ export const generateAchievementCustomNotificationTest = (
|
||||
}),
|
||||
iconUrl: "https://cdn.losbroxas.org/favicon.svg",
|
||||
points: 2440,
|
||||
isHidden: false,
|
||||
isRare: false,
|
||||
isPlatinum: false,
|
||||
isHidden: options.isHidden ?? false,
|
||||
isRare: options.isRare ?? false,
|
||||
isPlatinum: options.isPlatinum ?? false,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -272,6 +272,7 @@ export interface AchievementNotificationInfo {
|
||||
isPlatinum: boolean;
|
||||
points?: number;
|
||||
}
|
||||
|
||||
export interface GameArtifact {
|
||||
id: string;
|
||||
artifactLengthInBytes: number;
|
||||
@@ -281,6 +282,7 @@ export interface GameArtifact {
|
||||
hostname: string;
|
||||
downloadCount: number;
|
||||
label?: string;
|
||||
isFrozen: boolean;
|
||||
}
|
||||
|
||||
export interface ComparedAchievements {
|
||||
@@ -342,6 +344,23 @@ export type LibraryGame = Game &
|
||||
download: Download | null;
|
||||
};
|
||||
|
||||
export type UserGameDetails = ShopAssets & {
|
||||
id: string;
|
||||
playTimeInSeconds: number;
|
||||
unlockedAchievementCount: number;
|
||||
achievementsPointsEarnedSum: number;
|
||||
lastTimePlayed: Date | null;
|
||||
isDeleted: boolean;
|
||||
isFavorite: boolean;
|
||||
friendsWhoPlayed: {
|
||||
id: string;
|
||||
displayName: string;
|
||||
profileImageUrl: string | null;
|
||||
lastTimePlayed: Date | null;
|
||||
playTimeInSeconds: number;
|
||||
}[];
|
||||
};
|
||||
|
||||
export * from "./game.types";
|
||||
export * from "./steam.types";
|
||||
export * from "./download.types";
|
||||
|
||||
@@ -34,6 +34,7 @@ export interface Game {
|
||||
title: string;
|
||||
iconUrl: string | null;
|
||||
playTimeInMilliseconds: number;
|
||||
unsyncedDeltaPlayTimeInMilliseconds?: number;
|
||||
lastTimePlayed: Date | null;
|
||||
objectId: string;
|
||||
shop: GameShop;
|
||||
@@ -97,6 +98,7 @@ export interface UserPreferences {
|
||||
achievementCustomNotificationsEnabled?: boolean;
|
||||
achievementCustomNotificationPosition?: AchievementCustomNotificationPosition;
|
||||
friendRequestNotificationsEnabled?: boolean;
|
||||
friendStartGameNotificationsEnabled?: boolean;
|
||||
showDownloadSpeedInMegabytes?: boolean;
|
||||
extractFilesByDefault?: boolean;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user