From 10d3b253a494139516a2010213e6cde0c1ffc810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 10 Sep 2024 13:15:06 +0200 Subject: [PATCH 1/2] More InstallZip refactoring, add options for install directory where applicable --- Common/File/AndroidContentURI.h | 4 ++ Common/File/FileUtil.cpp | 17 ++++++++ Common/File/FileUtil.h | 4 ++ Common/File/Path.h | 3 ++ Common/StringUtils.cpp | 6 +++ Common/StringUtils.h | 2 + Core/Util/GameManager.cpp | 77 +++++++++++++++++---------------- Core/Util/GameManager.h | 4 +- UI/InstallZipScreen.cpp | 35 +++++++++++++++ UI/InstallZipScreen.h | 4 ++ 10 files changed, 117 insertions(+), 39 deletions(-) diff --git a/Common/File/AndroidContentURI.h b/Common/File/AndroidContentURI.h index 7015e0a20a..bc6bc65fe8 100644 --- a/Common/File/AndroidContentURI.h +++ b/Common/File/AndroidContentURI.h @@ -67,6 +67,10 @@ public: return root.empty() ? file : root; } + const std::string &Provider() const { + return provider; + } + bool IsTreeURI() const { return !root.empty(); } diff --git a/Common/File/FileUtil.cpp b/Common/File/FileUtil.cpp index aeb7235221..c750aec1f9 100644 --- a/Common/File/FileUtil.cpp +++ b/Common/File/FileUtil.cpp @@ -1276,4 +1276,21 @@ void ChangeMTime(const Path &path, time_t mtime) { #endif } +bool IsProbablyInDownloadsFolder(const Path &filename) { + INFO_LOG(Log::Common, "IsProbablyInDownloadsFolder: Looking at %s (%s)...", filename.c_str(), filename.ToVisualString().c_str()); + switch (filename.Type()) { + case PathType::CONTENT_URI: + { + AndroidContentURI uri(filename.ToString()); + INFO_LOG(Log::Common, "Content URI provider: %s", uri.Provider().c_str()); + if (containsNoCase(uri.Provider(), "download")) { + // like com.android.providers.downloads.documents + return true; + } + break; + } + } + return filename.FilePathContainsNoCase("download"); +} + } // namespace File diff --git a/Common/File/FileUtil.h b/Common/File/FileUtil.h index 9a3af34bb0..eedf4cecf1 100644 --- a/Common/File/FileUtil.h +++ b/Common/File/FileUtil.h @@ -122,6 +122,10 @@ bool CreateEmptyFile(const Path &filename); // TODO: Belongs in System or something. bool OpenFileInEditor(const Path &fileName); +// Uses some heuristics to determine if this is a folder that we would want to +// write to. +bool IsProbablyInDownloadsFolder(const Path &folder); + // TODO: Belongs in System or something. const Path &GetExeDirectory(); diff --git a/Common/File/Path.h b/Common/File/Path.h index e94caf14c3..cf48fb277d 100644 --- a/Common/File/Path.h +++ b/Common/File/Path.h @@ -50,6 +50,9 @@ public: PathType Type() const { return type_; } + bool IsLocalType() const { + return type_ == PathType::NATIVE || type_ == PathType::CONTENT_URI; + } bool Valid() const { return !path_.empty(); } bool IsRoot() const { return path_ == "/"; } // Special value - only path that can end in a slash. diff --git a/Common/StringUtils.cpp b/Common/StringUtils.cpp index 63ac6413e0..be11318d1d 100644 --- a/Common/StringUtils.cpp +++ b/Common/StringUtils.cpp @@ -93,6 +93,12 @@ long parseLong(std::string s) { return value; } +bool containsNoCase(std::string_view haystack, std::string_view needle) { + auto pred = [](char ch1, char ch2) { return std::toupper(ch1) == std::toupper(ch2); }; + auto found = std::search(haystack.begin(), haystack.end(), needle.begin(), needle.end(), pred); + return found != haystack.end(); +} + bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args) { int writtenCount = vsnprintf(out, outsize, format, args); diff --git a/Common/StringUtils.h b/Common/StringUtils.h index 6197877cd0..aa331e0f93 100644 --- a/Common/StringUtils.h +++ b/Common/StringUtils.h @@ -69,6 +69,8 @@ inline bool equalsNoCase(std::string_view str, std::string_view key) { return strncasecmp(str.data(), key.data(), key.size()) == 0; } +bool containsNoCase(std::string_view haystack, std::string_view needle); + void DataToHexString(const uint8_t *data, size_t size, std::string *output); void DataToHexString(int indent, uint32_t startAddr, const uint8_t* data, size_t size, std::string* output); diff --git a/Core/Util/GameManager.cpp b/Core/Util/GameManager.cpp index 95597ca3ce..433e280135 100644 --- a/Core/Util/GameManager.cpp +++ b/Core/Util/GameManager.cpp @@ -389,14 +389,30 @@ void GameManager::InstallZipContents(ZipFileTask task) { // Examine the URL to guess out what we're installing. // TODO: Bad idea due to Android content api where we don't always get the filename. if (urlExtension == ".cso" || urlExtension == ".iso" || urlExtension == ".chd") { - // It's a raw ISO or CSO file. We just copy it to the destination. - std::string shortFilename = task.url.GetFilename(); - bool success = InstallRawISO(task.fileName, shortFilename, task.deleteAfter); + // It's a raw ISO or CSO file. We just copy it to the destination, which is the + // currently selected directory in the game browser. Note: This might not be a good option! + Path destPath = Path(g_Config.currentDirectory) / task.url.GetFilename(); + if (!File::Exists(destPath)) { + // Fall back to the root of the memstick. + destPath = g_Config.memStickDirectory; + } + g_OSD.SetProgressBar("install", di->T("Installing..."), 0.0f, 0.0f, 0.0f, 0.1f); + + // TODO: To save disk space, we should probably attempt a move first, if deleteAfter is true. + // TODO: Update the progress bar continuously. + bool success = File::Copy(task.fileName, destPath); + if (!success) { ERROR_LOG(Log::HLE, "Raw ISO install failed"); // This shouldn't normally happen at all (only when putting ISOs in a store, which is not a normal use case), so skipping the translation string SetInstallError("Failed to install raw ISO"); } + if (task.deleteAfter) { + File::Delete(task.fileName); + } + g_OSD.RemoveProgressBar("install", success, 0.5f); + installProgress_ = 1.0f; + InstallDone(); return; } @@ -404,8 +420,10 @@ void GameManager::InstallZipContents(ZipFileTask task) { struct zip *z = ZipOpenPath(task.fileName); if (!z) { - g_OSD.RemoveProgressBar("install", false, 0.5f); + g_OSD.RemoveProgressBar("install", false, 1.5f); SetInstallError(sy->T("Unable to open zip file")); + installProgress_ = 1.0f; + InstallDone(); return; } @@ -424,15 +442,17 @@ void GameManager::InstallZipContents(ZipFileTask task) { { Path pspGame = GetSysDirectory(DIRECTORY_GAME); INFO_LOG(Log::HLE, "Installing '%s' into '%s'", task.fileName.c_str(), pspGame.c_str()); - // InstallZipContents contains code to close (and delete) z. + // InstallZipContents contains code to close z. success = ExtractZipContents(z, pspGame, zipInfo, false); break; } case ZipFileContents::ISO_FILE: - INFO_LOG(Log::HLE, "Installing '%s' into its containing directory", task.fileName.c_str()); + { + INFO_LOG(Log::HLE, "Installing '%s' into '%s'", task.fileName.c_str(), task.destination.c_str()); // InstallZippedISO contains code to close z. - success = InstallZippedISO(z, zipInfo.isoFileIndex, task.fileName, task.deleteAfter); + success = InstallZippedISO(z, zipInfo.isoFileIndex, task.destination); break; + } case ZipFileContents::TEXTURE_PACK: { // InstallMemstickGame contains code to close z, and works for textures too. @@ -468,10 +488,16 @@ void GameManager::InstallZipContents(ZipFileTask task) { break; } + // Common functionality. if (task.deleteAfter && success) { File::Delete(task.fileName); } g_OSD.RemoveProgressBar("install", success, 0.5f); + installProgress_ = 1.0f; + InstallDone(); + if (success) { + ResetInstallError(); + } } bool GameManager::DetectTexturePackDest(struct zip *z, int iniIndex, Path &dest) { @@ -765,10 +791,6 @@ bool GameManager::ExtractZipContents(struct zip *z, const Path &dest, const ZipF INFO_LOG(Log::HLE, "Unzipped %d files (%d bytes / %d).", info.numFiles, (int)bytesCopied, (int)allBytes); zip_close(z); z = nullptr; - installProgress_ = 1.0f; - InstallDone(); - ResetInstallError(); - g_OSD.RemoveProgressBar("install", true, 0.5f); return true; bail: @@ -782,7 +804,6 @@ bail: File::DeleteDir(iter); } SetInstallError(sy->T("Storage full")); - g_OSD.RemoveProgressBar("install", false, 0.5f); return false; } @@ -842,7 +863,7 @@ bool GameManager::InstallMemstickZip(struct zip *z, const Path &zipfile, const P return true; } -bool GameManager::InstallZippedISO(struct zip *z, int isoFileIndex, const Path &zipfile, bool deleteAfter) { +bool GameManager::InstallZippedISO(struct zip *z, int isoFileIndex, const Path &destDir) { // Let's place the output file in the currently selected Games directory. std::string fn = zip_get_name(z, isoFileIndex, 0); size_t nameOffset = fn.rfind('/'); @@ -866,7 +887,12 @@ bool GameManager::InstallZippedISO(struct zip *z, int isoFileIndex, const Path & name = name.substr(2); } - Path outputISOFilename = Path(g_Config.currentDirectory) / name; + Path outputISOFilename = destDir; + if (outputISOFilename.empty()) { + outputISOFilename = Path(g_Config.currentDirectory); + } + outputISOFilename = outputISOFilename / name; + size_t bytesCopied = 0; bool success = false; auto di = GetI18NCategory(I18NCat::DIALOG); @@ -876,10 +902,6 @@ bool GameManager::InstallZippedISO(struct zip *z, int isoFileIndex, const Path & success = true; } zip_close(z); - if (success && deleteAfter) { - File::Delete(zipfile); - g_OSD.SetProgressBar("install", di->T("Installing..."), 0.0f, 0.0f, 0.0f, 0.1f); - } g_OSD.RemoveProgressBar("install", success, 0.5f); z = 0; @@ -910,25 +932,6 @@ bool GameManager::UninstallGameOnThread(const std::string &name) { return true; } -bool GameManager::InstallRawISO(const Path &file, const std::string &originalName, bool deleteAfter) { - Path destPath = Path(g_Config.currentDirectory) / originalName; - auto di = GetI18NCategory(I18NCat::DIALOG); - g_OSD.SetProgressBar("install", di->T("Installing..."), 0.0f, 0.0f, 0.0f, 0.1f); - // TODO: To save disk space, we should probably attempt a move first. - if (File::Copy(file, destPath)) { - if (deleteAfter) { - File::Delete(file); - } - g_OSD.RemoveProgressBar("install", true, 0.5f); - } else { - g_OSD.RemoveProgressBar("install", false, 0.5f); - } - installProgress_ = 1.0f; - InstallDone(); - ResetInstallError(); - return true; -} - void GameManager::ResetInstallError() { if (!InstallInProgress()) { installError_.clear(); diff --git a/Core/Util/GameManager.h b/Core/Util/GameManager.h index dffddfd4fd..27d7422d2b 100644 --- a/Core/Util/GameManager.h +++ b/Core/Util/GameManager.h @@ -64,6 +64,7 @@ struct ZipFileTask { std::optional zipFileInfo; Path url; // Same as filename if installing from disk. Probably not really useful. Path fileName; + Path destination; // If set, will override the default destination. bool deleteAfter; }; @@ -117,8 +118,7 @@ private: bool ExtractZipContents(struct zip *z, const Path &dest, const ZipFileInfo &info, bool allowRoot); bool InstallMemstickZip(struct zip *z, const Path &zipFile, const Path &dest, const ZipFileInfo &info); - bool InstallZippedISO(struct zip *z, int isoFileIndex, const Path &zipfile, bool deleteAfter); - bool InstallRawISO(const Path &zipFile, const std::string &originalName, bool deleteAfter); + bool InstallZippedISO(struct zip *z, int isoFileIndex, const Path &destDir); void UninstallGame(const std::string &name); void InstallDone(); diff --git a/UI/InstallZipScreen.cpp b/UI/InstallZipScreen.cpp index c676d168a6..2278a88002 100644 --- a/UI/InstallZipScreen.cpp +++ b/UI/InstallZipScreen.cpp @@ -20,8 +20,10 @@ #include "Common/UI/ViewGroup.h" #include "Common/StringUtils.h" +#include "Common/File/FileUtil.h" #include "Common/Data/Text/I18n.h" #include "Common/Data/Text/Parsers.h" +#include "Core/Config.h" #include "Core/System.h" #include "Core/Util/GameManager.h" #include "Core/Loaders.h" @@ -65,6 +67,10 @@ void InstallZipScreen::CreateViews() { doneView_ = nullptr; installChoice_ = nullptr; existingSaveView_ = nullptr; + destFolders_.clear(); + + std::vector destOptions; + if (z) { DetectZipFileContents(z, &zipFileInfo_); // Even if this fails, it sets zipInfo->contents. if (zipFileInfo_.contents == ZipFileContents::ISO_FILE || zipFileInfo_.contents == ZipFileContents::PSP_GAME_DIR) { @@ -78,6 +84,21 @@ void InstallZipScreen::CreateViews() { doneView_ = leftColumn->Add(new TextView("")); + if (zipFileInfo_.contents == ZipFileContents::ISO_FILE) { + const bool isInDownloads = File::IsProbablyInDownloadsFolder(zipPath_); + Path parent; + if (!isInDownloads && zipPath_.CanNavigateUp()) { + parent = zipPath_.NavigateUp(); + destFolders_.push_back(parent); + } + if (g_Config.currentDirectory.IsLocalType() && File::Exists(g_Config.currentDirectory) && g_Config.currentDirectory != parent) { + destFolders_.push_back(g_Config.currentDirectory); + } + destFolders_.push_back(g_Config.memStickDirectory); + } else { + destFolders_.push_back(GetSysDirectory(DIRECTORY_GAME)); + } + installChoice_ = rightColumnItems->Add(new Choice(iz->T("Install"))); installChoice_->OnClick.Handle(this, &InstallZipScreen::OnInstall); returnToHomebrew_ = true; @@ -102,6 +123,8 @@ void InstallZipScreen::CreateViews() { Path savedataDir = GetSysDirectory(DIRECTORY_SAVEDATA); bool overwrite = !CanExtractWithoutOverwrite(z, savedataDir, 50); + destFolders_.push_back(savedataDir); + leftColumn->Add(new NoticeView(NoticeLevel::WARN, di->T("Confirm Overwrite"), "")); int columnWidth = 300; @@ -143,6 +166,15 @@ void InstallZipScreen::CreateViews() { leftColumn->Add(new TextView(er->T("Error reading file"), ALIGN_LEFT, false, new AnchorLayoutParams(10, 10, NONE, NONE))); } + if (destFolders_.size() > 1) { + leftColumn->Add(new TextView(iz->T("Install into folder"))); + for (int i = 0; i < (int)destFolders_.size(); i++) { + leftColumn->Add(new RadioButton(&destFolderChoice_, i, destFolders_[i].ToVisualString())); + } + } else if (destFolders_.size() == 1 && zipFileInfo_.contents != ZipFileContents::SAVE_DATA) { + leftColumn->Add(new TextView(StringFromFormat("%s %s", iz->T_cstr("Install into folder:"), destFolders_[0].ToVisualString().c_str()))); + } + // OK so that EmuScreen will handle it right. backChoice_ = rightColumnItems->Add(new Choice(di->T("Back"))); backChoice_->OnClick.Handle(this, &UIScreen::OnOK); @@ -166,6 +198,9 @@ UI::EventReturn InstallZipScreen::OnInstall(UI::EventParams ¶ms) { task.fileName = zipPath_; task.deleteAfter = deleteZipFile_; task.zipFileInfo = zipFileInfo_; + if (!destFolders_.empty() && destFolderChoice_ < destFolders_.size()) { + task.destination = destFolders_[destFolderChoice_]; + } if (g_GameManager.InstallZipOnThread(task)) { installStarted_ = true; if (installChoice_) { diff --git a/UI/InstallZipScreen.h b/UI/InstallZipScreen.h index 68ad95c427..68982187ac 100644 --- a/UI/InstallZipScreen.h +++ b/UI/InstallZipScreen.h @@ -19,6 +19,8 @@ #include +#include "Common/File/Path.h" + #include "Common/UI/View.h" #include "Common/UI/UIScreen.h" @@ -46,6 +48,8 @@ private: SavedataView *existingSaveView_ = nullptr; Path savedataToOverwrite_; Path zipPath_; + std::vector destFolders_; + int destFolderChoice_ = 0; ZipFileInfo zipFileInfo_{}; bool returnToHomebrew_ = true; bool installStarted_ = false; From 58da0fa93696d0385b688df1aa4c2484bf85e7df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 10 Sep 2024 13:15:57 +0200 Subject: [PATCH 2/2] Add new translation string --- assets/lang/ar_AE.ini | 1 + assets/lang/az_AZ.ini | 1 + assets/lang/bg_BG.ini | 1 + assets/lang/ca_ES.ini | 1 + assets/lang/cz_CZ.ini | 1 + assets/lang/da_DK.ini | 1 + assets/lang/de_DE.ini | 1 + assets/lang/dr_ID.ini | 1 + assets/lang/en_US.ini | 1 + assets/lang/es_ES.ini | 1 + assets/lang/es_LA.ini | 1 + assets/lang/fa_IR.ini | 1 + assets/lang/fi_FI.ini | 1 + assets/lang/fr_FR.ini | 1 + assets/lang/gl_ES.ini | 1 + assets/lang/gr_EL.ini | 1 + assets/lang/he_IL.ini | 1 + assets/lang/he_IL_invert.ini | 1 + assets/lang/hr_HR.ini | 1 + assets/lang/hu_HU.ini | 1 + assets/lang/id_ID.ini | 1 + assets/lang/it_IT.ini | 1 + assets/lang/ja_JP.ini | 1 + assets/lang/jv_ID.ini | 1 + assets/lang/ko_KR.ini | 1 + assets/lang/ku_SO.ini | 1 + assets/lang/lo_LA.ini | 1 + assets/lang/lt-LT.ini | 1 + assets/lang/ms_MY.ini | 1 + assets/lang/nl_NL.ini | 1 + assets/lang/no_NO.ini | 1 + assets/lang/pl_PL.ini | 1 + assets/lang/pt_BR.ini | 1 + assets/lang/pt_PT.ini | 1 + assets/lang/ro_RO.ini | 1 + assets/lang/ru_RU.ini | 1 + assets/lang/sv_SE.ini | 1 + assets/lang/tg_PH.ini | 1 + assets/lang/th_TH.ini | 1 + assets/lang/tr_TR.ini | 1 + assets/lang/uk_UA.ini | 1 + assets/lang/vi_VN.ini | 1 + assets/lang/zh_CN.ini | 1 + assets/lang/zh_TW.ini | 1 + 44 files changed, 44 insertions(+) diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 313104ecce..7dc26921a5 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -714,6 +714,7 @@ Delete ZIP file = ‎مسح الملف المضغوط Existing data = Existing data Install = ‎تثبيت Install game from ZIP file? = ‎تثبيت اللعبة من الملف المضغوط ? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = فشل في التثبيت Installed! = ‎مثبت! diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 79f47ec2cb..06978c6210 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -706,6 +706,7 @@ Delete ZIP file = Delete ZIP file Existing data = Existing data Install = Install Install game from ZIP file? = Install game from ZIP file? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Installed! diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index a5cc89d860..33887122d0 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -706,6 +706,7 @@ Delete ZIP file = Изтрий ZIP архива Existing data = Existing data Install = Инсталирай Install game from ZIP file? = Инсталирай игра от ZIP архив? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Инсталирано! diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index 92ab4b1213..aeede7096d 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -706,6 +706,7 @@ Delete ZIP file = Delete ZIP file Existing data = Existing data Install = Install Install game from ZIP file? = Install game from ZIP file? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Installed! diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index 3d27e6fcaa..0855779b33 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -706,6 +706,7 @@ Delete ZIP file = Smazat soubor ZIP Existing data = Existing data Install = Nainstalovat Install game from ZIP file? = Instalovat hru ze souboru ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Instalováno! diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index 1cc2ffdcf2..711ca6dce7 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -706,6 +706,7 @@ Delete ZIP file = Slet ZIP fil Existing data = Existing data Install = Installer Install game from ZIP file? = Installer spil fra ZIP fil? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Installeret! diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index 9b7ae5b0b2..39d4248417 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -706,6 +706,7 @@ Delete ZIP file = ZIP Datei löschen Existing data = Existing data Install = Installieren Install game from ZIP file? = Spiel aus ZIP Datei installieren? +Install in folder = Install in folder Install textures from ZIP file? = Texturen von ZIP Datei installieren? Installation failed = Installation failed Installed! = Installiert! diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index 0c702ae8b9..68e840afe3 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -706,6 +706,7 @@ Delete ZIP file = Delete ZIP file Existing data = Existing data Install = Install Install game from ZIP file? = Install game from ZIP file? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Installed! diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index 46bcbbb44f..857adc1436 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -730,6 +730,7 @@ Delete ZIP file = Delete ZIP file Existing data = Existing data Install = Install Install game from ZIP file? = Install game from ZIP file? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Installed! diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index 09cdf7c5bd..301dcfb9ac 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -706,6 +706,7 @@ Delete ZIP file = Borrar archivo ZIP Existing data = Existing data Install = Instalar Install game from ZIP file? = ¿Instalar juego desde archivo ZIP? +Install in folder = Install in folder Install textures from ZIP file? = ¿Instalar texturas desde archivo ZIP? Installation failed = Installation failed Installed! = ¡Instalado! diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index 49106ee515..930c6dbb25 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -706,6 +706,7 @@ Delete ZIP file = Borrar archivo ZIP Existing data = Existing data Install = Instalar Install game from ZIP file? = ¿Instalar juego desde un archivo ZIP? +Install in folder = Install in folder Install textures from ZIP file? = ¿Instalar texturas desde un archivo ZIP? Installation failed = Instalación fallida Installed! = ¡Instalado! diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index 493be1c02c..b6baa43a7c 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -706,6 +706,7 @@ Delete ZIP file = Delete ZIP file Existing data = Existing data Install = Install Install game from ZIP file? = Install game from ZIP file? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Installed! diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index 28975b0ae3..022382b574 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -706,6 +706,7 @@ Delete ZIP file = Poista ZIP-tiedosto Existing data = Existing data Install = Asenna Install game from ZIP file? = Asenna peli ZIP-tiedostosta? +Install in folder = Install in folder Install textures from ZIP file? = Asenna tekstuureja ZIP-tiedostosta? Installation failed = Installation failed Installed! = Asenettu! diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index 6bd5ab79e3..0b9ed664f2 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -706,6 +706,7 @@ Delete ZIP file = Supprimer le fichier ZIP Existing data = Existing data Install = Installer Install game from ZIP file? = Installer le jeu depuis le fichier ZIP ? +Install in folder = Install in folder Install textures from ZIP file? = Installer les textures depuis le fichier ZIP ? Installation failed = Installation failed Installed! = Installé ! diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index ef6c1dc308..69786c57af 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -706,6 +706,7 @@ Delete ZIP file = Borrar arquivo ZIP Existing data = Existing data Install = Instalar Install game from ZIP file? = Instalar xogo dende un arquivo ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = ¡Instalado! diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index 88e335afae..f47244b991 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -706,6 +706,7 @@ Delete ZIP file = Διαγραφή αρχείου ZIP Existing data = Existing data Install = Εγκατάσταση Install game from ZIP file? = Εγκατάσταση παιχνιδιού από το αρχείο ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Εγκαταστάθηκε! diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index 234c799b70..223f03c1fc 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -706,6 +706,7 @@ Delete ZIP file = Delete ZIP file Existing data = Existing data Install = Install Install game from ZIP file? = Install game from ZIP file? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Installed! diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index 724e01745f..771d8a2d20 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -706,6 +706,7 @@ Delete ZIP file = Delete ZIP file Existing data = Existing data Install = Install Install game from ZIP file? = Install game from ZIP file? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Installed! diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index 6bb59eb3b8..d899733a4e 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -706,6 +706,7 @@ Delete ZIP file = Izbriši ZIP datoteku Existing data = Existing data Install = Instaliraj Install game from ZIP file? = Instaliraj igru iz ZIP datoteke? +Install in folder = Install in folder Install textures from ZIP file? = Instaliraj teksture iz ZIP datoteke? Installation failed = Installation failed Installed! = Instalirano! diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 1841fb3cb8..f9573aeee5 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -706,6 +706,7 @@ Delete ZIP file = ZIP fájl törlése Existing data = Existing data Install = Telepítés Install game from ZIP file? = Játék telepítése ZIP fájlból? +Install in folder = Install in folder Install textures from ZIP file? = Textúrák telepítése ZIP fájlból? Installation failed = Installation failed Installed! = Telepítve! diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index b92c0c3439..257a7da6fb 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -706,6 +706,7 @@ Delete ZIP file = Hapus berkas ZIP Existing data = Existing data Install = Pasang Install game from ZIP file? = Pasang permainan dari berkas ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Pasang tekstur dari file ZIP? Installation failed = Installation failed Installed! = Terpasang! diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index 00286a0fca..00ccce1fc7 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -707,6 +707,7 @@ Delete ZIP file = Elimina file ZIP Existing data = Existing data Install = Installa Install game from ZIP file? = Installare il gioco dal file ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Installare le texture dal file ZIP? Installation failed = Installation failed Installed! = Installato! diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index 380cc520d4..0cef653fc7 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -706,6 +706,7 @@ Delete ZIP file = ZIPファイルを削除 Existing data = Existing data Install = インストールする Install game from ZIP file? = ZIPファイルからゲームをインストールしますか? +Install in folder = Install in folder Install textures from ZIP file? = ZIPファイルからテクスチャをインストールしますか? Installation failed = インストール失敗 Installed! = インストールしました diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index 9e75b0fb5c..0f9bf347fe 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -706,6 +706,7 @@ Delete ZIP file = Mbusek berkas ZIP Existing data = Existing data Install = Nginstal Install game from ZIP file? = Nginstal dolanan saka berkas ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Keinstal! diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index 12ad29c829..3ed05610fe 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -706,6 +706,7 @@ Delete ZIP file = ZIP 파일 삭제 Existing data = Existing data Install = 설치 Install game from ZIP file? = ZIP 파일에서 게임을 설치하겠습니까? +Install in folder = Install in folder Install textures from ZIP file? = ZIP 파일에서 텍스처를 설치하겠습니까? Installation failed = 설치 실패 Installed! = 설치되었습니다! diff --git a/assets/lang/ku_SO.ini b/assets/lang/ku_SO.ini index 56a5813447..498f018fc7 100644 --- a/assets/lang/ku_SO.ini +++ b/assets/lang/ku_SO.ini @@ -720,6 +720,7 @@ Delete ZIP file = Delete ZIP file Existing data = Existing data Install = Install Install game from ZIP file? = Install game from ZIP file? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Installed! diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index e2fb3c39bb..f744319725 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -706,6 +706,7 @@ Delete ZIP file = ລຶບໄຟລ໌ ZIP Existing data = Existing data Install = ຕິດຕັ້ງ Install game from ZIP file? = ຕິດຕັ້ງເກມຈາກໄຟລ໌ ZIP ຫຼືບໍ່? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = ຕິດຕັ້ງແລ້ວ! diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index 9d68ebc99b..15cefd32c9 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -706,6 +706,7 @@ Delete ZIP file = Ištrinti ZIP failą Existing data = Existing data Install = Instaliuoti Install game from ZIP file? = Instaliuoti žaidimą iš ZIP failo? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Instaliuota! diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index b5b49f7981..f082e183ce 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -706,6 +706,7 @@ Delete ZIP file = Padam fail ZIP Existing data = Existing data Install = Pasang Install game from ZIP file? = Pasang permainan dari fail ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Dipasang! diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index 4ce17bdc0b..336a60f550 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -706,6 +706,7 @@ Delete ZIP file = ZIP-bestand wissen Existing data = Existing data Install = Installeren Install game from ZIP file? = Game installeren vanuit het ZIP-bestand? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Installatie voltooid! diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index 314d195d45..f1f6258180 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -706,6 +706,7 @@ Delete ZIP file = Delete ZIP file Existing data = Existing data Install = Install Install game from ZIP file? = Install game from ZIP file? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Installed! diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index a2677fbf3d..14f805d8fc 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -710,6 +710,7 @@ Delete ZIP file = Usuń plik ZIP Existing data = Existing data Install = Zainstaluj Install game from ZIP file? = Zainstalować grę z pliku ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Czy zainstalować teksturę z archiwum ZIP? Installation failed = Installation failed Installed! = Zainstalowano! diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index 8024a5b91b..22df13ac4e 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -730,6 +730,7 @@ Delete ZIP file = Apagar arquivo ZIP Existing data = Existing data Install = Instalar Install game from ZIP file? = Instalar o jogo do arquivo ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Instalar as texturas do arquivo ZIP? Installation failed = A instalação falhou Installed! = Instalado! diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index ba633ef0d2..3c7a073712 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -730,6 +730,7 @@ Delete ZIP file = Eliminar ficheiro .zip Existing data = Existing data Install = Instalar Install game from ZIP file? = Instalar o jogo do ficheiro .zip? +Install in folder = Install in folder Install textures from ZIP file? = Instalar as texturas do ficheiro .zip? Installation failed = Installation failed Installed! = Instalado! diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index 50e349f87a..e4fff2753c 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -707,6 +707,7 @@ Delete ZIP file = Șterge fișier ZIP Existing data = Existing data Install = Instalează Install game from ZIP file? = Instalează joc din fișier ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Instalat! diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index 6bd404ebc5..367804a2cd 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -706,6 +706,7 @@ Delete ZIP file = Удалить файл ZIP Existing data = Existing data Install = Установить Install game from ZIP file? = Установить игру из файла ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Установить текстуры из файла ZIP? Installation failed = Не удалось установить Installed! = Установлено! diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index fc43a79f48..8f8a098490 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -707,6 +707,7 @@ Delete ZIP file = Ta bort ZIP-fil Existing data = Existerande data Install = Installera Install game from ZIP file? = Installera spel från ZIP-fil? +Install in folder = Installera i mapp Install textures from ZIP file? = Installera texturer från ZIP-fil? Installation failed = Installation misslyckades Installed! = Installerad! diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index 8ffc26bc2e..a07c5cd806 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -707,6 +707,7 @@ Delete ZIP file = Burahin ang ZIP File Existing data = Existing data Install = Install Install game from ZIP file? = I-install ang laro mula sa ZIP file? +Install in folder = Install in folder Install textures from ZIP file? = I-install ang texture mula sa ZIP file? Installation failed = Hindi mainstall Installed! = Naka-install na! diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index d1d6f70d36..9aabb24787 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -713,6 +713,7 @@ Delete ZIP file = ลบไฟล์ ZIP Existing data = Existing data Install = ติดตั้ง Install game from ZIP file? = ต้องการติดตั้งเกมจากไฟล์ ZIP เลยหรือไม่? +Install in folder = Install in folder Install textures from ZIP file? = ต้องการติดตั้งเท็คเจอร์จากไฟล์ ZIP เลยหรือไม่? Installation failed = การติดตั้งล้มเหลว Installed! = ติดตั้งเสร็จสิ้น! diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index f1d8a52d01..06c80a32ba 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -708,6 +708,7 @@ Delete ZIP file = ZIP dosyasını sil Existing data = Existing data Install = Yükle Install game from ZIP file? = ZIP dosyasından oyun yüklensin mi? +Install in folder = Install in folder Install textures from ZIP file? = ZIP dosyasından dokular yüklensin mi? Installation failed = Yükleme başarısız Installed! = Yüklendi! diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index 58d4610730..7ba65e614f 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -706,6 +706,7 @@ Delete ZIP file = Видалити ZIP файл Existing data = Existing data Install = Встановити Install game from ZIP file? = Встановити гру з ZIP-файлу? +Install in folder = Install in folder Install textures from ZIP file? = Встановити текстури з ZIP-файлу? Installation failed = Installation failed Installed! = Встановлено! diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index c93d3db9e2..4f5473cb61 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -706,6 +706,7 @@ Delete ZIP file = Xóa file ZIP Existing data = Existing data Install = Cài đặt Install game from ZIP file? = Cài đặt trò chơi từ file ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Đã cài xong! diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 969bfe77c5..1b72e2b5a2 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -706,6 +706,7 @@ Delete ZIP file = 删除ZIP文件 Existing data = Existing data Install = 安装 Install game from ZIP file? = 从ZIP文件安装游戏? +Install in folder = Install in folder Install textures from ZIP file? = 从ZIP文件安装纹理包? Installation failed = 安装失败! Installed! = 安装完成! diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 9f45854ebb..3c5f05c45d 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -706,6 +706,7 @@ Delete ZIP file = 刪除 ZIP 檔案 Existing data = Existing data Install = 安裝 Install game from ZIP file? = 從 ZIP 檔案安裝遊戲? +Install in folder = Install in folder Install textures from ZIP file? = 從 ZIP 檔案安裝紋理? Installation failed = 安裝失敗 Installed! = 已安裝!