[qt] fix translations (#2773)

Linguist strongly dislikes lookup tables of this sort due to the fact
that it looks for tr(), qsTr(), etc. when determining what strings need
translations. However, it does provide QT_TR_NOOP which marks the
string for translation *without* running the translation, which is designed
to allow for static or constexpr lookup tables. So let's use that.

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2773
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
This commit is contained in:
crueter 2025-10-18 22:19:06 +02:00
parent b330117a14
commit a53823646c
No known key found for this signature in database
GPG key ID: 425ACD2D4830EBC6
11 changed files with 234 additions and 193 deletions

View file

@ -15,21 +15,12 @@
#include <core/hle/service/am/frontend/applet_mii_edit.h>
#include <string>
#include "core/hle/result.h"
#include "core/hle/service/set/settings_types.h"
#include "core/hle/service/set/system_settings_server.h"
#include "core/hle/result.h"
namespace FirmwareManager {
static constexpr std::array<const char *, 5> KEY_INSTALL_RESULT_STRINGS = {
"Decryption Keys were successfully installed",
"Unable to read key directory, aborting",
"One or more keys failed to copy.",
"Verify your keys file has a .keys extension and try again.",
"Decryption Keys failed to initialize. Check that your dumping tools are up to date and "
"re-dump keys.",
};
static constexpr std::array<u64, 1> FIRMWARE_REQUIRED_GAMES = {
0x0100152000022000ULL, // MK8DX
};
@ -50,16 +41,6 @@ enum KeyInstallResult {
*/
KeyInstallResult InstallKeys(std::string location, std::string expected_extension);
/**
* \brief Get a string representation of a result from InstallKeys.
* \param result The result code.
* \return A string representation of the passed result code.
*/
inline constexpr const char *GetKeyInstallResultString(KeyInstallResult result)
{
return KEY_INSTALL_RESULT_STRINGS.at(static_cast<std::size_t>(result));
}
/**
* \brief Check if the specified program requires firmware to run properly.
* It is the responsibility of the frontend to properly expose this to the user.

View file

@ -66,7 +66,8 @@ target_compile_definitions(qt_common PUBLIC
add_subdirectory(externals)
find_package(frozen REQUIRED)
# pass targets
find_package(frozen)
target_link_libraries(qt_common PRIVATE core Qt6::Core Qt6::Concurrent SimpleIni::SimpleIni QuaZip::QuaZip)
target_link_libraries(qt_common PUBLIC frozen::frozen-headers)

View file

@ -13,7 +13,6 @@
"package": "frozen",
"repo": "serge-sans-paille/frozen",
"sha": "61dce5ae18",
"hash": "1ae3d073e659c1f24b2cdd76379c90d6af9e06bc707d285a4fafce05f7a4c9e592ff208c94a9ae0f0d07620b3c6cec191f126b03d70ad4dfa496a86ed5658a6d",
"bundled": true
"hash": "1ae3d073e659c1f24b2cdd76379c90d6af9e06bc707d285a4fafce05f7a4c9e592ff208c94a9ae0f0d07620b3c6cec191f126b03d70ad4dfa496a86ed5658a6d"
}
}

View file

@ -3,11 +3,10 @@
#pragma once
#include <QObject>
#include <QString>
#include <frozen/string.h>
#include <frozen/unordered_map.h>
#include <qobjectdefs.h>
#include <qtmetamacros.h>
#include "frozen/map.h"
#include "frozen/string.h"
namespace QtCommon::StringLookup {
@ -20,19 +19,85 @@ enum StringKey {
UserNandTooltip,
SysNandTooltip,
ModsTooltip,
// Key install results
KeyInstallSuccess,
KeyInstallInvalidDir,
KeyInstallErrorFailedCopy,
KeyInstallErrorWrongFilename,
KeyInstallErrorFailedInit,
// Firmware install results
FwInstallSuccess,
FwInstallNoNCAs,
FwInstallFailedDelete,
FwInstallFailedCopy,
FwInstallFailedCorrupted,
// user data migrator
MigrationPromptPrefix,
MigrationPrompt,
MigrationTooltipClearShader,
MigrationTooltipKeepOld,
MigrationTooltipClearOld,
MigrationTooltipLinkOld,
};
static constexpr const frozen::unordered_map<StringKey, frozen::string, 5> strings = {
{SavesTooltip, "Contains game save data. DO NOT REMOVE UNLESS YOU KNOW WHAT YOU'RE DOING!"},
{ShadersTooltip, "Contains Vulkan and OpenGL pipeline caches. Generally safe to remove."},
{UserNandTooltip, "Contains updates and DLC for games."},
{SysNandTooltip, "Contains firmware and applet data."},
{ModsTooltip, "Contains game mods, patches, and cheats."},
static const frozen::map<StringKey, frozen::string, 21> strings = {
{SavesTooltip,
QT_TR_NOOP("Contains game save data. DO NOT REMOVE UNLESS YOU KNOW WHAT YOU'RE DOING!")},
{ShadersTooltip,
QT_TR_NOOP("Contains Vulkan and OpenGL pipeline caches. Generally safe to remove.")},
{UserNandTooltip, QT_TR_NOOP("Contains updates and DLC for games.")},
{SysNandTooltip, QT_TR_NOOP("Contains firmware and applet data.")},
{ModsTooltip, QT_TR_NOOP("Contains game mods, patches, and cheats.")},
// Key install
{KeyInstallSuccess, QT_TR_NOOP("Decryption Keys were successfully installed")},
{KeyInstallInvalidDir, QT_TR_NOOP("Unable to read key directory, aborting")},
{KeyInstallErrorFailedCopy, QT_TR_NOOP("One or more keys failed to copy.")},
{KeyInstallErrorWrongFilename,
QT_TR_NOOP("Verify your keys file has a .keys extension and try again.")},
{KeyInstallErrorFailedInit,
QT_TR_NOOP(
"Decryption Keys failed to initialize. Check that your dumping tools are up to date and "
"re-dump keys.")},
// fw install
{FwInstallSuccess, QT_TR_NOOP("Successfully installed firmware version %1")},
{FwInstallNoNCAs, QT_TR_NOOP("Unable to locate potential firmware NCA files")},
{FwInstallFailedDelete, QT_TR_NOOP("Failed to delete one or more firmware files.")},
{FwInstallFailedCopy, QT_TR_NOOP("One or more firmware files failed to copy into NAND.")},
{FwInstallFailedCorrupted,
QT_TR_NOOP(
"Firmware installation cancelled, firmware may be in a bad state or corrupted. Restart "
"Eden or re-install firmware.")},
// migrator
{MigrationPromptPrefix, QT_TR_NOOP("Eden has detected user data for the following emulators:")},
{MigrationPrompt,
QT_TR_NOOP("Would you like to migrate your data for use in Eden?\n"
"Select the corresponding button to migrate data from that emulator.\n"
"This may take a while.")},
{MigrationTooltipClearShader,
QT_TR_NOOP("Clearing shader cache is recommended for all "
"users.\nDo not uncheck unless you know what "
"you're doing.")},
{MigrationTooltipKeepOld,
QT_TR_NOOP("Keeps the old data directory. This is recommended if you aren't\n"
"space-constrained and want to keep separate data for the old emulator.")},
{MigrationTooltipClearOld,
QT_TR_NOOP("Deletes the old data directory.\nThis is recommended on "
"devices with space constraints.")},
{MigrationTooltipLinkOld,
QT_TR_NOOP("Creates a filesystem link between the old directory and Eden directory.\n"
"This is recommended if you want to share data between emulators.")},
};
static inline const QString Lookup(StringKey key)
{
return QString::fromStdString(strings.at(key).data());
return QObject::tr(strings.at(key).data());
}
}
} // namespace QtCommon::StringLookup

View file

@ -10,15 +10,15 @@
#include "frontend_common/data_manager.h"
#include "frontend_common/firmware_manager.h"
#include "qt_common/qt_common.h"
#include "compress.h"
#include "qt_common/abstract/qt_progress_dialog.h"
#include "qt_common/abstract/qt_frontend_util.h"
#include "qt_common/abstract/qt_progress_dialog.h"
#include "qt_common/qt_common.h"
#include <QFuture>
#include <QFutureWatcher>
#include <QtConcurrentRun>
#include <JlCompress.h>
#include <QFutureWatcher>
namespace QtCommon::Content {
@ -60,15 +60,15 @@ void InstallFirmware(const QString& location, bool recursive)
return progress.wasCanceled();
};
static constexpr const char* failedTitle = "Firmware Install Failed";
static constexpr const char* successTitle = "Firmware Install Succeeded";
QString failedTitle = tr("Firmware Install Failed");
QString successTitle = tr("Firmware Install Succeeded");
QMessageBox::Icon icon;
FirmwareInstallResult result;
const auto ShowMessage = [&]() {
QtCommon::Frontend::ShowMessage(icon,
tr(failedTitle),
tr(GetFirmwareInstallResultString(result)));
failedTitle,
GetFirmwareInstallResultString(result));
};
LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString());
@ -188,10 +188,9 @@ void InstallFirmware(const QString& location, bool recursive)
const std::string display_version(firmware_data.display_version.data());
result = FirmwareInstallResult::Success;
QtCommon::Frontend::Information(
rootObject,
tr(successTitle),
tr(GetFirmwareInstallResultString(result)).arg(QString::fromStdString(display_version)));
QtCommon::Frontend::Information(successTitle,
GetFirmwareInstallResultString(result).arg(
QString::fromStdString(display_version)));
}
QString UnzipFirmwareToTmp(const QString& location)
@ -277,14 +276,13 @@ void InstallKeys()
system->GetFileSystemController().CreateFactories(*QtCommon::vfs);
const QString resMsg = GetKeyInstallResultString(result);
switch (result) {
case FirmwareManager::KeyInstallResult::Success:
QtCommon::Frontend::Information(tr("Decryption Keys install succeeded"),
tr("Decryption Keys were successfully installed"));
QtCommon::Frontend::Information(tr("Decryption Keys install succeeded"), resMsg);
break;
default:
QtCommon::Frontend::Critical(tr("Decryption Keys install failed"),
tr(FirmwareManager::GetKeyInstallResultString(result)));
QtCommon::Frontend::Critical(tr("Decryption Keys install failed"), resMsg);
break;
}
}
@ -296,7 +294,7 @@ void VerifyInstalledContents()
tr("Cancel"),
0,
100,
QtCommon::rootObject);
rootObject);
progress.setWindowModality(Qt::WindowModal);
progress.setMinimumDuration(100);
progress.setAutoClose(false);
@ -415,7 +413,9 @@ void ExportDataDir(FrontendCommon::DataManager::DataDir data_dir,
QGuiApplication::processEvents();
auto progress_callback = [=](size_t total_size, size_t processed_size) {
QMetaObject::invokeMethod(progress, "setValue", Qt::DirectConnection,
QMetaObject::invokeMethod(progress,
"setValue",
Qt::DirectConnection,
Q_ARG(int, static_cast<int>((processed_size * 100) / total_size)));
return !progress->wasCanceled();
};
@ -499,8 +499,11 @@ void ImportDataDir(FrontendCommon::DataManager::DataDir data_dir,
QObject::connect(delete_watcher, &QFutureWatcher<bool>::finished, rootObject, [=]() {
auto progress_callback = [=](size_t total_size, size_t processed_size) {
QMetaObject::invokeMethod(progress, "setValue", Qt::DirectConnection,
Q_ARG(int, static_cast<int>((processed_size * 100) / total_size)));
QMetaObject::invokeMethod(progress,
"setValue",
Qt::DirectConnection,
Q_ARG(int,
static_cast<int>((processed_size * 100) / total_size)));
return !progress->wasCanceled();
};

View file

@ -7,33 +7,36 @@
#include <QObject>
#include "common/common_types.h"
#include "frontend_common/data_manager.h"
#include "frontend_common/firmware_manager.h"
#include "qt_common/qt_string_lookup.h"
namespace QtCommon::Content {
//
bool CheckGameFirmware(u64 program_id, QObject *parent);
static constexpr std::array<const char *, 6> FIRMWARE_RESULTS
= {"Successfully installed firmware version %1",
"",
"Unable to locate potential firmware NCA files",
"Failed to delete one or more firmware files.",
"One or more firmware files failed to copy into NAND.",
"Firmware installation cancelled, firmware may be in a bad state or corrupted."
"Restart Eden or re-install firmware."};
enum class FirmwareInstallResult {
Success,
NoOp,
NoNCAs,
FailedDelete,
FailedCopy,
FailedCorrupted,
};
inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result)
inline const QString GetFirmwareInstallResultString(FirmwareInstallResult result)
{
return FIRMWARE_RESULTS.at(static_cast<std::size_t>(result));
return QtCommon::StringLookup::Lookup(static_cast<StringLookup::StringKey>((int) result + (int) QtCommon::StringLookup::FwInstallSuccess));
}
/**
* \brief Get a string representation of a result from InstallKeys.
* \param result The result code.
* \return A string representation of the passed result code.
*/
inline const QString GetKeyInstallResultString(FirmwareManager::KeyInstallResult result)
{
// this can probably be made into a common function of sorts
return QtCommon::StringLookup::Lookup(static_cast<StringLookup::StringKey>((int) result + (int) QtCommon::StringLookup::KeyInstallSuccess));
}
void InstallFirmware(const QString &location, bool recursive);

View file

@ -8,9 +8,9 @@
#include "core/file_sys/savedata_factory.h"
#include "core/hle/service/am/am_types.h"
#include "frontend_common/content_manager.h"
#include "qt_common/qt_common.h"
#include "qt_common/config/uisettings.h"
#include "qt_common/abstract/qt_frontend_util.h"
#include "qt_common/config/uisettings.h"
#include "qt_common/qt_common.h"
#include "yuzu/util/util.h"
#include <QDesktopServices>
@ -166,7 +166,8 @@ bool MakeShortcutIcoPath(const u64 program_id,
void OpenEdenFolder(const Common::FS::EdenPath& path)
{
QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(Common::FS::GetEdenPathString(path))));
QDesktopServices::openUrl(
QUrl::fromLocalFile(QString::fromStdString(Common::FS::GetEdenPathString(path))));
}
void OpenRootDataFolder()
@ -181,7 +182,8 @@ void OpenNANDFolder()
void OpenSaveFolder()
{
const auto path = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) / "user/save/0000000000000000";
const auto path = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir)
/ "user/save/0000000000000000";
QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(path.string())));
}
@ -220,12 +222,11 @@ void RemoveBaseContent(u64 program_id, InstalledEntryType type)
const auto res = ContentManager::RemoveBaseContent(system->GetFileSystemController(),
program_id);
if (res) {
QtCommon::Frontend::Information(rootObject,
tr("Successfully Removed"),
QtCommon::Frontend::Information(tr("Successfully Removed"),
tr("Successfully removed the installed base game."));
} else {
QtCommon::Frontend::Warning(
rootObject,
GetGameListErrorRemoving(type),
tr("The base game is not installed in the NAND and cannot be removed."));
}
@ -235,12 +236,10 @@ void RemoveUpdateContent(u64 program_id, InstalledEntryType type)
{
const auto res = ContentManager::RemoveUpdate(system->GetFileSystemController(), program_id);
if (res) {
QtCommon::Frontend::Information(rootObject,
tr("Successfully Removed"),
QtCommon::Frontend::Information(tr("Successfully Removed"),
tr("Successfully removed the installed update."));
} else {
QtCommon::Frontend::Warning(rootObject,
GetGameListErrorRemoving(type),
QtCommon::Frontend::Warning(GetGameListErrorRemoving(type),
tr("There is no update installed for this title."));
}
}
@ -249,14 +248,12 @@ void RemoveAddOnContent(u64 program_id, InstalledEntryType type)
{
const size_t count = ContentManager::RemoveAllDLC(*system, program_id);
if (count == 0) {
QtCommon::Frontend::Warning(rootObject,
GetGameListErrorRemoving(type),
QtCommon::Frontend::Warning(GetGameListErrorRemoving(type),
tr("There are no DLCs installed for this title."));
return;
}
QtCommon::Frontend::Information(rootObject,
tr("Successfully Removed"),
QtCommon::Frontend::Information(tr("Successfully Removed"),
tr("Successfully removed %1 installed DLC.").arg(count));
}
@ -279,18 +276,15 @@ void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target)
const auto target_file = shader_cache_folder_path / target_file_name;
if (!Common::FS::Exists(target_file)) {
QtCommon::Frontend::Warning(rootObject,
tr("Error Removing Transferable Shader Cache"),
QtCommon::Frontend::Warning(tr("Error Removing Transferable Shader Cache"),
tr("A shader cache for this title does not exist."));
return;
}
if (Common::FS::RemoveFile(target_file)) {
QtCommon::Frontend::Information(rootObject,
tr("Successfully Removed"),
QtCommon::Frontend::Information(tr("Successfully Removed"),
tr("Successfully removed the transferable shader cache."));
} else {
QtCommon::Frontend::Warning(rootObject,
tr("Error Removing Transferable Shader Cache"),
QtCommon::Frontend::Warning(tr("Error Removing Transferable Shader Cache"),
tr("Failed to remove the transferable shader cache."));
}
}
@ -307,8 +301,7 @@ void RemoveVulkanDriverPipelineCache(u64 program_id)
return;
}
if (!Common::FS::RemoveFile(target_file)) {
QtCommon::Frontend::Warning(rootObject,
tr("Error Removing Vulkan Driver Pipeline Cache"),
QtCommon::Frontend::Warning(tr("Error Removing Vulkan Driver Pipeline Cache"),
tr("Failed to remove the driver pipeline cache."));
}
}
@ -319,18 +312,16 @@ void RemoveAllTransferableShaderCaches(u64 program_id)
const auto program_shader_cache_dir = shader_cache_dir / fmt::format("{:016x}", program_id);
if (!Common::FS::Exists(program_shader_cache_dir)) {
QtCommon::Frontend::Warning(rootObject,
tr("Error Removing Transferable Shader Caches"),
QtCommon::Frontend::Warning(tr("Error Removing Transferable Shader Caches"),
tr("A shader cache for this title does not exist."));
return;
}
if (Common::FS::RemoveDirRecursively(program_shader_cache_dir)) {
QtCommon::Frontend::Information(rootObject,
tr("Successfully Removed"),
QtCommon::Frontend::Information(tr("Successfully Removed"),
tr("Successfully removed the transferable shader caches."));
} else {
QtCommon::Frontend::Warning(
rootObject,
tr("Error Removing Transferable Shader Caches"),
tr("Failed to remove the transferable shader cache directory."));
}
@ -339,27 +330,23 @@ void RemoveAllTransferableShaderCaches(u64 program_id)
void RemoveCustomConfiguration(u64 program_id, const std::string& game_path)
{
const auto file_path = std::filesystem::path(Common::FS::ToU8String(game_path));
const auto config_file_name = program_id == 0
? Common::FS::PathToUTF8String(file_path.filename())
.append(".ini")
const auto config_file_name
= program_id == 0 ? Common::FS::PathToUTF8String(file_path.filename()).append(".ini")
: fmt::format("{:016X}.ini", program_id);
const auto custom_config_file_path = Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir)
/ "custom" / config_file_name;
if (!Common::FS::Exists(custom_config_file_path)) {
QtCommon::Frontend::Warning(rootObject,
tr("Error Removing Custom Configuration"),
QtCommon::Frontend::Warning(tr("Error Removing Custom Configuration"),
tr("A custom configuration for this title does not exist."));
return;
}
if (Common::FS::RemoveFile(custom_config_file_path)) {
QtCommon::Frontend::Information(rootObject,
tr("Successfully Removed"),
QtCommon::Frontend::Information(tr("Successfully Removed"),
tr("Successfully removed the custom game configuration."));
} else {
QtCommon::Frontend::Warning(rootObject,
tr("Error Removing Custom Configuration"),
QtCommon::Frontend::Warning(tr("Error Removing Custom Configuration"),
tr("Failed to remove the custom game configuration."));
}
}
@ -392,16 +379,21 @@ void ResetMetadata(bool show_message)
if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir)
/ "game_list/")) {
if (show_message) QtCommon::Frontend::Warning(rootObject, title, tr("The metadata cache is already empty."));
if (show_message)
QtCommon::Frontend::Warning(rootObject,
title,
tr("The metadata cache is already empty."));
} else if (Common::FS::RemoveDirRecursively(
Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) {
if (show_message) QtCommon::Frontend::Information(rootObject,
if (show_message)
QtCommon::Frontend::Information(rootObject,
title,
tr("The operation completed successfully."));
UISettings::values.is_game_list_reload_pending.exchange(true);
} else {
if (show_message) QtCommon::Frontend::Warning(
rootObject,
if (show_message)
QtCommon::Frontend::Warning(
title,
tr("The metadata cache couldn't be deleted. It might be in use or non-existent."));
}
@ -446,7 +438,7 @@ inline constexpr bool CreateShortcutMessagesGUI(ShortcutMessages imsg, const QSt
void CreateShortcut(const std::string& game_path,
const u64 program_id,
const std::string& game_title_,
const ShortcutTarget &target,
const ShortcutTarget& target,
std::string arguments_,
const bool needs_title)
{
@ -463,11 +455,13 @@ void CreateShortcut(const std::string& game_path,
return;
}
const FileSys::PatchManager pm{program_id, QtCommon::system->GetFileSystemController(),
const FileSys::PatchManager pm{program_id,
QtCommon::system->GetFileSystemController(),
QtCommon::system->GetContentProvider()};
const auto control = pm.GetControlMetadata();
const auto loader =
Loader::GetLoader(*QtCommon::system, QtCommon::vfs->OpenFile(game_path, FileSys::OpenMode::Read));
const auto loader = Loader::GetLoader(*QtCommon::system,
QtCommon::vfs->OpenFile(game_path,
FileSys::OpenMode::Read));
std::string game_title{game_title_};
@ -498,8 +492,8 @@ void CreateShortcut(const std::string& game_path,
LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path);
}
QImage icon_data =
QImage::fromData(icon_image_file.data(), static_cast<int>(icon_image_file.size()));
QImage icon_data = QImage::fromData(icon_image_file.data(),
static_cast<int>(icon_image_file.size()));
std::filesystem::path out_icon_path;
if (QtCommon::Game::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) {
if (!SaveIconToFile(out_icon_path, icon_data)) {
@ -532,33 +526,39 @@ void CreateShortcut(const std::string& game_path,
const std::string categories = "Game;Emulator;Qt;";
const std::string keywords = "Switch;Nintendo;";
if (QtCommon::Game::CreateShortcutLink(shortcut_path, comment, out_icon_path, command,
arguments, categories, keywords, game_title)) {
CreateShortcutMessagesGUI(ShortcutMessages::Success,
qgame_title);
if (QtCommon::Game::CreateShortcutLink(shortcut_path,
comment,
out_icon_path,
command,
arguments,
categories,
keywords,
game_title)) {
CreateShortcutMessagesGUI(ShortcutMessages::Success, qgame_title);
return;
}
CreateShortcutMessagesGUI(ShortcutMessages::Failed,
qgame_title);
CreateShortcutMessagesGUI(ShortcutMessages::Failed, qgame_title);
}
// TODO: You want this to be constexpr? Well too bad, clang19 doesn't believe this is a string literal
std::string GetShortcutPath(ShortcutTarget target) {
std::string GetShortcutPath(ShortcutTarget target)
{
{
std::string shortcut_path{};
if (target == ShortcutTarget::Desktop) {
shortcut_path = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)
.toStdString();
shortcut_path
= QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).toStdString();
} else if (target == ShortcutTarget::Applications) {
shortcut_path = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation)
.toStdString();
shortcut_path
= QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString();
}
return shortcut_path;
}
}
void CreateHomeMenuShortcut(ShortcutTarget target) {
void CreateHomeMenuShortcut(ShortcutTarget target)
{
constexpr u64 QLaunchId = static_cast<u64>(Service::AM::AppletProgramId::QLaunch);
auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents();
if (!bis_system) {

View file

@ -406,7 +406,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan)
#define MIGRATE_DIR(type) \
std::string type##path = Common::FS::GetEdenPathString(Common::FS::EdenPath::type##Dir); \
if (type##path.starts_with(user_data_migrator.selected_emu.get_user_dir())) { \
boost::replace_all(type##path, user_data_migrator.selected_emu.lower_name(), "eden"); \
boost::replace_all(type##path, user_data_migrator.selected_emu.lower_name().toStdString(), "eden"); \
Common::FS::SetEdenPath(Common::FS::EdenPath::type##Dir, type##path); \
}

View file

@ -68,7 +68,7 @@ void MigrationWorker::process()
success_text.append(tr("\n\nNote that your configuration and data will be shared with %1.\n"
"If this is not desirable, delete the following files:\n%2\n%3\n%4")
.arg(tr(selected_legacy_emu.name),
.arg(selected_legacy_emu.name(),
QString::fromStdString(eden_dir.string()),
QString::fromStdString(config_dir.string()),
QString::fromStdString(cache_dir.string())));

View file

@ -10,7 +10,7 @@
using namespace Common::FS;
typedef struct Emulator {
const char *name;
const char *m_name;
LegacyPath e_user_dir;
LegacyPath e_config_dir;
@ -28,23 +28,19 @@ typedef struct Emulator {
return Common::FS::GetLegacyPath(e_cache_dir).string();
}
const std::string lower_name() const {
std::string lower_name{name};
std::transform(lower_name.begin(), lower_name.end(), lower_name.begin(),
[](unsigned char c){ return std::tolower(c); });
const QString name() const { return QObject::tr(m_name);
}
return lower_name;
const QString lower_name() const { return name().toLower();
}
} Emulator;
#define EMU(name) Emulator{#name, name##Dir, name##ConfigDir, name##CacheDir}
static constexpr std::array<Emulator, 4> legacy_emus = {
EMU(Citron),
EMU(Sudachi),
EMU(Suyu),
EMU(Yuzu),
Emulator{QT_TR_NOOP("Citron"), CitronDir, CitronConfigDir, CitronCacheDir},
Emulator{QT_TR_NOOP("Sudachi"), SudachiDir, SudachiConfigDir, SudachiCacheDir},
Emulator{QT_TR_NOOP("Suyu"), SuyuDir, SuyuConfigDir, SuyuCacheDir},
Emulator{QT_TR_NOOP("Yuzu"), YuzuDir, YuzuConfigDir, YuzuCacheDir},
};
#undef EMU
class MigrationWorker : public QObject
{

View file

@ -11,12 +11,13 @@
#include <QString>
#include <QTranslator>
#include "common/fs/path_util.h"
#include "../yuzu/migration_dialog.h"
#include "qt_common/qt_string_lookup.h"
#include "yuzu/migration_dialog.h"
// Needs to be included at the end due to https://bugreports.qt.io/browse/QTBUG-73263
#include <QGuiApplication>
#include <QButtonGroup>
#include <QCheckBox>
#include <QGuiApplication>
#include <QProgressDialog>
#include <QRadioButton>
#include <QThread>
@ -41,30 +42,19 @@ void UserDataMigrator::ShowMigrationPrompt(QMainWindow *main_window)
namespace fs = std::filesystem;
// define strings here for easy access
static constexpr const char *prompt_prefix_text
= "Eden has detected user data for the following emulators:";
static constexpr const char *migration_prompt_message
= "Would you like to migrate your data for use in Eden?\n"
"Select the corresponding button to migrate data from that emulator.\n"
"This may take a while.";
static constexpr const char *clear_shader_tooltip
= "Clearing shader cache is recommended for all "
"users.\nDo not uncheck unless you know what "
"you're doing.";
static constexpr const char *keep_old_data_tooltip
= "Keeps the old data directory. This is recommended if you aren't\n"
"space-constrained and want to keep separate data for the old emulator.";
static constexpr const char *clear_old_data_tooltip
= "Deletes the old data directory.\nThis is recommended on "
"devices with space constraints.";
static constexpr const char *link_old_dir_tooltip
= "Creates a filesystem link between the old directory and Eden directory.\n"
"This is recommended if you want to share data between emulators.";
QString prompt_prefix_text = QtCommon::StringLookup::Lookup(
QtCommon::StringLookup::MigrationPromptPrefix);
QString migration_prompt_message = QtCommon::StringLookup::Lookup(
QtCommon::StringLookup::MigrationPrompt);
QString clear_shader_tooltip = QtCommon::StringLookup::Lookup(
QtCommon::StringLookup::MigrationTooltipClearShader);
QString keep_old_data_tooltip = QtCommon::StringLookup::Lookup(
QtCommon::StringLookup::MigrationTooltipKeepOld);
QString clear_old_data_tooltip = QtCommon::StringLookup::Lookup(
QtCommon::StringLookup::MigrationTooltipClearOld);
QString link_old_dir_tooltip = QtCommon::StringLookup::Lookup(
QtCommon::StringLookup::MigrationTooltipLinkOld);
// actual migration code
@ -78,12 +68,12 @@ void UserDataMigrator::ShowMigrationPrompt(QMainWindow *main_window)
#define BUTTON(clazz, name, text, tooltip, checkState) \
clazz *name = new clazz(&migration_prompt); \
name->setText(QObject::tr(text)); \
name->setToolTip(QObject::tr(tooltip)); \
name->setText(text); \
name->setToolTip(tooltip); \
name->setChecked(checkState); \
migration_prompt.addBox(name);
BUTTON(QCheckBox, clear_shaders, "Clear Shader Cache", clear_shader_tooltip, true)
BUTTON(QCheckBox, clear_shaders, QObject::tr("Clear Shader Cache"), clear_shader_tooltip, true)
u32 id = 0;
@ -91,9 +81,9 @@ void UserDataMigrator::ShowMigrationPrompt(QMainWindow *main_window)
BUTTON(QRadioButton, name, text, tooltip, checkState) \
group->addButton(name, ++id);
RADIO(keep_old, "Keep Old Data", keep_old_data_tooltip, true)
RADIO(clear_old, "Clear Old Data", clear_old_data_tooltip, false)
RADIO(link_old, "Link Old Directory", link_old_dir_tooltip, false)
RADIO(keep_old, QObject::tr("Keep Old Data"), keep_old_data_tooltip, true)
RADIO(clear_old, QObject::tr("Clear Old Data"), clear_old_data_tooltip, false)
RADIO(link_old, QObject::tr("Link Old Directory"), link_old_dir_tooltip, false)
#undef RADIO
#undef BUTTON
@ -111,20 +101,20 @@ void UserDataMigrator::ShowMigrationPrompt(QMainWindow *main_window)
// makes my life easier
qRegisterMetaType<Emulator>();
QString prompt_text = QObject::tr(prompt_prefix_text);
QString prompt_text = prompt_prefix_text;
// natural language processing is a nightmare
for (const Emulator &emu : found) {
prompt_text.append(QStringLiteral("\n- %1").arg(QObject::tr(emu.name)));
prompt_text = prompt_text % QStringLiteral("\n ") % emu.name();
QAbstractButton *button = migration_prompt.addButton(QObject::tr(emu.name));
QAbstractButton *button = migration_prompt.addButton(emu.name());
// This is cursed, but it's actually the most efficient way by a mile
button->setProperty("emulator", QVariant::fromValue(emu));
}
prompt_text.append(QObject::tr("\n\n"));
prompt_text.append(QObject::tr(migration_prompt_message));
prompt_text = prompt_text % QStringLiteral("\n\n") % migration_prompt_message;
migration_prompt.setText(prompt_text);
migration_prompt.addButton(QObject::tr("No"), true);
@ -191,7 +181,10 @@ void UserDataMigrator::MigrateUserData(QMainWindow *main_window,
thread->connect(thread, &QThread::started, worker, &MigrationWorker::process);
thread->connect(worker, &MigrationWorker::finished, progress, [=, this](const QString &success_text, const std::string &path) {
thread->connect(worker,
&MigrationWorker::finished,
progress,
[=, this](const QString &success_text, const std::string &path) {
progress->close();
QMessageBox::information(main_window,
QObject::tr("Migration"),