Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43ebab52d4 | ||
|
|
a5f9eaa392 | ||
|
|
cc2064f296 | ||
|
|
f2462cff81 | ||
|
|
b2e25abf08 | ||
|
|
cd0817bd11 | ||
|
|
e88ca8ede1 | ||
|
|
7a83269d98 | ||
|
|
4be1d48215 | ||
|
|
8485ff1e99 | ||
|
|
be66b10f49 | ||
|
|
1f22971493 | ||
|
|
ea943088e5 | ||
|
|
298be4a344 | ||
|
|
f37fc13b7c | ||
|
|
506b74868e | ||
|
|
4a59d1cfda | ||
|
|
7201c8347f | ||
|
|
c8a3df3cfc | ||
|
|
2ef7742903 | ||
|
|
f98135325a | ||
|
|
fd765aa8c8 | ||
|
|
ec93dd5a7d | ||
|
|
0e885ff2d5 | ||
|
|
5893cb575e | ||
|
|
b46136b959 | ||
|
|
390c1e870d |
39
README.md
@@ -4,16 +4,16 @@ A homebrew menu for the Nintendo Switch.
|
|||||||
|
|
||||||
[See the GBATemp thread for more details / discussion](https://gbatemp.net/threads/sphaira-hbmenu-replacement.664523/).
|
[See the GBATemp thread for more details / discussion](https://gbatemp.net/threads/sphaira-hbmenu-replacement.664523/).
|
||||||
|
|
||||||
[We have now have a Discord server!](https://discord.gg/8vZBsrprEc). Please use the issues tab to report bugs, as it is much easier for me to track.
|
[We have now have a Discord server!](https://discord.gg/8vZBsrprEc) Please use the issues tab to report bugs, as it is much easier for me to track.
|
||||||
|
|
||||||
## Showcase
|
## Showcase
|
||||||
|
|
||||||
| | |
|
| | |
|
||||||
:-------------------------:|:-------------------------:
|
:-------------------------:|:-------------------------:
|
||||||
 | 
|
 | 
|
||||||
 | 
|
 | 
|
||||||
 | 
|
 | 
|
||||||
 | 
|
 | 
|
||||||
|
|
||||||
## Bug reports
|
## Bug reports
|
||||||
|
|
||||||
@@ -86,16 +86,21 @@ The output will be found in `build/MinSizeRel/sphaira.nro`
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
- borealis
|
- [borealis](https://github.com/natinusala/borealis)
|
||||||
- stb
|
- [stb](https://github.com/nothings/stb)
|
||||||
- yyjson
|
- [yyjson](https://github.com/ibireme/yyjson)
|
||||||
- nx-hbmenu
|
- [nx-hbmenu](https://github.com/switchbrew/nx-hbmenu)
|
||||||
- nx-hbloader
|
- [nx-hbloader](https://github.com/switchbrew/nx-hbloader)
|
||||||
- deko3d-nanovg
|
- [deko3d-nanovg](https://github.com/Adubbz/nanovg-deko3d)
|
||||||
- libpulsar
|
- [libpulsar](https://github.com/p-sam/switch-libpulsar)
|
||||||
- minIni
|
- [minIni](https://github.com/compuphase/minIni)
|
||||||
- GBATemp
|
- [GBATemp](https://gbatemp.net/threads/sphaira-hbmenu-replacement.664523/)
|
||||||
- hb-appstore
|
- [hb-appstore](https://github.com/fortheusers/hb-appstore)
|
||||||
- haze
|
- [haze](https://github.com/Atmosphere-NX/Atmosphere/tree/master/troposphere/haze)
|
||||||
- nxdumptool (for gamecard bin dumping and rsa verify code)
|
- [nxdumptool](https://github.com/DarkMatterCore/nxdumptool) (for gamecard bin dumping and rsa verify code)
|
||||||
|
- [libusbhsfs](https://github.com/DarkMatterCore/libusbhsfs)
|
||||||
|
- [libnxtc](https://github.com/DarkMatterCore/libnxtc)
|
||||||
|
- [oss-nvjpg](https://github.com/averne/oss-nvjpg)
|
||||||
|
- [nsz](https://github.com/nicoboss/nsz)
|
||||||
|
- [themezer](https://themezer.net/)
|
||||||
- Everyone who has contributed to this project!
|
- Everyone who has contributed to this project!
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
"No Internet": "Kein Internet",
|
"No Internet": "Kein Internet",
|
||||||
"Switch-Handheld!": "Handheld!",
|
"Switch-Handheld!": "Handheld!",
|
||||||
"Switch-Docked!": "Angedockt!",
|
"Switch-Docked!": "Angedockt!",
|
||||||
|
"Warning! Logs are enabled, Sphaira will run slowly!": "",
|
||||||
"Audio disabled due to suspended game": "Audio deaktivert wegen Spielabbruch",
|
"Audio disabled due to suspended game": "Audio deaktivert wegen Spielabbruch",
|
||||||
"Are you sure you wish to cancel?": "Bist du sicher dass du abbrechen willst?",
|
"Are you sure you wish to cancel?": "Bist du sicher dass du abbrechen willst?",
|
||||||
"An error occurred": "",
|
"An error occurred": "",
|
||||||
@@ -27,6 +28,8 @@
|
|||||||
"Nxlink Connected": "NXLink | Verbunden",
|
"Nxlink Connected": "NXLink | Verbunden",
|
||||||
"Nxlink Upload": "NXLink | wird hochgeladen...",
|
"Nxlink Upload": "NXLink | wird hochgeladen...",
|
||||||
"Nxlink Finished": "NXLink | Hochladen beendet",
|
"Nxlink Finished": "NXLink | Hochladen beendet",
|
||||||
|
"Hdd": "",
|
||||||
|
"Hdd write protect": "",
|
||||||
|
|
||||||
"Language": "Sprache",
|
"Language": "Sprache",
|
||||||
"Auto": "Systemsprache",
|
"Auto": "Systemsprache",
|
||||||
@@ -57,22 +60,35 @@
|
|||||||
"No meta entries found...\n": "",
|
"No meta entries found...\n": "",
|
||||||
"Updating application record list": "",
|
"Updating application record list": "",
|
||||||
"Dump": "",
|
"Dump": "",
|
||||||
|
"Dump options": "",
|
||||||
|
"Dump Options": "",
|
||||||
"Select content to dump": "",
|
"Select content to dump": "",
|
||||||
"Dump All": "",
|
"Dump All": "",
|
||||||
"Dump Application": "",
|
"Dump Application": "",
|
||||||
"Dump Patch": "",
|
"Dump Patch": "",
|
||||||
"Dump AddOnContent": "",
|
"Dump AddOnContent": "",
|
||||||
"Dump DataPatch": "",
|
"Dump DataPatch": "",
|
||||||
|
"Created nested folder": "",
|
||||||
|
"Append folder with .xci": "",
|
||||||
|
"Trim XCI": "",
|
||||||
|
"Label trimmed XCI": "",
|
||||||
|
"Multi-threaded USB transfer": "",
|
||||||
|
"Dump All Bins": "",
|
||||||
|
"Dump XCI": "",
|
||||||
|
"Dump Card ID Set": "",
|
||||||
|
"Dump Card UID": "",
|
||||||
|
"Dump Certificate": "",
|
||||||
|
"Dump Initial Data": "",
|
||||||
"Select dump location": "",
|
"Select dump location": "",
|
||||||
"microSD card (/dumps/NSP/)": "",
|
"microSD card (/dumps/)": "",
|
||||||
"USB transfer (Switch 2 Switch)": "",
|
"USB transfer (Switch 2 Switch)": "",
|
||||||
"/dev/null (Speed Test)": "",
|
"/dev/null (Speed Test)": "",
|
||||||
"Dumping": "",
|
"Dumping": "",
|
||||||
"Dump successfull!": "",
|
"Dump successfull!": "",
|
||||||
"Dump failed!": "",
|
"Dump failed!": "",
|
||||||
"Success": "",
|
|
||||||
"Delete successfull!": "",
|
"Delete successfull!": "",
|
||||||
"Delete failed!": "",
|
"Delete failed!": "",
|
||||||
|
"Success": "",
|
||||||
|
|
||||||
"Themezer": "Themezer | NX Themes",
|
"Themezer": "Themezer | NX Themes",
|
||||||
"Themezer Options": " Themezer | Optionen",
|
"Themezer Options": " Themezer | Optionen",
|
||||||
@@ -86,6 +102,8 @@
|
|||||||
"GitHub": "GitHub",
|
"GitHub": "GitHub",
|
||||||
"Downloading json": "Lade JSON-File",
|
"Downloading json": "Lade JSON-File",
|
||||||
"Select asset to download for ": "Wähle Asset für den Download von ",
|
"Select asset to download for ": "Wähle Asset für den Download von ",
|
||||||
|
"Failed to download json": "",
|
||||||
|
"Failed to download app!": "",
|
||||||
|
|
||||||
"FTP Install": "",
|
"FTP Install": "",
|
||||||
"FTP Install (EXPERIMENTAL)": "",
|
"FTP Install (EXPERIMENTAL)": "",
|
||||||
@@ -122,9 +140,12 @@
|
|||||||
"GC": "",
|
"GC": "",
|
||||||
"System memory %.1f GB": "",
|
"System memory %.1f GB": "",
|
||||||
"microSD card %.1f GB": "",
|
"microSD card %.1f GB": "",
|
||||||
"Nand Install": "",
|
|
||||||
"SD Card Install": "",
|
|
||||||
"Exit": "",
|
"Exit": "",
|
||||||
|
"Install disabled...\nPlease enable installing via the install options.": "",
|
||||||
|
"No GameCard inserted": "",
|
||||||
|
"GameCard is already trimmed!": "",
|
||||||
|
"WARNING: GameCard is already trimmed!": "",
|
||||||
|
"Continue": "",
|
||||||
"Gc install success!": "",
|
"Gc install success!": "",
|
||||||
"Gc install failed!": "",
|
"Gc install failed!": "",
|
||||||
|
|
||||||
@@ -160,14 +181,14 @@
|
|||||||
"Negative image": "Negativ-Bild",
|
"Negative image": "Negativ-Bild",
|
||||||
"Format": "Format",
|
"Format": "Format",
|
||||||
"Trimming Format": "Beschnitt-Format",
|
"Trimming Format": "Beschnitt-Format",
|
||||||
"320x240": "320×240",
|
|
||||||
"160x120": "160×120",
|
|
||||||
"80x60": "80×60",
|
|
||||||
"40x30": "40×30",
|
|
||||||
"20x15": "20×15",
|
|
||||||
"External Light Filter": "Externes Lichtfilter",
|
"External Light Filter": "Externes Lichtfilter",
|
||||||
"Load Default": "Standard laden",
|
"Load Default": "Standard laden",
|
||||||
|
|
||||||
|
"Web": "",
|
||||||
|
"Select URL": "",
|
||||||
|
"Enter custom URL": "",
|
||||||
|
"Enter URL": "",
|
||||||
|
|
||||||
"Advanced": "Erweitert...",
|
"Advanced": "Erweitert...",
|
||||||
"Advanced Options": " Erweitert | Optionen",
|
"Advanced Options": " Erweitert | Optionen",
|
||||||
"Logging": "Protokollieren",
|
"Logging": "Protokollieren",
|
||||||
@@ -181,10 +202,12 @@
|
|||||||
"Restored hbmenu": "hbmenu wurde wiederhergestellt",
|
"Restored hbmenu": "hbmenu wurde wiederhergestellt",
|
||||||
"Restart Sphaira?": "sphaira erneut starten?",
|
"Restart Sphaira?": "sphaira erneut starten?",
|
||||||
"Press OK to restart Sphaira": "Drücke OK um sphaira erneut zustarten",
|
"Press OK to restart Sphaira": "Drücke OK um sphaira erneut zustarten",
|
||||||
|
"Boost CPU during transfer": "",
|
||||||
"Text scroll speed": "Laufschrift Tempo",
|
"Text scroll speed": "Laufschrift Tempo",
|
||||||
"Slow": "Niedrig",
|
"Slow": "Niedrig",
|
||||||
"Normal": "Mittel",
|
"Normal": "Mittel",
|
||||||
"Fast": "Hoch",
|
"Fast": "Hoch",
|
||||||
|
"Set left-side menu": "",
|
||||||
"Set right-side menu": "",
|
"Set right-side menu": "",
|
||||||
"Install options": "",
|
"Install options": "",
|
||||||
"Install Options": "",
|
"Install Options": "",
|
||||||
@@ -194,7 +217,6 @@
|
|||||||
"Install location": "Einhängepunkt",
|
"Install location": "Einhängepunkt",
|
||||||
"System memory": "NAND Systemspeicher",
|
"System memory": "NAND Systemspeicher",
|
||||||
"microSD card": "SD-Karte",
|
"microSD card": "SD-Karte",
|
||||||
"Boost CPU clock": "",
|
|
||||||
"Allow downgrade": "",
|
"Allow downgrade": "",
|
||||||
"Skip if already installed": "",
|
"Skip if already installed": "",
|
||||||
"Ticket only": "",
|
"Ticket only": "",
|
||||||
@@ -225,6 +247,8 @@
|
|||||||
"Updating ncm databse": "Aktualisiere NCM-Datenbank",
|
"Updating ncm databse": "Aktualisiere NCM-Datenbank",
|
||||||
"Pushing application record": "Übertrage Anwendungsdaten",
|
"Pushing application record": "Übertrage Anwendungsdaten",
|
||||||
"Failed to install forwarder": "Fehler beim installieren des Forwarders",
|
"Failed to install forwarder": "Fehler beim installieren des Forwarders",
|
||||||
|
"Unstar": "Kein Favorit",
|
||||||
|
"Star": "Favorit",
|
||||||
"Unstarred ": "Favorit entfernt ",
|
"Unstarred ": "Favorit entfernt ",
|
||||||
"Starred ": "Favorit ",
|
"Starred ": "Favorit ",
|
||||||
"Failed to remove old forwarder, please manually remove it!": "",
|
"Failed to remove old forwarder, please manually remove it!": "",
|
||||||
@@ -257,12 +281,13 @@
|
|||||||
"Copy": "Kopieren",
|
"Copy": "Kopieren",
|
||||||
"Copying ": "Kopiert wird: ",
|
"Copying ": "Kopiert wird: ",
|
||||||
"Paste": "Einfügen",
|
"Paste": "Einfügen",
|
||||||
"Paste ": "Einfügen von: ",
|
"Paste file(s)?": "",
|
||||||
" file(s)?": " Datei/en?",
|
|
||||||
"Pasting ": "Eingefügt wird: ",
|
"Pasting ": "Eingefügt wird: ",
|
||||||
"Pasting": "Eingefügt wurde:",
|
"Pasting": "Eingefügt wurde:",
|
||||||
"Rename": "Umbenennen",
|
"Rename": "Umbenennen",
|
||||||
"Set New File Name": "Neuen Dateinamen festlegen",
|
"Set New File Name": "Neuen Dateinamen festlegen",
|
||||||
|
"Failed to delete directory": "",
|
||||||
|
"Failed to delete file": "",
|
||||||
"Extract zip": "",
|
"Extract zip": "",
|
||||||
"Extract Options": "",
|
"Extract Options": "",
|
||||||
"Extract here": "",
|
"Extract here": "",
|
||||||
@@ -285,13 +310,17 @@
|
|||||||
"Create Folder": "Neuer Ordner",
|
"Create Folder": "Neuer Ordner",
|
||||||
"Set Folder Name": "Ordner umbenennen",
|
"Set Folder Name": "Ordner umbenennen",
|
||||||
"Creating ": "Erstellt wird: ",
|
"Creating ": "Erstellt wird: ",
|
||||||
|
"View as text (unfinished)": "Als Text anzeigen",
|
||||||
"Upload": "",
|
"Upload": "",
|
||||||
"Select upload location": "",
|
"Select upload location": "",
|
||||||
"No upload locations set!": "",
|
"No upload locations set!": "",
|
||||||
"Uploading": "",
|
"Uploading": "",
|
||||||
"Upload successfull!": "",
|
"Upload successfull!": "",
|
||||||
"Upload failed!": "",
|
"Upload failed!": "",
|
||||||
"View as text (unfinished)": "Als Text anzeigen",
|
"Hash": "",
|
||||||
|
"Hash Options": "",
|
||||||
|
"Hashing": "",
|
||||||
|
"Failed to hash file...": "",
|
||||||
"Ignore read only": "Schreibschutz umgehen?",
|
"Ignore read only": "Schreibschutz umgehen?",
|
||||||
"Mount": "Einhängen",
|
"Mount": "Einhängen",
|
||||||
"Sd": "SD-Karte | Root-Verzeichnis",
|
"Sd": "SD-Karte | Root-Verzeichnis",
|
||||||
@@ -302,6 +331,7 @@
|
|||||||
"Launch ": "Starte ",
|
"Launch ": "Starte ",
|
||||||
"Launch option for: ": "Start Option für: ",
|
"Launch option for: ": "Start Option für: ",
|
||||||
"Select launcher for: ": "Wähle Launcher für: ",
|
"Select launcher for: ": "Wähle Launcher für: ",
|
||||||
|
"Close FileBrowser?": "",
|
||||||
|
|
||||||
"Sort By": "Sortierung",
|
"Sort By": "Sortierung",
|
||||||
"Sort Options": " Sortierung | Optionen",
|
"Sort Options": " Sortierung | Optionen",
|
||||||
@@ -335,16 +365,16 @@
|
|||||||
"Search": "Suchen",
|
"Search": "Suchen",
|
||||||
|
|
||||||
"Options": "Optionen",
|
"Options": "Optionen",
|
||||||
|
"Split": "",
|
||||||
"OK": "OK",
|
"OK": "OK",
|
||||||
"Back": "Zurück",
|
"Back": "Zurück",
|
||||||
"Select": "Auswählen",
|
"Select": "Auswählen",
|
||||||
"Open": "Öffne",
|
"Open": "Öffne",
|
||||||
|
"Close": "",
|
||||||
"Launch": "Starte",
|
"Launch": "Starte",
|
||||||
"Restart": "Neustart",
|
"Restart": "Neustart",
|
||||||
"Next": "",
|
"Next": "",
|
||||||
"Prev": "",
|
"Prev": "",
|
||||||
"Unstar": "Kein Favorit",
|
|
||||||
"Star": "Favorit",
|
|
||||||
"Yes": "Ja",
|
"Yes": "Ja",
|
||||||
"No": "Nein",
|
"No": "Nein",
|
||||||
"On": "",
|
"On": "",
|
||||||
@@ -367,12 +397,13 @@
|
|||||||
"Remove": "Entfernen",
|
"Remove": "Entfernen",
|
||||||
"Completely remove ": "Komplett gelöscht wird: ",
|
"Completely remove ": "Komplett gelöscht wird: ",
|
||||||
"Removing ": "Entfernt wird: ",
|
"Removing ": "Entfernt wird: ",
|
||||||
"Removed ": "Entfernt wurde: ",
|
|
||||||
"Uninstalling ": "Deinstalliert wird: ",
|
"Uninstalling ": "Deinstalliert wird: ",
|
||||||
|
"Removed ": "Entfernt wurde: ",
|
||||||
|
|
||||||
"Download": "Download",
|
"Download": "Download",
|
||||||
"Downloading ": "Heruntergeladen wird: ",
|
"Downloading ": "Heruntergeladen wird: ",
|
||||||
"Downloaded ": "Heruntergeladen wurde: ",
|
"Downloaded ": "Heruntergeladen wurde: ",
|
||||||
|
"Download via the Network options!": "",
|
||||||
|
|
||||||
"Update": "Update",
|
"Update": "Update",
|
||||||
"Update avaliable: ": "Update verfügbar: ",
|
"Update avaliable: ": "Update verfügbar: ",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
"No Internet": "No Internet",
|
"No Internet": "No Internet",
|
||||||
"Switch-Handheld!": "Switch-Handheld!",
|
"Switch-Handheld!": "Switch-Handheld!",
|
||||||
"Switch-Docked!": "Switch-Docked!",
|
"Switch-Docked!": "Switch-Docked!",
|
||||||
|
"Warning! Logs are enabled, Sphaira will run slowly!": "Warning! Logs are enabled, Sphaira will run slowly!",
|
||||||
"Audio disabled due to suspended game": "Audio disabled due to suspended game",
|
"Audio disabled due to suspended game": "Audio disabled due to suspended game",
|
||||||
"Are you sure you wish to cancel?": "Are you sure you wish to cancel?",
|
"Are you sure you wish to cancel?": "Are you sure you wish to cancel?",
|
||||||
"An error occurred": "An error occurred",
|
"An error occurred": "An error occurred",
|
||||||
@@ -27,6 +28,8 @@
|
|||||||
"Nxlink Connected": "Nxlink Connected",
|
"Nxlink Connected": "Nxlink Connected",
|
||||||
"Nxlink Upload": "Nxlink Upload",
|
"Nxlink Upload": "Nxlink Upload",
|
||||||
"Nxlink Finished": "Nxlink Finished",
|
"Nxlink Finished": "Nxlink Finished",
|
||||||
|
"Hdd": "Hdd",
|
||||||
|
"Hdd write protect": "Hdd write protect",
|
||||||
|
|
||||||
"Language": "Language",
|
"Language": "Language",
|
||||||
"Auto": "Auto",
|
"Auto": "Auto",
|
||||||
@@ -57,22 +60,35 @@
|
|||||||
"No meta entries found...\n": "No meta entries found...\n",
|
"No meta entries found...\n": "No meta entries found...\n",
|
||||||
"Updating application record list": "Updating application record list",
|
"Updating application record list": "Updating application record list",
|
||||||
"Dump": "Dump",
|
"Dump": "Dump",
|
||||||
|
"Dump options": "Dump options",
|
||||||
|
"Dump Options": "Dump Options",
|
||||||
"Select content to dump": "Select content to dump",
|
"Select content to dump": "Select content to dump",
|
||||||
"Dump All": "Dump All",
|
"Dump All": "Dump All",
|
||||||
"Dump Application": "Dump Application",
|
"Dump Application": "Dump Application",
|
||||||
"Dump Patch": "Dump Patch",
|
"Dump Patch": "Dump Patch",
|
||||||
"Dump AddOnContent": "Dump AddOnContent",
|
"Dump AddOnContent": "Dump AddOnContent",
|
||||||
"Dump DataPatch": "Dump DataPatch",
|
"Dump DataPatch": "Dump DataPatch",
|
||||||
|
"Created nested folder": "Created nested folder",
|
||||||
|
"Append folder with .xci": "Append folder with .xci",
|
||||||
|
"Trim XCI": "Trim XCI",
|
||||||
|
"Label trimmed XCI": "Label trimmed XCI",
|
||||||
|
"Multi-threaded USB transfer": "Multi-threaded USB transfer",
|
||||||
|
"Dump All Bins": "Dump All Bins",
|
||||||
|
"Dump XCI": "Dump XCI",
|
||||||
|
"Dump Card ID Set": "Dump Card ID Set",
|
||||||
|
"Dump Card UID": "Dump Card UID",
|
||||||
|
"Dump Certificate": "Dump Certificate",
|
||||||
|
"Dump Initial Data": "Dump Initial Data",
|
||||||
"Select dump location": "Select dump location",
|
"Select dump location": "Select dump location",
|
||||||
"microSD card (/dumps/NSP/)": "microSD card (/dumps/NSP/)",
|
"microSD card (/dumps/)": "microSD card (/dumps/)",
|
||||||
"USB transfer (Switch 2 Switch)": "USB transfer (Switch 2 Switch)",
|
"USB transfer (Switch 2 Switch)": "USB transfer (Switch 2 Switch)",
|
||||||
"/dev/null (Speed Test)": "/dev/null (Speed Test)",
|
"/dev/null (Speed Test)": "/dev/null (Speed Test)",
|
||||||
"Dumping": "Dumping",
|
"Dumping": "Dumping",
|
||||||
"Dump successfull!": "Dump successfull!",
|
"Dump successfull!": "Dump successfull!",
|
||||||
"Dump failed!": "Dump failed!",
|
"Dump failed!": "Dump failed!",
|
||||||
"Success": "Success",
|
|
||||||
"Delete successfull!": "Delete successfull!",
|
"Delete successfull!": "Delete successfull!",
|
||||||
"Delete failed!": "Delete failed!",
|
"Delete failed!": "Delete failed!",
|
||||||
|
"Success": "Success",
|
||||||
|
|
||||||
"Themezer": "Themezer",
|
"Themezer": "Themezer",
|
||||||
"Themezer Options": "Themezer Options",
|
"Themezer Options": "Themezer Options",
|
||||||
@@ -86,6 +102,8 @@
|
|||||||
"GitHub": "GitHub",
|
"GitHub": "GitHub",
|
||||||
"Downloading json": "Downloading json",
|
"Downloading json": "Downloading json",
|
||||||
"Select asset to download for ": "Select asset to download for ",
|
"Select asset to download for ": "Select asset to download for ",
|
||||||
|
"Failed to download json": "Failed to download json",
|
||||||
|
"Failed to download app!": "Failed to download app!",
|
||||||
|
|
||||||
"FTP Install": "FTP Install",
|
"FTP Install": "FTP Install",
|
||||||
"FTP Install (EXPERIMENTAL)": "FTP Install (EXPERIMENTAL)",
|
"FTP Install (EXPERIMENTAL)": "FTP Install (EXPERIMENTAL)",
|
||||||
@@ -122,9 +140,12 @@
|
|||||||
"GC": "GC",
|
"GC": "GC",
|
||||||
"System memory %.1f GB": "System memory %.1f GB",
|
"System memory %.1f GB": "System memory %.1f GB",
|
||||||
"microSD card %.1f GB": "microSD card %.1f GB",
|
"microSD card %.1f GB": "microSD card %.1f GB",
|
||||||
"Nand Install": "Nand Install",
|
|
||||||
"SD Card Install": "SD Card Install",
|
|
||||||
"Exit": "Exit",
|
"Exit": "Exit",
|
||||||
|
"Install disabled...\nPlease enable installing via the install options.": "Install disabled...\nPlease enable installing via the install options.",
|
||||||
|
"No GameCard inserted": "No GameCard inserted",
|
||||||
|
"GameCard is already trimmed!": "GameCard is already trimmed!",
|
||||||
|
"WARNING: GameCard is already trimmed!": "WARNING: GameCard is already trimmed!",
|
||||||
|
"Continue": "Continue",
|
||||||
"Gc install success!": "Gc install success!",
|
"Gc install success!": "Gc install success!",
|
||||||
"Gc install failed!": "Gc install failed!",
|
"Gc install failed!": "Gc install failed!",
|
||||||
|
|
||||||
@@ -160,14 +181,14 @@
|
|||||||
"Negative image": "Negative image",
|
"Negative image": "Negative image",
|
||||||
"Format": "Format",
|
"Format": "Format",
|
||||||
"Trimming Format": "Trimming Format",
|
"Trimming Format": "Trimming Format",
|
||||||
"320x240": "320×240",
|
|
||||||
"160x120": "160×120",
|
|
||||||
"80x60": "80×60",
|
|
||||||
"40x30": "40×30",
|
|
||||||
"20x15": "20×15",
|
|
||||||
"External Light Filter": "External Light Filter",
|
"External Light Filter": "External Light Filter",
|
||||||
"Load Default": "Load Default",
|
"Load Default": "Load Default",
|
||||||
|
|
||||||
|
"Web": "Web",
|
||||||
|
"Select URL": "Select URL",
|
||||||
|
"Enter custom URL": "Enter custom URL",
|
||||||
|
"Enter URL": "Enter URL",
|
||||||
|
|
||||||
"Advanced": "Advanced",
|
"Advanced": "Advanced",
|
||||||
"Advanced Options": "Advanced Options",
|
"Advanced Options": "Advanced Options",
|
||||||
"Logging": "Logging",
|
"Logging": "Logging",
|
||||||
@@ -181,10 +202,12 @@
|
|||||||
"Restored hbmenu": "Restored hbmenu",
|
"Restored hbmenu": "Restored hbmenu",
|
||||||
"Restart Sphaira?": "Restart Sphaira?",
|
"Restart Sphaira?": "Restart Sphaira?",
|
||||||
"Press OK to restart Sphaira": "Press OK to restart Sphaira",
|
"Press OK to restart Sphaira": "Press OK to restart Sphaira",
|
||||||
|
"Boost CPU during transfer": "Boost CPU during transfer",
|
||||||
"Text scroll speed": "Text scroll speed",
|
"Text scroll speed": "Text scroll speed",
|
||||||
"Slow": "Slow",
|
"Slow": "Slow",
|
||||||
"Normal": "Normal",
|
"Normal": "Normal",
|
||||||
"Fast": "Fast",
|
"Fast": "Fast",
|
||||||
|
"Set left-side menu": "Set left-side menu",
|
||||||
"Set right-side menu": "Set right-side menu",
|
"Set right-side menu": "Set right-side menu",
|
||||||
"Install options": "Install options",
|
"Install options": "Install options",
|
||||||
"Install Options": "Install Options",
|
"Install Options": "Install Options",
|
||||||
@@ -194,7 +217,6 @@
|
|||||||
"Install location": "Install location",
|
"Install location": "Install location",
|
||||||
"System memory": "System memory",
|
"System memory": "System memory",
|
||||||
"microSD card": "microSD card",
|
"microSD card": "microSD card",
|
||||||
"Boost CPU clock": "Boost CPU clock",
|
|
||||||
"Allow downgrade": "Allow downgrade",
|
"Allow downgrade": "Allow downgrade",
|
||||||
"Skip if already installed": "Skip if already installed",
|
"Skip if already installed": "Skip if already installed",
|
||||||
"Ticket only": "Ticket only",
|
"Ticket only": "Ticket only",
|
||||||
@@ -225,6 +247,8 @@
|
|||||||
"Updating ncm databse": "Updating ncm databse",
|
"Updating ncm databse": "Updating ncm databse",
|
||||||
"Pushing application record": "Pushing application record",
|
"Pushing application record": "Pushing application record",
|
||||||
"Failed to install forwarder": "Failed to install forwarder",
|
"Failed to install forwarder": "Failed to install forwarder",
|
||||||
|
"Unstar": "Unstar",
|
||||||
|
"Star": "Star",
|
||||||
"Unstarred ": "Unstarred ",
|
"Unstarred ": "Unstarred ",
|
||||||
"Starred ": "Starred ",
|
"Starred ": "Starred ",
|
||||||
"Failed to remove old forwarder, please manually remove it!": "Failed to remove old forwarder, please manually remove it!",
|
"Failed to remove old forwarder, please manually remove it!": "Failed to remove old forwarder, please manually remove it!",
|
||||||
@@ -257,12 +281,13 @@
|
|||||||
"Copy": "Copy",
|
"Copy": "Copy",
|
||||||
"Copying ": "Copying ",
|
"Copying ": "Copying ",
|
||||||
"Paste": "Paste",
|
"Paste": "Paste",
|
||||||
"Paste ": "Paste ",
|
"Paste file(s)?": "Paste file(s)?",
|
||||||
" file(s)?": " file(s)?",
|
|
||||||
"Pasting ": "Pasting ",
|
"Pasting ": "Pasting ",
|
||||||
"Pasting": "Pasting",
|
"Pasting": "Pasting",
|
||||||
"Rename": "Rename",
|
"Rename": "Rename",
|
||||||
"Set New File Name": "Set New File Name",
|
"Set New File Name": "Set New File Name",
|
||||||
|
"Failed to delete directory": "Failed to delete directory",
|
||||||
|
"Failed to delete file": "Failed to delete file",
|
||||||
"Extract zip": "Extract zip",
|
"Extract zip": "Extract zip",
|
||||||
"Extract Options": "Extract Options",
|
"Extract Options": "Extract Options",
|
||||||
"Extract here": "Extract here",
|
"Extract here": "Extract here",
|
||||||
@@ -285,13 +310,17 @@
|
|||||||
"Create Folder": "Create Folder",
|
"Create Folder": "Create Folder",
|
||||||
"Set Folder Name": "Set Folder Name",
|
"Set Folder Name": "Set Folder Name",
|
||||||
"Creating ": "Creating ",
|
"Creating ": "Creating ",
|
||||||
|
"View as text (unfinished)": "View as text (unfinished)",
|
||||||
"Upload": "Upload",
|
"Upload": "Upload",
|
||||||
"Select upload location": "Select upload location",
|
"Select upload location": "Select upload location",
|
||||||
"No upload locations set!": "No upload locations set!",
|
"No upload locations set!": "No upload locations set!",
|
||||||
"Uploading": "Uploading",
|
"Uploading": "Uploading",
|
||||||
"Upload successfull!": "Upload successfull!",
|
"Upload successfull!": "Upload successfull!",
|
||||||
"Upload failed!": "Upload failed!",
|
"Upload failed!": "Upload failed!",
|
||||||
"View as text (unfinished)": "View as text (unfinished)",
|
"Hash": "Hash",
|
||||||
|
"Hash Options": "Hash Options",
|
||||||
|
"Hashing": "Hashing",
|
||||||
|
"Failed to hash file...": "Failed to hash file...",
|
||||||
"Ignore read only": "Ignore read only",
|
"Ignore read only": "Ignore read only",
|
||||||
"Mount": "Mount",
|
"Mount": "Mount",
|
||||||
"Sd": "Sd",
|
"Sd": "Sd",
|
||||||
@@ -302,6 +331,7 @@
|
|||||||
"Launch ": "Launch ",
|
"Launch ": "Launch ",
|
||||||
"Launch option for: ": "Launch option for: ",
|
"Launch option for: ": "Launch option for: ",
|
||||||
"Select launcher for: ": "Select launcher for: ",
|
"Select launcher for: ": "Select launcher for: ",
|
||||||
|
"Close FileBrowser?": "Close FileBrowser?",
|
||||||
|
|
||||||
"Sort By": "Sort By",
|
"Sort By": "Sort By",
|
||||||
"Sort Options": "Sort Options",
|
"Sort Options": "Sort Options",
|
||||||
@@ -335,16 +365,16 @@
|
|||||||
"Search": "Search",
|
"Search": "Search",
|
||||||
|
|
||||||
"Options": "Options",
|
"Options": "Options",
|
||||||
|
"Split": "Split",
|
||||||
"OK": "OK",
|
"OK": "OK",
|
||||||
"Back": "Back",
|
"Back": "Back",
|
||||||
"Select": "Select",
|
"Select": "Select",
|
||||||
"Open": "Open",
|
"Open": "Open",
|
||||||
|
"Close": "Close",
|
||||||
"Launch": "Launch",
|
"Launch": "Launch",
|
||||||
"Restart": "Restart",
|
"Restart": "Restart",
|
||||||
"Next": "Next",
|
"Next": "Next",
|
||||||
"Prev": "Prev",
|
"Prev": "Prev",
|
||||||
"Unstar": "Unstar",
|
|
||||||
"Star": "Star",
|
|
||||||
"Yes": "Yes",
|
"Yes": "Yes",
|
||||||
"No": "No",
|
"No": "No",
|
||||||
"On": "On",
|
"On": "On",
|
||||||
@@ -367,12 +397,13 @@
|
|||||||
"Remove": "Remove",
|
"Remove": "Remove",
|
||||||
"Completely remove ": "Completely remove ",
|
"Completely remove ": "Completely remove ",
|
||||||
"Removing ": "Removing ",
|
"Removing ": "Removing ",
|
||||||
"Removed ": "Removed ",
|
|
||||||
"Uninstalling ": "Uninstalling ",
|
"Uninstalling ": "Uninstalling ",
|
||||||
|
"Removed ": "Removed ",
|
||||||
|
|
||||||
"Download": "Download",
|
"Download": "Download",
|
||||||
"Downloading ": "Downloading ",
|
"Downloading ": "Downloading ",
|
||||||
"Downloaded ": "Downloaded ",
|
"Downloaded ": "Downloaded ",
|
||||||
|
"Download via the Network options!": "Download via the Network options!",
|
||||||
|
|
||||||
"Update": "Update",
|
"Update": "Update",
|
||||||
"Update avaliable: ": "Update avaliable: ",
|
"Update avaliable: ": "Update avaliable: ",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
"No Internet": "Sin Internet",
|
"No Internet": "Sin Internet",
|
||||||
"Switch-Handheld!": "¡Switch-Modo-Portátil!",
|
"Switch-Handheld!": "¡Switch-Modo-Portátil!",
|
||||||
"Switch-Docked!": "¡Switch-Modo-TV!",
|
"Switch-Docked!": "¡Switch-Modo-TV!",
|
||||||
|
"Warning! Logs are enabled, Sphaira will run slowly!": "",
|
||||||
"Audio disabled due to suspended game": "",
|
"Audio disabled due to suspended game": "",
|
||||||
"Are you sure you wish to cancel?": "¿Estás seguro que deseas cancelar?",
|
"Are you sure you wish to cancel?": "¿Estás seguro que deseas cancelar?",
|
||||||
"An error occurred": "",
|
"An error occurred": "",
|
||||||
@@ -27,6 +28,8 @@
|
|||||||
"Nxlink Connected": "NXlink conectado",
|
"Nxlink Connected": "NXlink conectado",
|
||||||
"Nxlink Upload": "NXlink subida",
|
"Nxlink Upload": "NXlink subida",
|
||||||
"Nxlink Finished": "NXlink finalizado",
|
"Nxlink Finished": "NXlink finalizado",
|
||||||
|
"Hdd": "",
|
||||||
|
"Hdd write protect": "",
|
||||||
|
|
||||||
"Language": "Idioma",
|
"Language": "Idioma",
|
||||||
"Auto": "Automático",
|
"Auto": "Automático",
|
||||||
@@ -57,22 +60,35 @@
|
|||||||
"No meta entries found...\n": "",
|
"No meta entries found...\n": "",
|
||||||
"Updating application record list": "",
|
"Updating application record list": "",
|
||||||
"Dump": "",
|
"Dump": "",
|
||||||
|
"Dump options": "",
|
||||||
|
"Dump Options": "",
|
||||||
"Select content to dump": "",
|
"Select content to dump": "",
|
||||||
"Dump All": "",
|
"Dump All": "",
|
||||||
"Dump Application": "",
|
"Dump Application": "",
|
||||||
"Dump Patch": "",
|
"Dump Patch": "",
|
||||||
"Dump AddOnContent": "",
|
"Dump AddOnContent": "",
|
||||||
"Dump DataPatch": "",
|
"Dump DataPatch": "",
|
||||||
|
"Created nested folder": "",
|
||||||
|
"Append folder with .xci": "",
|
||||||
|
"Trim XCI": "",
|
||||||
|
"Label trimmed XCI": "",
|
||||||
|
"Multi-threaded USB transfer": "",
|
||||||
|
"Dump All Bins": "",
|
||||||
|
"Dump XCI": "",
|
||||||
|
"Dump Card ID Set": "",
|
||||||
|
"Dump Card UID": "",
|
||||||
|
"Dump Certificate": "",
|
||||||
|
"Dump Initial Data": "",
|
||||||
"Select dump location": "",
|
"Select dump location": "",
|
||||||
"microSD card (/dumps/NSP/)": "",
|
"microSD card (/dumps/)": "",
|
||||||
"USB transfer (Switch 2 Switch)": "",
|
"USB transfer (Switch 2 Switch)": "",
|
||||||
"/dev/null (Speed Test)": "",
|
"/dev/null (Speed Test)": "",
|
||||||
"Dumping": "",
|
"Dumping": "",
|
||||||
"Dump successfull!": "",
|
"Dump successfull!": "",
|
||||||
"Dump failed!": "",
|
"Dump failed!": "",
|
||||||
"Success": "",
|
|
||||||
"Delete successfull!": "",
|
"Delete successfull!": "",
|
||||||
"Delete failed!": "",
|
"Delete failed!": "",
|
||||||
|
"Success": "",
|
||||||
|
|
||||||
"Themezer": "Themezer",
|
"Themezer": "Themezer",
|
||||||
"Themezer Options": "Opciones de Themezer",
|
"Themezer Options": "Opciones de Themezer",
|
||||||
@@ -86,6 +102,8 @@
|
|||||||
"GitHub": "GitHub",
|
"GitHub": "GitHub",
|
||||||
"Downloading json": "Descargando json",
|
"Downloading json": "Descargando json",
|
||||||
"Select asset to download for ": "Seleccionar recurso a descargar para ",
|
"Select asset to download for ": "Seleccionar recurso a descargar para ",
|
||||||
|
"Failed to download json": "",
|
||||||
|
"Failed to download app!": "",
|
||||||
|
|
||||||
"FTP Install": "",
|
"FTP Install": "",
|
||||||
"FTP Install (EXPERIMENTAL)": "",
|
"FTP Install (EXPERIMENTAL)": "",
|
||||||
@@ -122,9 +140,12 @@
|
|||||||
"GC": "",
|
"GC": "",
|
||||||
"System memory %.1f GB": "",
|
"System memory %.1f GB": "",
|
||||||
"microSD card %.1f GB": "",
|
"microSD card %.1f GB": "",
|
||||||
"Nand Install": "",
|
|
||||||
"SD Card Install": "",
|
|
||||||
"Exit": "",
|
"Exit": "",
|
||||||
|
"Install disabled...\nPlease enable installing via the install options.": "",
|
||||||
|
"No GameCard inserted": "",
|
||||||
|
"GameCard is already trimmed!": "",
|
||||||
|
"WARNING: GameCard is already trimmed!": "",
|
||||||
|
"Continue": "",
|
||||||
"Gc install success!": "",
|
"Gc install success!": "",
|
||||||
"Gc install failed!": "",
|
"Gc install failed!": "",
|
||||||
|
|
||||||
@@ -160,14 +181,14 @@
|
|||||||
"Negative image": "Imagen negativa",
|
"Negative image": "Imagen negativa",
|
||||||
"Format": "Formato",
|
"Format": "Formato",
|
||||||
"Trimming Format": "Formato de recorte",
|
"Trimming Format": "Formato de recorte",
|
||||||
"320x240": "320×240",
|
|
||||||
"160x120": "160×120",
|
|
||||||
"80x60": "80×60",
|
|
||||||
"40x30": "40×30",
|
|
||||||
"20x15": "20×15",
|
|
||||||
"External Light Filter": "Filtro de luz externa",
|
"External Light Filter": "Filtro de luz externa",
|
||||||
"Load Default": "Cargar predeterminado",
|
"Load Default": "Cargar predeterminado",
|
||||||
|
|
||||||
|
"Web": "",
|
||||||
|
"Select URL": "",
|
||||||
|
"Enter custom URL": "",
|
||||||
|
"Enter URL": "",
|
||||||
|
|
||||||
"Advanced": "Avanzado",
|
"Advanced": "Avanzado",
|
||||||
"Advanced Options": "Opciones avanzadas",
|
"Advanced Options": "Opciones avanzadas",
|
||||||
"Logging": "Registro",
|
"Logging": "Registro",
|
||||||
@@ -181,10 +202,12 @@
|
|||||||
"Restored hbmenu": "hbmenu restaurado",
|
"Restored hbmenu": "hbmenu restaurado",
|
||||||
"Restart Sphaira?": "¿Reiniciar sphaira?",
|
"Restart Sphaira?": "¿Reiniciar sphaira?",
|
||||||
"Press OK to restart Sphaira": "Presiona OK para reiniciar sphaira",
|
"Press OK to restart Sphaira": "Presiona OK para reiniciar sphaira",
|
||||||
|
"Boost CPU during transfer": "",
|
||||||
"Text scroll speed": "Velocidad de scroll",
|
"Text scroll speed": "Velocidad de scroll",
|
||||||
"Slow": "Lento",
|
"Slow": "Lento",
|
||||||
"Normal": "Normal",
|
"Normal": "Normal",
|
||||||
"Fast": "Rápido",
|
"Fast": "Rápido",
|
||||||
|
"Set left-side menu": "",
|
||||||
"Set right-side menu": "",
|
"Set right-side menu": "",
|
||||||
"Install options": "",
|
"Install options": "",
|
||||||
"Install Options": "",
|
"Install Options": "",
|
||||||
@@ -194,7 +217,6 @@
|
|||||||
"Install location": "Dispositivo de instalación",
|
"Install location": "Dispositivo de instalación",
|
||||||
"System memory": "Memoria de sistema",
|
"System memory": "Memoria de sistema",
|
||||||
"microSD card": "microSD",
|
"microSD card": "microSD",
|
||||||
"Boost CPU clock": "",
|
|
||||||
"Allow downgrade": "",
|
"Allow downgrade": "",
|
||||||
"Skip if already installed": "",
|
"Skip if already installed": "",
|
||||||
"Ticket only": "",
|
"Ticket only": "",
|
||||||
@@ -225,6 +247,8 @@
|
|||||||
"Updating ncm databse": "Actualizando base de datos ncm",
|
"Updating ncm databse": "Actualizando base de datos ncm",
|
||||||
"Pushing application record": "Registro de aplicación",
|
"Pushing application record": "Registro de aplicación",
|
||||||
"Failed to install forwarder": "Fallo al instalar forwarder",
|
"Failed to install forwarder": "Fallo al instalar forwarder",
|
||||||
|
"Unstar": "Quitar favorito",
|
||||||
|
"Star": "Favorito",
|
||||||
"Unstarred ": "Quitar Favorito",
|
"Unstarred ": "Quitar Favorito",
|
||||||
"Starred ": "Favorito",
|
"Starred ": "Favorito",
|
||||||
"Failed to remove old forwarder, please manually remove it!": "",
|
"Failed to remove old forwarder, please manually remove it!": "",
|
||||||
@@ -257,12 +281,13 @@
|
|||||||
"Copy": "Copiar",
|
"Copy": "Copiar",
|
||||||
"Copying ": "Copiando ",
|
"Copying ": "Copiando ",
|
||||||
"Paste": "Pegar",
|
"Paste": "Pegar",
|
||||||
"Paste ": "Pegar ",
|
"Paste file(s)?": "",
|
||||||
" file(s)?": " ¿archivo(s)?",
|
|
||||||
"Pasting ": "Pegando ",
|
"Pasting ": "Pegando ",
|
||||||
"Pasting": "Pegando",
|
"Pasting": "Pegando",
|
||||||
"Rename": "Renombrar",
|
"Rename": "Renombrar",
|
||||||
"Set New File Name": "Establecer nuevo nombre de archivo",
|
"Set New File Name": "Establecer nuevo nombre de archivo",
|
||||||
|
"Failed to delete directory": "",
|
||||||
|
"Failed to delete file": "",
|
||||||
"Extract zip": "",
|
"Extract zip": "",
|
||||||
"Extract Options": "",
|
"Extract Options": "",
|
||||||
"Extract here": "",
|
"Extract here": "",
|
||||||
@@ -285,13 +310,17 @@
|
|||||||
"Create Folder": "Crear carpeta",
|
"Create Folder": "Crear carpeta",
|
||||||
"Set Folder Name": "Establecer nombre de carpeta",
|
"Set Folder Name": "Establecer nombre de carpeta",
|
||||||
"Creating ": "Creando ",
|
"Creating ": "Creando ",
|
||||||
|
"View as text (unfinished)": "Ver como texto (sin terminar)",
|
||||||
"Upload": "",
|
"Upload": "",
|
||||||
"Select upload location": "",
|
"Select upload location": "",
|
||||||
"No upload locations set!": "",
|
"No upload locations set!": "",
|
||||||
"Uploading": "",
|
"Uploading": "",
|
||||||
"Upload successfull!": "",
|
"Upload successfull!": "",
|
||||||
"Upload failed!": "",
|
"Upload failed!": "",
|
||||||
"View as text (unfinished)": "Ver como texto (sin terminar)",
|
"Hash": "",
|
||||||
|
"Hash Options": "",
|
||||||
|
"Hashing": "",
|
||||||
|
"Failed to hash file...": "",
|
||||||
"Ignore read only": "Ignorar sólo lectura",
|
"Ignore read only": "Ignorar sólo lectura",
|
||||||
"Mount": "Montar",
|
"Mount": "Montar",
|
||||||
"Sd": "SD",
|
"Sd": "SD",
|
||||||
@@ -302,6 +331,7 @@
|
|||||||
"Launch ": "Abrir ",
|
"Launch ": "Abrir ",
|
||||||
"Launch option for: ": "Opción de abrir con: ",
|
"Launch option for: ": "Opción de abrir con: ",
|
||||||
"Select launcher for: ": "Seleccionar abrir con: ",
|
"Select launcher for: ": "Seleccionar abrir con: ",
|
||||||
|
"Close FileBrowser?": "",
|
||||||
|
|
||||||
"Sort By": "Ordenar por",
|
"Sort By": "Ordenar por",
|
||||||
"Sort Options": "Opciones de clasificación",
|
"Sort Options": "Opciones de clasificación",
|
||||||
@@ -335,16 +365,16 @@
|
|||||||
"Search": "Buscar",
|
"Search": "Buscar",
|
||||||
|
|
||||||
"Options": "Opciones",
|
"Options": "Opciones",
|
||||||
|
"Split": "",
|
||||||
"OK": "OK",
|
"OK": "OK",
|
||||||
"Back": "Atrás",
|
"Back": "Atrás",
|
||||||
"Select": "Seleccionar",
|
"Select": "Seleccionar",
|
||||||
"Open": "Abrir",
|
"Open": "Abrir",
|
||||||
|
"Close": "",
|
||||||
"Launch": "Ejecutar",
|
"Launch": "Ejecutar",
|
||||||
"Restart": "Reiniciar",
|
"Restart": "Reiniciar",
|
||||||
"Next": "",
|
"Next": "",
|
||||||
"Prev": "",
|
"Prev": "",
|
||||||
"Unstar": "Quitar favorito",
|
|
||||||
"Star": "Favorito",
|
|
||||||
"Yes": "Sí",
|
"Yes": "Sí",
|
||||||
"No": "No",
|
"No": "No",
|
||||||
"On": "",
|
"On": "",
|
||||||
@@ -367,12 +397,13 @@
|
|||||||
"Remove": "Borrar",
|
"Remove": "Borrar",
|
||||||
"Completely remove ": "Eliminar completamente",
|
"Completely remove ": "Eliminar completamente",
|
||||||
"Removing ": "Removiendo ",
|
"Removing ": "Removiendo ",
|
||||||
"Removed ": "Removido ",
|
|
||||||
"Uninstalling ": "Desinstalando ",
|
"Uninstalling ": "Desinstalando ",
|
||||||
|
"Removed ": "Removido ",
|
||||||
|
|
||||||
"Download": "Descargar",
|
"Download": "Descargar",
|
||||||
"Downloading ": "Descargando ",
|
"Downloading ": "Descargando ",
|
||||||
"Downloaded ": "Descargado ",
|
"Downloaded ": "Descargado ",
|
||||||
|
"Download via the Network options!": "",
|
||||||
|
|
||||||
"Update": "Actualizar",
|
"Update": "Actualizar",
|
||||||
"Update avaliable: ": "Actualización disponible: ",
|
"Update avaliable: ": "Actualización disponible: ",
|
||||||
|
|||||||
@@ -1,32 +1,35 @@
|
|||||||
{
|
{
|
||||||
"[Applet Mode]": "[Mode Applet]",
|
"[Applet Mode]": "[Mode Applet]",
|
||||||
"No Internet": "Pas d'Internet",
|
"No Internet": "Pas d'Internet",
|
||||||
"Switch-Handheld!": "Switch-Portable",
|
"Switch-Handheld!": "Mode Portable",
|
||||||
"Switch-Docked!": "Switch-Dockée",
|
"Switch-Docked!": "Mode Dockée",
|
||||||
"Audio disabled due to suspended game": "Audio désactivé à cause d'un jeu suspendu",
|
"Warning! Logs are enabled, Sphaira will run slowly!": "Attention ! Les journaux sont activés, Sphaira fonctionnera lentement !",
|
||||||
"Are you sure you wish to cancel?": "Souhaitez-vous vraiment annuler?",
|
"Audio disabled due to suspended game": "Audio désactivé à cause d'un jeu en pause",
|
||||||
|
"Are you sure you wish to cancel?": "Souhaitez-vous vraiment annuler ?",
|
||||||
"An error occurred": "Une erreur s'est produite",
|
"An error occurred": "Une erreur s'est produite",
|
||||||
"If this message appears repeatedly, please open an issue.": "Si ce message apparait en boucle veuillez ouvrir une issue.",
|
"If this message appears repeatedly, please open an issue.": "Si ce message apparaît en boucle, veuillez ouvrir une issue sur :",
|
||||||
|
|
||||||
"Menu Options": "Options des Menus",
|
"Menu Options": "Paramètres",
|
||||||
"Menu": "Menu",
|
"Menu": "Paramètres",
|
||||||
"Theme": "Thème",
|
"Theme": "Thèmes",
|
||||||
"Theme Options": "Options de Thème",
|
"Theme Options": "Paramètres des Thèmes",
|
||||||
"Select Theme": "Choisir un Thème",
|
"Select Theme": "Choisir un thème",
|
||||||
"Music": "Musique",
|
"Music": "Musique",
|
||||||
"12 Hour Time": "Temps sur 12 heures",
|
"12 Hour Time": "Format horloge 12 heures",
|
||||||
"Download Default Music": "Télécharger la musique par défaut",
|
"Download Default Music": "Télécharger la musique par défaut",
|
||||||
"Failed to download default_music.bfstm, please try again": "Echec du téléchargement de default_music.bfstm, veuillez réessayer",
|
"Failed to download default_music.bfstm, please try again": "Échec du téléchargement de default_music.bfstm, veuillez réessayer",
|
||||||
"Overwrite current default music?": "Remplacer la musique actuelle par défaut?",
|
"Overwrite current default music?": "Remplacer la musique actuelle par défaut ?",
|
||||||
|
|
||||||
"Network": "Réseau",
|
"Network": "Réseau",
|
||||||
"Network Options": "Options Réseau",
|
"Network Options": "Paramètres Réseau",
|
||||||
"Ftp": "FTP",
|
"Ftp": "FTP",
|
||||||
"Mtp": "MTP",
|
"Mtp": "MTP",
|
||||||
"Nxlink": "Nxlink",
|
"Nxlink": "Nxlink",
|
||||||
"Nxlink Connected": "Nxlink Connecté",
|
"Nxlink Connected": "Nxlink Connecté",
|
||||||
"Nxlink Upload": "Nxlink téléversement",
|
"Nxlink Upload": "Téléchargement Nxlink",
|
||||||
"Nxlink Finished": "Nxlink terminé",
|
"Nxlink Finished": "Nxlink terminé",
|
||||||
|
"Hdd": "Disque Dur",
|
||||||
|
"Hdd write protect": "Protection en écriture du disque dur",
|
||||||
|
|
||||||
"Language": "Langue",
|
"Language": "Langue",
|
||||||
"Auto": "Auto",
|
"Auto": "Auto",
|
||||||
@@ -47,65 +50,80 @@
|
|||||||
|
|
||||||
"Misc": "Divers",
|
"Misc": "Divers",
|
||||||
"Misc Options": "Options Diverses",
|
"Misc Options": "Options Diverses",
|
||||||
"Games": "Jeux",
|
"Games": "Jeux installés",
|
||||||
"Game Options": "Options de jeu",
|
"Game Options": "Options des jeux",
|
||||||
"Hide forwarders": "Masquer les forwarders",
|
"Hide forwarders": "Masquer les forwarders",
|
||||||
"Launch random game": "Lancer un jeu au hasard",
|
"Launch random game": "Lancer un jeu au hasard",
|
||||||
"List meta records": "Lister les enregistrements meta",
|
"List meta records": "Lister les méta-enregistrements",
|
||||||
"Entries": "Entrées",
|
"Entries": "Meta disponible",
|
||||||
"Failed to list application meta entries": "Le listage des entrées meta de l'application a échoué",
|
"Failed to list application meta entries": "Le listage des entrées meta de l'application a échoué",
|
||||||
"No meta entries found...\n": "Aucune entrée meta trouvée...\n",
|
"No meta entries found...\n": "Aucune entrée meta trouvée...\n",
|
||||||
"Updating application record list": "Mise à jour de la liste d'enregistrement de l'application",
|
"Updating application record list": "Mise à jour de la liste d'enregistrement de l'application",
|
||||||
"Dump": "Dumper",
|
"Dump": "Dumper",
|
||||||
"Select content to dump": "Sélectionner un contenu à dumper",
|
"Dump options": "Option du Dumper",
|
||||||
|
"Dump options": "Paramètres",
|
||||||
|
"Select content to dump": "Contenu à dumper",
|
||||||
"Dump All": "Tout dumper",
|
"Dump All": "Tout dumper",
|
||||||
"Dump Application": "Dumper Application",
|
"Dump Application": "Dumper uniquement l'application (jeu)",
|
||||||
"Dump Patch": "Dumper mise à jour",
|
"Dump Patch": "Dumper uniquement la mise à jour",
|
||||||
"Dump AddOnContent": "Dumper DLCs",
|
"Dump AddOnContent": "Dumper uniquement le(s) DLCs",
|
||||||
"Dump DataPatch": "Dumper patch de données",
|
"Dump DataPatch": "Dumper le patch de données",
|
||||||
"Select dump location": "Sélectionner l'emplacement du dump",
|
"Created nested folder": "Créer un dossier imbriqué",
|
||||||
"microSD card (/dumps/NSP/)": "carte microSD (/dumps/NSP/)",
|
"Append folder with .xci": "Ajouter un dossier avec .xci",
|
||||||
|
"Trim XCI": "Trimmer le XCI",
|
||||||
|
"Label trimmed XCI": "Étiquette sur le XCI trimmer",
|
||||||
|
"Multi-threaded USB transfer": "Transfert USB multithread",
|
||||||
|
"Dump All Bins": "",
|
||||||
|
"Dump XCI": "",
|
||||||
|
"Dump Card ID Set": "",
|
||||||
|
"Dump Card UID": "",
|
||||||
|
"Dump Certificate": "",
|
||||||
|
"Dump Initial Data": "",
|
||||||
|
"Select dump location": "Sélectionner l'emplacement du dump :",
|
||||||
|
"microSD card (/dumps/)": "carte microSD (/dumps/)",
|
||||||
"USB transfer (Switch 2 Switch)": "Transfert USB (Switch à Switch",
|
"USB transfer (Switch 2 Switch)": "Transfert USB (Switch à Switch",
|
||||||
"/dev/null (Speed Test)": "/dev/null (test de vitesse)",
|
"/dev/null (Speed Test)": "/dev/null (test de vitesse)",
|
||||||
"Dumping": "Dump en cours",
|
"Dumping": "Dump en cours...",
|
||||||
"Dump successfull!": "Dump réussi!",
|
"Dump successfull!": "Dump réussi !",
|
||||||
"Dump failed!": "Dump échoué!",
|
"Dump failed!": "Échec du dump !",
|
||||||
|
"Delete successful!": "Fichier supprimé !",
|
||||||
|
"Delete failed!": "Échec de la suppression !",
|
||||||
"Success": "Succès",
|
"Success": "Succès",
|
||||||
"Delete successfull!": "Suprression réussie!",
|
|
||||||
"Delete failed!": "Suprression échouée!",
|
|
||||||
|
|
||||||
"Themezer": "Themezer",
|
"Themezer": "Themezer (thèmes Switch)",
|
||||||
"Themezer Options": "Options Themezer",
|
"Themezer Options": "Paramètres",
|
||||||
"Nsfw": "Nsfw",
|
"Nsfw": "Contenu NSFW",
|
||||||
"Page": "Page",
|
"Page": "Page",
|
||||||
"Page %zu / %zu": "Page %zu / %zu",
|
"Page %zu / %zu": "Page %zu / %zu",
|
||||||
"Enter Page Number": "Entrez Un Numéro De Page",
|
"Enter Page Number": "Numéro de la page :",
|
||||||
"Bad Page": "Page inexistante",
|
"Bad Page": "Page inexistante",
|
||||||
"Download theme?": "Télécharger le thème?",
|
"Download theme?": "Voulez-vous télécharger ce thème ?",
|
||||||
|
|
||||||
"GitHub": "GitHub",
|
"GitHub": "Github",
|
||||||
"Downloading json": "Téléchargement du json",
|
"Downloading json": "Téléchargement du .json",
|
||||||
"Select asset to download for ": "Sélectionner l'asset à télécharger pour ",
|
"Select asset to download for ": "Sélectionnez l'actif à télécharger pour :",
|
||||||
|
"Failed to download json": "Échec du téléchargement de .json",
|
||||||
|
"Failed to download app!": "Échec du téléchargement de l'application",
|
||||||
|
|
||||||
"FTP Install": "Installation via FTP",
|
"FTP Install": "Installer contenu via FTP",
|
||||||
"FTP Install (EXPERIMENTAL)": "Installation via FTP (EXPERIMENTAL)",
|
"FTP Install (EXPERIMENTAL)": "Installation via FTP (EXPERIMENTAL)",
|
||||||
"Connection Type: WiFi | Strength: ": "Type de connexion: WiFi, force du signal: ",
|
"Connection Type: WiFi | Strength: ": "Type de connexion : WiFi / Force du signal :",
|
||||||
"Connection Type: Ethernet": "Type de connexion: Ethernet",
|
"Connection Type: Ethernet": "Type de connexion : Ethernet",
|
||||||
"Connection Type: None": "Type de connexion: Aucune",
|
"Connection Type: None": "Type de connexion : Aucune",
|
||||||
"Host:": "Hôte:",
|
"Host:": "Hôte :",
|
||||||
"Port:": "Port:",
|
"Port:": "Port :",
|
||||||
"Username:": "Nom d'utilisateur:",
|
"Username:": "Nom d'utilisateur :",
|
||||||
"Password:": "Mot de passe:",
|
"Password:": "Mot de passe :",
|
||||||
"SSID:": "SSID:",
|
"SSID:": "SSID :",
|
||||||
"Passphrase:": "Mot de passe:",
|
"Passphrase:": "Mot de passe :",
|
||||||
"Failed to install via FTP, press B to exit...": "Installation via FTP échouée, appuyer sur B pour quitter...",
|
"Failed to install via FTP, press B to exit...": "Installation via FTP échouée, appuyer sur B pour quitter...",
|
||||||
"Ftp install success!": "Installation via FTP réussie!",
|
"Ftp install success!": "Installation via FTP réussie !",
|
||||||
"Ftp install failed!": "Installation via FTP échouée!",
|
"Ftp install failed!": "Installation via FTP échouée !",
|
||||||
"USB Install": "Installation via USB",
|
"USB Install": "Installer contenu via USB",
|
||||||
"USB": "USB",
|
"USB": "Installation via USB",
|
||||||
"Connected, waiting for file list...": "Connecté, en attente de la liste des fichiers...",
|
"Connected, waiting for file list...": "Connecté, en attente de la liste des fichiers...",
|
||||||
"Connected, starting transfer...": "Connecté, début du transfère...",
|
"Connected, starting transfer...": "Connecté, début du transfère...",
|
||||||
"Failed to init usb, press B to exit...": "Echec de l'initialisation de l'USB, appuyer sur B pour quitter...",
|
"Failed to init usb, press B to exit...": "Échec de l'initialisation de l'USB, appuyer sur B pour quitter...",
|
||||||
"Waiting for connection...": "En attente de la connexion...",
|
"Waiting for connection...": "En attente de la connexion...",
|
||||||
"Transferring data...": "Transfère de données...",
|
"Transferring data...": "Transfère de données...",
|
||||||
"USB connected, sending file list": "USB connecté, envoi de la liste des fichiers",
|
"USB connected, sending file list": "USB connecté, envoi de la liste des fichiers",
|
||||||
@@ -114,29 +132,32 @@
|
|||||||
"Disable MTP for usb install": "Désactivation du MTP pour l'installation via USB",
|
"Disable MTP for usb install": "Désactivation du MTP pour l'installation via USB",
|
||||||
"Re-enabled MTP": "Réactivation du MTP",
|
"Re-enabled MTP": "Réactivation du MTP",
|
||||||
"Installed via usb": "Installé via USB",
|
"Installed via usb": "Installé via USB",
|
||||||
"Usb install success!": "Installation via USB réussie!",
|
"Usb install success!": "Installation via USB réussie !",
|
||||||
"Usb install failed!": "Installation via USB échouée!",
|
"Usb install failed!": "Installation via USB échouée !",
|
||||||
"Press B to exit...": "Appuyer sur B pour quitter...",
|
"Press B to exit...": "Appuyer sur B pour quitter...",
|
||||||
"GameCard Install": "Installation de la cartouche",
|
"GameCard Install": "Installation de la cartouche du jeu",
|
||||||
"GameCard": "Cartouche",
|
"GameCard": "Carte du jeu",
|
||||||
"GC": "GC",
|
"GC": "GC",
|
||||||
"System memory %.1f GB": "Mémoire système %.1f GB",
|
"System memory %.1f GB": "Mémoire système %.1f GB",
|
||||||
"microSD card %.1f GB": "Carte microSD %.1f GB",
|
"microSD card %.1f GB": "Carte microSD %.1f GB",
|
||||||
"Nand Install": "Installer sur la Nand",
|
|
||||||
"SD Card Install": "Installer sur la carte SD",
|
|
||||||
"Exit": "Quitter",
|
"Exit": "Quitter",
|
||||||
"Gc install success!": "Installation de la cartouche réussie!",
|
"Install disabled...\nPlease enable installing via the install options.": "Installation désactivée...\nVeuillez activer l'installation via les options d'installation.",
|
||||||
"Gc install failed!": "Installation de la cartouche échouée!",
|
"No GameCard inserted": "Aucune cartouche de jeu insérée !",
|
||||||
|
"GameCard is already trimmed!": "La carte du jeu est déjà trimmer !",
|
||||||
|
"WARNING: GameCard is already trimmed!": "AVERTISSEMENT : la carte du jeu est déjà trimmer ! ",
|
||||||
|
"Continue": "Continuer",
|
||||||
|
"Gc install success!": "Installation de la cartouche réussie !",
|
||||||
|
"Gc install failed!": "Installation de la cartouche échouée !",
|
||||||
|
|
||||||
"IRS (Infrared Joycon Camera)": "IRS (infrarouge de la caméra du Joycon",
|
"IRS (Infrared Joycon Camera)": "IRS (infrarouge de la cam du Joycon",
|
||||||
"IRS": "IRS",
|
"IRS": "Infrarouge Camera",
|
||||||
"Irs": "Irs",
|
"Irs": "Irs",
|
||||||
"Ambient Noise Level: ": "Niveau De Bruit Ambiant: ",
|
"Ambient Noise Level: ": "Niveau de bruit ambiant: ",
|
||||||
"Controller": "Contrôleur",
|
"Controller": "Contrôleur",
|
||||||
"Pad ": "Manette ",
|
"Pad ": "Manette",
|
||||||
"HandHeld": "Portable",
|
"HandHeld": "Joycon",
|
||||||
" (Available)": " (Disponible)",
|
" (Available)": " (Connectée)",
|
||||||
" (Unsupported)": "Non supporté",
|
" (Unsupported)": "Non supportée",
|
||||||
" (Unconnected)": " (Non connectée)",
|
" (Unconnected)": " (Non connectée)",
|
||||||
"Rotation": "Rotation",
|
"Rotation": "Rotation",
|
||||||
"0 (Sideways)": "0 (Paysage)",
|
"0 (Sideways)": "0 (Paysage)",
|
||||||
@@ -155,59 +176,60 @@
|
|||||||
"Dim group": "Groupe sombre",
|
"Dim group": "Groupe sombre",
|
||||||
"None": "Aucun",
|
"None": "Aucun",
|
||||||
"Gain": "Gain",
|
"Gain": "Gain",
|
||||||
"Negative Image": "Image Négative",
|
"Negative Image": "Format d'image",
|
||||||
"Normal image": "Image normale",
|
"Normal image": "Normale",
|
||||||
"Negative image": "Image négative",
|
"Negative image": "Négative",
|
||||||
"Format": "Format",
|
"Format": "Format d'image",
|
||||||
"Trimming Format": "Format de Découpe",
|
"Trimming Format": "Format du découpage",
|
||||||
"320x240": "320×240",
|
"External Light Filter": "Filtre de lumière externe",
|
||||||
"160x120": "160×120",
|
"Load Default": "Rétablir par Défaut",
|
||||||
"80x60": "80×60",
|
|
||||||
"40x30": "40×30",
|
|
||||||
"20x15": "20×15",
|
|
||||||
"External Light Filter": "Filtre de Lumière Externe",
|
|
||||||
"Load Default": "Charger par Défaut",
|
|
||||||
|
|
||||||
"Advanced": "Avancé",
|
"Web": "Web",
|
||||||
"Advanced Options": "Options Avancées",
|
"Select URL": "Sélectionnez une adresse",
|
||||||
"Logging": "Journalisation",
|
"Enter custom URL": "Entrez une adresse personnalisée",
|
||||||
"Replace hbmenu on exit": "Remplacer hbmenu quand quitté",
|
"Enter URL": "Enter l'adresse :",
|
||||||
"Restore hbmenu?": "Restaurer hbmenu?",
|
|
||||||
"Restore": "Restaurer",
|
"Advanced": "Menu avancé",
|
||||||
"Failed to find /switch/hbmenu.nro\nUse the Appstore to re-install hbmenu": "/switch/hbmenu.nro n'a pas été trouvé\nUtiliser l'Appstore pour réinstaller le hbmenu",
|
"Advanced Options": "Menu avancé",
|
||||||
"Failed to restore hbmenu, please re-download hbmenu": "Echec de la restauration de hbmenu, veuillez le réinstaller",
|
"Logging": "Fichier journal",
|
||||||
"Failed to restore hbmenu, using sphaira instead": "Echec de la restauration de hbmenu, sphaira sera utilisé à la place",
|
"Replace hbmenu on exit": "Remplacer HBmenu par Sphaira",
|
||||||
"Restored hbmenu, closing sphaira": "Hbmenu restauré, fermeture de sphaira",
|
"Restore hbmenu?": "Restaurer HBmenu ?",
|
||||||
"Restored hbmenu": "Hbmenu restauré",
|
"Restore": "Restaurer !",
|
||||||
"Restart Sphaira?": "Redémarrer Sphaira?",
|
"Failed to find /switch/hbmenu.nro\nUse the Appstore to re-install hbmenu": "/switch/hbmenu.nro non trouvé\nRéinstaller le HBmenu via Appstore",
|
||||||
|
"Failed to restore hbmenu, please re-download hbmenu": "Échec de la restauration du HBmenu, veuillez le réinstaller",
|
||||||
|
"Failed to restore hbmenu, using sphaira instead": "Échec de la restauration de HBmenu, Sphaira sera utilisé à la place",
|
||||||
|
"Restored hbmenu, closing sphaira": "Hbmenu restauré, fermeture de Sphaira",
|
||||||
|
"Restored hbmenu": "HBmenu restauré !",
|
||||||
|
"Restart Sphaira?": "Redémarrer Sphaira ?",
|
||||||
"Press OK to restart Sphaira": "Appuyez sur OK pour redémarrer Sphaira",
|
"Press OK to restart Sphaira": "Appuyez sur OK pour redémarrer Sphaira",
|
||||||
|
"Boost CPU during transfer": "Augmenter le CPU pendant le transfert",
|
||||||
"Text scroll speed": "Vitesse de défilement du texte",
|
"Text scroll speed": "Vitesse de défilement du texte",
|
||||||
"Slow": "Lent",
|
"Slow": "Lent",
|
||||||
"Normal": "Normal",
|
"Normal": "Normal",
|
||||||
"Fast": "Rapide",
|
"Fast": "Rapide",
|
||||||
"Set right-side menu": "Configurer le menu de droite",
|
"Set left-side menu": "Menu de gauche par défaut",
|
||||||
"Install options": "Options d'installation",
|
"Set right-side menu": "Menu de droite par défaut",
|
||||||
|
"Install options": "Options d'installation des jeux",
|
||||||
"Install Options": "Options d'Installation",
|
"Install Options": "Options d'Installation",
|
||||||
"Enable sysmmc": "Activer sur la sysmmc",
|
"Enable sysmmc": "Afficher la SYSmmc",
|
||||||
"Enable emummc": "Activer sur l'emummc",
|
"Enable emummc": "Afficher sur l'EMUmmc",
|
||||||
"Show install warning": "Afficher l'avertissement d'installation",
|
"Show install warning": "Avertissement lors d'installation",
|
||||||
"Install location": "Emplacement d'installation",
|
"Install location": "Emplacement d'installation",
|
||||||
"System memory": "Mémoire système",
|
"System memory": "Mémoire système",
|
||||||
"microSD card": "Carte microSD",
|
"microSD card": "Carte microSD",
|
||||||
"Boost CPU clock": "Augmenter la vitesse de l'horloge CPU",
|
|
||||||
"Allow downgrade": "Autoriser le downgrade",
|
"Allow downgrade": "Autoriser le downgrade",
|
||||||
"Skip if already installed": "Ignorer si déjà installé",
|
"Skip if already installed": "Ignorer si déjà installé",
|
||||||
"Ticket only": "Seulement le ticket",
|
"Ticket only": "Seulement le ticket",
|
||||||
"Skip base": "Ignorer base",
|
"Skip base": "Ignorer la base du jeu",
|
||||||
"Skip patch": "Ignorer mise à jour",
|
"Skip patch": "Ignorer les mises à jour",
|
||||||
"Skip dlc": "Ignorer DLC",
|
"Skip dlc": "Ignorer le(s) DLC",
|
||||||
"Skip data patch": "Ignorer patch de données",
|
"Skip data patch": "Ignorer le patch de données",
|
||||||
"Skip ticket": "Ignorer ticket",
|
"Skip ticket": "Ignorer ticket",
|
||||||
"Skip NCA hash verify": "Ignorer la vérification du hash NCA",
|
"Skip NCA hash verify": "Vérification du hash NCA",
|
||||||
"Skip RSA header verify": "Ignorer la vérification de l'entête RSA",
|
"Skip RSA header verify": "Vérification de l'entête RSA",
|
||||||
"Skip RSA NPDM verify": "Ignorer la vérification RSA NPDM",
|
"Skip RSA NPDM verify": "Vérification RSA NPDM",
|
||||||
"Ignore distribution bit": "Ignorer le bit de distribution",
|
"Ignore distribution bit": "Ignorer le bit de distribution",
|
||||||
"Convert to standard crypto": "Convertir vers la crypto standard",
|
"Convert to standard crypto": "Convertir en crypto standard",
|
||||||
"Lower master key": "Abaisser la master key",
|
"Lower master key": "Abaisser la master key",
|
||||||
"Lower system version": "Abaisser la version du système",
|
"Lower system version": "Abaisser la version du système",
|
||||||
|
|
||||||
@@ -216,33 +238,35 @@
|
|||||||
"Homebrew Options": "Options Homebrew",
|
"Homebrew Options": "Options Homebrew",
|
||||||
"Hide Sphaira": "Masquer Sphaira",
|
"Hide Sphaira": "Masquer Sphaira",
|
||||||
"Install Forwarder": "Installer le Forwarder",
|
"Install Forwarder": "Installer le Forwarder",
|
||||||
"WARNING: Installing forwarders will lead to a ban!": "ATTENTION: L'installation de forwarders entraînera un ban!",
|
"WARNING: Installing forwarders will lead to a ban!": "ATTENTION : L'installation de forwarders entraînera un ban !",
|
||||||
"Installing Forwarder": "Installation Du Forwarder",
|
"Installing Forwarder": "Installation du Forwarder...",
|
||||||
"Creating Program": "Création de Program",
|
"Creating Program": "Création de Program",
|
||||||
"Creating Control": "Création de Control",
|
"Creating Control": "Création de Control",
|
||||||
"Creating Meta": "Création de Meta",
|
"Creating Meta": "Création de Meta",
|
||||||
"Writing Nca": "Ecriture NCA",
|
"Writing Nca": "Écriture NCA",
|
||||||
"Updating ncm databse": "Mise à jour de ncm databse",
|
"Updating ncm databse": "Mise à jour de la base de données ncm",
|
||||||
"Pushing application record": "Ajout de l'enregistrement de l'application",
|
"Pushing application record": "Ajout de l'enregistrement de l'application",
|
||||||
"Failed to install forwarder": "Echec de l'installation du forwarder",
|
"Failed to install forwarder": "Échec de l'installation du forwarder",
|
||||||
"Unstarred ": "Retiré des favories ",
|
"Unstar": "Retirer des favories",
|
||||||
"Starred ": "Ajouté aux favories ",
|
"Star": "Ajouter aux favories",
|
||||||
"Failed to remove old forwarder, please manually remove it!": "Supression de l'ancien forwarder échouée, supprimez-le manuellement!",
|
"Unstarred ": "Retiré des favories : ",
|
||||||
|
"Starred ": "Ajouté aux favories : ",
|
||||||
|
"Failed to remove old forwarder, please manually remove it!": "Suppression de l'ancien forwarder échouée, supprimez-le manuellement !",
|
||||||
|
|
||||||
"AppStore": "AppStore",
|
"AppStore": "AppStore",
|
||||||
"Appstore": "Magasin d'applications",
|
"Appstore": "Boutique d'applications",
|
||||||
"Store": "Magasin",
|
"Store": "AppStore",
|
||||||
"Filter: %s | Sort: %s | Order: %s": "Filtre: %s | Tri: %s | Ordre: %s",
|
"Filter: %s | Sort : %s | Order: %s" : "Filtre : %s | Tri : %s | Ordre : %s",
|
||||||
"AppStore Options": "Options de l'AppStore",
|
"AppStore Options": "Options du AppStore",
|
||||||
"Info": "Info.",
|
"Info": "Info.",
|
||||||
"Changelog": "Journal des modifications",
|
"Changelog": "Journal des modifications",
|
||||||
"Details": "Détails",
|
"Details": "Détails",
|
||||||
"version: %s": "version: %s",
|
"version: %s": "version : %s",
|
||||||
"updated: %s": "Mis à jour: %s",
|
"updated: %s": "Mis à jour : %s",
|
||||||
"category: %s": "catégorie: %s",
|
"category: %s": "catégorie : %s",
|
||||||
"extracted: %.2f MiB": "Extrait: %.2f MiB",
|
"extracted: %.2f MiB": "Extrait: %.2f MiB",
|
||||||
"app_dls: %s": "app_dls: %s",
|
"app_dls: %s": "app_dls: %s",
|
||||||
"More by Author": "Plus de cet Auteur",
|
"More by Author": "Plus de cet auteur",
|
||||||
"Leave Feedback": "Laisser un avis",
|
"Leave Feedback": "Laisser un avis",
|
||||||
|
|
||||||
"FileBrowser": "Explorateur de Fichiers",
|
"FileBrowser": "Explorateur de Fichiers",
|
||||||
@@ -250,58 +274,64 @@
|
|||||||
"%zd files": "%zd fichiers",
|
"%zd files": "%zd fichiers",
|
||||||
"%zd dirs": "%zd dossiers",
|
"%zd dirs": "%zd dossiers",
|
||||||
"File Options": "Options de Fichier",
|
"File Options": "Options de Fichier",
|
||||||
"Show Hidden": "Afficher Masqués",
|
"Show Hidden": "Afficher fichier masqué",
|
||||||
"Folders First": "Dossiers en Premier",
|
"Folders First": "Dossiers en Premier",
|
||||||
"Hidden Last": "Masqués en Dernier",
|
"Hidden Last": "Masqués en Dernier",
|
||||||
"Cut": "Couper",
|
"Cut": "Couper",
|
||||||
"Copy": "Copier",
|
"Copy": "Copier",
|
||||||
"Copying ": "Copie en cours ",
|
"Copying ": "Copie en cours...",
|
||||||
"Paste": "Coller",
|
"Paste": "Coller",
|
||||||
"Paste ": "Coller ",
|
"Paste file(s)?": "Copier le colis ?",
|
||||||
" file(s)?": " fichier(s)?",
|
"Pasting": "Collage en cours...",
|
||||||
"Pasting ": "Collage en cours ",
|
"Pasting": "Collage en cours...",
|
||||||
"Pasting": "Collage en cours",
|
|
||||||
"Rename": "Renommer",
|
"Rename": "Renommer",
|
||||||
"Set New File Name": "Nouveau Nom Du Fichier",
|
"Set New File Name": "Nouveau nom du fichier",
|
||||||
|
"Failed to delete directory": "Échec de la suppression du répertoire",
|
||||||
|
"Failed to delete file": "Échec de la suppression du répertoire",
|
||||||
"Extract zip": "Extraire le zip",
|
"Extract zip": "Extraire le zip",
|
||||||
"Extract Options": "Options d'extraction",
|
"Extract Options": "Options d'extraction",
|
||||||
"Extract here": "Extraire ici",
|
"Extract here": "Extraire ici",
|
||||||
"Extract to root": "Extraire à la racine",
|
"Extract to root": "Extraire à la racine",
|
||||||
"Are you sure you want to extract to root?": "Souhaitez-vous vraiment extraire à la racine?",
|
"Are you sure you want to extract to root?": "Souhaitez-vous vraiment extraire à la racine ?",
|
||||||
"Extract to...": "Extraire vers...",
|
"Extract to...": "Extraire vers...",
|
||||||
"Enter the path to the folder to extract into": "Entrer le chemin du répertoire vers lequel extraire",
|
"Enter the path to the folder to extract into": "Entrer le chemin du répertoire vers lequel extraire",
|
||||||
"Extracting ": "Extraction en cours ",
|
"Extracting ": "Extraction en cours...",
|
||||||
"Extract success!": "Extraction réussie!",
|
"Extract success!": "Extraction réussie !",
|
||||||
"Extract failed!": "Extraction échouée!",
|
"Extract failed!": "Extraction échouée !",
|
||||||
"Compress to zip": "Compresser en zip",
|
"Compress to zip": "Compresser en zip",
|
||||||
"Compress Options": "Options de compression",
|
"Compress Options": "Options de compression",
|
||||||
"Compress": "Compresser",
|
"Compress": "Compresser",
|
||||||
"Compress to...": "Compresser vers...",
|
"Compress to...": "Compresser vers...",
|
||||||
"Compressing ": "Compression en cours ",
|
"Compressing ": "Compression en cours...",
|
||||||
"Compress success!": "Compression réussie!",
|
"Compress success!": "Compression réussie !",
|
||||||
"Compress failed!": "Compression échouée!",
|
"Compress failed!": "Compression échouée !",
|
||||||
"Create File": "Créer un Fichier",
|
"Create File": "Créer un fichier",
|
||||||
"Set File Name": "Nommer Le Fichier",
|
"Set File Name": "Nommer Le fichier",
|
||||||
"Create Folder": "Créer un Dossier",
|
"Create Folder": "Créer un dossier",
|
||||||
"Set Folder Name": "Nommer Le Dossier",
|
"Set Folder Name": "Nommer la dossier",
|
||||||
"Creating ": "Création ",
|
"Creating ": "Création ",
|
||||||
"Upload": "Upload",
|
|
||||||
"Select upload location": "Sélectionner l'emplacement d'upload",
|
|
||||||
"No upload locations set!": "Aucun emplacement d'upload configuré!",
|
|
||||||
"Uploading": "Upload en cours",
|
|
||||||
"Upload successfull!": "Upload réussi!",
|
|
||||||
"Upload failed!": "Upload échoué!",
|
|
||||||
"View as text (unfinished)": "Afficher sous forme de texte (inachevé)",
|
"View as text (unfinished)": "Afficher sous forme de texte (inachevé)",
|
||||||
|
"Upload": "Télécharger",
|
||||||
|
"Select upload location": "Emplacement du téléchargement :",
|
||||||
|
"No upload locations set!": "Aucun emplacement configuré !",
|
||||||
|
"Uploading": "Téléchargement en cours...",
|
||||||
|
"Upload successfull!": "Téléchargement réussi !",
|
||||||
|
"Upload failed!": "Téléchargement échoué !",
|
||||||
|
"Hash": "Hash",
|
||||||
|
"Hash Options": "Options du Hash",
|
||||||
|
"Hashing": "Hachage",
|
||||||
|
"Failed to hash file...": "Échec du hachage du fichier...",
|
||||||
"Ignore read only": "Ignorer lecture seule",
|
"Ignore read only": "Ignorer lecture seule",
|
||||||
"Mount": "Monter",
|
"Mount": "Monter",
|
||||||
"Sd": "Sd",
|
"Sd": "SD",
|
||||||
"Image System memory": "Image de la mémoire System",
|
"Image System memory": "Image de la mémoire Système",
|
||||||
"Image microSD card": "Image de la Carte microSD",
|
"Image microSD card": "Image de la Carte microSD",
|
||||||
"Empty...": "Vide...",
|
"Empty...": "Vide...",
|
||||||
"Open with DayBreak?": "Ouvrir avec DayBreak?",
|
"Open with DayBreak?": "Ouvrir avec DayBreak ?",
|
||||||
"Launch ": "Lancer ",
|
"Launch ": "Lancer ",
|
||||||
"Launch option for: ": "Option de lancement pour: ",
|
"Launch option for: ": "Option de lancement pour : ",
|
||||||
"Select launcher for: ": "Sélectionner le lanceur pour: ",
|
"Select launcher for: ": "Sélectionner le lanceur pour : ",
|
||||||
|
"Close FileBrowser?": "Fermer le navigateur de fichiers ?",
|
||||||
|
|
||||||
"Sort By": "Tri Par",
|
"Sort By": "Tri Par",
|
||||||
"Sort Options": "Options de Tri",
|
"Sort Options": "Options de Tri",
|
||||||
@@ -311,15 +341,15 @@
|
|||||||
"Tools": "Outils",
|
"Tools": "Outils",
|
||||||
"Themes": "Thèmes",
|
"Themes": "Thèmes",
|
||||||
"Legacy": "Legacy",
|
"Legacy": "Legacy",
|
||||||
"Sort": "Tri",
|
"Sort": "Trier",
|
||||||
"Size": "Taille",
|
"Size": "Taille",
|
||||||
"Size (Star)": "Taille (Favories)",
|
"Size (Star)": "Taille (Favoris)",
|
||||||
"Alphabetical": "Alphabétique",
|
"Alphabetical": "Alphabétique",
|
||||||
"Alphabetical (Star)": "Alphabétique (Favories)",
|
"Alphabetical (Star)": "Alphabétique (Favoris)",
|
||||||
"Updated": "Mis à jour",
|
"Updated": "Mis à jour",
|
||||||
"Updated (Star)": "Mis à jour (Favories)",
|
"Updated (Star)": "Mis à jour (Favoris)",
|
||||||
"Downloads": "Téléchargements",
|
"Downloads": "Téléchargements",
|
||||||
"Likes": "Likes",
|
"Likes": "Aimer",
|
||||||
"ID": "ID",
|
"ID": "ID",
|
||||||
"Order": "Ordre",
|
"Order": "Ordre",
|
||||||
"Descending": "Décroissant",
|
"Descending": "Décroissant",
|
||||||
@@ -332,61 +362,62 @@
|
|||||||
"List": "Liste",
|
"List": "Liste",
|
||||||
"Icon": "Icône",
|
"Icon": "Icône",
|
||||||
"Grid": "Grille",
|
"Grid": "Grille",
|
||||||
"Search": "Recherche",
|
"Search": "Lancer la recherche",
|
||||||
|
|
||||||
"Options": "Options",
|
"Options": "Options",
|
||||||
|
"Split": "Découper",
|
||||||
"OK": "OK",
|
"OK": "OK",
|
||||||
"Back": "Retour",
|
"Back": "Retour",
|
||||||
"Select": "Sélectionner",
|
"Select": "Sélectionner",
|
||||||
"Open": "Ouvrir",
|
"Open": "Ouvrir",
|
||||||
|
"Close": "Fermer",
|
||||||
"Launch": "Exécuter",
|
"Launch": "Exécuter",
|
||||||
"Restart": "Redémarrer",
|
"Restart": "Redémarrer",
|
||||||
"Next": "Suivant",
|
"Next": "Suivant",
|
||||||
"Prev": "Précédent",
|
"Prev": "Précédent",
|
||||||
"Unstar": "Retirer des favories",
|
|
||||||
"Star": "Ajouter aux favories",
|
|
||||||
"Yes": "Oui",
|
"Yes": "Oui",
|
||||||
"No": "Non",
|
"No": "Non",
|
||||||
"On": "On",
|
"On": "On",
|
||||||
"Off": "Off",
|
"Off": "Off",
|
||||||
|
|
||||||
"Install": "Installer",
|
"Install": "Installer",
|
||||||
"Install Selected files?": "Installer les fichiers sélectionnés?",
|
"Install Selected files?": "Installer les fichiers sélectionnés ?",
|
||||||
"Installing ": "Installation en cours ",
|
"Installing ": "Installation en cours...",
|
||||||
"Installed ": "Installé ",
|
"Installed ": "Installé ",
|
||||||
"Installed!": "Installé!",
|
"Installed!": "Installé !",
|
||||||
"Trying to load ": "Tente de charger ",
|
"Trying to load ": "Essayer de charger ",
|
||||||
"Checking MD5": "Vérification MD5",
|
"Checking MD5": "Vérification MD5",
|
||||||
|
|
||||||
"Delete": "Supprimer",
|
"Delete": "Supprimer",
|
||||||
"Delete Selected files?": "Supprimer les fichiers sélectionnés?",
|
"Delete Selected files?": "Supprimer les fichiers sélectionnés ?",
|
||||||
"Are you sure you want to delete ": "Êtes-vous sûr de vouloir supprimer ",
|
"Are you sure you want to delete ": "Êtes-vous sûr de vouloir supprimer ",
|
||||||
"Scanning ": "Scan en cours ",
|
"Scanning ": "Scan en cours...",
|
||||||
"Deleting ": "Suppression en cours ",
|
"Deleting ": "Suppression en cours...",
|
||||||
"Deleting": "Suppression en cours",
|
"Deleting": "Suppression en cours...",
|
||||||
"Remove": "Supprimer",
|
"Remove": "Supprimer",
|
||||||
"Completely remove ": "Supprimer totalement ",
|
"Completely remove ": "Supprimer totalement ",
|
||||||
"Removing ": "Suppression en cours ",
|
"Removing ": "Suppression en cours...",
|
||||||
|
"Uninstalling ": "Désinstallation en cours...",
|
||||||
"Removed ": "Supprimé ",
|
"Removed ": "Supprimé ",
|
||||||
"Uninstalling ": "Désinstallation en cours ",
|
|
||||||
|
|
||||||
"Download": "Télécharger",
|
"Download": "Télécharger",
|
||||||
"Downloading ": "Téléchargement en cours ",
|
"Downloading ": "Téléchargement en cours...",
|
||||||
"Downloaded ": "Téléchargé",
|
"Downloaded ": "Téléchargé ",
|
||||||
|
"Download via the Network options!": "Téléchargez via les options réseau !",
|
||||||
|
|
||||||
"Update": "Mise à jour",
|
"Update": "Mise à jour",
|
||||||
"Update avaliable: ": "Mise à jour disponible: ",
|
"Update avaliable: ": "Mise à jour disponible : ",
|
||||||
"Download update: ": "Télécharger la mise à jour: ",
|
"Download update: ": "Télécharger la mise à jour : ",
|
||||||
"Updated to ": "Mis à jour vers ",
|
"Updated to ": "Mis à jour vers ",
|
||||||
"Failed to download update": "Echec du téléchargement de la mise à jour",
|
"Failed to download update": "Échec du téléchargement de la mise à jour !",
|
||||||
|
|
||||||
"%zu hours %zu minutes remaining": "%zu heures %zu minutes restantes",
|
"%zu hours %zu minutes remaining": "%zu heures %zu minutes restantes",
|
||||||
"%zu minutes %zu seconds remaining": "%zu minutes %zu secondes restantes",
|
"%zu minutes %zu seconds remaining": "%zu minutes %zu secondes restantes",
|
||||||
"%zu seconds remaining": "%zu secondes restantes",
|
"%zu seconds remaining": "%zu secondes restantes",
|
||||||
|
|
||||||
"Loading...": "Chargement...",
|
"Loading...": "Chargement...",
|
||||||
"Loading": "Chargement en cours",
|
"Loading": "Chargement en cours...",
|
||||||
"Empty!": "Vide!",
|
"Empty!": "Vide !",
|
||||||
"Not Ready...": "Pas prêt",
|
"Not Ready...": "Pas prêt !",
|
||||||
"Error loading page!": "Erreur du chargement de la page!"
|
"Error loading page!": "Erreur du chargement de la page!"
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
"No Internet": "Niente Internet",
|
"No Internet": "Niente Internet",
|
||||||
"Switch-Handheld!": "Switch Portatile",
|
"Switch-Handheld!": "Switch Portatile",
|
||||||
"Switch-Docked!": "Switch Dock",
|
"Switch-Docked!": "Switch Dock",
|
||||||
|
"Warning! Logs are enabled, Sphaira will run slowly!": "",
|
||||||
"Audio disabled due to suspended game": "Audio disabilitato poichè un app è in pausa",
|
"Audio disabled due to suspended game": "Audio disabilitato poichè un app è in pausa",
|
||||||
"Are you sure you wish to cancel?": "Sei sicuro di voler annullare?",
|
"Are you sure you wish to cancel?": "Sei sicuro di voler annullare?",
|
||||||
"An error occurred": "",
|
"An error occurred": "",
|
||||||
@@ -27,6 +28,8 @@
|
|||||||
"Nxlink Connected": "Nxlink connesso",
|
"Nxlink Connected": "Nxlink connesso",
|
||||||
"Nxlink Upload": "Nxlink upload",
|
"Nxlink Upload": "Nxlink upload",
|
||||||
"Nxlink Finished": "Nxlink finito",
|
"Nxlink Finished": "Nxlink finito",
|
||||||
|
"Hdd": "",
|
||||||
|
"Hdd write protect": "",
|
||||||
|
|
||||||
"Language": "Lingua",
|
"Language": "Lingua",
|
||||||
"Auto": "Auto",
|
"Auto": "Auto",
|
||||||
@@ -57,22 +60,35 @@
|
|||||||
"No meta entries found...\n": "",
|
"No meta entries found...\n": "",
|
||||||
"Updating application record list": "",
|
"Updating application record list": "",
|
||||||
"Dump": "",
|
"Dump": "",
|
||||||
|
"Dump options": "",
|
||||||
|
"Dump Options": "",
|
||||||
"Select content to dump": "",
|
"Select content to dump": "",
|
||||||
"Dump All": "",
|
"Dump All": "",
|
||||||
"Dump Application": "",
|
"Dump Application": "",
|
||||||
"Dump Patch": "",
|
"Dump Patch": "",
|
||||||
"Dump AddOnContent": "",
|
"Dump AddOnContent": "",
|
||||||
"Dump DataPatch": "",
|
"Dump DataPatch": "",
|
||||||
|
"Created nested folder": "",
|
||||||
|
"Append folder with .xci": "",
|
||||||
|
"Trim XCI": "",
|
||||||
|
"Label trimmed XCI": "",
|
||||||
|
"Multi-threaded USB transfer": "",
|
||||||
|
"Dump All Bins": "",
|
||||||
|
"Dump XCI": "",
|
||||||
|
"Dump Card ID Set": "",
|
||||||
|
"Dump Card UID": "",
|
||||||
|
"Dump Certificate": "",
|
||||||
|
"Dump Initial Data": "",
|
||||||
"Select dump location": "",
|
"Select dump location": "",
|
||||||
"microSD card (/dumps/NSP/)": "",
|
"microSD card (/dumps/)": "",
|
||||||
"USB transfer (Switch 2 Switch)": "",
|
"USB transfer (Switch 2 Switch)": "",
|
||||||
"/dev/null (Speed Test)": "",
|
"/dev/null (Speed Test)": "",
|
||||||
"Dumping": "",
|
"Dumping": "",
|
||||||
"Dump successfull!": "",
|
"Dump successfull!": "",
|
||||||
"Dump failed!": "",
|
"Dump failed!": "",
|
||||||
"Success": "",
|
|
||||||
"Delete successfull!": "",
|
"Delete successfull!": "",
|
||||||
"Delete failed!": "",
|
"Delete failed!": "",
|
||||||
|
"Success": "",
|
||||||
|
|
||||||
"Themezer": "Themezer",
|
"Themezer": "Themezer",
|
||||||
"Themezer Options": "Impostazioni Themezer",
|
"Themezer Options": "Impostazioni Themezer",
|
||||||
@@ -86,6 +102,8 @@
|
|||||||
"GitHub": "GitHub",
|
"GitHub": "GitHub",
|
||||||
"Downloading json": "Scaricamento json",
|
"Downloading json": "Scaricamento json",
|
||||||
"Select asset to download for ": "",
|
"Select asset to download for ": "",
|
||||||
|
"Failed to download json": "",
|
||||||
|
"Failed to download app!": "",
|
||||||
|
|
||||||
"FTP Install": "",
|
"FTP Install": "",
|
||||||
"FTP Install (EXPERIMENTAL)": "",
|
"FTP Install (EXPERIMENTAL)": "",
|
||||||
@@ -122,9 +140,12 @@
|
|||||||
"GC": "",
|
"GC": "",
|
||||||
"System memory %.1f GB": "",
|
"System memory %.1f GB": "",
|
||||||
"microSD card %.1f GB": "",
|
"microSD card %.1f GB": "",
|
||||||
"Nand Install": "",
|
|
||||||
"SD Card Install": "",
|
|
||||||
"Exit": "",
|
"Exit": "",
|
||||||
|
"Install disabled...\nPlease enable installing via the install options.": "",
|
||||||
|
"No GameCard inserted": "",
|
||||||
|
"GameCard is already trimmed!": "",
|
||||||
|
"WARNING: GameCard is already trimmed!": "",
|
||||||
|
"Continue": "",
|
||||||
"Gc install success!": "",
|
"Gc install success!": "",
|
||||||
"Gc install failed!": "",
|
"Gc install failed!": "",
|
||||||
|
|
||||||
@@ -160,14 +181,14 @@
|
|||||||
"Negative image": "Immagine negativa",
|
"Negative image": "Immagine negativa",
|
||||||
"Format": "Formato",
|
"Format": "Formato",
|
||||||
"Trimming Format": "Formato di ritaglio",
|
"Trimming Format": "Formato di ritaglio",
|
||||||
"320x240": "320×240",
|
|
||||||
"160x120": "160×120",
|
|
||||||
"80x60": "80×60",
|
|
||||||
"40x30": "40×30",
|
|
||||||
"20x15": "20×15",
|
|
||||||
"External Light Filter": "Filtro luce esterno",
|
"External Light Filter": "Filtro luce esterno",
|
||||||
"Load Default": "Carica predefinito",
|
"Load Default": "Carica predefinito",
|
||||||
|
|
||||||
|
"Web": "",
|
||||||
|
"Select URL": "",
|
||||||
|
"Enter custom URL": "",
|
||||||
|
"Enter URL": "",
|
||||||
|
|
||||||
"Advanced": "Avanzato",
|
"Advanced": "Avanzato",
|
||||||
"Advanced Options": "Opzioni avanzate",
|
"Advanced Options": "Opzioni avanzate",
|
||||||
"Logging": "Logging",
|
"Logging": "Logging",
|
||||||
@@ -181,10 +202,12 @@
|
|||||||
"Restored hbmenu": "hbmenu ripristinato",
|
"Restored hbmenu": "hbmenu ripristinato",
|
||||||
"Restart Sphaira?": "Vuoi riavviare Sphaira?",
|
"Restart Sphaira?": "Vuoi riavviare Sphaira?",
|
||||||
"Press OK to restart Sphaira": "Premi OK per riavviare Sphaira",
|
"Press OK to restart Sphaira": "Premi OK per riavviare Sphaira",
|
||||||
|
"Boost CPU during transfer": "",
|
||||||
"Text scroll speed": "",
|
"Text scroll speed": "",
|
||||||
"Slow": "",
|
"Slow": "",
|
||||||
"Normal": "",
|
"Normal": "",
|
||||||
"Fast": "",
|
"Fast": "",
|
||||||
|
"Set left-side menu": "",
|
||||||
"Set right-side menu": "",
|
"Set right-side menu": "",
|
||||||
"Install options": "",
|
"Install options": "",
|
||||||
"Install Options": "",
|
"Install Options": "",
|
||||||
@@ -194,7 +217,6 @@
|
|||||||
"Install location": "Installa posizione",
|
"Install location": "Installa posizione",
|
||||||
"System memory": "Memoria di sistema",
|
"System memory": "Memoria di sistema",
|
||||||
"microSD card": "Scheda microSD",
|
"microSD card": "Scheda microSD",
|
||||||
"Boost CPU clock": "",
|
|
||||||
"Allow downgrade": "",
|
"Allow downgrade": "",
|
||||||
"Skip if already installed": "",
|
"Skip if already installed": "",
|
||||||
"Ticket only": "",
|
"Ticket only": "",
|
||||||
@@ -225,6 +247,8 @@
|
|||||||
"Updating ncm databse": "",
|
"Updating ncm databse": "",
|
||||||
"Pushing application record": "",
|
"Pushing application record": "",
|
||||||
"Failed to install forwarder": "",
|
"Failed to install forwarder": "",
|
||||||
|
"Unstar": "Rimuovi dai preferiti",
|
||||||
|
"Star": "Aggiungi ai preferiti",
|
||||||
"Unstarred ": "",
|
"Unstarred ": "",
|
||||||
"Starred ": "",
|
"Starred ": "",
|
||||||
"Failed to remove old forwarder, please manually remove it!": "",
|
"Failed to remove old forwarder, please manually remove it!": "",
|
||||||
@@ -257,12 +281,13 @@
|
|||||||
"Copy": "Copia",
|
"Copy": "Copia",
|
||||||
"Copying ": "Copio",
|
"Copying ": "Copio",
|
||||||
"Paste": "Incolla",
|
"Paste": "Incolla",
|
||||||
"Paste ": "Incolla ",
|
"Paste file(s)?": "",
|
||||||
" file(s)?": "(i)file?",
|
|
||||||
"Pasting ": "Incollo",
|
"Pasting ": "Incollo",
|
||||||
"Pasting": "Incollo",
|
"Pasting": "Incollo",
|
||||||
"Rename": "Rinomina",
|
"Rename": "Rinomina",
|
||||||
"Set New File Name": "Imposta nuovo nome",
|
"Set New File Name": "Imposta nuovo nome",
|
||||||
|
"Failed to delete directory": "",
|
||||||
|
"Failed to delete file": "",
|
||||||
"Extract zip": "",
|
"Extract zip": "",
|
||||||
"Extract Options": "",
|
"Extract Options": "",
|
||||||
"Extract here": "",
|
"Extract here": "",
|
||||||
@@ -285,13 +310,17 @@
|
|||||||
"Create Folder": "Crea cartella",
|
"Create Folder": "Crea cartella",
|
||||||
"Set Folder Name": "Imposta nome",
|
"Set Folder Name": "Imposta nome",
|
||||||
"Creating ": "Creazione",
|
"Creating ": "Creazione",
|
||||||
|
"View as text (unfinished)": "Visualizza come testo (non finito)",
|
||||||
"Upload": "",
|
"Upload": "",
|
||||||
"Select upload location": "",
|
"Select upload location": "",
|
||||||
"No upload locations set!": "",
|
"No upload locations set!": "",
|
||||||
"Uploading": "",
|
"Uploading": "",
|
||||||
"Upload successfull!": "",
|
"Upload successfull!": "",
|
||||||
"Upload failed!": "",
|
"Upload failed!": "",
|
||||||
"View as text (unfinished)": "Visualizza come testo (non finito)",
|
"Hash": "",
|
||||||
|
"Hash Options": "",
|
||||||
|
"Hashing": "",
|
||||||
|
"Failed to hash file...": "",
|
||||||
"Ignore read only": "Ignora read only",
|
"Ignore read only": "Ignora read only",
|
||||||
"Mount": "Monta",
|
"Mount": "Monta",
|
||||||
"Sd": "SD",
|
"Sd": "SD",
|
||||||
@@ -302,6 +331,7 @@
|
|||||||
"Launch ": "Lancia",
|
"Launch ": "Lancia",
|
||||||
"Launch option for: ": "Lancia opzione per",
|
"Launch option for: ": "Lancia opzione per",
|
||||||
"Select launcher for: ": "Scegli launcher per",
|
"Select launcher for: ": "Scegli launcher per",
|
||||||
|
"Close FileBrowser?": "",
|
||||||
|
|
||||||
"Sort By": "Ordina per",
|
"Sort By": "Ordina per",
|
||||||
"Sort Options": "Opzioni filtro",
|
"Sort Options": "Opzioni filtro",
|
||||||
@@ -335,16 +365,16 @@
|
|||||||
"Search": "Ricerca",
|
"Search": "Ricerca",
|
||||||
|
|
||||||
"Options": "Opzioni",
|
"Options": "Opzioni",
|
||||||
|
"Split": "",
|
||||||
"OK": "OK",
|
"OK": "OK",
|
||||||
"Back": "Indietro",
|
"Back": "Indietro",
|
||||||
"Select": "Seleziona",
|
"Select": "Seleziona",
|
||||||
"Open": "Apri",
|
"Open": "Apri",
|
||||||
|
"Close": "",
|
||||||
"Launch": "Lancia",
|
"Launch": "Lancia",
|
||||||
"Restart": "Riavvia",
|
"Restart": "Riavvia",
|
||||||
"Next": "",
|
"Next": "",
|
||||||
"Prev": "",
|
"Prev": "",
|
||||||
"Unstar": "Rimuovi dai preferiti",
|
|
||||||
"Star": "Aggiungi ai preferiti",
|
|
||||||
"Yes": "Sì",
|
"Yes": "Sì",
|
||||||
"No": "No",
|
"No": "No",
|
||||||
"On": "",
|
"On": "",
|
||||||
@@ -367,12 +397,13 @@
|
|||||||
"Remove": "Rimuovi",
|
"Remove": "Rimuovi",
|
||||||
"Completely remove ": "Elimina definitivamente",
|
"Completely remove ": "Elimina definitivamente",
|
||||||
"Removing ": "Rimozione",
|
"Removing ": "Rimozione",
|
||||||
"Removed ": "Rimosso",
|
|
||||||
"Uninstalling ": "Disinstallazione",
|
"Uninstalling ": "Disinstallazione",
|
||||||
|
"Removed ": "Rimosso",
|
||||||
|
|
||||||
"Download": "Download",
|
"Download": "Download",
|
||||||
"Downloading ": "Scaricando",
|
"Downloading ": "Scaricando",
|
||||||
"Downloaded ": "Scaricato",
|
"Downloaded ": "Scaricato",
|
||||||
|
"Download via the Network options!": "",
|
||||||
|
|
||||||
"Update": "Aggiorna",
|
"Update": "Aggiorna",
|
||||||
"Update avaliable: ": "Aggiornamento disponibile",
|
"Update avaliable: ": "Aggiornamento disponibile",
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
{
|
{
|
||||||
"[Applet Mode]": "[Appletモード]",
|
"[Applet Mode]": "[Appletモード]",
|
||||||
"No Internet": "インターネットなし",
|
"No Internet": "インターネットなし",
|
||||||
"Switch-Handheld!": "ハンドヘルド!",
|
"Switch-Handheld!": "ハンドヘルドになりました!",
|
||||||
"Switch-Docked!": "ドック接続!",
|
"Switch-Docked!": "ドックに接続しました!",
|
||||||
"Audio disabled due to suspended game": "ゲームが一時停止状態の場合、オーディオは無効になります",
|
"Warning! Logs are enabled, Sphaira will run slowly!": "警告: ログが有効になったため、Sphairaの速度が遅くなります",
|
||||||
|
"Audio disabled due to suspended game": "ゲームが一時停止状態の場合、BGMは無効になります",
|
||||||
"Are you sure you wish to cancel?": "本当に取り消しますか?",
|
"Are you sure you wish to cancel?": "本当に取り消しますか?",
|
||||||
"An error occurred": "不具合のお知らせ",
|
"An error occurred": "不具合のお知らせ",
|
||||||
"If this message appears repeatedly, please open an issue.": "このメッセージが繰り返し表示される場合は、問題を開いてください",
|
"If this message appears repeatedly, please open an issue.": "このメッセージが繰り返し表示される場合、問題を開いてください",
|
||||||
|
|
||||||
"Menu Options": "メニュー設定",
|
"Menu Options": "メニュー設定",
|
||||||
"Menu": "メニュー",
|
"Menu": "メニュー",
|
||||||
@@ -24,9 +25,11 @@
|
|||||||
"Ftp": "FTP",
|
"Ftp": "FTP",
|
||||||
"Mtp": "MTP",
|
"Mtp": "MTP",
|
||||||
"Nxlink": "Nxlink",
|
"Nxlink": "Nxlink",
|
||||||
"Nxlink Connected": "Nxlink 接続",
|
"Nxlink Connected": "Nxlinkに接続しました",
|
||||||
"Nxlink Upload": "Nxlink アップロード",
|
"Nxlink Upload": "Nxlinkにアップロードされました",
|
||||||
"Nxlink Finished": "Nxlink 終了",
|
"Nxlink Finished": "Nxlinkを終了します",
|
||||||
|
"Hdd": "HDD",
|
||||||
|
"Hdd write protect": "HDD書き込み保護",
|
||||||
|
|
||||||
"Language": "言語",
|
"Language": "言語",
|
||||||
"Auto": "自動",
|
"Auto": "自動",
|
||||||
@@ -57,22 +60,35 @@
|
|||||||
"No meta entries found...\n": "メタエントリが見つかりませんでした\n",
|
"No meta entries found...\n": "メタエントリが見つかりませんでした\n",
|
||||||
"Updating application record list": "ゲームのレコードを更新しています",
|
"Updating application record list": "ゲームのレコードを更新しています",
|
||||||
"Dump": "吸出し",
|
"Dump": "吸出し",
|
||||||
|
"Dump options": "吸出し設定",
|
||||||
|
"Dump Options": "吸出し設定",
|
||||||
"Select content to dump": "吸出すコンテンツを選択",
|
"Select content to dump": "吸出すコンテンツを選択",
|
||||||
"Dump All": "全て",
|
"Dump All": "全て",
|
||||||
"Dump Application": "ゲームのみ",
|
"Dump Application": "ゲームのみ",
|
||||||
"Dump Patch": "ゲームパッチのみ",
|
"Dump Patch": "ゲームパッチのみ",
|
||||||
"Dump AddOnContent": "DLCのみ",
|
"Dump AddOnContent": "DLCのみ",
|
||||||
"Dump DataPatch": "DLCパッチのみ",
|
"Dump DataPatch": "DLCパッチのみ",
|
||||||
|
"Created nested folder": "ネストされたフォルダを作成",
|
||||||
|
"Append folder with .xci": ".xci付きフォルダを追加",
|
||||||
|
"Trim XCI": "XCIをトリム",
|
||||||
|
"Label trimmed XCI": "トリム済みXCIのラベルを指定",
|
||||||
|
"Multi-threaded USB transfer": "マルチスレッドのUSB転送",
|
||||||
|
"Dump All Bins": "すべてのBINを吸出す",
|
||||||
|
"Dump XCI": "XCIを吸出す",
|
||||||
|
"Dump Card ID Set": "ゲームカードIDを吸出す",
|
||||||
|
"Dump Card UID": "ゲームカードUIDを吸出す",
|
||||||
|
"Dump Certificate": "証明書を吸出す",
|
||||||
|
"Dump Initial Data": "初期データを吸出す",
|
||||||
"Select dump location": "吸出し位置を選択",
|
"Select dump location": "吸出し位置を選択",
|
||||||
"microSD card (/dumps/NSP/)": "SDカード (/dumps/NSP/)",
|
"microSD card (/dumps/)": "SDカード (/dumps/)",
|
||||||
"USB transfer (Switch 2 Switch)": "USB転送 (Switch 2 Switch)",
|
"USB transfer (Switch 2 Switch)": "USBで転送 (Switch 2 Switch)",
|
||||||
"/dev/null (Speed Test)": "/dev/null (Speed Test)",
|
"/dev/null (Speed Test)": "/dev/null (Speed Test)",
|
||||||
"Dumping": "吸出し中",
|
"Dumping": "吸出し中",
|
||||||
"Dump successfull!": "吸出し完了!",
|
"Dump successfull!": "吸出し完了!",
|
||||||
"Dump failed!": "吸出し失敗!",
|
"Dump failed!": "吸出し失敗!",
|
||||||
"Success": "完了",
|
|
||||||
"Delete successfull!": "削除完了!",
|
"Delete successfull!": "削除完了!",
|
||||||
"Delete failed!": "削除失敗!",
|
"Delete failed!": "削除失敗!",
|
||||||
|
"Success": "完了",
|
||||||
|
|
||||||
"Themezer": "Themezer",
|
"Themezer": "Themezer",
|
||||||
"Themezer Options": "Themezer設定",
|
"Themezer Options": "Themezer設定",
|
||||||
@@ -86,14 +102,16 @@
|
|||||||
"GitHub": "GitHub",
|
"GitHub": "GitHub",
|
||||||
"Downloading json": "JSONからダウンロード",
|
"Downloading json": "JSONからダウンロード",
|
||||||
"Select asset to download for ": "ダウンロードアイテムを選択 ",
|
"Select asset to download for ": "ダウンロードアイテムを選択 ",
|
||||||
|
"Failed to download json": "JSONからのダウンロードに失敗しました!",
|
||||||
|
"Failed to download app!": "アプリのダウンロードに失敗しました!",
|
||||||
|
|
||||||
"FTP Install": "FTPでインストール",
|
"FTP Install": "FTPでインストール",
|
||||||
"FTP Install (EXPERIMENTAL)": "FTPでインストール(実験機能)",
|
"FTP Install (EXPERIMENTAL)": "FTPでインストール(実験機能)",
|
||||||
"Connection Type: WiFi | Strength: ": "接続: WiFi | 強度: ",
|
"Connection Type: WiFi | Strength: ": "接続: WiFi | 強度: ",
|
||||||
"Connection Type: Ethernet": "接続: イーサネット",
|
"Connection Type: Ethernet": "接続: イーサネット",
|
||||||
"Connection Type: None": "接続: なし",
|
"Connection Type: None": "接続: なし",
|
||||||
"Host:": "ホースと:",
|
"Host:": "ホスト:",
|
||||||
"Port:": "Port:",
|
"Port:": "ポート:",
|
||||||
"Username:": "ユーザー名:",
|
"Username:": "ユーザー名:",
|
||||||
"Password:": "暗証番号:",
|
"Password:": "暗証番号:",
|
||||||
"SSID:": "SSID:",
|
"SSID:": "SSID:",
|
||||||
@@ -103,14 +121,14 @@
|
|||||||
"Ftp install failed!": "FTPインストール失敗!",
|
"Ftp install failed!": "FTPインストール失敗!",
|
||||||
"USB Install": "USBインストール",
|
"USB Install": "USBインストール",
|
||||||
"USB": "USBインストール",
|
"USB": "USBインストール",
|
||||||
"Connected, waiting for file list...": "接続されました、ファイル リスト待機中",
|
"Connected, waiting for file list...": "接続されました、ファイルリストを待っています",
|
||||||
"Connected, starting transfer...": "接続されました、転送開始",
|
"Connected, starting transfer...": "接続されました、転送を開始します",
|
||||||
"Failed to init usb, press B to exit...": "USB接続できませんでした、を押して終了します",
|
"Failed to init usb, press B to exit...": "USB接続できませんでした、を押して終了します",
|
||||||
"Waiting for connection...": "接続待機中",
|
"Waiting for connection...": "接続待機中",
|
||||||
"Transferring data...": "データ転送中",
|
"Transferring data...": "データを転送しています",
|
||||||
"USB connected, sending file list": "接続されました、ファイルリスト送信中",
|
"USB connected, sending file list": "接続されました、ファイルリスト送信します",
|
||||||
"Sent file list, waiting for command...": "ファイルリストを送信しました、入力待機中",
|
"Sent file list, waiting for command...": "ファイルリストを送信しました、入力を待っています",
|
||||||
"waiting for usb connection...": "USB接続待機中",
|
"waiting for usb connection...": "USBの接続を待っています",
|
||||||
"Disable MTP for usb install": "USBインストールのため、MTPを無効にします",
|
"Disable MTP for usb install": "USBインストールのため、MTPを無効にします",
|
||||||
"Re-enabled MTP": "MTPに再接続します",
|
"Re-enabled MTP": "MTPに再接続します",
|
||||||
"Installed via usb": "USBインストールに成功しました",
|
"Installed via usb": "USBインストールに成功しました",
|
||||||
@@ -122,9 +140,12 @@
|
|||||||
"GC": "ゲームカード",
|
"GC": "ゲームカード",
|
||||||
"System memory %.1f GB": "本体保存メモリー %.1f GB",
|
"System memory %.1f GB": "本体保存メモリー %.1f GB",
|
||||||
"microSD card %.1f GB": "SDカード %.1f GB",
|
"microSD card %.1f GB": "SDカード %.1f GB",
|
||||||
"Nand Install": "本体保存メモリーにインストール",
|
|
||||||
"SD Card Install": "SDカードにインストール",
|
|
||||||
"Exit": "もどる",
|
"Exit": "もどる",
|
||||||
|
"Install disabled...\nPlease enable installing via the install options.": "インストールが無効化されています\nインストール設定で有効にしてください",
|
||||||
|
"No GameCard inserted": "ゲームカードが挿入されていません",
|
||||||
|
"GameCard is already trimmed!": "ゲームカードがすでにトリムされています!",
|
||||||
|
"WARNING: GameCard is already trimmed!": "警告: ゲームカードがすでにトリムされています!",
|
||||||
|
"Continue": "つづく",
|
||||||
"Gc install success!": "ゲームカードインストール完了!",
|
"Gc install success!": "ゲームカードインストール完了!",
|
||||||
"Gc install failed!": "ゲームカードインストール失敗!",
|
"Gc install failed!": "ゲームカードインストール失敗!",
|
||||||
|
|
||||||
@@ -160,14 +181,14 @@
|
|||||||
"Negative image": "ネガティブなイメージ",
|
"Negative image": "ネガティブなイメージ",
|
||||||
"Format": "解像度",
|
"Format": "解像度",
|
||||||
"Trimming Format": "トリミングされた解像度",
|
"Trimming Format": "トリミングされた解像度",
|
||||||
"320x240": "320×240",
|
|
||||||
"160x120": "160×120",
|
|
||||||
"80x60": "80×60",
|
|
||||||
"40x30": "40×30",
|
|
||||||
"20x15": "20×15",
|
|
||||||
"External Light Filter": "外光フィルター",
|
"External Light Filter": "外光フィルター",
|
||||||
"Load Default": "基本設定に戻す",
|
"Load Default": "基本設定に戻す",
|
||||||
|
|
||||||
|
"Web": "ウェブサイト",
|
||||||
|
"Select URL": "URLを選択してください",
|
||||||
|
"Enter custom URL": "URLを直接入力",
|
||||||
|
"Enter URL": "URLを記入してください",
|
||||||
|
|
||||||
"Advanced": "高度な",
|
"Advanced": "高度な",
|
||||||
"Advanced Options": "高度設定",
|
"Advanced Options": "高度設定",
|
||||||
"Logging": "ログの取得",
|
"Logging": "ログの取得",
|
||||||
@@ -181,10 +202,12 @@
|
|||||||
"Restored hbmenu": "hbmenuに復元されました",
|
"Restored hbmenu": "hbmenuに復元されました",
|
||||||
"Restart Sphaira?": "Sphairaを再起動しますか?",
|
"Restart Sphaira?": "Sphairaを再起動しますか?",
|
||||||
"Press OK to restart Sphaira": "確認ボタンを押してSphairaを再起動",
|
"Press OK to restart Sphaira": "確認ボタンを押してSphairaを再起動",
|
||||||
|
"Boost CPU during transfer": "転送する間CPUを加速",
|
||||||
"Text scroll speed": "流れる文字の速さ",
|
"Text scroll speed": "流れる文字の速さ",
|
||||||
"Slow": "遅い",
|
"Slow": "遅く",
|
||||||
"Normal": "普通",
|
"Normal": "普通",
|
||||||
"Fast": "速い",
|
"Fast": "速く",
|
||||||
|
"Set left-side menu": "左側メニュー設定",
|
||||||
"Set right-side menu": "右側メニュー設定",
|
"Set right-side menu": "右側メニュー設定",
|
||||||
"Install options": "インストール設定",
|
"Install options": "インストール設定",
|
||||||
"Install Options": "インストール設定",
|
"Install Options": "インストール設定",
|
||||||
@@ -194,7 +217,6 @@
|
|||||||
"Install location": "インストール経路",
|
"Install location": "インストール経路",
|
||||||
"System memory": "本体保存メモリー",
|
"System memory": "本体保存メモリー",
|
||||||
"microSD card": "SDカード",
|
"microSD card": "SDカード",
|
||||||
"Boost CPU clock": "CPUクロックをブースト",
|
|
||||||
"Allow downgrade": "ダウングレード許可",
|
"Allow downgrade": "ダウングレード許可",
|
||||||
"Skip if already installed": "既にインストールされている場合はスキップします",
|
"Skip if already installed": "既にインストールされている場合はスキップします",
|
||||||
"Ticket only": "チケットのみ設置",
|
"Ticket only": "チケットのみ設置",
|
||||||
@@ -225,6 +247,8 @@
|
|||||||
"Updating ncm databse": "ncmのDBをアップデート中",
|
"Updating ncm databse": "ncmのDBをアップデート中",
|
||||||
"Pushing application record": "アプリの記録をプッシュ中",
|
"Pushing application record": "アプリの記録をプッシュ中",
|
||||||
"Failed to install forwarder": "Forwarderのインストール失敗",
|
"Failed to install forwarder": "Forwarderのインストール失敗",
|
||||||
|
"Unstar": "お気に入り解除",
|
||||||
|
"Star": "お気に入り",
|
||||||
"Unstarred ": "お気に入り解除: ",
|
"Unstarred ": "お気に入り解除: ",
|
||||||
"Starred ": "お気に入りに登録: ",
|
"Starred ": "お気に入りに登録: ",
|
||||||
"Failed to remove old forwarder, please manually remove it!": "古いForwarderを削除できませんでした、手動で削除してください!",
|
"Failed to remove old forwarder, please manually remove it!": "古いForwarderを削除できませんでした、手動で削除してください!",
|
||||||
@@ -247,8 +271,8 @@
|
|||||||
|
|
||||||
"FileBrowser": "ファイルブラウザ",
|
"FileBrowser": "ファイルブラウザ",
|
||||||
"Files": "ファイル",
|
"Files": "ファイル",
|
||||||
"%zd files": "%zd個のファイル",
|
"%zd files": "%zd ファイル",
|
||||||
"%zd dirs": "%zd個のフォルダー",
|
"%zd dirs": "%zd フォルダー",
|
||||||
"File Options": "ファイル設定",
|
"File Options": "ファイル設定",
|
||||||
"Show Hidden": "非表示ファイルを表示",
|
"Show Hidden": "非表示ファイルを表示",
|
||||||
"Folders First": "フォルダーを優先",
|
"Folders First": "フォルダーを優先",
|
||||||
@@ -257,12 +281,13 @@
|
|||||||
"Copy": "コピー",
|
"Copy": "コピー",
|
||||||
"Copying ": "コピー中 ",
|
"Copying ": "コピー中 ",
|
||||||
"Paste": "ペースト",
|
"Paste": "ペースト",
|
||||||
"Paste ": " ",
|
"Paste file(s)?": "",
|
||||||
" file(s)?": "個のファイルをペーストしますか?",
|
|
||||||
"Pasting ": "ペースト中 ",
|
"Pasting ": "ペースト中 ",
|
||||||
"Pasting": "ペースト中",
|
"Pasting": "ペースト中",
|
||||||
"Rename": "名前の変更",
|
"Rename": "名前の変更",
|
||||||
"Set New File Name": "新しい名前を入力",
|
"Set New File Name": "新しい名前を入力",
|
||||||
|
"Failed to delete directory": "フォルダーを削除できませんでした",
|
||||||
|
"Failed to delete file": "ファイルを削除できませんでした",
|
||||||
"Extract zip": "ZIPファイルを解凍",
|
"Extract zip": "ZIPファイルを解凍",
|
||||||
"Extract Options": "解凍設定",
|
"Extract Options": "解凍設定",
|
||||||
"Extract here": "ここに解凍",
|
"Extract here": "ここに解凍",
|
||||||
@@ -285,13 +310,17 @@
|
|||||||
"Create Folder": "フォルダーの作成",
|
"Create Folder": "フォルダーの作成",
|
||||||
"Set Folder Name": "名前を入力",
|
"Set Folder Name": "名前を入力",
|
||||||
"Creating ": "作成中 ",
|
"Creating ": "作成中 ",
|
||||||
|
"View as text (unfinished)": "テキストとして表示 (未完成)",
|
||||||
"Upload": "アップロード",
|
"Upload": "アップロード",
|
||||||
"Select upload location": "アップロードの位置を設定",
|
"Select upload location": "アップロードの位置を設定",
|
||||||
"No upload locations set!": "アップロードの位置が設定されていません",
|
"No upload locations set!": "アップロードの位置が設定されていません",
|
||||||
"Uploading": "アップロード中",
|
"Uploading": "アップロード中",
|
||||||
"Upload successfull!": "アップロード完了!",
|
"Upload successfull!": "アップロード完了!",
|
||||||
"Upload failed!": "アップロード失敗!",
|
"Upload failed!": "アップロード失敗!",
|
||||||
"View as text (unfinished)": "テキストとして表示 (未完成)",
|
"Hash": "ハッシュ",
|
||||||
|
"Hash Options": "ハッシュ設定",
|
||||||
|
"Hashing": "ハッシュ化中",
|
||||||
|
"Failed to hash file...": "ハッシュ化できませんでした",
|
||||||
"Ignore read only": "読み取り専用を無視する",
|
"Ignore read only": "読み取り専用を無視する",
|
||||||
"Mount": "マウント",
|
"Mount": "マウント",
|
||||||
"Sd": "SDメモリーカード",
|
"Sd": "SDメモリーカード",
|
||||||
@@ -302,6 +331,7 @@
|
|||||||
"Launch ": "起動しますか",
|
"Launch ": "起動しますか",
|
||||||
"Launch option for: ": "起動設定: ",
|
"Launch option for: ": "起動設定: ",
|
||||||
"Select launcher for: ": "起動ランチャーを選ぶ: ",
|
"Select launcher for: ": "起動ランチャーを選ぶ: ",
|
||||||
|
"Close FileBrowser?": "ファイルブラウザを閉じますか?",
|
||||||
|
|
||||||
"Sort By": "並べ替え",
|
"Sort By": "並べ替え",
|
||||||
"Sort Options": "並べ替え設定",
|
"Sort Options": "並べ替え設定",
|
||||||
@@ -335,16 +365,16 @@
|
|||||||
"Search": "検索",
|
"Search": "検索",
|
||||||
|
|
||||||
"Options": "設定",
|
"Options": "設定",
|
||||||
|
"Split": "スクリーン分割",
|
||||||
"OK": "確認",
|
"OK": "確認",
|
||||||
"Back": "戻る",
|
"Back": "戻る",
|
||||||
"Select": "選択",
|
"Select": "選択",
|
||||||
"Open": "開く",
|
"Open": "開く",
|
||||||
|
"Close": "閉じる",
|
||||||
"Launch": "起動",
|
"Launch": "起動",
|
||||||
"Restart": "再起動",
|
"Restart": "再起動",
|
||||||
"Next": "次へ",
|
"Next": "次へ",
|
||||||
"Prev": "前へ",
|
"Prev": "前へ",
|
||||||
"Unstar": "お気に入り解除",
|
|
||||||
"Star": "お気に入り",
|
|
||||||
"Yes": "はい",
|
"Yes": "はい",
|
||||||
"No": "いいえ",
|
"No": "いいえ",
|
||||||
"On": "オン",
|
"On": "オン",
|
||||||
@@ -367,18 +397,19 @@
|
|||||||
"Remove": "除去",
|
"Remove": "除去",
|
||||||
"Completely remove ": "除去しますか ",
|
"Completely remove ": "除去しますか ",
|
||||||
"Removing ": "除去中 ",
|
"Removing ": "除去中 ",
|
||||||
"Removed ": "除去完了 ",
|
|
||||||
"Uninstalling ": "アンインストール中 ",
|
"Uninstalling ": "アンインストール中 ",
|
||||||
|
"Removed ": "除去完了 ",
|
||||||
|
|
||||||
"Download": "ダウンロード",
|
"Download": "ダウンロード",
|
||||||
"Downloading ": "ダウンロード中 ",
|
"Downloading ": "ダウンロード中 ",
|
||||||
"Downloaded ": "ダウンロード完了 ",
|
"Downloaded ": "ダウンロード完了 ",
|
||||||
|
"Download via the Network options!": "ネットワーク設定からダウンロードしました!",
|
||||||
|
|
||||||
"Update": "アップデート",
|
"Update": "アップデート",
|
||||||
"Update avaliable: ": "アップデート可能: ",
|
"Update avaliable: ": "アップデート可能: ",
|
||||||
"Download update: ": "アップデートをダウンロード: ",
|
"Download update: ": "アップデートをダウンロード: ",
|
||||||
"Updated to ": "アップデート: ",
|
"Updated to ": "アップデート: ",
|
||||||
"Failed to download update": "アップデートのダウンロード失敗",
|
"Failed to download update": "アップデートのダウンロードに失敗しました",
|
||||||
|
|
||||||
"%zu hours %zu minutes remaining": "残り %zu 時間 %zu 分",
|
"%zu hours %zu minutes remaining": "残り %zu 時間 %zu 分",
|
||||||
"%zu minutes %zu seconds remaining": "残り %zu 分",
|
"%zu minutes %zu seconds remaining": "残り %zu 分",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
"No Internet": "인터넷 연결 없음",
|
"No Internet": "인터넷 연결 없음",
|
||||||
"Switch-Handheld!": "휴대모드로 전환됨!",
|
"Switch-Handheld!": "휴대모드로 전환됨!",
|
||||||
"Switch-Docked!": "독 모드로 전환됨!",
|
"Switch-Docked!": "독 모드로 전환됨!",
|
||||||
|
"Warning! Logs are enabled, Sphaira will run slowly!": "경고: 로깅 활성화, 앱이 느려집니다!",
|
||||||
"Audio disabled due to suspended game": "게임 실행 중에는 BGM이 비활성화 됩니다",
|
"Audio disabled due to suspended game": "게임 실행 중에는 BGM이 비활성화 됩니다",
|
||||||
"Are you sure you wish to cancel?": "정말 취소할까요?",
|
"Are you sure you wish to cancel?": "정말 취소할까요?",
|
||||||
"An error occurred": "오류가 발생했습니다!",
|
"An error occurred": "오류가 발생했습니다!",
|
||||||
@@ -27,6 +28,8 @@
|
|||||||
"Nxlink Connected": "Nxlink 연결됨",
|
"Nxlink Connected": "Nxlink 연결됨",
|
||||||
"Nxlink Upload": "Nxlink 업로드",
|
"Nxlink Upload": "Nxlink 업로드",
|
||||||
"Nxlink Finished": "Nxlink 종료됨",
|
"Nxlink Finished": "Nxlink 종료됨",
|
||||||
|
"Hdd": "HDD",
|
||||||
|
"Hdd write protect": "HDD 쓰기 방지",
|
||||||
|
|
||||||
"Language": "언어",
|
"Language": "언어",
|
||||||
"Auto": "자동",
|
"Auto": "자동",
|
||||||
@@ -57,22 +60,35 @@
|
|||||||
"No meta entries found...\n": "메타 항목을 찾을 수 없습니다...\n",
|
"No meta entries found...\n": "메타 항목을 찾을 수 없습니다...\n",
|
||||||
"Updating application record list": "앱 기록 업데이트 중",
|
"Updating application record list": "앱 기록 업데이트 중",
|
||||||
"Dump": "덤프",
|
"Dump": "덤프",
|
||||||
"Select content to dump": "덤프 옵션",
|
"Dump options": "덤프 옵션",
|
||||||
|
"Dump Options": "덤프 옵션",
|
||||||
|
"Select content to dump": "덤프 콘텐츠 선택",
|
||||||
"Dump All": "모든 콘텐츠",
|
"Dump All": "모든 콘텐츠",
|
||||||
"Dump Application": "게임",
|
"Dump Application": "게임",
|
||||||
"Dump Patch": "게임 패치",
|
"Dump Patch": "게임 패치",
|
||||||
"Dump AddOnContent": "DLC",
|
"Dump AddOnContent": "DLC",
|
||||||
"Dump DataPatch": "DLC 패치",
|
"Dump DataPatch": "DLC 패치",
|
||||||
|
"Created nested folder": "중첩 폴더 생성",
|
||||||
|
"Append folder with .xci": ".xci 파일이 포함된 폴더 추가",
|
||||||
|
"Trim XCI": "XCI 트림",
|
||||||
|
"Label trimmed XCI": "트림된 XCI의 라벨 지정",
|
||||||
|
"Multi-threaded USB transfer": "멀티스레드 USB 전송",
|
||||||
|
"Dump All Bins": "모든 바이너리 덤프",
|
||||||
|
"Dump XCI": "XCI 덤프",
|
||||||
|
"Dump Card ID Set": "카트리지 ID 덤프",
|
||||||
|
"Dump Card UID": "카트리지 UID 덤프",
|
||||||
|
"Dump Certificate": "서명 덤프",
|
||||||
|
"Dump Initial Data": "초기화 데이터 덤프",
|
||||||
"Select dump location": "덤프 위치",
|
"Select dump location": "덤프 위치",
|
||||||
"microSD card (/dumps/NSP/)": "SD 카드 (sdmc:/dumps/NSP/)",
|
"microSD card (/dumps/)": "SD 카드 (sdmc:/dumps/)",
|
||||||
"USB transfer (Switch 2 Switch)": "USB 전송 (Switch 2 Switch)",
|
"USB transfer (Switch 2 Switch)": "USB 전송 (Switch 2 Switch)",
|
||||||
"/dev/null (Speed Test)": "/dev/null (Speed Test)",
|
"/dev/null (Speed Test)": "/dev/null (벤치마크)",
|
||||||
"Dumping": "덤프 중",
|
"Dumping": "덤프 중",
|
||||||
"Dump successfull!": "덤프 완료!",
|
"Dump successfull!": "덤프 완료!",
|
||||||
"Dump failed!": "덤프 실패!",
|
"Dump failed!": "덤프 실패!",
|
||||||
"Success": "완료!",
|
|
||||||
"Delete successfull!": "삭제 완료!",
|
"Delete successfull!": "삭제 완료!",
|
||||||
"Delete failed!": "삭제 실패!",
|
"Delete failed!": "삭제 실패!",
|
||||||
|
"Success": "완료!",
|
||||||
|
|
||||||
"Themezer": "Themezer",
|
"Themezer": "Themezer",
|
||||||
"Themezer Options": "Themezer 옵션",
|
"Themezer Options": "Themezer 옵션",
|
||||||
@@ -86,6 +102,8 @@
|
|||||||
"GitHub": "GitHub",
|
"GitHub": "GitHub",
|
||||||
"Downloading json": "JSON에서 다운로드",
|
"Downloading json": "JSON에서 다운로드",
|
||||||
"Select asset to download for ": "다운로드 아이템: ",
|
"Select asset to download for ": "다운로드 아이템: ",
|
||||||
|
"Failed to download json": "JSON에서 다운로드 실패!",
|
||||||
|
"Failed to download app!": "앱 다운로드 실패!",
|
||||||
|
|
||||||
"FTP Install": "FTP 설치",
|
"FTP Install": "FTP 설치",
|
||||||
"FTP Install (EXPERIMENTAL)": "FTP 설치 (실험실 기능)",
|
"FTP Install (EXPERIMENTAL)": "FTP 설치 (실험실 기능)",
|
||||||
@@ -122,9 +140,12 @@
|
|||||||
"GC": "카트리지",
|
"GC": "카트리지",
|
||||||
"System memory %.1f GB": "본체 저장 메모리 %.1f GB",
|
"System memory %.1f GB": "본체 저장 메모리 %.1f GB",
|
||||||
"microSD card %.1f GB": "SD 카드 %.1f GB",
|
"microSD card %.1f GB": "SD 카드 %.1f GB",
|
||||||
"Nand Install": "본체 저장 메모리에 설치",
|
|
||||||
"SD Card Install": "SD 카드에 설치",
|
|
||||||
"Exit": "나가기",
|
"Exit": "나가기",
|
||||||
|
"Install disabled...\nPlease enable installing via the install options.": "설치가 비활성화 되었습니다\n설치 옵션에서 활성화해주세요",
|
||||||
|
"No GameCard inserted": "카트리지가 없습니다",
|
||||||
|
"GameCard is already trimmed!": "카트리지를 이미 트림했습니다",
|
||||||
|
"WARNING: GameCard is already trimmed!": "경고: 카트리지를 이미 트림했습니다",
|
||||||
|
"Continue": "계속",
|
||||||
"Gc install success!": "카트리지 설치 완료!",
|
"Gc install success!": "카트리지 설치 완료!",
|
||||||
"Gc install failed!": "카트리지 설치 실패!",
|
"Gc install failed!": "카트리지 설치 실패!",
|
||||||
|
|
||||||
@@ -160,14 +181,14 @@
|
|||||||
"Negative image": "반전",
|
"Negative image": "반전",
|
||||||
"Format": "해상도",
|
"Format": "해상도",
|
||||||
"Trimming Format": "트리밍 해상도",
|
"Trimming Format": "트리밍 해상도",
|
||||||
"320x240": "320×240",
|
|
||||||
"160x120": "160×120",
|
|
||||||
"80x60": "80×60",
|
|
||||||
"40x30": "40×30",
|
|
||||||
"20x15": "20×15",
|
|
||||||
"External Light Filter": "외부 조명 필터",
|
"External Light Filter": "외부 조명 필터",
|
||||||
"Load Default": "기본값으로 설정",
|
"Load Default": "기본값으로 설정",
|
||||||
|
|
||||||
|
"Web": "웹 브라우저",
|
||||||
|
"Select URL": "URL 주소 선택",
|
||||||
|
"Enter custom URL": "직접 지정",
|
||||||
|
"Enter URL": "URL을 기입하세요",
|
||||||
|
|
||||||
"Advanced": "고급",
|
"Advanced": "고급",
|
||||||
"Advanced Options": "고급 옵션",
|
"Advanced Options": "고급 옵션",
|
||||||
"Logging": "로깅",
|
"Logging": "로깅",
|
||||||
@@ -181,10 +202,12 @@
|
|||||||
"Restored hbmenu": "hbmenu 복원됨",
|
"Restored hbmenu": "hbmenu 복원됨",
|
||||||
"Restart Sphaira?": "Sphaira를 재시작할까요?",
|
"Restart Sphaira?": "Sphaira를 재시작할까요?",
|
||||||
"Press OK to restart Sphaira": "확인 버튼 입력하여 Sphaira 재시작",
|
"Press OK to restart Sphaira": "확인 버튼 입력하여 Sphaira 재시작",
|
||||||
|
"Boost CPU during transfer": "전송시 CPU 부스트",
|
||||||
"Text scroll speed": "긴 텍스트 표시 속도",
|
"Text scroll speed": "긴 텍스트 표시 속도",
|
||||||
"Slow": "천천히",
|
"Slow": "천천히",
|
||||||
"Normal": "보통",
|
"Normal": "보통",
|
||||||
"Fast": "빠르게",
|
"Fast": "빠르게",
|
||||||
|
"Set left-side menu": "좌측 메뉴 설정",
|
||||||
"Set right-side menu": "우측 메뉴 설정",
|
"Set right-side menu": "우측 메뉴 설정",
|
||||||
"Install options": "설치 옵션",
|
"Install options": "설치 옵션",
|
||||||
"Install Options": "설치 옵션",
|
"Install Options": "설치 옵션",
|
||||||
@@ -194,7 +217,6 @@
|
|||||||
"Install location": "설치 위치",
|
"Install location": "설치 위치",
|
||||||
"System memory": "본체 저장 메모리",
|
"System memory": "본체 저장 메모리",
|
||||||
"microSD card": "SD 카드",
|
"microSD card": "SD 카드",
|
||||||
"Boost CPU clock": "CPU 클럭 향상",
|
|
||||||
"Allow downgrade": "다운그레이드 허용",
|
"Allow downgrade": "다운그레이드 허용",
|
||||||
"Skip if already installed": "설치된 항목 건너뛰기",
|
"Skip if already installed": "설치된 항목 건너뛰기",
|
||||||
"Ticket only": "티켓만 설치",
|
"Ticket only": "티켓만 설치",
|
||||||
@@ -217,7 +239,7 @@
|
|||||||
"Hide Sphaira": "Sphaira 숨기기",
|
"Hide Sphaira": "Sphaira 숨기기",
|
||||||
"Install Forwarder": "바로가기 설치",
|
"Install Forwarder": "바로가기 설치",
|
||||||
"WARNING: Installing forwarders will lead to a ban!": "경고: 시스낸드에 설치 시, 밴 위험이 있습니다!",
|
"WARNING: Installing forwarders will lead to a ban!": "경고: 시스낸드에 설치 시, 밴 위험이 있습니다!",
|
||||||
"Installing Forwarder": "바로가기 설치",
|
"Installing Forwarder": "바로가기 설치 중",
|
||||||
"Creating Program": "프로그램 생성",
|
"Creating Program": "프로그램 생성",
|
||||||
"Creating Control": "컨트롤 생성",
|
"Creating Control": "컨트롤 생성",
|
||||||
"Creating Meta": "메타 생성",
|
"Creating Meta": "메타 생성",
|
||||||
@@ -225,6 +247,8 @@
|
|||||||
"Updating ncm databse": "Ncm 데이터베이스 업데이트",
|
"Updating ncm databse": "Ncm 데이터베이스 업데이트",
|
||||||
"Pushing application record": "응용 프로그램 기록 푸싱",
|
"Pushing application record": "응용 프로그램 기록 푸싱",
|
||||||
"Failed to install forwarder": "바로가기 설치 실패함",
|
"Failed to install forwarder": "바로가기 설치 실패함",
|
||||||
|
"Unstar": "즐겨찾기 해제",
|
||||||
|
"Star": "즐겨찾기",
|
||||||
"Unstarred ": "즐겨찾기 해제: ",
|
"Unstarred ": "즐겨찾기 해제: ",
|
||||||
"Starred ": "즐겨찾기 등록: ",
|
"Starred ": "즐겨찾기 등록: ",
|
||||||
"Failed to remove old forwarder, please manually remove it!": "바로가기 제거 실패함, 직접 제거해주세요!",
|
"Failed to remove old forwarder, please manually remove it!": "바로가기 제거 실패함, 직접 제거해주세요!",
|
||||||
@@ -257,12 +281,13 @@
|
|||||||
"Copy": "복사",
|
"Copy": "복사",
|
||||||
"Copying ": "복사 중 ",
|
"Copying ": "복사 중 ",
|
||||||
"Paste": "붙여넣기",
|
"Paste": "붙여넣기",
|
||||||
"Paste ": " ",
|
"Paste file(s)?": "붙여넣을까요?",
|
||||||
" file(s)?": "개 항목을 붙여넣을까요?",
|
|
||||||
"Pasting ": "붙여넣는 중 ",
|
"Pasting ": "붙여넣는 중 ",
|
||||||
"Pasting": "붙여넣기",
|
"Pasting": "붙여넣는 중",
|
||||||
"Rename": "이름 바꾸기",
|
"Rename": "이름 바꾸기",
|
||||||
"Set New File Name": "새 파일명 입력",
|
"Set New File Name": "새 파일명 입력",
|
||||||
|
"Failed to delete directory": "폴더 삭제 실패",
|
||||||
|
"Failed to delete file": "파일 삭제 실패",
|
||||||
"Extract zip": "압축 해제",
|
"Extract zip": "압축 해제",
|
||||||
"Extract Options": "압축 해제 옵션",
|
"Extract Options": "압축 해제 옵션",
|
||||||
"Extract here": "여기에 풀기",
|
"Extract here": "여기에 풀기",
|
||||||
@@ -285,13 +310,17 @@
|
|||||||
"Create Folder": "새 폴더",
|
"Create Folder": "새 폴더",
|
||||||
"Set Folder Name": "폴더명 입력",
|
"Set Folder Name": "폴더명 입력",
|
||||||
"Creating ": "생성 중 ",
|
"Creating ": "생성 중 ",
|
||||||
|
"View as text (unfinished)": "텍스트로 보기 (미완성)",
|
||||||
"Upload": "업로드",
|
"Upload": "업로드",
|
||||||
"Select upload location": "업로드 위치 선택",
|
"Select upload location": "업로드 위치 선택",
|
||||||
"No upload locations set!": "업로드 위치가 설정되지 않았습니다!",
|
"No upload locations set!": "업로드 위치가 설정되지 않았습니다!",
|
||||||
"Uploading": "업로드 중 ",
|
"Uploading": "업로드 중 ",
|
||||||
"Upload successfull!": "업로드 완료!",
|
"Upload successfull!": "업로드 완료!",
|
||||||
"Upload failed!": "업로드 실패!",
|
"Upload failed!": "업로드 실패!",
|
||||||
"View as text (unfinished)": "텍스트로 보기 (미완성)",
|
"Hash": "해시",
|
||||||
|
"Hash Options": "해시 옵션",
|
||||||
|
"Hashing": "해시화중",
|
||||||
|
"Failed to hash file...": "해시화에 실패했습니다...",
|
||||||
"Ignore read only": "읽기 전용 설정 무시",
|
"Ignore read only": "읽기 전용 설정 무시",
|
||||||
"Mount": "마운트",
|
"Mount": "마운트",
|
||||||
"Sd": "SD 카드",
|
"Sd": "SD 카드",
|
||||||
@@ -302,6 +331,7 @@
|
|||||||
"Launch ": "실행할까요 ",
|
"Launch ": "실행할까요 ",
|
||||||
"Launch option for: ": "실행 옵션: ",
|
"Launch option for: ": "실행 옵션: ",
|
||||||
"Select launcher for: ": "실행 런처: ",
|
"Select launcher for: ": "실행 런처: ",
|
||||||
|
"Close FileBrowser?": "파일 탐색창을 닫을까요?",
|
||||||
|
|
||||||
"Sort By": "정렬",
|
"Sort By": "정렬",
|
||||||
"Sort Options": "정렬 옵션",
|
"Sort Options": "정렬 옵션",
|
||||||
@@ -335,16 +365,16 @@
|
|||||||
"Search": "검색",
|
"Search": "검색",
|
||||||
|
|
||||||
"Options": "설정",
|
"Options": "설정",
|
||||||
|
"Split": "화면 분할",
|
||||||
"OK": "확인",
|
"OK": "확인",
|
||||||
"Back": "뒤로",
|
"Back": "뒤로",
|
||||||
"Select": "선택",
|
"Select": "선택",
|
||||||
"Open": "열기",
|
"Open": "열기",
|
||||||
|
"Close": "닫기",
|
||||||
"Launch": "실행",
|
"Launch": "실행",
|
||||||
"Restart": "재시작",
|
"Restart": "재시작",
|
||||||
"Next": "다음",
|
"Next": "다음",
|
||||||
"Prev": "이전",
|
"Prev": "이전",
|
||||||
"Unstar": "즐겨찾기 해제",
|
|
||||||
"Star": "즐겨찾기",
|
|
||||||
"Yes": "예",
|
"Yes": "예",
|
||||||
"No": "아니요",
|
"No": "아니요",
|
||||||
"On": "켬",
|
"On": "켬",
|
||||||
@@ -367,12 +397,13 @@
|
|||||||
"Remove": "제거",
|
"Remove": "제거",
|
||||||
"Completely remove ": "정말 삭제할까요 ",
|
"Completely remove ": "정말 삭제할까요 ",
|
||||||
"Removing ": "제거 중 ",
|
"Removing ": "제거 중 ",
|
||||||
|
"Uninstalling ": "설치 제거중 ",
|
||||||
"Removed ": "제거됨: ",
|
"Removed ": "제거됨: ",
|
||||||
"Uninstalling ": "설치 제거됨: ",
|
|
||||||
|
|
||||||
"Download": "다운로드",
|
"Download": "다운로드",
|
||||||
"Downloading ": "다운로드 중 ",
|
"Downloading ": "다운로드 중 ",
|
||||||
"Downloaded ": "다운로드 완료: ",
|
"Downloaded ": "다운로드 완료: ",
|
||||||
|
"Download via the Network options!": "네트워크 옵션에서 다운로드했습니다!",
|
||||||
|
|
||||||
"Update": "업데이트",
|
"Update": "업데이트",
|
||||||
"Update avaliable: ": "업데이트 가능: ",
|
"Update avaliable: ": "업데이트 가능: ",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
"No Internet": "Geen internet",
|
"No Internet": "Geen internet",
|
||||||
"Switch-Handheld!": "",
|
"Switch-Handheld!": "",
|
||||||
"Switch-Docked!": "",
|
"Switch-Docked!": "",
|
||||||
|
"Warning! Logs are enabled, Sphaira will run slowly!": "",
|
||||||
"Audio disabled due to suspended game": "",
|
"Audio disabled due to suspended game": "",
|
||||||
"Are you sure you wish to cancel?": "",
|
"Are you sure you wish to cancel?": "",
|
||||||
"An error occurred": "",
|
"An error occurred": "",
|
||||||
@@ -27,6 +28,8 @@
|
|||||||
"Nxlink Connected": "",
|
"Nxlink Connected": "",
|
||||||
"Nxlink Upload": "",
|
"Nxlink Upload": "",
|
||||||
"Nxlink Finished": "",
|
"Nxlink Finished": "",
|
||||||
|
"Hdd": "",
|
||||||
|
"Hdd write protect": "",
|
||||||
|
|
||||||
"Language": "Taal",
|
"Language": "Taal",
|
||||||
"Auto": "",
|
"Auto": "",
|
||||||
@@ -57,22 +60,35 @@
|
|||||||
"No meta entries found...\n": "",
|
"No meta entries found...\n": "",
|
||||||
"Updating application record list": "",
|
"Updating application record list": "",
|
||||||
"Dump": "",
|
"Dump": "",
|
||||||
|
"Dump options": "",
|
||||||
|
"Dump Options": "",
|
||||||
"Select content to dump": "",
|
"Select content to dump": "",
|
||||||
"Dump All": "",
|
"Dump All": "",
|
||||||
"Dump Application": "",
|
"Dump Application": "",
|
||||||
"Dump Patch": "",
|
"Dump Patch": "",
|
||||||
"Dump AddOnContent": "",
|
"Dump AddOnContent": "",
|
||||||
"Dump DataPatch": "",
|
"Dump DataPatch": "",
|
||||||
|
"Created nested folder": "",
|
||||||
|
"Append folder with .xci": "",
|
||||||
|
"Trim XCI": "",
|
||||||
|
"Label trimmed XCI": "",
|
||||||
|
"Multi-threaded USB transfer": "",
|
||||||
|
"Dump All Bins": "",
|
||||||
|
"Dump XCI": "",
|
||||||
|
"Dump Card ID Set": "",
|
||||||
|
"Dump Card UID": "",
|
||||||
|
"Dump Certificate": "",
|
||||||
|
"Dump Initial Data": "",
|
||||||
"Select dump location": "",
|
"Select dump location": "",
|
||||||
"microSD card (/dumps/NSP/)": "",
|
"microSD card (/dumps/)": "",
|
||||||
"USB transfer (Switch 2 Switch)": "",
|
"USB transfer (Switch 2 Switch)": "",
|
||||||
"/dev/null (Speed Test)": "",
|
"/dev/null (Speed Test)": "",
|
||||||
"Dumping": "",
|
"Dumping": "",
|
||||||
"Dump successfull!": "",
|
"Dump successfull!": "",
|
||||||
"Dump failed!": "",
|
"Dump failed!": "",
|
||||||
"Success": "",
|
|
||||||
"Delete successfull!": "",
|
"Delete successfull!": "",
|
||||||
"Delete failed!": "",
|
"Delete failed!": "",
|
||||||
|
"Success": "",
|
||||||
|
|
||||||
"Themezer": "Themamaker",
|
"Themezer": "Themamaker",
|
||||||
"Themezer Options": "",
|
"Themezer Options": "",
|
||||||
@@ -86,6 +102,8 @@
|
|||||||
"GitHub": "",
|
"GitHub": "",
|
||||||
"Downloading json": "",
|
"Downloading json": "",
|
||||||
"Select asset to download for ": "",
|
"Select asset to download for ": "",
|
||||||
|
"Failed to download json": "",
|
||||||
|
"Failed to download app!": "",
|
||||||
|
|
||||||
"FTP Install": "",
|
"FTP Install": "",
|
||||||
"FTP Install (EXPERIMENTAL)": "",
|
"FTP Install (EXPERIMENTAL)": "",
|
||||||
@@ -122,9 +140,12 @@
|
|||||||
"GC": "",
|
"GC": "",
|
||||||
"System memory %.1f GB": "",
|
"System memory %.1f GB": "",
|
||||||
"microSD card %.1f GB": "",
|
"microSD card %.1f GB": "",
|
||||||
"Nand Install": "",
|
|
||||||
"SD Card Install": "",
|
|
||||||
"Exit": "",
|
"Exit": "",
|
||||||
|
"Install disabled...\nPlease enable installing via the install options.": "",
|
||||||
|
"No GameCard inserted": "",
|
||||||
|
"GameCard is already trimmed!": "",
|
||||||
|
"WARNING: GameCard is already trimmed!": "",
|
||||||
|
"Continue": "",
|
||||||
"Gc install success!": "",
|
"Gc install success!": "",
|
||||||
"Gc install failed!": "",
|
"Gc install failed!": "",
|
||||||
|
|
||||||
@@ -160,14 +181,14 @@
|
|||||||
"Negative image": "Negatief beeld",
|
"Negative image": "Negatief beeld",
|
||||||
"Format": "Formaat",
|
"Format": "Formaat",
|
||||||
"Trimming Format": "Trimformaat",
|
"Trimming Format": "Trimformaat",
|
||||||
"320x240": "320×240",
|
|
||||||
"160x120": "160×120",
|
|
||||||
"80x60": "80×60",
|
|
||||||
"40x30": "40×30",
|
|
||||||
"20x15": "20×15",
|
|
||||||
"External Light Filter": "Extern lichtfilter",
|
"External Light Filter": "Extern lichtfilter",
|
||||||
"Load Default": "Standaard laden",
|
"Load Default": "Standaard laden",
|
||||||
|
|
||||||
|
"Web": "",
|
||||||
|
"Select URL": "",
|
||||||
|
"Enter custom URL": "",
|
||||||
|
"Enter URL": "",
|
||||||
|
|
||||||
"Advanced": "Geavanceerd",
|
"Advanced": "Geavanceerd",
|
||||||
"Advanced Options": "Bestand maken",
|
"Advanced Options": "Bestand maken",
|
||||||
"Logging": "Loggen",
|
"Logging": "Loggen",
|
||||||
@@ -181,10 +202,12 @@
|
|||||||
"Restored hbmenu": "",
|
"Restored hbmenu": "",
|
||||||
"Restart Sphaira?": "",
|
"Restart Sphaira?": "",
|
||||||
"Press OK to restart Sphaira": "",
|
"Press OK to restart Sphaira": "",
|
||||||
|
"Boost CPU during transfer": "",
|
||||||
"Text scroll speed": "",
|
"Text scroll speed": "",
|
||||||
"Slow": "",
|
"Slow": "",
|
||||||
"Normal": "",
|
"Normal": "",
|
||||||
"Fast": "",
|
"Fast": "",
|
||||||
|
"Set left-side menu": "",
|
||||||
"Set right-side menu": "",
|
"Set right-side menu": "",
|
||||||
"Install options": "",
|
"Install options": "",
|
||||||
"Install Options": "",
|
"Install Options": "",
|
||||||
@@ -194,7 +217,6 @@
|
|||||||
"Install location": "",
|
"Install location": "",
|
||||||
"System memory": "",
|
"System memory": "",
|
||||||
"microSD card": "",
|
"microSD card": "",
|
||||||
"Boost CPU clock": "",
|
|
||||||
"Allow downgrade": "",
|
"Allow downgrade": "",
|
||||||
"Skip if already installed": "",
|
"Skip if already installed": "",
|
||||||
"Ticket only": "",
|
"Ticket only": "",
|
||||||
@@ -225,6 +247,8 @@
|
|||||||
"Updating ncm databse": "",
|
"Updating ncm databse": "",
|
||||||
"Pushing application record": "",
|
"Pushing application record": "",
|
||||||
"Failed to install forwarder": "",
|
"Failed to install forwarder": "",
|
||||||
|
"Unstar": "",
|
||||||
|
"Star": "",
|
||||||
"Unstarred ": "",
|
"Unstarred ": "",
|
||||||
"Starred ": "",
|
"Starred ": "",
|
||||||
"Failed to remove old forwarder, please manually remove it!": "",
|
"Failed to remove old forwarder, please manually remove it!": "",
|
||||||
@@ -257,12 +281,13 @@
|
|||||||
"Copy": "Kopiëren",
|
"Copy": "Kopiëren",
|
||||||
"Copying ": "",
|
"Copying ": "",
|
||||||
"Paste": "",
|
"Paste": "",
|
||||||
"Paste ": "",
|
"Paste file(s)?": "",
|
||||||
" file(s)?": "",
|
|
||||||
"Pasting ": "",
|
"Pasting ": "",
|
||||||
"Pasting": "",
|
"Pasting": "",
|
||||||
"Rename": "Hernoemen",
|
"Rename": "Hernoemen",
|
||||||
"Set New File Name": "",
|
"Set New File Name": "",
|
||||||
|
"Failed to delete directory": "",
|
||||||
|
"Failed to delete file": "",
|
||||||
"Extract zip": "",
|
"Extract zip": "",
|
||||||
"Extract Options": "",
|
"Extract Options": "",
|
||||||
"Extract here": "",
|
"Extract here": "",
|
||||||
@@ -285,13 +310,17 @@
|
|||||||
"Create Folder": "Map maken",
|
"Create Folder": "Map maken",
|
||||||
"Set Folder Name": "",
|
"Set Folder Name": "",
|
||||||
"Creating ": "",
|
"Creating ": "",
|
||||||
|
"View as text (unfinished)": "Bekijk als tekst (onvoltooid)",
|
||||||
"Upload": "",
|
"Upload": "",
|
||||||
"Select upload location": "",
|
"Select upload location": "",
|
||||||
"No upload locations set!": "",
|
"No upload locations set!": "",
|
||||||
"Uploading": "",
|
"Uploading": "",
|
||||||
"Upload successfull!": "",
|
"Upload successfull!": "",
|
||||||
"Upload failed!": "",
|
"Upload failed!": "",
|
||||||
"View as text (unfinished)": "Bekijk als tekst (onvoltooid)",
|
"Hash": "",
|
||||||
|
"Hash Options": "",
|
||||||
|
"Hashing": "",
|
||||||
|
"Failed to hash file...": "",
|
||||||
"Ignore read only": "",
|
"Ignore read only": "",
|
||||||
"Mount": "",
|
"Mount": "",
|
||||||
"Sd": "",
|
"Sd": "",
|
||||||
@@ -302,6 +331,7 @@
|
|||||||
"Launch ": "",
|
"Launch ": "",
|
||||||
"Launch option for: ": "",
|
"Launch option for: ": "",
|
||||||
"Select launcher for: ": "",
|
"Select launcher for: ": "",
|
||||||
|
"Close FileBrowser?": "",
|
||||||
|
|
||||||
"Sort By": "Sorteer op",
|
"Sort By": "Sorteer op",
|
||||||
"Sort Options": "Sorteeropties",
|
"Sort Options": "Sorteeropties",
|
||||||
@@ -335,16 +365,16 @@
|
|||||||
"Search": "Zoekopdracht",
|
"Search": "Zoekopdracht",
|
||||||
|
|
||||||
"Options": "Opties",
|
"Options": "Opties",
|
||||||
|
"Split": "",
|
||||||
"OK": "",
|
"OK": "",
|
||||||
"Back": "Terug",
|
"Back": "Terug",
|
||||||
"Select": "",
|
"Select": "",
|
||||||
"Open": "Open",
|
"Open": "Open",
|
||||||
|
"Close": "",
|
||||||
"Launch": "Launch",
|
"Launch": "Launch",
|
||||||
"Restart": "",
|
"Restart": "",
|
||||||
"Next": "",
|
"Next": "",
|
||||||
"Prev": "",
|
"Prev": "",
|
||||||
"Unstar": "",
|
|
||||||
"Star": "",
|
|
||||||
"Yes": "Ja",
|
"Yes": "Ja",
|
||||||
"No": "Nee",
|
"No": "Nee",
|
||||||
"On": "",
|
"On": "",
|
||||||
@@ -367,12 +397,13 @@
|
|||||||
"Remove": "",
|
"Remove": "",
|
||||||
"Completely remove ": "",
|
"Completely remove ": "",
|
||||||
"Removing ": "",
|
"Removing ": "",
|
||||||
"Removed ": "",
|
|
||||||
"Uninstalling ": "",
|
"Uninstalling ": "",
|
||||||
|
"Removed ": "",
|
||||||
|
|
||||||
"Download": "Downloaden",
|
"Download": "Downloaden",
|
||||||
"Downloading ": "",
|
"Downloading ": "",
|
||||||
"Downloaded ": "",
|
"Downloaded ": "",
|
||||||
|
"Download via the Network options!": "",
|
||||||
|
|
||||||
"Update": "",
|
"Update": "",
|
||||||
"Update avaliable: ": "",
|
"Update avaliable: ": "",
|
||||||
|
|||||||
@@ -3,15 +3,16 @@
|
|||||||
"No Internet": "Sem internet",
|
"No Internet": "Sem internet",
|
||||||
"Switch-Handheld!": "Switch-Portátil",
|
"Switch-Handheld!": "Switch-Portátil",
|
||||||
"Switch-Docked!": "Switch-Docado",
|
"Switch-Docked!": "Switch-Docado",
|
||||||
|
"Warning! Logs are enabled, Sphaira will run slowly!": "",
|
||||||
"Audio disabled due to suspended game": "Áudio desativado devido ao software suspenso.",
|
"Audio disabled due to suspended game": "Áudio desativado devido ao software suspenso.",
|
||||||
"Are you sure you wish to cancel?": "Tem certeza de que quer cancelar?",
|
"Are you sure you wish to cancel?": "Tem certeza de que quer cancelar?",
|
||||||
"An error occurred": "Ocorreu um erro.",
|
"An error occurred": "Ocorreu um erro.",
|
||||||
"If this message appears repeatedly, please open an issue.": "Se esta mensagem aparecer repetidamente, abra um issue.",
|
"If this message appears repeatedly, please open an issue.": "Se esta mensagem aparecer repetidamente, abra um issue.",
|
||||||
|
|
||||||
"Menu Options": "Opções do menu",
|
"Menu Options": "Menu",
|
||||||
"Menu": "Menu",
|
"Menu": "Menu",
|
||||||
"Theme": "Tema",
|
"Theme": "Tema",
|
||||||
"Theme Options": "Opções de tema",
|
"Theme Options": "Tema",
|
||||||
"Select Theme": "Estilo",
|
"Select Theme": "Estilo",
|
||||||
"Music": "Música",
|
"Music": "Música",
|
||||||
"12 Hour Time": "Relógio de 12 horas",
|
"12 Hour Time": "Relógio de 12 horas",
|
||||||
@@ -20,7 +21,7 @@
|
|||||||
"Overwrite current default music?": "Substituir a música padrão atual?",
|
"Overwrite current default music?": "Substituir a música padrão atual?",
|
||||||
|
|
||||||
"Network": "Rede",
|
"Network": "Rede",
|
||||||
"Network Options": "Opções de rede",
|
"Network Options": "Rede",
|
||||||
"Ftp": "Servidor FTP",
|
"Ftp": "Servidor FTP",
|
||||||
"Mtp": "Escuta MTP",
|
"Mtp": "Escuta MTP",
|
||||||
"Nxlink": "Nxlink",
|
"Nxlink": "Nxlink",
|
||||||
@@ -48,23 +49,36 @@
|
|||||||
"Ukrainian": "Українська",
|
"Ukrainian": "Українська",
|
||||||
|
|
||||||
"Misc": "Diversos",
|
"Misc": "Diversos",
|
||||||
"Misc Options": "Opções diversas",
|
"Misc Options": "Diversos",
|
||||||
"Games": "Softwares",
|
"Games": "Softwares",
|
||||||
"Game Options": "Opções de software",
|
"Game Options": "Opções do software",
|
||||||
"Hide forwarders": "Ocultar atalhos forwarder",
|
"Hide forwarders": "Ocultar atalhos forwarder",
|
||||||
"Launch random game": "Iniciar um software aleatório",
|
"Launch random game": "Iniciar um software aleatório",
|
||||||
"List meta records": "Registro de dados",
|
"List meta records": "Registro de dados",
|
||||||
"Entries": "Entradas",
|
"Entries": "Entradas",
|
||||||
"Failed to list application meta entries": "Falha ao listar as meta entradas do aplicativo.",
|
"Failed to list application meta entries": "Falha ao listar as meta entradas do software.",
|
||||||
"No meta entries found...\n": "Nenhuma entrada de registros encontrada...\n",
|
"No meta entries found...\n": "Nenhuma entrada de registros encontrada...\n",
|
||||||
"Updating application record list": "Atualizando a lista de registros do software...",
|
"Updating application record list": "Atualizando a lista de registros do software...",
|
||||||
"Dump": "Exportar dados",
|
"Dump": "Exportar dados",
|
||||||
|
"Dump options": "Opções de exportação",
|
||||||
|
"Dump Options": "Opções de exportação",
|
||||||
"Select content to dump": "Exportação de dados",
|
"Select content to dump": "Exportação de dados",
|
||||||
"Dump All": "Exportar tudo",
|
"Dump All": "Exportar tudo",
|
||||||
"Dump Application": "Exportar software base",
|
"Dump Application": "Exportar software base",
|
||||||
"Dump Patch": "Exportar atualização",
|
"Dump Patch": "Exportar atualização",
|
||||||
"Dump AddOnContent": "Exportar DLCs",
|
"Dump AddOnContent": "Exportar DLCs",
|
||||||
"Dump DataPatch": "Exportar atualização de DLCs",
|
"Dump DataPatch": "Exportar atualização de DLCs",
|
||||||
|
"Created nested folder": "Criar pastas aninhadas",
|
||||||
|
"Append folder with .xci": "Acrescentar .xci à pasta",
|
||||||
|
"Trim XCI": "Aparar arquivos .xci",
|
||||||
|
"Label trimmed XCI": "Rotular .xci aparados",
|
||||||
|
"Multi-threaded USB transfer": "Trasfêrencia em multithread",
|
||||||
|
"Dump All Bins": "Exportar todos os binários",
|
||||||
|
"Dump XCI": "Exportar .xci",
|
||||||
|
"Dump Card ID Set": "Exportar conjunto de IDs",
|
||||||
|
"Dump Card UID": "Exportar UID",
|
||||||
|
"Dump Certificate": "Exportar certificado",
|
||||||
|
"Dump Initial Data": "Exportar dados iniciais",
|
||||||
"Select dump location": "Selecione o local de exportação",
|
"Select dump location": "Selecione o local de exportação",
|
||||||
"microSD card (/dumps/)": "Cartão microSD (/dumps/)",
|
"microSD card (/dumps/)": "Cartão microSD (/dumps/)",
|
||||||
"USB transfer (Switch 2 Switch)": "Transferência via USB (Switch 2 Switch)",
|
"USB transfer (Switch 2 Switch)": "Transferência via USB (Switch 2 Switch)",
|
||||||
@@ -72,9 +86,9 @@
|
|||||||
"Dumping": "Exportando...",
|
"Dumping": "Exportando...",
|
||||||
"Dump successfull!": "Exportação concluída.",
|
"Dump successfull!": "Exportação concluída.",
|
||||||
"Dump failed!": "Exportação falhou.",
|
"Dump failed!": "Exportação falhou.",
|
||||||
"Success": "Concluído.",
|
|
||||||
"Delete successfull!": "Remoção concluída.",
|
"Delete successfull!": "Remoção concluída.",
|
||||||
"Delete failed!": "Remoção falhou.",
|
"Delete failed!": "Remoção falhou.",
|
||||||
|
"Success": "Concluído.",
|
||||||
|
|
||||||
"Themezer": "Themezer",
|
"Themezer": "Themezer",
|
||||||
"Themezer Options": "Opções do Themezer",
|
"Themezer Options": "Opções do Themezer",
|
||||||
@@ -88,11 +102,13 @@
|
|||||||
"GitHub": "GitHub",
|
"GitHub": "GitHub",
|
||||||
"Downloading json": "Baixando JSON",
|
"Downloading json": "Baixando JSON",
|
||||||
"Select asset to download for ": "Selecione o recurso para baixar de ",
|
"Select asset to download for ": "Selecione o recurso para baixar de ",
|
||||||
|
"Failed to download json": "",
|
||||||
|
"Failed to download app!": "",
|
||||||
|
|
||||||
"FTP Install": "Instalação via FTP",
|
"FTP Install": "Instalação via FTP",
|
||||||
"FTP Install (EXPERIMENTAL)": "Instalação via FTP (EXPERIMENTAL)",
|
"FTP Install (EXPERIMENTAL)": "Instalação via FTP (experimental)",
|
||||||
"Connection Type: WiFi | Strength: ": "Conexão por rede Wi-Fi | Intensidade do sinal: ",
|
"Connection Type: WiFi | Strength: ": "Conexão por rede Wi-Fi | Intensidade do sinal: ",
|
||||||
"Connection Type: Ethernet": "Conexão por cabo (ethernet)",
|
"Connection Type: Ethernet": "Conexão por cabo Ethernet",
|
||||||
"Connection Type: None": "Sem conexão",
|
"Connection Type: None": "Sem conexão",
|
||||||
"Host:": "Host:",
|
"Host:": "Host:",
|
||||||
"Port:": "Porta:",
|
"Port:": "Porta:",
|
||||||
@@ -124,11 +140,16 @@
|
|||||||
"GC": "Cartão de jogo",
|
"GC": "Cartão de jogo",
|
||||||
"System memory %.1f GB": "Memória do console %.1f GB",
|
"System memory %.1f GB": "Memória do console %.1f GB",
|
||||||
"microSD card %.1f GB": "Cartão microSD %.1f GB",
|
"microSD card %.1f GB": "Cartão microSD %.1f GB",
|
||||||
"Nand Install": "Instalar na memória do console",
|
|
||||||
"SD Card Install": "Instalar no cartão microSD",
|
|
||||||
"Exit": "Sair",
|
"Exit": "Sair",
|
||||||
|
"Install disabled...\nPlease enable installing via the install options.": "",
|
||||||
|
"No GameCard inserted": "",
|
||||||
|
"GameCard is already trimmed!": "",
|
||||||
|
"WARNING: GameCard is already trimmed!": "",
|
||||||
|
"Continue": "",
|
||||||
"Gc install success!": "Instalação de cartão de jogo concluída.",
|
"Gc install success!": "Instalação de cartão de jogo concluída.",
|
||||||
"Gc install failed!": "Instalação de cartão de jogo falhou.",
|
"Gc install failed!": "Instalação de cartão de jogo falhou.",
|
||||||
|
"Gc install success!": "Instalação do cartão de jogo concluída.",
|
||||||
|
"Gc install failed!": "Instalação do cartão de jogo falhou.",
|
||||||
|
|
||||||
"IRS (Infrared Joycon Camera)": "Câmera de movimento IR",
|
"IRS (Infrared Joycon Camera)": "Câmera de movimento IR",
|
||||||
"IRS": "Câmera de movimento IR",
|
"IRS": "Câmera de movimento IR",
|
||||||
@@ -162,22 +183,26 @@
|
|||||||
"Negative image": "Imagem negativa",
|
"Negative image": "Imagem negativa",
|
||||||
"Format": "Formato",
|
"Format": "Formato",
|
||||||
"Trimming Format": "Formato do recorte",
|
"Trimming Format": "Formato do recorte",
|
||||||
"320x240": "320×240",
|
|
||||||
"160x120": "160×120",
|
|
||||||
"80x60": "80×60",
|
|
||||||
"40x30": "40×30",
|
|
||||||
"20x15": "20×15",
|
|
||||||
"External Light Filter": "Filtro de luz externa",
|
"External Light Filter": "Filtro de luz externa",
|
||||||
"Load Default": "Restaurar padrão",
|
"Load Default": "Restaurar padrão",
|
||||||
|
|
||||||
"Advanced": "Avançados",
|
"Web": "Navegador de internet",
|
||||||
|
"Select URL": "Selecione uma URL",
|
||||||
|
"Enter custom URL": "Digitar URL",
|
||||||
|
|
||||||
|
"Web": "",
|
||||||
|
"Select URL": "",
|
||||||
|
"Enter custom URL": "",
|
||||||
|
"Enter URL": "",
|
||||||
|
|
||||||
|
"Advanced": "Opções avançadas",
|
||||||
"Advanced Options": "Opções avançadas",
|
"Advanced Options": "Opções avançadas",
|
||||||
"Logging": "Registro de depuração",
|
"Logging": "Registro de depuração",
|
||||||
"Replace hbmenu on exit": "Substituir hbmenu ao sair",
|
"Replace hbmenu on exit": "Substituir hbmenu ao sair",
|
||||||
"Restore hbmenu?": "Restaurar hbmenu?",
|
"Restore hbmenu?": "Restaurar hbmenu?",
|
||||||
"Restore": "Restaurar",
|
"Restore": "Restaurar",
|
||||||
"Failed to find /switch/hbmenu.nro\nUse the Appstore to re-install hbmenu": "Falha ao buscar /switch/hbmenu.nro\nUse a loja (AppStore) para reinstalar o hbmenu.",
|
"Failed to find /switch/hbmenu.nro\nUse the Appstore to re-install hbmenu": "Falha ao buscar /switch/hbmenu.nro\nUse a loja (AppStore) para reinstalar o hbmenu.",
|
||||||
"Failed to restore hbmenu, please re-download hbmenu": "Falha ao restaurar o hbmenu, tente baixa-lo novamente.",
|
"Failed to restore hbmenu, please re-download hbmenu": "Falha ao restaurar hbmenu, tente baixa-lo novamente.",
|
||||||
"Failed to restore hbmenu, using sphaira instead": "Falha ao restaurar hbmenu, usando sphaira no seu lugar.",
|
"Failed to restore hbmenu, using sphaira instead": "Falha ao restaurar hbmenu, usando sphaira no seu lugar.",
|
||||||
"Restored hbmenu, closing sphaira": "hbmenu restaurado, fechando sphaira.",
|
"Restored hbmenu, closing sphaira": "hbmenu restaurado, fechando sphaira.",
|
||||||
"Restored hbmenu": "hbmenu restaurado.",
|
"Restored hbmenu": "hbmenu restaurado.",
|
||||||
@@ -198,7 +223,6 @@
|
|||||||
"Install location": "Local de instalação",
|
"Install location": "Local de instalação",
|
||||||
"System memory": "Memória do console",
|
"System memory": "Memória do console",
|
||||||
"microSD card": "Cartão microSD",
|
"microSD card": "Cartão microSD",
|
||||||
"Boost CPU clock": "Impulsionar CPU",
|
|
||||||
"Allow downgrade": "Permitir downgrade",
|
"Allow downgrade": "Permitir downgrade",
|
||||||
"Skip if already installed": "Pular se já instalado",
|
"Skip if already installed": "Pular se já instalado",
|
||||||
"Ticket only": "Instalar apenas tickets",
|
"Ticket only": "Instalar apenas tickets",
|
||||||
@@ -220,12 +244,12 @@
|
|||||||
"Append folder with .xci": "Acrescentar .xci à pasta",
|
"Append folder with .xci": "Acrescentar .xci à pasta",
|
||||||
"Trim XCI": "Aparar arquivos .xci",
|
"Trim XCI": "Aparar arquivos .xci",
|
||||||
"Label trimmed XCI": "Rotular .xci aparados",
|
"Label trimmed XCI": "Rotular .xci aparados",
|
||||||
"Multi-threaded USB transfer": "Trasfêrencia em multithread",
|
"Multi-threaded USB transfer": "Transferências em multithread",
|
||||||
|
|
||||||
"Homebrew": "Aplicativos",
|
"Homebrew": "Homebrews",
|
||||||
"Apps": "Aplicativos",
|
"Apps": "Homebrews",
|
||||||
"Homebrew Options": "Opções de aplicativo",
|
"Homebrew Options": "Opções do homebrew",
|
||||||
"Hide Sphaira": "Esconder sphaira",
|
"Hide Sphaira": "Esconder sphaira da lista",
|
||||||
"Install Forwarder": "Instalar atalho forwarder",
|
"Install Forwarder": "Instalar atalho forwarder",
|
||||||
"WARNING: Installing forwarders will lead to a ban!": "AVISO: Instalar atalhos forwarder pode resultar em um banimento!",
|
"WARNING: Installing forwarders will lead to a ban!": "AVISO: Instalar atalhos forwarder pode resultar em um banimento!",
|
||||||
"Installing Forwarder": "Instalando atalho forwarder...",
|
"Installing Forwarder": "Instalando atalho forwarder...",
|
||||||
@@ -236,6 +260,8 @@
|
|||||||
"Updating ncm databse": "Atualizando base de dados NCM",
|
"Updating ncm databse": "Atualizando base de dados NCM",
|
||||||
"Pushing application record": "Aplicando registro do software",
|
"Pushing application record": "Aplicando registro do software",
|
||||||
"Failed to install forwarder": "Falha ao instalar atalho forwarder.",
|
"Failed to install forwarder": "Falha ao instalar atalho forwarder.",
|
||||||
|
"Unstar": "Desfavoritar",
|
||||||
|
"Star": "Favoritar",
|
||||||
"Unstarred ": "Desfavoritado ",
|
"Unstarred ": "Desfavoritado ",
|
||||||
"Starred ": "Favoritado ",
|
"Starred ": "Favoritado ",
|
||||||
"Failed to remove old forwarder, please manually remove it!": "Falha ao desinstalar atalho forwarder, tente remove-lo manualmente.",
|
"Failed to remove old forwarder, please manually remove it!": "Falha ao desinstalar atalho forwarder, tente remove-lo manualmente.",
|
||||||
@@ -260,23 +286,24 @@
|
|||||||
"Files": "Arquivos",
|
"Files": "Arquivos",
|
||||||
"%zd files": "%zd arquivo(s)",
|
"%zd files": "%zd arquivo(s)",
|
||||||
"%zd dirs": "%zd diretório(s)",
|
"%zd dirs": "%zd diretório(s)",
|
||||||
"File Options": "Opções de arquivo",
|
"File Options": "Opções do arquivo",
|
||||||
"Show Hidden": "Mostrar ocultos",
|
"Show Hidden": "Mostrar arquivos ocultos",
|
||||||
"Folders First": "Pastas primeiro",
|
"Folders First": "Ordenar pastas primeiro",
|
||||||
"Hidden Last": "Ocultos por último",
|
"Hidden Last": "Ordenar ocultos por último",
|
||||||
"Split": "Dividir",
|
"Split": "Dividir",
|
||||||
"Close": "Fechar",
|
"Close": "Fechar",
|
||||||
"Cut": "Recortar",
|
"Cut": "Recortar",
|
||||||
"Copy": "Copiar",
|
"Copy": "Copiar",
|
||||||
"Copying ": "Copiando ",
|
"Copying ": "Copiando ",
|
||||||
"Paste": "Colar",
|
"Paste": "Colar",
|
||||||
"Paste ": "Colar ",
|
"Paste file(s)?": "",
|
||||||
" file(s)?": " arquivo(s)?",
|
|
||||||
"Pasting ": "Colando ",
|
"Pasting ": "Colando ",
|
||||||
"Pasting": "Colando ",
|
"Pasting": "Colando ",
|
||||||
"Rename": "Renomear",
|
"Rename": "Renomear",
|
||||||
"Set New File Name": "Defina o nome do novo arquivo",
|
"Set New File Name": "Defina o nome do novo arquivo",
|
||||||
"Extract zip": "Extrair zip",
|
"Failed to delete directory": "",
|
||||||
|
"Failed to delete file": "",
|
||||||
|
"Extract zip": "Extrair .zip",
|
||||||
"Extract Options": "Opções de extração",
|
"Extract Options": "Opções de extração",
|
||||||
"Extract here": "Extrair aqui",
|
"Extract here": "Extrair aqui",
|
||||||
"Extract to root": "Extrair para a raiz",
|
"Extract to root": "Extrair para a raiz",
|
||||||
@@ -286,8 +313,8 @@
|
|||||||
"Extracting ": "Extraindo ",
|
"Extracting ": "Extraindo ",
|
||||||
"Extract success!": "Extração concluída.",
|
"Extract success!": "Extração concluída.",
|
||||||
"Extract failed!": "Extração falhou.",
|
"Extract failed!": "Extração falhou.",
|
||||||
"Compress to zip": "Comprimir em zip",
|
"Compress to zip": "Comprimir em .zip",
|
||||||
"Compress Options": "Opções de compressão",
|
"Compress Options": "Comprimir em .zip",
|
||||||
"Compress": "Comprimir",
|
"Compress": "Comprimir",
|
||||||
"Compress to...": "Comprimir para...",
|
"Compress to...": "Comprimir para...",
|
||||||
"Compressing ": "Comprimindo ",
|
"Compressing ": "Comprimindo ",
|
||||||
@@ -298,29 +325,32 @@
|
|||||||
"Create Folder": "Criar pasta",
|
"Create Folder": "Criar pasta",
|
||||||
"Set Folder Name": "Defina o nome da pasta",
|
"Set Folder Name": "Defina o nome da pasta",
|
||||||
"Creating ": "Criando ",
|
"Creating ": "Criando ",
|
||||||
|
"View as text (unfinished)": "Ver como texto (inacabado)",
|
||||||
"Upload": "Enviar",
|
"Upload": "Enviar",
|
||||||
"Select upload location": "Selecione o local de envio",
|
"Select upload location": "Selecione o local de envio",
|
||||||
"No upload locations set!": "Nenhum local de envio definido.",
|
"No upload locations set!": "Nenhum local de envio definido.",
|
||||||
"Uploading": "Enviando",
|
"Uploading": "Enviando",
|
||||||
"Upload successfull!": "Envio concluído.",
|
"Upload successfull!": "Envio concluído.",
|
||||||
"Upload failed!": "Envio falhou.",
|
"Upload failed!": "Envio falhou.",
|
||||||
"Hash": "Hash",
|
"Hash": "Calcular hash",
|
||||||
"Hash Options": "Opções de hash",
|
"Hash Options": "Calcular hash",
|
||||||
|
"Hashing": "",
|
||||||
|
"Failed to hash file...": "",
|
||||||
"View as text (unfinished)": "Ver como texto (inacabado)",
|
"View as text (unfinished)": "Ver como texto (inacabado)",
|
||||||
"Ignore read only": "Ignorar modo somente leitura",
|
"Ignore read only": "Ignorar modo somente leitura",
|
||||||
"Mount": "Montar",
|
"Mount": "Montar",
|
||||||
"Sd": "SD",
|
"Sd": "SD",
|
||||||
"Image System memory": "Imagem (memória do console)",
|
"Image System memory": "Imagem (memória do console)",
|
||||||
"Image microSD card": "Imagem (cartão microSD)",
|
"Image microSD card": "Imagem (cartão microSD)",
|
||||||
"Empty...": "Vazio",
|
"Empty...": "Vazio.",
|
||||||
"Open with DayBreak?": "Abrir com DayBreak?",
|
"Open with DayBreak?": "Abrir com DayBreak?",
|
||||||
"Launch ": "Iniciar ",
|
"Launch ": "Iniciar ",
|
||||||
"Launch option for: ": "Opções de inicialização para: ",
|
"Launch option for: ": "Opções de inicialização para: ",
|
||||||
"Select launcher for: ": "Selecionar inicializador para: ",
|
"Select launcher for: ": "Selecionar inicializador para: ",
|
||||||
"Close FileBrowser?": "Fechar o gerenciador de arquivos?",
|
"Close FileBrowser?": "Fechar gerenciador de arquivos?",
|
||||||
|
|
||||||
"Sort By": "Ordernar",
|
"Sort By": "Ordenar",
|
||||||
"Sort Options": "Opções de ordenação",
|
"Sort Options": "Ordenar",
|
||||||
"Filter": "Filtro",
|
"Filter": "Filtro",
|
||||||
"All": "Todos",
|
"All": "Todos",
|
||||||
"Emulators": "Emuladores",
|
"Emulators": "Emuladores",
|
||||||
@@ -351,16 +381,16 @@
|
|||||||
"Search": "Buscar",
|
"Search": "Buscar",
|
||||||
|
|
||||||
"Options": "Opções",
|
"Options": "Opções",
|
||||||
|
"Split": "Dividir",
|
||||||
"OK": "OK",
|
"OK": "OK",
|
||||||
"Back": "Voltar",
|
"Back": "Voltar",
|
||||||
"Select": "Selecionar",
|
"Select": "Selecionar",
|
||||||
"Open": "Abrir",
|
"Open": "Abrir",
|
||||||
|
"Close": "Fechar",
|
||||||
"Launch": "Iniciar",
|
"Launch": "Iniciar",
|
||||||
"Restart": "Reiniciar",
|
"Restart": "Reiniciar",
|
||||||
"Next": "Prómixo",
|
"Next": "Prómixo",
|
||||||
"Prev": "Anterior",
|
"Prev": "Anterior",
|
||||||
"Unstar": "Desfavoritar",
|
|
||||||
"Star": "Favoritar",
|
|
||||||
"Yes": "Sim",
|
"Yes": "Sim",
|
||||||
"No": "Não",
|
"No": "Não",
|
||||||
"On": "Sim",
|
"On": "Sim",
|
||||||
@@ -383,12 +413,13 @@
|
|||||||
"Remove": "Remover",
|
"Remove": "Remover",
|
||||||
"Completely remove ": "Remover completamente ",
|
"Completely remove ": "Remover completamente ",
|
||||||
"Removing ": "Removendo ",
|
"Removing ": "Removendo ",
|
||||||
"Removed ": "Removido ",
|
|
||||||
"Uninstalling ": "Desinstalando ",
|
"Uninstalling ": "Desinstalando ",
|
||||||
|
"Removed ": "Removido ",
|
||||||
|
|
||||||
"Download": "Baixar",
|
"Download": "Baixar",
|
||||||
"Downloading ": "Baixando ",
|
"Downloading ": "Baixando ",
|
||||||
"Downloaded ": "Baixado ",
|
"Downloaded ": "Baixado ",
|
||||||
|
"Download via the Network options!": "",
|
||||||
|
|
||||||
"Update": "Atualizar",
|
"Update": "Atualizar",
|
||||||
"Update avaliable: ": "Atualização disponível: ",
|
"Update avaliable: ": "Atualização disponível: ",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
"No Internet": "Нет интернета",
|
"No Internet": "Нет интернета",
|
||||||
"Switch-Handheld!": "Режим Портатива",
|
"Switch-Handheld!": "Режим Портатива",
|
||||||
"Switch-Docked!": "Режим Дока",
|
"Switch-Docked!": "Режим Дока",
|
||||||
|
"Warning! Logs are enabled, Sphaira will run slowly!": "",
|
||||||
"Audio disabled due to suspended game": "Звук отключён из-за приостановки игры",
|
"Audio disabled due to suspended game": "Звук отключён из-за приостановки игры",
|
||||||
"Are you sure you wish to cancel?": "Вы уверены, что хотите отменить?",
|
"Are you sure you wish to cancel?": "Вы уверены, что хотите отменить?",
|
||||||
"An error occurred": "Произошла ошибка",
|
"An error occurred": "Произошла ошибка",
|
||||||
@@ -59,22 +60,35 @@
|
|||||||
"No meta entries found...\n": "Мета-записей не найдено...\n",
|
"No meta entries found...\n": "Мета-записей не найдено...\n",
|
||||||
"Updating application record list": "Обновление списка записей приложений",
|
"Updating application record list": "Обновление списка записей приложений",
|
||||||
"Dump": "Дамп",
|
"Dump": "Дамп",
|
||||||
|
"Dump options": "Опции дампа",
|
||||||
|
"Dump Options": "Опции дампа",
|
||||||
"Select content to dump": "Выберите содержимое для дампа",
|
"Select content to dump": "Выберите содержимое для дампа",
|
||||||
"Dump All": "Дамп всего",
|
"Dump All": "Дамп всего",
|
||||||
"Dump Application": "Дамп приложения",
|
"Dump Application": "Дамп приложения",
|
||||||
"Dump Patch": "Дамп патча",
|
"Dump Patch": "Дамп патча",
|
||||||
"Dump AddOnContent": "Дамп дополнительного контента",
|
"Dump AddOnContent": "Дамп дополнительного контента",
|
||||||
"Dump DataPatch": "Дамп патча данных",
|
"Dump DataPatch": "Дамп патча данных",
|
||||||
|
"Created nested folder": "Создать вложенную папку",
|
||||||
|
"Append folder with .xci": "Добавить папку с .xci",
|
||||||
|
"Trim XCI": "Обрезать .xci",
|
||||||
|
"Label trimmed XCI": "Пометить обрезанный .xci",
|
||||||
|
"Multi-threaded USB transfer": "Многоядерная USB передача",
|
||||||
|
"Dump All Bins": "",
|
||||||
|
"Dump XCI": "",
|
||||||
|
"Dump Card ID Set": "",
|
||||||
|
"Dump Card UID": "",
|
||||||
|
"Dump Certificate": "",
|
||||||
|
"Dump Initial Data": "",
|
||||||
"Select dump location": "Выберите место для дампа",
|
"Select dump location": "Выберите место для дампа",
|
||||||
"microSD card (/dumps/NSP/)": "microSD карта (/dumps/NSP/)",
|
"microSD card (/dumps/)": "microSD карта (/dumps/)",
|
||||||
"USB transfer (Switch 2 Switch)": "Передача по USB (Switch 2 Switch)",
|
"USB transfer (Switch 2 Switch)": "Передача по USB (Switch 2 Switch)",
|
||||||
"/dev/null (Speed Test)": "/dev/null (тест скорости)",
|
"/dev/null (Speed Test)": "/dev/null (тест скорости)",
|
||||||
"Dumping": "Снятие дампа",
|
"Dumping": "Снятие дампа",
|
||||||
"Dump successfull!": "Дамп выполнен успешно!",
|
"Dump successfull!": "Дамп выполнен успешно!",
|
||||||
"Dump failed!": "Сбой дампа!",
|
"Dump failed!": "Сбой дампа!",
|
||||||
"Success": "Успех",
|
|
||||||
"Delete successfull!": "Удаление успешно!",
|
"Delete successfull!": "Удаление успешно!",
|
||||||
"Delete failed!": "Ошибка удаления!",
|
"Delete failed!": "Ошибка удаления!",
|
||||||
|
"Success": "Успех",
|
||||||
|
|
||||||
"Themezer": "Themezer",
|
"Themezer": "Themezer",
|
||||||
"Themezer Options": "Опции Themezer",
|
"Themezer Options": "Опции Themezer",
|
||||||
@@ -88,6 +102,8 @@
|
|||||||
"GitHub": "GitHub",
|
"GitHub": "GitHub",
|
||||||
"Downloading json": "Загрузка json",
|
"Downloading json": "Загрузка json",
|
||||||
"Select asset to download for ": "Выберите ресурс для загрузки: ",
|
"Select asset to download for ": "Выберите ресурс для загрузки: ",
|
||||||
|
"Failed to download json": "",
|
||||||
|
"Failed to download app!": "",
|
||||||
|
|
||||||
"FTP Install": "Установка по FTP",
|
"FTP Install": "Установка по FTP",
|
||||||
"FTP Install (EXPERIMENTAL)": "Установка по FTP (ЭКСПЕРИМЕНТАЛЬНО)",
|
"FTP Install (EXPERIMENTAL)": "Установка по FTP (ЭКСПЕРИМЕНТАЛЬНО)",
|
||||||
@@ -124,9 +140,12 @@
|
|||||||
"GC": "GC",
|
"GC": "GC",
|
||||||
"System memory %.1f GB": "Память системы %.1f ГБ",
|
"System memory %.1f GB": "Память системы %.1f ГБ",
|
||||||
"microSD card %.1f GB": "Карта microSD %.1f ГБ",
|
"microSD card %.1f GB": "Карта microSD %.1f ГБ",
|
||||||
"Nand Install": "Установка в NAND",
|
|
||||||
"SD Card Install": "Установка на SD карту",
|
|
||||||
"Exit": "Выход",
|
"Exit": "Выход",
|
||||||
|
"Install disabled...\nPlease enable installing via the install options.": "",
|
||||||
|
"No GameCard inserted": "",
|
||||||
|
"GameCard is already trimmed!": "",
|
||||||
|
"WARNING: GameCard is already trimmed!": "",
|
||||||
|
"Continue": "",
|
||||||
"Gc install success!": "Установка с картриджа успешна!",
|
"Gc install success!": "Установка с картриджа успешна!",
|
||||||
"Gc install failed!": "Сбой установки с картриджа!",
|
"Gc install failed!": "Сбой установки с картриджа!",
|
||||||
|
|
||||||
@@ -162,14 +181,14 @@
|
|||||||
"Negative image": "Включен",
|
"Negative image": "Включен",
|
||||||
"Format": "Разрешение",
|
"Format": "Разрешение",
|
||||||
"Trimming Format": "Обрезка",
|
"Trimming Format": "Обрезка",
|
||||||
"320x240": "320×240",
|
|
||||||
"160x120": "160×120",
|
|
||||||
"80x60": "80×60",
|
|
||||||
"40x30": "40×30",
|
|
||||||
"20x15": "20×15",
|
|
||||||
"External Light Filter": "Внешний светофильтр",
|
"External Light Filter": "Внешний светофильтр",
|
||||||
"Load Default": "По умолчанию",
|
"Load Default": "По умолчанию",
|
||||||
|
|
||||||
|
"Web": "",
|
||||||
|
"Select URL": "",
|
||||||
|
"Enter custom URL": "",
|
||||||
|
"Enter URL": "",
|
||||||
|
|
||||||
"Advanced": "Продвинутые",
|
"Advanced": "Продвинутые",
|
||||||
"Advanced Options": "Расширенные опции",
|
"Advanced Options": "Расширенные опции",
|
||||||
"Logging": "Журналирование",
|
"Logging": "Журналирование",
|
||||||
@@ -198,7 +217,6 @@
|
|||||||
"Install location": "Место установки",
|
"Install location": "Место установки",
|
||||||
"System memory": "NAND",
|
"System memory": "NAND",
|
||||||
"microSD card": "microSD",
|
"microSD card": "microSD",
|
||||||
"Boost CPU clock": "Разгон CPU",
|
|
||||||
"Allow downgrade": "Разрешить даунгрейд",
|
"Allow downgrade": "Разрешить даунгрейд",
|
||||||
"Skip if already installed": "Пропуск установленного",
|
"Skip if already installed": "Пропуск установленного",
|
||||||
"Ticket only": "Только тикет",
|
"Ticket only": "Только тикет",
|
||||||
@@ -214,13 +232,6 @@
|
|||||||
"Convert to standard crypto": "Конверт. в стандарт. крипт.",
|
"Convert to standard crypto": "Конверт. в стандарт. крипт.",
|
||||||
"Lower master key": "Снизить мастер-ключ",
|
"Lower master key": "Снизить мастер-ключ",
|
||||||
"Lower system version": "Снизить версию системы",
|
"Lower system version": "Снизить версию системы",
|
||||||
"Dump options": "Опции дампа",
|
|
||||||
"Dump Options": "Опции дампа",
|
|
||||||
"Created nested folder": "Создать вложенную папку",
|
|
||||||
"Append folder with .xci": "Добавить папку с .xci",
|
|
||||||
"Trim XCI": "Обрезать .xci",
|
|
||||||
"Label trimmed XCI": "Пометить обрезанный .xci",
|
|
||||||
"Multi-threaded USB transfer": "Многоядерная USB передача",
|
|
||||||
|
|
||||||
"Homebrew": "Homebrew",
|
"Homebrew": "Homebrew",
|
||||||
"Apps": "Приложения",
|
"Apps": "Приложения",
|
||||||
@@ -236,6 +247,8 @@
|
|||||||
"Updating ncm databse": "Обновление базы данных NCM",
|
"Updating ncm databse": "Обновление базы данных NCM",
|
||||||
"Pushing application record": "Добавление записи приложения",
|
"Pushing application record": "Добавление записи приложения",
|
||||||
"Failed to install forwarder": "Не удалось установить форвардер",
|
"Failed to install forwarder": "Не удалось установить форвардер",
|
||||||
|
"Unstar": "Убрать из избранного",
|
||||||
|
"Star": "Добавить в избранное",
|
||||||
"Unstarred ": "Удалено из избранного: ",
|
"Unstarred ": "Удалено из избранного: ",
|
||||||
"Starred ": "Добавлено в избранное: ",
|
"Starred ": "Добавлено в избранное: ",
|
||||||
"Failed to remove old forwarder, please manually remove it!": "Не удалось удалить старый форвардер, удалите его вручную!",
|
"Failed to remove old forwarder, please manually remove it!": "Не удалось удалить старый форвардер, удалите его вручную!",
|
||||||
@@ -264,18 +277,17 @@
|
|||||||
"Show Hidden": "Показать скрытые",
|
"Show Hidden": "Показать скрытые",
|
||||||
"Folders First": "Папки в начале",
|
"Folders First": "Папки в начале",
|
||||||
"Hidden Last": "Скрытые в конце",
|
"Hidden Last": "Скрытые в конце",
|
||||||
"Split": "Разделить",
|
|
||||||
"Close": "Закрыть",
|
|
||||||
"Cut": "Вырезать",
|
"Cut": "Вырезать",
|
||||||
"Copy": "Копировать",
|
"Copy": "Копировать",
|
||||||
"Copying ": "Копирование ",
|
"Copying ": "Копирование ",
|
||||||
"Paste": "Вставить",
|
"Paste": "Вставить",
|
||||||
"Paste ": "Вставить ",
|
"Paste file(s)?": "",
|
||||||
" file(s)?": " файл(ов)?",
|
|
||||||
"Pasting ": "Вставка ",
|
"Pasting ": "Вставка ",
|
||||||
"Pasting": "Вставка",
|
"Pasting": "Вставка",
|
||||||
"Rename": "Переименовать",
|
"Rename": "Переименовать",
|
||||||
"Set New File Name": "Задайте новое имя файла",
|
"Set New File Name": "Задайте новое имя файла",
|
||||||
|
"Failed to delete directory": "",
|
||||||
|
"Failed to delete file": "",
|
||||||
"Extract zip": "Распаковать .zip",
|
"Extract zip": "Распаковать .zip",
|
||||||
"Extract Options": "Опции распаковки",
|
"Extract Options": "Опции распаковки",
|
||||||
"Extract here": "Распаковать сюда",
|
"Extract here": "Распаковать сюда",
|
||||||
@@ -298,6 +310,7 @@
|
|||||||
"Create Folder": "Создать папку",
|
"Create Folder": "Создать папку",
|
||||||
"Set Folder Name": "Укажите имя папки",
|
"Set Folder Name": "Укажите имя папки",
|
||||||
"Creating ": "Создание ",
|
"Creating ": "Создание ",
|
||||||
|
"View as text (unfinished)": "Открыть как текст (не доделано)",
|
||||||
"Upload": "Отправить",
|
"Upload": "Отправить",
|
||||||
"Select upload location": "Выберите место загрузки",
|
"Select upload location": "Выберите место загрузки",
|
||||||
"No upload locations set!": "Места загрузки не заданы!",
|
"No upload locations set!": "Места загрузки не заданы!",
|
||||||
@@ -306,7 +319,8 @@
|
|||||||
"Upload failed!": "Сбой Отправки!",
|
"Upload failed!": "Сбой Отправки!",
|
||||||
"Hash": "Хэш",
|
"Hash": "Хэш",
|
||||||
"Hash Options": "Опции хэша",
|
"Hash Options": "Опции хэша",
|
||||||
"View as text (unfinished)": "Открыть как текст (не доделано)",
|
"Hashing": "",
|
||||||
|
"Failed to hash file...": "",
|
||||||
"Ignore read only": "Игнор. только для чтения",
|
"Ignore read only": "Игнор. только для чтения",
|
||||||
"Mount": "Монтирован",
|
"Mount": "Монтирован",
|
||||||
"Sd": "Micro SD",
|
"Sd": "Micro SD",
|
||||||
@@ -351,16 +365,16 @@
|
|||||||
"Search": "Поиск",
|
"Search": "Поиск",
|
||||||
|
|
||||||
"Options": "Опции",
|
"Options": "Опции",
|
||||||
|
"Split": "Разделить",
|
||||||
"OK": "ОК",
|
"OK": "ОК",
|
||||||
"Back": "Назад",
|
"Back": "Назад",
|
||||||
"Select": "Выбрать",
|
"Select": "Выбрать",
|
||||||
"Open": "Открыть",
|
"Open": "Открыть",
|
||||||
|
"Close": "Закрыть",
|
||||||
"Launch": "Запуск",
|
"Launch": "Запуск",
|
||||||
"Restart": "Перезапустить",
|
"Restart": "Перезапустить",
|
||||||
"Next": "Далее",
|
"Next": "Далее",
|
||||||
"Prev": "Назад",
|
"Prev": "Назад",
|
||||||
"Unstar": "Убрать из избранного",
|
|
||||||
"Star": "Добавить в избранное",
|
|
||||||
"Yes": "Да",
|
"Yes": "Да",
|
||||||
"No": "Нет",
|
"No": "Нет",
|
||||||
"On": "Вкл",
|
"On": "Вкл",
|
||||||
@@ -383,12 +397,13 @@
|
|||||||
"Remove": "Удалить",
|
"Remove": "Удалить",
|
||||||
"Completely remove ": "Полностью удалить ",
|
"Completely remove ": "Полностью удалить ",
|
||||||
"Removing ": "Удаляется ",
|
"Removing ": "Удаляется ",
|
||||||
"Removed ": "Удалено ",
|
|
||||||
"Uninstalling ": "Деинсталляция ",
|
"Uninstalling ": "Деинсталляция ",
|
||||||
|
"Removed ": "Удалено ",
|
||||||
|
|
||||||
"Download": "Скачать",
|
"Download": "Скачать",
|
||||||
"Downloading ": "Загрузка ",
|
"Downloading ": "Загрузка ",
|
||||||
"Downloaded ": "Загружено ",
|
"Downloaded ": "Загружено ",
|
||||||
|
"Download via the Network options!": "",
|
||||||
|
|
||||||
"Update": "Обновить",
|
"Update": "Обновить",
|
||||||
"Update avaliable: ": "Доступно обновление: ",
|
"Update avaliable: ": "Доступно обновление: ",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
"No Internet": "Ingen Internetanslutning",
|
"No Internet": "Ingen Internetanslutning",
|
||||||
"Switch-Handheld!": "Switch Handhållen!",
|
"Switch-Handheld!": "Switch Handhållen!",
|
||||||
"Switch-Docked!": "Switch Dockad!",
|
"Switch-Docked!": "Switch Dockad!",
|
||||||
|
"Warning! Logs are enabled, Sphaira will run slowly!": "",
|
||||||
"Audio disabled due to suspended game": "Ljud är avstängt på grund av bakgrundsprogram",
|
"Audio disabled due to suspended game": "Ljud är avstängt på grund av bakgrundsprogram",
|
||||||
"Are you sure you wish to cancel?": "Är du säker på att du vill avbryta?",
|
"Are you sure you wish to cancel?": "Är du säker på att du vill avbryta?",
|
||||||
"An error occurred": "",
|
"An error occurred": "",
|
||||||
@@ -27,6 +28,8 @@
|
|||||||
"Nxlink Connected": "Nxlink ansluten",
|
"Nxlink Connected": "Nxlink ansluten",
|
||||||
"Nxlink Upload": "Nxlink överför",
|
"Nxlink Upload": "Nxlink överför",
|
||||||
"Nxlink Finished": "Nxlink klar",
|
"Nxlink Finished": "Nxlink klar",
|
||||||
|
"Hdd": "",
|
||||||
|
"Hdd write protect": "",
|
||||||
|
|
||||||
"Language": "Språk",
|
"Language": "Språk",
|
||||||
"Auto": "Auto",
|
"Auto": "Auto",
|
||||||
@@ -57,22 +60,35 @@
|
|||||||
"No meta entries found...\n": "",
|
"No meta entries found...\n": "",
|
||||||
"Updating application record list": "",
|
"Updating application record list": "",
|
||||||
"Dump": "",
|
"Dump": "",
|
||||||
|
"Dump options": "",
|
||||||
|
"Dump Options": "",
|
||||||
"Select content to dump": "",
|
"Select content to dump": "",
|
||||||
"Dump All": "",
|
"Dump All": "",
|
||||||
"Dump Application": "",
|
"Dump Application": "",
|
||||||
"Dump Patch": "",
|
"Dump Patch": "",
|
||||||
"Dump AddOnContent": "",
|
"Dump AddOnContent": "",
|
||||||
"Dump DataPatch": "",
|
"Dump DataPatch": "",
|
||||||
|
"Created nested folder": "",
|
||||||
|
"Append folder with .xci": "",
|
||||||
|
"Trim XCI": "",
|
||||||
|
"Label trimmed XCI": "",
|
||||||
|
"Multi-threaded USB transfer": "",
|
||||||
|
"Dump All Bins": "",
|
||||||
|
"Dump XCI": "",
|
||||||
|
"Dump Card ID Set": "",
|
||||||
|
"Dump Card UID": "",
|
||||||
|
"Dump Certificate": "",
|
||||||
|
"Dump Initial Data": "",
|
||||||
"Select dump location": "",
|
"Select dump location": "",
|
||||||
"microSD card (/dumps/NSP/)": "",
|
"microSD card (/dumps/)": "",
|
||||||
"USB transfer (Switch 2 Switch)": "",
|
"USB transfer (Switch 2 Switch)": "",
|
||||||
"/dev/null (Speed Test)": "",
|
"/dev/null (Speed Test)": "",
|
||||||
"Dumping": "",
|
"Dumping": "",
|
||||||
"Dump successfull!": "",
|
"Dump successfull!": "",
|
||||||
"Dump failed!": "",
|
"Dump failed!": "",
|
||||||
"Success": "",
|
|
||||||
"Delete successfull!": "",
|
"Delete successfull!": "",
|
||||||
"Delete failed!": "",
|
"Delete failed!": "",
|
||||||
|
"Success": "",
|
||||||
|
|
||||||
"Themezer": "Themezer",
|
"Themezer": "Themezer",
|
||||||
"Themezer Options": "Themezer-alternativ",
|
"Themezer Options": "Themezer-alternativ",
|
||||||
@@ -86,6 +102,8 @@
|
|||||||
"GitHub": "GitHub",
|
"GitHub": "GitHub",
|
||||||
"Downloading json": "Laddar ner JSON",
|
"Downloading json": "Laddar ner JSON",
|
||||||
"Select asset to download for ": "Välj tillgång att ladda ner för ",
|
"Select asset to download for ": "Välj tillgång att ladda ner för ",
|
||||||
|
"Failed to download json": "",
|
||||||
|
"Failed to download app!": "",
|
||||||
|
|
||||||
"FTP Install": "",
|
"FTP Install": "",
|
||||||
"FTP Install (EXPERIMENTAL)": "",
|
"FTP Install (EXPERIMENTAL)": "",
|
||||||
@@ -122,9 +140,12 @@
|
|||||||
"GC": "",
|
"GC": "",
|
||||||
"System memory %.1f GB": "",
|
"System memory %.1f GB": "",
|
||||||
"microSD card %.1f GB": "",
|
"microSD card %.1f GB": "",
|
||||||
"Nand Install": "",
|
|
||||||
"SD Card Install": "",
|
|
||||||
"Exit": "",
|
"Exit": "",
|
||||||
|
"Install disabled...\nPlease enable installing via the install options.": "",
|
||||||
|
"No GameCard inserted": "",
|
||||||
|
"GameCard is already trimmed!": "",
|
||||||
|
"WARNING: GameCard is already trimmed!": "",
|
||||||
|
"Continue": "",
|
||||||
"Gc install success!": "",
|
"Gc install success!": "",
|
||||||
"Gc install failed!": "",
|
"Gc install failed!": "",
|
||||||
|
|
||||||
@@ -160,14 +181,14 @@
|
|||||||
"Negative image": "Negativ bild",
|
"Negative image": "Negativ bild",
|
||||||
"Format": "Format",
|
"Format": "Format",
|
||||||
"Trimming Format": "Trimningsformat",
|
"Trimming Format": "Trimningsformat",
|
||||||
"320x240": "320×240",
|
|
||||||
"160x120": "160×120",
|
|
||||||
"80x60": "80×60",
|
|
||||||
"40x30": "40×30",
|
|
||||||
"20x15": "20×15",
|
|
||||||
"External Light Filter": "Externt ljusfilter",
|
"External Light Filter": "Externt ljusfilter",
|
||||||
"Load Default": "Ladda standard",
|
"Load Default": "Ladda standard",
|
||||||
|
|
||||||
|
"Web": "",
|
||||||
|
"Select URL": "",
|
||||||
|
"Enter custom URL": "",
|
||||||
|
"Enter URL": "",
|
||||||
|
|
||||||
"Advanced": "Avancerat",
|
"Advanced": "Avancerat",
|
||||||
"Advanced Options": "Avancerade alternativ",
|
"Advanced Options": "Avancerade alternativ",
|
||||||
"Logging": "Loggning",
|
"Logging": "Loggning",
|
||||||
@@ -181,10 +202,12 @@
|
|||||||
"Restored hbmenu": "Återställde hbmenu.",
|
"Restored hbmenu": "Återställde hbmenu.",
|
||||||
"Restart Sphaira?": "Starta om Sphaira?",
|
"Restart Sphaira?": "Starta om Sphaira?",
|
||||||
"Press OK to restart Sphaira": "",
|
"Press OK to restart Sphaira": "",
|
||||||
|
"Boost CPU during transfer": "",
|
||||||
"Text scroll speed": "",
|
"Text scroll speed": "",
|
||||||
"Slow": "",
|
"Slow": "",
|
||||||
"Normal": "",
|
"Normal": "",
|
||||||
"Fast": "",
|
"Fast": "",
|
||||||
|
"Set left-side menu": "",
|
||||||
"Set right-side menu": "",
|
"Set right-side menu": "",
|
||||||
"Install options": "",
|
"Install options": "",
|
||||||
"Install Options": "",
|
"Install Options": "",
|
||||||
@@ -194,7 +217,6 @@
|
|||||||
"Install location": "Installationsplats",
|
"Install location": "Installationsplats",
|
||||||
"System memory": "Systemminne",
|
"System memory": "Systemminne",
|
||||||
"microSD card": "microSD-kort",
|
"microSD card": "microSD-kort",
|
||||||
"Boost CPU clock": "",
|
|
||||||
"Allow downgrade": "",
|
"Allow downgrade": "",
|
||||||
"Skip if already installed": "",
|
"Skip if already installed": "",
|
||||||
"Ticket only": "",
|
"Ticket only": "",
|
||||||
@@ -225,6 +247,8 @@
|
|||||||
"Updating ncm databse": "Uppdaterar ncm-databas",
|
"Updating ncm databse": "Uppdaterar ncm-databas",
|
||||||
"Pushing application record": "Skickar programpost",
|
"Pushing application record": "Skickar programpost",
|
||||||
"Failed to install forwarder": "Misslyckades att installera genväg",
|
"Failed to install forwarder": "Misslyckades att installera genväg",
|
||||||
|
"Unstar": "Avmarkera stjärna",
|
||||||
|
"Star": "Markera stjärna",
|
||||||
"Unstarred ": "Avmarkerad ",
|
"Unstarred ": "Avmarkerad ",
|
||||||
"Starred ": "Markerad ",
|
"Starred ": "Markerad ",
|
||||||
"Failed to remove old forwarder, please manually remove it!": "",
|
"Failed to remove old forwarder, please manually remove it!": "",
|
||||||
@@ -257,12 +281,13 @@
|
|||||||
"Copy": "Kopiera",
|
"Copy": "Kopiera",
|
||||||
"Copying ": "Kopierar ",
|
"Copying ": "Kopierar ",
|
||||||
"Paste": "Klistra in",
|
"Paste": "Klistra in",
|
||||||
"Paste ": "Klistra in ",
|
"Paste file(s)?": "",
|
||||||
" file(s)?": " fil(er)?",
|
|
||||||
"Pasting ": "Klistrar in ",
|
"Pasting ": "Klistrar in ",
|
||||||
"Pasting": "Klistrar in",
|
"Pasting": "Klistrar in",
|
||||||
"Rename": "Byt namn",
|
"Rename": "Byt namn",
|
||||||
"Set New File Name": "Ange nytt filnamn",
|
"Set New File Name": "Ange nytt filnamn",
|
||||||
|
"Failed to delete directory": "",
|
||||||
|
"Failed to delete file": "",
|
||||||
"Extract zip": "",
|
"Extract zip": "",
|
||||||
"Extract Options": "",
|
"Extract Options": "",
|
||||||
"Extract here": "",
|
"Extract here": "",
|
||||||
@@ -285,13 +310,17 @@
|
|||||||
"Create Folder": "Skapa mapp",
|
"Create Folder": "Skapa mapp",
|
||||||
"Set Folder Name": "Ange mappnamn",
|
"Set Folder Name": "Ange mappnamn",
|
||||||
"Creating ": "Skapar ",
|
"Creating ": "Skapar ",
|
||||||
|
"View as text (unfinished)": "Visa som text (ofärdig)",
|
||||||
"Upload": "",
|
"Upload": "",
|
||||||
"Select upload location": "",
|
"Select upload location": "",
|
||||||
"No upload locations set!": "",
|
"No upload locations set!": "",
|
||||||
"Uploading": "",
|
"Uploading": "",
|
||||||
"Upload successfull!": "",
|
"Upload successfull!": "",
|
||||||
"Upload failed!": "",
|
"Upload failed!": "",
|
||||||
"View as text (unfinished)": "Visa som text (ofärdig)",
|
"Hash": "",
|
||||||
|
"Hash Options": "",
|
||||||
|
"Hashing": "",
|
||||||
|
"Failed to hash file...": "",
|
||||||
"Ignore read only": "Ignorera skrivskydd",
|
"Ignore read only": "Ignorera skrivskydd",
|
||||||
"Mount": "Montera",
|
"Mount": "Montera",
|
||||||
"Sd": "Sd",
|
"Sd": "Sd",
|
||||||
@@ -302,6 +331,7 @@
|
|||||||
"Launch ": "Starta ",
|
"Launch ": "Starta ",
|
||||||
"Launch option for: ": "Startalternativ för: ",
|
"Launch option for: ": "Startalternativ för: ",
|
||||||
"Select launcher for: ": "Välj startprogram för: ",
|
"Select launcher for: ": "Välj startprogram för: ",
|
||||||
|
"Close FileBrowser?": "",
|
||||||
|
|
||||||
"Sort By": "Sortera efter",
|
"Sort By": "Sortera efter",
|
||||||
"Sort Options": "Sorteringsalternativ",
|
"Sort Options": "Sorteringsalternativ",
|
||||||
@@ -335,16 +365,16 @@
|
|||||||
"Search": "Sök",
|
"Search": "Sök",
|
||||||
|
|
||||||
"Options": "Alternativ",
|
"Options": "Alternativ",
|
||||||
|
"Split": "",
|
||||||
"OK": "OK",
|
"OK": "OK",
|
||||||
"Back": "Tillbaka",
|
"Back": "Tillbaka",
|
||||||
"Select": "Välj",
|
"Select": "Välj",
|
||||||
"Open": "Öppna",
|
"Open": "Öppna",
|
||||||
|
"Close": "",
|
||||||
"Launch": "Starta",
|
"Launch": "Starta",
|
||||||
"Restart": "Starta om",
|
"Restart": "Starta om",
|
||||||
"Next": "",
|
"Next": "",
|
||||||
"Prev": "",
|
"Prev": "",
|
||||||
"Unstar": "Avmarkera stjärna",
|
|
||||||
"Star": "Markera stjärna",
|
|
||||||
"Yes": "Ja",
|
"Yes": "Ja",
|
||||||
"No": "Nej",
|
"No": "Nej",
|
||||||
"On": "",
|
"On": "",
|
||||||
@@ -367,12 +397,13 @@
|
|||||||
"Remove": "Ta bort",
|
"Remove": "Ta bort",
|
||||||
"Completely remove ": "Ta bort helt ",
|
"Completely remove ": "Ta bort helt ",
|
||||||
"Removing ": "Tar bort ",
|
"Removing ": "Tar bort ",
|
||||||
"Removed ": "Borttagen ",
|
|
||||||
"Uninstalling ": "Avinstallerar ",
|
"Uninstalling ": "Avinstallerar ",
|
||||||
|
"Removed ": "Borttagen ",
|
||||||
|
|
||||||
"Download": "Ladda ner",
|
"Download": "Ladda ner",
|
||||||
"Downloading ": "Laddar ner ",
|
"Downloading ": "Laddar ner ",
|
||||||
"Downloaded ": "Nedladdad ",
|
"Downloaded ": "Nedladdad ",
|
||||||
|
"Download via the Network options!": "",
|
||||||
|
|
||||||
"Update": "Uppdatera",
|
"Update": "Uppdatera",
|
||||||
"Update avaliable: ": "Uppdatering tillgänglig: ",
|
"Update avaliable: ": "Uppdatering tillgänglig: ",
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
{
|
{
|
||||||
"[Applet Mode]": "[Режим Аплету]",
|
"[Applet Mode]": "[Аплет]",
|
||||||
"No Internet": "Без інтернету",
|
"No Internet": "Без інтернету",
|
||||||
"Switch-Handheld!": "Switch - Портатив!",
|
"Switch-Handheld!": "Switch - Портатив!",
|
||||||
"Switch-Docked!": "Switch - Докований!",
|
"Switch-Docked!": "Switch - Док!",
|
||||||
|
"Warning! Logs are enabled, Sphaira will run slowly!": "Увага! Логи увімкнені, Sphaira працюватиме повільно!",
|
||||||
"Audio disabled due to suspended game": "Аудіо вимкнено через призупинену програму",
|
"Audio disabled due to suspended game": "Аудіо вимкнено через призупинену програму",
|
||||||
"Are you sure you wish to cancel?": "Ви впевнені, що хочете скасувати?",
|
"Are you sure you wish to cancel?": "Ви впевнені, що хочете скасувати?",
|
||||||
"An error occurred": "",
|
"An error occurred": "Сталася помилка",
|
||||||
"If this message appears repeatedly, please open an issue.": "Якщо це повідомлення з'являється повторно, будь ласка, повідомте про проблему.",
|
"If this message appears repeatedly, please open an issue.": "Якщо це повідомлення з'являється повторно, будь ласка, повідомте про проблему.",
|
||||||
|
|
||||||
"Menu Options": "Опції меню",
|
"Menu Options": "Опції меню",
|
||||||
@@ -16,8 +17,8 @@
|
|||||||
"Music": "Музика",
|
"Music": "Музика",
|
||||||
"12 Hour Time": "12-годинний формат часу",
|
"12 Hour Time": "12-годинний формат часу",
|
||||||
"Download Default Music": "Завантажити музику за замовчуванням",
|
"Download Default Music": "Завантажити музику за замовчуванням",
|
||||||
"Failed to download default_music.bfstm, please try again": "",
|
"Failed to download default_music.bfstm, please try again": "Не вдалося завантажити default_music.bfstm, спробуйте ще раз",
|
||||||
"Overwrite current default music?": "",
|
"Overwrite current default music?": "Перезаписати поточну музику за замовчуванням?",
|
||||||
|
|
||||||
"Network": "Мережа",
|
"Network": "Мережа",
|
||||||
"Network Options": "Опції мережі",
|
"Network Options": "Опції мережі",
|
||||||
@@ -27,6 +28,8 @@
|
|||||||
"Nxlink Connected": "Nxlink підключено",
|
"Nxlink Connected": "Nxlink підключено",
|
||||||
"Nxlink Upload": "Nxlink | Завантаження",
|
"Nxlink Upload": "Nxlink | Завантаження",
|
||||||
"Nxlink Finished": "Nxlink | Завершено",
|
"Nxlink Finished": "Nxlink | Завершено",
|
||||||
|
"Hdd": "HDD",
|
||||||
|
"Hdd write protect": "Захист HDD від запису",
|
||||||
|
|
||||||
"Language": "Мова",
|
"Language": "Мова",
|
||||||
"Auto": "Автоматично",
|
"Auto": "Автоматично",
|
||||||
@@ -53,26 +56,39 @@
|
|||||||
"Launch random game": "Запустити випадкову гру",
|
"Launch random game": "Запустити випадкову гру",
|
||||||
"List meta records": "Список метаданих записів",
|
"List meta records": "Список метаданих записів",
|
||||||
"Entries": "Записи",
|
"Entries": "Записи",
|
||||||
"Failed to list application meta entries": "",
|
"Failed to list application meta entries": "Не вдалося вивести список метаданих програм",
|
||||||
"No meta entries found...\n": "",
|
"No meta entries found...\n": "Не знайдено метаданих...\n",
|
||||||
"Updating application record list": "",
|
"Updating application record list": "Оновлення списку записів програм",
|
||||||
"Dump": "",
|
"Dump": "Дамп",
|
||||||
"Select content to dump": "",
|
"Dump options": "Опції дампу",
|
||||||
"Dump All": "",
|
"Dump Options": "Опції дампу",
|
||||||
"Dump Application": "",
|
"Select content to dump": "Виберіть вміст для дампу",
|
||||||
"Dump Patch": "",
|
"Dump All": "Дамп всього",
|
||||||
"Dump AddOnContent": "",
|
"Dump Application": "Дамп програми",
|
||||||
"Dump DataPatch": "",
|
"Dump Patch": "Дамп патчу",
|
||||||
"Select dump location": "",
|
"Dump AddOnContent": "Дамп DLC",
|
||||||
"microSD card (/dumps/NSP/)": "",
|
"Dump DataPatch": "Дамп патчу даних",
|
||||||
"USB transfer (Switch 2 Switch)": "",
|
"Created nested folder": "Створено вкладену теку",
|
||||||
"/dev/null (Speed Test)": "",
|
"Append folder with .xci": "Додати до теки .xci",
|
||||||
"Dumping": "",
|
"Trim XCI": "Обрізати XCI",
|
||||||
"Dump successfull!": "",
|
"Label trimmed XCI": "Позначити обрізаний XCI",
|
||||||
"Dump failed!": "",
|
"Multi-threaded USB transfer": "Многопоточ. передача USB",
|
||||||
"Success": "",
|
"Dump All Bins": "Дамп всіх BIN-файлів",
|
||||||
"Delete successfull!": "",
|
"Dump XCI": "Дамп XCI",
|
||||||
"Delete failed!": "",
|
"Dump Card ID Set": "Дамп набору ID картриджа",
|
||||||
|
"Dump Card UID": "Дамп UID картриджа",
|
||||||
|
"Dump Certificate": "Дамп сертифіката",
|
||||||
|
"Dump Initial Data": "Дамп початкових даних",
|
||||||
|
"Select dump location": "Виберіть місце для дампу",
|
||||||
|
"microSD card (/dumps/)": "SD-карта (/dumps/)",
|
||||||
|
"USB transfer (Switch 2 Switch)": "Передача USB (Switch <-> Switch)",
|
||||||
|
"/dev/null (Speed Test)": "Тест швидкості (/dev/null)",
|
||||||
|
"Dumping": "Дампінг",
|
||||||
|
"Dump successfull!": "Дамп успішний!",
|
||||||
|
"Dump failed!": "Помилка дампу!",
|
||||||
|
"Delete successfull!": "Видалення успішне!",
|
||||||
|
"Delete failed!": "Помилка видалення!",
|
||||||
|
"Success": "Успіх",
|
||||||
|
|
||||||
"Themezer": "Themezer",
|
"Themezer": "Themezer",
|
||||||
"Themezer Options": "Опції Themezer",
|
"Themezer Options": "Опції Themezer",
|
||||||
@@ -86,6 +102,8 @@
|
|||||||
"GitHub": "GitHub",
|
"GitHub": "GitHub",
|
||||||
"Downloading json": "Завантаження JSON",
|
"Downloading json": "Завантаження JSON",
|
||||||
"Select asset to download for ": "Виберіть ресурс для завантаження для ",
|
"Select asset to download for ": "Виберіть ресурс для завантаження для ",
|
||||||
|
"Failed to download json": "Не вдалося завантажити JSON",
|
||||||
|
"Failed to download app!": "Не вдалося завантажити програму!",
|
||||||
|
|
||||||
"FTP Install": "Встановлення через FTP",
|
"FTP Install": "Встановлення через FTP",
|
||||||
"FTP Install (EXPERIMENTAL)": "Встановлення через FTP (ЕКСПЕРИМЕНТАЛЬНО)",
|
"FTP Install (EXPERIMENTAL)": "Встановлення через FTP (ЕКСПЕРИМЕНТАЛЬНО)",
|
||||||
@@ -103,14 +121,14 @@
|
|||||||
"Ftp install failed!": "Встановлення через FTP не вдалося.",
|
"Ftp install failed!": "Встановлення через FTP не вдалося.",
|
||||||
"USB Install": "Встановлення через USB",
|
"USB Install": "Встановлення через USB",
|
||||||
"USB": "USB",
|
"USB": "USB",
|
||||||
"Connected, waiting for file list...": "",
|
"Connected, waiting for file list...": "Підключено, очікування списку файлів...",
|
||||||
"Connected, starting transfer...": "",
|
"Connected, starting transfer...": "Підключено, початок передачі...",
|
||||||
"Failed to init usb, press B to exit...": "Не вдалося ініціалізувати USB, натисніть B для виходу...",
|
"Failed to init usb, press B to exit...": "Не вдалося ініціалізувати USB, натисніть B для виходу...",
|
||||||
"Waiting for connection...": "Очікування підключення...",
|
"Waiting for connection...": "Очікування підключення...",
|
||||||
"Transferring data...": "Передача даних...",
|
"Transferring data...": "Передача даних...",
|
||||||
"USB connected, sending file list": "",
|
"USB connected, sending file list": "USB підключено, надсилання списку файлів",
|
||||||
"Sent file list, waiting for command...": "",
|
"Sent file list, waiting for command...": "Список файлів надіслано, очікування команди...",
|
||||||
"waiting for usb connection...": "",
|
"waiting for usb connection...": "очікування USB підключення...",
|
||||||
"Disable MTP for usb install": "Вимкнути MTP для встановлення через USB",
|
"Disable MTP for usb install": "Вимкнути MTP для встановлення через USB",
|
||||||
"Re-enabled MTP": "MTP знову увімкнено",
|
"Re-enabled MTP": "MTP знову увімкнено",
|
||||||
"Installed via usb": "Встановлено через USB",
|
"Installed via usb": "Встановлено через USB",
|
||||||
@@ -119,17 +137,20 @@
|
|||||||
"Press B to exit...": "Натисніть B для виходу...",
|
"Press B to exit...": "Натисніть B для виходу...",
|
||||||
"GameCard Install": "Встановлення з картриджа",
|
"GameCard Install": "Встановлення з картриджа",
|
||||||
"GameCard": "Картридж",
|
"GameCard": "Картридж",
|
||||||
"GC": "",
|
"GC": "К",
|
||||||
"System memory %.1f GB": "",
|
"System memory %.1f GB": "Пам'ять консолі %.1f ГБ",
|
||||||
"microSD card %.1f GB": "",
|
"microSD card %.1f GB": "SD-карта %.1f ГБ",
|
||||||
"Nand Install": "",
|
"Exit": "Вихід",
|
||||||
"SD Card Install": "",
|
"Install disabled...\nPlease enable installing via the install options.": "Встановлення вимкнено...\nБудь ласка, увімкніть встановлення в опціях.",
|
||||||
"Exit": "",
|
"No GameCard inserted": "Картридж не вставлено",
|
||||||
|
"GameCard is already trimmed!": "Картридж вже обрізано!",
|
||||||
|
"WARNING: GameCard is already trimmed!": "УВАГА: Картридж вже обрізано!",
|
||||||
|
"Continue": "Продовжити",
|
||||||
"Gc install success!": "Встановлення з картриджа успішно завершено.",
|
"Gc install success!": "Встановлення з картриджа успішно завершено.",
|
||||||
"Gc install failed!": "Встановлення з картриджа не вдалося.",
|
"Gc install failed!": "Встановлення з картриджа не вдалося.",
|
||||||
|
|
||||||
"IRS (Infrared Joycon Camera)": "ІЧ (Інфрачервона камера Joycon)",
|
"IRS (Infrared Joycon Camera)": "ІЧ (Інфрачервона камера Joycon)",
|
||||||
"IRS": "",
|
"IRS": "ІЧ",
|
||||||
"Irs": "ІЧ-сенсор",
|
"Irs": "ІЧ-сенсор",
|
||||||
"Ambient Noise Level: ": "Рівень навколишнього шуму: ",
|
"Ambient Noise Level: ": "Рівень навколишнього шуму: ",
|
||||||
"Controller": "Контролер",
|
"Controller": "Контролер",
|
||||||
@@ -157,17 +178,17 @@
|
|||||||
"Gain": "Підсилення",
|
"Gain": "Підсилення",
|
||||||
"Negative Image": "Негативне зображення",
|
"Negative Image": "Негативне зображення",
|
||||||
"Normal image": "Нормальне зображення",
|
"Normal image": "Нормальне зображення",
|
||||||
"Negative image": "",
|
"Negative image": "Негативне зображення",
|
||||||
"Format": "Формат",
|
"Format": "Формат",
|
||||||
"Trimming Format": "Формат обрізки",
|
"Trimming Format": "Формат обрізки",
|
||||||
"320x240": "320×240",
|
|
||||||
"160x120": "160×120",
|
|
||||||
"80x60": "80×60",
|
|
||||||
"40x30": "40×30",
|
|
||||||
"20x15": "20×15",
|
|
||||||
"External Light Filter": "Фільтр зовнішнього освітлення",
|
"External Light Filter": "Фільтр зовнішнього освітлення",
|
||||||
"Load Default": "Завантажити типові",
|
"Load Default": "Завантажити типові",
|
||||||
|
|
||||||
|
"Web": "Веб",
|
||||||
|
"Select URL": "Вибрати URL",
|
||||||
|
"Enter custom URL": "Ввести власний URL",
|
||||||
|
"Enter URL": "Ввести URL",
|
||||||
|
|
||||||
"Advanced": "Додатково",
|
"Advanced": "Додатково",
|
||||||
"Advanced Options": "Додаткові опції",
|
"Advanced Options": "Додаткові опції",
|
||||||
"Logging": "Логування",
|
"Logging": "Логування",
|
||||||
@@ -181,37 +202,38 @@
|
|||||||
"Restored hbmenu": "hbmenu відновлено",
|
"Restored hbmenu": "hbmenu відновлено",
|
||||||
"Restart Sphaira?": "Перезапустити Sphaira?",
|
"Restart Sphaira?": "Перезапустити Sphaira?",
|
||||||
"Press OK to restart Sphaira": "Натисніть OK для перезапуску Sphaira",
|
"Press OK to restart Sphaira": "Натисніть OK для перезапуску Sphaira",
|
||||||
|
"Boost CPU during transfer": "Розгін при передачі",
|
||||||
"Text scroll speed": "Швидк. прокрутки",
|
"Text scroll speed": "Швидк. прокрутки",
|
||||||
"Slow": "Повільно",
|
"Slow": "Повільно",
|
||||||
"Normal": "Нормально",
|
"Normal": "Середнє",
|
||||||
"Fast": "Швидко",
|
"Fast": "Швидко",
|
||||||
|
"Set left-side menu": "Ліве меню",
|
||||||
"Set right-side menu": "Праве меню",
|
"Set right-side menu": "Праве меню",
|
||||||
"Install options": "Опції встановлення",
|
"Install options": "Опції встановлення",
|
||||||
"Install Options": "Опції встановлення",
|
"Install Options": "Опції встановлення",
|
||||||
"Enable sysmmc": "",
|
"Enable sysmmc": "Дозволити в sysMMC",
|
||||||
"Enable emummc": "",
|
"Enable emummc": "Дозволити в emuMMC",
|
||||||
"Show install warning": "Попередж. при встанов.",
|
"Show install warning": "Попередж. при встанов.",
|
||||||
"Install location": "Місце встановлення",
|
"Install location": "Ставити в",
|
||||||
"System memory": "Пам'ять консолі",
|
"System memory": "NAND",
|
||||||
"microSD card": "SD-карта",
|
"microSD card": "microSD",
|
||||||
"Boost CPU clock": "Розігнати CPU",
|
|
||||||
"Allow downgrade": "Дозволити відкат",
|
"Allow downgrade": "Дозволити відкат",
|
||||||
"Skip if already installed": "Пропуск, якщо встановл.",
|
"Skip if already installed": "Пропуск встановленого",
|
||||||
"Ticket only": "Тільки тікет",
|
"Ticket only": "Тільки тікет",
|
||||||
"Skip base": "Пропустити базу",
|
"Skip base": "Пропустити базу",
|
||||||
"Skip patch": "Пропустити патч",
|
"Skip patch": "Пропустити патч",
|
||||||
"Skip dlc": "Пропустити DLC",
|
"Skip dlc": "Пропустити DLC",
|
||||||
"Skip data patch": "Пропустити патч даних",
|
"Skip data patch": "Пропустити патч даних",
|
||||||
"Skip ticket": "Пропустити тікет",
|
"Skip ticket": "Пропустити тікет",
|
||||||
"Skip NCA hash verify": "",
|
"Skip NCA hash verify": "Не перевір. NCA hash",
|
||||||
"Skip RSA header verify": "Пропуск перевірку заголовка RSA",
|
"Skip RSA header verify": "Не перевір. RSA header",
|
||||||
"Skip RSA NPDM verify": "Пропуск перевірку NPDM RSA",
|
"Skip RSA NPDM verify": "Не перевір. NPDM RSA",
|
||||||
"Ignore distribution bit": "Ігнорувати біт розподілу",
|
"Ignore distribution bit": "Ігнор. біт розподілу",
|
||||||
"Convert to standard crypto": "Конвертувати у стандартне шифрування",
|
"Convert to standard crypto": "Конверт. у стандарт. шифр.",
|
||||||
"Lower master key": "Знизити майстер-ключ",
|
"Lower master key": "Знизити майстер-ключ",
|
||||||
"Lower system version": "Знизити версію системи",
|
"Lower system version": "Знизити версію системи",
|
||||||
|
|
||||||
"Homebrew": "Домашні програми",
|
"Homebrew": "Homebrew",
|
||||||
"Apps": "Програми",
|
"Apps": "Програми",
|
||||||
"Homebrew Options": "Опції домашніх програм",
|
"Homebrew Options": "Опції домашніх програм",
|
||||||
"Hide Sphaira": "Приховати Sphaira",
|
"Hide Sphaira": "Приховати Sphaira",
|
||||||
@@ -225,12 +247,14 @@
|
|||||||
"Updating ncm databse": "Оновлення бази даних NCM",
|
"Updating ncm databse": "Оновлення бази даних NCM",
|
||||||
"Pushing application record": "Запис даних програми",
|
"Pushing application record": "Запис даних програми",
|
||||||
"Failed to install forwarder": "Не вдалося встановити форвардер",
|
"Failed to install forwarder": "Не вдалося встановити форвардер",
|
||||||
|
"Unstar": "Прибрати з обраного",
|
||||||
|
"Star": "Позначити зіркою",
|
||||||
"Unstarred ": "Знято зірку з ",
|
"Unstarred ": "Знято зірку з ",
|
||||||
"Starred ": "Позначено зіркою ",
|
"Starred ": "Позначено зіркою ",
|
||||||
"Failed to remove old forwarder, please manually remove it!": "",
|
"Failed to remove old forwarder, please manually remove it!": "Не вдалося видалити старий форвардер, видаліть його вручну!",
|
||||||
|
|
||||||
"AppStore": "Магазин програм",
|
"AppStore": "AppStore",
|
||||||
"Appstore": "",
|
"Appstore": "AppStore",
|
||||||
"Store": "Магазин",
|
"Store": "Магазин",
|
||||||
"Filter: %s | Sort: %s | Order: %s": "Фільтр: %s | Сорт.: %s | Порядок: %s",
|
"Filter: %s | Sort: %s | Order: %s": "Фільтр: %s | Сорт.: %s | Порядок: %s",
|
||||||
"AppStore Options": "Опції магазину програм",
|
"AppStore Options": "Опції магазину програм",
|
||||||
@@ -257,41 +281,46 @@
|
|||||||
"Copy": "Копіювати",
|
"Copy": "Копіювати",
|
||||||
"Copying ": "Копіювання ",
|
"Copying ": "Копіювання ",
|
||||||
"Paste": "Вставити",
|
"Paste": "Вставити",
|
||||||
"Paste ": "Вставити: ",
|
"Paste file(s)?": "Вставити файл(и)?",
|
||||||
" file(s)?": " файл(и)?",
|
|
||||||
"Pasting ": "Вставлення ",
|
"Pasting ": "Вставлення ",
|
||||||
"Pasting": "Вставлення",
|
"Pasting": "Вставлення",
|
||||||
"Rename": "Перейменувати",
|
"Rename": "Перейменувати",
|
||||||
"Set New File Name": "Введіть нове ім'я файлу",
|
"Set New File Name": "Введіть нове ім'я файлу",
|
||||||
"Extract zip": "",
|
"Failed to delete directory": "Не вдалося видалити теку",
|
||||||
"Extract Options": "",
|
"Failed to delete file": "Не вдалося видалити файл",
|
||||||
"Extract here": "",
|
"Extract zip": "Розпакувати zip",
|
||||||
"Extract to root": "",
|
"Extract Options": "Опції розпакування",
|
||||||
"Are you sure you want to extract to root?": "",
|
"Extract here": "Розпакувати тут",
|
||||||
"Extract to...": "",
|
"Extract to root": "Розпакувати в корінь",
|
||||||
"Enter the path to the folder to extract into": "",
|
"Are you sure you want to extract to root?": "Ви впевнені, що хочете розпакувати в корінь?",
|
||||||
"Extracting ": "",
|
"Extract to...": "Розпакувати в...",
|
||||||
"Extract success!": "",
|
"Enter the path to the folder to extract into": "Введіть шлях до теки для розпакування",
|
||||||
"Extract failed!": "",
|
"Extracting ": "Розпакування ",
|
||||||
|
"Extract success!": "Розпакування успішне!",
|
||||||
|
"Extract failed!": "Помилка розпакування!",
|
||||||
"Compress to zip": "Стиснути в zip",
|
"Compress to zip": "Стиснути в zip",
|
||||||
"Compress Options": "",
|
"Compress Options": "Опції стиснення",
|
||||||
"Compress": "",
|
"Compress": "Стиснути",
|
||||||
"Compress to...": "",
|
"Compress to...": "Стиснути в...",
|
||||||
"Compressing ": "",
|
"Compressing ": "Стиснення ",
|
||||||
"Compress success!": "",
|
"Compress success!": "Стиснення успішне!",
|
||||||
"Compress failed!": "",
|
"Compress failed!": "Помилка стиснення!",
|
||||||
"Create File": "Створити файл",
|
"Create File": "Створити файл",
|
||||||
"Set File Name": "Введіть ім'я файлу",
|
"Set File Name": "Введіть ім'я файлу",
|
||||||
"Create Folder": "Створити теку",
|
"Create Folder": "Створити теку",
|
||||||
"Set Folder Name": "Введіть ім'я теки",
|
"Set Folder Name": "Введіть ім'я теки",
|
||||||
"Creating ": "Створення ",
|
"Creating ": "Створення ",
|
||||||
"Upload": "",
|
|
||||||
"Select upload location": "",
|
|
||||||
"No upload locations set!": "",
|
|
||||||
"Uploading": "",
|
|
||||||
"Upload successfull!": "",
|
|
||||||
"Upload failed!": "",
|
|
||||||
"View as text (unfinished)": "Переглянути як текст (незавершено)",
|
"View as text (unfinished)": "Переглянути як текст (незавершено)",
|
||||||
|
"Upload": "Завантажити (на сервер)",
|
||||||
|
"Select upload location": "Виберіть місце для завантаження",
|
||||||
|
"No upload locations set!": "Не встановлено місць для завантаження!",
|
||||||
|
"Uploading": "Завантаження (на сервер)",
|
||||||
|
"Upload successfull!": "Завантаження успішне!",
|
||||||
|
"Upload failed!": "Помилка завантаження!",
|
||||||
|
"Hash": "Хеш",
|
||||||
|
"Hash Options": "Опції хешування",
|
||||||
|
"Hashing": "Хешування",
|
||||||
|
"Failed to hash file...": "Не вдалося обчислити хеш файлу...",
|
||||||
"Ignore read only": "Ігнорувати лише читання",
|
"Ignore read only": "Ігнорувати лише читання",
|
||||||
"Mount": "Монтувати",
|
"Mount": "Монтувати",
|
||||||
"Sd": "SD-карта",
|
"Sd": "SD-карта",
|
||||||
@@ -302,6 +331,7 @@
|
|||||||
"Launch ": "Запустити ",
|
"Launch ": "Запустити ",
|
||||||
"Launch option for: ": "Опція запуску для: ",
|
"Launch option for: ": "Опція запуску для: ",
|
||||||
"Select launcher for: ": "Виберіть лаунчер для: ",
|
"Select launcher for: ": "Виберіть лаунчер для: ",
|
||||||
|
"Close FileBrowser?": "Закрити файловий менеджер?",
|
||||||
|
|
||||||
"Sort By": "Сортувати за",
|
"Sort By": "Сортувати за",
|
||||||
"Sort Options": "Опції сортування",
|
"Sort Options": "Опції сортування",
|
||||||
@@ -328,23 +358,23 @@
|
|||||||
"Ascending": "За зростанням",
|
"Ascending": "За зростанням",
|
||||||
"Ascending (Up)": "За зростанням (вгору)",
|
"Ascending (Up)": "За зростанням (вгору)",
|
||||||
"Asc": "Зрост.",
|
"Asc": "Зрост.",
|
||||||
"Layout": "",
|
"Layout": "Макет",
|
||||||
"List": "",
|
"List": "Список",
|
||||||
"Icon": "",
|
"Icon": "Іконки",
|
||||||
"Grid": "",
|
"Grid": "Сітка",
|
||||||
"Search": "Пошук",
|
"Search": "Пошук",
|
||||||
|
|
||||||
"Options": "Налаштування",
|
"Options": "Налаштування",
|
||||||
|
"Split": "Розділити",
|
||||||
"OK": "ОК",
|
"OK": "ОК",
|
||||||
"Back": "Назад",
|
"Back": "Назад",
|
||||||
"Select": "Вибрати",
|
"Select": "Вибрати",
|
||||||
"Open": "Відкрити",
|
"Open": "Відкрити",
|
||||||
|
"Close": "Закрити",
|
||||||
"Launch": "Запустити",
|
"Launch": "Запустити",
|
||||||
"Restart": "Перезапустити",
|
"Restart": "Перезапустити",
|
||||||
"Next": "Наступний",
|
"Next": "Наступний",
|
||||||
"Prev": "Попередній",
|
"Prev": "Попередній",
|
||||||
"Unstar": "Прибрати з обраного",
|
|
||||||
"Star": "Позначити зіркою",
|
|
||||||
"Yes": "Так",
|
"Yes": "Так",
|
||||||
"No": "Ні",
|
"No": "Ні",
|
||||||
"On": "Увімк.",
|
"On": "Увімк.",
|
||||||
@@ -367,12 +397,13 @@
|
|||||||
"Remove": "Видалити",
|
"Remove": "Видалити",
|
||||||
"Completely remove ": "Повністю видалити ",
|
"Completely remove ": "Повністю видалити ",
|
||||||
"Removing ": "Видалення ",
|
"Removing ": "Видалення ",
|
||||||
"Removed ": "Видалено ",
|
|
||||||
"Uninstalling ": "Видалення ",
|
"Uninstalling ": "Видалення ",
|
||||||
|
"Removed ": "Видалено ",
|
||||||
|
|
||||||
"Download": "Завантажити",
|
"Download": "Завантажити",
|
||||||
"Downloading ": "Завантаження ",
|
"Downloading ": "Завантаження ",
|
||||||
"Downloaded ": "Завантажено ",
|
"Downloaded ": "Завантажено ",
|
||||||
|
"Download via the Network options!": "Завантажуйте через опції мережі!",
|
||||||
|
|
||||||
"Update": "Оновити",
|
"Update": "Оновити",
|
||||||
"Update avaliable: ": "Доступне оновлення: ",
|
"Update avaliable: ": "Доступне оновлення: ",
|
||||||
@@ -380,9 +411,9 @@
|
|||||||
"Updated to ": "Оновлено до ",
|
"Updated to ": "Оновлено до ",
|
||||||
"Failed to download update": "Не вдалося завантажити оновлення",
|
"Failed to download update": "Не вдалося завантажити оновлення",
|
||||||
|
|
||||||
"%zu hours %zu minutes remaining": "",
|
"%zu hours %zu minutes remaining": "залишилось %zu год %zu хв",
|
||||||
"%zu minutes %zu seconds remaining": "",
|
"%zu minutes %zu seconds remaining": "залишилось %zu хв %zu сек",
|
||||||
"%zu seconds remaining": "",
|
"%zu seconds remaining": "залишилось %zu сек",
|
||||||
|
|
||||||
"Loading...": "Завантаження...",
|
"Loading...": "Завантаження...",
|
||||||
"Loading": "Завантаження",
|
"Loading": "Завантаження",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
"No Internet": "Không có Internet",
|
"No Internet": "Không có Internet",
|
||||||
"Switch-Handheld!": "Switch-Handheld!",
|
"Switch-Handheld!": "Switch-Handheld!",
|
||||||
"Switch-Docked!": "Switch-Docked!",
|
"Switch-Docked!": "Switch-Docked!",
|
||||||
|
"Warning! Logs are enabled, Sphaira will run slowly!": "",
|
||||||
"Audio disabled due to suspended game": "",
|
"Audio disabled due to suspended game": "",
|
||||||
"Are you sure you wish to cancel?": "Bạn có chắn muốn huỷ không?",
|
"Are you sure you wish to cancel?": "Bạn có chắn muốn huỷ không?",
|
||||||
"An error occurred": "",
|
"An error occurred": "",
|
||||||
@@ -27,6 +28,8 @@
|
|||||||
"Nxlink Connected": "Nxlink Kết Nối",
|
"Nxlink Connected": "Nxlink Kết Nối",
|
||||||
"Nxlink Upload": "Nxlink Đăng Tải",
|
"Nxlink Upload": "Nxlink Đăng Tải",
|
||||||
"Nxlink Finished": "Nxlink Hoàn Thành",
|
"Nxlink Finished": "Nxlink Hoàn Thành",
|
||||||
|
"Hdd": "",
|
||||||
|
"Hdd write protect": "",
|
||||||
|
|
||||||
"Language": "Ngôn ngữ",
|
"Language": "Ngôn ngữ",
|
||||||
"Auto": "Tự động",
|
"Auto": "Tự động",
|
||||||
@@ -57,22 +60,35 @@
|
|||||||
"No meta entries found...\n": "",
|
"No meta entries found...\n": "",
|
||||||
"Updating application record list": "",
|
"Updating application record list": "",
|
||||||
"Dump": "",
|
"Dump": "",
|
||||||
|
"Dump options": "",
|
||||||
|
"Dump Options": "",
|
||||||
"Select content to dump": "",
|
"Select content to dump": "",
|
||||||
"Dump All": "",
|
"Dump All": "",
|
||||||
"Dump Application": "",
|
"Dump Application": "",
|
||||||
"Dump Patch": "",
|
"Dump Patch": "",
|
||||||
"Dump AddOnContent": "",
|
"Dump AddOnContent": "",
|
||||||
"Dump DataPatch": "",
|
"Dump DataPatch": "",
|
||||||
|
"Created nested folder": "",
|
||||||
|
"Append folder with .xci": "",
|
||||||
|
"Trim XCI": "",
|
||||||
|
"Label trimmed XCI": "",
|
||||||
|
"Multi-threaded USB transfer": "",
|
||||||
|
"Dump All Bins": "",
|
||||||
|
"Dump XCI": "",
|
||||||
|
"Dump Card ID Set": "",
|
||||||
|
"Dump Card UID": "",
|
||||||
|
"Dump Certificate": "",
|
||||||
|
"Dump Initial Data": "",
|
||||||
"Select dump location": "",
|
"Select dump location": "",
|
||||||
"microSD card (/dumps/NSP/)": "",
|
"microSD card (/dumps/)": "",
|
||||||
"USB transfer (Switch 2 Switch)": "",
|
"USB transfer (Switch 2 Switch)": "",
|
||||||
"/dev/null (Speed Test)": "",
|
"/dev/null (Speed Test)": "",
|
||||||
"Dumping": "",
|
"Dumping": "",
|
||||||
"Dump successfull!": "",
|
"Dump successfull!": "",
|
||||||
"Dump failed!": "",
|
"Dump failed!": "",
|
||||||
"Success": "",
|
|
||||||
"Delete successfull!": "",
|
"Delete successfull!": "",
|
||||||
"Delete failed!": "",
|
"Delete failed!": "",
|
||||||
|
"Success": "",
|
||||||
|
|
||||||
"Themezer": "Themezer",
|
"Themezer": "Themezer",
|
||||||
"Themezer Options": "Tuỳ chọn Themezer",
|
"Themezer Options": "Tuỳ chọn Themezer",
|
||||||
@@ -86,6 +102,8 @@
|
|||||||
"GitHub": "GitHub",
|
"GitHub": "GitHub",
|
||||||
"Downloading json": "Đang tải json",
|
"Downloading json": "Đang tải json",
|
||||||
"Select asset to download for ": "Chọn nội dung để tải xuống cho ",
|
"Select asset to download for ": "Chọn nội dung để tải xuống cho ",
|
||||||
|
"Failed to download json": "",
|
||||||
|
"Failed to download app!": "",
|
||||||
|
|
||||||
"FTP Install": "",
|
"FTP Install": "",
|
||||||
"FTP Install (EXPERIMENTAL)": "",
|
"FTP Install (EXPERIMENTAL)": "",
|
||||||
@@ -122,9 +140,12 @@
|
|||||||
"GC": "",
|
"GC": "",
|
||||||
"System memory %.1f GB": "",
|
"System memory %.1f GB": "",
|
||||||
"microSD card %.1f GB": "",
|
"microSD card %.1f GB": "",
|
||||||
"Nand Install": "",
|
|
||||||
"SD Card Install": "",
|
|
||||||
"Exit": "",
|
"Exit": "",
|
||||||
|
"Install disabled...\nPlease enable installing via the install options.": "",
|
||||||
|
"No GameCard inserted": "",
|
||||||
|
"GameCard is already trimmed!": "",
|
||||||
|
"WARNING: GameCard is already trimmed!": "",
|
||||||
|
"Continue": "",
|
||||||
"Gc install success!": "",
|
"Gc install success!": "",
|
||||||
"Gc install failed!": "",
|
"Gc install failed!": "",
|
||||||
|
|
||||||
@@ -160,14 +181,14 @@
|
|||||||
"Negative image": "Ảnh âm bản",
|
"Negative image": "Ảnh âm bản",
|
||||||
"Format": "Định dạng",
|
"Format": "Định dạng",
|
||||||
"Trimming Format": "Định dạng cắt tỉa",
|
"Trimming Format": "Định dạng cắt tỉa",
|
||||||
"320x240": "320×240",
|
|
||||||
"160x120": "160×120",
|
|
||||||
"80x60": "80×60",
|
|
||||||
"40x30": "40×30",
|
|
||||||
"20x15": "20×15",
|
|
||||||
"External Light Filter": "Bộ lộc ánh sáng bên ngoài",
|
"External Light Filter": "Bộ lộc ánh sáng bên ngoài",
|
||||||
"Load Default": "Tải mặc định",
|
"Load Default": "Tải mặc định",
|
||||||
|
|
||||||
|
"Web": "",
|
||||||
|
"Select URL": "",
|
||||||
|
"Enter custom URL": "",
|
||||||
|
"Enter URL": "",
|
||||||
|
|
||||||
"Advanced": "Mở rộng",
|
"Advanced": "Mở rộng",
|
||||||
"Advanced Options": "Tuỳ chọn mở rộng",
|
"Advanced Options": "Tuỳ chọn mở rộng",
|
||||||
"Logging": "Logging",
|
"Logging": "Logging",
|
||||||
@@ -181,10 +202,12 @@
|
|||||||
"Restored hbmenu": "Đã khôi phục hbmenu",
|
"Restored hbmenu": "Đã khôi phục hbmenu",
|
||||||
"Restart Sphaira?": "Khởi động lại Sphaira?",
|
"Restart Sphaira?": "Khởi động lại Sphaira?",
|
||||||
"Press OK to restart Sphaira": "",
|
"Press OK to restart Sphaira": "",
|
||||||
|
"Boost CPU during transfer": "",
|
||||||
"Text scroll speed": "",
|
"Text scroll speed": "",
|
||||||
"Slow": "",
|
"Slow": "",
|
||||||
"Normal": "",
|
"Normal": "",
|
||||||
"Fast": "",
|
"Fast": "",
|
||||||
|
"Set left-side menu": "",
|
||||||
"Set right-side menu": "",
|
"Set right-side menu": "",
|
||||||
"Install options": "",
|
"Install options": "",
|
||||||
"Install Options": "",
|
"Install Options": "",
|
||||||
@@ -194,7 +217,6 @@
|
|||||||
"Install location": "Vị trí cài đặt",
|
"Install location": "Vị trí cài đặt",
|
||||||
"System memory": "Bộ nhớ máy",
|
"System memory": "Bộ nhớ máy",
|
||||||
"microSD card": "Thẻ nhớ",
|
"microSD card": "Thẻ nhớ",
|
||||||
"Boost CPU clock": "",
|
|
||||||
"Allow downgrade": "",
|
"Allow downgrade": "",
|
||||||
"Skip if already installed": "",
|
"Skip if already installed": "",
|
||||||
"Ticket only": "",
|
"Ticket only": "",
|
||||||
@@ -225,6 +247,8 @@
|
|||||||
"Updating ncm databse": "Cập nhật ncm databse",
|
"Updating ncm databse": "Cập nhật ncm databse",
|
||||||
"Pushing application record": "Đẩy ứng dụng",
|
"Pushing application record": "Đẩy ứng dụng",
|
||||||
"Failed to install forwarder": "Cài đặt ra ngoài màn hình thất bại",
|
"Failed to install forwarder": "Cài đặt ra ngoài màn hình thất bại",
|
||||||
|
"Unstar": "Xoá yêu thích",
|
||||||
|
"Star": "Yêu thích",
|
||||||
"Unstarred ": "Bỏ yêu thích ",
|
"Unstarred ": "Bỏ yêu thích ",
|
||||||
"Starred ": "Đã yêu thích ",
|
"Starred ": "Đã yêu thích ",
|
||||||
"Failed to remove old forwarder, please manually remove it!": "",
|
"Failed to remove old forwarder, please manually remove it!": "",
|
||||||
@@ -257,12 +281,13 @@
|
|||||||
"Copy": "Sao chép",
|
"Copy": "Sao chép",
|
||||||
"Copying ": "Đang sao chép ",
|
"Copying ": "Đang sao chép ",
|
||||||
"Paste": "Dán",
|
"Paste": "Dán",
|
||||||
"Paste ": "Paste ",
|
"Paste file(s)?": "",
|
||||||
" file(s)?": " tập tin(nhiều)?",
|
|
||||||
"Pasting ": "Đang dán ",
|
"Pasting ": "Đang dán ",
|
||||||
"Pasting": "Đang dán",
|
"Pasting": "Đang dán",
|
||||||
"Rename": "Đổi tên",
|
"Rename": "Đổi tên",
|
||||||
"Set New File Name": "Đặt tên mới cho tập tin",
|
"Set New File Name": "Đặt tên mới cho tập tin",
|
||||||
|
"Failed to delete directory": "",
|
||||||
|
"Failed to delete file": "",
|
||||||
"Extract zip": "",
|
"Extract zip": "",
|
||||||
"Extract Options": "",
|
"Extract Options": "",
|
||||||
"Extract here": "",
|
"Extract here": "",
|
||||||
@@ -285,13 +310,17 @@
|
|||||||
"Create Folder": "Tạo thư mục",
|
"Create Folder": "Tạo thư mục",
|
||||||
"Set Folder Name": "Đặt tên thư mục",
|
"Set Folder Name": "Đặt tên thư mục",
|
||||||
"Creating ": "Đang tạo ",
|
"Creating ": "Đang tạo ",
|
||||||
|
"View as text (unfinished)": "Xem dạng văn bản (chưa xong)",
|
||||||
"Upload": "",
|
"Upload": "",
|
||||||
"Select upload location": "",
|
"Select upload location": "",
|
||||||
"No upload locations set!": "",
|
"No upload locations set!": "",
|
||||||
"Uploading": "",
|
"Uploading": "",
|
||||||
"Upload successfull!": "",
|
"Upload successfull!": "",
|
||||||
"Upload failed!": "",
|
"Upload failed!": "",
|
||||||
"View as text (unfinished)": "Xem dạng văn bản (chưa xong)",
|
"Hash": "",
|
||||||
|
"Hash Options": "",
|
||||||
|
"Hashing": "",
|
||||||
|
"Failed to hash file...": "",
|
||||||
"Ignore read only": "Bỏ qua chỉ đọc",
|
"Ignore read only": "Bỏ qua chỉ đọc",
|
||||||
"Mount": "Gắn",
|
"Mount": "Gắn",
|
||||||
"Sd": "Sd",
|
"Sd": "Sd",
|
||||||
@@ -302,6 +331,7 @@
|
|||||||
"Launch ": "Chạy ",
|
"Launch ": "Chạy ",
|
||||||
"Launch option for: ": "Chạy với tuỳ chọn cho: ",
|
"Launch option for: ": "Chạy với tuỳ chọn cho: ",
|
||||||
"Select launcher for: ": "Chọn trình chạy cho: ",
|
"Select launcher for: ": "Chọn trình chạy cho: ",
|
||||||
|
"Close FileBrowser?": "",
|
||||||
|
|
||||||
"Sort By": "Sắp xếp bởi",
|
"Sort By": "Sắp xếp bởi",
|
||||||
"Sort Options": "Tuỳ chọn sắp xếp",
|
"Sort Options": "Tuỳ chọn sắp xếp",
|
||||||
@@ -335,16 +365,16 @@
|
|||||||
"Search": "Tìm kiếm",
|
"Search": "Tìm kiếm",
|
||||||
|
|
||||||
"Options": "Tuỳ chọn",
|
"Options": "Tuỳ chọn",
|
||||||
|
"Split": "",
|
||||||
"OK": "OK",
|
"OK": "OK",
|
||||||
"Back": "Trở về",
|
"Back": "Trở về",
|
||||||
"Select": "Chọn",
|
"Select": "Chọn",
|
||||||
"Open": "Mở",
|
"Open": "Mở",
|
||||||
|
"Close": "",
|
||||||
"Launch": "Chạy",
|
"Launch": "Chạy",
|
||||||
"Restart": "Khởi động lại",
|
"Restart": "Khởi động lại",
|
||||||
"Next": "",
|
"Next": "",
|
||||||
"Prev": "",
|
"Prev": "",
|
||||||
"Unstar": "Xoá yêu thích",
|
|
||||||
"Star": "Yêu thích",
|
|
||||||
"Yes": "Có",
|
"Yes": "Có",
|
||||||
"No": "Không",
|
"No": "Không",
|
||||||
"On": "",
|
"On": "",
|
||||||
@@ -367,12 +397,13 @@
|
|||||||
"Remove": "Gỡ",
|
"Remove": "Gỡ",
|
||||||
"Completely remove ": "Đã gỡ thành công ",
|
"Completely remove ": "Đã gỡ thành công ",
|
||||||
"Removing ": "Đang gỡ ",
|
"Removing ": "Đang gỡ ",
|
||||||
"Removed ": "Đã gỡ ",
|
|
||||||
"Uninstalling ": "Đang gỡ cài đặt ",
|
"Uninstalling ": "Đang gỡ cài đặt ",
|
||||||
|
"Removed ": "Đã gỡ ",
|
||||||
|
|
||||||
"Download": "Tải về",
|
"Download": "Tải về",
|
||||||
"Downloading ": "Đang tải xuống ",
|
"Downloading ": "Đang tải xuống ",
|
||||||
"Downloaded ": "Đã tải xong ",
|
"Downloaded ": "Đã tải xong ",
|
||||||
|
"Download via the Network options!": "",
|
||||||
|
|
||||||
"Update": "Cập nhật",
|
"Update": "Cập nhật",
|
||||||
"Update avaliable: ": "Cập nhậc có sẵn: ",
|
"Update avaliable: ": "Cập nhậc có sẵn: ",
|
||||||
|
|||||||
@@ -3,9 +3,10 @@
|
|||||||
"No Internet": "网络未连接",
|
"No Internet": "网络未连接",
|
||||||
"Switch-Handheld!": "切换至掌机模式!",
|
"Switch-Handheld!": "切换至掌机模式!",
|
||||||
"Switch-Docked!": "切换至底座模式!",
|
"Switch-Docked!": "切换至底座模式!",
|
||||||
|
"Warning! Logs are enabled, Sphaira will run slowly!": "警告!日志已启用,将导致Sphaira运行缓慢!",
|
||||||
"Audio disabled due to suspended game": "由于游戏暂停,音频已禁用",
|
"Audio disabled due to suspended game": "由于游戏暂停,音频已禁用",
|
||||||
"Are you sure you wish to cancel?": "您确定要取消吗?",
|
"Are you sure you wish to cancel?": "您确定要取消吗?",
|
||||||
"An error occurred": "",
|
"An error occurred": "发生错误",
|
||||||
"If this message appears repeatedly, please open an issue.": "若此消息反复出现,请提交问题报告。",
|
"If this message appears repeatedly, please open an issue.": "若此消息反复出现,请提交问题报告。",
|
||||||
|
|
||||||
"Menu Options": "菜单选项",
|
"Menu Options": "菜单选项",
|
||||||
@@ -16,8 +17,8 @@
|
|||||||
"Music": "音乐",
|
"Music": "音乐",
|
||||||
"12 Hour Time": "12小时制时间",
|
"12 Hour Time": "12小时制时间",
|
||||||
"Download Default Music": "下载默认音乐",
|
"Download Default Music": "下载默认音乐",
|
||||||
"Failed to download default_music.bfstm, please try again": "",
|
"Failed to download default_music.bfstm, please try again": "下载default_music.bfstm失败,请重试",
|
||||||
"Overwrite current default music?": "",
|
"Overwrite current default music?": "覆盖当前默认音乐?",
|
||||||
|
|
||||||
"Network": "网络",
|
"Network": "网络",
|
||||||
"Network Options": "网络选项",
|
"Network Options": "网络选项",
|
||||||
@@ -27,6 +28,8 @@
|
|||||||
"Nxlink Connected": "Nxlink 已连接",
|
"Nxlink Connected": "Nxlink 已连接",
|
||||||
"Nxlink Upload": "Nxlink 上传中",
|
"Nxlink Upload": "Nxlink 上传中",
|
||||||
"Nxlink Finished": "Nxlink 已结束",
|
"Nxlink Finished": "Nxlink 已结束",
|
||||||
|
"Hdd": "HDD",
|
||||||
|
"Hdd write protect": "HDD写保护",
|
||||||
|
|
||||||
"Language": "语言",
|
"Language": "语言",
|
||||||
"Auto": "自动",
|
"Auto": "自动",
|
||||||
@@ -53,26 +56,26 @@
|
|||||||
"Launch random game": "开启随机游戏",
|
"Launch random game": "开启随机游戏",
|
||||||
"List meta records": "列出元数据记录",
|
"List meta records": "列出元数据记录",
|
||||||
"Entries": "条目",
|
"Entries": "条目",
|
||||||
"Failed to list application meta entries": "",
|
"Failed to list application meta entries": "未能列出应用程序元条目",
|
||||||
"No meta entries found...\n": "",
|
"No meta entries found...\n": "未找到元条目...\n",
|
||||||
"Updating application record list": "",
|
"Updating application record list": "更新应用程序记录列表",
|
||||||
"Dump": "",
|
"Dump": "转储",
|
||||||
"Select content to dump": "",
|
"Select content to dump": "选择要转储的内容",
|
||||||
"Dump All": "",
|
"Dump All": "转储全部内容",
|
||||||
"Dump Application": "",
|
"Dump Application": "转储应用程序(本体)",
|
||||||
"Dump Patch": "",
|
"Dump Patch": "转储补丁(DLC)",
|
||||||
"Dump AddOnContent": "",
|
"Dump AddOnContent": "转储追加内容(UPD)",
|
||||||
"Dump DataPatch": "",
|
"Dump DataPatch": "转储游戏数据",
|
||||||
"Select dump location": "",
|
"Select dump location": "选择转储位置",
|
||||||
"microSD card (/dumps/NSP/)": "",
|
"microSD card (/dumps/NSP/)": "microSD卡(/dumps/NSP/)",
|
||||||
"USB transfer (Switch 2 Switch)": "",
|
"USB transfer (Switch 2 Switch)": "USB传输(Switch 2 Switch)",
|
||||||
"/dev/null (Speed Test)": "",
|
"/dev/null (Speed Test)": "/dev/null(速度测试)",
|
||||||
"Dumping": "",
|
"Dumping": "正在转储",
|
||||||
"Dump successfull!": "",
|
"Dump successfull!": "转储成功!",
|
||||||
"Dump failed!": "",
|
"Dump failed!": "转储失败!",
|
||||||
"Success": "",
|
"Success": "成功",
|
||||||
"Delete successfull!": "",
|
"Delete successfull!": "删除成功!",
|
||||||
"Delete failed!": "",
|
"Delete failed!": "删除失败!",
|
||||||
|
|
||||||
"Themezer": "在线主题",
|
"Themezer": "在线主题",
|
||||||
"Themezer Options": "在线主题选项",
|
"Themezer Options": "在线主题选项",
|
||||||
@@ -86,10 +89,12 @@
|
|||||||
"GitHub": "GitHub",
|
"GitHub": "GitHub",
|
||||||
"Downloading json": "正在下载 json",
|
"Downloading json": "正在下载 json",
|
||||||
"Select asset to download for ": "选择要下载的资源用于 ",
|
"Select asset to download for ": "选择要下载的资源用于 ",
|
||||||
|
"Failed to download json": "下载json失败",
|
||||||
|
"Failed to download app!": "下载应用程序失败!",
|
||||||
|
|
||||||
"FTP Install": "通过 FTP 安装",
|
"FTP Install": "通过 FTP 安装",
|
||||||
"FTP Install (EXPERIMENTAL)": "通过 FTP 安装(实验性)",
|
"FTP Install (EXPERIMENTAL)": "通过 FTP 安装(实验性)",
|
||||||
"Connection Type: WiFi | Strength: ": "",
|
"Connection Type: WiFi | Strength: ": "连接类型:WiFi |强度:",
|
||||||
"Connection Type: Ethernet": "连接类型:以太网",
|
"Connection Type: Ethernet": "连接类型:以太网",
|
||||||
"Connection Type: None": "连接类型:无",
|
"Connection Type: None": "连接类型:无",
|
||||||
"Host:": "主机:",
|
"Host:": "主机:",
|
||||||
@@ -103,14 +108,14 @@
|
|||||||
"Ftp install failed!": "通过 FTP 安装失败。",
|
"Ftp install failed!": "通过 FTP 安装失败。",
|
||||||
"USB Install": "通过 USB 安装",
|
"USB Install": "通过 USB 安装",
|
||||||
"USB": "USB",
|
"USB": "USB",
|
||||||
"Connected, waiting for file list...": "",
|
"Connected, waiting for file list...": "已连接,正在等待文件列表...",
|
||||||
"Connected, starting transfer...": "",
|
"Connected, starting transfer...": "已连接,开始传输...",
|
||||||
"Failed to init usb, press B to exit...": "USB 初始化失败,按 B 键退出...",
|
"Failed to init usb, press B to exit...": "USB 初始化失败,按 B 键退出...",
|
||||||
"Waiting for connection...": "等待连接中...",
|
"Waiting for connection...": "等待连接中...",
|
||||||
"Transferring data...": "正在传输数据...",
|
"Transferring data...": "正在传输数据...",
|
||||||
"USB connected, sending file list": "",
|
"USB connected, sending file list": "USB已连接,正在发送文件列表",
|
||||||
"Sent file list, waiting for command...": "",
|
"Sent file list, waiting for command...": "已发送文件列表,正在等待命令...",
|
||||||
"waiting for usb connection...": "",
|
"waiting for usb connection...": "等待USB连接...",
|
||||||
"Disable MTP for usb install": "暂时禁用 USB 安装的 MTP 功能",
|
"Disable MTP for usb install": "暂时禁用 USB 安装的 MTP 功能",
|
||||||
"Re-enabled MTP": "重新启用 MTP",
|
"Re-enabled MTP": "重新启用 MTP",
|
||||||
"Installed via usb": "通过 USB 安装",
|
"Installed via usb": "通过 USB 安装",
|
||||||
@@ -119,17 +124,20 @@
|
|||||||
"Press B to exit...": "按 B 键退出...",
|
"Press B to exit...": "按 B 键退出...",
|
||||||
"GameCard Install": "卡带安装",
|
"GameCard Install": "卡带安装",
|
||||||
"GameCard": "卡带",
|
"GameCard": "卡带",
|
||||||
"GC": "",
|
"GC": "GC",
|
||||||
"System memory %.1f GB": "",
|
"System memory %.1f GB": "系统内存 %.1f GB",
|
||||||
"microSD card %.1f GB": "",
|
"microSD card %.1f GB": "SD卡内存 %.1f GB",
|
||||||
"Nand Install": "",
|
"Exit": "退出",
|
||||||
"SD Card Install": "",
|
"Install disabled...\nPlease enable installing via the install options.": "安装已禁用...\n请通过安装选项启用安装。",
|
||||||
"Exit": "",
|
"No GameCard inserted": "未插入游戏卡",
|
||||||
|
"GameCard is already trimmed!": "游戏卡已被修剪!",
|
||||||
|
"WARNING: GameCard is already trimmed!": "警告:游戏卡已被修剪!",
|
||||||
|
"Continue": "继续",
|
||||||
"Gc install success!": "游戏安装成功。",
|
"Gc install success!": "游戏安装成功。",
|
||||||
"Gc install failed!": "游戏安装失败。",
|
"Gc install failed!": "游戏安装失败。",
|
||||||
|
|
||||||
"IRS (Infrared Joycon Camera)": "",
|
"IRS (Infrared Joycon Camera)": "IRS(Joycon红外摄像头)",
|
||||||
"IRS": "",
|
"IRS": "IRS",
|
||||||
"Irs": "红外成像",
|
"Irs": "红外成像",
|
||||||
"Ambient Noise Level: ": "环境噪声等级:",
|
"Ambient Noise Level: ": "环境噪声等级:",
|
||||||
"Controller": "控制器",
|
"Controller": "控制器",
|
||||||
@@ -159,7 +167,7 @@
|
|||||||
"Normal image": "正常图像",
|
"Normal image": "正常图像",
|
||||||
"Negative image": "负片图像",
|
"Negative image": "负片图像",
|
||||||
"Format": "格式",
|
"Format": "格式",
|
||||||
"Trimming Format": "裁剪格式",
|
"Trimming Format": "修剪格式",
|
||||||
"320x240": "320×240",
|
"320x240": "320×240",
|
||||||
"160x120": "160×120",
|
"160x120": "160×120",
|
||||||
"80x60": "80×60",
|
"80x60": "80×60",
|
||||||
@@ -168,6 +176,11 @@
|
|||||||
"External Light Filter": "外部光滤镜",
|
"External Light Filter": "外部光滤镜",
|
||||||
"Load Default": "加载默认值",
|
"Load Default": "加载默认值",
|
||||||
|
|
||||||
|
"Web": "网络",
|
||||||
|
"Select URL": "选择链接",
|
||||||
|
"Enter custom URL": "输入自定义链接",
|
||||||
|
"Enter URL": "输入网址",
|
||||||
|
|
||||||
"Advanced": "高级",
|
"Advanced": "高级",
|
||||||
"Advanced Options": "高级选项",
|
"Advanced Options": "高级选项",
|
||||||
"Logging": "日志",
|
"Logging": "日志",
|
||||||
@@ -181,15 +194,17 @@
|
|||||||
"Restored hbmenu": "已恢复 hbmenu",
|
"Restored hbmenu": "已恢复 hbmenu",
|
||||||
"Restart Sphaira?": "重启 Sphaira?",
|
"Restart Sphaira?": "重启 Sphaira?",
|
||||||
"Press OK to restart Sphaira": "按OK键以重启shphaira菜单",
|
"Press OK to restart Sphaira": "按OK键以重启shphaira菜单",
|
||||||
|
"Boost CPU during transfer": "在传输过程中提升CPU",
|
||||||
"Text scroll speed": "文本滚动速度",
|
"Text scroll speed": "文本滚动速度",
|
||||||
"Slow": "慢",
|
"Slow": "慢",
|
||||||
"Normal": "正常",
|
"Normal": "正常",
|
||||||
"Fast": "快",
|
"Fast": "快",
|
||||||
"Set right-side menu": "",
|
"Set left-side menu": "设置左侧菜单",
|
||||||
|
"Set right-side menu": "设置右侧菜单",
|
||||||
"Install options": "安装选项",
|
"Install options": "安装选项",
|
||||||
"Install Options": "安装选项",
|
"Install Options": "安装选项",
|
||||||
"Enable sysmmc": "",
|
"Enable sysmmc": "启用sysmmc",
|
||||||
"Enable emummc": "",
|
"Enable emummc": "启用emummc",
|
||||||
"Show install warning": "显示安装警告",
|
"Show install warning": "显示安装警告",
|
||||||
"Install location": "安装位置",
|
"Install location": "安装位置",
|
||||||
"System memory": "主机内存",
|
"System memory": "主机内存",
|
||||||
@@ -203,13 +218,20 @@
|
|||||||
"Skip dlc": "跳过 DLC(可下载内容)",
|
"Skip dlc": "跳过 DLC(可下载内容)",
|
||||||
"Skip data patch": "跳过数据补丁",
|
"Skip data patch": "跳过数据补丁",
|
||||||
"Skip ticket": "跳过票据",
|
"Skip ticket": "跳过票据",
|
||||||
"Skip NCA hash verify": "",
|
"Skip NCA hash verify": "跳过NCA哈希验证",
|
||||||
"Skip RSA header verify": "跳过 RSA 头部验证",
|
"Skip RSA header verify": "跳过 RSA 头部验证",
|
||||||
"Skip RSA NPDM verify": "跳过 RSA NPDM 验证",
|
"Skip RSA NPDM verify": "跳过 RSA NPDM 验证",
|
||||||
"Ignore distribution bit": "忽略分布位",
|
"Ignore distribution bit": "忽略分布位",
|
||||||
"Convert to standard crypto": "转换为标准加密方式",
|
"Convert to standard crypto": "转换为标准加密方式",
|
||||||
"Lower master key": "降低主密钥",
|
"Lower master key": "降低主密钥",
|
||||||
"Lower system version": "降低系统版本",
|
"Lower system version": "降低系统版本",
|
||||||
|
"Dump options": "转储选项",
|
||||||
|
"Dump Options": "转储选项",
|
||||||
|
"Created nested folder": "已创建嵌套文件夹",
|
||||||
|
"Append folder with .xci": "用.xci附加文件夹",
|
||||||
|
"Trim XCI": "修剪 XCI",
|
||||||
|
"Label trimmed XCI": "标记已修剪的XCI",
|
||||||
|
"Multi-threaded USB transfer": "多线程USB传输",
|
||||||
|
|
||||||
"Homebrew": "应用列表",
|
"Homebrew": "应用列表",
|
||||||
"Apps": "应用",
|
"Apps": "应用",
|
||||||
@@ -225,12 +247,14 @@
|
|||||||
"Updating ncm databse": "正在更新ncm数据库",
|
"Updating ncm databse": "正在更新ncm数据库",
|
||||||
"Pushing application record": "正在推送应用记录",
|
"Pushing application record": "正在推送应用记录",
|
||||||
"Failed to install forwarder": "前端应用安装失败",
|
"Failed to install forwarder": "前端应用安装失败",
|
||||||
|
"Unstar": "取消星标",
|
||||||
|
"Star": "星标",
|
||||||
"Unstarred ": "取消星标 ",
|
"Unstarred ": "取消星标 ",
|
||||||
"Starred ": "已星标 ",
|
"Starred ": "已星标 ",
|
||||||
"Failed to remove old forwarder, please manually remove it!": "",
|
"Failed to remove old forwarder, please manually remove it!": "删除旧前端应用失败,请手动删除!",
|
||||||
|
|
||||||
"AppStore": "应用商店",
|
"AppStore": "应用商店",
|
||||||
"Appstore": "",
|
"Appstore": "应用商店",
|
||||||
"Store": "商店",
|
"Store": "商店",
|
||||||
"Filter: %s | Sort: %s | Order: %s": "筛选: %s | 排序: %s | 顺序: %s",
|
"Filter: %s | Sort: %s | Order: %s": "筛选: %s | 排序: %s | 顺序: %s",
|
||||||
"AppStore Options": "应用商店选项",
|
"AppStore Options": "应用商店选项",
|
||||||
@@ -257,41 +281,46 @@
|
|||||||
"Copy": "复制",
|
"Copy": "复制",
|
||||||
"Copying ": "正在复制 ",
|
"Copying ": "正在复制 ",
|
||||||
"Paste": "粘贴",
|
"Paste": "粘贴",
|
||||||
"Paste ": "粘贴 ",
|
"Paste file(s)?": "粘贴 个文件(夹)?",
|
||||||
" file(s)?": "个文件(夹)?",
|
|
||||||
"Pasting ": "正在粘贴 ",
|
"Pasting ": "正在粘贴 ",
|
||||||
"Pasting": "正在粘贴",
|
"Pasting": "正在粘贴",
|
||||||
"Rename": "重命名",
|
"Rename": "重命名",
|
||||||
"Set New File Name": "输入新命名",
|
"Set New File Name": "输入新命名",
|
||||||
"Extract zip": "",
|
"Failed to delete directory": "删除目录失败",
|
||||||
"Extract Options": "",
|
"Failed to delete file": "删除文件失败",
|
||||||
"Extract here": "",
|
"Extract zip": "解压 zip",
|
||||||
"Extract to root": "",
|
"Extract Options": "解压选项",
|
||||||
"Are you sure you want to extract to root?": "",
|
"Extract here": "解压到这里",
|
||||||
"Extract to...": "",
|
"Extract to root": "解压到根目录",
|
||||||
"Enter the path to the folder to extract into": "",
|
"Are you sure you want to extract to root?": "您确定要解压到根目录吗?",
|
||||||
"Extracting ": "",
|
"Extract to...": "解压到...",
|
||||||
"Extract success!": "",
|
"Enter the path to the folder to extract into": "输入要解压到的文件夹的路径",
|
||||||
"Extract failed!": "",
|
"Extracting ": "正在解压",
|
||||||
|
"Extract success!": "解压成功!",
|
||||||
|
"Extract failed!": "解压失败!",
|
||||||
"Compress to zip": "压缩到zip",
|
"Compress to zip": "压缩到zip",
|
||||||
"Compress Options": "",
|
"Compress Options": "压缩选项",
|
||||||
"Compress": "",
|
"Compress": "压缩",
|
||||||
"Compress to...": "",
|
"Compress to...": "压缩到...",
|
||||||
"Compressing ": "",
|
"Compressing ": "正在压缩 ",
|
||||||
"Compress success!": "",
|
"Compress success!": "压缩成功!",
|
||||||
"Compress failed!": "",
|
"Compress failed!": "压缩失败",
|
||||||
"Create File": "新建文件",
|
"Create File": "新建文件",
|
||||||
"Set File Name": "输入文件名",
|
"Set File Name": "输入文件名",
|
||||||
"Create Folder": "新建文件夹",
|
"Create Folder": "新建文件夹",
|
||||||
"Set Folder Name": "输入文件夹名",
|
"Set Folder Name": "输入文件夹名",
|
||||||
"Creating ": "正在创建 ",
|
"Creating ": "正在创建 ",
|
||||||
"Upload": "",
|
|
||||||
"Select upload location": "",
|
|
||||||
"No upload locations set!": "",
|
|
||||||
"Uploading": "",
|
|
||||||
"Upload successfull!": "",
|
|
||||||
"Upload failed!": "",
|
|
||||||
"View as text (unfinished)": "以文本形式查看(未完善)",
|
"View as text (unfinished)": "以文本形式查看(未完善)",
|
||||||
|
"Upload": "上传",
|
||||||
|
"Select upload location": "选择上传位置",
|
||||||
|
"No upload locations set!": "未设置上传位置",
|
||||||
|
"Uploading": "正在上传",
|
||||||
|
"Upload successfull!": "上传成功!",
|
||||||
|
"Upload failed!": "上传失败!",
|
||||||
|
"Hash": "哈希",
|
||||||
|
"Hash Options": "哈希选项",
|
||||||
|
"Hashing": "正在哈希文件",
|
||||||
|
"Failed to hash file...": "哈希文件失败...",
|
||||||
"Ignore read only": "忽略只读",
|
"Ignore read only": "忽略只读",
|
||||||
"Mount": "挂载",
|
"Mount": "挂载",
|
||||||
"Sd": "SD卡",
|
"Sd": "SD卡",
|
||||||
@@ -302,6 +331,7 @@
|
|||||||
"Launch ": "启动 ",
|
"Launch ": "启动 ",
|
||||||
"Launch option for: ": "启动选项:",
|
"Launch option for: ": "启动选项:",
|
||||||
"Select launcher for: ": "选择启动器用于:",
|
"Select launcher for: ": "选择启动器用于:",
|
||||||
|
"Close FileBrowser?": "是否关闭文件浏览器?",
|
||||||
|
|
||||||
"Sort By": "排序方式",
|
"Sort By": "排序方式",
|
||||||
"Sort Options": "排序选项",
|
"Sort Options": "排序选项",
|
||||||
@@ -328,32 +358,32 @@
|
|||||||
"Ascending": "升序",
|
"Ascending": "升序",
|
||||||
"Ascending (Up)": "升序",
|
"Ascending (Up)": "升序",
|
||||||
"Asc": "升序",
|
"Asc": "升序",
|
||||||
"Layout": "",
|
"Layout": "布局",
|
||||||
"List": "",
|
"List": "列表",
|
||||||
"Icon": "",
|
"Icon": "图标",
|
||||||
"Grid": "",
|
"Grid": "网格",
|
||||||
"Search": "搜索",
|
"Search": "搜索",
|
||||||
|
|
||||||
"Options": "选项",
|
"Options": "选项",
|
||||||
|
"Split": "拆分",
|
||||||
"OK": "确定",
|
"OK": "确定",
|
||||||
"Back": "返回",
|
"Back": "返回",
|
||||||
"Select": "选择",
|
"Select": "选择",
|
||||||
"Open": "打开",
|
"Open": "打开",
|
||||||
|
"Close": "关闭",
|
||||||
"Launch": "启动",
|
"Launch": "启动",
|
||||||
"Restart": "重启",
|
"Restart": "重启",
|
||||||
"Next": "下一项",
|
"Next": "下一项",
|
||||||
"Prev": "上一项",
|
"Prev": "上一项",
|
||||||
"Unstar": "取消星标",
|
|
||||||
"Star": "星标",
|
|
||||||
"Yes": "是",
|
"Yes": "是",
|
||||||
"No": "否",
|
"No": "否",
|
||||||
"On": "",
|
"On": "开",
|
||||||
"Off": "",
|
"Off": "关",
|
||||||
|
|
||||||
"Install": "安装",
|
"Install": "安装",
|
||||||
"Install Selected files?": "安装所选文件?",
|
"Install Selected files?": "安装所选文件?",
|
||||||
"Installing ": "正在安装 ",
|
"Installing ": "正在安装 ",
|
||||||
"Installed ": "",
|
"Installed ": "已安装",
|
||||||
"Installed!": "安装完成!",
|
"Installed!": "安装完成!",
|
||||||
"Trying to load ": "尝试加载 ",
|
"Trying to load ": "尝试加载 ",
|
||||||
"Checking MD5": "正在校验 MD5",
|
"Checking MD5": "正在校验 MD5",
|
||||||
@@ -367,12 +397,13 @@
|
|||||||
"Remove": "删除",
|
"Remove": "删除",
|
||||||
"Completely remove ": "彻底删除 ",
|
"Completely remove ": "彻底删除 ",
|
||||||
"Removing ": "正在移除 ",
|
"Removing ": "正在移除 ",
|
||||||
"Removed ": "已移除 ",
|
|
||||||
"Uninstalling ": "正在卸载 ",
|
"Uninstalling ": "正在卸载 ",
|
||||||
|
"Removed ": "已移除 ",
|
||||||
|
|
||||||
"Download": "下载",
|
"Download": "下载",
|
||||||
"Downloading ": "正在下载 ",
|
"Downloading ": "正在下载 ",
|
||||||
"Downloaded ": "已下载 ",
|
"Downloaded ": "已下载 ",
|
||||||
|
"Download via the Network options!": "通过网络选项下载!",
|
||||||
|
|
||||||
"Update": "更新",
|
"Update": "更新",
|
||||||
"Update avaliable: ": "有可用更新!",
|
"Update avaliable: ": "有可用更新!",
|
||||||
@@ -380,9 +411,9 @@
|
|||||||
"Updated to ": "更新至 ",
|
"Updated to ": "更新至 ",
|
||||||
"Failed to download update": "更新下载失败",
|
"Failed to download update": "更新下载失败",
|
||||||
|
|
||||||
"%zu hours %zu minutes remaining": "",
|
"%zu hours %zu minutes remaining": "剩余 %zu 小时 %zu 分钟",
|
||||||
"%zu minutes %zu seconds remaining": "",
|
"%zu minutes %zu seconds remaining": "剩余 %zu 分钟 %zu 秒",
|
||||||
"%zu seconds remaining": "",
|
"%zu seconds remaining": "剩余 %zu 秒",
|
||||||
|
|
||||||
"Loading...": "加载中...",
|
"Loading...": "加载中...",
|
||||||
"Loading": "加载中",
|
"Loading": "加载中",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ background = 0x2d2d2d
|
|||||||
grid = 0x46464630
|
grid = 0x46464630
|
||||||
popup = 0x2d2d2d
|
popup = 0x2d2d2d
|
||||||
error = 0xfa5a3a
|
error = 0xfa5a3a
|
||||||
|
focus = 0x000000b4
|
||||||
|
|
||||||
line = 0xfbfbfb
|
line = 0xfbfbfb
|
||||||
line_separator = 0x707070
|
line_separator = 0x707070
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ background = 0xebebeb
|
|||||||
grid = 0xf0f0f0
|
grid = 0xf0f0f0
|
||||||
popup = 0xebebeb
|
popup = 0xebebeb
|
||||||
error = 0xfa5a3a
|
error = 0xfa5a3a
|
||||||
|
focus = 0xd3d3d3a0
|
||||||
|
|
||||||
line = 0x373737
|
line = 0x373737
|
||||||
line_separator = 0x6d787a
|
line_separator = 0x6d787a
|
||||||
|
|||||||
30
assets/romfs/themes/default_theme.ini
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
[meta]
|
||||||
|
name=Default
|
||||||
|
author=ninstar
|
||||||
|
version=1.0.0
|
||||||
|
inherit=romfs:/themes/base_black_theme.ini
|
||||||
|
|
||||||
|
[theme]
|
||||||
|
background = 0x111f28
|
||||||
|
grid = 0x122430
|
||||||
|
popup = 0x143144
|
||||||
|
error = 0xfa3a5d
|
||||||
|
|
||||||
|
line = 0x335e77
|
||||||
|
line_separator = 0x163951
|
||||||
|
|
||||||
|
text = 0xfbfbfb
|
||||||
|
text_info = 0xbed0d6
|
||||||
|
text_selected = 0x32ffcf
|
||||||
|
selected_background = 0x143144
|
||||||
|
|
||||||
|
sidebar = 0x071013ef
|
||||||
|
|
||||||
|
scrollbar = 0x32ffcf
|
||||||
|
scrollbar_background = ; hide the background
|
||||||
|
|
||||||
|
progressbar = 0x32ffcf
|
||||||
|
progressbar_background = 0x0B1519
|
||||||
|
|
||||||
|
highlight_1 = 0x69ff8f
|
||||||
|
highlight_2 = 0x5cbeff
|
||||||
|
Before Width: | Height: | Size: 257 KiB |
|
Before Width: | Height: | Size: 169 KiB |
|
Before Width: | Height: | Size: 153 KiB |
|
Before Width: | Height: | Size: 161 KiB |
|
Before Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 278 KiB |
|
Before Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 116 KiB |
BIN
assets/screenshots/appstore.jpg
Normal file
|
After Width: | Height: | Size: 161 KiB |
BIN
assets/screenshots/appstore_page.jpg
Normal file
|
After Width: | Height: | Size: 235 KiB |
BIN
assets/screenshots/file_browser.jpg
Normal file
|
After Width: | Height: | Size: 131 KiB |
BIN
assets/screenshots/games.jpg
Normal file
|
After Width: | Height: | Size: 202 KiB |
BIN
assets/screenshots/homebrew.jpg
Normal file
|
After Width: | Height: | Size: 166 KiB |
BIN
assets/screenshots/launch_options.jpg
Normal file
|
After Width: | Height: | Size: 122 KiB |
BIN
assets/screenshots/themezer.jpg
Normal file
|
After Width: | Height: | Size: 246 KiB |
BIN
assets/screenshots/web.jpg
Normal file
|
After Width: | Height: | Size: 100 KiB |
@@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
set(sphaira_VERSION 0.11.3)
|
set(sphaira_VERSION 0.12.0)
|
||||||
|
|
||||||
project(sphaira
|
project(sphaira
|
||||||
VERSION ${sphaira_VERSION}
|
VERSION ${sphaira_VERSION}
|
||||||
@@ -40,6 +40,7 @@ add_executable(sphaira
|
|||||||
source/ui/menus/irs_menu.cpp
|
source/ui/menus/irs_menu.cpp
|
||||||
source/ui/menus/main_menu.cpp
|
source/ui/menus/main_menu.cpp
|
||||||
source/ui/menus/menu_base.cpp
|
source/ui/menus/menu_base.cpp
|
||||||
|
source/ui/menus/save_menu.cpp
|
||||||
source/ui/menus/themezer.cpp
|
source/ui/menus/themezer.cpp
|
||||||
source/ui/menus/ghdl.cpp
|
source/ui/menus/ghdl.cpp
|
||||||
source/ui/menus/usb_menu.cpp
|
source/ui/menus/usb_menu.cpp
|
||||||
@@ -79,6 +80,7 @@ add_executable(sphaira
|
|||||||
source/i18n.cpp
|
source/i18n.cpp
|
||||||
source/ftpsrv_helper.cpp
|
source/ftpsrv_helper.cpp
|
||||||
source/threaded_file_transfer.cpp
|
source/threaded_file_transfer.cpp
|
||||||
|
source/minizip_helper.cpp
|
||||||
|
|
||||||
source/usb/base.cpp
|
source/usb/base.cpp
|
||||||
source/usb/usbds.cpp
|
source/usb/usbds.cpp
|
||||||
@@ -178,7 +180,7 @@ FetchContent_Declare(stb
|
|||||||
|
|
||||||
FetchContent_Declare(yyjson
|
FetchContent_Declare(yyjson
|
||||||
GIT_REPOSITORY https://github.com/ibireme/yyjson.git
|
GIT_REPOSITORY https://github.com/ibireme/yyjson.git
|
||||||
GIT_TAG 0.10.0
|
GIT_TAG 0.11.1
|
||||||
)
|
)
|
||||||
|
|
||||||
FetchContent_Declare(minIni
|
FetchContent_Declare(minIni
|
||||||
@@ -197,7 +199,19 @@ FetchContent_Declare(libusbhsfs
|
|||||||
GIT_TAG db2bf2a
|
GIT_TAG db2bf2a
|
||||||
)
|
)
|
||||||
|
|
||||||
|
FetchContent_Declare(libnxtc
|
||||||
|
GIT_REPOSITORY https://github.com/ITotalJustice/libnxtc.git
|
||||||
|
GIT_TAG 0d369b8
|
||||||
|
)
|
||||||
|
|
||||||
|
FetchContent_Declare(nvjpg
|
||||||
|
GIT_REPOSITORY https://github.com/averne/oss-nvjpg.git
|
||||||
|
GIT_TAG fdcaba8
|
||||||
|
)
|
||||||
|
|
||||||
set(USE_NEW_ZSTD ON)
|
set(USE_NEW_ZSTD ON)
|
||||||
|
# has issues with some homebrew and game icons (oxenfree, overwatch2).
|
||||||
|
set(USE_NVJPG ON)
|
||||||
|
|
||||||
set(ZSTD_BUILD_STATIC ON)
|
set(ZSTD_BUILD_STATIC ON)
|
||||||
set(ZSTD_BUILD_SHARED OFF)
|
set(ZSTD_BUILD_SHARED OFF)
|
||||||
@@ -249,6 +263,8 @@ FetchContent_MakeAvailable(
|
|||||||
yyjson
|
yyjson
|
||||||
zstd
|
zstd
|
||||||
libusbhsfs
|
libusbhsfs
|
||||||
|
libnxtc
|
||||||
|
nvjpg
|
||||||
)
|
)
|
||||||
|
|
||||||
set(FTPSRV_LIB_BUILD TRUE)
|
set(FTPSRV_LIB_BUILD TRUE)
|
||||||
@@ -259,7 +275,7 @@ set(FTPSRV_LIB_SESSIONS 16)
|
|||||||
set(FTPSRV_LIB_BUF_SIZE 1024*64)
|
set(FTPSRV_LIB_BUF_SIZE 1024*64)
|
||||||
|
|
||||||
set(FTPSRV_LIB_CUSTOM_DEFINES
|
set(FTPSRV_LIB_CUSTOM_DEFINES
|
||||||
USE_VFS_SAVE=$<BOOL:TRUE>
|
USE_VFS_SAVE=$<BOOL:FALSE>
|
||||||
USE_VFS_STORAGE=$<BOOL:TRUE>
|
USE_VFS_STORAGE=$<BOOL:TRUE>
|
||||||
# disabled as it may conflict with the gamecard menu.
|
# disabled as it may conflict with the gamecard menu.
|
||||||
USE_VFS_GC=$<BOOL:FALSE>
|
USE_VFS_GC=$<BOOL:FALSE>
|
||||||
@@ -278,7 +294,6 @@ add_library(ftpsrv_helper
|
|||||||
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_none.c
|
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_none.c
|
||||||
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_root.c
|
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_root.c
|
||||||
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_fs.c
|
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_fs.c
|
||||||
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_save.c
|
|
||||||
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_storage.c
|
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_storage.c
|
||||||
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_stdio.c
|
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_stdio.c
|
||||||
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_hdd.c
|
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_hdd.c
|
||||||
@@ -291,6 +306,23 @@ target_include_directories(ftpsrv_helper PUBLIC ${ftpsrv_SOURCE_DIR}/src/platfor
|
|||||||
add_library(stb INTERFACE)
|
add_library(stb INTERFACE)
|
||||||
target_include_directories(stb INTERFACE ${stb_SOURCE_DIR})
|
target_include_directories(stb INTERFACE ${stb_SOURCE_DIR})
|
||||||
|
|
||||||
|
add_library(libnxtc
|
||||||
|
${libnxtc_SOURCE_DIR}/source/nxtc.c
|
||||||
|
${libnxtc_SOURCE_DIR}/source/nxtc_log.c
|
||||||
|
${libnxtc_SOURCE_DIR}/source/nxtc_utils.c
|
||||||
|
)
|
||||||
|
target_include_directories(libnxtc PUBLIC ${libnxtc_SOURCE_DIR}/include)
|
||||||
|
|
||||||
|
if (USE_NVJPG)
|
||||||
|
add_library(nvjpg
|
||||||
|
${nvjpg_SOURCE_DIR}/lib/decoder.cpp
|
||||||
|
${nvjpg_SOURCE_DIR}/lib/image.cpp
|
||||||
|
${nvjpg_SOURCE_DIR}/lib/surface.cpp
|
||||||
|
)
|
||||||
|
target_include_directories(nvjpg PUBLIC ${nvjpg_SOURCE_DIR}/include)
|
||||||
|
set_target_properties(nvjpg PROPERTIES CXX_STANDARD 26)
|
||||||
|
endif()
|
||||||
|
|
||||||
find_package(ZLIB REQUIRED)
|
find_package(ZLIB REQUIRED)
|
||||||
find_library(minizip_lib minizip REQUIRED)
|
find_library(minizip_lib minizip REQUIRED)
|
||||||
find_path(minizip_inc minizip REQUIRED)
|
find_path(minizip_inc minizip REQUIRED)
|
||||||
@@ -320,6 +352,7 @@ target_link_libraries(sphaira PRIVATE
|
|||||||
stb
|
stb
|
||||||
yyjson
|
yyjson
|
||||||
# libusbhsfs
|
# libusbhsfs
|
||||||
|
libnxtc
|
||||||
|
|
||||||
${minizip_lib}
|
${minizip_lib}
|
||||||
ZLIB::ZLIB
|
ZLIB::ZLIB
|
||||||
@@ -336,6 +369,11 @@ else()
|
|||||||
target_include_directories(sphaira PRIVATE ${zstd_inc})
|
target_include_directories(sphaira PRIVATE ${zstd_inc})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (USE_NVJPG)
|
||||||
|
target_link_libraries(sphaira PRIVATE nvjpg)
|
||||||
|
target_compile_definitions(sphaira PRIVATE USE_NVJPG)
|
||||||
|
endif()
|
||||||
|
|
||||||
target_include_directories(sphaira PRIVATE
|
target_include_directories(sphaira PRIVATE
|
||||||
include
|
include
|
||||||
${minizip_inc}
|
${minizip_inc}
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
#include "fs.hpp"
|
#include "fs.hpp"
|
||||||
#include "log.hpp"
|
#include "log.hpp"
|
||||||
|
|
||||||
|
#ifdef USE_NVJPG
|
||||||
|
#include <nvjpg.hpp>
|
||||||
|
#endif
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -193,7 +196,7 @@ public:
|
|||||||
static constexpr inline auto CONFIG_PATH = "/config/sphaira/config.ini";
|
static constexpr inline auto CONFIG_PATH = "/config/sphaira/config.ini";
|
||||||
static constexpr inline auto PLAYLOG_PATH = "/config/sphaira/playlog.ini";
|
static constexpr inline auto PLAYLOG_PATH = "/config/sphaira/playlog.ini";
|
||||||
static constexpr inline auto INI_SECTION = "config";
|
static constexpr inline auto INI_SECTION = "config";
|
||||||
static constexpr inline auto DEFAULT_THEME_PATH = "romfs:/themes/abyss_theme.ini";
|
static constexpr inline auto DEFAULT_THEME_PATH = "romfs:/themes/default_theme.ini";
|
||||||
|
|
||||||
fs::FsPath m_app_path;
|
fs::FsPath m_app_path;
|
||||||
u64 m_start_timestamp{};
|
u64 m_start_timestamp{};
|
||||||
@@ -272,6 +275,10 @@ public:
|
|||||||
|
|
||||||
PLSR_PlayerSoundId m_sound_ids[SoundEffect_MAX]{};
|
PLSR_PlayerSoundId m_sound_ids[SoundEffect_MAX]{};
|
||||||
|
|
||||||
|
#ifdef USE_NVJPG
|
||||||
|
nj::Decoder m_decoder;
|
||||||
|
#endif
|
||||||
|
|
||||||
private: // from nanovg decko3d example by adubbz
|
private: // from nanovg decko3d example by adubbz
|
||||||
static constexpr unsigned NumFramebuffers = 2;
|
static constexpr unsigned NumFramebuffers = 2;
|
||||||
static constexpr unsigned StaticCmdSize = 0x1000;
|
static constexpr unsigned StaticCmdSize = 0x1000;
|
||||||
|
|||||||
@@ -527,27 +527,37 @@ struct FsNativeSd final : FsNative {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct FsNativeBis final : FsNative {
|
struct FsNativeBis final : FsNative {
|
||||||
FsNativeBis(FsBisPartitionId id, const FsPath& string, bool ignore_read_only = true) : FsNative{ignore_read_only} {
|
FsNativeBis(FsBisPartitionId id, const FsPath& string) {
|
||||||
m_open_result = fsOpenBisFileSystem(&m_fs, id, string);
|
m_open_result = fsOpenBisFileSystem(&m_fs, id, string);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FsNativeImage final : FsNative {
|
struct FsNativeImage final : FsNative {
|
||||||
FsNativeImage(FsImageDirectoryId id, bool ignore_read_only = true) : FsNative{ignore_read_only} {
|
FsNativeImage(FsImageDirectoryId id) {
|
||||||
m_open_result = fsOpenImageDirectoryFileSystem(&m_fs, id);
|
m_open_result = fsOpenImageDirectoryFileSystem(&m_fs, id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FsNativeContentStorage final : FsNative {
|
struct FsNativeContentStorage final : FsNative {
|
||||||
FsNativeContentStorage(FsContentStorageId id, bool ignore_read_only = true) : FsNative{ignore_read_only} {
|
FsNativeContentStorage(FsContentStorageId id) {
|
||||||
m_open_result = fsOpenContentStorageFileSystem(&m_fs, id);
|
m_open_result = fsOpenContentStorageFileSystem(&m_fs, id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FsNativeGameCard final : FsNative {
|
struct FsNativeGameCard final : FsNative {
|
||||||
FsNativeGameCard(const FsGameCardHandle* handle, FsGameCardPartition partition, bool ignore_read_only = true) : FsNative{ignore_read_only} {
|
FsNativeGameCard(const FsGameCardHandle* handle, FsGameCardPartition partition) {
|
||||||
m_open_result = fsOpenGameCardFileSystem(&m_fs, handle, partition);
|
m_open_result = fsOpenGameCardFileSystem(&m_fs, handle, partition);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FsNativeSave final : FsNative {
|
||||||
|
FsNativeSave(FsSaveDataSpaceId save_data_space_id, const FsSaveDataAttribute *attr, bool read_only) {
|
||||||
|
if (read_only) {
|
||||||
|
m_open_result = fsOpenReadOnlySaveDataFileSystem(&m_fs, save_data_space_id, attr);
|
||||||
|
} else {
|
||||||
|
m_open_result = fsOpenSaveDataFileSystem(&m_fs, save_data_space_id, attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace fs
|
} // namespace fs
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "ui/progress_box.hpp"
|
#include "ui/progress_box.hpp"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
|
|
||||||
namespace sphaira::hash {
|
namespace sphaira::hash {
|
||||||
@@ -26,5 +27,6 @@ auto GetTypeStr(Type type) -> const char*;
|
|||||||
// returns the hash string.
|
// returns the hash string.
|
||||||
Result Hash(ui::ProgressBox* pbox, Type type, std::shared_ptr<BaseSource> source, std::string& out);
|
Result Hash(ui::ProgressBox* pbox, Type type, std::shared_ptr<BaseSource> source, std::string& out);
|
||||||
Result Hash(ui::ProgressBox* pbox, Type type, fs::Fs* fs, const fs::FsPath& path, std::string& out);
|
Result Hash(ui::ProgressBox* pbox, Type type, fs::Fs* fs, const fs::FsPath& path, std::string& out);
|
||||||
|
Result Hash(ui::ProgressBox* pbox, Type type, std::span<const u8> data, std::string& out);
|
||||||
|
|
||||||
} // namespace sphaira::hash
|
} // namespace sphaira::hash
|
||||||
|
|||||||
@@ -12,8 +12,14 @@ struct ImageResult {
|
|||||||
int w, h;
|
int w, h;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto ImageLoadFromMemory(std::span<const u8> data) -> ImageResult;
|
enum ImageFlag {
|
||||||
auto ImageLoadFromFile(const fs::FsPath& file) -> ImageResult;
|
ImageFlag_None = 0,
|
||||||
|
// set this if the image is a jpeg, will use oss-nvjpg to load.
|
||||||
|
ImageFlag_JPEG = 1 << 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
auto ImageLoadFromMemory(std::span<const u8> data, u32 flags = ImageFlag_None) -> ImageResult;
|
||||||
|
auto ImageLoadFromFile(const fs::FsPath& file, u32 flags = ImageFlag_None) -> ImageResult;
|
||||||
auto ImageResize(std::span<const u8> data, int inx, int iny, int outx, int outy) -> ImageResult;
|
auto ImageResize(std::span<const u8> data, int inx, int iny, int outx, int outy) -> ImageResult;
|
||||||
auto ImageConvertToJpg(std::span<const u8> data, int x, int y) -> ImageResult;
|
auto ImageConvertToJpg(std::span<const u8> data, int x, int y) -> ImageResult;
|
||||||
|
|
||||||
|
|||||||
24
sphaira/include/minizip_helper.hpp
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <minizip/ioapi.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <span>
|
||||||
|
#include <switch.h>
|
||||||
|
|
||||||
|
namespace sphaira::mz {
|
||||||
|
|
||||||
|
struct MzMem {
|
||||||
|
std::vector<u8> buf;
|
||||||
|
size_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MzSpan {
|
||||||
|
std::span<const u8> buf;
|
||||||
|
size_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
void FileFuncMem(MzMem* mem, zlib_filefunc64_def* funcs);
|
||||||
|
void FileFuncSpan(MzSpan* span, zlib_filefunc64_def* funcs);
|
||||||
|
void FileFuncStdio(zlib_filefunc64_def* funcs);
|
||||||
|
|
||||||
|
} // namespace sphaira::mz
|
||||||
@@ -6,6 +6,15 @@
|
|||||||
|
|
||||||
namespace sphaira::thread {
|
namespace sphaira::thread {
|
||||||
|
|
||||||
|
enum class Mode {
|
||||||
|
// default, always multi-thread.
|
||||||
|
MultiThreaded,
|
||||||
|
// always single-thread.
|
||||||
|
SingleThreaded,
|
||||||
|
// check buffer size, if smaller, single thread.
|
||||||
|
SingleThreadedIfSmaller,
|
||||||
|
};
|
||||||
|
|
||||||
using ReadCallback = std::function<Result(void* data, s64 off, s64 size, u64* bytes_read)>;
|
using ReadCallback = std::function<Result(void* data, s64 off, s64 size, u64* bytes_read)>;
|
||||||
using WriteCallback = std::function<Result(const void* data, s64 off, s64 size)>;
|
using WriteCallback = std::function<Result(const void* data, s64 off, s64 size)>;
|
||||||
|
|
||||||
@@ -23,10 +32,25 @@ using StartCallback = std::function<Result(PullCallback pull)>;
|
|||||||
using StartCallback2 = std::function<Result(StartThreadCallback start, PullCallback pull)>;
|
using StartCallback2 = std::function<Result(StartThreadCallback start, PullCallback pull)>;
|
||||||
|
|
||||||
// reads data from rfunc into wfunc.
|
// reads data from rfunc into wfunc.
|
||||||
Result Transfer(ui::ProgressBox* pbox, s64 size, ReadCallback rfunc, WriteCallback wfunc);
|
Result Transfer(ui::ProgressBox* pbox, s64 size, ReadCallback rfunc, WriteCallback wfunc, Mode mode = Mode::MultiThreaded);
|
||||||
|
|
||||||
// reads data from rfunc, pull data from provided pull() callback.
|
// reads data from rfunc, pull data from provided pull() callback.
|
||||||
Result TransferPull(ui::ProgressBox* pbox, s64 size, ReadCallback rfunc, StartCallback sfunc);
|
Result TransferPull(ui::ProgressBox* pbox, s64 size, ReadCallback rfunc, StartCallback sfunc, Mode mode = Mode::MultiThreaded);
|
||||||
Result TransferPull(ui::ProgressBox* pbox, s64 size, ReadCallback rfunc, StartCallback2 sfunc);
|
Result TransferPull(ui::ProgressBox* pbox, s64 size, ReadCallback rfunc, StartCallback2 sfunc, Mode mode = Mode::MultiThreaded);
|
||||||
|
|
||||||
|
// helper for extract zips.
|
||||||
|
// this will multi-thread unzip if size >= 512KiB, otherwise it'll single pass.
|
||||||
|
Result TransferUnzip(ui::ProgressBox* pbox, void* zfile, fs::Fs* fs, const fs::FsPath& path, s64 size, u32 crc32 = 0);
|
||||||
|
|
||||||
|
// same as above but for zipping files.
|
||||||
|
Result TransferZip(ui::ProgressBox* pbox, void* zfile, fs::Fs* fs, const fs::FsPath& path, u32* crc32 = nullptr);
|
||||||
|
|
||||||
|
// passes the name inside the zip an final output path.
|
||||||
|
using UnzipAllFilter = std::function<bool(const fs::FsPath& name, fs::FsPath& path)>;
|
||||||
|
|
||||||
|
// helper all-in-one unzip function that unzips a zip (either open or path provided).
|
||||||
|
// the filter function can be used to modify the path and filter out unwanted files.
|
||||||
|
Result TransferUnzipAll(ui::ProgressBox* pbox, void* zfile, fs::Fs* fs, const fs::FsPath& base_path, UnzipAllFilter filter = nullptr);
|
||||||
|
Result TransferUnzipAll(ui::ProgressBox* pbox, const fs::FsPath& zip_out, fs::Fs* fs, const fs::FsPath& base_path, UnzipAllFilter filter = nullptr);
|
||||||
|
|
||||||
} // namespace sphaira::thread
|
} // namespace sphaira::thread
|
||||||
|
|||||||
@@ -108,8 +108,11 @@ private:
|
|||||||
std::shared_ptr<ScrollableText> m_details{};
|
std::shared_ptr<ScrollableText> m_details{};
|
||||||
std::shared_ptr<ScrollableText> m_changelog{};
|
std::shared_ptr<ScrollableText> m_changelog{};
|
||||||
std::shared_ptr<ScrollableText> m_detail_changelog{};
|
std::shared_ptr<ScrollableText> m_detail_changelog{};
|
||||||
|
std::unique_ptr<ScrollableText> m_manifest_list{};
|
||||||
|
|
||||||
bool m_show_changlog{};
|
bool m_show_changlog{};
|
||||||
|
bool m_show_file_list{};
|
||||||
|
ImageDownloadState m_file_list_state{};
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Filter {
|
enum Filter {
|
||||||
|
|||||||
@@ -181,6 +181,9 @@ struct FsView final : Widget {
|
|||||||
|
|
||||||
void SetSide(ViewSide side);
|
void SetSide(ViewSide side);
|
||||||
|
|
||||||
|
static auto get_collection(fs::Fs* fs, const fs::FsPath& path, const fs::FsPath& parent_name, FsDirCollection& out, bool inc_file, bool inc_dir, bool inc_size) -> Result;
|
||||||
|
static auto get_collections(fs::Fs* fs, const fs::FsPath& path, const fs::FsPath& parent_name, FsDirCollections& out, bool inc_size = false) -> Result;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetIndex(s64 index);
|
void SetIndex(s64 index);
|
||||||
void InstallForwarder();
|
void InstallForwarder();
|
||||||
@@ -249,9 +252,6 @@ private:
|
|||||||
void OnRenameCallback();
|
void OnRenameCallback();
|
||||||
auto CheckIfUpdateFolder() -> Result;
|
auto CheckIfUpdateFolder() -> Result;
|
||||||
|
|
||||||
static auto get_collection(fs::Fs* fs, const fs::FsPath& path, const fs::FsPath& parent_name, FsDirCollection& out, bool inc_file, bool inc_dir, bool inc_size) -> Result;
|
|
||||||
static auto get_collections(fs::Fs* fs, const fs::FsPath& path, const fs::FsPath& parent_name, FsDirCollections& out, bool inc_size = false) -> Result;
|
|
||||||
|
|
||||||
auto get_collection(const fs::FsPath& path, const fs::FsPath& parent_name, FsDirCollection& out, bool inc_file, bool inc_dir, bool inc_size) -> Result;
|
auto get_collection(const fs::FsPath& path, const fs::FsPath& parent_name, FsDirCollection& out, bool inc_file, bool inc_dir, bool inc_size) -> Result;
|
||||||
auto get_collections(const fs::FsPath& path, const fs::FsPath& parent_name, FsDirCollections& out, bool inc_size = false) -> Result;
|
auto get_collections(const fs::FsPath& path, const fs::FsPath& parent_name, FsDirCollections& out, bool inc_size = false) -> Result;
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "option.hpp"
|
#include "option.hpp"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
namespace sphaira::ui::menu::game {
|
namespace sphaira::ui::menu::game {
|
||||||
|
|
||||||
@@ -22,13 +23,12 @@ enum class NacpLoadStatus {
|
|||||||
|
|
||||||
struct Entry {
|
struct Entry {
|
||||||
u64 app_id{};
|
u64 app_id{};
|
||||||
char display_version[0x10]{};
|
|
||||||
NacpLanguageEntry lang{};
|
NacpLanguageEntry lang{};
|
||||||
int image{};
|
int image{};
|
||||||
bool selected{};
|
bool selected{};
|
||||||
|
|
||||||
std::shared_ptr<NsApplicationControlData> control{};
|
std::shared_ptr<NsApplicationControlData> control{};
|
||||||
u64 control_size{};
|
u64 jpeg_size{};
|
||||||
NacpLoadStatus status{NacpLoadStatus::None};
|
NacpLoadStatus status{NacpLoadStatus::None};
|
||||||
|
|
||||||
auto GetName() const -> const char* {
|
auto GetName() const -> const char* {
|
||||||
@@ -38,35 +38,38 @@ struct Entry {
|
|||||||
auto GetAuthor() const -> const char* {
|
auto GetAuthor() const -> const char* {
|
||||||
return lang.author;
|
return lang.author;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto GetDisplayVersion() const -> const char* {
|
|
||||||
return display_version;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ThreadResultData {
|
struct ThreadResultData {
|
||||||
u64 id{};
|
u64 id{};
|
||||||
std::shared_ptr<NsApplicationControlData> control{};
|
std::shared_ptr<NsApplicationControlData> control{};
|
||||||
u64 control_size{};
|
u64 jpeg_size{};
|
||||||
char display_version[0x10]{};
|
|
||||||
NacpLanguageEntry lang{};
|
NacpLanguageEntry lang{};
|
||||||
NacpLoadStatus status{NacpLoadStatus::None};
|
NacpLoadStatus status{NacpLoadStatus::None};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ThreadData {
|
struct ThreadData {
|
||||||
ThreadData();
|
ThreadData(bool title_cache);
|
||||||
|
|
||||||
auto IsRunning() const -> bool;
|
|
||||||
void Run();
|
void Run();
|
||||||
void Close();
|
void Close();
|
||||||
void Push(u64 id);
|
void Push(u64 id);
|
||||||
void Push(std::span<const Entry> entries);
|
void Push(std::span<const Entry> entries);
|
||||||
void Pop(std::vector<ThreadResultData>& out);
|
void Pop(std::vector<ThreadResultData>& out);
|
||||||
|
|
||||||
|
auto IsRunning() const -> bool {
|
||||||
|
return m_running;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto IsTitleCacheEnabled() const {
|
||||||
|
return m_title_cache;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UEvent m_uevent{};
|
UEvent m_uevent{};
|
||||||
Mutex m_mutex_id{};
|
Mutex m_mutex_id{};
|
||||||
Mutex m_mutex_result{};
|
Mutex m_mutex_result{};
|
||||||
|
bool m_title_cache{};
|
||||||
|
|
||||||
// app_ids pushed to the queue, signal uevent when pushed.
|
// app_ids pushed to the queue, signal uevent when pushed.
|
||||||
std::vector<u64> m_ids{};
|
std::vector<u64> m_ids{};
|
||||||
@@ -141,13 +144,14 @@ private:
|
|||||||
bool m_is_reversed{};
|
bool m_is_reversed{};
|
||||||
bool m_dirty{};
|
bool m_dirty{};
|
||||||
|
|
||||||
ThreadData m_thread_data{};
|
std::unique_ptr<ThreadData> m_thread_data{};
|
||||||
Thread m_thread{};
|
Thread m_thread{};
|
||||||
|
|
||||||
option::OptionLong m_sort{INI_SECTION, "sort", SortType::SortType_Updated};
|
option::OptionLong m_sort{INI_SECTION, "sort", SortType::SortType_Updated};
|
||||||
option::OptionLong m_order{INI_SECTION, "order", OrderType::OrderType_Descending};
|
option::OptionLong m_order{INI_SECTION, "order", OrderType::OrderType_Descending};
|
||||||
option::OptionLong m_layout{INI_SECTION, "layout", LayoutType::LayoutType_GridDetail};
|
option::OptionLong m_layout{INI_SECTION, "layout", LayoutType::LayoutType_Grid};
|
||||||
option::OptionBool m_hide_forwarders{INI_SECTION, "hide_forwarders", false};
|
option::OptionBool m_hide_forwarders{INI_SECTION, "hide_forwarders", false};
|
||||||
|
option::OptionBool m_title_cache{INI_SECTION, "title_cache", true};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sphaira::ui::menu::game
|
} // namespace sphaira::ui::menu::game
|
||||||
|
|||||||
156
sphaira/include/ui/menus/save_menu.hpp
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ui/menus/grid_menu_base.hpp"
|
||||||
|
#include "ui/list.hpp"
|
||||||
|
#include "fs.hpp"
|
||||||
|
#include "option.hpp"
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
|
namespace sphaira::ui::menu::save {
|
||||||
|
|
||||||
|
enum class NacpLoadStatus {
|
||||||
|
// not yet attempted to be loaded.
|
||||||
|
None,
|
||||||
|
// started loading.
|
||||||
|
Progress,
|
||||||
|
// loaded, ready to parse.
|
||||||
|
Loaded,
|
||||||
|
// failed to load, do not attempt to load again!
|
||||||
|
Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Entry final : FsSaveDataInfo {
|
||||||
|
NacpLanguageEntry lang{};
|
||||||
|
int image{};
|
||||||
|
bool selected{};
|
||||||
|
|
||||||
|
std::shared_ptr<NsApplicationControlData> control{};
|
||||||
|
u64 jpeg_size{};
|
||||||
|
NacpLoadStatus status{NacpLoadStatus::None};
|
||||||
|
|
||||||
|
auto GetName() const -> const char* {
|
||||||
|
return lang.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GetAuthor() const -> const char* {
|
||||||
|
return lang.author;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AccountEntry {
|
||||||
|
AccountUid uid;
|
||||||
|
AccountProfile profile;
|
||||||
|
AccountProfileBase base;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ThreadResultData {
|
||||||
|
u64 id{};
|
||||||
|
std::shared_ptr<NsApplicationControlData> control{};
|
||||||
|
u64 jpeg_size{};
|
||||||
|
NacpLanguageEntry lang{};
|
||||||
|
NacpLoadStatus status{NacpLoadStatus::None};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ThreadData {
|
||||||
|
ThreadData();
|
||||||
|
|
||||||
|
auto IsRunning() const -> bool;
|
||||||
|
void Run();
|
||||||
|
void Close();
|
||||||
|
void Push(u64 id);
|
||||||
|
void Push(std::span<const Entry> entries);
|
||||||
|
void Pop(std::vector<ThreadResultData>& out);
|
||||||
|
|
||||||
|
private:
|
||||||
|
UEvent m_uevent{};
|
||||||
|
Mutex m_mutex_id{};
|
||||||
|
Mutex m_mutex_result{};
|
||||||
|
|
||||||
|
// app_ids pushed to the queue, signal uevent when pushed.
|
||||||
|
std::vector<u64> m_ids{};
|
||||||
|
// control data pushed to the queue.
|
||||||
|
std::vector<ThreadResultData> m_result{};
|
||||||
|
|
||||||
|
std::atomic_bool m_running{};
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SortType {
|
||||||
|
SortType_Updated,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum OrderType {
|
||||||
|
OrderType_Descending,
|
||||||
|
OrderType_Ascending,
|
||||||
|
};
|
||||||
|
|
||||||
|
using LayoutType = grid::LayoutType;
|
||||||
|
|
||||||
|
struct Menu final : grid::Menu {
|
||||||
|
Menu(u32 flags);
|
||||||
|
~Menu();
|
||||||
|
|
||||||
|
auto GetShortTitle() const -> const char* override { return "Saves"; };
|
||||||
|
void Update(Controller* controller, TouchInfo* touch) override;
|
||||||
|
void Draw(NVGcontext* vg, Theme* theme) override;
|
||||||
|
void OnFocusGained() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SetIndex(s64 index);
|
||||||
|
void ScanHomebrew();
|
||||||
|
void Sort();
|
||||||
|
void SortAndFindLastFile(bool scan);
|
||||||
|
void FreeEntries();
|
||||||
|
void OnLayoutChange();
|
||||||
|
|
||||||
|
auto GetSelectedEntries() const {
|
||||||
|
std::vector<Entry> out;
|
||||||
|
for (auto& e : m_entries) {
|
||||||
|
if (e.selected) {
|
||||||
|
out.emplace_back(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_entries.empty() && out.empty()) {
|
||||||
|
out.emplace_back(m_entries[m_index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearSelection() {
|
||||||
|
for (auto& e : m_entries) {
|
||||||
|
e.selected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_selected_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackupSaves(std::vector<std::reference_wrapper<Entry>>& entries);
|
||||||
|
void RestoreSave();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr inline const char* INI_SECTION = "saves";
|
||||||
|
|
||||||
|
std::vector<Entry> m_entries{};
|
||||||
|
s64 m_index{}; // where i am in the array
|
||||||
|
s64 m_selected_count{};
|
||||||
|
std::unique_ptr<List> m_list{};
|
||||||
|
bool m_is_reversed{};
|
||||||
|
bool m_dirty{};
|
||||||
|
|
||||||
|
std::vector<AccountEntry> m_accounts{};
|
||||||
|
s64 m_account_index{};
|
||||||
|
|
||||||
|
ThreadData m_thread_data{};
|
||||||
|
Thread m_thread{};
|
||||||
|
|
||||||
|
option::OptionLong m_sort{INI_SECTION, "sort", SortType::SortType_Updated};
|
||||||
|
option::OptionLong m_order{INI_SECTION, "order", OrderType::OrderType_Descending};
|
||||||
|
option::OptionLong m_layout{INI_SECTION, "layout", LayoutType::LayoutType_Grid};
|
||||||
|
option::OptionBool m_auto_backup_on_restore{INI_SECTION, "auto_backup_on_restore", true};
|
||||||
|
option::OptionBool m_compress_save_backup{INI_SECTION, "compress_save_backup", true};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sphaira::ui::menu::save
|
||||||
@@ -25,6 +25,7 @@ struct ProgressBox final : Widget {
|
|||||||
auto Update(Controller* controller, TouchInfo* touch) -> void override;
|
auto Update(Controller* controller, TouchInfo* touch) -> void override;
|
||||||
auto Draw(NVGcontext* vg, Theme* theme) -> void override;
|
auto Draw(NVGcontext* vg, Theme* theme) -> void override;
|
||||||
|
|
||||||
|
auto SetActionName(const std::string& action) -> ProgressBox&;
|
||||||
auto SetTitle(const std::string& title) -> ProgressBox&;
|
auto SetTitle(const std::string& title) -> ProgressBox&;
|
||||||
auto NewTransfer(const std::string& transfer) -> ProgressBox&;
|
auto NewTransfer(const std::string& transfer) -> ProgressBox&;
|
||||||
auto UpdateTransfer(s64 offset, s64 size) -> ProgressBox&;
|
auto UpdateTransfer(s64 offset, s64 size) -> ProgressBox&;
|
||||||
|
|||||||
@@ -179,6 +179,8 @@ enum ThemeEntryID {
|
|||||||
ThemeEntryID_TEXT_SELECTED,
|
ThemeEntryID_TEXT_SELECTED,
|
||||||
// background colour of a selected item, can be an image (not recommended).
|
// background colour of a selected item, can be an image (not recommended).
|
||||||
ThemeEntryID_SELECTED_BACKGROUND,
|
ThemeEntryID_SELECTED_BACKGROUND,
|
||||||
|
// colour of the split screen and selected item.
|
||||||
|
ThemeEntryID_FOCUS,
|
||||||
|
|
||||||
// colour of line separators in a list.
|
// colour of line separators in a list.
|
||||||
ThemeEntryID_LINE,
|
ThemeEntryID_LINE,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
namespace sphaira::es {
|
namespace sphaira::es {
|
||||||
|
|
||||||
enum { TicketModule = 522 };
|
enum { TicketModule = 507 };
|
||||||
|
|
||||||
enum : Result {
|
enum : Result {
|
||||||
// found ticket has missmatching rights_id from it's name.
|
// found ticket has missmatching rights_id from it's name.
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ Result VerifyFixedKey(const Header& header);
|
|||||||
|
|
||||||
// helpers that parse an nca.
|
// helpers that parse an nca.
|
||||||
Result ParseCnmt(const fs::FsPath& path, u64 program_id, ncm::PackagedContentMeta& header, std::vector<u8>& extended_header, std::vector<NcmPackagedContentInfo>& infos);
|
Result ParseCnmt(const fs::FsPath& path, u64 program_id, ncm::PackagedContentMeta& header, std::vector<u8>& extended_header, std::vector<NcmPackagedContentInfo>& infos);
|
||||||
Result ParseControl(const fs::FsPath& path, u64 program_id, void* nacp_out = nullptr, s64 nacp_size = 0, std::vector<u8>* icon_out = nullptr);
|
Result ParseControl(const fs::FsPath& path, u64 program_id, void* nacp_out = nullptr, s64 nacp_size = 0, std::vector<u8>* icon_out = nullptr, s64 nacp_off = 0);
|
||||||
|
|
||||||
auto GetKeyGenStr(u8 key_gen) -> const char*;
|
auto GetKeyGenStr(u8 key_gen) -> const char*;
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
namespace sphaira::yati::source {
|
namespace sphaira::yati::source {
|
||||||
|
|
||||||
struct Usb final : Base {
|
struct Usb final : Base {
|
||||||
enum { USBModule = 523 };
|
enum { USBModule = 508 };
|
||||||
|
|
||||||
enum : Result {
|
enum : Result {
|
||||||
Result_BadMagic = MAKERESULT(USBModule, 0),
|
Result_BadMagic = MAKERESULT(USBModule, 0),
|
||||||
|
|||||||
@@ -16,8 +16,18 @@
|
|||||||
|
|
||||||
namespace sphaira::yati {
|
namespace sphaira::yati {
|
||||||
|
|
||||||
enum { YatiModule = 521 };
|
enum { YatiModule = 506 };
|
||||||
|
|
||||||
|
/*
|
||||||
|
Improving compression ratio via block splitting is now enabled by default for high compression levels (16+).
|
||||||
|
The amount of benefit varies depending on the workload.
|
||||||
|
Compressing archives comprised of heavily differing files will see more improvement than compression of single files that don’t
|
||||||
|
vary much entropically (like text files/enwik). At levels 16+, we observe no measurable regression to compression speed.
|
||||||
|
|
||||||
|
The block splitter can be forcibly enabled on lower compression levels as well with the advanced parameter ZSTD_c_splitBlocks.
|
||||||
|
When forcibly enabled at lower levels, speed regressions can become more notable.
|
||||||
|
Additionally, since more compressed blocks may be produced, decompression speed on these blobs may also see small regressions.
|
||||||
|
*/
|
||||||
enum : Result {
|
enum : Result {
|
||||||
// unkown container for the source provided.
|
// unkown container for the source provided.
|
||||||
Result_ContainerNotFound = MAKERESULT(YatiModule, 10),
|
Result_ContainerNotFound = MAKERESULT(YatiModule, 10),
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ constexpr ThemeIdPair THEME_ENTRIES[] = {
|
|||||||
{ "selected_background", ThemeEntryID_SELECTED_BACKGROUND, ElementType::Colour },
|
{ "selected_background", ThemeEntryID_SELECTED_BACKGROUND, ElementType::Colour },
|
||||||
{ "error", ThemeEntryID_ERROR, ElementType::Colour },
|
{ "error", ThemeEntryID_ERROR, ElementType::Colour },
|
||||||
{ "popup", ThemeEntryID_POPUP, ElementType::Colour },
|
{ "popup", ThemeEntryID_POPUP, ElementType::Colour },
|
||||||
|
{ "focus", ThemeEntryID_FOCUS, ElementType::Colour },
|
||||||
{ "line", ThemeEntryID_LINE, ElementType::Colour },
|
{ "line", ThemeEntryID_LINE, ElementType::Colour },
|
||||||
{ "line_separator", ThemeEntryID_LINE_SEPARATOR, ElementType::Colour },
|
{ "line_separator", ThemeEntryID_LINE_SEPARATOR, ElementType::Colour },
|
||||||
{ "sidebar", ThemeEntryID_SIDEBAR, ElementType::Colour },
|
{ "sidebar", ThemeEntryID_SIDEBAR, ElementType::Colour },
|
||||||
@@ -895,22 +896,18 @@ void App::SetTextScrollSpeed(long index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto App::Install(OwoConfig& config) -> Result {
|
auto App::Install(OwoConfig& config) -> Result {
|
||||||
config.nro_path = nro_add_arg_file(config.nro_path);
|
App::Push(std::make_shared<ui::ProgressBox>(0, "Installing Forwarder"_i18n, config.name, [config](auto pbox) mutable -> Result {
|
||||||
if (!config.icon.empty()) {
|
return Install(pbox, config);
|
||||||
config.icon = GetNroIcon(config.icon);
|
}, [](Result rc){
|
||||||
}
|
App::PushErrorBox(rc, "Failed to install forwarder"_i18n);
|
||||||
|
|
||||||
const auto rc = install_forwarder(config, App::GetInstallSdEnable() ? NcmStorageId_SdCard : NcmStorageId_BuiltInUser);
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
App::PlaySoundEffect(SoundEffect_Error);
|
|
||||||
App::Push(std::make_shared<ui::ErrorBox>(rc, "Failed to install forwarder"_i18n));
|
|
||||||
} else {
|
|
||||||
App::PlaySoundEffect(SoundEffect_Install);
|
App::PlaySoundEffect(SoundEffect_Install);
|
||||||
App::Notify("Installed!"_i18n);
|
App::Notify("Installed!"_i18n);
|
||||||
}
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
return rc;
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto App::Install(ui::ProgressBox* pbox, OwoConfig& config) -> Result {
|
auto App::Install(ui::ProgressBox* pbox, OwoConfig& config) -> Result {
|
||||||
@@ -919,17 +916,15 @@ auto App::Install(ui::ProgressBox* pbox, OwoConfig& config) -> Result {
|
|||||||
config.icon = GetNroIcon(config.icon);
|
config.icon = GetNroIcon(config.icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto rc = install_forwarder(pbox, config, GetInstallSdEnable() ? NcmStorageId_SdCard : NcmStorageId_BuiltInUser);
|
if (config.logo.empty()) {
|
||||||
|
fs::FsNativeSd().read_entire_file("/config/sphaira/logo/NintendoLogo.png", config.logo);
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
App::PlaySoundEffect(SoundEffect_Error);
|
|
||||||
App::Push(std::make_shared<ui::ErrorBox>(rc, "Failed to install forwarder"_i18n));
|
|
||||||
} else {
|
|
||||||
App::PlaySoundEffect(SoundEffect_Install);
|
|
||||||
App::Notify("Installed!"_i18n);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
if (config.gif.empty()) {
|
||||||
|
fs::FsNativeSd().read_entire_file("/config/sphaira/logo/StartupMovie.gif", config.gif);
|
||||||
|
}
|
||||||
|
|
||||||
|
return install_forwarder(pbox, config, GetInstallSdEnable() ? NcmStorageId_SdCard : NcmStorageId_BuiltInUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto App::IsEmummc() -> bool {
|
auto App::IsEmummc() -> bool {
|
||||||
@@ -1375,6 +1370,8 @@ App::App(const char* argv0) {
|
|||||||
// loading each config one by one as it avoids re-opening the file multiple times.
|
// loading each config one by one as it avoids re-opening the file multiple times.
|
||||||
ini_browse(cb, this, CONFIG_PATH);
|
ini_browse(cb, this, CONFIG_PATH);
|
||||||
|
|
||||||
|
i18n::init(GetLanguage());
|
||||||
|
|
||||||
if (App::GetLogEnable()) {
|
if (App::GetLogEnable()) {
|
||||||
log_file_init();
|
log_file_init();
|
||||||
log_write("hello world v%s\n", APP_VERSION_HASH);
|
log_write("hello world v%s\n", APP_VERSION_HASH);
|
||||||
@@ -1403,6 +1400,12 @@ App::App(const char* argv0) {
|
|||||||
|
|
||||||
curl::Init();
|
curl::Init();
|
||||||
|
|
||||||
|
#ifdef USE_NVJPG
|
||||||
|
// this has to be init before deko3d.
|
||||||
|
nj::initialize();
|
||||||
|
m_decoder.initialize();
|
||||||
|
#endif
|
||||||
|
|
||||||
// get current size of the framebuffer
|
// get current size of the framebuffer
|
||||||
const auto fb = GetFrameBufferSize();
|
const auto fb = GetFrameBufferSize();
|
||||||
s_width = fb.size.x;
|
s_width = fb.size.x;
|
||||||
@@ -1435,8 +1438,6 @@ App::App(const char* argv0) {
|
|||||||
this->renderer.emplace(s_width, s_height, this->device, this->queue, *this->pool_images, *this->pool_code, *this->pool_data);
|
this->renderer.emplace(s_width, s_height, this->device, this->queue, *this->pool_images, *this->pool_code, *this->pool_data);
|
||||||
this->vg = nvgCreateDk(&*this->renderer, NVG_ANTIALIAS | NVG_STENCIL_STROKES);
|
this->vg = nvgCreateDk(&*this->renderer, NVG_ANTIALIAS | NVG_STENCIL_STROKES);
|
||||||
|
|
||||||
i18n::init(GetLanguage());
|
|
||||||
|
|
||||||
// not sure if these are meant to be deleted or not...
|
// not sure if these are meant to be deleted or not...
|
||||||
PlFontData font_standard, font_extended, font_lang;
|
PlFontData font_standard, font_extended, font_lang;
|
||||||
plGetSharedFontByType(&font_standard, PlSharedFontType_Standard);
|
plGetSharedFontByType(&font_standard, PlSharedFontType_Standard);
|
||||||
@@ -1643,7 +1644,7 @@ void App::DisplayMiscOptions(bool left_side) {
|
|||||||
const auto index = *op_index;
|
const auto index = *op_index;
|
||||||
if (index == items.size() - 1) {
|
if (index == items.size() - 1) {
|
||||||
std::string out;
|
std::string out;
|
||||||
if (R_SUCCEEDED(swkbd::ShowText(out, "Enter URL", "https://")) && !out.empty()) {
|
if (R_SUCCEEDED(swkbd::ShowText(out, "Enter URL"_i18n.c_str(), "https://")) && !out.empty()) {
|
||||||
WebShow(out);
|
WebShow(out);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1665,7 +1666,8 @@ void App::DisplayAdvancedOptions(bool left_side) {
|
|||||||
text_scroll_speed_items.push_back("Normal"_i18n);
|
text_scroll_speed_items.push_back("Normal"_i18n);
|
||||||
text_scroll_speed_items.push_back("Fast"_i18n);
|
text_scroll_speed_items.push_back("Fast"_i18n);
|
||||||
|
|
||||||
std::vector<const char*> menu_names;
|
std::vector<std::string> menu_names;
|
||||||
|
ui::SidebarEntryArray::Items menu_items;
|
||||||
for (auto& e : ui::menu::main::GetMiscMenuEntries()) {
|
for (auto& e : ui::menu::main::GetMiscMenuEntries()) {
|
||||||
if (!e.IsShortcut()) {
|
if (!e.IsShortcut()) {
|
||||||
continue;
|
continue;
|
||||||
@@ -1676,16 +1678,7 @@ void App::DisplayAdvancedOptions(bool left_side) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
menu_names.emplace_back(e.name);
|
menu_names.emplace_back(e.name);
|
||||||
}
|
menu_items.push_back(i18n::get(e.name));
|
||||||
|
|
||||||
ui::SidebarEntryArray::Items side_menu_items;
|
|
||||||
for (auto& str : menu_names) {
|
|
||||||
side_menu_items.push_back(i18n::get(str));
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto it = std::find(menu_names.cbegin(), menu_names.cend(), g_app->m_right_menu.Get());
|
|
||||||
if (it == menu_names.cend()) {
|
|
||||||
g_app->m_right_menu.Set(menu_names[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
options->Add(std::make_shared<ui::SidebarEntryBool>("Logging"_i18n, App::GetLogEnable(), [](bool& enable){
|
options->Add(std::make_shared<ui::SidebarEntryBool>("Logging"_i18n, App::GetLogEnable(), [](bool& enable){
|
||||||
@@ -1704,10 +1697,15 @@ void App::DisplayAdvancedOptions(bool left_side) {
|
|||||||
App::SetTextScrollSpeed(index_out);
|
App::SetTextScrollSpeed(index_out);
|
||||||
}, App::GetTextScrollSpeed()));
|
}, App::GetTextScrollSpeed()));
|
||||||
|
|
||||||
options->Add(std::make_shared<ui::SidebarEntryArray>("Set left-side menu"_i18n, side_menu_items, [menu_names](s64& index_out){
|
options->Add(std::make_shared<ui::SidebarEntryArray>("Set left-side menu"_i18n, menu_items, [menu_names](s64& index_out){
|
||||||
const auto e = menu_names[index_out];
|
const auto e = menu_names[index_out];
|
||||||
if (g_app->m_left_menu.Get() != e) {
|
if (g_app->m_left_menu.Get() != e) {
|
||||||
|
// swap menus around.
|
||||||
|
if (g_app->m_right_menu.Get() == e) {
|
||||||
|
g_app->m_right_menu.Set(g_app->m_left_menu.Get());
|
||||||
|
}
|
||||||
g_app->m_left_menu.Set(e);
|
g_app->m_left_menu.Set(e);
|
||||||
|
|
||||||
App::Push(std::make_shared<ui::OptionBox>(
|
App::Push(std::make_shared<ui::OptionBox>(
|
||||||
"Press OK to restart Sphaira"_i18n, "OK"_i18n, [](auto){
|
"Press OK to restart Sphaira"_i18n, "OK"_i18n, [](auto){
|
||||||
App::ExitRestart();
|
App::ExitRestart();
|
||||||
@@ -1716,10 +1714,15 @@ void App::DisplayAdvancedOptions(bool left_side) {
|
|||||||
}
|
}
|
||||||
}, i18n::get(g_app->m_left_menu.Get())));
|
}, i18n::get(g_app->m_left_menu.Get())));
|
||||||
|
|
||||||
options->Add(std::make_shared<ui::SidebarEntryArray>("Set right-side menu"_i18n, side_menu_items, [menu_names](s64& index_out){
|
options->Add(std::make_shared<ui::SidebarEntryArray>("Set right-side menu"_i18n, menu_items, [menu_names](s64& index_out){
|
||||||
const auto e = menu_names[index_out];
|
const auto e = menu_names[index_out];
|
||||||
if (g_app->m_right_menu.Get() != e) {
|
if (g_app->m_right_menu.Get() != e) {
|
||||||
|
// swap menus around.
|
||||||
|
if (g_app->m_left_menu.Get() == e) {
|
||||||
|
g_app->m_left_menu.Set(g_app->m_right_menu.Get());
|
||||||
|
}
|
||||||
g_app->m_right_menu.Set(e);
|
g_app->m_right_menu.Set(e);
|
||||||
|
|
||||||
App::Push(std::make_shared<ui::OptionBox>(
|
App::Push(std::make_shared<ui::OptionBox>(
|
||||||
"Press OK to restart Sphaira"_i18n, "OK"_i18n, [](auto){
|
"Press OK to restart Sphaira"_i18n, "OK"_i18n, [](auto){
|
||||||
App::ExitRestart();
|
App::ExitRestart();
|
||||||
@@ -1852,6 +1855,7 @@ App::~App() {
|
|||||||
ON_SCOPE_EXIT(appletSetCpuBoostMode(ApmCpuBoostMode_Normal));
|
ON_SCOPE_EXIT(appletSetCpuBoostMode(ApmCpuBoostMode_Normal));
|
||||||
|
|
||||||
log_write("starting to exit\n");
|
log_write("starting to exit\n");
|
||||||
|
TimeStamp ts;
|
||||||
|
|
||||||
i18n::exit();
|
i18n::exit();
|
||||||
curl::Exit();
|
curl::Exit();
|
||||||
@@ -1881,6 +1885,11 @@ App::~App() {
|
|||||||
nvgDeleteDk(this->vg);
|
nvgDeleteDk(this->vg);
|
||||||
this->renderer.reset();
|
this->renderer.reset();
|
||||||
|
|
||||||
|
#ifdef USE_NVJPG
|
||||||
|
m_decoder.finalize();
|
||||||
|
nj::finalize();
|
||||||
|
#endif
|
||||||
|
|
||||||
// backup hbmenu if it is not sphaira
|
// backup hbmenu if it is not sphaira
|
||||||
if (App::GetReplaceHbmenuEnable() && !IsHbmenu()) {
|
if (App::GetReplaceHbmenuEnable() && !IsHbmenu()) {
|
||||||
NacpStruct hbmenu_nacp;
|
NacpStruct hbmenu_nacp;
|
||||||
@@ -1953,6 +1962,8 @@ App::~App() {
|
|||||||
usbHsFsExit();
|
usbHsFsExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_write("\t[EXIT] time taken: %.2fs %zums\n", ts.GetSecondsD(), ts.GetMs());
|
||||||
|
|
||||||
if (App::GetLogEnable()) {
|
if (App::GetLogEnable()) {
|
||||||
log_write("closing log\n");
|
log_write("closing log\n");
|
||||||
log_file_exit();
|
log_file_exit();
|
||||||
|
|||||||
@@ -332,7 +332,7 @@ struct ThreadQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto Add(const Api& api, bool is_upload = false) -> bool {
|
auto Add(const Api& api, bool is_upload = false) -> bool {
|
||||||
if (api.GetUrl().empty() || api.GetPath().empty() || !api.GetOnComplete()) {
|
if (api.GetUrl().empty() || !api.GetOnComplete()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -207,14 +207,14 @@ Result DumpToUsbS2S(ui::ProgressBox* pbox, BaseSource* source, std::span<const f
|
|||||||
|
|
||||||
while (!pbox->ShouldExit()) {
|
while (!pbox->ShouldExit()) {
|
||||||
if (R_SUCCEEDED(usb->IsUsbConnected(timeout))) {
|
if (R_SUCCEEDED(usb->IsUsbConnected(timeout))) {
|
||||||
pbox->NewTransfer("USB connected, sending file list");
|
pbox->NewTransfer("USB connected, sending file list"_i18n);
|
||||||
u8 flags = usb::tinfoil::USBFlag_NONE;
|
u8 flags = usb::tinfoil::USBFlag_NONE;
|
||||||
if (App::GetApp()->m_dump_usb_transfer_stream.Get()) {
|
if (App::GetApp()->m_dump_usb_transfer_stream.Get()) {
|
||||||
flags |= usb::tinfoil::USBFlag_STREAM;
|
flags |= usb::tinfoil::USBFlag_STREAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (R_SUCCEEDED(usb->WaitForConnection(timeout, flags, file_list))) {
|
if (R_SUCCEEDED(usb->WaitForConnection(timeout, flags, file_list))) {
|
||||||
pbox->NewTransfer("Sent file list, waiting for command...");
|
pbox->NewTransfer("Sent file list, waiting for command..."_i18n);
|
||||||
|
|
||||||
Result rc;
|
Result rc;
|
||||||
if (flags & usb::tinfoil::USBFlag_STREAM) {
|
if (flags & usb::tinfoil::USBFlag_STREAM) {
|
||||||
@@ -240,7 +240,7 @@ Result DumpToUsbS2S(ui::ProgressBox* pbox, BaseSource* source, std::span<const f
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pbox->NewTransfer("waiting for usb connection...");
|
pbox->NewTransfer("waiting for usb connection..."_i18n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -118,6 +118,18 @@ Result CreateDirectory(FsFileSystem* fs, const FsPath& path, bool ignore_read_on
|
|||||||
Result CreateDirectoryRecursively(FsFileSystem* fs, const FsPath& _path, bool ignore_read_only) {
|
Result CreateDirectoryRecursively(FsFileSystem* fs, const FsPath& _path, bool ignore_read_only) {
|
||||||
R_UNLESS(ignore_read_only || !is_read_only_root(_path), Fs::ResultReadOnly);
|
R_UNLESS(ignore_read_only || !is_read_only_root(_path), Fs::ResultReadOnly);
|
||||||
|
|
||||||
|
// try and create the directory / see if it already exists before the loop.
|
||||||
|
Result rc;
|
||||||
|
if (fs) {
|
||||||
|
rc = CreateDirectory(fs, _path, ignore_read_only);
|
||||||
|
} else {
|
||||||
|
rc = CreateDirectory(_path, ignore_read_only);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc) || rc == FsError_PathAlreadyExists) {
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
auto path_view = std::string_view{_path};
|
auto path_view = std::string_view{_path};
|
||||||
// todo: fix this for sdmc: and ums0:
|
// todo: fix this for sdmc: and ums0:
|
||||||
FsPath path{"/"};
|
FsPath path{"/"};
|
||||||
@@ -134,7 +146,6 @@ Result CreateDirectoryRecursively(FsFileSystem* fs, const FsPath& _path, bool ig
|
|||||||
std::strncat(path, dir.data(), dir.size());
|
std::strncat(path, dir.data(), dir.size());
|
||||||
log_write("[FS] dir creation path is now: %s\n", path.s);
|
log_write("[FS] dir creation path is now: %s\n", path.s);
|
||||||
|
|
||||||
Result rc;
|
|
||||||
if (fs) {
|
if (fs) {
|
||||||
rc = CreateDirectory(fs, path, ignore_read_only);
|
rc = CreateDirectory(fs, path, ignore_read_only);
|
||||||
} else {
|
} else {
|
||||||
@@ -155,31 +166,15 @@ Result CreateDirectoryRecursively(FsFileSystem* fs, const FsPath& _path, bool ig
|
|||||||
Result CreateDirectoryRecursivelyWithPath(FsFileSystem* fs, const FsPath& _path, bool ignore_read_only) {
|
Result CreateDirectoryRecursivelyWithPath(FsFileSystem* fs, const FsPath& _path, bool ignore_read_only) {
|
||||||
R_UNLESS(ignore_read_only || !is_read_only_root(_path), Fs::ResultReadOnly);
|
R_UNLESS(ignore_read_only || !is_read_only_root(_path), Fs::ResultReadOnly);
|
||||||
|
|
||||||
size_t off = 0;
|
// strip file name form path.
|
||||||
while (true) {
|
const auto last_slash = std::strrchr(_path, '/');
|
||||||
const auto first = std::strchr(_path + off, '/');
|
if (!last_slash) {
|
||||||
if (!first) {
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
off = (first - _path.s) + 1;
|
FsPath new_path{};
|
||||||
FsPath path;
|
std::snprintf(new_path, sizeof(new_path), "%.*s", (int)(last_slash - _path.s), _path.s);
|
||||||
std::strncpy(path, _path, off);
|
return CreateDirectoryRecursively(fs, new_path, ignore_read_only);
|
||||||
|
|
||||||
Result rc;
|
|
||||||
if (fs) {
|
|
||||||
rc = CreateDirectory(fs, path, ignore_read_only);
|
|
||||||
} else {
|
|
||||||
rc = CreateDirectory(path, ignore_read_only);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R_FAILED(rc) && rc != FsError_PathAlreadyExists) {
|
|
||||||
log_write("failed to create folder recursively: %s\n", path.s);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
// log_write("created_directory recursively: %s\n", path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeleteFile(FsFileSystem* fs, const FsPath& path, bool ignore_read_only) {
|
Result DeleteFile(FsFileSystem* fs, const FsPath& path, bool ignore_read_only) {
|
||||||
|
|||||||
@@ -35,6 +35,25 @@ private:
|
|||||||
bool m_is_file_based_emummc{};
|
bool m_is_file_based_emummc{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MemSource final : BaseSource {
|
||||||
|
MemSource(std::span<const u8> data) : m_data{data} { }
|
||||||
|
|
||||||
|
Result Size(s64* out) {
|
||||||
|
*out = m_data.size();
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Read(void* buf, s64 off, s64 size, u64* bytes_read) {
|
||||||
|
size = std::min<s64>(size, m_data.size() - off);
|
||||||
|
std::memcpy(buf, m_data.data() + off, size);
|
||||||
|
*bytes_read = size;
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::span<const u8> m_data;
|
||||||
|
};
|
||||||
|
|
||||||
struct HashSource {
|
struct HashSource {
|
||||||
virtual ~HashSource() = default;
|
virtual ~HashSource() = default;
|
||||||
virtual void Update(const void* buf, s64 size) = 0;
|
virtual void Update(const void* buf, s64 size) = 0;
|
||||||
@@ -181,4 +200,9 @@ Result Hash(ui::ProgressBox* pbox, Type type, fs::Fs* fs, const fs::FsPath& path
|
|||||||
return Hash(pbox, type, source, out);
|
return Hash(pbox, type, source, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result Hash(ui::ProgressBox* pbox, Type type, std::span<const u8> data, std::string& out) {
|
||||||
|
auto source = std::make_shared<MemSource>(data);
|
||||||
|
return Hash(pbox, type, source, out);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace sphaira::has
|
} // namespace sphaira::has
|
||||||
|
|||||||
@@ -20,7 +20,11 @@
|
|||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
#include "app.hpp"
|
||||||
#include "log.hpp"
|
#include "log.hpp"
|
||||||
|
#ifdef USE_NVJPG
|
||||||
|
#include <nvjpg.hpp>
|
||||||
|
#endif
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
namespace sphaira {
|
namespace sphaira {
|
||||||
@@ -30,7 +34,6 @@ constexpr int BPP = 4;
|
|||||||
|
|
||||||
auto ImageLoadInternal(stbi_uc* image_data, int x, int y) -> ImageResult {
|
auto ImageLoadInternal(stbi_uc* image_data, int x, int y) -> ImageResult {
|
||||||
if (image_data) {
|
if (image_data) {
|
||||||
log_write("loaded image: w: %d h: %d\n", x, y);
|
|
||||||
ImageResult result{};
|
ImageResult result{};
|
||||||
result.data.resize(x*y*BPP);
|
result.data.resize(x*y*BPP);
|
||||||
result.w = x;
|
result.w = x;
|
||||||
@@ -44,17 +47,83 @@ auto ImageLoadInternal(stbi_uc* image_data, int x, int y) -> ImageResult {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_NVJPG
|
||||||
|
auto ImageLoadInternal(nj::Image&& image) -> ImageResult {
|
||||||
|
if (!image.is_valid() || image.parse()) {
|
||||||
|
log_write("[NVJPG] failed to parse image\n");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
nj::Surface surf{image.width, image.height};
|
||||||
|
if (surf.allocate()) {
|
||||||
|
log_write("[NVJPG] failed to allocate surf\n");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (R_FAILED(App::GetApp()->m_decoder.render(image, surf, 255))) {
|
||||||
|
log_write("[NVJPG] failed to render\n");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (R_FAILED(App::GetApp()->m_decoder.wait(surf))) {
|
||||||
|
log_write("[NVJPG] failed to wait\n");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageResult result{};
|
||||||
|
result.w = surf.width;
|
||||||
|
result.h = surf.height;
|
||||||
|
result.data.resize(surf.width * surf.height * surf.get_bpp());
|
||||||
|
// std::printf("[NVJPG] w: %zu h: %zu bpp: %u pitch: %zu size: %zu size2: %u\n", surf.width, surf.height, surf.get_bpp(), surf.pitch, surf.size(), 256*256*4);
|
||||||
|
|
||||||
|
if (surf.width * surf.get_bpp() == surf.pitch) [[likely]] {
|
||||||
|
std::memcpy(result.data.data(), surf.data(), result.data.size());
|
||||||
|
} else {
|
||||||
|
for (size_t i = 0; i < surf.height; i++) {
|
||||||
|
const auto src_pitch = surf.pitch;
|
||||||
|
const auto dst_pitch = surf.width * surf.get_bpp();
|
||||||
|
std::memcpy(result.data.data() + i * dst_pitch, surf.data() + i * src_pitch, dst_pitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
auto ImageLoadFromMemory(std::span<const u8> data) -> ImageResult {
|
auto ImageLoadFromMemory(std::span<const u8> data, u32 flags) -> ImageResult {
|
||||||
|
#ifdef USE_NVJPG
|
||||||
|
if (flags & ImageFlag_JPEG) {
|
||||||
|
auto shared_vec = std::make_shared<std::vector<u8>>(data.size());
|
||||||
|
std::memcpy(shared_vec->data(), data.data(), shared_vec->size());
|
||||||
|
// don't make const as it prevents RTO.
|
||||||
|
auto result = ImageLoadInternal(nj::Image{shared_vec});
|
||||||
|
// if it failed, try again but without using oss-jpg.
|
||||||
|
return result.data.empty() ? ImageLoadFromMemory(data, 0) : result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
int x, y, channels;
|
int x, y, channels;
|
||||||
return ImageLoadInternal(stbi_load_from_memory(data.data(), data.size(), &x, &y, &channels, BPP), x, y);
|
return ImageLoadInternal(stbi_load_from_memory(data.data(), data.size(), &x, &y, &channels, BPP), x, y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ImageLoadFromFile(const fs::FsPath& file) -> ImageResult {
|
auto ImageLoadFromFile(const fs::FsPath& file, u32 flags) -> ImageResult {
|
||||||
log_write("doing file load\n");
|
#ifdef USE_NVJPG
|
||||||
|
if (flags & ImageFlag_JPEG) {
|
||||||
|
// don't make const as it prevents RTO.
|
||||||
|
auto result = ImageLoadInternal(nj::Image{file});
|
||||||
|
// if it failed, try again but without using oss-jpg.
|
||||||
|
return result.data.empty() ? ImageLoadFromFile(file, 0) : result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
int x, y, channels;
|
int x, y, channels;
|
||||||
return ImageLoadInternal(stbi_load(file, &x, &y, &channels, BPP), x, y);
|
return ImageLoadInternal(stbi_load(file, &x, &y, &channels, BPP), x, y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ImageResize(std::span<const u8> data, int inx, int iny, int outx, int outy) -> ImageResult {
|
auto ImageResize(std::span<const u8> data, int inx, int iny, int outx, int outy) -> ImageResult {
|
||||||
|
|||||||
@@ -83,6 +83,10 @@ void userAppExit(void) {
|
|||||||
psmExit();
|
psmExit();
|
||||||
plExit();
|
plExit();
|
||||||
socketExit();
|
socketExit();
|
||||||
|
// NOTE (DMC): prevents exfat corruption.
|
||||||
|
if (auto fs = fsdevGetDeviceFileSystem("sdmc:")) {
|
||||||
|
fsFsCommit(fs);
|
||||||
|
}
|
||||||
appletUnlockExit();
|
appletUnlockExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
210
sphaira/source/minizip_helper.cpp
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
#include "minizip_helper.hpp"
|
||||||
|
#include <minizip/unzip.h>
|
||||||
|
#include <minizip/zip.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
namespace sphaira::mz {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
voidpf minizip_open_file_func_mem(voidpf opaque, const void* filename, int mode) {
|
||||||
|
return opaque;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZPOS64_T minizip_tell_file_func_mem(voidpf opaque, voidpf stream) {
|
||||||
|
auto mem = static_cast<const MzMem*>(opaque);
|
||||||
|
return mem->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
long minizip_seek_file_func_mem(voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) {
|
||||||
|
auto mem = static_cast<MzMem*>(opaque);
|
||||||
|
size_t new_offset = 0;
|
||||||
|
|
||||||
|
switch (origin) {
|
||||||
|
case ZLIB_FILEFUNC_SEEK_SET: new_offset = offset; break;
|
||||||
|
case ZLIB_FILEFUNC_SEEK_CUR: new_offset = mem->offset + offset; break;
|
||||||
|
case ZLIB_FILEFUNC_SEEK_END: new_offset = (mem->buf.size() - 1) + offset; break;
|
||||||
|
default: return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_offset > mem->buf.size()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem->offset = new_offset;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uLong minizip_read_file_func_mem(voidpf opaque, voidpf stream, void* buf, uLong size) {
|
||||||
|
auto mem = static_cast<MzMem*>(opaque);
|
||||||
|
|
||||||
|
size = std::min(size, mem->buf.size() - mem->offset);
|
||||||
|
std::memcpy(buf, mem->buf.data() + mem->offset, size);
|
||||||
|
mem->offset += size;
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
uLong minizip_write_file_func_mem(voidpf opaque, voidpf stream, const void* buf, uLong size) {
|
||||||
|
auto mem = static_cast<MzMem*>(opaque);
|
||||||
|
|
||||||
|
// give it more memory
|
||||||
|
if (mem->buf.capacity() < mem->offset + size) {
|
||||||
|
mem->buf.reserve(mem->buf.capacity() + 1024*1024*64);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mem->buf.size() < mem->offset + size) {
|
||||||
|
mem->buf.resize(mem->offset + size);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(mem->buf.data() + mem->offset, buf, size);
|
||||||
|
mem->offset += size;
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int minizip_close_file_func_mem(voidpf opaque, voidpf stream) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr zlib_filefunc64_def zlib_filefunc_mem = {
|
||||||
|
.zopen64_file = minizip_open_file_func_mem,
|
||||||
|
.zread_file = minizip_read_file_func_mem,
|
||||||
|
.zwrite_file = minizip_write_file_func_mem,
|
||||||
|
.ztell64_file = minizip_tell_file_func_mem,
|
||||||
|
.zseek64_file = minizip_seek_file_func_mem,
|
||||||
|
.zclose_file = minizip_close_file_func_mem,
|
||||||
|
};
|
||||||
|
|
||||||
|
voidpf minizip_open_file_func_span(voidpf opaque, const void* filename, int mode) {
|
||||||
|
return opaque;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZPOS64_T minizip_tell_file_func_span(voidpf opaque, voidpf stream) {
|
||||||
|
auto mem = static_cast<const MzSpan*>(opaque);
|
||||||
|
return mem->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
long minizip_seek_file_func_span(voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) {
|
||||||
|
auto mem = static_cast<MzSpan*>(opaque);
|
||||||
|
size_t new_offset = 0;
|
||||||
|
|
||||||
|
switch (origin) {
|
||||||
|
case ZLIB_FILEFUNC_SEEK_SET: new_offset = offset; break;
|
||||||
|
case ZLIB_FILEFUNC_SEEK_CUR: new_offset = mem->offset + offset; break;
|
||||||
|
case ZLIB_FILEFUNC_SEEK_END: new_offset = (mem->buf.size() - 1) + offset; break;
|
||||||
|
default: return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_offset > mem->buf.size()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem->offset = new_offset;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uLong minizip_read_file_func_span(voidpf opaque, voidpf stream, void* buf, uLong size) {
|
||||||
|
auto mem = static_cast<MzSpan*>(opaque);
|
||||||
|
|
||||||
|
size = std::min(size, mem->buf.size() - mem->offset);
|
||||||
|
std::memcpy(buf, mem->buf.data() + mem->offset, size);
|
||||||
|
mem->offset += size;
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int minizip_close_file_func_span(voidpf opaque, voidpf stream) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr zlib_filefunc64_def zlib_filefunc_span = {
|
||||||
|
.zopen64_file = minizip_open_file_func_span,
|
||||||
|
.zread_file = minizip_read_file_func_span,
|
||||||
|
.ztell64_file = minizip_tell_file_func_span,
|
||||||
|
.zseek64_file = minizip_seek_file_func_span,
|
||||||
|
.zclose_file = minizip_close_file_func_span,
|
||||||
|
};
|
||||||
|
|
||||||
|
voidpf minizip_open_file_func_stdio(voidpf opaque, const void* filename, int mode) {
|
||||||
|
const char* mode_fopen = NULL;
|
||||||
|
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) {
|
||||||
|
mode_fopen = "rb";
|
||||||
|
} else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) {
|
||||||
|
mode_fopen = "r+b";
|
||||||
|
} else if (mode & ZLIB_FILEFUNC_MODE_CREATE) {
|
||||||
|
mode_fopen = "wb";
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto f = std::fopen((const char*)filename, mode_fopen);
|
||||||
|
if (f) {
|
||||||
|
std::setvbuf(f, nullptr, _IOFBF, 1024 * 512);
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZPOS64_T minizip_tell_file_func_stdio(voidpf opaque, voidpf stream) {
|
||||||
|
auto file = static_cast<std::FILE*>(stream);
|
||||||
|
return std::ftell(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
long minizip_seek_file_func_stdio(voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) {
|
||||||
|
auto file = static_cast<std::FILE*>(stream);
|
||||||
|
return std::fseek(file, offset, origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
uLong minizip_read_file_func_stdio(voidpf opaque, voidpf stream, void* buf, uLong size) {
|
||||||
|
auto file = static_cast<std::FILE*>(stream);
|
||||||
|
return std::fread(buf, 1, size, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
uLong minizip_write_file_func_stdio(voidpf opaque, voidpf stream, const void* buf, uLong size) {
|
||||||
|
auto file = static_cast<std::FILE*>(stream);
|
||||||
|
return std::fwrite(buf, 1, size, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
int minizip_close_file_func_stdio(voidpf opaque, voidpf stream) {
|
||||||
|
auto file = static_cast<std::FILE*>(stream);
|
||||||
|
if (file) {
|
||||||
|
return std::fclose(file);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int minizip_error_file_func_stdio(voidpf opaque, voidpf stream) {
|
||||||
|
auto file = static_cast<std::FILE*>(stream);
|
||||||
|
if (file) {
|
||||||
|
return std::ferror(file);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr zlib_filefunc64_def zlib_filefunc_stdio = {
|
||||||
|
.zopen64_file = minizip_open_file_func_stdio,
|
||||||
|
.zread_file = minizip_read_file_func_stdio,
|
||||||
|
.zwrite_file = minizip_write_file_func_stdio,
|
||||||
|
.ztell64_file = minizip_tell_file_func_stdio,
|
||||||
|
.zseek64_file = minizip_seek_file_func_stdio,
|
||||||
|
.zclose_file = minizip_close_file_func_stdio,
|
||||||
|
.zerror_file = minizip_error_file_func_stdio,
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void FileFuncMem(MzMem* mem, zlib_filefunc64_def* funcs) {
|
||||||
|
*funcs = zlib_filefunc_mem;
|
||||||
|
funcs->opaque = mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileFuncSpan(MzSpan* span, zlib_filefunc64_def* funcs) {
|
||||||
|
*funcs = zlib_filefunc_span;
|
||||||
|
funcs->opaque = span;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileFuncStdio(zlib_filefunc64_def* funcs) {
|
||||||
|
*funcs = zlib_filefunc_stdio;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sphaira::mz
|
||||||
@@ -2,19 +2,25 @@
|
|||||||
#include "log.hpp"
|
#include "log.hpp"
|
||||||
#include "defines.hpp"
|
#include "defines.hpp"
|
||||||
#include "app.hpp"
|
#include "app.hpp"
|
||||||
|
#include "minizip_helper.hpp"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <minizip/unzip.h>
|
||||||
|
#include <minizip/zip.h>
|
||||||
|
|
||||||
namespace sphaira::thread {
|
namespace sphaira::thread {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr u64 READ_BUFFER_MAX = 1024*1024*4;
|
// used for file based emummc and zip/unzip.
|
||||||
|
constexpr u64 SMALL_BUFFER_SIZE = 1024 * 512;
|
||||||
|
// used for everything else.
|
||||||
|
constexpr u64 NORMAL_BUFFER_SIZE = 1024*1024*4;
|
||||||
|
|
||||||
struct ThreadBuffer {
|
struct ThreadBuffer {
|
||||||
ThreadBuffer() {
|
ThreadBuffer() {
|
||||||
buf.reserve(READ_BUFFER_MAX);
|
buf.reserve(NORMAL_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> buf;
|
std::vector<u8> buf;
|
||||||
@@ -65,7 +71,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ThreadData {
|
struct ThreadData {
|
||||||
ThreadData(ui::ProgressBox* _pbox, s64 size, ReadCallback _rfunc, WriteCallback _wfunc);
|
ThreadData(ui::ProgressBox* _pbox, s64 size, ReadCallback _rfunc, WriteCallback _wfunc, u64 buffer_size);
|
||||||
|
|
||||||
auto GetResults() -> Result;
|
auto GetResults() -> Result;
|
||||||
void WakeAllThreads();
|
void WakeAllThreads();
|
||||||
@@ -104,9 +110,9 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// these need to be copied
|
// these need to be copied
|
||||||
ui::ProgressBox* pbox{};
|
ui::ProgressBox* const pbox;
|
||||||
ReadCallback rfunc{};
|
const ReadCallback rfunc;
|
||||||
WriteCallback wfunc{};
|
const WriteCallback wfunc;
|
||||||
|
|
||||||
// these need to be created
|
// these need to be created
|
||||||
Mutex mutex{};
|
Mutex mutex{};
|
||||||
@@ -121,21 +127,24 @@ private:
|
|||||||
std::vector<u8> pull_buffer{};
|
std::vector<u8> pull_buffer{};
|
||||||
s64 pull_buffer_offset{};
|
s64 pull_buffer_offset{};
|
||||||
|
|
||||||
u64 read_buffer_size{};
|
const u64 read_buffer_size;
|
||||||
u64 max_buffer_size{};
|
const s64 write_size;
|
||||||
|
|
||||||
// these are shared between threads
|
// these are shared between threads
|
||||||
volatile s64 read_offset{};
|
volatile s64 read_offset{};
|
||||||
volatile s64 write_offset{};
|
volatile s64 write_offset{};
|
||||||
volatile s64 write_size{};
|
|
||||||
|
|
||||||
volatile Result read_result{};
|
volatile Result read_result{};
|
||||||
volatile Result write_result{};
|
volatile Result write_result{};
|
||||||
volatile Result pull_result{};
|
volatile Result pull_result{};
|
||||||
};
|
};
|
||||||
|
|
||||||
ThreadData::ThreadData(ui::ProgressBox* _pbox, s64 size, ReadCallback _rfunc, WriteCallback _wfunc)
|
ThreadData::ThreadData(ui::ProgressBox* _pbox, s64 size, ReadCallback _rfunc, WriteCallback _wfunc, u64 buffer_size)
|
||||||
: pbox{_pbox}, rfunc{_rfunc}, wfunc{_wfunc} {
|
: pbox{_pbox}
|
||||||
|
, rfunc{_rfunc}
|
||||||
|
, wfunc{_wfunc}
|
||||||
|
, read_buffer_size{buffer_size}
|
||||||
|
, write_size{size} {
|
||||||
mutexInit(std::addressof(mutex));
|
mutexInit(std::addressof(mutex));
|
||||||
mutexInit(std::addressof(pull_mutex));
|
mutexInit(std::addressof(pull_mutex));
|
||||||
|
|
||||||
@@ -143,16 +152,6 @@ ThreadData::ThreadData(ui::ProgressBox* _pbox, s64 size, ReadCallback _rfunc, Wr
|
|||||||
condvarInit(std::addressof(can_write));
|
condvarInit(std::addressof(can_write));
|
||||||
condvarInit(std::addressof(can_pull));
|
condvarInit(std::addressof(can_pull));
|
||||||
condvarInit(std::addressof(can_pull_write));
|
condvarInit(std::addressof(can_pull_write));
|
||||||
|
|
||||||
write_size = size;
|
|
||||||
|
|
||||||
if (App::IsFileBaseEmummc()) {
|
|
||||||
read_buffer_size = 1024 * 512;
|
|
||||||
max_buffer_size = 1024 * 512;
|
|
||||||
} else {
|
|
||||||
read_buffer_size = READ_BUFFER_MAX;
|
|
||||||
max_buffer_size = READ_BUFFER_MAX;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ThreadData::GetResults() -> Result {
|
auto ThreadData::GetResults() -> Result {
|
||||||
@@ -251,7 +250,7 @@ Result ThreadData::Pull(void* data, s64 size, u64* bytes_read) {
|
|||||||
Result ThreadData::readFuncInternal() {
|
Result ThreadData::readFuncInternal() {
|
||||||
// the main buffer which data is read into.
|
// the main buffer which data is read into.
|
||||||
std::vector<u8> buf;
|
std::vector<u8> buf;
|
||||||
buf.reserve(this->max_buffer_size);
|
buf.reserve(this->read_buffer_size);
|
||||||
|
|
||||||
while (this->read_offset < this->write_size && R_SUCCEEDED(this->GetResults())) {
|
while (this->read_offset < this->write_size && R_SUCCEEDED(this->GetResults())) {
|
||||||
// read more data
|
// read more data
|
||||||
@@ -265,14 +264,14 @@ Result ThreadData::readFuncInternal() {
|
|||||||
R_TRY(this->SetWriteBuf(buf, buf_size));
|
R_TRY(this->SetWriteBuf(buf, buf_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
log_write("read success\n");
|
log_write("finished read thread success!\n");
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
// write thread writes data to the nca placeholder.
|
// write thread writes data to the nca placeholder.
|
||||||
Result ThreadData::writeFuncInternal() {
|
Result ThreadData::writeFuncInternal() {
|
||||||
std::vector<u8> buf;
|
std::vector<u8> buf;
|
||||||
buf.reserve(this->max_buffer_size);
|
buf.reserve(this->read_buffer_size);
|
||||||
|
|
||||||
while (this->write_offset < this->write_size && R_SUCCEEDED(this->GetResults())) {
|
while (this->write_offset < this->write_size && R_SUCCEEDED(this->GetResults())) {
|
||||||
s64 dummy_off;
|
s64 dummy_off;
|
||||||
@@ -288,7 +287,7 @@ Result ThreadData::writeFuncInternal() {
|
|||||||
this->write_offset += size;
|
this->write_offset += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_write("finished write thread!\n");
|
log_write("finished write thread success!\n");
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,21 +307,55 @@ auto GetAlternateCore(int id) {
|
|||||||
return id == 1 ? 2 : 1;
|
return id == 1 ? 2 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result TransferInternal(ui::ProgressBox* pbox, s64 size, ReadCallback rfunc, WriteCallback wfunc, StartCallback2 sfunc) {
|
Result TransferInternal(ui::ProgressBox* pbox, s64 size, ReadCallback rfunc, WriteCallback wfunc, StartCallback2 sfunc, Mode mode, u64 buffer_size = NORMAL_BUFFER_SIZE) {
|
||||||
App::SetAutoSleepDisabled(true);
|
const auto is_file_based_emummc = App::IsFileBaseEmummc();
|
||||||
ON_SCOPE_EXIT(App::SetAutoSleepDisabled(false));
|
|
||||||
|
|
||||||
|
if (is_file_based_emummc) {
|
||||||
|
buffer_size = SMALL_BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == Mode::SingleThreadedIfSmaller) {
|
||||||
|
if (size <= buffer_size) {
|
||||||
|
mode = Mode::SingleThreaded;
|
||||||
|
} else {
|
||||||
|
mode = Mode::MultiThreaded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// single threaded pull buffer is not supported.
|
||||||
|
R_UNLESS(mode != Mode::MultiThreaded || !sfunc, 0x1);
|
||||||
|
|
||||||
|
// todo: support single threaded pull buffer.
|
||||||
|
if (mode == Mode::SingleThreaded) {
|
||||||
|
std::vector<u8> buf(buffer_size);
|
||||||
|
|
||||||
|
s64 offset{};
|
||||||
|
while (offset < size) {
|
||||||
|
R_TRY(pbox->ShouldExitResult());
|
||||||
|
|
||||||
|
u64 bytes_read;
|
||||||
|
const auto rsize = std::min<s64>(buf.size(), size - offset);
|
||||||
|
R_TRY(rfunc(buf.data(), offset, rsize, &bytes_read));
|
||||||
|
R_TRY(wfunc(buf.data(), offset, bytes_read));
|
||||||
|
|
||||||
|
offset += bytes_read;
|
||||||
|
pbox->UpdateTransfer(offset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
else {
|
||||||
const auto WRITE_THREAD_CORE = sfunc ? pbox->GetCpuId() : GetAlternateCore(pbox->GetCpuId());
|
const auto WRITE_THREAD_CORE = sfunc ? pbox->GetCpuId() : GetAlternateCore(pbox->GetCpuId());
|
||||||
const auto READ_THREAD_CORE = GetAlternateCore(WRITE_THREAD_CORE);
|
const auto READ_THREAD_CORE = GetAlternateCore(WRITE_THREAD_CORE);
|
||||||
|
|
||||||
ThreadData t_data{pbox, size, rfunc, wfunc};
|
ThreadData t_data{pbox, size, rfunc, wfunc, buffer_size};
|
||||||
|
|
||||||
Thread t_read{};
|
Thread t_read{};
|
||||||
R_TRY(threadCreate(&t_read, readFunc, std::addressof(t_data), nullptr, 1024*64, PRIO_PREEMPTIVE, READ_THREAD_CORE));
|
R_TRY(threadCreate(&t_read, readFunc, std::addressof(t_data), nullptr, 1024*256, 0x3B, READ_THREAD_CORE));
|
||||||
ON_SCOPE_EXIT(threadClose(&t_read));
|
ON_SCOPE_EXIT(threadClose(&t_read));
|
||||||
|
|
||||||
Thread t_write{};
|
Thread t_write{};
|
||||||
R_TRY(threadCreate(&t_write, writeFunc, std::addressof(t_data), nullptr, 1024*64, PRIO_PREEMPTIVE, WRITE_THREAD_CORE));
|
R_TRY(threadCreate(&t_write, writeFunc, std::addressof(t_data), nullptr, 1024*256, 0x3B, WRITE_THREAD_CORE));
|
||||||
ON_SCOPE_EXIT(threadClose(&t_write));
|
ON_SCOPE_EXIT(threadClose(&t_write));
|
||||||
|
|
||||||
const auto start_threads = [&]() -> Result {
|
const auto start_threads = [&]() -> Result {
|
||||||
@@ -336,12 +369,16 @@ Result TransferInternal(ui::ProgressBox* pbox, s64 size, ReadCallback rfunc, Wri
|
|||||||
ON_SCOPE_EXIT(threadWaitForExit(std::addressof(t_write)));
|
ON_SCOPE_EXIT(threadWaitForExit(std::addressof(t_write)));
|
||||||
|
|
||||||
if (sfunc) {
|
if (sfunc) {
|
||||||
|
log_write("[THREAD] doing sfuncn\n");
|
||||||
t_data.SetPullResult(sfunc(start_threads, [&](void* data, s64 size, u64* bytes_read) -> Result {
|
t_data.SetPullResult(sfunc(start_threads, [&](void* data, s64 size, u64* bytes_read) -> Result {
|
||||||
R_TRY(t_data.GetResults());
|
R_TRY(t_data.GetResults());
|
||||||
return t_data.Pull(data, size, bytes_read);
|
return t_data.Pull(data, size, bytes_read);
|
||||||
}));
|
}));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
|
log_write("[THREAD] doing normal\n");
|
||||||
R_TRY(start_threads());
|
R_TRY(start_threads());
|
||||||
|
log_write("[THREAD] started threads\n");
|
||||||
|
|
||||||
while (t_data.GetWriteOffset() != t_data.GetWriteSize() && R_SUCCEEDED(t_data.GetResults())) {
|
while (t_data.GetWriteOffset() != t_data.GetWriteSize() && R_SUCCEEDED(t_data.GetResults())) {
|
||||||
pbox->UpdateTransfer(t_data.GetWriteOffset(), t_data.GetWriteSize());
|
pbox->UpdateTransfer(t_data.GetWriteOffset(), t_data.GetWriteSize());
|
||||||
@@ -371,24 +408,174 @@ Result TransferInternal(ui::ProgressBox* pbox, s64 size, ReadCallback rfunc, Wri
|
|||||||
return t_data.GetResults();
|
return t_data.GetResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_write("returning from thread func\n");
|
||||||
return t_data.GetResults();
|
return t_data.GetResults();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Result Transfer(ui::ProgressBox* pbox, s64 size, ReadCallback rfunc, WriteCallback wfunc) {
|
Result Transfer(ui::ProgressBox* pbox, s64 size, ReadCallback rfunc, WriteCallback wfunc, Mode mode) {
|
||||||
return TransferInternal(pbox, size, rfunc, wfunc, nullptr);
|
return TransferInternal(pbox, size, rfunc, wfunc, nullptr, Mode::MultiThreaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result TransferPull(ui::ProgressBox* pbox, s64 size, ReadCallback rfunc, StartCallback sfunc) {
|
Result TransferPull(ui::ProgressBox* pbox, s64 size, ReadCallback rfunc, StartCallback sfunc, Mode mode) {
|
||||||
return TransferInternal(pbox, size, rfunc, nullptr, [sfunc](StartThreadCallback start, PullCallback pull) -> Result {
|
return TransferInternal(pbox, size, rfunc, nullptr, [sfunc](StartThreadCallback start, PullCallback pull) -> Result {
|
||||||
R_TRY(start());
|
R_TRY(start());
|
||||||
return sfunc(pull);
|
return sfunc(pull);
|
||||||
});
|
}, Mode::MultiThreaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result TransferPull(ui::ProgressBox* pbox, s64 size, ReadCallback rfunc, StartCallback2 sfunc) {
|
Result TransferPull(ui::ProgressBox* pbox, s64 size, ReadCallback rfunc, StartCallback2 sfunc, Mode mode) {
|
||||||
return TransferInternal(pbox, size, rfunc, nullptr, sfunc);
|
return TransferInternal(pbox, size, rfunc, nullptr, sfunc, Mode::MultiThreaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result TransferUnzip(ui::ProgressBox* pbox, void* zfile, fs::Fs* fs, const fs::FsPath& path, s64 size, u32 crc32) {
|
||||||
|
Result rc;
|
||||||
|
if (R_FAILED(rc = fs->CreateDirectoryRecursivelyWithPath(path)) && rc != FsError_PathAlreadyExists) {
|
||||||
|
log_write("failed to create folder: %s 0x%04X\n", path.s, rc);
|
||||||
|
R_THROW(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (R_FAILED(rc = fs->CreateFile(path, size, 0)) && rc != FsError_PathAlreadyExists) {
|
||||||
|
log_write("failed to create file: %s 0x%04X\n", path.s, rc);
|
||||||
|
R_THROW(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::File f;
|
||||||
|
R_TRY(fs->OpenFile(path, FsOpenMode_Write, &f));
|
||||||
|
|
||||||
|
// only update the size if this is an existing file.
|
||||||
|
if (rc == FsError_PathAlreadyExists) {
|
||||||
|
R_TRY(f.SetSize(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTES: do not use temp file with rename / delete after as it massively slows
|
||||||
|
// down small file transfers (RA 21s -> 50s).
|
||||||
|
u32 crc32_out{};
|
||||||
|
R_TRY(thread::TransferInternal(pbox, size,
|
||||||
|
[&](void* data, s64 off, s64 size, u64* bytes_read) -> Result {
|
||||||
|
const auto result = unzReadCurrentFile(zfile, data, size);
|
||||||
|
if (result <= 0) {
|
||||||
|
log_write("failed to read zip file: %s %d\n", path.s, result);
|
||||||
|
R_THROW(0x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crc32) {
|
||||||
|
crc32_out = crc32CalculateWithSeed(crc32_out, data, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
*bytes_read = result;
|
||||||
|
R_SUCCEED();
|
||||||
|
},
|
||||||
|
[&](const void* data, s64 off, s64 size) -> Result {
|
||||||
|
return f.Write(off, data, size, FsWriteOption_None);
|
||||||
|
},
|
||||||
|
nullptr, Mode::SingleThreadedIfSmaller, SMALL_BUFFER_SIZE
|
||||||
|
));
|
||||||
|
|
||||||
|
// validate crc32 (if set in the info).
|
||||||
|
R_UNLESS(!crc32 || crc32 == crc32_out, 0x8);
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result TransferZip(ui::ProgressBox* pbox, void* zfile, fs::Fs* fs, const fs::FsPath& path, u32* crc32) {
|
||||||
|
fs::File f;
|
||||||
|
R_TRY(fs->OpenFile(path, FsOpenMode_Read, &f));
|
||||||
|
|
||||||
|
s64 file_size;
|
||||||
|
R_TRY(f.GetSize(&file_size));
|
||||||
|
|
||||||
|
if (crc32) {
|
||||||
|
*crc32 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return thread::TransferInternal(pbox, file_size,
|
||||||
|
[&](void* data, s64 off, s64 size, u64* bytes_read) -> Result {
|
||||||
|
const auto rc = f.Read(off, data, size, FsReadOption_None, bytes_read);
|
||||||
|
if (R_SUCCEEDED(rc) && crc32) {
|
||||||
|
*crc32 = crc32CalculateWithSeed(*crc32, data, *bytes_read);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
},
|
||||||
|
[&](const void* data, s64 off, s64 size) -> Result {
|
||||||
|
if (ZIP_OK != zipWriteInFileInZip(zfile, data, size)) {
|
||||||
|
log_write("failed to write zip file: %s\n", path.s);
|
||||||
|
R_THROW(0x1);
|
||||||
|
}
|
||||||
|
R_SUCCEED();
|
||||||
|
},
|
||||||
|
nullptr, Mode::SingleThreadedIfSmaller, SMALL_BUFFER_SIZE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result TransferUnzipAll(ui::ProgressBox* pbox, void* zfile, fs::Fs* fs, const fs::FsPath& base_path, UnzipAllFilter filter) {
|
||||||
|
unz_global_info64 ginfo;
|
||||||
|
if (UNZ_OK != unzGetGlobalInfo64(zfile, &ginfo)) {
|
||||||
|
R_THROW(0x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UNZ_OK != unzGoToFirstFile(zfile)) {
|
||||||
|
R_THROW(0x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s64 i = 0; i < ginfo.number_entry; i++) {
|
||||||
|
R_TRY(pbox->ShouldExitResult());
|
||||||
|
|
||||||
|
if (i > 0) {
|
||||||
|
if (UNZ_OK != unzGoToNextFile(zfile)) {
|
||||||
|
log_write("failed to unzGoToNextFile\n");
|
||||||
|
R_THROW(0x1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UNZ_OK != unzOpenCurrentFile(zfile)) {
|
||||||
|
log_write("failed to open current file\n");
|
||||||
|
R_THROW(0x1);
|
||||||
|
}
|
||||||
|
ON_SCOPE_EXIT(unzCloseCurrentFile(zfile));
|
||||||
|
|
||||||
|
unz_file_info64 info;
|
||||||
|
fs::FsPath name;
|
||||||
|
if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, name, sizeof(name), 0, 0, 0, 0)) {
|
||||||
|
log_write("failed to get current info\n");
|
||||||
|
R_THROW(0x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we should skip this file.
|
||||||
|
// don't make const as to allow the function to modify the path
|
||||||
|
// this function is used for the updater to change sphaira.nro to exe path.
|
||||||
|
auto path = fs::AppendPath(base_path, name);
|
||||||
|
if (filter && !filter(name, path)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pbox->NewTransfer(name);
|
||||||
|
|
||||||
|
if (path[std::strlen(path) -1] == '/') {
|
||||||
|
Result rc;
|
||||||
|
if (R_FAILED(rc = fs->CreateDirectoryRecursively(path)) && rc != FsError_PathAlreadyExists) {
|
||||||
|
log_write("failed to create folder: %s 0x%04X\n", path.s, rc);
|
||||||
|
R_THROW(rc);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
R_TRY(TransferUnzip(pbox, zfile, fs, path, info.uncompressed_size, info.crc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result TransferUnzipAll(ui::ProgressBox* pbox, const fs::FsPath& zip_out, fs::Fs* fs, const fs::FsPath& base_path, UnzipAllFilter filter) {
|
||||||
|
zlib_filefunc64_def file_func;
|
||||||
|
mz::FileFuncStdio(&file_func);
|
||||||
|
|
||||||
|
auto zfile = unzOpen2_64(zip_out, &file_func);
|
||||||
|
R_UNLESS(zfile, 0x1);
|
||||||
|
ON_SCOPE_EXIT(unzClose(zfile));
|
||||||
|
|
||||||
|
return TransferUnzipAll(pbox, zfile, fs, base_path, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace::thread
|
} // namespace::thread
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
namespace sphaira::ui {
|
namespace sphaira::ui {
|
||||||
|
|
||||||
ErrorBox::ErrorBox(const std::string& message) : m_message{message} {
|
ErrorBox::ErrorBox(const std::string& message) : m_message{message} {
|
||||||
|
log_write("[ERROR] %s\n", m_message.c_str());
|
||||||
|
|
||||||
m_pos.w = 770.f;
|
m_pos.w = 770.f;
|
||||||
m_pos.h = 430.f;
|
m_pos.h = 430.f;
|
||||||
@@ -21,6 +22,7 @@ ErrorBox::ErrorBox(const std::string& message) : m_message{message} {
|
|||||||
|
|
||||||
ErrorBox::ErrorBox(Result code, const std::string& message) : ErrorBox{message} {
|
ErrorBox::ErrorBox(Result code, const std::string& message) : ErrorBox{message} {
|
||||||
m_code = code;
|
m_code = code;
|
||||||
|
log_write("[ERROR] Code: 0x%X Module: %u Description: %u\n", R_VALUE(code), R_MODULE(code), R_DESCRIPTION(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ErrorBox::Update(Controller* controller, TouchInfo* touch) -> void {
|
auto ErrorBox::Update(Controller* controller, TouchInfo* touch) -> void {
|
||||||
|
|||||||
@@ -14,7 +14,10 @@
|
|||||||
#include "swkbd.hpp"
|
#include "swkbd.hpp"
|
||||||
#include "i18n.hpp"
|
#include "i18n.hpp"
|
||||||
#include "hasher.hpp"
|
#include "hasher.hpp"
|
||||||
|
#include "threaded_file_transfer.hpp"
|
||||||
#include "nro.hpp"
|
#include "nro.hpp"
|
||||||
|
#include "web.hpp"
|
||||||
|
#include "minizip_helper.hpp"
|
||||||
|
|
||||||
#include <minIni.h>
|
#include <minIni.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -87,6 +90,12 @@ auto BuildBannerUrl(const Entry& e) -> std::string {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto BuildManifestUrl(const Entry& e) -> std::string {
|
||||||
|
char out[0x100];
|
||||||
|
std::snprintf(out, sizeof(out), "%s/packages/%s/manifest.install", URL_BASE, e.name.c_str());
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
auto BuildZipUrl(const Entry& e) -> std::string {
|
auto BuildZipUrl(const Entry& e) -> std::string {
|
||||||
char out[0x100];
|
char out[0x100];
|
||||||
std::snprintf(out, sizeof(out), "%s/zips/%s.zip", URL_BASE, e.name.c_str());
|
std::snprintf(out, sizeof(out), "%s/zips/%s.zip", URL_BASE, e.name.c_str());
|
||||||
@@ -332,6 +341,7 @@ auto UninstallApp(ProgressBox* pbox, const Entry& entry) -> Result {
|
|||||||
log_write("failed to delete file: %s\n", safe_buf.s);
|
log_write("failed to delete file: %s\n", safe_buf.s);
|
||||||
} else {
|
} else {
|
||||||
log_write("deleted file: %s\n", safe_buf.s);
|
log_write("deleted file: %s\n", safe_buf.s);
|
||||||
|
svcSleepThread(1e+5);
|
||||||
// todo: delete empty directories!
|
// todo: delete empty directories!
|
||||||
// fs::delete_directory(safe_buf);
|
// fs::delete_directory(safe_buf);
|
||||||
}
|
}
|
||||||
@@ -363,19 +373,30 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> Result {
|
|||||||
fs::FsNativeSd fs;
|
fs::FsNativeSd fs;
|
||||||
R_TRY(fs.GetFsOpenResult());
|
R_TRY(fs.GetFsOpenResult());
|
||||||
|
|
||||||
|
// check if we can download the entire zip to mem for faster download / extract times.
|
||||||
|
// current limit is 300MiB, or disabled for applet mode.
|
||||||
|
const auto file_download = App::IsApplet() || entry.filesize >= 1024 * 1024 * 300;
|
||||||
|
curl::ApiResult api_result{};
|
||||||
|
|
||||||
// 1. download the zip
|
// 1. download the zip
|
||||||
if (!pbox->ShouldExit()) {
|
if (!pbox->ShouldExit()) {
|
||||||
pbox->NewTransfer("Downloading "_i18n + entry.title);
|
pbox->NewTransfer("Downloading "_i18n + entry.title);
|
||||||
log_write("starting download\n");
|
log_write("starting download\n");
|
||||||
|
|
||||||
const auto url = BuildZipUrl(entry);
|
const auto url = BuildZipUrl(entry);
|
||||||
const auto result = curl::Api().ToFile(
|
curl::Api api{
|
||||||
curl::Url{url},
|
curl::Url{url},
|
||||||
curl::Path{zip_out},
|
|
||||||
curl::OnProgress{pbox->OnDownloadProgressCallback()}
|
curl::OnProgress{pbox->OnDownloadProgressCallback()}
|
||||||
);
|
};
|
||||||
|
|
||||||
R_UNLESS(result.success, 0x1);
|
if (file_download) {
|
||||||
|
api.SetOption(curl::Path{zip_out});
|
||||||
|
api_result = curl::ToFile(api);
|
||||||
|
} else {
|
||||||
|
api_result = curl::ToMemory(api);
|
||||||
|
}
|
||||||
|
|
||||||
|
R_UNLESS(api_result.success, 0x1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ON_SCOPE_EXIT(fs.DeleteFile(zip_out));
|
ON_SCOPE_EXIT(fs.DeleteFile(zip_out));
|
||||||
@@ -386,7 +407,11 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> Result {
|
|||||||
log_write("starting md5 check\n");
|
log_write("starting md5 check\n");
|
||||||
|
|
||||||
std::string hash_out;
|
std::string hash_out;
|
||||||
|
if (file_download) {
|
||||||
R_TRY(hash::Hash(pbox, hash::Type::Md5, &fs, zip_out, hash_out));
|
R_TRY(hash::Hash(pbox, hash::Type::Md5, &fs, zip_out, hash_out));
|
||||||
|
} else {
|
||||||
|
R_TRY(hash::Hash(pbox, hash::Type::Md5, api_result.data, hash_out));
|
||||||
|
}
|
||||||
|
|
||||||
if (strncasecmp(hash_out.data(), entry.md5.data(), entry.md5.length())) {
|
if (strncasecmp(hash_out.data(), entry.md5.data(), entry.md5.length())) {
|
||||||
log_write("bad md5: %.*s vs %.*s\n", 32, hash_out.data(), 32, entry.md5.c_str());
|
log_write("bad md5: %.*s vs %.*s\n", 32, hash_out.data(), 32, entry.md5.c_str());
|
||||||
@@ -394,9 +419,17 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> Result {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mz::MzSpan mz_span{api_result.data};
|
||||||
|
zlib_filefunc64_def file_func;
|
||||||
|
if (!file_download) {
|
||||||
|
mz::FileFuncSpan(&mz_span, &file_func);
|
||||||
|
} else {
|
||||||
|
mz::FileFuncStdio(&file_func);
|
||||||
|
}
|
||||||
|
|
||||||
// 3. extract the zip
|
// 3. extract the zip
|
||||||
if (!pbox->ShouldExit()) {
|
if (!pbox->ShouldExit()) {
|
||||||
auto zfile = unzOpen64(zip_out);
|
auto zfile = unzOpen2_64(zip_out, &file_func);
|
||||||
R_UNLESS(zfile, 0x1);
|
R_UNLESS(zfile, 0x1);
|
||||||
ON_SCOPE_EXIT(unzClose(zfile));
|
ON_SCOPE_EXIT(unzClose(zfile));
|
||||||
|
|
||||||
@@ -434,43 +467,6 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> Result {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto unzip_to_file = [&](const unz_file_info64& info, const fs::FsPath& inzip, fs::FsPath output) -> Result {
|
|
||||||
if (output[0] != '/') {
|
|
||||||
output = fs::AppendPath("/", output);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create directories
|
|
||||||
fs.CreateDirectoryRecursivelyWithPath(output);
|
|
||||||
|
|
||||||
Result rc;
|
|
||||||
if (R_FAILED(rc = fs.CreateFile(output, info.uncompressed_size, 0)) && rc != FsError_PathAlreadyExists) {
|
|
||||||
log_write("failed to create file: %s 0x%04X\n", output.s, rc);
|
|
||||||
R_THROW(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
fs::File f;
|
|
||||||
R_TRY(fs.OpenFile(output, FsOpenMode_Write, &f));
|
|
||||||
R_TRY(f.SetSize(info.uncompressed_size));
|
|
||||||
|
|
||||||
u64 offset{};
|
|
||||||
while (offset < info.uncompressed_size) {
|
|
||||||
R_TRY(pbox->ShouldExitResult());
|
|
||||||
|
|
||||||
const auto bytes_read = unzReadCurrentFile(zfile, buf.data(), buf.size());
|
|
||||||
if (bytes_read <= 0) {
|
|
||||||
log_write("failed to read zip file: %s\n", inzip.s);
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
R_TRY(f.Write(offset, buf.data(), bytes_read, FsWriteOption_None));
|
|
||||||
|
|
||||||
pbox->UpdateTransfer(offset, info.uncompressed_size);
|
|
||||||
offset += bytes_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto unzip_to = [&](const fs::FsPath& inzip, const fs::FsPath& output) -> Result {
|
const auto unzip_to = [&](const fs::FsPath& inzip, const fs::FsPath& output) -> Result {
|
||||||
pbox->NewTransfer(inzip);
|
pbox->NewTransfer(inzip);
|
||||||
|
|
||||||
@@ -491,48 +487,28 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> Result {
|
|||||||
R_THROW(0x1);
|
R_THROW(0x1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return unzip_to_file(info, inzip, output);
|
auto path = output;
|
||||||
|
if (path[0] != '/') {
|
||||||
|
path = fs::AppendPath("/", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return thread::TransferUnzip(pbox, zfile, &fs, path, info.uncompressed_size, info.crc);
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto unzip_all = [&](std::span<const ManifestEntry> entries) -> Result {
|
// unzip manifest, info and all entries.
|
||||||
unz_global_info64 ginfo;
|
TimeStamp ts;
|
||||||
if (UNZ_OK != unzGetGlobalInfo64(zfile, &ginfo)) {
|
#if 1
|
||||||
R_THROW(0x1);
|
R_TRY(unzip_to("info.json", BuildInfoCachePath(entry)));
|
||||||
}
|
R_TRY(unzip_to("manifest.install", BuildManifestCachePath(entry)));
|
||||||
|
#endif
|
||||||
|
|
||||||
if (UNZ_OK != unzGoToFirstFile(zfile)) {
|
R_TRY(thread::TransferUnzipAll(pbox, zfile, &fs, "/", [&](const fs::FsPath& name, fs::FsPath& path) -> bool {
|
||||||
R_THROW(0x1);
|
const auto it = std::ranges::find_if(new_manifest, [&name](auto& e){
|
||||||
}
|
|
||||||
|
|
||||||
for (s64 i = 0; i < ginfo.number_entry; i++) {
|
|
||||||
R_TRY(pbox->ShouldExitResult());
|
|
||||||
|
|
||||||
if (i > 0) {
|
|
||||||
if (UNZ_OK != unzGoToNextFile(zfile)) {
|
|
||||||
log_write("failed to unzGoToNextFile\n");
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UNZ_OK != unzOpenCurrentFile(zfile)) {
|
|
||||||
log_write("failed to open current file\n");
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
ON_SCOPE_EXIT(unzCloseCurrentFile(zfile));
|
|
||||||
|
|
||||||
unz_file_info64 info;
|
|
||||||
char name[512];
|
|
||||||
if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, name, sizeof(name), 0, 0, 0, 0)) {
|
|
||||||
log_write("failed to get current info\n");
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto it = std::ranges::find_if(entries, [&name](auto& e){
|
|
||||||
return !strcasecmp(name, e.path);
|
return !strcasecmp(name, e.path);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (it == entries.end()) [[unlikely]] {
|
if (it == new_manifest.end()) [[unlikely]] {
|
||||||
continue;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pbox->NewTransfer(it->path);
|
pbox->NewTransfer(it->path);
|
||||||
@@ -540,30 +516,17 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> Result {
|
|||||||
switch (it->command) {
|
switch (it->command) {
|
||||||
case 'E': // both are the same?
|
case 'E': // both are the same?
|
||||||
case 'U':
|
case 'U':
|
||||||
break;
|
return true;
|
||||||
|
|
||||||
case 'G': { // checks if file exists, if not, extract
|
case 'G': // checks if file exists, if not, extract
|
||||||
if (fs.FileExists(fs::AppendPath("/", it->path))) {
|
return !fs.FileExists(fs::AppendPath("/", it->path));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log_write("bad command: %c\n", it->command);
|
log_write("bad command: %c\n", it->command);
|
||||||
continue;
|
return false;
|
||||||
}
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
R_TRY(unzip_to_file(info, it->path, it->path));
|
|
||||||
}
|
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
};
|
|
||||||
|
|
||||||
// unzip manifest, info and all entries.
|
|
||||||
TimeStamp ts;
|
|
||||||
R_TRY(unzip_to("info.json", BuildInfoCachePath(entry)));
|
|
||||||
R_TRY(unzip_to("manifest.install", BuildManifestCachePath(entry)));
|
|
||||||
R_TRY(unzip_all(new_manifest));
|
|
||||||
log_write("\n\t[APPSTORE] finished extract new, time taken: %.2fs %zums\n\n", ts.GetSecondsD(), ts.GetMs());
|
log_write("\n\t[APPSTORE] finished extract new, time taken: %.2fs %zums\n\n", ts.GetSecondsD(), ts.GetMs());
|
||||||
|
|
||||||
// finally finally, remove files no longer in the manifest
|
// finally finally, remove files no longer in the manifest
|
||||||
@@ -583,6 +546,7 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> Result {
|
|||||||
log_write("failed to delete: %s\n", safe_buf.s);
|
log_write("failed to delete: %s\n", safe_buf.s);
|
||||||
} else {
|
} else {
|
||||||
log_write("deleted file: %s\n", safe_buf.s);
|
log_write("deleted file: %s\n", safe_buf.s);
|
||||||
|
svcSleepThread(1e+5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -621,12 +585,15 @@ EntryMenu::EntryMenu(Entry& entry, const LazyImage& default_icon, Menu& menu)
|
|||||||
}
|
}
|
||||||
}}),
|
}}),
|
||||||
std::make_pair(Button::X, Action{"Options"_i18n, [this](){
|
std::make_pair(Button::X, Action{"Options"_i18n, [this](){
|
||||||
auto sidebar = std::make_shared<Sidebar>("Options"_i18n, Sidebar::Side::RIGHT);
|
auto options = std::make_shared<Sidebar>("Options"_i18n, Sidebar::Side::RIGHT);
|
||||||
sidebar->Add(std::make_shared<SidebarEntryCallback>("More by Author"_i18n, [this](){
|
ON_SCOPE_EXIT(App::Push(options));
|
||||||
|
|
||||||
|
options->Add(std::make_shared<SidebarEntryCallback>("More by Author"_i18n, [this](){
|
||||||
m_menu.SetAuthor();
|
m_menu.SetAuthor();
|
||||||
SetPop();
|
SetPop();
|
||||||
}, true));
|
}, true));
|
||||||
sidebar->Add(std::make_shared<SidebarEntryCallback>("Leave Feedback"_i18n, [this](){
|
|
||||||
|
options->Add(std::make_shared<SidebarEntryCallback>("Leave Feedback"_i18n, [this](){
|
||||||
std::string out;
|
std::string out;
|
||||||
if (R_SUCCEEDED(swkbd::ShowText(out)) && !out.empty()) {
|
if (R_SUCCEEDED(swkbd::ShowText(out)) && !out.empty()) {
|
||||||
const auto post = "name=" "switch_user" "&package=" + m_entry.name + "&message=" + out;
|
const auto post = "name=" "switch_user" "&package=" + m_entry.name + "&message=" + out;
|
||||||
@@ -647,10 +614,44 @@ EntryMenu::EntryMenu(Entry& entry, const LazyImage& default_icon, Menu& menu)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, true));
|
}, true));
|
||||||
App::Push(sidebar);
|
|
||||||
|
if (App::IsApplication() && !m_entry.url.empty()) {
|
||||||
|
options->Add(std::make_shared<SidebarEntryCallback>("Visit Website"_i18n, [this](){
|
||||||
|
WebShow(m_entry.url);
|
||||||
|
}));
|
||||||
|
}
|
||||||
}}),
|
}}),
|
||||||
std::make_pair(Button::B, Action{"Back"_i18n, [this](){
|
std::make_pair(Button::B, Action{"Back"_i18n, [this](){
|
||||||
SetPop();
|
SetPop();
|
||||||
|
}}),
|
||||||
|
std::make_pair(Button::L2, Action{"Files"_i18n, [this](){
|
||||||
|
m_show_file_list ^= 1;
|
||||||
|
|
||||||
|
if (m_show_file_list && !m_manifest_list && m_file_list_state == ImageDownloadState::None) {
|
||||||
|
m_file_list_state = ImageDownloadState::Progress;
|
||||||
|
const auto path = BuildManifestCachePath(m_entry);
|
||||||
|
std::vector<u8> data;
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(fs::read_entire_file(path, data))) {
|
||||||
|
m_file_list_state = ImageDownloadState::Done;
|
||||||
|
data.push_back('\0');
|
||||||
|
m_manifest_list = std::make_unique<ScrollableText>((const char*)data.data(), 0, 374, 250, 768, 18);
|
||||||
|
} else {
|
||||||
|
curl::Api().ToMemoryAsync(
|
||||||
|
curl::Url{BuildManifestUrl(m_entry)},
|
||||||
|
curl::StopToken{this->GetToken()},
|
||||||
|
curl::OnComplete{[this](auto& result){
|
||||||
|
if (result.success) {
|
||||||
|
m_file_list_state = ImageDownloadState::Done;
|
||||||
|
result.data.push_back('\0');
|
||||||
|
m_manifest_list = std::make_unique<ScrollableText>((const char*)result.data.data(), 0, 374, 250, 768, 18);
|
||||||
|
} else {
|
||||||
|
m_file_list_state = ImageDownloadState::Failed;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}})
|
}})
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -699,7 +700,13 @@ EntryMenu::~EntryMenu() {
|
|||||||
void EntryMenu::Update(Controller* controller, TouchInfo* touch) {
|
void EntryMenu::Update(Controller* controller, TouchInfo* touch) {
|
||||||
MenuBase::Update(controller, touch);
|
MenuBase::Update(controller, touch);
|
||||||
|
|
||||||
|
if (m_show_file_list) {
|
||||||
|
if (m_manifest_list) {
|
||||||
|
m_manifest_list->Update(controller, touch);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
m_detail_changelog->Update(controller, touch);
|
m_detail_changelog->Update(controller, touch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntryMenu::Draw(NVGcontext* vg, Theme* theme) {
|
void EntryMenu::Draw(NVGcontext* vg, Theme* theme) {
|
||||||
@@ -754,12 +761,24 @@ void EntryMenu::Draw(NVGcontext* vg, Theme* theme) {
|
|||||||
y -= block.h + 18;
|
y -= block.h + 18;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_show_file_list) {
|
||||||
|
if (m_manifest_list) {
|
||||||
|
m_manifest_list->Draw(vg, theme);
|
||||||
|
} else if (m_file_list_state == ImageDownloadState::Progress) {
|
||||||
|
gfx::drawText(vg, 110, 374, 18, theme->GetColour(ThemeEntryID_TEXT), "Loading..."_i18n.c_str());
|
||||||
|
} else if (m_file_list_state == ImageDownloadState::Failed) {
|
||||||
|
gfx::drawText(vg, 110, 374, 18, theme->GetColour(ThemeEntryID_TEXT), "Failed to download manifest"_i18n.c_str());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
m_detail_changelog->Draw(vg, theme);
|
m_detail_changelog->Draw(vg, theme);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntryMenu::ShowChangelogAction() {
|
void EntryMenu::ShowChangelogAction() {
|
||||||
std::function<void()> func = std::bind(&EntryMenu::ShowChangelogAction, this);
|
std::function<void()> func = std::bind(&EntryMenu::ShowChangelogAction, this);
|
||||||
m_show_changlog ^= 1;
|
m_show_changlog ^= 1;
|
||||||
|
m_show_file_list = false;
|
||||||
|
|
||||||
|
|
||||||
if (m_show_changlog) {
|
if (m_show_changlog) {
|
||||||
SetAction(Button::L, Action{"Details"_i18n, func});
|
SetAction(Button::L, Action{"Details"_i18n, func});
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "hasher.hpp"
|
#include "hasher.hpp"
|
||||||
#include "location.hpp"
|
#include "location.hpp"
|
||||||
#include "threaded_file_transfer.hpp"
|
#include "threaded_file_transfer.hpp"
|
||||||
|
#include "minizip_helper.hpp"
|
||||||
|
|
||||||
#include "yati/yati.hpp"
|
#include "yati/yati.hpp"
|
||||||
#include "yati/source/file.hpp"
|
#include "yati/source/file.hpp"
|
||||||
@@ -435,7 +436,6 @@ FsView::~FsView() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FsView::Update(Controller* controller, TouchInfo* touch) {
|
void FsView::Update(Controller* controller, TouchInfo* touch) {
|
||||||
Widget::Update(controller, touch);
|
|
||||||
m_list->OnUpdate(controller, touch, m_index, m_entries_current.size(), [this](bool touch, auto i) {
|
m_list->OnUpdate(controller, touch, m_index, m_entries_current.size(), [this](bool touch, auto i) {
|
||||||
if (touch && m_index == i) {
|
if (touch && m_index == i) {
|
||||||
FireAction(Button::A);
|
FireAction(Button::A);
|
||||||
@@ -561,7 +561,7 @@ void FsView::SetSide(ViewSide side) {
|
|||||||
if (m_menu->IsSplitScreen()) {
|
if (m_menu->IsSplitScreen()) {
|
||||||
if (m_side == ViewSide::Left) {
|
if (m_side == ViewSide::Left) {
|
||||||
this->SetW(pos.w / 2 - pos.x / 2);
|
this->SetW(pos.w / 2 - pos.x / 2);
|
||||||
this->SetX(pos.x / 2);
|
this->SetX(pos.x / 2 + 20.f);
|
||||||
} else if (m_side == ViewSide::Right) {
|
} else if (m_side == ViewSide::Right) {
|
||||||
this->SetW(pos.w / 2 - pos.x / 2);
|
this->SetW(pos.w / 2 - pos.x / 2);
|
||||||
this->SetX(pos.x / 2 + SCREEN_WIDTH / 2);
|
this->SetX(pos.x / 2 + SCREEN_WIDTH / 2);
|
||||||
@@ -571,7 +571,7 @@ void FsView::SetSide(ViewSide side) {
|
|||||||
v.w -= v.x / 2;
|
v.w -= v.x / 2;
|
||||||
|
|
||||||
if (m_side == ViewSide::Left) {
|
if (m_side == ViewSide::Left) {
|
||||||
v.x = v.x / 2;
|
v.x = v.x / 2 + 20.f;
|
||||||
} else if (m_side == ViewSide::Right) {
|
} else if (m_side == ViewSide::Right) {
|
||||||
v.x = v.x / 2 + SCREEN_WIDTH / 2;
|
v.x = v.x / 2 + SCREEN_WIDTH / 2;
|
||||||
}
|
}
|
||||||
@@ -671,7 +671,19 @@ void FsView::InstallForwarder() {
|
|||||||
config.icon = GetRomIcon(m_fs.get(), pbox, file_name, db_indexs, nro);
|
config.icon = GetRomIcon(m_fs.get(), pbox, file_name, db_indexs, nro);
|
||||||
pbox->SetImageDataConst(config.icon);
|
pbox->SetImageDataConst(config.icon);
|
||||||
|
|
||||||
|
if (!db_indexs.empty()) {
|
||||||
|
fs::FsNativeSd().read_entire_file("/config/sphaira/logo/rom/NintendoLogo.png", config.logo);
|
||||||
|
fs::FsNativeSd().read_entire_file("/config/sphaira/logo/rom/StartupMovie.gif", config.gif);
|
||||||
|
}
|
||||||
|
|
||||||
return App::Install(pbox, config);
|
return App::Install(pbox, config);
|
||||||
|
}, [this](Result rc){
|
||||||
|
App::PushErrorBox(rc, "Failed to install forwarder"_i18n);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
App::PlaySoundEffect(SoundEffect_Install);
|
||||||
|
App::Notify("Installed!"_i18n);
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
log_write("pressed B to skip launch...\n");
|
log_write("pressed B to skip launch...\n");
|
||||||
@@ -694,6 +706,8 @@ void FsView::InstallFiles() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
|
}, [this](Result rc){
|
||||||
|
App::PushErrorBox(rc, "File install failed!"_i18n);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@@ -708,75 +722,10 @@ void FsView::UnzipFiles(fs::FsPath dir_path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
App::Push(std::make_shared<ui::ProgressBox>(0, "Extracting "_i18n, "", [this, dir_path, targets](auto pbox) -> Result {
|
App::Push(std::make_shared<ui::ProgressBox>(0, "Extracting "_i18n, "", [this, dir_path, targets](auto pbox) -> Result {
|
||||||
constexpr auto chunk_size = 1024 * 512; // 512KiB
|
|
||||||
|
|
||||||
for (auto& e : targets) {
|
for (auto& e : targets) {
|
||||||
pbox->SetTitle(e.GetName());
|
pbox->SetTitle(e.GetName());
|
||||||
|
|
||||||
const auto zip_out = GetNewPath(e);
|
const auto zip_out = GetNewPath(e);
|
||||||
auto zfile = unzOpen64(zip_out);
|
R_TRY(thread::TransferUnzipAll(pbox, zip_out, m_fs.get(), dir_path));
|
||||||
R_UNLESS(zfile, 0x1);
|
|
||||||
ON_SCOPE_EXIT(unzClose(zfile));
|
|
||||||
|
|
||||||
unz_global_info64 pglobal_info;
|
|
||||||
if (UNZ_OK != unzGetGlobalInfo64(zfile, &pglobal_info)) {
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (s64 i = 0; i < pglobal_info.number_entry; i++) {
|
|
||||||
if (i > 0) {
|
|
||||||
if (UNZ_OK != unzGoToNextFile(zfile)) {
|
|
||||||
log_write("failed to unzGoToNextFile\n");
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UNZ_OK != unzOpenCurrentFile(zfile)) {
|
|
||||||
log_write("failed to open current file\n");
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
ON_SCOPE_EXIT(unzCloseCurrentFile(zfile));
|
|
||||||
|
|
||||||
unz_file_info64 info;
|
|
||||||
char name[512];
|
|
||||||
if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, name, sizeof(name), 0, 0, 0, 0)) {
|
|
||||||
log_write("failed to get current info\n");
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto file_path = fs::AppendPath(dir_path, name);
|
|
||||||
pbox->NewTransfer(name);
|
|
||||||
|
|
||||||
// create directories
|
|
||||||
m_fs->CreateDirectoryRecursivelyWithPath(file_path);
|
|
||||||
|
|
||||||
Result rc;
|
|
||||||
if (R_FAILED(rc = m_fs->CreateFile(file_path, info.uncompressed_size, 0)) && rc != FsError_PathAlreadyExists) {
|
|
||||||
log_write("failed to create file: %s 0x%04X\n", file_path.s, rc);
|
|
||||||
R_THROW(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
fs::File f;
|
|
||||||
R_TRY(m_fs->OpenFile(file_path, FsOpenMode_Write, &f));
|
|
||||||
R_TRY(f.SetSize(info.uncompressed_size));
|
|
||||||
|
|
||||||
std::vector<char> buf(chunk_size);
|
|
||||||
s64 offset{};
|
|
||||||
while (offset < info.uncompressed_size) {
|
|
||||||
R_TRY(pbox->ShouldExitResult());
|
|
||||||
|
|
||||||
const auto bytes_read = unzReadCurrentFile(zfile, buf.data(), buf.size());
|
|
||||||
if (bytes_read <= 0) {
|
|
||||||
log_write("failed to read zip file: %s\n", name);
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
R_TRY(f.Write(offset, buf.data(), bytes_read, FsWriteOption_None));
|
|
||||||
|
|
||||||
pbox->UpdateTransfer(offset, info.uncompressed_size);
|
|
||||||
offset += bytes_read;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
@@ -784,7 +733,7 @@ void FsView::UnzipFiles(fs::FsPath dir_path) {
|
|||||||
App::PushErrorBox(rc, "Extract failed!"_i18n);
|
App::PushErrorBox(rc, "Extract failed!"_i18n);
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
App::Notify("Extract success!");
|
App::Notify("Extract success!"_i18n);
|
||||||
}
|
}
|
||||||
|
|
||||||
Scan(m_path);
|
Scan(m_path);
|
||||||
@@ -829,8 +778,6 @@ void FsView::ZipFiles(fs::FsPath zip_out) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
App::Push(std::make_shared<ui::ProgressBox>(0, "Compressing "_i18n, "", [this, zip_out, targets](auto pbox) -> Result {
|
App::Push(std::make_shared<ui::ProgressBox>(0, "Compressing "_i18n, "", [this, zip_out, targets](auto pbox) -> Result {
|
||||||
constexpr auto chunk_size = 1024 * 512; // 512KiB
|
|
||||||
|
|
||||||
const auto t = std::time(NULL);
|
const auto t = std::time(NULL);
|
||||||
const auto tm = std::localtime(&t);
|
const auto tm = std::localtime(&t);
|
||||||
|
|
||||||
@@ -843,7 +790,10 @@ void FsView::ZipFiles(fs::FsPath zip_out) {
|
|||||||
zip_info.tmz_date.tm_mon = tm->tm_mon;
|
zip_info.tmz_date.tm_mon = tm->tm_mon;
|
||||||
zip_info.tmz_date.tm_year = tm->tm_year;
|
zip_info.tmz_date.tm_year = tm->tm_year;
|
||||||
|
|
||||||
auto zfile = zipOpen(zip_out, APPEND_STATUS_CREATE);
|
zlib_filefunc64_def file_func;
|
||||||
|
mz::FileFuncStdio(&file_func);
|
||||||
|
|
||||||
|
auto zfile = zipOpen2_64(zip_out, APPEND_STATUS_CREATE, nullptr, &file_func);
|
||||||
R_UNLESS(zfile, 0x1);
|
R_UNLESS(zfile, 0x1);
|
||||||
ON_SCOPE_EXIT(zipClose(zfile, "sphaira v" APP_VERSION_HASH));
|
ON_SCOPE_EXIT(zipClose(zfile, "sphaira v" APP_VERSION_HASH));
|
||||||
|
|
||||||
@@ -851,6 +801,11 @@ void FsView::ZipFiles(fs::FsPath zip_out) {
|
|||||||
// the file name needs to be relative to the current directory.
|
// the file name needs to be relative to the current directory.
|
||||||
const char* file_name_in_zip = file_path.s + std::strlen(m_path);
|
const char* file_name_in_zip = file_path.s + std::strlen(m_path);
|
||||||
|
|
||||||
|
// strip root path (/ or ums0:)
|
||||||
|
if (!std::strncmp(file_name_in_zip, m_fs->Root(), std::strlen(m_fs->Root()))) {
|
||||||
|
file_name_in_zip += std::strlen(m_fs->Root());
|
||||||
|
}
|
||||||
|
|
||||||
// root paths are banned in zips, they will warn when extracting otherwise.
|
// root paths are banned in zips, they will warn when extracting otherwise.
|
||||||
if (file_name_in_zip[0] == '/') {
|
if (file_name_in_zip[0] == '/') {
|
||||||
file_name_in_zip++;
|
file_name_in_zip++;
|
||||||
@@ -858,38 +813,13 @@ void FsView::ZipFiles(fs::FsPath zip_out) {
|
|||||||
|
|
||||||
pbox->NewTransfer(file_name_in_zip);
|
pbox->NewTransfer(file_name_in_zip);
|
||||||
|
|
||||||
const auto ext = std::strrchr(file_name_in_zip, '.');
|
if (ZIP_OK != zipOpenNewFileInZip(zfile, file_name_in_zip, &zip_info, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION)) {
|
||||||
const auto raw = ext && IsExtension(ext + 1, COMPRESSED_EXTENSIONS);
|
log_write("failed to add zip for %s\n", file_path.s);
|
||||||
|
|
||||||
if (ZIP_OK != zipOpenNewFileInZip2(zfile, file_name_in_zip, &zip_info, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION, raw)) {
|
|
||||||
R_THROW(0x1);
|
R_THROW(0x1);
|
||||||
}
|
}
|
||||||
ON_SCOPE_EXIT(zipCloseFileInZip(zfile));
|
ON_SCOPE_EXIT(zipCloseFileInZip(zfile));
|
||||||
|
|
||||||
fs::File f;
|
return thread::TransferZip(pbox, zfile, m_fs.get(), file_path);
|
||||||
R_TRY(m_fs->OpenFile(file_path, FsOpenMode_Read, &f));
|
|
||||||
|
|
||||||
s64 file_size;
|
|
||||||
R_TRY(f.GetSize(&file_size));
|
|
||||||
|
|
||||||
std::vector<char> buf(chunk_size);
|
|
||||||
s64 offset{};
|
|
||||||
while (offset < file_size) {
|
|
||||||
R_TRY(pbox->ShouldExitResult());
|
|
||||||
|
|
||||||
u64 bytes_read;
|
|
||||||
R_TRY(f.Read(offset, buf.data(), buf.size(), FsReadOption_None, &bytes_read));
|
|
||||||
|
|
||||||
if (ZIP_OK != zipWriteInFileInZip(zfile, buf.data(), bytes_read)) {
|
|
||||||
log_write("failed to write zip file: %s\n", file_path.s);
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
pbox->UpdateTransfer(offset, file_size);
|
|
||||||
offset += bytes_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto& e : targets) {
|
for (auto& e : targets) {
|
||||||
@@ -915,7 +845,7 @@ void FsView::ZipFiles(fs::FsPath zip_out) {
|
|||||||
App::PushErrorBox(rc, "Compress failed!"_i18n);
|
App::PushErrorBox(rc, "Compress failed!"_i18n);
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
App::Notify("Compress success!");
|
App::Notify("Compress success!"_i18n);
|
||||||
}
|
}
|
||||||
|
|
||||||
Scan(m_path);
|
Scan(m_path);
|
||||||
@@ -1498,9 +1428,11 @@ static Result DeleteAllCollections(ProgressBox* pbox, fs::Fs* fs, const Selected
|
|||||||
if ((mode & FsDirOpenMode_ReadDirs) && p.type == FsDirEntryType_Dir) {
|
if ((mode & FsDirOpenMode_ReadDirs) && p.type == FsDirEntryType_Dir) {
|
||||||
log_write("deleting dir: %s\n", full_path.s);
|
log_write("deleting dir: %s\n", full_path.s);
|
||||||
R_TRY(fs->DeleteDirectory(full_path));
|
R_TRY(fs->DeleteDirectory(full_path));
|
||||||
|
svcSleepThread(1e+5);
|
||||||
} else if ((mode & FsDirOpenMode_ReadFiles) && p.type == FsDirEntryType_File) {
|
} else if ((mode & FsDirOpenMode_ReadFiles) && p.type == FsDirEntryType_File) {
|
||||||
log_write("deleting file: %s\n", full_path.s);
|
log_write("deleting file: %s\n", full_path.s);
|
||||||
R_TRY(fs->DeleteFile(full_path));
|
R_TRY(fs->DeleteFile(full_path));
|
||||||
|
svcSleepThread(1e+5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1925,6 +1857,13 @@ Menu::~Menu() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Menu::Update(Controller* controller, TouchInfo* touch) {
|
void Menu::Update(Controller* controller, TouchInfo* touch) {
|
||||||
|
// workaround the buttons not being display properly.
|
||||||
|
// basically, inherit all actions from the view, draw them,
|
||||||
|
// then restore state after.
|
||||||
|
const auto actions_copy = GetActions();
|
||||||
|
ON_SCOPE_EXIT(m_actions = actions_copy);
|
||||||
|
m_actions.insert_range(view->GetActions());
|
||||||
|
|
||||||
MenuBase::Update(controller, touch);
|
MenuBase::Update(controller, touch);
|
||||||
view->Update(controller, touch);
|
view->Update(controller, touch);
|
||||||
}
|
}
|
||||||
@@ -1944,9 +1883,9 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) {
|
|||||||
view_right->Draw(vg, theme);
|
view_right->Draw(vg, theme);
|
||||||
|
|
||||||
if (view == view_left) {
|
if (view == view_left) {
|
||||||
gfx::drawRect(vg, view_right->GetPos(), nvgRGBA(0, 0, 0, 180), 5);
|
gfx::drawRect(vg, view_right->GetPos(), theme->GetColour(ThemeEntryID_FOCUS), 5);
|
||||||
} else {
|
} else {
|
||||||
gfx::drawRect(vg, view_left->GetPos(), nvgRGBA(0, 0, 0, 180), 5);
|
gfx::drawRect(vg, view_left->GetPos(), theme->GetColour(ThemeEntryID_FOCUS), 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::drawRect(vg, SCREEN_WIDTH/2, GetY(), 1, GetH(), theme->GetColour(ThemeEntryID_LINE));
|
gfx::drawRect(vg, SCREEN_WIDTH/2, GetY(), 1, GetH(), theme->GetColour(ThemeEntryID_LINE));
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "dumper.hpp"
|
#include "dumper.hpp"
|
||||||
#include "defines.hpp"
|
#include "defines.hpp"
|
||||||
#include "i18n.hpp"
|
#include "i18n.hpp"
|
||||||
|
#include "image.hpp"
|
||||||
|
|
||||||
#include "ui/menus/game_menu.hpp"
|
#include "ui/menus/game_menu.hpp"
|
||||||
#include "ui/sidebar.hpp"
|
#include "ui/sidebar.hpp"
|
||||||
@@ -23,6 +24,7 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <minIni.h>
|
#include <minIni.h>
|
||||||
|
#include <nxtc.h>
|
||||||
|
|
||||||
namespace sphaira::ui::menu::game {
|
namespace sphaira::ui::menu::game {
|
||||||
namespace {
|
namespace {
|
||||||
@@ -30,6 +32,34 @@ namespace {
|
|||||||
constexpr int THREAD_PRIO = PRIO_PREEMPTIVE;
|
constexpr int THREAD_PRIO = PRIO_PREEMPTIVE;
|
||||||
constexpr int THREAD_CORE = 1;
|
constexpr int THREAD_CORE = 1;
|
||||||
|
|
||||||
|
// taken from nxtc
|
||||||
|
constexpr u8 g_nacpLangTable[SetLanguage_Total] = {
|
||||||
|
[SetLanguage_JA] = 2,
|
||||||
|
[SetLanguage_ENUS] = 0,
|
||||||
|
[SetLanguage_FR] = 3,
|
||||||
|
[SetLanguage_DE] = 4,
|
||||||
|
[SetLanguage_IT] = 7,
|
||||||
|
[SetLanguage_ES] = 6,
|
||||||
|
[SetLanguage_ZHCN] = 14,
|
||||||
|
[SetLanguage_KO] = 12,
|
||||||
|
[SetLanguage_NL] = 8,
|
||||||
|
[SetLanguage_PT] = 10,
|
||||||
|
[SetLanguage_RU] = 11,
|
||||||
|
[SetLanguage_ZHTW] = 13,
|
||||||
|
[SetLanguage_ENGB] = 1,
|
||||||
|
[SetLanguage_FRCA] = 9,
|
||||||
|
[SetLanguage_ES419] = 5,
|
||||||
|
[SetLanguage_ZHHANS] = 14,
|
||||||
|
[SetLanguage_ZHHANT] = 13,
|
||||||
|
[SetLanguage_PTBR] = 15
|
||||||
|
};
|
||||||
|
|
||||||
|
auto GetNacpLangEntryIndex() -> u8 {
|
||||||
|
SetLanguage lang{SetLanguage_ENUS};
|
||||||
|
nxtcGetCacheLanguage(&lang);
|
||||||
|
return g_nacpLangTable[lang];
|
||||||
|
}
|
||||||
|
|
||||||
constexpr u32 ContentMetaTypeToContentFlag(u8 meta_type) {
|
constexpr u32 ContentMetaTypeToContentFlag(u8 meta_type) {
|
||||||
if (meta_type & 0x80) {
|
if (meta_type & 0x80) {
|
||||||
return 1 << (meta_type - 0x80);
|
return 1 << (meta_type - 0x80);
|
||||||
@@ -284,31 +314,27 @@ void FakeNacpEntry(ThreadResultData& e) {
|
|||||||
// fake the nacp entry
|
// fake the nacp entry
|
||||||
std::strcpy(e.lang.name, "Corrupted");
|
std::strcpy(e.lang.name, "Corrupted");
|
||||||
std::strcpy(e.lang.author, "Corrupted");
|
std::strcpy(e.lang.author, "Corrupted");
|
||||||
std::strcpy(e.display_version, "0.0.0");
|
|
||||||
e.control.reset();
|
e.control.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadControlImage(Entry& e) {
|
bool LoadControlImage(Entry& e) {
|
||||||
if (!e.image && e.control) {
|
if (!e.image && e.control) {
|
||||||
|
ON_SCOPE_EXIT(e.control.reset());
|
||||||
|
|
||||||
TimeStamp ts;
|
TimeStamp ts;
|
||||||
const auto jpeg_size = e.control_size - sizeof(NacpStruct);
|
const auto image = ImageLoadFromMemory({e.control->icon, e.jpeg_size}, ImageFlag_JPEG);
|
||||||
e.image = nvgCreateImageMem(App::GetVg(), 0, e.control->icon, jpeg_size);
|
if (!image.data.empty()) {
|
||||||
e.control.reset();
|
e.image = nvgCreateImageRGBA(App::GetVg(), image.w, image.h, 0, image.data.data());
|
||||||
log_write("\t\t[image load] time taken: %.2fs %zums\n", ts.GetSecondsD(), ts.GetMs());
|
log_write("\t[image load] time taken: %.2fs %zums\n", ts.GetSecondsD(), ts.GetMs());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result LoadControlManual(u64 id, ThreadResultData& data) {
|
Result GetControlPathFromStatus(const NsApplicationContentMetaStatus& status, u64* out_program_id, fs::FsPath* out_path) {
|
||||||
TimeStamp ts;
|
const auto& ee = status;
|
||||||
|
|
||||||
MetaEntries entries;
|
|
||||||
R_TRY(GetMetaEntries(id, entries));
|
|
||||||
R_UNLESS(!entries.empty(), 0x1);
|
|
||||||
|
|
||||||
const auto& ee = entries.back();
|
|
||||||
if (ee.storageID != NcmStorageId_SdCard && ee.storageID != NcmStorageId_BuiltInUser && ee.storageID != NcmStorageId_GameCard) {
|
if (ee.storageID != NcmStorageId_SdCard && ee.storageID != NcmStorageId_BuiltInUser && ee.storageID != NcmStorageId_GameCard) {
|
||||||
return 0x1;
|
return 0x1;
|
||||||
}
|
}
|
||||||
@@ -322,17 +348,28 @@ Result LoadControlManual(u64 id, ThreadResultData& data) {
|
|||||||
NcmContentId content_id;
|
NcmContentId content_id;
|
||||||
R_TRY(ncmContentMetaDatabaseGetContentIdByType(&db, &content_id, &key, NcmContentType_Control));
|
R_TRY(ncmContentMetaDatabaseGetContentIdByType(&db, &content_id, &key, NcmContentType_Control));
|
||||||
|
|
||||||
u64 program_id;
|
R_TRY(ncmContentStorageGetProgramId(&cs, out_program_id, &content_id, FsContentAttributes_All));
|
||||||
R_TRY(ncmContentStorageGetProgramId(&cs, &program_id, &content_id, FsContentAttributes_All));
|
|
||||||
|
|
||||||
|
R_TRY(ncmContentStorageGetPath(&cs, out_path->s, sizeof(*out_path), &content_id));
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result LoadControlManual(u64 id, ThreadResultData& data) {
|
||||||
|
TimeStamp ts;
|
||||||
|
|
||||||
|
MetaEntries entries;
|
||||||
|
R_TRY(GetMetaEntries(id, entries));
|
||||||
|
R_UNLESS(!entries.empty(), 0x1);
|
||||||
|
|
||||||
|
u64 program_id;
|
||||||
fs::FsPath path;
|
fs::FsPath path;
|
||||||
R_TRY(ncmContentStorageGetPath(&cs, path, sizeof(path), &content_id));
|
R_TRY(GetControlPathFromStatus(entries.back(), &program_id, &path));
|
||||||
|
|
||||||
std::vector<u8> icon;
|
std::vector<u8> icon;
|
||||||
R_TRY(nca::ParseControl(path, program_id, &data.control->nacp, sizeof(data.control->nacp), &icon));
|
R_TRY(nca::ParseControl(path, program_id, &data.control->nacp.lang[GetNacpLangEntryIndex()], sizeof(NacpLanguageEntry), &icon));
|
||||||
std::memcpy(data.control->icon, icon.data(), icon.size());
|
std::memcpy(data.control->icon, icon.data(), icon.size());
|
||||||
|
|
||||||
data.control_size = sizeof(data.control->nacp) + icon.size();
|
data.jpeg_size = icon.size();
|
||||||
log_write("\t\t[manual control] time taken: %.2fs %zums\n", ts.GetSecondsD(), ts.GetMs());
|
log_write("\t\t[manual control] time taken: %.2fs %zums\n", ts.GetSecondsD(), ts.GetMs());
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
@@ -347,8 +384,10 @@ auto LoadControlEntry(u64 id) -> ThreadResultData {
|
|||||||
bool manual_load = true;
|
bool manual_load = true;
|
||||||
if (hosversionBefore(20,0,0)) {
|
if (hosversionBefore(20,0,0)) {
|
||||||
TimeStamp ts;
|
TimeStamp ts;
|
||||||
if (R_SUCCEEDED(nsGetApplicationControlData(NsApplicationControlSource_CacheOnly, id, data.control.get(), sizeof(NsApplicationControlData), &data.control_size))) {
|
u64 actual_size;
|
||||||
|
if (R_SUCCEEDED(nsGetApplicationControlData(NsApplicationControlSource_CacheOnly, id, data.control.get(), sizeof(NsApplicationControlData), &actual_size))) {
|
||||||
manual_load = false;
|
manual_load = false;
|
||||||
|
data.jpeg_size = actual_size - sizeof(NacpStruct);
|
||||||
log_write("\t\t[ns control cache] time taken: %.2fs %zums\n", ts.GetSecondsD(), ts.GetMs());
|
log_write("\t\t[ns control cache] time taken: %.2fs %zums\n", ts.GetSecondsD(), ts.GetMs());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -360,18 +399,17 @@ auto LoadControlEntry(u64 id) -> ThreadResultData {
|
|||||||
Result rc{};
|
Result rc{};
|
||||||
if (!manual_load) {
|
if (!manual_load) {
|
||||||
TimeStamp ts;
|
TimeStamp ts;
|
||||||
rc = nsGetApplicationControlData(NsApplicationControlSource_Storage, id, data.control.get(), sizeof(NsApplicationControlData), &data.control_size);
|
u64 actual_size;
|
||||||
|
if (R_SUCCEEDED(rc = nsGetApplicationControlData(NsApplicationControlSource_Storage, id, data.control.get(), sizeof(NsApplicationControlData), &actual_size))) {
|
||||||
|
data.jpeg_size = actual_size - sizeof(NacpStruct);
|
||||||
log_write("\t\t[ns control storage] time taken: %.2fs %zums\n", ts.GetSecondsD(), ts.GetMs());
|
log_write("\t\t[ns control storage] time taken: %.2fs %zums\n", ts.GetSecondsD(), ts.GetMs());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
NacpLanguageEntry* lang{};
|
data.lang = data.control->nacp.lang[GetNacpLangEntryIndex()];
|
||||||
if (R_SUCCEEDED(rc = nsGetApplicationDesiredLanguage(&data.control->nacp, &lang)) && lang) {
|
|
||||||
data.lang = *lang;
|
|
||||||
std::memcpy(data.display_version, data.control->nacp.display_version, sizeof(data.display_version));
|
|
||||||
data.status = NacpLoadStatus::Loaded;
|
data.status = NacpLoadStatus::Loaded;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (R_FAILED(rc)) {
|
if (R_FAILED(rc)) {
|
||||||
FakeNacpEntry(data);
|
FakeNacpEntry(data);
|
||||||
@@ -383,8 +421,7 @@ auto LoadControlEntry(u64 id) -> ThreadResultData {
|
|||||||
void LoadResultIntoEntry(Entry& e, const ThreadResultData& result) {
|
void LoadResultIntoEntry(Entry& e, const ThreadResultData& result) {
|
||||||
e.status = result.status;
|
e.status = result.status;
|
||||||
e.control = result.control;
|
e.control = result.control;
|
||||||
e.control_size = result.control_size;
|
e.jpeg_size= result.jpeg_size;
|
||||||
std::memcpy(e.display_version, result.display_version, sizeof(result.display_version));
|
|
||||||
e.lang = result.lang;
|
e.lang = result.lang;
|
||||||
e.status = result.status;
|
e.status = result.status;
|
||||||
}
|
}
|
||||||
@@ -462,8 +499,16 @@ auto BuildNspPath(const Entry& e, const NsApplicationContentMetaStatus& status)
|
|||||||
utilsReplaceIllegalCharacters(name_buf, true);
|
utilsReplaceIllegalCharacters(name_buf, true);
|
||||||
|
|
||||||
char version[sizeof(NacpStruct::display_version) + 1]{};
|
char version[sizeof(NacpStruct::display_version) + 1]{};
|
||||||
|
// status.storageID
|
||||||
if (status.meta_type == NcmContentMetaType_Patch) {
|
if (status.meta_type == NcmContentMetaType_Patch) {
|
||||||
std::snprintf(version, sizeof(version), "%s ", e.GetDisplayVersion());
|
u64 program_id;
|
||||||
|
fs::FsPath path;
|
||||||
|
if (R_SUCCEEDED(GetControlPathFromStatus(status, &program_id, &path))) {
|
||||||
|
char display_version[0x10];
|
||||||
|
if (R_SUCCEEDED(nca::ParseControl(path, program_id, display_version, sizeof(display_version), nullptr, offsetof(NacpStruct, display_version)))) {
|
||||||
|
std::snprintf(version, sizeof(version), "%s ", display_version);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::FsPath path;
|
fs::FsPath path;
|
||||||
@@ -619,6 +664,11 @@ void LaunchEntry(const Entry& e) {
|
|||||||
void ThreadFunc(void* user) {
|
void ThreadFunc(void* user) {
|
||||||
auto data = static_cast<ThreadData*>(user);
|
auto data = static_cast<ThreadData*>(user);
|
||||||
|
|
||||||
|
if (data->IsTitleCacheEnabled() && !nxtcInitialize()) {
|
||||||
|
log_write("[NXTC] failed to init cache\n");
|
||||||
|
}
|
||||||
|
ON_SCOPE_EXIT(nxtcExit());
|
||||||
|
|
||||||
while (data->IsRunning()) {
|
while (data->IsRunning()) {
|
||||||
data->Run();
|
data->Run();
|
||||||
}
|
}
|
||||||
@@ -626,21 +676,23 @@ void ThreadFunc(void* user) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
ThreadData::ThreadData() {
|
ThreadData::ThreadData(bool title_cache) : m_title_cache{title_cache} {
|
||||||
ueventCreate(&m_uevent, true);
|
ueventCreate(&m_uevent, true);
|
||||||
mutexInit(&m_mutex_id);
|
mutexInit(&m_mutex_id);
|
||||||
mutexInit(&m_mutex_result);
|
mutexInit(&m_mutex_result);
|
||||||
m_running = true;
|
m_running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ThreadData::IsRunning() const -> bool {
|
|
||||||
return m_running;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ThreadData::Run() {
|
void ThreadData::Run() {
|
||||||
while (IsRunning()) {
|
|
||||||
const auto waiter = waiterForUEvent(&m_uevent);
|
const auto waiter = waiterForUEvent(&m_uevent);
|
||||||
waitSingle(waiter, UINT64_MAX);
|
while (IsRunning()) {
|
||||||
|
const auto rc = waitSingle(waiter, 3e+9);
|
||||||
|
|
||||||
|
// if we timed out, flush the cache and poll again.
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
nxtcFlushCacheFile();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!IsRunning()) {
|
if (!IsRunning()) {
|
||||||
return;
|
return;
|
||||||
@@ -658,10 +710,28 @@ void ThreadData::Run() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ThreadResultData result{ids[i]};
|
||||||
|
TimeStamp ts;
|
||||||
|
if (auto data = nxtcGetApplicationMetadataEntryById(ids[i])) {
|
||||||
|
log_write("[NXTC] loaded from cache time taken: %.2fs %zums %zuns\n", ts.GetSecondsD(), ts.GetMs(), ts.GetNs());
|
||||||
|
ON_SCOPE_EXIT(nxtcFreeApplicationMetadata(&data));
|
||||||
|
|
||||||
|
result.control = std::make_unique<NsApplicationControlData>();
|
||||||
|
result.status = NacpLoadStatus::Loaded;
|
||||||
|
std::strcpy(result.lang.name, data->name);
|
||||||
|
std::strcpy(result.lang.author, data->publisher);
|
||||||
|
std::memcpy(result.control->icon, data->icon_data, data->icon_size);
|
||||||
|
result.jpeg_size = data->icon_size;
|
||||||
|
} else {
|
||||||
// sleep after every other entry loaded.
|
// sleep after every other entry loaded.
|
||||||
svcSleepThread(2e+6); // 2ms
|
svcSleepThread(2e+6); // 2ms
|
||||||
|
|
||||||
const auto result = LoadControlEntry(ids[i]);
|
result = LoadControlEntry(ids[i]);
|
||||||
|
if (result.status == NacpLoadStatus::Loaded) {
|
||||||
|
nxtcAddEntry(ids[i], &result.control->nacp, result.jpeg_size, result.control->icon, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mutexLock(&m_mutex_result);
|
mutexLock(&m_mutex_result);
|
||||||
ON_SCOPE_EXIT(mutexUnlock(&m_mutex_result));
|
ON_SCOPE_EXIT(mutexUnlock(&m_mutex_result));
|
||||||
m_result.emplace_back(result);
|
m_result.emplace_back(result);
|
||||||
@@ -871,6 +941,10 @@ Menu::Menu(u32 flags) : grid::Menu{"Games"_i18n, flags} {
|
|||||||
));
|
));
|
||||||
}, true));
|
}, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
options->Add(std::make_shared<SidebarEntryBool>("Title cache"_i18n, m_title_cache.Get(), [this](bool& v_out){
|
||||||
|
m_title_cache.Set(v_out);
|
||||||
|
}));
|
||||||
}})
|
}})
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -883,13 +957,14 @@ Menu::Menu(u32 flags) : grid::Menu{"Games"_i18n, flags} {
|
|||||||
e.Open();
|
e.Open();
|
||||||
}
|
}
|
||||||
|
|
||||||
threadCreate(&m_thread, ThreadFunc, &m_thread_data, nullptr, 1024*32, THREAD_PRIO, THREAD_CORE);
|
m_thread_data = std::make_unique<ThreadData>(m_title_cache.Get());
|
||||||
|
threadCreate(&m_thread, ThreadFunc, m_thread_data.get(), nullptr, 1024*32, THREAD_PRIO, THREAD_CORE);
|
||||||
svcSetThreadCoreMask(m_thread.handle, THREAD_CORE, THREAD_AFFINITY_DEFAULT(THREAD_CORE));
|
svcSetThreadCoreMask(m_thread.handle, THREAD_CORE, THREAD_AFFINITY_DEFAULT(THREAD_CORE));
|
||||||
threadStart(&m_thread);
|
threadStart(&m_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu::~Menu() {
|
Menu::~Menu() {
|
||||||
m_thread_data.Close();
|
m_thread_data->Close();
|
||||||
|
|
||||||
for (auto& e : ncm_entries) {
|
for (auto& e : ncm_entries) {
|
||||||
e.Close();
|
e.Close();
|
||||||
@@ -923,12 +998,17 @@ void Menu::Update(Controller* controller, TouchInfo* touch) {
|
|||||||
void Menu::Draw(NVGcontext* vg, Theme* theme) {
|
void Menu::Draw(NVGcontext* vg, Theme* theme) {
|
||||||
MenuBase::Draw(vg, theme);
|
MenuBase::Draw(vg, theme);
|
||||||
|
|
||||||
|
if (m_entries.empty()) {
|
||||||
|
gfx::drawTextArgs(vg, GetX() + GetW() / 2.f, GetY() + GetH() / 2.f, 36.f, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT_INFO), "Empty..."_i18n.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// max images per frame, in order to not hit io / gpu too hard.
|
// max images per frame, in order to not hit io / gpu too hard.
|
||||||
const int image_load_max = 2;
|
const int image_load_max = 2;
|
||||||
int image_load_count = 0;
|
int image_load_count = 0;
|
||||||
|
|
||||||
std::vector<ThreadResultData> data;
|
std::vector<ThreadResultData> data;
|
||||||
m_thread_data.Pop(data);
|
m_thread_data->Pop(data);
|
||||||
|
|
||||||
for (const auto& d : data) {
|
for (const auto& d : data) {
|
||||||
const auto it = std::ranges::find_if(m_entries, [&d](auto& e) {
|
const auto it = std::ranges::find_if(m_entries, [&d](auto& e) {
|
||||||
@@ -945,7 +1025,7 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) {
|
|||||||
auto& e = m_entries[pos];
|
auto& e = m_entries[pos];
|
||||||
|
|
||||||
if (e.status == NacpLoadStatus::None) {
|
if (e.status == NacpLoadStatus::None) {
|
||||||
m_thread_data.Push(e.app_id);
|
m_thread_data->Push(e.app_id);
|
||||||
e.status = NacpLoadStatus::Progress;
|
e.status = NacpLoadStatus::Progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -956,11 +1036,14 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char title_id[33];
|
||||||
|
std::snprintf(title_id, sizeof(title_id), "%016lX", e.app_id);
|
||||||
|
|
||||||
const auto selected = pos == m_index;
|
const auto selected = pos == m_index;
|
||||||
DrawEntry(vg, theme, m_layout.Get(), v, selected, e.image, e.GetName(), e.GetAuthor(), e.GetDisplayVersion());
|
DrawEntry(vg, theme, m_layout.Get(), v, selected, e.image, e.GetName(), e.GetAuthor(), title_id);
|
||||||
|
|
||||||
if (e.selected) {
|
if (e.selected) {
|
||||||
gfx::drawRect(vg, v, nvgRGBA(0, 0, 0, 180), 5);
|
gfx::drawRect(vg, v, theme->GetColour(ThemeEntryID_FOCUS), 5);
|
||||||
gfx::drawText(vg, x + w / 2, y + h / 2, 24.f, "\uE14B", nullptr, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT_SELECTED));
|
gfx::drawText(vg, x + w / 2, y + h / 2, 24.f, "\uE14B", nullptr, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT_SELECTED));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1018,7 +1101,7 @@ void Menu::ScanHomebrew() {
|
|||||||
u64 unk_x11;// = e.unk_x11;
|
u64 unk_x11;// = e.unk_x11;
|
||||||
memcpy(&unk_x0a, e.unk_x0a, sizeof(e.unk_x0a));
|
memcpy(&unk_x0a, e.unk_x0a, sizeof(e.unk_x0a));
|
||||||
memcpy(&unk_x11, e.unk_x11, sizeof(e.unk_x11));
|
memcpy(&unk_x11, e.unk_x11, sizeof(e.unk_x11));
|
||||||
log_write("ID: %016lx got type: %u unk_x09: %u unk_x0a: %zu unk_x10: %u unk_x11: %zu\n", e.application_id, e.type,
|
log_write("ID: %016lx got type: %u unk_x09: %u unk_x0a: %zu unk_x10: %u unk_x11: %zu\n", e.app_id, e.type,
|
||||||
unk_x09,
|
unk_x09,
|
||||||
unk_x0a,
|
unk_x0a,
|
||||||
unk_x10,
|
unk_x10,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "i18n.hpp"
|
#include "i18n.hpp"
|
||||||
#include "download.hpp"
|
#include "download.hpp"
|
||||||
#include "dumper.hpp"
|
#include "dumper.hpp"
|
||||||
|
#include "image.hpp"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -528,7 +529,7 @@ Result Menu::GcMount() {
|
|||||||
// the fs, same as mounting storage.
|
// the fs, same as mounting storage.
|
||||||
for (u32 i = 0; i < REMOUNT_ATTEMPT_MAX; i++) {
|
for (u32 i = 0; i < REMOUNT_ATTEMPT_MAX; i++) {
|
||||||
R_TRY(fsDeviceOperatorGetGameCardHandle(std::addressof(m_dev_op), std::addressof(m_handle)));
|
R_TRY(fsDeviceOperatorGetGameCardHandle(std::addressof(m_dev_op), std::addressof(m_handle)));
|
||||||
m_fs = std::make_unique<fs::FsNativeGameCard>(std::addressof(m_handle), FsGameCardPartition_Secure, false);
|
m_fs = std::make_unique<fs::FsNativeGameCard>(std::addressof(m_handle), FsGameCardPartition_Secure);
|
||||||
if (R_SUCCEEDED(m_fs->GetFsOpenResult())) {
|
if (R_SUCCEEDED(m_fs->GetFsOpenResult())) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -664,7 +665,7 @@ Result Menu::GcMount() {
|
|||||||
auto source = std::make_shared<GcSource>(m_entries[m_entry_index], m_fs.get());
|
auto source = std::make_shared<GcSource>(m_entries[m_entry_index], m_fs.get());
|
||||||
return yati::InstallFromCollections(pbox, source, source->m_collections, source->m_config);
|
return yati::InstallFromCollections(pbox, source, source->m_collections, source->m_config);
|
||||||
}, [this](Result rc){
|
}, [this](Result rc){
|
||||||
App::PushErrorBox(rc, "Gc install failed"_i18n);
|
App::PushErrorBox(rc, "Gc install failed!"_i18n);
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
App::Notify("Gc install success!"_i18n);
|
App::Notify("Gc install success!"_i18n);
|
||||||
@@ -965,7 +966,13 @@ void Menu::OnChangeIndex(s64 new_index) {
|
|||||||
|
|
||||||
const auto& e = m_entries[m_entry_index];
|
const auto& e = m_entries[m_entry_index];
|
||||||
const auto jpeg_size = e.control_size - sizeof(NacpStruct);
|
const auto jpeg_size = e.control_size - sizeof(NacpStruct);
|
||||||
m_icon = nvgCreateImageMem(App::GetVg(), 0, e.control->icon, jpeg_size);
|
|
||||||
|
TimeStamp ts;
|
||||||
|
const auto image = ImageLoadFromMemory({e.control->icon, jpeg_size}, ImageFlag_JPEG);
|
||||||
|
if (!image.data.empty()) {
|
||||||
|
m_icon = nvgCreateImageRGBA(App::GetVg(), image.w, image.h, 0, image.data.data());
|
||||||
|
log_write("\t[image load] time taken: %.2fs %zums\n", ts.GetSecondsD(), ts.GetMs());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,9 +14,9 @@
|
|||||||
#include "download.hpp"
|
#include "download.hpp"
|
||||||
#include "i18n.hpp"
|
#include "i18n.hpp"
|
||||||
#include "yyjson_helper.hpp"
|
#include "yyjson_helper.hpp"
|
||||||
|
#include "threaded_file_transfer.hpp"
|
||||||
|
|
||||||
#include <minIni.h>
|
#include <minIni.h>
|
||||||
#include <minizip/unzip.h>
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -83,7 +83,6 @@ void from_json(const fs::FsPath& path, GhApiEntry& e) {
|
|||||||
|
|
||||||
auto DownloadApp(ProgressBox* pbox, const GhApiAsset& gh_asset, const AssetEntry* entry) -> Result {
|
auto DownloadApp(ProgressBox* pbox, const GhApiAsset& gh_asset, const AssetEntry* entry) -> Result {
|
||||||
static const fs::FsPath temp_file{"/switch/sphaira/cache/github/ghdl.temp"};
|
static const fs::FsPath temp_file{"/switch/sphaira/cache/github/ghdl.temp"};
|
||||||
constexpr auto chunk_size = 1024 * 512; // 512KiB
|
|
||||||
|
|
||||||
fs::FsNativeSd fs;
|
fs::FsNativeSd fs;
|
||||||
R_TRY(fs.GetFsOpenResult());
|
R_TRY(fs.GetFsOpenResult());
|
||||||
@@ -113,77 +112,7 @@ auto DownloadApp(ProgressBox* pbox, const GhApiAsset& gh_asset, const AssetEntry
|
|||||||
// 3. extract the zip / file
|
// 3. extract the zip / file
|
||||||
if (gh_asset.content_type.find("zip") != gh_asset.content_type.npos) {
|
if (gh_asset.content_type.find("zip") != gh_asset.content_type.npos) {
|
||||||
log_write("found zip\n");
|
log_write("found zip\n");
|
||||||
auto zfile = unzOpen64(temp_file);
|
R_TRY(thread::TransferUnzipAll(pbox, temp_file, &fs, root_path));
|
||||||
R_UNLESS(zfile, 0x1);
|
|
||||||
ON_SCOPE_EXIT(unzClose(zfile));
|
|
||||||
|
|
||||||
unz_global_info64 pglobal_info;
|
|
||||||
if (UNZ_OK != unzGetGlobalInfo64(zfile, &pglobal_info)) {
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < pglobal_info.number_entry; i++) {
|
|
||||||
if (i > 0) {
|
|
||||||
if (UNZ_OK != unzGoToNextFile(zfile)) {
|
|
||||||
log_write("failed to unzGoToNextFile\n");
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UNZ_OK != unzOpenCurrentFile(zfile)) {
|
|
||||||
log_write("failed to open current file\n");
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
ON_SCOPE_EXIT(unzCloseCurrentFile(zfile));
|
|
||||||
|
|
||||||
unz_file_info64 info;
|
|
||||||
fs::FsPath file_path;
|
|
||||||
if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, file_path, sizeof(file_path), 0, 0, 0, 0)) {
|
|
||||||
log_write("failed to get current info\n");
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
file_path = fs::AppendPath(root_path, file_path);
|
|
||||||
|
|
||||||
Result rc;
|
|
||||||
if (file_path[strlen(file_path) -1] == '/') {
|
|
||||||
if (R_FAILED(rc = fs.CreateDirectoryRecursively(file_path)) && rc != FsError_PathAlreadyExists) {
|
|
||||||
log_write("failed to create folder: %s 0x%04X\n", file_path.s, rc);
|
|
||||||
R_THROW(rc);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (R_FAILED(rc = fs.CreateDirectoryRecursivelyWithPath(file_path)) && rc != FsError_PathAlreadyExists) {
|
|
||||||
log_write("failed to create folder: %s 0x%04X\n", file_path.s, rc);
|
|
||||||
R_THROW(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R_FAILED(rc = fs.CreateFile(file_path, info.uncompressed_size, 0)) && rc != FsError_PathAlreadyExists) {
|
|
||||||
log_write("failed to create file: %s 0x%04X\n", file_path.s, rc);
|
|
||||||
R_THROW(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
fs::File f;
|
|
||||||
R_TRY(fs.OpenFile(file_path, FsOpenMode_Write, &f));
|
|
||||||
R_TRY(f.SetSize(info.uncompressed_size));
|
|
||||||
|
|
||||||
std::vector<char> buf(chunk_size);
|
|
||||||
s64 offset{};
|
|
||||||
while (offset < info.uncompressed_size) {
|
|
||||||
R_TRY(pbox->ShouldExitResult());
|
|
||||||
|
|
||||||
const auto bytes_read = unzReadCurrentFile(zfile, buf.data(), buf.size());
|
|
||||||
if (bytes_read <= 0) {
|
|
||||||
log_write("failed to read zip file: %s\n", file_path.s);
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
R_TRY(f.Write(offset, buf.data(), bytes_read, FsWriteOption_None));
|
|
||||||
|
|
||||||
pbox->UpdateTransfer(offset, info.uncompressed_size);
|
|
||||||
offset += bytes_read;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
fs.CreateDirectoryRecursivelyWithPath(root_path);
|
fs.CreateDirectoryRecursivelyWithPath(root_path);
|
||||||
fs.DeleteFile(root_path);
|
fs.DeleteFile(root_path);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "owo.hpp"
|
#include "owo.hpp"
|
||||||
#include "defines.hpp"
|
#include "defines.hpp"
|
||||||
#include "i18n.hpp"
|
#include "i18n.hpp"
|
||||||
|
#include "image.hpp"
|
||||||
|
|
||||||
#include <minIni.h>
|
#include <minIni.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -175,9 +176,17 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) {
|
|||||||
// really, switch-tools should handle this by resizing the image before
|
// really, switch-tools should handle this by resizing the image before
|
||||||
// adding it to the nro, as well as validate its a valid jpeg.
|
// adding it to the nro, as well as validate its a valid jpeg.
|
||||||
const auto icon = nro_get_icon(e.path, e.icon_size, e.icon_offset);
|
const auto icon = nro_get_icon(e.path, e.icon_size, e.icon_offset);
|
||||||
|
TimeStamp ts;
|
||||||
if (!icon.empty()) {
|
if (!icon.empty()) {
|
||||||
e.image = nvgCreateImageMem(vg, 0, icon.data(), icon.size());
|
const auto image = ImageLoadFromMemory(icon, ImageFlag_None);
|
||||||
|
if (!image.data.empty()) {
|
||||||
|
e.image = nvgCreateImageRGBA(vg, image.w, image.h, 0, image.data.data());
|
||||||
|
log_write("\t[image load] time taken: %.2fs %zums\n", ts.GetSecondsD(), ts.GetMs());
|
||||||
image_load_count++;
|
image_load_count++;
|
||||||
|
} else {
|
||||||
|
// prevent loading of this icon again as it's already failed.
|
||||||
|
e.icon_offset = e.icon_size = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,12 +118,12 @@ Menu::Menu(u32 flags) : MenuBase{"Irs"_i18n, flags} {
|
|||||||
is_negative_image_used_str.emplace_back("Negative image"_i18n);
|
is_negative_image_used_str.emplace_back("Negative image"_i18n);
|
||||||
|
|
||||||
SidebarEntryArray::Items format_str;
|
SidebarEntryArray::Items format_str;
|
||||||
format_str.emplace_back("320x240"_i18n);
|
format_str.emplace_back("320\u00D7240");
|
||||||
format_str.emplace_back("160x120"_i18n);
|
format_str.emplace_back("160\u00D7120");
|
||||||
format_str.emplace_back("80x60"_i18n);
|
format_str.emplace_back("80\u00D760");
|
||||||
if (hosversionAtLeast(4,0,0)) {
|
if (hosversionAtLeast(4,0,0)) {
|
||||||
format_str.emplace_back("40x30"_i18n);
|
format_str.emplace_back("40\u00D730");
|
||||||
format_str.emplace_back("20x15"_i18n);
|
format_str.emplace_back("20\u00D715");
|
||||||
}
|
}
|
||||||
|
|
||||||
options->Add(std::make_shared<SidebarEntryArray>("Controller"_i18n, controller_str, [this](s64& index){
|
options->Add(std::make_shared<SidebarEntryArray>("Controller"_i18n, controller_str, [this](s64& index){
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "ui/menus/ftp_menu.hpp"
|
#include "ui/menus/ftp_menu.hpp"
|
||||||
#include "ui/menus/gc_menu.hpp"
|
#include "ui/menus/gc_menu.hpp"
|
||||||
#include "ui/menus/game_menu.hpp"
|
#include "ui/menus/game_menu.hpp"
|
||||||
|
#include "ui/menus/save_menu.hpp"
|
||||||
#include "ui/menus/appstore.hpp"
|
#include "ui/menus/appstore.hpp"
|
||||||
|
|
||||||
#include "app.hpp"
|
#include "app.hpp"
|
||||||
@@ -22,9 +23,9 @@
|
|||||||
#include "download.hpp"
|
#include "download.hpp"
|
||||||
#include "defines.hpp"
|
#include "defines.hpp"
|
||||||
#include "i18n.hpp"
|
#include "i18n.hpp"
|
||||||
|
#include "threaded_file_transfer.hpp"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <minizip/unzip.h>
|
|
||||||
#include <yyjson.h>
|
#include <yyjson.h>
|
||||||
|
|
||||||
namespace sphaira::ui::menu::main {
|
namespace sphaira::ui::menu::main {
|
||||||
@@ -49,6 +50,7 @@ const MiscMenuEntry MISC_MENU_ENTRIES[] = {
|
|||||||
{ .name = "Appstore", .title = "Appstore", .func = MiscMenuFuncGenerator<ui::menu::appstore::Menu>, .flag = MiscMenuFlag_Shortcut },
|
{ .name = "Appstore", .title = "Appstore", .func = MiscMenuFuncGenerator<ui::menu::appstore::Menu>, .flag = MiscMenuFlag_Shortcut },
|
||||||
{ .name = "Games", .title = "Games", .func = MiscMenuFuncGenerator<ui::menu::game::Menu>, .flag = MiscMenuFlag_Shortcut },
|
{ .name = "Games", .title = "Games", .func = MiscMenuFuncGenerator<ui::menu::game::Menu>, .flag = MiscMenuFlag_Shortcut },
|
||||||
{ .name = "FileBrowser", .title = "FileBrowser", .func = MiscMenuFuncGenerator<ui::menu::filebrowser::Menu>, .flag = MiscMenuFlag_Shortcut },
|
{ .name = "FileBrowser", .title = "FileBrowser", .func = MiscMenuFuncGenerator<ui::menu::filebrowser::Menu>, .flag = MiscMenuFlag_Shortcut },
|
||||||
|
{ .name = "Saves", .title = "Saves", .func = MiscMenuFuncGenerator<ui::menu::save::Menu>, .flag = MiscMenuFlag_Shortcut },
|
||||||
{ .name = "Themezer", .title = "Themezer", .func = MiscMenuFuncGenerator<ui::menu::themezer::Menu>, .flag = MiscMenuFlag_Shortcut },
|
{ .name = "Themezer", .title = "Themezer", .func = MiscMenuFuncGenerator<ui::menu::themezer::Menu>, .flag = MiscMenuFlag_Shortcut },
|
||||||
{ .name = "GitHub", .title = "GitHub", .func = MiscMenuFuncGenerator<ui::menu::gh::Menu>, .flag = MiscMenuFlag_Shortcut },
|
{ .name = "GitHub", .title = "GitHub", .func = MiscMenuFuncGenerator<ui::menu::gh::Menu>, .flag = MiscMenuFlag_Shortcut },
|
||||||
{ .name = "FTP", .title = "FTP Install", .func = MiscMenuFuncGenerator<ui::menu::ftp::Menu>, .flag = MiscMenuFlag_Install },
|
{ .name = "FTP", .title = "FTP Install", .func = MiscMenuFuncGenerator<ui::menu::ftp::Menu>, .flag = MiscMenuFlag_Install },
|
||||||
@@ -59,7 +61,6 @@ const MiscMenuEntry MISC_MENU_ENTRIES[] = {
|
|||||||
|
|
||||||
auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string version) -> Result {
|
auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string version) -> Result {
|
||||||
static fs::FsPath zip_out{"/switch/sphaira/cache/update.zip"};
|
static fs::FsPath zip_out{"/switch/sphaira/cache/update.zip"};
|
||||||
constexpr auto chunk_size = 1024 * 512; // 512KiB
|
|
||||||
|
|
||||||
fs::FsNativeSd fs;
|
fs::FsNativeSd fs;
|
||||||
R_TRY(fs.GetFsOpenResult());
|
R_TRY(fs.GetFsOpenResult());
|
||||||
@@ -82,83 +83,23 @@ auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string v
|
|||||||
|
|
||||||
// 2. extract the zip
|
// 2. extract the zip
|
||||||
if (!pbox->ShouldExit()) {
|
if (!pbox->ShouldExit()) {
|
||||||
auto zfile = unzOpen64(zip_out);
|
const auto exe_path = App::GetExePath();
|
||||||
R_UNLESS(zfile, 0x1);
|
bool found_exe{};
|
||||||
ON_SCOPE_EXIT(unzClose(zfile));
|
|
||||||
|
|
||||||
unz_global_info64 pglobal_info;
|
R_TRY(thread::TransferUnzipAll(pbox, zip_out, &fs, "/", [&](const fs::FsPath& name, fs::FsPath& path) -> bool {
|
||||||
if (UNZ_OK != unzGetGlobalInfo64(zfile, &pglobal_info)) {
|
if (std::strstr(path, "sphaira.nro")) {
|
||||||
R_THROW(0x1);
|
path = exe_path;
|
||||||
}
|
found_exe = true;
|
||||||
|
|
||||||
for (s64 i = 0; i < pglobal_info.number_entry; i++) {
|
|
||||||
if (i > 0) {
|
|
||||||
if (UNZ_OK != unzGoToNextFile(zfile)) {
|
|
||||||
log_write("failed to unzGoToNextFile\n");
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UNZ_OK != unzOpenCurrentFile(zfile)) {
|
|
||||||
log_write("failed to open current file\n");
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
ON_SCOPE_EXIT(unzCloseCurrentFile(zfile));
|
|
||||||
|
|
||||||
unz_file_info64 info;
|
|
||||||
fs::FsPath file_path;
|
|
||||||
if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, file_path, sizeof(file_path), 0, 0, 0, 0)) {
|
|
||||||
log_write("failed to get current info\n");
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_path[0] != '/') {
|
|
||||||
file_path = fs::AppendPath("/", file_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (std::strstr(file_path, "sphaira.nro")) {
|
|
||||||
file_path = App::GetExePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result rc;
|
|
||||||
if (file_path[std::strlen(file_path) -1] == '/') {
|
|
||||||
if (R_FAILED(rc = fs.CreateDirectoryRecursively(file_path)) && rc != FsError_PathAlreadyExists) {
|
|
||||||
log_write("failed to create folder: %s 0x%04X\n", file_path.s, rc);
|
|
||||||
R_THROW(rc);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Result rc;
|
|
||||||
if (R_FAILED(rc = fs.CreateFile(file_path, info.uncompressed_size, 0)) && rc != FsError_PathAlreadyExists) {
|
|
||||||
log_write("failed to create file: %s 0x%04X\n", file_path.s, rc);
|
|
||||||
R_THROW(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
fs::File f;
|
|
||||||
R_TRY(fs.OpenFile(file_path, FsOpenMode_Write, &f));
|
|
||||||
R_TRY(f.SetSize(info.uncompressed_size));
|
|
||||||
|
|
||||||
std::vector<char> buf(chunk_size);
|
|
||||||
s64 offset{};
|
|
||||||
while (offset < info.uncompressed_size) {
|
|
||||||
const auto bytes_read = unzReadCurrentFile(zfile, buf.data(), buf.size());
|
|
||||||
if (bytes_read <= 0) {
|
|
||||||
// log_write("failed to read zip file: %s\n", inzip.c_str());
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
R_TRY(f.Write(offset, buf.data(), bytes_read, FsWriteOption_None));
|
|
||||||
|
|
||||||
pbox->UpdateTransfer(offset, info.uncompressed_size);
|
|
||||||
offset += bytes_read;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}));
|
||||||
|
|
||||||
// check if we have sphaira installed in other locations and update them.
|
// check if we have sphaira installed in other locations and update them.
|
||||||
if (file_path == App::GetExePath()) {
|
if (found_exe) {
|
||||||
for (auto& path : SPHAIRA_PATHS) {
|
for (auto& path : SPHAIRA_PATHS) {
|
||||||
log_write("[UPD] checking path: %s\n", path.s);
|
log_write("[UPD] checking path: %s\n", path.s);
|
||||||
// skip if we already updated this path.
|
// skip if we already updated this path.
|
||||||
if (file_path == path) {
|
if (exe_path == path) {
|
||||||
log_write("[UPD] skipped as already updated\n");
|
log_write("[UPD] skipped as already updated\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -169,8 +110,7 @@ auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string v
|
|||||||
if (R_SUCCEEDED(nro_get_nacp(path, nacp)) && !std::strcmp(nacp.lang[0].name, "sphaira")) {
|
if (R_SUCCEEDED(nro_get_nacp(path, nacp)) && !std::strcmp(nacp.lang[0].name, "sphaira")) {
|
||||||
log_write("[UPD] found, updating\n");
|
log_write("[UPD] found, updating\n");
|
||||||
pbox->NewTransfer(path);
|
pbox->NewTransfer(path);
|
||||||
R_TRY(pbox->CopyFile(&fs, file_path, path));
|
R_TRY(pbox->CopyFile(&fs, exe_path, path));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ void MenuBase::Draw(NVGcontext* vg, Theme* theme) {
|
|||||||
|
|
||||||
gfx::drawTextArgs(vg, 80, start_y, 28.f, NVG_ALIGN_LEFT | NVG_ALIGN_BOTTOM, theme->GetColour(ThemeEntryID_TEXT), m_title.c_str());
|
gfx::drawTextArgs(vg, 80, start_y, 28.f, NVG_ALIGN_LEFT | NVG_ALIGN_BOTTOM, theme->GetColour(ThemeEntryID_TEXT), m_title.c_str());
|
||||||
m_scroll_title_sub_heading.Draw(vg, true, title_sub_x, start_y, text_w - title_sub_x, 16, NVG_ALIGN_LEFT | NVG_ALIGN_BOTTOM, theme->GetColour(ThemeEntryID_TEXT_INFO), m_title_sub_heading.c_str());
|
m_scroll_title_sub_heading.Draw(vg, true, title_sub_x, start_y, text_w - title_sub_x, 16, NVG_ALIGN_LEFT | NVG_ALIGN_BOTTOM, theme->GetColour(ThemeEntryID_TEXT_INFO), m_title_sub_heading.c_str());
|
||||||
m_scroll_sub_heading.Draw(vg, true, 80, 685, text_w - 80, 18, NVG_ALIGN_LEFT, theme->GetColour(ThemeEntryID_TEXT), m_sub_heading.c_str());
|
m_scroll_sub_heading.Draw(vg, true, 80, 685, text_w - 160, 18, NVG_ALIGN_LEFT, theme->GetColour(ThemeEntryID_TEXT), m_sub_heading.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuBase::SetTitle(std::string title) {
|
void MenuBase::SetTitle(std::string title) {
|
||||||
|
|||||||
1274
sphaira/source/ui/menus/save_menu.cpp
Normal file
@@ -11,11 +11,12 @@
|
|||||||
#include "ui/nvg_util.hpp"
|
#include "ui/nvg_util.hpp"
|
||||||
#include "swkbd.hpp"
|
#include "swkbd.hpp"
|
||||||
#include "i18n.hpp"
|
#include "i18n.hpp"
|
||||||
|
#include "threaded_file_transfer.hpp"
|
||||||
|
#include "image.hpp"
|
||||||
|
|
||||||
#include <minIni.h>
|
#include <minIni.h>
|
||||||
#include <stb_image.h>
|
#include <stb_image.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <minizip/unzip.h>
|
|
||||||
#include <yyjson.h>
|
#include <yyjson.h>
|
||||||
#include "yyjson_helper.hpp"
|
#include "yyjson_helper.hpp"
|
||||||
|
|
||||||
@@ -134,19 +135,14 @@ auto loadThemeImage(ThemeEntry& e) -> bool {
|
|||||||
}
|
}
|
||||||
auto vg = App::GetVg();
|
auto vg = App::GetVg();
|
||||||
|
|
||||||
fs::FsNativeSd fs;
|
|
||||||
std::vector<u8> image_buf;
|
|
||||||
|
|
||||||
const auto path = apiBuildIconCache(e);
|
const auto path = apiBuildIconCache(e);
|
||||||
if (R_FAILED(fs.read_entire_file(path, image_buf))) {
|
TimeStamp ts;
|
||||||
log_write("failed to load image from file: %s\n", path.s);
|
const auto data = ImageLoadFromFile(path, ImageFlag_JPEG);
|
||||||
} else {
|
if (!data.data.empty()) {
|
||||||
int channels_in_file;
|
image.w = data.w;
|
||||||
auto buf = stbi_load_from_memory(image_buf.data(), image_buf.size(), &image.w, &image.h, &channels_in_file, 4);
|
image.h = data.h;
|
||||||
if (buf) {
|
image.image = nvgCreateImageRGBA(vg, data.w, data.h, 0, data.data.data());
|
||||||
ON_SCOPE_EXIT(stbi_image_free(buf));
|
log_write("\t[image load] time taken: %.2fs %zums\n", ts.GetSecondsD(), ts.GetMs());
|
||||||
image.image = nvgCreateImageRGBA(vg, image.w, image.h, 0, buf);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!image.image) {
|
if (!image.image) {
|
||||||
@@ -222,7 +218,6 @@ void from_json(const fs::FsPath& path, PackList& e) {
|
|||||||
|
|
||||||
auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> Result {
|
auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> Result {
|
||||||
static const fs::FsPath zip_out{"/switch/sphaira/cache/themezer/temp.zip"};
|
static const fs::FsPath zip_out{"/switch/sphaira/cache/themezer/temp.zip"};
|
||||||
constexpr auto chunk_size = 1024 * 512; // 512KiB
|
|
||||||
|
|
||||||
fs::FsNativeSd fs;
|
fs::FsNativeSd fs;
|
||||||
R_TRY(fs.GetFsOpenResult());
|
R_TRY(fs.GetFsOpenResult());
|
||||||
@@ -272,66 +267,7 @@ auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> Result {
|
|||||||
|
|
||||||
// 3. extract the zip
|
// 3. extract the zip
|
||||||
if (!pbox->ShouldExit()) {
|
if (!pbox->ShouldExit()) {
|
||||||
auto zfile = unzOpen64(zip_out);
|
R_TRY(thread::TransferUnzipAll(pbox, zip_out, &fs, dir_path));
|
||||||
R_UNLESS(zfile, 0x1);
|
|
||||||
ON_SCOPE_EXIT(unzClose(zfile));
|
|
||||||
|
|
||||||
unz_global_info64 pglobal_info;
|
|
||||||
if (UNZ_OK != unzGetGlobalInfo64(zfile, &pglobal_info)) {
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < pglobal_info.number_entry; i++) {
|
|
||||||
if (i > 0) {
|
|
||||||
if (UNZ_OK != unzGoToNextFile(zfile)) {
|
|
||||||
log_write("failed to unzGoToNextFile\n");
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UNZ_OK != unzOpenCurrentFile(zfile)) {
|
|
||||||
log_write("failed to open current file\n");
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
ON_SCOPE_EXIT(unzCloseCurrentFile(zfile));
|
|
||||||
|
|
||||||
unz_file_info64 info;
|
|
||||||
char name[512];
|
|
||||||
if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, name, sizeof(name), 0, 0, 0, 0)) {
|
|
||||||
log_write("failed to get current info\n");
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto file_path = fs::AppendPath(dir_path, name);
|
|
||||||
pbox->NewTransfer(name);
|
|
||||||
|
|
||||||
Result rc;
|
|
||||||
if (R_FAILED(rc = fs.CreateFile(file_path, info.uncompressed_size, 0)) && rc != FsError_PathAlreadyExists) {
|
|
||||||
log_write("failed to create file: %s 0x%04X\n", file_path.s, rc);
|
|
||||||
R_THROW(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
fs::File f;
|
|
||||||
R_TRY(fs.OpenFile(file_path, FsOpenMode_Write, &f));
|
|
||||||
R_TRY(f.SetSize(info.uncompressed_size));
|
|
||||||
|
|
||||||
std::vector<char> buf(chunk_size);
|
|
||||||
s64 offset{};
|
|
||||||
while (offset < info.uncompressed_size) {
|
|
||||||
R_TRY(pbox->ShouldExitResult());
|
|
||||||
|
|
||||||
const auto bytes_read = unzReadCurrentFile(zfile, buf.data(), buf.size());
|
|
||||||
if (bytes_read <= 0) {
|
|
||||||
// log_write("failed to read zip file: %s\n", inzip.c_str());
|
|
||||||
R_THROW(0x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
R_TRY(f.Write(offset, buf.data(), bytes_read, FsWriteOption_None));
|
|
||||||
|
|
||||||
pbox->UpdateTransfer(offset, info.uncompressed_size);
|
|
||||||
offset += bytes_read;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log_write("finished install :)\n");
|
log_write("finished install :)\n");
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ void Menu::Update(Controller* controller, TouchInfo* touch) {
|
|||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}, [this](Result rc){
|
}, [this](Result rc){
|
||||||
App::PushErrorBox(rc, "USB install failed"_i18n);
|
App::PushErrorBox(rc, "USB install failed!"_i18n);
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
App::Notify("Usb install success!"_i18n);
|
App::Notify("Usb install success!"_i18n);
|
||||||
|
|||||||
@@ -296,8 +296,8 @@ void drawScrollbar(NVGcontext* vg, const Theme* theme, float x, float y, float h
|
|||||||
if (entry_total > max_entry_display) {
|
if (entry_total > max_entry_display) {
|
||||||
const float sb_h = 1.f / (float)entry_total * h;
|
const float sb_h = 1.f / (float)entry_total * h;
|
||||||
const float sb_y = SCROLL;
|
const float sb_y = SCROLL;
|
||||||
gfx::drawRect(vg, x, y, scc2, h, theme->GetColour(ThemeEntryID_SCROLLBAR_BACKGROUND), false);
|
gfx::drawRect(vg, x, y, scc2, h, theme->GetColour(ThemeEntryID_SCROLLBAR_BACKGROUND), 5);
|
||||||
gfx::drawRect(vg, x + scw, y + scw + sb_h * sb_y, scc2 - scw * 2, sb_h * float(max_entry_display) - scw * 2, theme->GetColour(ThemeEntryID_SCROLLBAR), false);
|
gfx::drawRect(vg, x + scw, y + scw + sb_h * sb_y, scc2 - scw * 2, sb_h * float(max_entry_display) - scw * 2, theme->GetColour(ThemeEntryID_SCROLLBAR), 5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,8 +318,8 @@ void drawScrollbar2(NVGcontext* vg, const Theme* theme, float x, float y, float
|
|||||||
if (count > page) {
|
if (count > page) {
|
||||||
const float sb_h = 1.f / (float)count * h;
|
const float sb_h = 1.f / (float)count * h;
|
||||||
const float sb_y = index_off;
|
const float sb_y = index_off;
|
||||||
gfx::drawRect(vg, x, y, scc2, h, theme->GetColour(ThemeEntryID_SCROLLBAR_BACKGROUND), false);
|
gfx::drawRect(vg, x, y, scc2, h, theme->GetColour(ThemeEntryID_SCROLLBAR_BACKGROUND), 5);
|
||||||
gfx::drawRect(vg, x + scw, y + scw + sb_h * sb_y, scc2 - scw * 2, sb_h * float(page) - scw * 2, theme->GetColour(ThemeEntryID_SCROLLBAR), false);
|
gfx::drawRect(vg, x + scw, y + scw + sb_h * sb_y, scc2 - scw * 2, sb_h * float(page) - scw * 2, theme->GetColour(ThemeEntryID_SCROLLBAR), 5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,9 +373,7 @@ void drawAppLable(NVGcontext* vg, const Theme* theme, ScrollingText& st, float x
|
|||||||
const float text_x = box_x + text_pad;
|
const float text_x = box_x + text_pad;
|
||||||
const float text_y = y_offset + (box_h / 2.f);
|
const float text_y = y_offset + (box_h / 2.f);
|
||||||
|
|
||||||
drawRect(vg, {x-4, y-4, w+8, w+8}, theme->GetColour(ThemeEntryID_GRID));
|
|
||||||
nvgBeginPath(vg);
|
nvgBeginPath(vg);
|
||||||
|
|
||||||
nvgRoundedRect(vg, box_x, y_offset, box_w, box_h, 3.f);
|
nvgRoundedRect(vg, box_x, y_offset, box_w, box_h, 3.f);
|
||||||
nvgFillColor(vg, theme->GetColour(ThemeEntryID_SELECTED_BACKGROUND));
|
nvgFillColor(vg, theme->GetColour(ThemeEntryID_SELECTED_BACKGROUND));
|
||||||
nvgFill(vg);
|
nvgFill(vg);
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ auto ProgressBox::Draw(NVGcontext* vg, Theme* theme) -> void {
|
|||||||
m_last_offset = m_offset;
|
m_last_offset = m_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto action = m_action;
|
||||||
const auto title = m_title;
|
const auto title = m_title;
|
||||||
const auto transfer = m_transfer;
|
const auto transfer = m_transfer;
|
||||||
const auto size = m_size;
|
const auto size = m_size;
|
||||||
@@ -166,7 +167,7 @@ auto ProgressBox::Draw(NVGcontext* vg, Theme* theme) -> void {
|
|||||||
gfx::drawTextArgs(vg, center_x, prog_bar.y + prog_bar.h + 30, 18, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "%s (%s)", time_str, speed_str);
|
gfx::drawTextArgs(vg, center_x, prog_bar.y + prog_bar.h + 30, 18, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "%s (%s)", time_str, speed_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::drawTextArgs(vg, center_x, m_pos.y + 40, 24, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), m_action.c_str());
|
gfx::drawTextArgs(vg, center_x, m_pos.y + 40, 24, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), action.c_str());
|
||||||
|
|
||||||
const auto draw_text = [&](ScrollingText& scroll, const std::string& txt, float y, float size, float pad, ThemeEntryID id){
|
const auto draw_text = [&](ScrollingText& scroll, const std::string& txt, float y, float size, float pad, ThemeEntryID id){
|
||||||
float bounds[4];
|
float bounds[4];
|
||||||
@@ -187,6 +188,14 @@ auto ProgressBox::Draw(NVGcontext* vg, Theme* theme) -> void {
|
|||||||
nvgRestore(vg);
|
nvgRestore(vg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto ProgressBox::SetActionName(const std::string& action) -> ProgressBox& {
|
||||||
|
mutexLock(&m_mutex);
|
||||||
|
m_action = action;
|
||||||
|
mutexUnlock(&m_mutex);
|
||||||
|
Yield();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
auto ProgressBox::SetTitle(const std::string& title) -> ProgressBox& {
|
auto ProgressBox::SetTitle(const std::string& title) -> ProgressBox& {
|
||||||
mutexLock(&m_mutex);
|
mutexLock(&m_mutex);
|
||||||
m_title = title;
|
m_title = title;
|
||||||
|
|||||||
@@ -87,16 +87,8 @@ void ScrollableText::Draw(NVGcontext* vg, Theme* theme) {
|
|||||||
// const Vec4 banner_vec(70, line_vec.y + 20, 848.f, 208.f);
|
// const Vec4 banner_vec(70, line_vec.y + 20, 848.f, 208.f);
|
||||||
const Vec4 banner_vec(70, line_vec.y + 20, m_end_w + (110.0F), 208.f);
|
const Vec4 banner_vec(70, line_vec.y + 20, m_end_w + (110.0F), 208.f);
|
||||||
|
|
||||||
// only draw scrollbar if needed
|
|
||||||
if ((m_bounds[3] - m_bounds[1]) > m_clip_y) {
|
|
||||||
const auto scrollbar_size = m_clip_y;
|
|
||||||
const auto max_index = (m_bounds[3] - m_bounds[1]) / m_step;
|
const auto max_index = (m_bounds[3] - m_bounds[1]) / m_step;
|
||||||
const auto sb_h = 1.f / max_index * scrollbar_size;
|
gfx::drawScrollbar2(vg, theme, banner_vec.w + 25, m_y_off_base, m_clip_y, m_index, max_index, 1, m_clip_y / m_step - 1);
|
||||||
const auto in_clip = m_clip_y / m_step - 1;
|
|
||||||
const auto sb_y = m_index;
|
|
||||||
gfx::drawRect(vg, banner_vec.w, m_y_off_base, 10, scrollbar_size, theme->GetColour(ThemeEntryID_SCROLLBAR_BACKGROUND));
|
|
||||||
gfx::drawRect(vg, banner_vec.w+2, m_y_off_base + sb_h * sb_y, 10-4, sb_h + (sb_h * in_clip) - 4, theme->GetColour(ThemeEntryID_SCROLLBAR));
|
|
||||||
}
|
|
||||||
|
|
||||||
nvgSave(vg);
|
nvgSave(vg);
|
||||||
nvgIntersectScissor(vg, 0, m_y_off_base - m_font_size, 1280, m_clip_y + m_font_size); // clip
|
nvgIntersectScissor(vg, 0, m_y_off_base - m_font_size, 1280, m_clip_y + m_font_size); // clip
|
||||||
|
|||||||
@@ -293,12 +293,14 @@ Result UsbDs::WaitTransferCompletion(UsbSessionEndpoint ep, u64 timeout) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result UsbDs::TransferAsync(UsbSessionEndpoint ep, void *buffer, u32 remaining, u32 size, u32 *out_urb_id) {
|
Result UsbDs::TransferAsync(UsbSessionEndpoint ep, void *buffer, u32 remaining, u32 size, u32 *out_urb_id) {
|
||||||
|
if (ep == UsbSessionEndpoint_In) {
|
||||||
if (remaining == size && !(size % (u32)m_max_packet_size)) {
|
if (remaining == size && !(size % (u32)m_max_packet_size)) {
|
||||||
log_write("[USBDS] SetZlt(true)\n");
|
log_write("[USBDS] SetZlt(true)\n");
|
||||||
R_TRY(usbDsEndpoint_SetZlt(m_endpoints[ep], true));
|
R_TRY(usbDsEndpoint_SetZlt(m_endpoints[ep], true));
|
||||||
} else {
|
} else {
|
||||||
R_TRY(usbDsEndpoint_SetZlt(m_endpoints[ep], false));
|
R_TRY(usbDsEndpoint_SetZlt(m_endpoints[ep], false));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return usbDsEndpoint_PostBufferAsync(m_endpoints[ep], buffer, size, out_urb_id);
|
return usbDsEndpoint_PostBufferAsync(m_endpoints[ep], buffer, size, out_urb_id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ Result ParseCnmt(const fs::FsPath& path, u64 program_id, ncm::PackagedContentMet
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result ParseControl(const fs::FsPath& path, u64 program_id, void* nacp_out, s64 nacp_size, std::vector<u8>* icon_out) {
|
Result ParseControl(const fs::FsPath& path, u64 program_id, void* nacp_out, s64 nacp_size, std::vector<u8>* icon_out, s64 nacp_off) {
|
||||||
FsFileSystem fs;
|
FsFileSystem fs;
|
||||||
R_TRY(fsOpenFileSystemWithId(std::addressof(fs), program_id, FsFileSystemType_ContentControl, path, FsContentAttributes_All));
|
R_TRY(fsOpenFileSystemWithId(std::addressof(fs), program_id, FsFileSystemType_ContentControl, path, FsContentAttributes_All));
|
||||||
ON_SCOPE_EXIT(fsFsClose(std::addressof(fs)));
|
ON_SCOPE_EXIT(fsFsClose(std::addressof(fs)));
|
||||||
@@ -198,7 +198,7 @@ Result ParseControl(const fs::FsPath& path, u64 program_id, void* nacp_out, s64
|
|||||||
ON_SCOPE_EXIT(fsFileClose(std::addressof(file)));
|
ON_SCOPE_EXIT(fsFileClose(std::addressof(file)));
|
||||||
|
|
||||||
u64 bytes_read;
|
u64 bytes_read;
|
||||||
R_TRY(fsFileRead(&file, 0, nacp_out, nacp_size, 0, &bytes_read));
|
R_TRY(fsFileRead(&file, nacp_off, nacp_out, nacp_size, 0, &bytes_read));
|
||||||
}
|
}
|
||||||
|
|
||||||
// read icon.
|
// read icon.
|
||||||
|
|||||||
@@ -433,7 +433,7 @@ Result Yati::decompressFuncInternal(ThreadData* t) {
|
|||||||
inflate_buf.reserve(t->max_buffer_size);
|
inflate_buf.reserve(t->max_buffer_size);
|
||||||
|
|
||||||
s64 written{};
|
s64 written{};
|
||||||
s64 decompress_buf_off{};
|
s64 block_offset{};
|
||||||
std::vector<u8> buf{};
|
std::vector<u8> buf{};
|
||||||
buf.reserve(t->max_buffer_size);
|
buf.reserve(t->max_buffer_size);
|
||||||
|
|
||||||
@@ -454,14 +454,15 @@ Result Yati::decompressFuncInternal(ThreadData* t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (s64 off = 0; off < size;) {
|
for (s64 off = 0; off < size;) {
|
||||||
// log_write("looking for section\n");
|
|
||||||
if (!ncz_section || !ncz_section->InRange(written)) {
|
if (!ncz_section || !ncz_section->InRange(written)) {
|
||||||
|
log_write("[NCZ] looking for new section: %zu\n", written);
|
||||||
auto it = std::ranges::find_if(t->ncz_sections, [written](auto& e){
|
auto it = std::ranges::find_if(t->ncz_sections, [written](auto& e){
|
||||||
return e.InRange(written);
|
return e.InRange(written);
|
||||||
});
|
});
|
||||||
|
|
||||||
R_UNLESS(it != t->ncz_sections.cend(), Result_NczSectionNotFound);
|
R_UNLESS(it != t->ncz_sections.cend(), Result_NczSectionNotFound);
|
||||||
ncz_section = &(*it);
|
ncz_section = &(*it);
|
||||||
|
log_write("[NCZ] found new section: %zu\n", written);
|
||||||
|
|
||||||
if (ncz_section->crypto_type >= nca::EncryptionType_AesCtr) {
|
if (ncz_section->crypto_type >= nca::EncryptionType_AesCtr) {
|
||||||
const auto swp = std::byteswap(u64(written) >> 4);
|
const auto swp = std::byteswap(u64(written) >> 4);
|
||||||
@@ -488,7 +489,7 @@ Result Yati::decompressFuncInternal(ThreadData* t) {
|
|||||||
|
|
||||||
// restore remaining data to the swapped buffer.
|
// restore remaining data to the swapped buffer.
|
||||||
if (!temp_vector.empty()) {
|
if (!temp_vector.empty()) {
|
||||||
log_write("storing data size: %zu\n", temp_vector.size());
|
log_write("[NCZ] storing data size: %zu\n", temp_vector.size());
|
||||||
inflate_buf = temp_vector;
|
inflate_buf = temp_vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,6 +497,7 @@ Result Yati::decompressFuncInternal(ThreadData* t) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
while (t->decompress_offset < t->write_size && R_SUCCEEDED(t->GetResults())) {
|
while (t->decompress_offset < t->write_size && R_SUCCEEDED(t->GetResults())) {
|
||||||
|
s64 decompress_buf_off{};
|
||||||
R_TRY(t->GetDecompressBuf(buf, decompress_buf_off));
|
R_TRY(t->GetDecompressBuf(buf, decompress_buf_off));
|
||||||
|
|
||||||
// do we have an nsz? if so, setup buffers.
|
// do we have an nsz? if so, setup buffers.
|
||||||
@@ -616,12 +618,14 @@ Result Yati::decompressFuncInternal(ThreadData* t) {
|
|||||||
// todo: blocks need to use read offset, as the offset + size is compressed range.
|
// todo: blocks need to use read offset, as the offset + size is compressed range.
|
||||||
if (t->ncz_blocks.size()) {
|
if (t->ncz_blocks.size()) {
|
||||||
if (!ncz_block || !ncz_block->InRange(decompress_buf_off)) {
|
if (!ncz_block || !ncz_block->InRange(decompress_buf_off)) {
|
||||||
|
block_offset = 0;
|
||||||
|
log_write("[NCZ] looking for new block: %zu\n", decompress_buf_off);
|
||||||
auto it = std::ranges::find_if(t->ncz_blocks, [decompress_buf_off](auto& e){
|
auto it = std::ranges::find_if(t->ncz_blocks, [decompress_buf_off](auto& e){
|
||||||
return e.InRange(decompress_buf_off);
|
return e.InRange(decompress_buf_off);
|
||||||
});
|
});
|
||||||
|
|
||||||
R_UNLESS(it != t->ncz_blocks.cend(), Result_NczBlockNotFound);
|
R_UNLESS(it != t->ncz_blocks.cend(), Result_NczBlockNotFound);
|
||||||
// log_write("looking found block\n");
|
log_write("[NCZ] found new block: %zu off: %zd size: %zd\n", decompress_buf_off, it->offset, it->size);
|
||||||
ncz_block = &(*it);
|
ncz_block = &(*it);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -629,7 +633,7 @@ Result Yati::decompressFuncInternal(ThreadData* t) {
|
|||||||
auto decompressedBlockSize = 1 << t->ncz_block_header.block_size_exponent;
|
auto decompressedBlockSize = 1 << t->ncz_block_header.block_size_exponent;
|
||||||
// special handling for the last block to check it's actually compressed
|
// special handling for the last block to check it's actually compressed
|
||||||
if (ncz_block->offset == t->ncz_blocks.back().offset) {
|
if (ncz_block->offset == t->ncz_blocks.back().offset) {
|
||||||
log_write("last block special handling\n");
|
log_write("[NCZ] last block special handling\n");
|
||||||
decompressedBlockSize = t->ncz_block_header.decompressed_size % decompressedBlockSize;
|
decompressedBlockSize = t->ncz_block_header.decompressed_size % decompressedBlockSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -637,12 +641,12 @@ Result Yati::decompressFuncInternal(ThreadData* t) {
|
|||||||
compressed = ncz_block->size < decompressedBlockSize;
|
compressed = ncz_block->size < decompressedBlockSize;
|
||||||
|
|
||||||
// clip read size as blocks can be up to 32GB in size!
|
// clip read size as blocks can be up to 32GB in size!
|
||||||
const auto size = std::min<u64>(buf.size() - buf_off, ncz_block->size);
|
const auto size = std::min<u64>(buffer.size(), ncz_block->size - block_offset);
|
||||||
buffer = {buf.data() + buf_off, size};
|
buffer = buffer.subspan(0, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compressed) {
|
if (compressed) {
|
||||||
// log_write("COMPRESSED block\n");
|
log_write("[NCZ] COMPRESSED block\n");
|
||||||
ZSTD_inBuffer input = { buffer.data(), buffer.size(), 0 };
|
ZSTD_inBuffer input = { buffer.data(), buffer.size(), 0 };
|
||||||
while (input.pos < input.size) {
|
while (input.pos < input.size) {
|
||||||
R_TRY(t->GetResults());
|
R_TRY(t->GetResults());
|
||||||
@@ -650,12 +654,15 @@ Result Yati::decompressFuncInternal(ThreadData* t) {
|
|||||||
inflate_buf.resize(inflate_offset + chunk_size);
|
inflate_buf.resize(inflate_offset + chunk_size);
|
||||||
ZSTD_outBuffer output = { inflate_buf.data() + inflate_offset, chunk_size, 0 };
|
ZSTD_outBuffer output = { inflate_buf.data() + inflate_offset, chunk_size, 0 };
|
||||||
const auto res = ZSTD_decompressStream(dctx, std::addressof(output), std::addressof(input));
|
const auto res = ZSTD_decompressStream(dctx, std::addressof(output), std::addressof(input));
|
||||||
|
if (ZSTD_isError(res)) {
|
||||||
|
log_write("[NCZ] ZSTD_decompressStream() pos: %zu size: %zu res: %zd msg: %s\n", input.pos, input.size, res, ZSTD_getErrorName(res));
|
||||||
|
}
|
||||||
R_UNLESS(!ZSTD_isError(res), Result_InvalidNczZstdError);
|
R_UNLESS(!ZSTD_isError(res), Result_InvalidNczZstdError);
|
||||||
|
|
||||||
t->decompress_offset += output.pos;
|
t->decompress_offset += output.pos;
|
||||||
inflate_offset += output.pos;
|
inflate_offset += output.pos;
|
||||||
if (inflate_offset >= INFLATE_BUFFER_MAX) {
|
if (inflate_offset >= INFLATE_BUFFER_MAX) {
|
||||||
// log_write("flushing compressed data: %zd vs %zd diff: %zd\n", inflate_offset, INFLATE_BUFFER_MAX, inflate_offset - INFLATE_BUFFER_MAX);
|
log_write("[NCZ] flushing compressed data: %zd vs %zd diff: %zd\n", inflate_offset, INFLATE_BUFFER_MAX, inflate_offset - INFLATE_BUFFER_MAX);
|
||||||
R_TRY(ncz_flush(INFLATE_BUFFER_MAX));
|
R_TRY(ncz_flush(INFLATE_BUFFER_MAX));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -666,13 +673,14 @@ Result Yati::decompressFuncInternal(ThreadData* t) {
|
|||||||
t->decompress_offset += buffer.size();
|
t->decompress_offset += buffer.size();
|
||||||
inflate_offset += buffer.size();
|
inflate_offset += buffer.size();
|
||||||
if (inflate_offset >= INFLATE_BUFFER_MAX) {
|
if (inflate_offset >= INFLATE_BUFFER_MAX) {
|
||||||
// log_write("flushing copy data\n");
|
log_write("[NCZ] flushing copy data\n");
|
||||||
R_TRY(ncz_flush(INFLATE_BUFFER_MAX));
|
R_TRY(ncz_flush(INFLATE_BUFFER_MAX));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buf_off += buffer.size();
|
buf_off += buffer.size();
|
||||||
decompress_buf_off += buffer.size();
|
decompress_buf_off += buffer.size();
|
||||||
|
block_offset += buffer.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||