powershell_unzip | changelog fix

Does not use zlin-ng to unpack, now uses powershell on windows and on linux/mac uses unzip or 7z, and if it does not find it, it will ask if you want to install it before extracting.

Do not show the changelog button if: The current version is a pre-release and the version to be downloaded is a release.
This commit is contained in:
DanielSvoboda 2024-09-20 21:39:18 -03:00
parent 110522f57a
commit bef0fc0c41
29 changed files with 155 additions and 549 deletions

View File

@ -17,12 +17,12 @@ static s32 gpuId = -1; // Vulkan physical device index. Set to negative for auto
static std::string logFilter;
static std::string logType = "async";
static std::string userName = "shadPS4";
static std::string updateChannel = "unstable";
static std::string updateChannel = "stable";
static bool useSpecialPad = false;
static int specialPadClass = 1;
static bool isDebugDump = false;
static bool isShowSplash = false;
static bool isAutoUpdate = true;
static bool isAutoUpdate = false;
static bool isNullGpu = false;
static bool shouldCopyGPUBuffers = false;
static bool shouldDumpShaders = false;
@ -382,9 +382,9 @@ void load(const std::filesystem::path& path) {
logFilter = toml::find_or<std::string>(general, "logFilter", "");
logType = toml::find_or<std::string>(general, "logType", "sync");
userName = toml::find_or<std::string>(general, "userName", "shadPS4");
updateChannel = toml::find_or<std::string>(general, "updateChannel", "unstable");
updateChannel = toml::find_or<std::string>(general, "updateChannel", "stable");
isShowSplash = toml::find_or<bool>(general, "showSplash", true);
isAutoUpdate = toml::find_or<bool>(general, "autoUpdate", true);
isAutoUpdate = toml::find_or<bool>(general, "autoUpdate", false);
}
if (data.contains("Input")) {
@ -529,12 +529,12 @@ void setDefaultValues() {
logFilter = "";
logType = "async";
userName = "shadPS4";
updateChannel = "unstable";
updateChannel = "stable";
useSpecialPad = false;
specialPadClass = 1;
isDebugDump = false;
isShowSplash = false;
isAutoUpdate = true;
isAutoUpdate = false;
isNullGpu = false;
shouldDumpShaders = false;
shouldDumpPM4 = false;

View File

@ -5,7 +5,6 @@
#include <QDateTime>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
@ -23,7 +22,6 @@
#include <common/config.h>
#include <common/path_util.h>
#include <common/scm_rev.h>
#include <zlib-ng.h>
#include "checkUpdate.h"
using namespace Common::FS;
@ -142,13 +140,13 @@ void CheckUpdate::CheckForUpdates(const bool showMessage) {
close();
return;
} else {
setupUI_UpdateAvailable(downloadUrl, latestDate, latestRev, currentDate, currentRev);
setupUI(downloadUrl, latestDate, latestRev, currentDate, currentRev);
}
reply->deleteLater();
});
}
void CheckUpdate::setupUI_UpdateAvailable(const QString& downloadUrl, const QString& latestDate,
void CheckUpdate::setupUI(const QString& downloadUrl, const QString& latestDate,
const QString& latestRev, const QString& currentDate,
const QString& currentRev) {
QVBoxLayout* layout = new QVBoxLayout(this);
@ -158,7 +156,7 @@ void CheckUpdate::setupUI_UpdateAvailable(const QString& downloadUrl, const QStr
QPixmap pixmap(":/images/shadps4.ico");
imageLabel->setPixmap(pixmap);
imageLabel->setScaledContents(true);
imageLabel->setFixedSize(40, 40);
imageLabel->setFixedSize(50, 50);
QLabel* titleLabel = new QLabel("<h1>" + tr("Update Available") + "</h1>", this);
titleLayout->addWidget(imageLabel);
@ -189,28 +187,27 @@ void CheckUpdate::setupUI_UpdateAvailable(const QString& downloadUrl, const QStr
layout->addLayout(bottomLayout);
QString updateChannel = QString::fromStdString(Config::getUpdateChannel());
// Create text field for changelog
if (updateChannel == "unstable") {
// Don't show changelog button if:
// The current version is a pre-release and the version to be downloaded is a release.
bool current_isRelease = currentRev.startsWith('v', Qt::CaseInsensitive);
bool latest_isRelease = latestRev.startsWith('v', Qt::CaseInsensitive);
if (!current_isRelease && latest_isRelease) {
} else {
QTextEdit* textField = new QTextEdit(this);
textField->setReadOnly(true);
textField->setFixedWidth(400);
textField->setFixedHeight(200);
textField->setVisible(false);
layout->addWidget(textField);
// Create toggle button for changelog
QPushButton* toggleButton = new QPushButton(tr("Show Changelog"), this);
layout->addWidget(toggleButton);
// Connect the toggle button to the slot to show/hide changelog
connect(toggleButton, &QPushButton::clicked,
[this, textField, toggleButton, currentRev, latestRev, downloadUrl, latestDate,
currentDate]() {
QString updateChannel = QString::fromStdString(Config::getUpdateChannel());
if (updateChannel == "unstable") {
if (!textField->isVisible()) {
requestChangelog(currentRev, latestRev, downloadUrl, latestDate,
currentDate);
@ -222,18 +219,15 @@ void CheckUpdate::setupUI_UpdateAvailable(const QString& downloadUrl, const QStr
toggleButton->setText(tr("Show Changelog"));
adjustSize();
}
} else {
QMessageBox::information(
this, tr("Changelog Unavailable"),
tr("Viewing changelog is only available for the 'unstable' channel."));
}
});
} else {
adjustSize();
}
connect(yesButton, &QPushButton::clicked, this,
[this, downloadUrl]() { DownloadAndInstallUpdate(downloadUrl); });
connect(yesButton, &QPushButton::clicked, this, [this, downloadUrl]() {
yesButton->setEnabled(false);
noButton->setEnabled(false);
DownloadUpdate(downloadUrl);
});
connect(noButton, &QPushButton::clicked, this, [this]() { close(); });
autoUpdateCheckBox->setChecked(Config::autoUpdate());
@ -278,7 +272,7 @@ void CheckUpdate::requestChangelog(const QString& currentRev, const QString& lat
QJsonObject commitObj = commitValue.toObject();
QString message = commitObj["commit"].toObject()["message"].toString();
// Remove texts after the first line break, if any
// Remove texts after first line break, if any, to make it cleaner
int newlineIndex = message.indexOf('\n');
if (newlineIndex != -1) {
message = message.left(newlineIndex);
@ -299,7 +293,7 @@ void CheckUpdate::requestChangelog(const QString& currentRev, const QString& lat
});
}
void CheckUpdate::DownloadAndInstallUpdate(const QString& url) {
void CheckUpdate::DownloadUpdate(const QString& url) {
QNetworkRequest request(url);
QNetworkReply* reply = networkManager->get(request);
@ -327,7 +321,6 @@ void CheckUpdate::DownloadAndInstallUpdate(const QString& url) {
file.close();
QMessageBox::information(this, tr("Download Complete"),
tr("The update has been downloaded, press OK to install."));
Unzip();
Install();
} else {
QMessageBox::warning(
@ -339,209 +332,13 @@ void CheckUpdate::DownloadAndInstallUpdate(const QString& url) {
});
}
void CheckUpdate::Unzip() {
QString userPath =
QString::fromStdString(Common::FS::GetUserPath(Common::FS::PathType::UserDir).string());
QString tempDirPath = userPath + "/temp_download_update";
QString zipFilePath = tempDirPath + "/temp_download_update.zip";
QFile zipFile(zipFilePath);
if (!zipFile.open(QIODevice::ReadOnly)) {
QMessageBox::warning(this, tr("Error"),
tr("Failed to open the ZIP file") + ":\n" + zipFilePath);
return;
}
QByteArray zipData = zipFile.readAll();
zipFile.close();
const uint8_t* data = reinterpret_cast<const uint8_t*>(zipData.constData());
size_t size = zipData.size();
size_t offset = 0;
#pragma pack(push, 1)
struct ZipLocalFileHeader {
uint32_t signature;
uint16_t version;
uint16_t flags;
uint16_t method;
uint16_t time;
uint16_t date;
uint32_t crc32;
uint32_t compressedSize;
uint32_t uncompressedSize;
uint16_t filenameLength;
uint16_t extraFieldLength;
};
#pragma pack(pop)
auto readLocalFileHeader = [&](const uint8_t* data, size_t offset,
ZipLocalFileHeader& header) -> bool {
memcpy(&header, data + offset, sizeof(header));
return header.signature == 0x04034b50;
};
auto decompressData = [&](const std::vector<uint8_t>& compressedData,
std::vector<uint8_t>& decompressedData) -> bool {
zng_stream strm = {};
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = compressedData.size();
strm.next_in = reinterpret_cast<Bytef*>(const_cast<uint8_t*>(compressedData.data()));
if (zng_inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
return false;
}
strm.avail_out = decompressedData.size();
strm.next_out = decompressedData.data();
int result = zng_inflate(&strm, Z_NO_FLUSH);
if (result != Z_STREAM_END) {
zng_inflateEnd(&strm);
return false;
}
zng_inflateEnd(&strm);
return true;
};
while (offset < size) {
ZipLocalFileHeader header;
if (readLocalFileHeader(data, offset, header)) {
uint16_t fileNameLength = header.filenameLength;
std::string fileName(reinterpret_cast<const char*>(data + offset + sizeof(header)),
fileNameLength);
if (fileName.empty()) {
QMessageBox::warning(this, tr("Error"),
tr("File name is empty. Possibly corrupted ZIP."));
break;
}
offset += sizeof(header) + fileNameLength + header.extraFieldLength;
size_t compressedDataOffset = offset;
size_t compressedDataSize = header.compressedSize;
size_t uncompressedSize = header.uncompressedSize;
if (header.method == 0) {
// 0 = No need to decompress, just copy the data
std::vector<uint8_t> decompressedData(
data + compressedDataOffset, data + compressedDataOffset + compressedDataSize);
QString filePath = QString::fromUtf8(fileName.c_str());
QString fullPath = tempDirPath + "/" + filePath;
QFileInfo fileInfo(fullPath);
QString dirPath = fileInfo.path();
QDir dir(dirPath);
if (!dir.exists()) {
if (!dir.mkpath(dirPath)) {
QMessageBox::warning(this, tr("Error"),
tr("Failed to create directory") + ":\n" + dirPath);
continue;
}
}
QFile outFile(fullPath);
outFile.write(reinterpret_cast<const char*>(decompressedData.data()),
decompressedData.size());
outFile.close();
offset += compressedDataSize;
} else if (header.method == 8) {
// 8 = Decompression Deflate
std::vector<uint8_t> compressedData(
data + compressedDataOffset, data + compressedDataOffset + compressedDataSize);
std::vector<uint8_t> decompressedData(uncompressedSize);
if (!decompressData(compressedData, decompressedData)) {
QMessageBox::warning(this, tr("Error"),
tr("Error decompressing file") + ":\n" +
QString::fromStdString(fileName));
continue;
}
QString filePath = QString::fromUtf8(fileName.c_str());
QString fullPath = tempDirPath + "/" + filePath;
QFileInfo fileInfo(fullPath);
QString dirPath = fileInfo.path();
QDir dir(dirPath);
if (!dir.exists()) {
if (!dir.mkpath(dirPath)) {
QMessageBox::warning(this, tr("Error"),
tr("Failed to create directory") + ":\n" + dirPath);
continue;
}
}
QFile outFile(fullPath);
if (!outFile.open(QIODevice::WriteOnly)) {
QMessageBox::warning(this, tr("Error"),
tr("Failed to open output file") + ":\n" + fullPath);
continue;
}
outFile.write(reinterpret_cast<const char*>(decompressedData.data()),
decompressedData.size());
outFile.close();
offset += compressedDataSize;
} else {
QMessageBox::warning(this, tr("Error"),
tr("Unsupported compression method for file:") +
header.method + "\n" + QString::fromStdString(fileName));
break;
}
#if defined(Q_OS_MAC)
if (filePath == "shadps4-macos-qt.tar.gz") {
// Unpack the tar.gz file
QString tarGzFilePath = tempDirPath + "/" + filePath;
QString tarExtractDirPath = tempDirPath + "/tar_extracted";
QDir tarExtractDir(tarExtractDirPath);
if (!tarExtractDir.exists()) {
if (!tarExtractDir.mkpath(tarExtractDirPath)) {
QMessageBox::warning(this, tr("Error"),
tr("Failed to create TAR extraction directory") +
":\n" + tarExtractDirPath);
return;
}
}
QString tarCommand =
QString("tar -xzf %1 -C %2").arg(tarGzFilePath, tarExtractDirPath);
QProcess tarProcess;
tarProcess.start(tarCommand);
tarProcess.waitForFinished();
// Check if tar was successful
if (tarProcess.exitStatus() != QProcess::NormalExit || tarProcess.exitCode() != 0) {
QMessageBox::warning(this, tr("Error"),
tr("Failed to extract the TAR file") + ":\n" +
tarProcess.errorString());
return;
}
// Remove .tar.gz file after extraction
QFile::remove(tarGzFilePath);
}
#endif
} else {
offset++;
}
}
}
void CheckUpdate::Install() {
QString userPath =
QString::fromStdString(Common::FS::GetUserPath(Common::FS::PathType::UserDir).string());
QString tempDirPath = userPath + "/temp_download_update";
QString rootPath = QString::fromStdString(std::filesystem::current_path().string());
QString startingUpdate = tr("Starting Update...");
QString tempDirPath = userPath + "/temp_download_update";
QString rootPath = QString::fromStdString(std::filesystem::current_path().string());
QString scriptContent;
QString scriptFileName;
@ -550,50 +347,120 @@ void CheckUpdate::Install() {
#ifdef Q_OS_WIN
// Windows Batch Script
scriptFileName = tempDirPath + "/update.bat";
scriptContent = QStringLiteral("@echo off\n"
"chcp 65001\n"
"echo %1\n"
"timeout /t 2 /nobreak\n"
"xcopy /E /I /Y \"%2\\*\" \"%3\\\"\n"
"timeout /t 2 /nobreak\n"
"del /Q \"%3\\update.bat\"\n"
"del /Q \"%3\\temp_download_update.zip\"\n"
"start \"\" \"%3\\shadps4.exe\"\n"
"rmdir /S /Q \"%2\"\n");
arguments << "/C" << scriptFileName;
processCommand = "cmd.exe";
scriptFileName = tempDirPath + "/update.ps1";
scriptContent = QStringLiteral(
"Set-ExecutionPolicy Bypass -Scope Process -Force\n"
"Write-Output '%1'\n"
"Expand-Archive -Path '%2\\temp_download_update.zip' -DestinationPath '%2' -Force\n"
"Start-Sleep -Seconds 3\n"
"Copy-Item -Recurse -Force '%2\\*' '%3\\'\n"
"Start-Sleep -Seconds 2\n"
"Remove-Item -Force '%3\\update.ps1'\n"
"Remove-Item -Force '%3\\temp_download_update.zip'\n"
"Start-Process '%3\\shadps4.exe'\n"
"Remove-Item -Recurse -Force '%2'\n");
arguments << "-ExecutionPolicy"
<< "Bypass"
<< "-File" << scriptFileName;
processCommand = "powershell.exe";
#elif defined(Q_OS_LINUX)
// Linux Shell Script
scriptFileName = tempDirPath + "/update.sh";
scriptContent = QStringLiteral("#!/bin/bash\n"
"echo \"%1\"\n"
"sleep 2\n"
"cp -r \"%2/\"* \"%3/\"\n"
"sleep 2\n"
"rm \"%3/update.sh\"\n"
"rm \"%3/temp_download_update.zip\"\n"
"rm -r \"%2\"\n"
"chmod +x \"%3/Shadps4-qt.AppImage\"\n"
"cd \"%3\" && ./Shadps4-qt.AppImage\n");
scriptContent = QStringLiteral(
"#!/bin/bash\n"
"check_unzip() {\n"
" if ! command -v unzip &> /dev/null && ! command -v 7z &> /dev/null; then\n"
" echo \"Neither 'unzip' nor '7z' is installed.\"\n"
" read -p \"Would you like to install 'unzip'? (y/n): \" response\n"
" if [[ \"$response\" == \"y\" || \"$response\" == \"Y\" ]]; then\n"
" if [[ -f /etc/os-release ]]; then\n"
" . /etc/os-release\n"
" case \"$ID\" in\n"
" ubuntu|debian)\n"
" sudo apt-get install unzip -y\n"
" ;;\n"
" fedora|redhat)\n"
" sudo dnf install unzip -y\n"
" ;;\n"
" *)\n"
" echo \"Unsupported distribution for automatic installation.\"\n"
" exit 1\n"
" ;;\n"
" esac\n"
" else\n"
" echo \"Could not identify the distribution.\"\n"
" exit 1\n"
" fi\n"
" else\n"
" echo \"At least one of 'unzip' or '7z' is required to continue. The process "
"will be terminated.\"\n"
" exit 1\n"
" fi\n"
" fi\n"
"}\n"
"extract_file() {\n"
" if command -v unzip &> /dev/null; then\n"
" unzip -o \"%2/temp_download_update.zip\" -d \"%2/\"\n"
" elif command -v 7z &> /dev/null; then\n"
" 7z x \"%2/temp_download_update.zip\" -o\"%2/\" -y\n"
" else\n"
" echo \"No suitable extraction tool found.\"\n"
" exit 1\n"
" fi\n"
"}\n"
"main() {\n"
" check_unzip\n"
" echo \"%1\"\n"
" sleep 2\n"
" extract_file\n"
" sleep 2\n"
" cp -r \"%2/\"* \"%3/\"\n"
" sleep 2\n"
" rm \"%3/update.sh\"\n"
" rm \"%3/temp_download_update.zip\"\n"
" chmod +x \"%3/Shadps4-qt.AppImage\"\n"
" rm -r \"%2\"\n"
" cd \"%3\" && ./Shadps4-qt.AppImage\n"
"}\n"
"main\n");
arguments << scriptFileName;
processCommand = "bash";
#elif defined(Q_OS_MAC)
// macOS Shell Script
scriptFileName = tempDirPath + "/update.sh";
scriptContent = QStringLiteral("#!/bin/bash\n"
scriptContent = QStringLiteral(
"#!/bin/bash\n"
"check_tools() {\n"
" if ! command -v unzip &> /dev/null && ! command -v tar &> /dev/null; then\n"
" echo \"Neither 'unzip' nor 'tar' is installed.\"\n"
" read -p \"Would you like to install 'unzip'? (y/n): \" response\n"
" if [[ \"$response\" == \"y\" || \"$response\" == \"Y\" ]]; then\n"
" echo \"Please install 'unzip' using Homebrew or another package manager.\"\n"
" exit 1\n"
" else\n"
" echo \"At least one of 'unzip' or 'tar' is required to continue. The process "
"will be terminated.\"\n"
" exit 1\n"
" fi\n"
" fi\n"
"}\n"
"check_tools\n"
"echo \"%1\"\n"
"sleep 2\n"
"tar -xzf \"%2/temp_download_update.tar.gz\" -C \"%3\"\n"
"unzip -o \"%2/temp_download_update.zip\" -d \"%2/\"\n"
"sleep 2\n"
"tar -xzf \"%2/shadps4-macos-qt.tar.gz\" -C \"%3\"\n"
"sleep 2\n"
"rm \"%3/update.sh\"\n"
"chmod +x \"%3/shadps4.app/Contents/MacOS/shadps4\"\n"
"open \"%3/shadps4.app\"\n"
"rm -r \"%2\"\n");
arguments << scriptFileName;
processCommand = "bash";
#else
QMessageBox::warning(this, tr("Error"), "Unsupported operating system.");
return;

View File

@ -18,12 +18,11 @@ public:
private slots:
void CheckForUpdates(const bool showMessage);
void DownloadAndInstallUpdate(const QString& url);
void Unzip();
void DownloadUpdate(const QString& url);
void Install();
private:
void setupUI_UpdateAvailable(const QString& downloadUrl, const QString& latestDate,
void setupUI(const QString& downloadUrl, const QString& latestDate,
const QString& latestRev, const QString& currentDate,
const QString& currentRev);

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>إخفاء سجل التغييرات</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>سجل التغييرات غير متوفر</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>عرض سجل التغييرات متاح فقط للقناة 'غير المستقرة'.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>Skjul ændringslog</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>Ændringslog ikke tilgængelig</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>Visning af ændringsloggen er kun tilgængelig for den 'ustabile' kanal.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>Änderungsprotokoll ausblenden</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>Änderungsprotokoll nicht verfügbar</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>Die Ansicht des Änderungsprotokolls ist nur für den 'unstabilen' Kanal verfügbar.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>Απόκρυψη Ιστορικού Αλλαγών</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>Το Ιστορικό Αλλαγών δεν είναι διαθέσιμο</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>Η προβολή του ιστορικού αλλαγών είναι διαθέσιμη μόνο για το 'unstable' κανάλι.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>Hide Changelog</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>Changelog Unavailable</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>Viewing changelog is only available for the 'unstable' channel.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -21,7 +21,7 @@
<message>
<location filename="../about_dialog.ui" line="99"/>
<source>This software should not be used to play games you have not legally obtained.</source>
<translation>Este software no debe utilizarse para jugar juegos que no hayas obtenido legalmente.</translation>
<translation>Este software no debe utilizarse para jugar juegos que hayas obtenido ilegalmente.</translation>
</message>
</context>
<context>
@ -118,7 +118,7 @@
<message>
<location filename="../gui_context_menus.h" line="61"/>
<source>Copy Serial</source>
<translation>Copiar serial</translation>
<translation>Copiar número de serie</translation>
</message>
<message>
<location filename="../gui_context_menus.h" line="62"/>
@ -301,7 +301,7 @@
<message>
<location filename="../main_window_ui.h" line="355"/>
<source>Settings</source>
<translation>Configuraciones</translation>
<translation>Configuración</translation>
</message>
<message>
<location filename="../main_window_ui.h" line="356"/>
@ -346,7 +346,7 @@
<message>
<location filename="../main_window_ui.h" line="364"/>
<source>toolBar</source>
<translation>barra de herramientas</translation>
<translation>Barra de herramientas</translation>
</message>
</context>
<context>
@ -370,7 +370,7 @@
<message>
<location filename="../settings_dialog.ui" line="29"/>
<source>Settings</source>
<translation>Configuraciones</translation>
<translation>Configuración</translation>
</message>
<message>
<location filename="../settings_dialog.ui" line="67"/>
@ -558,7 +558,7 @@
<message>
<location filename="../main_window.cpp" line="392"/>
<source>All Patches available for all games have been downloaded.</source>
<translation>Todos los parches disponibles para todos los juegos han sido descargados.</translation>
<translation>Todos los parches disponibles han sido descargados para todos los juegos.</translation>
</message>
<message>
<location filename="../main_window.cpp" line="549"/>
@ -668,7 +668,7 @@
<message>
<location filename="../main_window.cpp" line="725"/>
<source>File doesn't appear to be a valid PKG file</source>
<translation>El archivo no parece ser un archivo PKG válido</translation>
<translation>El archivo parece no ser un archivo PKG válido</translation>
</message>
</context>
<context>
@ -691,7 +691,7 @@
<message>
<location filename="../cheats_patches.cpp" line="79"/>
<source>Serial: </source>
<translation>Serie: </translation>
<translation>Número de serie: </translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="83"/>
@ -731,7 +731,7 @@
<message>
<location filename="../cheats_patches.cpp" line="170"/>
<source>You can delete the cheats you don't want after downloading them.</source>
<translation>Puedes eliminar los trucos que no quieras después de descargarlos.</translation>
<translation>Puedes eliminar los trucos que no quieras una vez descargados.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="178"/>
@ -761,7 +761,7 @@
<message>
<location filename="../cheats_patches.cpp" line="257"/>
<source>Patches</source>
<translation>Parche</translation>
<translation>Parches</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="278"/>
@ -781,7 +781,7 @@
<message>
<location filename="../cheats_patches.cpp" line="316"/>
<source>No patch file found for the current serial.</source>
<translation>No se encontró ningún archivo de parche para la serie actual.</translation>
<translation>No se encontró ningún archivo de parche para el número de serie actual.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="323"/>
@ -957,7 +957,7 @@
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>Ícono</translation>
<translation>Icono</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
@ -967,7 +967,7 @@
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>Serie</translation>
<translation>Numero de serie</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>Ocultar registro de cambios</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>Registro de cambios no disponible</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>La visualización del registro de cambios solo está disponible para el canal 'inestable'.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>مخفی کردن تغییرات</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>تغییرات در دسترس نیست</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>نمایش تغییرات فقط برای کانال 'unstable' در دسترس است.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>Piilota muutospäiväkirja</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>Muutospäiväkirja ei saatavilla</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>Muutospäiväkirjan katsominen on saatavilla vain 'unstable'-kanavalle.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>Cacher le journal des modifications</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>Journal des modifications indisponible</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>La consultation du journal des modifications n'est disponible que pour le canal 'unstable'.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>Módosítások elrejtése</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>Módosítások nem elérhetők</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>A módosítások megtekintése csak az 'unstable' csatornára érhető el.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>Sembunyikan Catatan Perubahan</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>Catatan perubahan tidak tersedia</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>Pemirsa catatan perubahan hanya tersedia untuk saluran 'unstable'.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>Nascondi il Changelog</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>Changelog non disponibile</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>La visualizzazione del changelog è disponibile solo per il canale 'unstable'.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation></translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation></translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>unstable</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>Hide Changelog</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>Changelog Unavailable</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>Viewing changelog is only available for the 'unstable' channel.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>Slėpti pakeitimų sąrašą</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>Pakeitimų sąrašas neprieinamas</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>Žiūrėjimas pakeitimų sąrašo galimas tik 'unstable' kanalui.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>Skjul endringslogg</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>Endringslogg utilgjengelig</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>Visning av endringslogg er kun tilgjengelig for 'unstable' kanalen.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>Verberg changelog</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>Changelog niet beschikbaar</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>Weergave van de changelog is alleen beschikbaar voor het 'unstable' kanaal.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>Ukryj zmiany</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>Brak zmian do wyświetlenia</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>Podgląd zmian jest dostępny tylko dla kanału 'unstable'.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -510,7 +510,7 @@
<message>
<location filename="../settings_dialog.ui" line="286"/>
<source>Check for Updates at Startup</source>
<translation>Verificar atualizações ao Iniciar</translation>
<translation>Verificar Atualizações ao Iniciar</translation>
</message>
<message>
<location filename="../settings_dialog.ui" line="322"/>
@ -1075,7 +1075,7 @@
<message>
<location filename="../checkUpdate.cpp" line="198"/>
<source>Check for Updates at Startup</source>
<translation>Verificar atualizações ao Iniciar</translation>
<translation>Verificar Atualizações ao Iniciar</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="199"/>
@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>Ocultar Changelog</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>Changelog indisponível</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>A visualização do changelog está disponível apenas para o canal 'unstable'.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>Ascunde jurnalul de modificări</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>Jurnal de modificări indisponibil</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>Vizualizarea jurnalului de modificări este disponibilă doar pentru canalul 'unstable'.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>Скрыть изменения</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>Изменения недоступны</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>Просмотр изменений доступен только для канала 'unstable'.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>Fshih ndryshimet</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>Ndryshimet nuk janë disponueshme</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>Shikimi i ndryshimeve është i disponueshëm vetëm për kanalin 'unstable'.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>Değişiklik Günlüğünü Gizle</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>Değişiklik Günlüğü Mevcut Değil</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>Değişiklik günlüğünü görüntüleme yalnızca 'unstable' kanalı için mevcuttur.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation>n nhật thay đi</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation>Nhật thay đi không sẵn</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>Việc xem nhật thay đi chỉ khả dụng cho kênh 'unstable'.</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation></translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation></translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation>unstable</translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>

View File

@ -1092,16 +1092,6 @@
<source>Hide Changelog</source>
<translation></translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="231"/>
<source>Changelog Unavailable</source>
<translation></translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="232"/>
<source>Viewing changelog is only available for the 'unstable' channel.</source>
<translation> 'unstable' </translation>
</message>
<message>
<location filename="../checkUpdate.cpp" line="296"/>
<source>Changes</source>