diff --git a/.gitmodules b/.gitmodules index 5f63fec51..05fcb7284 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "src/backend/hyperplay-overlay"] path = src/backend/hyperplay-overlay url = https://github.com/HyperPlay-Gaming/hyperplay-overlay.git +[submodule "src/backend/hyperplay-achievements"] + path = src/backend/hyperplay-achievements + url = git@github.com:HyperPlay-Gaming/hyperplay-achievements.git diff --git a/package.json b/package.json index 280c3a431..d0a0abb58 100644 --- a/package.json +++ b/package.json @@ -157,7 +157,7 @@ "@fortawesome/free-regular-svg-icons": "^6.1.1", "@fortawesome/free-solid-svg-icons": "^6.1.1", "@fortawesome/react-fontawesome": "^0.1.18", - "@hyperplay/ui": "^0.1.33", + "@hyperplay/ui": "^0.1.38", "@mantine/carousel": "^6.0.19", "@mantine/core": "^6.0.19", "@mantine/hooks": "^6.0.19", diff --git a/public/locales/en/gamepage.json b/public/locales/en/gamepage.json index 32464b411..a1f49e066 100644 --- a/public/locales/en/gamepage.json +++ b/public/locales/en/gamepage.json @@ -1,227 +1,218 @@ -{ - "box": { - "change": { - "message": "This will change the install location of this game, are you sure?", - "path": "Choose a new install path", - "title": "Change Games Install Path" - }, - "choose": "Choose", - "importpath": "Choose Game Folder to import", - "move": { - "message": "This can take a long time, are you sure?", - "path": "Choose where you want to move", - "title": "Move Game Installation" - }, - "no": "NO", - "ok": "OK", - "repair": { - "message": "Do you want to try to repair this game? This can take a long time.", - "title": "Verify and Repair" - }, - "runexe": { - "title": "Select EXE to Run" - }, - "select": { - "button": "Select" - }, - "sideload": { - "exe": "Select Executable" - }, - "stopInstall": { - "keepFilesMessage": "Check here if you want to keep the download files after canceling.", - "keepInstalling": "Keep Installing", - "message": "Do you wish to KEEP downloaded files?", - "title": "Do you want to cancel the download?" - }, - "uninstall": { - "checkbox": "Remove prefix: {{prefix}}{{newLine}}Note: This can't be undone and will also remove not backed up save files.", - "dlc": "Do you want to Uninstall this DLC?", - "message": "Do you want to uninstall this game?", - "prefix_warning": "The Wine prefix for this game is the default prefix. If you really want to delete it, you have to do it manually.", - "settingcheckbox": "Erase settings and remove log{{newLine}}Note: This can't be undone. Any modified settings will be forgotten and log will be deleted.", - "title": "Uninstall" - }, - "update": { - "message": "This game has an update, apply update now?", - "message-cancel": "It is not possible to play this game without updating", - "title": "Game Needs Update" - }, - "wineprefix": "Select WinePrefix Folder", - "yes": "YES", - "yesCancel": "Yes, cancel" - }, - "button": { - "cancel": "Pause/Cancel", - "continue": "Continue Download", - "details": "Details", - "favorites": "Favorite", - "finish": "Finish", - "force_update": "Force Update if Available", - "force-innstall": "Force Install", - "hide_game": "Hide Game", - "import": "Import Game", - "install": "Install", - "no-path-selected": "No path selected", - "queue": { - "cancel": "Cancel Download", - "continue": "Continue Download", - "remove": "Remove from Queue" - }, - "remove_from_library": "Remove", - "remove_from_recent": "Remove From Recent", - "run-exe-first": "Run Installer First", - "running-setup": "Running Setup", - "sideload": { - "edit": "Edit App/Game" - }, - "unfavorites": "Unfavorite", - "unhide_game": "Unhide Game", - "uninstall": "Uninstall", - "update": "Update" - }, - "cloud_save_unsupported": "Unsupported", - "disabled": "Disabled", - "dlc": { - "installDlcs": "Install all DLCs" - }, - "enabled": "Enabled", - "game": { - "dlcs": "DLCs", - "downloadSize": "Download Size", - "firstPlayed": "First Played", - "getting-download-size": "Getting download size", - "getting-install-size": "Getting install size", - "installSize": "Install Size", - "language": "Language", - "lastPlayed": "Last Played", - "neverPlayed": "Never", - "platform": "Select Platform", - "requirements": "System Requirements", - "selectChannelName": "Select Channel Name", - "totalPlayed": "Time Played" - }, - "gamecard": { - "moving": "Moving", - "repairing": "Repairing" - }, - "generic": { - "error": "Unknown error", - "noDescription": "No description available" - }, - "hyperplay": { - "gamecard": { - "extracting": "Extracting...", - "installing": "Downloading...", - "paused": "Paused" - } - }, - "info": { - "canRunOffline": "Online Required", - "installedPlatform": "Installed Platform", - "path": "Install Path", - "size": "Size", - "syncsaves": "Sync Saves", - "version": "Version", - "web3-supported": "Has Web3 features" - }, - "install": { - "disk-space-left": "Space Available", - "not-enough-disk-space": "Not enough disk space", - "path": "Select Install Path", - "path-not-writtable": "Warning: path might not be writable.", - "space-after-install": "After Install", - "wineprefix": "WinePrefix", - "wineversion": "Wine version" - }, - "label": { - "playing": { - "start": "Play", - "stop": "Playing (Stop)", - "update": "Update" - }, - "saves": { - "syncing": "Syncing Saves" - } - }, - "launch": { - "options": "Launch Options..." - }, - "not_logged_in": { - "amazon": "You are not logged in with an Amazon account in Hyperplay. Don't use the store page to login, click the following button instead:", - "epic": "You are not logged in with an Epic account in HyperPlay. Don't use the store page to login, click the following button instead:", - "gog": "You are not logged in with a GOG account in HyperPlay. Don't use the store page to login, click the following button instead:", - "login": "Log in", - "title": "You are NOT logged in" - }, - "report_problem": "Report a problem running this game", - "setting": { - "use-default-wine-settings": "Use Default Compatibility Settings", - "winecrossoverbottle": "CrossOver Bottle" - }, - "sideload": { - "field": { - "title": "Title" - }, - "info": { - "broser": "BrowserURL", - "exe": "Select Executable", - "image": "App Image", - "supports-web3": "This Games has Web3 Features", - "title": "Game/App Title" - }, - "placeholder": { - "image": "Paste an Image URL here", - "title": "Add a title to your Game/App", - "url": "Paste the Game URL here" - } - }, - "specs": { - "minimum": "Minimum", - "recommended": "Recommended" - }, - "status": { - "clickToUpdate": "Click to Update", - "downloading": "Downloading", - "extracting": { - "cancel": "Cancel Extraction", - "progress": "Extracting" - }, - "gameNotAvailable": "Game not available", - "gog-goodie": "This game doesn't appear to be installable. Check downloadable content on https://gog.com/account", - "goodie": "Not installable", - "hasUpdates": "New Version Available!", - "installed": "Installed", - "installing": "Installing", - "moving": "Moving Installation, please wait", - "moving-files": "Moving file '{{file}}': {{percent}} ", - "notinstalled": "This game is not installed", - "notSupported": "Not supported", - "notSupportedGame": "Not Supported", - "paused": "Paused", - "playing": "Playing", - "preparing": "Preparing Download, please wait", - "processing": "Processing files, please wait", - "queued": "Queued", - "reparing": "Repairing Game, please wait", - "syncingSaves": "Syncing Saves", - "this-game-uses-third-party": "This game uses third party launcher and it is not supported yet", - "totalDownloaded": "Total Downloaded", - "uninstalling": "Uninstalling", - "updating": "Updating Game" - }, - "submenu": { - "addShortcut": "Add shortcut", - "addToSteam": "Add to Steam", - "change": "Change install path", - "disableEosOverlay": "Disable Epic Overlay", - "enableEosOverlay": "Enable Epic Overlay", - "extraInfo": "Extra Info", - "move": "Move Game", - "protondb": "Check Compatibility", - "removeFromSteam": "Remove from Steam", - "removeShortcut": "Remove shortcuts", - "settings": "Settings", - "store": "Store Page", - "verify": "Verify and Repair" - } -} +{ + "box": { + "change": { + "message": "This will change the install location of this game, are you sure?", + "path": "Choose a new install path", + "title": "Change Games Install Path" + }, + "choose": "Choose", + "importpath": "Choose Game Folder to import", + "move": { + "message": "This can take a long time, are you sure?", + "path": "Choose where you want to move", + "title": "Move Game Installation" + }, + "no": "NO", + "ok": "OK", + "repair": { + "message": "Do you want to try to repair this game? This can take a long time.", + "title": "Verify and Repair" + }, + "runexe": { + "title": "Select EXE to Run" + }, + "select": { + "button": "Select" + }, + "sideload": { + "exe": "Select Executable" + }, + "stopInstall": { + "keepFilesMessage": "Check here if you want to keep the download files after canceling.", + "keepInstalling": "Keep Installing", + "message": "Do you wish to KEEP downloaded files?", + "title": "Do you want to cancel the download?" + }, + "uninstall": { + "checkbox": "Remove prefix: {{prefix}}{{newLine}}Note: This can't be undone and will also remove not backed up save files.", + "dlc": "Do you want to Uninstall this DLC?", + "message": "Do you want to uninstall this game?", + "prefix_warning": "The Wine prefix for this game is the default prefix. If you really want to delete it, you have to do it manually.", + "settingcheckbox": "Erase settings and remove log{{newLine}}Note: This can't be undone. Any modified settings will be forgotten and log will be deleted.", + "title": "Uninstall" + }, + "update": { + "message": "This game has an update, apply update now?", + "message-cancel": "It is not possible to play this game without updating", + "title": "Game Needs Update" + }, + "wineprefix": "Select WinePrefix Folder", + "yes": "YES", + "yesCancel": "Yes, cancel" + }, + "button": { + "cancel": "Pause/Cancel", + "continue": "Continue Download", + "details": "Details", + "favorites": "Favorite", + "finish": "Finish", + "force_update": "Force Update if Available", + "force-innstall": "Force Install", + "hide_game": "Hide Game", + "import": "Import Game", + "install": "Install", + "no-path-selected": "No path selected", + "queue": { + "cancel": "Cancel Download", + "continue": "Continue Download", + "remove": "Remove from Queue" + }, + "remove_from_library": "Remove", + "remove_from_recent": "Remove From Recent", + "run-exe-first": "Run Installer First", + "running-setup": "Running Setup", + "sideload": { + "edit": "Edit App/Game" + }, + "unfavorites": "Unfavorite", + "unhide_game": "Unhide Game", + "uninstall": "Uninstall", + "update": "Update" + }, + "cloud_save_unsupported": "Unsupported", + "disabled": "Disabled", + "dlc": { + "installDlcs": "Install all DLCs" + }, + "enabled": "Enabled", + "game": { + "dlcs": "DLCs", + "downloadSize": "Download Size", + "firstPlayed": "First Played", + "getting-download-size": "Getting download size", + "getting-install-size": "Getting install size", + "installSize": "Install Size", + "language": "Language", + "lastPlayed": "Last Played", + "neverPlayed": "Never", + "platform": "Select Platform", + "requirements": "System Requirements", + "selectChannelName": "Select Channel Name", + "totalPlayed": "Time Played" + }, + "gamecard": { + "moving": "Moving", + "repairing": "Repairing" + }, + "generic": { + "error": "Unknown error", + "noDescription": "No description available" + }, + "info": { + "canRunOffline": "Online Required", + "installedPlatform": "Installed Platform", + "path": "Install Path", + "size": "Size", + "syncsaves": "Sync Saves", + "version": "Version", + "web3-supported": "Has Web3 features" + }, + "install": { + "disk-space-left": "Space Available", + "not-enough-disk-space": "Not enough disk space", + "path": "Select Install Path", + "path-not-writtable": "Warning: path might not be writable.", + "space-after-install": "After Install", + "wineprefix": "WinePrefix", + "wineversion": "Wine version" + }, + "label": { + "playing": { + "start": "Play", + "stop": "Playing (Stop)", + "update": "Update" + }, + "saves": { + "syncing": "Syncing Saves" + } + }, + "launch": { + "options": "Launch Options..." + }, + "not_logged_in": { + "amazon": "You are not logged in with an Amazon account in Hyperplay. Don't use the store page to login, click the following button instead:", + "epic": "You are not logged in with an Epic account in HyperPlay. Don't use the store page to login, click the following button instead:", + "gog": "You are not logged in with a GOG account in HyperPlay. Don't use the store page to login, click the following button instead:", + "login": "Log in", + "title": "You are NOT logged in" + }, + "report_problem": "Report a problem running this game", + "setting": { + "use-default-wine-settings": "Use Default Compatibility Settings", + "winecrossoverbottle": "CrossOver Bottle" + }, + "sideload": { + "field": { + "title": "Title" + }, + "info": { + "broser": "BrowserURL", + "exe": "Select Executable", + "image": "App Image", + "supports-web3": "This Games has Web3 Features", + "title": "Game/App Title" + }, + "placeholder": { + "image": "Paste an Image URL here", + "title": "Add a title to your Game/App", + "url": "Paste the Game URL here" + } + }, + "specs": { + "minimum": "Minimum", + "recommended": "Recommended" + }, + "status": { + "downloading": "Downloading", + "extracting": { + "cancel": "Cancel Extraction", + "progress": "Extracting" + }, + "gameNotAvailable": "Game not available", + "gog-goodie": "This game doesn't appear to be installable. Check downloadable content on https://gog.com/account", + "goodie": "Not installable", + "installed": "Installed", + "installing": "Installing", + "moving": "Moving Installation, please wait", + "moving-files": "Moving file '{{file}}': {{percent}} ", + "notinstalled": "This game is not installed", + "notSupported": "Not supported", + "notSupportedGame": "Not Supported", + "paused": "Paused", + "playing": "Playing", + "preparing": "Preparing Download, please wait", + "processing": "Processing files, please wait", + "queued": "Queued", + "reparing": "Repairing Game, please wait", + "syncingSaves": "Syncing Saves", + "this-game-uses-third-party": "This game uses third party launcher and it is not supported yet", + "totalDownloaded": "Total Downloaded", + "uninstalling": "Uninstalling", + "updating": "Updating Game" + }, + "submenu": { + "addShortcut": "Add shortcut", + "addToSteam": "Add to Steam", + "change": "Change install path", + "disableEosOverlay": "Disable Epic Overlay", + "enableEosOverlay": "Enable Epic Overlay", + "extraInfo": "Extra Info", + "move": "Move Game", + "protondb": "Check Compatibility", + "removeFromSteam": "Remove from Steam", + "removeShortcut": "Remove shortcuts", + "settings": "Settings", + "store": "Store Page", + "verify": "Verify and Repair" + } +} diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index e0d8a3b99..7cb22c50b 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -1,834 +1,854 @@ -{ - "accessibility": { - "actions_font_family_no_default": "Actions Font Family (Default: ", - "all_tiles_in_color": "Show all game tiles in color", - "content_font_family_no_default": "Content Font Family (Default: ", - "fonts": "Fonts", - "title": "Accessibility", - "zoom": "Zoom" - }, - "accounts": "accounts", - "add_game": "Add Game", - "All": "All", - "ALL": "ALL", - "amazon": "", - "Amazon": "Amazon", - "Amazon Games": "Amazon Games", - "analytics": "Analytics", - "anticheat": { - "anticheats": "Anticheats", - "may_not_work": "It may not work due to denied or broken anticheat support.", - "reference": "Reference", - "source": "Source", - "status": "Status", - "title": "This game includes anticheat software" - }, - "box": { - "cache-cleared": { - "message": "HyperPlay cache cleared.", - "title": "Cache cleared" - }, - "choose": "Choose", - "choose-egs-prefix": "Choose Prefix where EGS is installed", - "choose-gogdl-binary": "Select GOGDL Binary (needs restart)", - "choose-legendary-binary": "Select Legendary binary", - "customWine": "Select the Wine or Proton binary", - "default-install-path": "Choose Default Install Path", - "default-steam-path": "Steam path.", - "dontShowAgain": "Don't show again", - "downloadNow": "Download now", - "error": { - "add": { - "steam": { - "body": "Adding {{game}} to Steam failed with:{{newLine}} {{error}}", - "title": "Adding Error" - } - }, - "credentials": { - "message": "Your credentials have expired, please log out and log in again." - }, - "cx-bottle-not-found": { - "message": "The CrossOver bottle \"{{bottle_name}}\" does not exist, can't launch!", - "title": "CrossOver bottle not found" - }, - "diskspace": { - "message": "Not enough available disk space", - "title": "No Space" - }, - "dxvk": { - "message": "Error installing DXVK/VKD3D! Please check your connection!", - "title": "DXVK/VKD3D error" - }, - "folder-not-found": { - "title": "Game folder appears to be deleted, do you want to remove the game from the installed list?" - }, - "generic": { - "message": "", - "title": "Select EXE to Run" - }, - "launchAborted": "Launch aborted", - "moving": "Error Moving Game {{error}}", - "title": "Error", - "ubisoft-connect": { - "message": "Installation of Ubisoft Connect in the game prefix failed. Check our wiki page at https://github.com/Heroic-Games-Launcher/HeroicGamesLauncher/wiki/How-to-install-Ubisoft-Connect-on-Linux-and-Mac to install it maunally.", - "title": "Ubisoft Connect" - }, - "update": { - "message": "Something went wrong with the update! Please manually uninstall and reinstall HyperPlay.", - "title": "Update Error" - }, - "winetricks": { - "message": "Winetricks returned the following error during execution:{{newLine}}{{error}}", - "title": "Winetricks error" - } - }, - "info": { - "update": { - "changelog": "Open changelog", - "detail": "Do you want to download the update in the background?", - "message": "There is a new Version available!", - "message-finished": "Do you want to restart HyperPlay now?", - "title": "HyperPlay Games Launcher", - "title-finished": "Update Finished" - } - }, - "no": "NO", - "ok": "OK", - "protocol": { - "install": { - "not_installed": "Currently not installed. Install it?" - } - }, - "quit": { - "message": "There are pending operations, are you sure?", - "title": "Exit" - }, - "reset-app": { - "question": { - "message": "Are you sure you want to reset HyperPlay? This will remove all Settings and Caching but won't remove your Installed games or your Epic credentials. Portable versions (AppImage, WinPortable, ...) of HyperPlay needs to be restarted manually afterwards.", - "title": "Reset HyperPlay" - } - }, - "runexe": { - "title": "Select EXE to Run" - }, - "select": { - "button": "Select", - "exe": "Select EXE" - }, - "shortcuts": { - "message": "Shortcuts were created on Desktop and Start Menu", - "message-mac": "Shortcuts were created on the Applications folder", - "message-remove": "Shortcuts were removed from Desktop and Start Menu", - "message-remove-mac": "Shortcuts were removed from the Applications folder", - "title": "Shortcuts" - }, - "sync": { - "button": "Choose", - "error": "Invalid Path", - "title": "Choose the saves directory" - }, - "vcruntime": { - "install": { - "message": "The download links for the Visual C++ Runtimes have been opened. Please install both the x86 and x64 versions." - }, - "notfound": { - "message": "The Microsoft Visual C++ Runtimes are not installed, which are required by some games", - "title": "VCRuntime not installed" - } - }, - "warning": { - "epic": { - "import": "Epic Servers are having major outage right now, the game cannot be imported!", - "install": "Epic Servers are having major outage right now, the game cannot be installed!", - "update": "Epic Servers are having major outage right now, the game cannot be updated!" - }, - "title": "Warning", - "wine-change": { - "message": "We could not find the selected wine version to launch this title ({{selectedWine}}). {{newline}} We found another one, do you want to continue launching using {{foundWine}} ?", - "title": "Wine not found!" - } - }, - "wineprefix": "Choose Wine Prefix Folder", - "yes": "YES" - }, - "button": { - "cancel": "Cancel", - "continue": "Continue", - "download": "Download", - "go_to_library": "Go to Library", - "sync": "Sync", - "syncing": "Syncing", - "unsync": "Unsync" - }, - "controller": { - "hints": { - "back": "Back", - "backspace": "Backspace", - "close_dialog": "Close dialog", - "close_keyboard": "Close keyboard", - "close_options": "Close Options", - "game_details": "Game details", - "game_settings": "Game settings", - "install_game": "Install game", - "move_cursor": "Move cursor", - "open_virtual_keyboard": "Open virtual keyboard", - "options": "Options", - "play_game": "Play game", - "scroll": "Scroll", - "select": "Select", - "space": "Space", - "update_game": "Update game" - } - }, - "dlc": { - "actions": "Actions", - "installDlcs": "Install all DLCs", - "noDlcFound": "No DLCs found", - "size": "Size", - "title": "Title" - }, - "dlcs": { - "label": "Select DLCs to install:" - }, - "download-manager": { - "ETA": "Estimated Time", - "install-type": { - "install": "Install", - "update": "Update" - }, - "label": { - "disk": "Disk", - "speed": "Download" - }, - "queue": { - "end-time": "Finished at", - "queue-time": "Added at", - "start-time": "Started at", - "type": "Type" - }, - "title": "Downloads" - }, - "epic": { - "offline-notification-body": "Online services may not work fully as Epic Games servers are offline!", - "offline-notification-title": "offline" - }, - "Epic Games": "Epic Games", - "error": "Error", - "exit_game": "Exit Game", - "externalLink": { - "dontAskAgain": "Don't ask again", - "warning": "You are about to open an external link." - }, - "favourites": "Favourites", - "game": { - "status": "Status", - "store": "Store", - "title": "Game Title" - }, - "gameRelease": { - "alpha": "Alpha", - "beta": "Beta", - "demo": "Demo", - "main": "Main", - "prototype": "Prototype" - }, - "generic": { - "error": { - "component": "No Games found - Try to logout and login again or one of the options bellow" - }, - "library": { - "refresh": "Refresh Library" - } - }, - "globalSettings": "Global Settings", - "GOG": "GOG", - "header": { - "show_available_games": "Show non-available games", - "show_hidden": "Show Hidden", - "store": "Filter Store" - }, - "help": { - "amdfsr": "AMD's FSR helps boost framerate by upscaling lower resolutions in Fullscreen Mode. Image quality increases from 5 to 1 at the cost of a slight performance hit. Enabling may improve performance.", - "custom_themes_path": "Do not use CSS files from untrusted sources. When in doubt, ask for a review in our Discord channel.", - "custom_themes_wiki": "Check the Wiki for more details on adding custom themes. Click here.", - "disable_logs": "Toggle this checkbox ON to disable most of the writes to log files (critical information is always logged). Make sure to turn OFF this setting before reporting any issue.", - "dxvk": "DXVK is a Vulkan-based translational layer for DirectX 9, 10 and 11 games. Enabling may improve compatibility. Might cause issues especially for older DirectX games.", - "dxvkfpslimit": "Sets a frame rate cap for DXVK games", - "dxvknvapi": "DXVK-NVAPI is an implementation of NVAPI built on top of DXVK and the linux native NVAPI, it allows for the usage of DLSS on Nvidia GPUs.", - "esync": "Esync aims to reduce wineserver overhead in CPU-intensive games. Enabling may improve performance.", - "fsync": "Fsync aims to reduce wineserver overhead in CPU-intensive games. Enabling may improve performance on supported Linux kernels.", - "game_language": { - "fallback": "Leave blank to use HyperPlay's language.", - "in_game_config": "Not all games support this configuration, some have in-game language setting.", - "valid_codes": "Valid language codes are game-dependant." - }, - "gamemode": "Feral GameMode applies automatic and temporary tweaks to the system when running games. Enabling may improve performance.", - "general": "Sync with EGL if you have a working installation of the Epic Games Launcher elsewhere and want to import your games to avoid downloading them again.", - "mangohud": "MangoHUD is an overlay that displays and monitors FPS, temperatures, CPU/GPU load and other system resources.", - "other": { - "part4": "Use the ", - "part5": "Game Arguments", - "part6": " to be called after the launch command, for instance: ", - "part7": " to skip the launcher in some games, etc." - }, - "preferSystemLibs": "Custom Wine versions (Wine-GE, Wine-Lutris) are shipped with their library dependencies. By enabling this option, these shipped libraries will be ignored and Wine will load system libraries instead. Warning! Issues may occur if dependencies are not met.", - "primerun": "Use dedicated graphics card to render game on multi-GPU systems. Only needed on gaming laptops or desktops that use a headless GPU for rendering (NVIDIA Optimus, AMD CrossFire)", - "steam_path": { - "info": "This path lets HyperPlay determine what version of Proton Steam uses, for adding non-Steam games to Steam." - }, - "steamruntime": "Custom libraries provided by Steam to help run Linux and Windows (Proton) games. Enabling might improve compatibility.", - "sync": { - "part1": "HyperPlay tries to guess the right save folder and this will work on the majority of cases. In case the folder is wrong, use the override box to change it.", - "part2": "In case you change the prefix folder for Wine or Proton, you will need to check the path again since Proton uses a different prefix (/pfx) and username (steamuser). So you can simple erase the current path get out of the sync settings page and get back again for HyperPlay to guess the folder one more time with the right prefix.", - "part3": "Manual Sync: Choose Download to download the games saves stored on the Cloud. Upload to upload the local ones to the cloud. Force Download and Force Upload will ignore the version that is locally or on the cloud.", - "part4": "Sync Saves Automatically will sync the saves every time you Start a Game and after finishing playing." - }, - "vkd3d": "VKD3D is a Vulkan-based translational layer for DirectX 12 games. Enabling may improve compatibility significantly. Has no effect on older DirectX games.", - "wine": { - "part1": "HyperPlay searches for versions of Wine, Proton, and CrossOver in the following folders:", - "part2": "For other places, use a symbolic link to one of these folders" - } - }, - "hyperplay": { - "accesscodes": { - "error": { - "validation": "Access code is invalid" - }, - "success": { - "validation": "Success! Access code is valid" - } - }, - "analyticsOff": "Analytics is turned off", - "analyticsOn": "Analytics is turned on", - "browserImport": { - "appId": "App Id", - "profile": "Profile" - }, - "buttons": { - "agree": "I agree", - "noThanks": "No Thanks" - }, - "changeWallet": "Change wallet", - "connectWallet": "Connect wallet", - "copyUrl": "Copy URL", - "currentWallet": "Current wallet", - "discordApp": "Discord", - "folder": "Folder", - "gamecard": { - "extracting": "Extracting...", - "installed": "Ready to play", - "installing": "Downloading...", - "paused": "Paused" - }, - "misc": "Never", - "onboarding": { - "analytics": { - "anonymized": "Send anonymized click & game interaction;", - "body": "HyperPlay would like to gather usage data to better understand how our users interact with the application. This information helps us understand how you use the app and lets us make HyperPlay even better for you.", - "hyperplayWill": "HyperPlay will:", - "neverCollectIP": " collect your full IP address;", - "neverCollectPersonal": " collect keys, addresses, balances, hashes, or any personal information;", - "neverSellData": " sell data for profit. Ever!", - "optOut": "Always allow you to opt-out via Settings;", - "privacyCaption": "This data is aggregated and is therefore anonymous for the purposes of General Data Protection Regulation (EU) 2016/679. For more information in relation to our privacy practices, please see our ", - "privacyPolicyHere": "Privacy Policy here.", - "title": "Help Us improve HyperPlay!" - }, - "connectAgain": "Connect again", - "connectionCanceled": { - "description": "Please confirm the connection request on your mobile wallet to proceed.", - "title": "Connection canceled!" - }, - "connectionConnected": { - "description": "Your wallet is connected. You are ready to game.", - "title": "Wallet connected!" - }, - "terms": "Terms of Service.", - "walletSelection": { - "pleaseConnect": "Please connect your wallet, or download the Metamask mobile-app to get\n started:", - "screens": { - "import": { - "cantFindProfile": "Can't find your browser profile?", - "createNewWallet": "Create new MM extension wallet", - "details": "By importing, your MetaMask installation and settings will be imported into HyperPlay.", - "title": "Select the browser to import from", - "useRecoveryPhrase": "Access with secret recovery phrase" - }, - "info": { - "createWalletCTA": "Create a wallet", - "createWalletDescription": "Click in “Create a wallet” below if you do not have a wallet or want to create a new one:", - "digitalAssets": { - "details": "Wallets are used to send, receive, store, and display digital assets like tokens and NFTs.", - "title": "A Home for your Digital Assets" - }, - "login": { - "details": "An alternative to creating new accounts and passwords on every website, just connect your wallet instead.", - "title": "A New Way to Log In" - }, - "skip": "Skip for now", - "title": "What is a wallet?" - }, - "scan": { - "details": "Create an encrypted communication channel. Your keys will never be shared with HyperPlay.", - "dontHaveWallet": "Don’t have a wallet?", - "getMetamask": "Get MetaMask", - "title": "Scan QR with ", - "updateWarning": "Having issues? Make sure MetaMask is up to date." - } - }, - "title": "Wallet Connections" - }, - "welcome": { - "text": { - "bugs": "Please note that HyperPlay is a public alpha. Many features are still\n in development, and there will be bugs.", - "communityCTA_1": "We'd love your feedback and to have you join us in our", - "communityCTA_2": "community. Together, let's shape the future of gaming!", - "construction": "HyperPlay is under construction.", - "description": "HyperPlay is a game launcher and game store aggregator from the\n future. With HyperPlay, you can carry your wallet, tokens, and assets\n into every game. HyperPlay supports the entire library of the Epic\n Store, GOG, and our own HyperPlay store. By using HyperPlay, you agree\n to our" - }, - "title": "Welcome to HyperPlay Early Access!" - } - }, - "otp": "One Time Passcode", - "publicAlpha": "Public Alpha", - "turnAnalyticsOff": "Turn off", - "turnAnalyticsOn": "Turn on", - "viewFullscreen": "View fullscreen", - "viewItem": "View {{item}}", - "viewPortfolio": "View portfolio", - "wallet": { - "connected": "Connected", - "notConnected": "Not connected" - } - }, - "HyperPlay": "", - "hyperplayOverlay": { - "chainRequest": { - "CONFIRMED": "Custom network added", - "FAILED": "Custom network canceled", - "INITIATED": "Custom network request" - }, - "closeOverlay": "Press {{overlayKeyMod}} + X to close the overlay", - "description": { - "CONFIRMED": "The transaction was successfully confirmed!", - "FAILED": "The transaction was canceled or not submitted, please try again", - "INITIATED": "A wallet confirmation is pending in your mobile wallet", - "PENDING": "Waiting for blockchain confirmation. We'll let you know when it's confirmed" - }, - "extensionNotification": { - "DESCRIPTION": "Press {{overlayKeyMod}} + X to see this transaction", - "TITLE": "Transaction requested" - }, - "greeting": { - "description": "HyperPlay Overlay is ready! Press {{overlayKeyMod}} + X to show or hide it.", - "title": "HyperPlay Overlay" - }, - "signatureRequest": { - "CONFIRMED": "Signature submitted", - "FAILED": "Signature interrupted", - "INITIATED": "Signature request pending" - }, - "txnRequest": { - "CONFIRMED": "Transaction confirmed", - "FAILED": "Transaction interrupted", - "INITIATED": "Transaction request pending", - "PENDING": "Transaction submitted" - }, - "walletWatch": { - "CONFIRMED": "Custom token added", - "FAILED": "Custom token request canceled", - "INITIATED": "Add custom token request pending" - } - }, - "info": { - "hyperplay": { - "version": "HyperPlay Version" - }, - "save-sync": { - "searching": "Trying to detect the correct save folder (click to cancel)" - }, - "settings": "Settings are saved automatically", - "version": "Wine Version" - }, - "infobox": { - "help": "Help", - "requirements": "System Requirements", - "warning": "Warning", - "wine-path": "Wine Path", - "wine-path-invalid": "Wine Path is invalid, please select another one.", - "wine-path-none-found": "No Wine version was found, download one from the Compatibility Manager", - "wine-prefix": { - "title": "Wine Prefix" - }, - "wine-repfix": { - "message": "Wine uses what is called a WINEPREFIX to encapsulate Windows applications. This prefix contains the Wine configuration files and a reproduction of the file hierarchy of C: (the main disk on a Windows OS). In this reproduction of the C: drive, your game save files and dependencies installed via winetricks are stored." - } - }, - "library": { - "alphabeticalAZ": "Alphabetical A-Z", - "alphabeticalZA": "Alphabetical Z-A", - "label": "Library", - "refresh": "Refresh", - "sortByStatus": "Sort by Status" - }, - "loading": { - "default": "Loading", - "website": "Loading Website" - }, - "login": { - "alternative_method": "Alternative Login Method", - "amazon": "Amazon Login", - "epic": "Epic Games Login", - "gog": "GOG Login", - "message": "Login with your platform. You can login to more than one platform at the same time." - }, - "message": { - "sync": "Sync Complete", - "unsync": "Unsync Complete" - }, - "notify": { - "error": { - "move": "Error Moving the Game", - "reparing": "Error Repairing" - }, - "finished": { - "add": { - "steam": { - "corrupt": "{{game}} could not be added to all found Steam users. See logs for more info. A restart of Steam is required for changes to take effect.", - "success": "{{game}} was successfully added to Steam. A restart of Steam is required for changes to take effect.", - "title": "Added to Steam" - } - }, - "remove": { - "steam": { - "corrupt": "{{game}} could not be removed from all found Steam users. See logs for more info. A restart of Steam is required for changes to take effect.", - "success": "{{game}} was successfully removed from Steam. A restart of Steam is required for changes to take effect.", - "title": "Removed from Steam" - } - }, - "reparing": "Finished Repairing" - }, - "install": { - "canceled": "Installation Canceled", - "error": "Installation Failed", - "finished": "Installation Finished", - "imported": "Game Imported", - "paused": "Installation Paused", - "startInstall": "Installation Started", - "stopped": "Installation stopped" - }, - "moved": "Finished Moving", - "moving": "Moving Game", - "refresh": { - "error": "Couldn't fetch releases from upstream, maybe because of Github API restrictions! Try again later." - }, - "uninstalled": "Uninstalled", - "update": { - "canceled": "Update Canceled", - "finished": "Update Finished", - "paused": "Update Paused", - "started": "Update Started", - "stopped": "Update stopped" - } - }, - "offline-message": { - "hint": "We are checking the connectivity against:{{newline}}github.com,{{newline}}gog.com,{{newline}}store.epicgames.com and{{newline}}cloudflare-dns.com", - "ignore": "Ignore", - "offline": "Offline", - "offline-retry-in": "Offline. Retrying in {{seconds}} seconds.", - "retrying": "Retrying" - }, - "Open": "", - "options": { - "advanced": { - "key": "Variable Name", - "placeHolderKey": "NAME", - "placeHolderValue": "E.g.: Path/To/ExtraFiles", - "title": "Environment Variables", - "value": "Value" - }, - "env_variables": { - "error": { - "empty_key": "Variable names can't be empty", - "equal_sign_in_key": "Variable names can't contain the \"=\" sign", - "space_in_key": "Variable names can't contain spaces" - }, - "example": "Do NOT include the \"=\" sign, e.g: for a setting like \"MY_FLAG=123\", set MY_FLAG in NAME and 123 in VALUE.", - "info": "Set environment variables to append to the command." - }, - "gameargs": { - "placeholder": "Put here the Launcher Arguments", - "title": "Game Arguments (To run after the command):" - }, - "quote-args-with-spaces": "Warning: Make sure to quote args with spaces! E.g.: \"path/with spaces/\"", - "wrapper": { - "args": "Arguments", - "arguments_example": "Arguments example: --arg; --extra-file=\"file-path/ with/spaces\"", - "exe": "Wrapper", - "placeHolderKey": "New Wrapper", - "placeHolderValue": "Wrapper Arguments", - "title": "Wrapper command:" - } - }, - "other": { - "gogdl-version": "GOGDL Version: ", - "legendary-version": "Legendary Version: ", - "weblate": "Help Translate HyperPlay." - }, - "Other": "Other", - "overlay": { - "EXTERNAL_WALLET_CONNECTED": "You are connected to HyperPlay with an external wallet. \n \n To approve transactions in the HyperPlay overlay, you will need to connect to HyperPlay with the MetaMask Extension." - }, - "placeholder": { - "alt-gogdl-bin": "Using built-in GOGDL binary...", - "alt-legendary-bin": "Using built-in Legendary binary...", - "custom_themes_path": "Select the path to look for custom CSS files", - "dxvkfpsvalue": "Positive integer value (e.g. 30, 60, ...)", - "egs-prefix": "Prefix where EGS is installed", - "prefered_language": "2-char code (i.e.: \"en\" or \"fr\")" - }, - "please-wait": "Please wait...", - "progress": "Progress", - "queue": { - "label": { - "canceled": "Canceled", - "clear": "Clear List", - "downloading": "Downloading", - "empty": "Nothing to download", - "finished": "Completed", - "pause": "Pause download", - "queued": "Queued", - "remove": "Remove from Downloads", - "resume": "Resume download" - } - }, - "Recent": "Played Recently", - "search": "Search for Games", - "setting": { - "adddesktopshortcuts": "Add desktop shortcuts automatically", - "addgamestoapplications": "Add games to Applications automatically", - "addgamestostartmenu": "Add games to start menu automatically", - "addgamestosteam": "Add games to Steam automatically", - "alt-gogdl-bin": "Choose an Alternative GOGDL Binary to use", - "alt-legendary-bin": "Choose an Alternative Legendary Binary", - "autodxvk": "Auto Install/Update DXVK on Prefix", - "autodxvknvapi": "Auto Install/Update DXVK-NVAPI on Prefix", - "autosync": "Autosync Saves", - "autoUpdateGames": "Automatically update games", - "autovkd3d": "Auto Install/Update VKD3D on Prefix", - "change-target-exe": "Select an alternative EXE to run", - "checkForUpdatesOnStartup": "Check for HyperPlay Updates on Startup", - "crossover-version": "Crossover/Wine Version", - "custom_themes_path": "Custom Themes Path", - "customWineProton": "Custom Wine/Proton Paths", - "darktray": "Use Dark Tray Icon", - "default-install-path": "Default Installation Path", - "default-steam-path": "Default Steam path", - "defaultWinePrefix": "Set Folder for new Wine Prefixes", - "disable_controller": "Disable Hyperplay navigation using controller", - "disable_logs": "Disable Logs", - "discordRPC": "Enable Discord Rich Presence", - "download-no-https": "Download games without HTTPS (useful for CDNs e.g. LanCache)", - "dxvkfpslimit": "Limit FPS (DX9, 10 and 11)", - "egs-sync": "Sync with Installed Epic Games", - "enableFSRHack": "Enable FSR Hack (Wine version needs to support it)", - "eosOverlay": { - "cancelInstall": "Cancel", - "checkForUpdates": "Check for updates", - "checkingForUpdates": "Checking for updates...", - "currentVersion": "Current Version: {{version}}", - "disable": "Disable", - "enable": "Enable", - "install": "Install", - "installed": "The Epic Overlay is installed", - "installing": "The Epic Overlay is being installed...", - "latestVersion": "Latest Version: {{version}}", - "notInstalled": "The Epic Overlay is not installed", - "notInstalledMsg": "The Epic Overlay is not installed. Do you want to install it now?", - "notInstalledTitle": "Overlay not installed", - "remove": "Uninstall", - "removeConfirm": "Are you sure you want to uninstall the Epic Overlay?", - "removeConfirmTitle": "Confirm overlay removal", - "updateNow": "Update", - "updating": "Updating..." - }, - "esync": "Enable Esync", - "exit-to-tray": "Exit to System Tray", - "experimental_features": { - "enableNewShinyFeature": "New shiny feature" - }, - "FsrSharpnessStrenght": "FSR Sharpness Strength", - "fsync": "Enable Fsync", - "gamemode": "Use GameMode (Feral Game Mode needs to be installed)", - "ignoreGameUpdates": "Ignore game updates", - "language": "Choose Language", - "library_top_option": { - "disabled": "Disabled", - "favourites": "Favourite Games", - "recently_played": "Recently Played Games", - "recently_played_installed": "Recently Played Games (Only Installed)" - }, - "library_top_section": "Library Top Section", - "log": { - "copy-to-clipboard": "Copy log content to clipboard", - "current-log": "Current Log", - "instructions_title": "How to report a problem?", - "instructions-part-01": "If you encounter any issues while using HyperPlay, we have two designated areas to report your issues in our Discord Server. If you're a player, please report any problems by visiting the player-support-forum. If you are a game dev, please report any problems by visiting the dev-support-forum.", - "instructions-part-02": "To help us diagnose and fix the problem as quickly as possible, please provide as much information as possible, including a copy of your logs. Our support team will monitor both channels and do their best to respond to your issue as quickly as possible. Thank you for your patience and understanding while we work to resolve any problems you may encounter.", - "last-log": "Last Log", - "no-file": "No log file found", - "show-in-folder": "Show log file in folder" - }, - "mangohud": "Enable Mangohud (Mangohud needs to be installed)", - "manualsync": { - "download": "Download", - "forcedownload": "Force Download", - "forceupload": "Force Upload", - "sync": "Sync", - "syncing": "Syncing", - "title": "Manual Sync Saves", - "upload": "Upload" - }, - "maxRecentGames": "Played Recently to Show", - "maxworkers": "Maximum Number of Workers when downloading", - "minimize-on-launch": "Minimize HyperPlay After Game Launch", - "offlinemode": "Run Game Offline", - "prefered_language": "Prefered Language (Language Code)", - "preferSystemLibs": "Prefer system libraries", - "primerun": { - "confirmation": { - "message": "Only one graphics card was detected in this system. Please note that this option is intended for multi-GPU systems with headless GPUs (like laptops). On single-GPU systems, the GPU is automatically used & enabling this option can cause issues. Do you really want to enable this option?", - "title": "Only 1 GPU detected" - }, - "description": "Use Dedicated Graphics Card" - }, - "runexe": { - "message": "Drag and Drop Files here", - "title": "Run EXE on Prefix" - }, - "savefolder": { - "not-found": "Save folder not found, please select it manually (click to retry)", - "placeholder": "Select the exact save games folder", - "warning": "Please check twice if the path is correct (click to retry)" - }, - "select_theme": "Select Theme", - "showfps": "Show FPS (DX9, 10 and 11)", - "showMetalOverlay": "Show Stats Overlay", - "start-in-tray": "Start Minimized", - "steamruntime": "Use Steam Runtime", - "winecrossoverbottle": "CrossOver Bottle", - "wineprefix": "WinePrefix folder", - "wineversion": "Wine Version" - }, - "settings": { - "battlEyeRuntime": { - "installing": "Installing BattlEye Runtime...", - "name": "BattlEye AntiCheat Runtime" - }, - "clear-cache": "Clear HyperPlay Cache", - "copiedToClipboard": "Copied to Clipboard!", - "copyToClipboard": "Copy All Settings to Clipboard", - "default_hint": "Changes in this section only apply as default values when installing games. If you want to change the settings of an already installed game, use the Settings button in the game page.", - "eacRuntime": { - "gameModeRequired": { - "message": "GameMode is required for the EAC runtime to work on Flatpak. Do you want to enable it now?", - "title": "GameMode required" - }, - "installing": "Installing EAC Runtime...", - "name": "EasyAntiCheat Runtime" - }, - "experimental_features": { - "title": "Experimental Features" - }, - "gameMode": { - "eacRuntimeEnabled": { - "message": "The EAC runtime is enabled, which won't function correctly without GameMode. Do you want to disable the EAC Runtime and GameMode?", - "title": "EAC runtime enabled" - } - }, - "gamesSettings": "Games Settings", - "log": { - "long-log-hint": "Log truncated, last 1000 lines are shown!" - }, - "navbar": { - "advanced": "Advanced", - "general": "General", - "log": "Log", - "other": "Other", - "sync": "Cloud Saves Sync" - }, - "open-config-file": "Open Config File", - "reset-hyperplay": "Reset HyperPlay", - "saves": { - "warning": "Cloud Saves feature is in Beta, please backup your saves before syncing (in case something goes wrong)" - }, - "wine": { - "manager": { - "title": "" - } - } - }, - "Settings": "Settings", - "sideload": { - "warningMessage": "Side-loading a game is a feature intended for developers and experienced power users. Side-loading an installer that contains malware could compromise your computer and lead to theft of funds.", - "warningTitle": "Important" - }, - "status": { - "installing": "Installing", - "logging": "Logging In...", - "preparing_login": "Preparing Login... ", - "processing": "Processing files, please wait" - }, - "store": "Epic Store", - "title": { - "allGames": "All Games" - }, - "toolbox": { - "settings": { - "default-wineprefix": "Select the default prefix folder for new configs", - "wineprefix": "Select a Folder for new Wine Prefixes" - } - }, - "tooltip": { - "addpath": "Add New Path", - "removepath": "Remove Path" - }, - "tray": { - "about": "About", - "quit": "Quit", - "reload": "Reload", - "show": "Show" - }, - "two_col_table": { - "save_hint": "Changes in this table are not saved automatically. Click the + button" - }, - "userselector": { - "logging_out": "Logging out", - "logout": "Log out", - "logout_confirmation": "Are you sure you want to log out?", - "manageaccounts": "Manage Accounts", - "quit": "Quit" - }, - "webview": { - "controls": { - "back": "Go back", - "forward": "Go forward", - "openInBrowser": "Open in browser", - "reload": "Reload page" - } - }, - "wiki_info": { - "not_found": "We couldn't find extra information." - }, - "wine": { - "actions": "Action", - "manager": { - "not-found": "No Wine versions found. Please click the refresh icon to try again.", - "title": "Compatibility Layer ", - "unzipping": "Unzipping" - }, - "release": "Release Date", - "size": "Size" - } -} +{ + "accessibility": { + "actions_font_family_no_default": "Actions Font Family (Default: ", + "all_tiles_in_color": "Show all game tiles in color", + "content_font_family_no_default": "Content Font Family (Default: ", + "fonts": "Fonts", + "title": "Accessibility", + "zoom": "Zoom" + }, + "accounts": "accounts", + "achievements": { + "progress": { + "minted": "on chain", + "notMinted": "off chain" + } + }, + "add_game": "Add Game", + "All": "All", + "ALL": "ALL", + "amazon": "", + "Amazon": "Amazon", + "Amazon Games": "Amazon Games", + "analytics": "Analytics", + "anticheat": { + "anticheats": "Anticheats", + "may_not_work": "It may not work due to denied or broken anticheat support.", + "reference": "Reference", + "source": "Source", + "status": "Status", + "title": "This game includes anticheat software" + }, + "box": { + "cache-cleared": { + "message": "HyperPlay cache cleared.", + "title": "Cache cleared" + }, + "choose": "Choose", + "choose-egs-prefix": "Choose Prefix where EGS is installed", + "choose-gogdl-binary": "Select GOGDL Binary (needs restart)", + "choose-legendary-binary": "Select Legendary binary", + "customWine": "Select the Wine or Proton binary", + "default-install-path": "Choose Default Install Path", + "default-steam-path": "Steam path.", + "dontShowAgain": "Don't show again", + "downloadNow": "Download now", + "error": { + "add": { + "steam": { + "body": "Adding {{game}} to Steam failed with:{{newLine}} {{error}}", + "title": "Adding Error" + } + }, + "credentials": { + "message": "Your credentials have expired, please log out and log in again." + }, + "cx-bottle-not-found": { + "message": "The CrossOver bottle \"{{bottle_name}}\" does not exist, can't launch!", + "title": "CrossOver bottle not found" + }, + "diskspace": { + "message": "Not enough available disk space", + "title": "No Space" + }, + "dxvk": { + "message": "Error installing DXVK/VKD3D! Please check your connection!", + "title": "DXVK/VKD3D error" + }, + "folder-not-found": { + "title": "Game folder appears to be deleted, do you want to remove the game from the installed list?" + }, + "generic": { + "message": "", + "title": "Select EXE to Run" + }, + "launchAborted": "Launch aborted", + "moving": "Error Moving Game {{error}}", + "title": "Error", + "ubisoft-connect": { + "message": "Installation of Ubisoft Connect in the game prefix failed. Check our wiki page at https://github.com/Heroic-Games-Launcher/HeroicGamesLauncher/wiki/How-to-install-Ubisoft-Connect-on-Linux-and-Mac to install it maunally.", + "title": "Ubisoft Connect" + }, + "update": { + "message": "Something went wrong with the update! Please manually uninstall and reinstall HyperPlay.", + "title": "Update Error" + }, + "winetricks": { + "message": "Winetricks returned the following error during execution:{{newLine}}{{error}}", + "title": "Winetricks error" + } + }, + "info": { + "update": { + "changelog": "Open changelog", + "detail": "Do you want to download the update in the background?", + "message": "There is a new Version available!", + "message-finished": "Do you want to restart HyperPlay now?", + "title": "HyperPlay Games Launcher", + "title-finished": "Update Finished" + } + }, + "no": "NO", + "ok": "OK", + "protocol": { + "install": { + "not_installed": "Currently not installed. Install it?" + } + }, + "quit": { + "message": "There are pending operations, are you sure?", + "title": "Exit" + }, + "reset-app": { + "question": { + "message": "Are you sure you want to reset HyperPlay? This will remove all Settings and Caching but won't remove your Installed games or your Epic credentials. Portable versions (AppImage, WinPortable, ...) of HyperPlay needs to be restarted manually afterwards.", + "title": "Reset HyperPlay" + } + }, + "runexe": { + "title": "Select EXE to Run" + }, + "select": { + "button": "Select", + "exe": "Select EXE" + }, + "shortcuts": { + "message": "Shortcuts were created on Desktop and Start Menu", + "message-mac": "Shortcuts were created on the Applications folder", + "message-remove": "Shortcuts were removed from Desktop and Start Menu", + "message-remove-mac": "Shortcuts were removed from the Applications folder", + "title": "Shortcuts" + }, + "sync": { + "button": "Choose", + "error": "Invalid Path", + "title": "Choose the saves directory" + }, + "vcruntime": { + "install": { + "message": "The download links for the Visual C++ Runtimes have been opened. Please install both the x86 and x64 versions." + }, + "notfound": { + "message": "The Microsoft Visual C++ Runtimes are not installed, which are required by some games", + "title": "VCRuntime not installed" + } + }, + "warning": { + "epic": { + "import": "Epic Servers are having major outage right now, the game cannot be imported!", + "install": "Epic Servers are having major outage right now, the game cannot be installed!", + "update": "Epic Servers are having major outage right now, the game cannot be updated!" + }, + "title": "Warning", + "wine-change": { + "message": "We could not find the selected wine version to launch this title ({{selectedWine}}). {{newline}} We found another one, do you want to continue launching using {{foundWine}} ?", + "title": "Wine not found!" + } + }, + "wineprefix": "Choose Wine Prefix Folder", + "yes": "YES" + }, + "button": { + "cancel": "Cancel", + "continue": "Continue", + "download": "Download", + "go_to_library": "Go to Library", + "sync": "Sync", + "syncing": "Syncing", + "unsync": "Unsync" + }, + "controller": { + "hints": { + "back": "Back", + "backspace": "Backspace", + "close_dialog": "Close dialog", + "close_keyboard": "Close keyboard", + "close_options": "Close Options", + "game_details": "Game details", + "game_settings": "Game settings", + "install_game": "Install game", + "move_cursor": "Move cursor", + "open_virtual_keyboard": "Open virtual keyboard", + "options": "Options", + "play_game": "Play game", + "scroll": "Scroll", + "select": "Select", + "space": "Space", + "update_game": "Update game" + } + }, + "dlc": { + "actions": "Actions", + "installDlcs": "Install all DLCs", + "noDlcFound": "No DLCs found", + "size": "Size", + "title": "Title" + }, + "dlcs": { + "label": "Select DLCs to install:" + }, + "download-manager": { + "ETA": "Estimated Time", + "install-type": { + "install": "Install", + "update": "Update" + }, + "label": { + "disk": "Disk", + "speed": "Download" + }, + "queue": { + "end-time": "Finished at", + "queue-time": "Added at", + "start-time": "Started at", + "type": "Type" + }, + "title": "Downloads" + }, + "epic": { + "offline-notification-body": "Online services may not work fully as Epic Games servers are offline!", + "offline-notification-title": "offline" + }, + "Epic Games": "Epic Games", + "error": "Error", + "exit_game": "Exit Game", + "externalLink": { + "dontAskAgain": "Don't ask again", + "warning": "You are about to open an external link." + }, + "favourites": "Favourites", + "game": { + "status": "Status", + "store": "Store", + "title": "Game Title" + }, + "gameRelease": { + "alpha": "Alpha", + "beta": "Beta", + "demo": "Demo", + "main": "Main", + "prototype": "Prototype" + }, + "generic": { + "error": { + "component": "No Games found - Try to logout and login again or one of the options bellow" + }, + "library": { + "refresh": "Refresh Library" + } + }, + "globalSettings": "Global Settings", + "GOG": "GOG", + "header": { + "show_available_games": "Show non-available games", + "show_hidden": "Show Hidden", + "store": "Filter Store" + }, + "help": { + "amdfsr": "AMD's FSR helps boost framerate by upscaling lower resolutions in Fullscreen Mode. Image quality increases from 5 to 1 at the cost of a slight performance hit. Enabling may improve performance.", + "custom_themes_path": "Do not use CSS files from untrusted sources. When in doubt, ask for a review in our Discord channel.", + "custom_themes_wiki": "Check the Wiki for more details on adding custom themes. Click here.", + "disable_logs": "Toggle this checkbox ON to disable most of the writes to log files (critical information is always logged). Make sure to turn OFF this setting before reporting any issue.", + "dxvk": "DXVK is a Vulkan-based translational layer for DirectX 9, 10 and 11 games. Enabling may improve compatibility. Might cause issues especially for older DirectX games.", + "dxvkfpslimit": "Sets a frame rate cap for DXVK games", + "dxvknvapi": "DXVK-NVAPI is an implementation of NVAPI built on top of DXVK and the linux native NVAPI, it allows for the usage of DLSS on Nvidia GPUs.", + "esync": "Esync aims to reduce wineserver overhead in CPU-intensive games. Enabling may improve performance.", + "fsync": "Fsync aims to reduce wineserver overhead in CPU-intensive games. Enabling may improve performance on supported Linux kernels.", + "game_language": { + "fallback": "Leave blank to use HyperPlay's language.", + "in_game_config": "Not all games support this configuration, some have in-game language setting.", + "valid_codes": "Valid language codes are game-dependant." + }, + "gamemode": "Feral GameMode applies automatic and temporary tweaks to the system when running games. Enabling may improve performance.", + "general": "Sync with EGL if you have a working installation of the Epic Games Launcher elsewhere and want to import your games to avoid downloading them again.", + "mangohud": "MangoHUD is an overlay that displays and monitors FPS, temperatures, CPU/GPU load and other system resources.", + "other": { + "part4": "Use the ", + "part5": "Game Arguments", + "part6": " to be called after the launch command, for instance: ", + "part7": " to skip the launcher in some games, etc." + }, + "preferSystemLibs": "Custom Wine versions (Wine-GE, Wine-Lutris) are shipped with their library dependencies. By enabling this option, these shipped libraries will be ignored and Wine will load system libraries instead. Warning! Issues may occur if dependencies are not met.", + "primerun": "Use dedicated graphics card to render game on multi-GPU systems. Only needed on gaming laptops or desktops that use a headless GPU for rendering (NVIDIA Optimus, AMD CrossFire)", + "steam_path": { + "info": "This path lets HyperPlay determine what version of Proton Steam uses, for adding non-Steam games to Steam." + }, + "steamruntime": "Custom libraries provided by Steam to help run Linux and Windows (Proton) games. Enabling might improve compatibility.", + "sync": { + "part1": "HyperPlay tries to guess the right save folder and this will work on the majority of cases. In case the folder is wrong, use the override box to change it.", + "part2": "In case you change the prefix folder for Wine or Proton, you will need to check the path again since Proton uses a different prefix (/pfx) and username (steamuser). So you can simple erase the current path get out of the sync settings page and get back again for HyperPlay to guess the folder one more time with the right prefix.", + "part3": "Manual Sync: Choose Download to download the games saves stored on the Cloud. Upload to upload the local ones to the cloud. Force Download and Force Upload will ignore the version that is locally or on the cloud.", + "part4": "Sync Saves Automatically will sync the saves every time you Start a Game and after finishing playing." + }, + "vkd3d": "VKD3D is a Vulkan-based translational layer for DirectX 12 games. Enabling may improve compatibility significantly. Has no effect on older DirectX games.", + "wine": { + "part1": "HyperPlay searches for versions of Wine, Proton, and CrossOver in the following folders:", + "part2": "For other places, use a symbolic link to one of these folders" + } + }, + "hyperplay": { + "accesscodes": { + "error": { + "validation": "Access code is invalid" + }, + "success": { + "validation": "Success! Access code is valid" + } + }, + "achievements": { + "addThisGame": "Add this game", + "freeMints": "Free Mints", + "gamesToMint": "Games to mint", + "noAchievements": { + "doubleCheckMessage": "It looks like we couldn't find any games in your Steam account at the moment. Just a quick reminder to double-check that your game details are set to public. This way, we can access your achievements and provide you with the best experience.", + "oops": "Oops!" + } + }, + "analyticsOff": "Analytics is turned off", + "analyticsOn": "Analytics is turned on", + "browserImport": { + "appId": "App Id", + "profile": "Profile" + }, + "buttons": { + "agree": "I agree", + "noThanks": "No Thanks" + }, + "changeWallet": "Change wallet", + "connectWallet": "Connect wallet", + "copyUrl": "Copy URL", + "currentWallet": "Current wallet", + "discordApp": "Discord", + "folder": "Folder", + "gamecard": { + "extracting": "Extracting...", + "installed": "Ready to play", + "installing": "Downloading...", + "paused": "Paused" + }, + "misc": "Never", + "onboarding": { + "analytics": { + "anonymized": "Send anonymized click & game interaction;", + "body": "HyperPlay would like to gather usage data to better understand how our users interact with the application. This information helps us understand how you use the app and lets us make HyperPlay even better for you.", + "hyperplayWill": "HyperPlay will:", + "neverCollectIP": " collect your full IP address;", + "neverCollectPersonal": " collect keys, addresses, balances, hashes, or any personal information;", + "neverSellData": " sell data for profit. Ever!", + "optOut": "Always allow you to opt-out via Settings;", + "privacyCaption": "This data is aggregated and is therefore anonymous for the purposes of General Data Protection Regulation (EU) 2016/679. For more information in relation to our privacy practices, please see our ", + "privacyPolicyHere": "Privacy Policy here.", + "title": "Help Us improve HyperPlay!" + }, + "connectAgain": "Connect again", + "connectionCanceled": { + "description": "Please confirm the connection request on your mobile wallet to proceed.", + "title": "Connection canceled!" + }, + "connectionConnected": { + "description": "Your wallet is connected. You are ready to game.", + "title": "Wallet connected!" + }, + "terms": "Terms of Service.", + "walletSelection": { + "pleaseConnect": "Please connect your wallet, or download the Metamask mobile-app to get\n started:", + "screens": { + "import": { + "cantFindProfile": "Can't find your browser profile?", + "createNewWallet": "Create new MM extension wallet", + "details": "By importing, your MetaMask installation and settings will be imported into HyperPlay.", + "title": "Select the browser to import from", + "useRecoveryPhrase": "Access with secret recovery phrase" + }, + "info": { + "createWalletCTA": "Create a wallet", + "createWalletDescription": "Click in “Create a wallet” below if you do not have a wallet or want to create a new one:", + "digitalAssets": { + "details": "Wallets are used to send, receive, store, and display digital assets like tokens and NFTs.", + "title": "A Home for your Digital Assets" + }, + "login": { + "details": "An alternative to creating new accounts and passwords on every website, just connect your wallet instead.", + "title": "A New Way to Log In" + }, + "skip": "Skip for now", + "title": "What is a wallet?" + }, + "scan": { + "details": "Create an encrypted communication channel. Your keys will never be shared with HyperPlay.", + "dontHaveWallet": "Don’t have a wallet?", + "getMetamask": "Get MetaMask", + "title": "Scan QR with ", + "updateWarning": "Having issues? Make sure MetaMask is up to date." + } + }, + "title": "Wallet Connections" + }, + "welcome": { + "text": { + "bugs": "Please note that HyperPlay is a public alpha. Many features are still\n in development, and there will be bugs.", + "communityCTA_1": "We'd love your feedback and to have you join us in our", + "communityCTA_2": "community. Together, let's shape the future of gaming!", + "construction": "HyperPlay is under construction.", + "description": "HyperPlay is a game launcher and game store aggregator from the\n future. With HyperPlay, you can carry your wallet, tokens, and assets\n into every game. HyperPlay supports the entire library of the Epic\n Store, GOG, and our own HyperPlay store. By using HyperPlay, you agree\n to our" + }, + "title": "Welcome to HyperPlay Early Access!" + } + }, + "otp": "One Time Passcode", + "publicAlpha": "Public Alpha", + "Sync": "Sync", + "syncing": "Syncing...", + "turnAnalyticsOff": "Turn off", + "turnAnalyticsOn": "Turn on", + "viewFullscreen": "View fullscreen", + "viewItem": "View {{item}}", + "viewPortfolio": "View portfolio", + "wallet": { + "connected": "Connected", + "notConnected": "Not connected" + } + }, + "HyperPlay": "", + "hyperplayOverlay": { + "chainRequest": { + "CONFIRMED": "Custom network added", + "FAILED": "Custom network canceled", + "INITIATED": "Custom network request" + }, + "closeOverlay": "Press {{overlayKeyMod}} + X to close the overlay", + "description": { + "CONFIRMED": "The transaction was successfully confirmed!", + "FAILED": "The transaction was canceled or not submitted, please try again", + "INITIATED": "A wallet confirmation is pending in your mobile wallet", + "PENDING": "Waiting for blockchain confirmation. We'll let you know when it's confirmed" + }, + "extensionNotification": { + "DESCRIPTION": "Press {{overlayKeyMod}} + X to see this transaction", + "TITLE": "Transaction requested" + }, + "greeting": { + "description": "HyperPlay Overlay is ready! Press {{overlayKeyMod}} + X to show or hide it.", + "title": "HyperPlay Overlay" + }, + "signatureRequest": { + "CONFIRMED": "Signature submitted", + "FAILED": "Signature interrupted", + "INITIATED": "Signature request pending" + }, + "txnRequest": { + "CONFIRMED": "Transaction confirmed", + "FAILED": "Transaction interrupted", + "INITIATED": "Transaction request pending", + "PENDING": "Transaction submitted" + }, + "walletWatch": { + "CONFIRMED": "Custom token added", + "FAILED": "Custom token request canceled", + "INITIATED": "Add custom token request pending" + } + }, + "info": { + "hyperplay": { + "version": "HyperPlay Version" + }, + "save-sync": { + "searching": "Trying to detect the correct save folder (click to cancel)" + }, + "settings": "Settings are saved automatically", + "version": "Wine Version" + }, + "infobox": { + "help": "Help", + "requirements": "System Requirements", + "warning": "Warning", + "wine-path": "Wine Path", + "wine-path-invalid": "Wine Path is invalid, please select another one.", + "wine-path-none-found": "No Wine version was found, download one from the Compatibility Manager", + "wine-prefix": { + "title": "Wine Prefix" + }, + "wine-repfix": { + "message": "Wine uses what is called a WINEPREFIX to encapsulate Windows applications. This prefix contains the Wine configuration files and a reproduction of the file hierarchy of C: (the main disk on a Windows OS). In this reproduction of the C: drive, your game save files and dependencies installed via winetricks are stored." + } + }, + "library": { + "alphabeticalAZ": "Alphabetical A-Z", + "alphabeticalZA": "Alphabetical Z-A", + "label": "Library", + "refresh": "Refresh", + "sortByStatus": "Sort by Status" + }, + "loading": { + "default": "Loading", + "website": "Loading Website" + }, + "login": { + "alternative_method": "Alternative Login Method", + "amazon": "Amazon Login", + "epic": "Epic Games Login", + "gog": "GOG Login", + "message": "Login with your platform. You can login to more than one platform at the same time." + }, + "message": { + "sync": "Sync Complete", + "unsync": "Unsync Complete" + }, + "notify": { + "error": { + "move": "Error Moving the Game", + "reparing": "Error Repairing" + }, + "finished": { + "add": { + "steam": { + "corrupt": "{{game}} could not be added to all found Steam users. See logs for more info. A restart of Steam is required for changes to take effect.", + "success": "{{game}} was successfully added to Steam. A restart of Steam is required for changes to take effect.", + "title": "Added to Steam" + } + }, + "remove": { + "steam": { + "corrupt": "{{game}} could not be removed from all found Steam users. See logs for more info. A restart of Steam is required for changes to take effect.", + "success": "{{game}} was successfully removed from Steam. A restart of Steam is required for changes to take effect.", + "title": "Removed from Steam" + } + }, + "reparing": "Finished Repairing" + }, + "install": { + "canceled": "Installation Canceled", + "error": "Installation Failed", + "finished": "Installation Finished", + "imported": "Game Imported", + "paused": "Installation Paused", + "startInstall": "Installation Started", + "stopped": "Installation stopped" + }, + "moved": "Finished Moving", + "moving": "Moving Game", + "refresh": { + "error": "Couldn't fetch releases from upstream, maybe because of Github API restrictions! Try again later." + }, + "uninstalled": "Uninstalled", + "update": { + "canceled": "Update Canceled", + "finished": "Update Finished", + "paused": "Update Paused", + "started": "Update Started", + "stopped": "Update stopped" + } + }, + "offline-message": { + "hint": "We are checking the connectivity against:{{newline}}github.com,{{newline}}gog.com,{{newline}}store.epicgames.com and{{newline}}cloudflare-dns.com", + "ignore": "Ignore", + "offline": "Offline", + "offline-retry-in": "Offline. Retrying in {{seconds}} seconds.", + "retrying": "Retrying" + }, + "Open": "", + "options": { + "advanced": { + "key": "Variable Name", + "placeHolderKey": "NAME", + "placeHolderValue": "E.g.: Path/To/ExtraFiles", + "title": "Environment Variables", + "value": "Value" + }, + "env_variables": { + "error": { + "empty_key": "Variable names can't be empty", + "equal_sign_in_key": "Variable names can't contain the \"=\" sign", + "space_in_key": "Variable names can't contain spaces" + }, + "example": "Do NOT include the \"=\" sign, e.g: for a setting like \"MY_FLAG=123\", set MY_FLAG in NAME and 123 in VALUE.", + "info": "Set environment variables to append to the command." + }, + "gameargs": { + "placeholder": "Put here the Launcher Arguments", + "title": "Game Arguments (To run after the command):" + }, + "quote-args-with-spaces": "Warning: Make sure to quote args with spaces! E.g.: \"path/with spaces/\"", + "wrapper": { + "args": "Arguments", + "arguments_example": "Arguments example: --arg; --extra-file=\"file-path/ with/spaces\"", + "exe": "Wrapper", + "placeHolderKey": "New Wrapper", + "placeHolderValue": "Wrapper Arguments", + "title": "Wrapper command:" + } + }, + "other": { + "gogdl-version": "GOGDL Version: ", + "legendary-version": "Legendary Version: ", + "weblate": "Help Translate HyperPlay." + }, + "Other": "Other", + "overlay": { + "EXTERNAL_WALLET_CONNECTED": "You are connected to HyperPlay with an external wallet. \n \n To approve transactions in the HyperPlay overlay, you will need to connect to HyperPlay with the MetaMask Extension." + }, + "placeholder": { + "alt-gogdl-bin": "Using built-in GOGDL binary...", + "alt-legendary-bin": "Using built-in Legendary binary...", + "custom_themes_path": "Select the path to look for custom CSS files", + "dxvkfpsvalue": "Positive integer value (e.g. 30, 60, ...)", + "egs-prefix": "Prefix where EGS is installed", + "prefered_language": "2-char code (i.e.: \"en\" or \"fr\")" + }, + "please-wait": "Please wait...", + "progress": "Progress", + "queue": { + "label": { + "canceled": "Canceled", + "clear": "Clear List", + "downloading": "Downloading", + "empty": "Nothing to download", + "finished": "Completed", + "pause": "Pause download", + "queued": "Queued", + "remove": "Remove from Downloads", + "resume": "Resume download" + } + }, + "Recent": "Played Recently", + "search": "Search for Games", + "setting": { + "adddesktopshortcuts": "Add desktop shortcuts automatically", + "addgamestoapplications": "Add games to Applications automatically", + "addgamestostartmenu": "Add games to start menu automatically", + "addgamestosteam": "Add games to Steam automatically", + "alt-gogdl-bin": "Choose an Alternative GOGDL Binary to use", + "alt-legendary-bin": "Choose an Alternative Legendary Binary", + "autodxvk": "Auto Install/Update DXVK on Prefix", + "autodxvknvapi": "Auto Install/Update DXVK-NVAPI on Prefix", + "autosync": "Autosync Saves", + "autoUpdateGames": "Automatically update games", + "autovkd3d": "Auto Install/Update VKD3D on Prefix", + "change-target-exe": "Select an alternative EXE to run", + "checkForUpdatesOnStartup": "Check for HyperPlay Updates on Startup", + "crossover-version": "Crossover/Wine Version", + "custom_themes_path": "Custom Themes Path", + "customWineProton": "Custom Wine/Proton Paths", + "darktray": "Use Dark Tray Icon", + "default-install-path": "Default Installation Path", + "default-steam-path": "Default Steam path", + "defaultWinePrefix": "Set Folder for new Wine Prefixes", + "disable_controller": "Disable Hyperplay navigation using controller", + "disable_logs": "Disable Logs", + "discordRPC": "Enable Discord Rich Presence", + "download-no-https": "Download games without HTTPS (useful for CDNs e.g. LanCache)", + "dxvkfpslimit": "Limit FPS (DX9, 10 and 11)", + "egs-sync": "Sync with Installed Epic Games", + "enableFSRHack": "Enable FSR Hack (Wine version needs to support it)", + "eosOverlay": { + "cancelInstall": "Cancel", + "checkForUpdates": "Check for updates", + "checkingForUpdates": "Checking for updates...", + "currentVersion": "Current Version: {{version}}", + "disable": "Disable", + "enable": "Enable", + "install": "Install", + "installed": "The Epic Overlay is installed", + "installing": "The Epic Overlay is being installed...", + "latestVersion": "Latest Version: {{version}}", + "notInstalled": "The Epic Overlay is not installed", + "notInstalledMsg": "The Epic Overlay is not installed. Do you want to install it now?", + "notInstalledTitle": "Overlay not installed", + "remove": "Uninstall", + "removeConfirm": "Are you sure you want to uninstall the Epic Overlay?", + "removeConfirmTitle": "Confirm overlay removal", + "updateNow": "Update", + "updating": "Updating..." + }, + "esync": "Enable Esync", + "exit-to-tray": "Exit to System Tray", + "experimental_features": { + "enableNewShinyFeature": "New shiny feature" + }, + "FsrSharpnessStrenght": "FSR Sharpness Strength", + "fsync": "Enable Fsync", + "gamemode": "Use GameMode (Feral Game Mode needs to be installed)", + "ignoreGameUpdates": "Ignore game updates", + "language": "Choose Language", + "library_top_option": { + "disabled": "Disabled", + "favourites": "Favourite Games", + "recently_played": "Recently Played Games", + "recently_played_installed": "Recently Played Games (Only Installed)" + }, + "library_top_section": "Library Top Section", + "log": { + "copy-to-clipboard": "Copy log content to clipboard", + "current-log": "Current Log", + "instructions_title": "How to report a problem?", + "instructions-part-01": "If you encounter any issues while using HyperPlay, we have two designated areas to report your issues in our Discord Server. If you're a player, please report any problems by visiting the player-support-forum. If you are a game dev, please report any problems by visiting the dev-support-forum.", + "instructions-part-02": "To help us diagnose and fix the problem as quickly as possible, please provide as much information as possible, including a copy of your logs. Our support team will monitor both channels and do their best to respond to your issue as quickly as possible. Thank you for your patience and understanding while we work to resolve any problems you may encounter.", + "last-log": "Last Log", + "no-file": "No log file found", + "show-in-folder": "Show log file in folder" + }, + "mangohud": "Enable Mangohud (Mangohud needs to be installed)", + "manualsync": { + "download": "Download", + "forcedownload": "Force Download", + "forceupload": "Force Upload", + "sync": "Sync", + "syncing": "Syncing", + "title": "Manual Sync Saves", + "upload": "Upload" + }, + "maxRecentGames": "Played Recently to Show", + "maxworkers": "Maximum Number of Workers when downloading", + "minimize-on-launch": "Minimize HyperPlay After Game Launch", + "offlinemode": "Run Game Offline", + "prefered_language": "Prefered Language (Language Code)", + "preferSystemLibs": "Prefer system libraries", + "primerun": { + "confirmation": { + "message": "Only one graphics card was detected in this system. Please note that this option is intended for multi-GPU systems with headless GPUs (like laptops). On single-GPU systems, the GPU is automatically used & enabling this option can cause issues. Do you really want to enable this option?", + "title": "Only 1 GPU detected" + }, + "description": "Use Dedicated Graphics Card" + }, + "runexe": { + "message": "Drag and Drop Files here", + "title": "Run EXE on Prefix" + }, + "savefolder": { + "not-found": "Save folder not found, please select it manually (click to retry)", + "placeholder": "Select the exact save games folder", + "warning": "Please check twice if the path is correct (click to retry)" + }, + "select_theme": "Select Theme", + "showfps": "Show FPS (DX9, 10 and 11)", + "showMetalOverlay": "Show Stats Overlay", + "start-in-tray": "Start Minimized", + "steamId": "Steam ID", + "steamruntime": "Use Steam Runtime", + "winecrossoverbottle": "CrossOver Bottle", + "wineprefix": "WinePrefix folder", + "wineversion": "Wine Version" + }, + "settings": { + "battlEyeRuntime": { + "installing": "Installing BattlEye Runtime...", + "name": "BattlEye AntiCheat Runtime" + }, + "clear-cache": "Clear HyperPlay Cache", + "copiedToClipboard": "Copied to Clipboard!", + "copyToClipboard": "Copy All Settings to Clipboard", + "default_hint": "Changes in this section only apply as default values when installing games. If you want to change the settings of an already installed game, use the Settings button in the game page.", + "eacRuntime": { + "gameModeRequired": { + "message": "GameMode is required for the EAC runtime to work on Flatpak. Do you want to enable it now?", + "title": "GameMode required" + }, + "installing": "Installing EAC Runtime...", + "name": "EasyAntiCheat Runtime" + }, + "experimental_features": { + "title": "Experimental Features" + }, + "gameMode": { + "eacRuntimeEnabled": { + "message": "The EAC runtime is enabled, which won't function correctly without GameMode. Do you want to disable the EAC Runtime and GameMode?", + "title": "EAC runtime enabled" + } + }, + "gamesSettings": "Games Settings", + "log": { + "long-log-hint": "Log truncated, last 1000 lines are shown!" + }, + "navbar": { + "accounts": "Accounts", + "advanced": "Advanced", + "general": "General", + "log": "Log", + "other": "Other", + "sync": "Cloud Saves Sync" + }, + "open-config-file": "Open Config File", + "reset-hyperplay": "Reset HyperPlay", + "saves": { + "warning": "Cloud Saves feature is in Beta, please backup your saves before syncing (in case something goes wrong)" + }, + "wine": { + "manager": { + "title": "" + } + } + }, + "Settings": "Settings", + "sideload": { + "warningMessage": "Side-loading a game is a feature intended for developers and experienced power users. Side-loading an installer that contains malware could compromise your computer and lead to theft of funds.", + "warningTitle": "Important" + }, + "status": { + "installing": "Installing", + "logging": "Logging In...", + "preparing_login": "Preparing Login... ", + "processing": "Processing files, please wait" + }, + "store": "Epic Store", + "title": { + "allGames": "All Games" + }, + "toolbox": { + "settings": { + "default-wineprefix": "Select the default prefix folder for new configs", + "wineprefix": "Select a Folder for new Wine Prefixes" + } + }, + "tooltip": { + "addpath": "Add New Path", + "removepath": "Remove Path" + }, + "tray": { + "about": "About", + "quit": "Quit", + "reload": "Reload", + "show": "Show" + }, + "two_col_table": { + "save_hint": "Changes in this table are not saved automatically. Click the + button" + }, + "userselector": { + "logging_out": "Logging out", + "logout": "Log out", + "logout_confirmation": "Are you sure you want to log out?", + "manageaccounts": "Manage Accounts", + "manageStore": "Manage stores", + "quit": "Quit" + }, + "webview": { + "controls": { + "back": "Go back", + "forward": "Go forward", + "openInBrowser": "Open in browser", + "reload": "Reload page" + } + }, + "wiki_info": { + "not_found": "We couldn't find extra information." + }, + "wine": { + "actions": "Action", + "manager": { + "not-found": "No Wine versions found. Please click the refresh icon to try again.", + "title": "Compatibility Layer ", + "unzipping": "Unzipping" + }, + "release": "Release Date", + "size": "Size" + } +} diff --git a/src/backend/api/index.ts b/src/backend/api/index.ts index 347cbfe30..889dc6363 100644 --- a/src/backend/api/index.ts +++ b/src/backend/api/index.ts @@ -9,6 +9,7 @@ import * as DownloadManager from './downloadmanager' import * as Extensions from '../hyperplay-extension-helper/api/extensions' import * as Metrics from './metrics' import * as Overlay from 'backend/hyperplay-overlay/api' +import * as Achievements from 'backend/hyperplay-achievements/api' export default { ...Misc, @@ -21,5 +22,6 @@ export default { ...DownloadManager, ...Extensions, ...Metrics, - ...Overlay + ...Overlay, + ...Achievements } diff --git a/src/backend/hyperplay-achievements b/src/backend/hyperplay-achievements new file mode 160000 index 000000000..40b507d5f --- /dev/null +++ b/src/backend/hyperplay-achievements @@ -0,0 +1 @@ +Subproject commit 40b507d5f6e2f6e28cbede130f005a671c63e185 diff --git a/src/backend/logger/logger.ts b/src/backend/logger/logger.ts index ab7f6b701..96e5ac02d 100644 --- a/src/backend/logger/logger.ts +++ b/src/backend/logger/logger.ts @@ -31,7 +31,8 @@ export enum LogPrefix { DownloadManager = 'DownloadManager', ExtraGameInfo = 'ExtraGameInfo', HyperPlay = 'HyperPlay', - Sideload = 'Sideload' + Sideload = 'Sideload', + Achievements = 'Achievements' } export const RunnerToLogPrefixMap = { diff --git a/src/backend/main.ts b/src/backend/main.ts index 4cc52a357..f5b3f0bb5 100644 --- a/src/backend/main.ts +++ b/src/backend/main.ts @@ -190,6 +190,7 @@ import { libraryStore as sideloadLibraryStore } from 'backend/storeManagers/side import { backendEvents } from 'backend/backend_events' import { closeOverlay, toggleOverlay } from 'backend/hyperplay-overlay' import { PROVIDERS } from 'common/types/proxy-types' +import 'backend/hyperplay-achievements' ProxyServer.serverStarted.then(() => console.log('Server started')) diff --git a/src/common/typedefs/ipcBridge.d.ts b/src/common/typedefs/ipcBridge.d.ts index ea80a26e8..a57b96902 100644 --- a/src/common/typedefs/ipcBridge.d.ts +++ b/src/common/typedefs/ipcBridge.d.ts @@ -1,4 +1,10 @@ -import { HyperPlayInstallInfo, DownloadManagerState, LDEnv } from './../types' +import { + HyperPlayInstallInfo, + DownloadManagerState, + Achievement, + SummaryAchievement, + LDEnv +} from './../types' import { ProxiedProviderEventCallback } from './../../backend/hyperplay-proxy-server/providers/types' import { MetaMaskImportOptions } from './../../backend/hyperplay-extension-helper/ipcHandlers/index' import { EventEmitter } from 'node:events' @@ -219,10 +225,24 @@ interface HyperPlayAsyncIPCFunctions { removeTempDownloadFiles: (appName: string) => Promise getImportFolderPath: () => Promise appIsInLibrary: (appName: string, runner: Runner) => Promise + getSummaryAchievements: (options: GetAchievementsOptions) => Promise<{ + data: SummaryAchievement[] + totalPages: number + }> + getIndividualAchievements: ( + options: GetIndividualAchievementsOptions + ) => Promise<{ + data: Achievement[] + currentPage: number + totalPages: number + }> + getAchievementsStats: (options: PlayerOptions) => Promise + syncAchievements: (options: PlayerOptions) => Promise checkHyperPlayAccessCode: ( channelId: number, accessCode: string ) => Promise + shouldShowAchievements: () => Promise get_wallet_state_address: () => Promise get_wallet_state_isConnected: () => Promise get_wallet_state_provider: () => Promise diff --git a/src/common/types.ts b/src/common/types.ts index 930c92205..260a2a5bc 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -121,6 +121,7 @@ export interface AppSettings extends GameSettings { minimizeOnGameLaunch: boolean startInTray: boolean userInfo: UserInfo + steamId: string ldUser: LDUser } @@ -804,6 +805,66 @@ export type AvailablePlatforms = { icon: IconDefinition }[] +export type AchievementStore = 'HYPERPLAY' | 'STEAM' | 'EPIC' + +export interface Achievement { + id: string + apiname: string + achieved: number + unlocktime: number + name: string + defaultvalue: number + displayName: string + hidden: number + description: string + icon: string + icongray: string + iconName: string + gameId: number + gameName: string + gameImageURL: string +} + +export interface SummaryAchievement extends Achievement { + totalAchievementCount: number + mintedAchievementCount: number + mintableAchievementsCount: number + isNewAchievement: boolean + isMinted: boolean + tags: string[] +} + +export type AchievementSort = 'ALPHA_A_TO_Z' | 'ALPHA_Z_TO_A' | 'SORT_BY_STATUS' + +export type AchievementFilter = 'ALL' | 'NEW' | 'MINTED' + +export interface PlayerOptions { + playerStoreId: string + playerAddress: string + store: AchievementStore +} + +export interface GetAchievementsOptions extends PlayerOptions { + filter: AchievementFilter + sort: AchievementSort + page: number + pageSize?: number +} + +export interface GetIndividualAchievementsOptions extends PlayerOptions { + gameId: number + sort: AchievementSort + page: number + pageSize: number +} +export interface AchievementsStats { + newAchievements: number + mintedAchievements: number + totalAchievements: number + totalGames: number + numFreeMints: number +} + export type WalletOnboardCloseReason = | 'skipped' | 'connected' diff --git a/src/common/utils.ts b/src/common/utils.ts index 1038ed76d..34ea06b03 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -11,3 +11,10 @@ export function domainsAreEqual(url: URL, otherUrl: URL) { if (urlDomain === otherUrlDomain) return true return false } + +export function isTimestampInPast(unixTimestamp: number) { + const currentTime = new Date().getTime() + const timestampInMilliseconds = unixTimestamp * 1000 // Convert to milliseconds + + return timestampInMilliseconds < currentTime +} diff --git a/src/frontend/App.tsx b/src/frontend/App.tsx index 252fa3d65..3f1a712f0 100644 --- a/src/frontend/App.tsx +++ b/src/frontend/App.tsx @@ -1,11 +1,12 @@ import React, { useContext } from 'react' import './App.css' -import { HashRouter, Navigate, Route, Routes } from 'react-router-dom' +import { HashRouter, Navigate, Outlet, Route, Routes } from 'react-router-dom' import Login from './screens/Login' import WebView from './screens/WebView' import { GamePage } from './screens/Game' import Library from './screens/Library' +import Achievements from './screens/Achievements' import Sidebar from './components/UI/Sidebar' import Settings from './screens/Settings' import ContextProvider from './state/ContextProvider' @@ -29,6 +30,8 @@ import DownloadToastManager from './components/UI/DownloadToastManager' import TopNavBar from './components/UI/TopNavBar' import StoreNavHandler from './StoreNavHandler' import QaAuthHandler from './QaAuthHandler' +import AchievementsLayout from './screens/Achievements/AchievementsLayout' +import GameAchievementDetails from './screens/Achievements/GameAchievementDetails' import AuthModal from './components/UI/AuthModal' import EmailVerifiedModal from './components/UI/EmailVerifiedModal' import { WalletOnboardCloseReason } from 'common/types' @@ -67,6 +70,20 @@ function App() { element={} /> } /> + + + + } + > + } /> + } + /> + } /> { return ( - + ) } diff --git a/src/frontend/components/UI/Sidebar/components/SidebarLinks/index.tsx b/src/frontend/components/UI/Sidebar/components/SidebarLinks/index.tsx index bbe3b9ac1..138798029 100644 --- a/src/frontend/components/UI/Sidebar/components/SidebarLinks/index.tsx +++ b/src/frontend/components/UI/Sidebar/components/SidebarLinks/index.tsx @@ -9,6 +9,7 @@ import { Images } from '@hyperplay/ui' import libraryState from 'frontend/state/libraryState' import { observer } from 'mobx-react-lite' import storeAuthState from 'frontend/state/storeAuthState' +import AchievementState from 'frontend/state/AchievementState' export default observer(function SidebarLinks() { const location = useLocation() as { pathname: string } @@ -77,11 +78,27 @@ export default observer(function SidebarLinks() { } end to={'/library'} - onClick={async () => handleRefresh()} + onClick={handleRefresh} > + {AchievementState.showAchievements && ( +
+ + classNames('Sidebar__item', { + active: isActive || location.pathname.includes('achievements') + }) + } + end + to={'/achievements'} + onClick={handleRefresh} + > + + +
+ )}
diff --git a/src/frontend/hooks/useSettingsContext.ts b/src/frontend/hooks/useSettingsContext.ts index 686fe2742..bb55b131b 100644 --- a/src/frontend/hooks/useSettingsContext.ts +++ b/src/frontend/hooks/useSettingsContext.ts @@ -6,7 +6,7 @@ import ContextProvider from 'frontend/state/ContextProvider' type Props = { appName: string - gameInfo: GameInfo + gameInfo: GameInfo | null runner: Runner } diff --git a/src/frontend/screens/Achievements/AchievementsLayout/AchievementStores.tsx b/src/frontend/screens/Achievements/AchievementsLayout/AchievementStores.tsx new file mode 100644 index 000000000..e124c5419 --- /dev/null +++ b/src/frontend/screens/Achievements/AchievementsLayout/AchievementStores.tsx @@ -0,0 +1,86 @@ +import React, { useEffect } from 'react' + +import { StoreRow, Images, Button } from '@hyperplay/ui' +import { Flex } from '@mantine/core' + +import styles from './index.module.css' + +import classNames from 'classnames' +import { observer } from 'mobx-react-lite' +import AchievementState from 'frontend/state/AchievementState' +import useSetting from 'frontend/hooks/useSetting' +import walletState from 'frontend/state/WalletState' +import { useTranslation } from 'react-i18next' + +export const AchievementStores = observer(() => { + const [steamId] = useSetting('steamId', '') + const { t } = useTranslation() + + const { + store, + totalGames, + setStore, + syncAchievements, + setPlayerStoreId, + getAchievementsStats + } = AchievementState + + useEffect(() => { + setPlayerStoreId(steamId) + getAchievementsStats() + syncAchievements('STEAM') + }, [steamId, walletState.address]) + + const activeSecondaryText = `${totalGames} Games` + const isSteam = store === 'STEAM' + + async function handleSyncClicked() { + syncAchievements('STEAM') + } + + return ( +
+
My Stores
+ +
+ +
+ {AchievementState.storesEnabled.length > 1 ? ( + + ) : null} + {AchievementState.syncing ? ( +
+
+ {t('hyperplay.syncing', 'Syncing...')} +
+ +
+ ) : ( + + )} +
+
+
+
+
+ ) +}) diff --git a/src/frontend/screens/Achievements/AchievementsLayout/AchievementsStats.tsx b/src/frontend/screens/Achievements/AchievementsLayout/AchievementsStats.tsx new file mode 100644 index 000000000..cb915fcd8 --- /dev/null +++ b/src/frontend/screens/Achievements/AchievementsLayout/AchievementsStats.tsx @@ -0,0 +1,17 @@ +import { AchievementsInfo } from '@hyperplay/ui' +import React from 'react' +import { observer } from 'mobx-react-lite' +import AchievementState from 'frontend/state/AchievementState' + +export const AchievementsStats = observer(() => { + const { newAchievements, mintedAchievements, totalAchievements, totalGames } = + AchievementState + + return ( + + ) +}) diff --git a/src/frontend/screens/Achievements/AchievementsLayout/index.module.css b/src/frontend/screens/Achievements/AchievementsLayout/index.module.css new file mode 100644 index 000000000..57c004df4 --- /dev/null +++ b/src/frontend/screens/Achievements/AchievementsLayout/index.module.css @@ -0,0 +1,56 @@ +.gridItems { + height: 100%; +} + +.storeCard { + flex-grow: 1; + gap: var(--space-2lg); + width: 100%; + border-radius: var(--space-md); + background: var(--color-neutral-800); + padding: var(--space-2lg); + flex: 1; +} + +.storeTitle { + font-size: var(--text-2xl); + color: var(--color-neutral-400); + margin-bottom: var(--space-lg); +} + +.fullHeight { + max-height: 100%; +} + +.notActive { + opacity: 0.5; +} + +.statsAndStoresContainer { + height: 100%; +} + +.achievementsContainer { + flex: 1; + max-height: 100%; +} + +.refreshing { + animation: refreshing 1.5s infinite; +} + +@keyframes refreshing { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + +.syncingContainer { + display: flex; + flex-direction: row; + gap: var(--space-sm); + align-items: center; +} diff --git a/src/frontend/screens/Achievements/AchievementsLayout/index.tsx b/src/frontend/screens/Achievements/AchievementsLayout/index.tsx new file mode 100644 index 000000000..5350ecea1 --- /dev/null +++ b/src/frontend/screens/Achievements/AchievementsLayout/index.tsx @@ -0,0 +1,47 @@ +import React, { PropsWithChildren } from 'react' + +import { Background } from '@hyperplay/ui' +import { Flex, Grid } from '@mantine/core' + +import styles from './index.module.css' +import { AchievementsStats } from './AchievementsStats' +import useSettingsContext from 'frontend/hooks/useSettingsContext' +import SettingsContext from 'frontend/screens/Settings/SettingsContext' +import { AchievementStores } from './AchievementStores' + +export default React.memo(function AchievementsLayout({ + children +}: PropsWithChildren): JSX.Element { + const contextValues = useSettingsContext({ + appName: 'default', + runner: 'hyperplay', + gameInfo: null + }) + + if (!contextValues) { + return <> + } + + return ( + + +
+ + + + + + + + + {children} + + +
+
+ ) +}) diff --git a/src/frontend/screens/Achievements/GameAchievementDetails/index.tsx b/src/frontend/screens/Achievements/GameAchievementDetails/index.tsx new file mode 100644 index 000000000..2082452d8 --- /dev/null +++ b/src/frontend/screens/Achievements/GameAchievementDetails/index.tsx @@ -0,0 +1,124 @@ +import { GameAchievements, DropdownItemType } from '@hyperplay/ui' +import React, { useEffect } from 'react' +import { useNavigate, useParams } from 'react-router-dom' +import walletState from 'frontend/state/WalletState' +import { useTranslation } from 'react-i18next' +import { observer } from 'mobx-react-lite' +import AchievementState, { + ACHIEVEMENT_SORT_OPTIONS +} from 'frontend/state/AchievementState' +import MintAchievementsState from 'frontend/state/MintAchievementsState' +import { isTimestampInPast } from 'common/utils' +import { getAchievementNavTranslations } from '../utils' + +const pageSize = 100 + +export default observer(function GameAchievementDetails(): JSX.Element { + const { t } = useTranslation() + const { id } = useParams() + + const { + achievementsToBeMinted, + achievementsToBeUpdated, + isLoading, + handleMint, + handleUpdate + } = MintAchievementsState + + const numFreeMints = AchievementState.numFreeMints + const individualAchievements = AchievementState.individualAchievementsForGame( + id ?? '0' + ) + + const summaryAchievement = AchievementState.getSummaryAchievement( + id as string + ) + + useEffect(() => { + AchievementState.fetchIndividualAchievements({ + gameId: id as string, + page: 1, + pageSize + }) + }, []) + + const navigate = useNavigate() + const handlePrevPage = () => { + navigate('/achievements') + } + + const isDisabled = isLoading || !walletState.isConnected + + if (!summaryAchievement) return <> + + async function sortUpdated(sortOption: DropdownItemType) { + const chosenItem = ACHIEVEMENT_SORT_OPTIONS.find( + (option) => option.text === sortOption.text + ) + + if (chosenItem) { + AchievementState.currentIndividualSort = chosenItem + AchievementState.fetchIndividualAchievements({ + gameId: id as string, + page: 1, + pageSize + }) + } + } + + return ( + ({ + id: achievement.id, + title: achievement.displayName, + description: achievement.description, + image: achievement.icon, + isLocked: !isTimestampInPast(achievement.unlocktime) + })) ?? [] + } + sortProps={{ + options: ACHIEVEMENT_SORT_OPTIONS, + selected: AchievementState.currentIndividualSort, + onItemChange: sortUpdated + }} + paginationProps={{ + handlePrevPage, + handleNextPage: () => { + console.log('next page') + } + }} + mintButtonProps={{ + onClick: handleMint, + disabled: achievementsToBeMinted.length === 0 ?? isDisabled, + totalToMint: achievementsToBeMinted.length + }} + updateButtonProps={{ + onClick: handleUpdate, + disabled: achievementsToBeUpdated.length === 0 ?? isDisabled, + totalToUpdate: achievementsToBeUpdated.length + }} + progressKeyProps={{ + i18n: { + mintedLabel: t('achievements.progress.minted', 'on chain'), + notMintedLabel: t('achievements.progress.notMinted', 'off chain') + } + }} + loadingAchievements={individualAchievements === undefined} + gameCardImage={summaryAchievement.gameImageURL} + /> + ) +}) diff --git a/src/frontend/screens/Achievements/index.tsx b/src/frontend/screens/Achievements/index.tsx new file mode 100644 index 000000000..0aa741f60 --- /dev/null +++ b/src/frontend/screens/Achievements/index.tsx @@ -0,0 +1,178 @@ +import React from 'react' +import walletState from 'frontend/state/WalletState' +import { AchievementCard, AchievementSummaryTable } from '@hyperplay/ui' +import { NavLink } from 'react-router-dom' +import { StatusIconState } from '@hyperplay/ui/dist/components/AchievementCard/components/StatusIcon' +import { useTranslation } from 'react-i18next' +import { observer } from 'mobx-react-lite' +import AchievementState, { + ACHIEVEMENT_SORT_OPTIONS +} from 'frontend/state/AchievementState' +import MintAchievementsState from 'frontend/state/MintAchievementsState' +import { getAchievementNavTranslations } from './utils' + +export default observer(function Achievements(): JSX.Element { + const { t } = useTranslation() + + const numFreeMints = AchievementState.numFreeMints + + const achievementsToBeMinted = MintAchievementsState.achievementsToBeMinted + const toggleAchievementToBeMinted = + MintAchievementsState.toggleAchievementToBeMinted + const isLoading = MintAchievementsState.isLoading + const handleMint = MintAchievementsState.handleMint + const handleUpdate = MintAchievementsState.handleUpdate + const achievementsToBeUpdated = MintAchievementsState.achievementsToBeUpdated + const toggleAchievementToBeUpdated = + MintAchievementsState.toggleAchievementToBeUpdated + + const isDisabled = isLoading || !walletState.isConnected + + if (AchievementState.summaryAchievementsToDisplay === undefined) { + AchievementState.fetchMoreSummaryAchievements() + } + + const tabs = [ + { value: 'all', label: 'All' }, + { value: 'new', label: 'New' } + ] + if (AchievementState.mintedAchievements > 0) { + tabs.push({ value: 'minted', label: 'Minted' }) + } + + const imagesToPreload = + AchievementState?.summaryAchievementsToDisplay?.map( + (game) => game.gameImageURL + ) ?? [] + + return ( + <> + { + const id = String(game.gameId) + const isUpdate = + game.isNewAchievement && game.mintedAchievementCount > 0 + + let state = 'default' + + if (!walletState.isConnected) { + state = 'disabled' + } else if ( + achievementsToBeMinted.includes(id) || + achievementsToBeUpdated.includes(id) + ) { + state = 'active' + } else if (isUpdate) { + state = 'update' + } + + return ( + + { + e.preventDefault() + if (isUpdate) { + toggleAchievementToBeUpdated(id) + } else { + toggleAchievementToBeMinted(id) + } + }, + disabled: isDisabled + }} + progressKeyProps={{ + i18n: { + mintedLabel: t( + 'achievements.progress.minted', + 'on chain' + ), + notMintedLabel: t( + 'achievements.progress.notMinted', + 'off chain' + ) + } + }} + /> + + ) + }) + : [] + } + sortProps={{ + options: ACHIEVEMENT_SORT_OPTIONS, + selected: AchievementState.currentSort, + onItemChange: async (sortOption) => { + const chosenItem = ACHIEVEMENT_SORT_OPTIONS.find( + (option) => option.text === sortOption.text + ) + + if (chosenItem) { + AchievementState.setSort(chosenItem) + } + } + }} + paginationProps={{ + handleNextPage: () => { + console.log('handling next page') + }, + handlePrevPage: () => { + console.log('handling previous page') + } + }} + filterProps={{ + activeFilter: AchievementState.filterDisplayName, + setActiveFilter: async (filterDisplayName) => { + const filter = + AchievementState.getFilterNameFromDisplayName(filterDisplayName) + AchievementState.setFilter(filter) + } + }} + mintButtonProps={{ + onClick: handleMint, + disabled: isDisabled || achievementsToBeMinted.length === 0, + totalToMint: achievementsToBeMinted.length + }} + updateButtonProps={{ + onClick: handleUpdate, + disabled: isDisabled || achievementsToBeUpdated.length === 0, + totalToUpdate: achievementsToBeUpdated.length + }} + achievementNavProps={{ + freeMints: numFreeMints, + basketAmount: + achievementsToBeMinted.length + achievementsToBeUpdated.length, + gamesAdded: [], + showGameAddButton: false, + i18n: getAchievementNavTranslations(t) + }} + fetchNextPage={() => { + AchievementState.fetchMoreSummaryAchievements() + }} + isPageLoading={ + AchievementState.summaryAchievementsToDisplay === undefined && + AchievementState.fetching + } + tabs={tabs} + messageModalProps={{ + title: t('hyperplay.achievements.noAchievements.oops', 'Oops!'), + message: t( + 'hyperplay.achievements.noAchievements.doubleCheckMessage', + `It looks like we couldn't find any games in your Steam account at the moment. Just a quick reminder to double-check that your game details are set to public. This way, we can access your achievements and provide you with the best experience.` + ) + }} + /> + + ) +}) diff --git a/src/frontend/screens/Achievements/utils.ts b/src/frontend/screens/Achievements/utils.ts new file mode 100644 index 000000000..7087e680f --- /dev/null +++ b/src/frontend/screens/Achievements/utils.ts @@ -0,0 +1,14 @@ +import { TFunction } from 'i18next' + +export function getAchievementNavTranslations( + t: TFunction<'translation', undefined, 'translation'> +) { + return { + addThisGameText: t('hyperplay.achievements.addThisGame', 'Add this game'), + gamesToMintLabelText: t( + 'hyperplay.achievements.gamesToMint', + 'Games to mint' + ), + freeMintsLabel: t('hyperplay.achievements.freeMints', 'Free Mints') + } +} diff --git a/src/frontend/screens/Settings/components/SteamId.tsx b/src/frontend/screens/Settings/components/SteamId.tsx new file mode 100644 index 000000000..f3d6269f9 --- /dev/null +++ b/src/frontend/screens/Settings/components/SteamId.tsx @@ -0,0 +1,33 @@ +import React from 'react' +import { useTranslation } from 'react-i18next' +import useSetting from 'frontend/hooks/useSetting' +import { configStore } from 'frontend/helpers/electronStores' +import { TextInput } from '@hyperplay/ui' + +/** + * Used only for testing. + * TODO: replace with auth system session's steam id + */ +const SteamId = () => { + const { t } = useTranslation() + const [steamId, setSteamId] = useSetting('steamId', '') + + function setSteamIdWrapper(path: string) { + setSteamId(path) + configStore.set('settings.steamId', path) + } + + return ( + + setSteamIdWrapper(event.target.value?.replaceAll("'", '')) + } + /> + ) +} + +export default SteamId diff --git a/src/frontend/screens/Settings/index.scss b/src/frontend/screens/Settings/index.scss index 117c21722..b616f72b8 100644 --- a/src/frontend/screens/Settings/index.scss +++ b/src/frontend/screens/Settings/index.scss @@ -61,7 +61,7 @@ .save { cursor: default; - margin: var(--space-md) 0 0 var(--space-md); + margin: var(--space-md) 0 0 0; padding-block-end: var(--space-xs); display: flex; align-items: center; @@ -216,3 +216,7 @@ a { .settingsSectionHeader { text-align: left; } + +.capitalize { + text-transform: capitalize; +} diff --git a/src/frontend/screens/Settings/index.tsx b/src/frontend/screens/Settings/index.tsx index 9e34b08a8..f98ca8afc 100644 --- a/src/frontend/screens/Settings/index.tsx +++ b/src/frontend/screens/Settings/index.tsx @@ -17,6 +17,9 @@ import useSettingsContext from 'frontend/hooks/useSettingsContext' import { Tabs } from '@hyperplay/ui' import Accessibility from '../Accessibility' import WineManager from '../WineManager' +import AccountSettings from './sections/AccountSettings' +import { observer } from 'mobx-react-lite' +import AchievementState from 'frontend/state/AchievementState' import DeviceState from 'frontend/state/DeviceState' export const defaultWineVersion: WineInstallation = { @@ -131,6 +134,9 @@ function Settings() {
{t('accessibility.title')}
+ +
{t('accounts')}
+
{!isWin ? (
@@ -154,6 +160,11 @@ function Settings() { + {AchievementState.showAchievements && ( + + + + )} {!isWin ? ( @@ -168,4 +179,4 @@ function Settings() { ) } -export default React.memo(Settings) +export default observer(Settings) diff --git a/src/frontend/screens/Settings/sections/AccountSettings/index.tsx b/src/frontend/screens/Settings/sections/AccountSettings/index.tsx new file mode 100644 index 000000000..d239031a8 --- /dev/null +++ b/src/frontend/screens/Settings/sections/AccountSettings/index.tsx @@ -0,0 +1,17 @@ +import React from 'react' +import { useTranslation } from 'react-i18next' +import SteamId from '../../components/SteamId' + +export default function AccountSettings() { + const { t } = useTranslation() + + return ( + <> +
+ {t('settings.navbar.accounts', 'Accounts')} +
+ + + + ) +} diff --git a/src/frontend/state/AchievementState.ts b/src/frontend/state/AchievementState.ts new file mode 100644 index 000000000..f136926e5 --- /dev/null +++ b/src/frontend/state/AchievementState.ts @@ -0,0 +1,319 @@ +import { makeAutoObservable, runInAction } from 'mobx' +import walletState from 'frontend/state/WalletState' +import type { + Achievement, + AchievementFilter, + AchievementSort, + AchievementStore, + AchievementsStats, + SummaryAchievement +} from 'common/types' + +interface AchievementData { + data: SummaryAchievement[] + pagesFetched: number + totalPages: number +} + +interface AchievementRequestKey { + filter: AchievementFilter + sort: AchievementSort + store: AchievementStore +} + +interface AchievementSortOption { + text: string + value: AchievementSort +} + +interface IndividualAchievementKey { + gameId: string + sort: AchievementSort + store: AchievementStore +} + +interface IndividualAchievementData { + data: Achievement[] +} + +export const ACHIEVEMENT_SORT_OPTIONS = [ + { text: 'Alphabetically (ASC)', value: 'ALPHA_A_TO_Z' }, + { text: 'Alphabetically (DES)', value: 'ALPHA_Z_TO_A' } +] as AchievementSortOption[] + +class AchievementState { + /** + * feature flag for enabled stores + */ + storesEnabled = ['STEAM'] + + store = 'STEAM' as AchievementStore + private playerStoreId = '' + + // Stats + newAchievements = 0 + totalAchievements = 0 + totalGames = 0 + mintedAchievements = 0 + numFreeMints = 0 + + // Summary Achievements + summaryAchievements = new Map() + currentFilter: AchievementFilter = 'ALL' + currentSort: AchievementSortOption = ACHIEVEMENT_SORT_OPTIONS[0] + currentStore: AchievementStore = 'STEAM' + + // Individual Achievements + individualAchievements = new Map() + currentIndividualSort: AchievementSortOption = ACHIEVEMENT_SORT_OPTIONS[0] + + // Achievements Feature Flag + showAchievements = false + + fetching = false + + syncing = false + + constructor() { + makeAutoObservable( + this, + {}, + { + deep: true, + proxy: false, + name: 'AchievementState' + } + ) + } + + init() { + window.api + .shouldShowAchievements() + .then((res) => (this.showAchievements = res)) + } + + getAchievementsStats = async () => { + try { + const stats = await window.api.getAchievementsStats({ + store: this.store, + playerStoreId: this.playerStoreId, + playerAddress: walletState.address + }) + this.setStats(stats) + } catch (err) { + console.error(`Error while getting achievement stats ${err}`) + } + } + + individualAchievementsKey(gameId: string) { + const key: IndividualAchievementKey = { + gameId, + store: this.currentStore, + sort: this.currentIndividualSort.value + } + const keyString = JSON.stringify(key) + return keyString + } + + async fetchIndividualAchievements({ + gameId, + page, + pageSize + }: { + gameId: string + page: number + pageSize: number + }) { + const keyString = this.individualAchievementsKey(gameId) + + /** + * Check cache for hit + */ + if (this.individualAchievements.has(keyString)) { + return this.individualAchievements.get(keyString)?.data + } + + const individualAchievements = await window.api.getIndividualAchievements({ + gameId: Number(gameId), + store: this.store, + sort: this.currentIndividualSort.value, + page, + pageSize, + playerStoreId: this.playerStoreId, + playerAddress: walletState.address + }) + + this.individualAchievements.set(keyString, individualAchievements) + return individualAchievements.data + } + + individualAchievementsForGame(gameId: string) { + const keyString = this.individualAchievementsKey(gameId) + return this.individualAchievements.get(keyString) + } + + fetchMoreSummaryAchievements = async () => { + if (this.fetching) { + return + } + if (!this.playerStoreId) { + console.error('player store id is not set!') + return + } + this.setFetching(true) + const pagesFetched = this.currentSummaryAchievements?.pagesFetched + const totalPages = this.currentSummaryAchievements?.totalPages + const alreadyFetchedAllPages = + pagesFetched !== undefined && + totalPages !== undefined && + pagesFetched >= totalPages + if (alreadyFetchedAllPages) { + this.setFetching(false) + return + } + const requestKey = this.currentSummaryKey + + const nextPageOfSummaryAchievements = + await window.api.getSummaryAchievements({ + store: this.store, + filter: requestKey.filter, + sort: requestKey.sort, + // api is one indexed not zero indexed + page: pagesFetched ? pagesFetched + 1 : 1, + playerStoreId: this.playerStoreId, + playerAddress: walletState.address + }) + + const valRef = this.summaryAchievements.get(JSON.stringify(requestKey)) + + if (valRef !== undefined) { + valRef.data = valRef.data.concat(nextPageOfSummaryAchievements.data) + valRef.pagesFetched += 1 + } else { + this.summaryAchievements.set(JSON.stringify(requestKey), { + data: nextPageOfSummaryAchievements.data, + pagesFetched: 1, + totalPages: nextPageOfSummaryAchievements.totalPages + }) + } + this.setFetching(false) + } + + /** + * Necessary since strict-mode is enabled in mobx + */ + setFetching = (val: boolean) => { + runInAction(() => { + this.fetching = val + }) + } + + private get currentSummaryKey(): AchievementRequestKey { + return { + filter: this.currentFilter, + sort: this.currentSort.value, + store: this.currentStore + } + } + + get currentSummaryAchievements() { + const key = this.currentSummaryKey + return this.summaryAchievements.get(JSON.stringify(key)) + } + + get summaryAchievementsToDisplay() { + return this.currentSummaryAchievements?.data + } + + /** + * Fetch for current key if no game summaries have been fetched + */ + initGameSummaryKey() { + if (this.summaryAchievementsToDisplay === undefined) { + this.fetchMoreSummaryAchievements() + } + } + + setFilter(filter: AchievementFilter) { + this.currentFilter = filter + this.initGameSummaryKey() + } + + setSort(sort: AchievementSortOption) { + this.currentSort = sort + this.initGameSummaryKey() + } + + syncAchievements = async (store: AchievementStore) => { + if (!this.playerStoreId) { + console.error('Player store id is not set!') + return + } + if (this.syncing) { + return + } + this.setSyncing(true) + try { + await window.api.syncAchievements({ + store, + playerStoreId: this.playerStoreId, + playerAddress: walletState.address + }) + } catch (err) { + console.error(err) + } + this.setSyncing(false) + } + + /** + * Necessary since strict-mode is enabled in mobx + */ + setSyncing = (val: boolean) => { + runInAction(() => { + this.syncing = val + }) + } + + setStats = (state: AchievementsStats) => { + this.newAchievements = state.newAchievements + this.totalAchievements = state.totalAchievements + this.totalGames = state.totalGames + this.mintedAchievements = state.mintedAchievements + this.numFreeMints = state.numFreeMints + } + + setStore = (store: AchievementStore) => { + this.store = store + } + + setPlayerStoreId = (playerStoreId: string) => { + this.playerStoreId = playerStoreId + this.summaryAchievements.clear() + } + + get getPlayerStoreId() { + return this.playerStoreId + } + + get filterDisplayName() { + const activeFilter = this.currentFilter + if (activeFilter === 'NEW') return 'new' + if (activeFilter === 'MINTED') return 'minted' + return 'all' + } + + getFilterNameFromDisplayName(displayName: string) { + let newFilter = 'ALL' as AchievementFilter + if (displayName === 'new') newFilter = 'NEW' + if (displayName === 'minted') newFilter = 'MINTED' + return newFilter + } + + getSummaryAchievement(id: string) { + return this.summaryAchievementsToDisplay?.find( + (val) => val.gameId.toString() === id + ) + } +} + +export default new AchievementState() diff --git a/src/frontend/state/MintAchievementsState.ts b/src/frontend/state/MintAchievementsState.ts new file mode 100644 index 000000000..fbe3759a6 --- /dev/null +++ b/src/frontend/state/MintAchievementsState.ts @@ -0,0 +1,47 @@ +import { makeAutoObservable, runInAction } from 'mobx' + +class MintAchievementsState { + achievementsToBeMinted = [] as string[] + achievementsToBeUpdated = [] as string[] + isLoading = false + + constructor() { + makeAutoObservable(this) + } + + toggleAchievementToBeMinted = (id: string) => { + if (this.achievementsToBeMinted.includes(id)) { + this.achievementsToBeMinted = this.achievementsToBeMinted.filter( + (item) => item !== id + ) + } else { + this.achievementsToBeMinted = [...this.achievementsToBeMinted, id] + } + } + + toggleAchievementToBeUpdated = (id: string) => { + if (this.achievementsToBeUpdated.includes(id)) { + this.achievementsToBeUpdated = this.achievementsToBeUpdated.filter( + (item) => item !== id + ) + } else { + this.achievementsToBeUpdated = [...this.achievementsToBeUpdated, id] + } + } + + testLoad = (ms: number) => { + this.isLoading = true + setTimeout(() => { + runInAction(() => { + this.isLoading = false + this.achievementsToBeMinted = [] + }) + }, ms) + } + + handleMint = () => this.testLoad(3000) + + handleUpdate = () => this.testLoad(3000) +} + +export default new MintAchievementsState() diff --git a/yarn.lock b/yarn.lock index 26379050a..9b7fb3214 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1692,10 +1692,10 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== -"@hyperplay/ui@^0.1.33": - version "0.1.33" - resolved "https://registry.yarnpkg.com/@hyperplay/ui/-/ui-0.1.33.tgz#4c49ff8280df981b25928733b96c4e18ae50127b" - integrity sha512-AsUb41dNhs7C6D39XOq3pxrvSJB2TXDvtkTl0N15j1wHzJXU4G02GTt5mSljnLwWDGcrX6i1cfxDeaALkf35Wg== +"@hyperplay/ui@^0.1.38": + version "0.1.38" + resolved "https://registry.yarnpkg.com/@hyperplay/ui/-/ui-0.1.38.tgz#f1e0308a7e827055afeb3912a5e4450b9dedc47c" + integrity sha512-0IdbKKik4mtmD08PrScrCOg7d5qbd1kX8cE1Nq8sc3bCgtdAl7FNlhaI+FWeV/zwI74cvkDBDUATgl7IE/6teQ== "@ioredis/commands@^1.1.1": version "1.2.0"