From ab002e78e15cbf9596c0c805c6c21d6c9daf9208 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sat, 22 Aug 2020 13:01:52 +1000 Subject: [PATCH] Support translating strings in emulator core --- src/core/analog_controller.cpp | 24 ++- src/core/game_list.cpp | 8 +- src/core/game_settings.cpp | 26 +-- src/core/host_interface.cpp | 31 ++- src/core/host_interface.h | 6 + src/core/settings.cpp | 37 ++-- src/core/system.cpp | 40 ++-- src/duckstation-qt/advancedsettingswidget.cpp | 4 +- src/duckstation-qt/audiosettingswidget.cpp | 5 +- src/duckstation-qt/consolesettingswidget.cpp | 17 +- .../controllersettingswidget.cpp | 5 +- src/duckstation-qt/gamepropertiesdialog.cpp | 21 +- src/duckstation-qt/gpusettingswidget.cpp | 13 +- src/duckstation-qt/hotkeysettingswidget.cpp | 3 +- .../memorycardsettingswidget.cpp | 2 +- src/duckstation-qt/qthostinterface.cpp | 69 +++++- src/duckstation-qt/qthostinterface.h | 3 + src/duckstation-qt/update_translations.bat | 14 +- src/frontend-common/common_host_interface.cpp | 199 ++++++++++-------- 19 files changed, 353 insertions(+), 174 deletions(-) diff --git a/src/core/analog_controller.cpp b/src/core/analog_controller.cpp index 41165cec6..b745386e3 100644 --- a/src/core/analog_controller.cpp +++ b/src/core/analog_controller.cpp @@ -53,8 +53,12 @@ bool AnalogController::DoState(StateWrapper& sw) if (old_analog_mode != m_analog_mode) { - g_host_interface->AddFormattedOSDMessage(5.0f, "Controller %u switched to %s mode.", m_index + 1u, - m_analog_mode ? "analog" : "digital"); + g_host_interface->AddFormattedOSDMessage( + 5.0f, + m_analog_mode ? + g_host_interface->TranslateString("AnalogController", "Controller %u switched to analog mode.") : + g_host_interface->TranslateString("AnalogController", "Controller %u switched to digital mode."), + m_index + 1u); } } return true; @@ -95,8 +99,13 @@ void AnalogController::SetButtonState(Button button, bool pressed) { if (m_analog_locked) { - g_host_interface->AddFormattedOSDMessage(5.0f, "Controller %u is locked to %s mode by the game.", m_index + 1u, - m_analog_mode ? "analog" : "digital"); + g_host_interface->AddFormattedOSDMessage( + 5.0f, + m_analog_mode ? g_host_interface->TranslateString("AnalogController", + "Controller %u is locked to analog mode by the game.") : + g_host_interface->TranslateString("AnalogController", + "Controller %u is locked to digital mode by the game."), + m_index + 1u); } else { @@ -155,8 +164,11 @@ void AnalogController::SetAnalogMode(bool enabled) return; Log_InfoPrintf("Controller %u switched to %s mode.", m_index + 1u, enabled ? "analog" : "digital"); - g_host_interface->AddFormattedOSDMessage(5.0f, "Controller %u switched to %s mode.", m_index + 1u, - enabled ? "analog" : "digital"); + g_host_interface->AddFormattedOSDMessage( + 5.0f, + enabled ? g_host_interface->TranslateString("AnalogController", "Controller %u switched to analog mode.") : + g_host_interface->TranslateString("AnalogController", "Controller %u switched to digital mode."), + m_index + 1u); m_analog_mode = enabled; } diff --git a/src/core/game_list.cpp b/src/core/game_list.cpp index 6c0bd4420..fef61d38b 100644 --- a/src/core/game_list.cpp +++ b/src/core/game_list.cpp @@ -8,6 +8,7 @@ #include "common/log.h" #include "common/progress_callback.h" #include "common/string_util.h" +#include "host_interface.h" #include "settings.h" #include #include @@ -270,7 +271,12 @@ std::vector GameList::ParseM3UFile(const char* path) const char* GameList::GetGameListCompatibilityRatingString(GameListCompatibilityRating rating) { static constexpr std::array(GameListCompatibilityRating::Count)> names = { - {"Unknown", "Doesn't Boot", "Crashes In Intro", "Crashes In-Game", "Graphical/Audio Issues", "No Issues"}}; + {TRANSLATABLE("GameListCompatibilityRating", "Unknown"), + TRANSLATABLE("GameListCompatibilityRating", "Doesn't Boot"), + TRANSLATABLE("GameListCompatibilityRating", "Crashes In Intro"), + TRANSLATABLE("GameListCompatibilityRating", "Crashes In-Game"), + TRANSLATABLE("GameListCompatibilityRating", "Graphical/Audio Issues"), + TRANSLATABLE("GameListCompatibilityRating", "No Issues")}}; return (rating >= GameListCompatibilityRating::Unknown && rating < GameListCompatibilityRating::Count) ? names[static_cast(rating)] : ""; diff --git a/src/core/game_settings.cpp b/src/core/game_settings.cpp index d1ec1c370..0db275879 100644 --- a/src/core/game_settings.cpp +++ b/src/core/game_settings.cpp @@ -19,19 +19,19 @@ Log_SetChannel(GameSettings); namespace GameSettings { std::array, static_cast(Trait::Count)> s_trait_names = {{ - {"ForceInterpreter", "Force Interpreter"}, - {"ForceSoftwareRenderer", "Force Software Renderer"}, - {"EnableInterlacing", "Enable Interlacing"}, - {"DisableTrueColor", "Disable True Color"}, - {"DisableUpscaling", "Disable Upscaling"}, - {"DisableScaledDithering", "Disable Scaled Dithering"}, - {"DisableWidescreen", "Disable Widescreen"}, - {"DisablePGXP", "Disable PGXP"}, - {"DisablePGXPCulling", "Disable PGXP Culling"}, - {"EnablePGXPVertexCache", "Enable PGXP Vertex Cache"}, - {"EnablePGXPCPUMode", "Enable PGXP CPU Mode"}, - {"ForceDigitalController", "Force Digital Controller"}, - {"EnableRecompilerMemoryExceptions", "Enable Recompiler Memory Exceptions"}, + {"ForceInterpreter", TRANSLATABLE("GameSettingsTrait", "Force Interpreter")}, + {"ForceSoftwareRenderer", TRANSLATABLE("GameSettingsTrait", "Force Software Renderer")}, + {"EnableInterlacing", TRANSLATABLE("GameSettingsTrait", "Enable Interlacing")}, + {"DisableTrueColor", TRANSLATABLE("GameSettingsTrait", "Disable True Color")}, + {"DisableUpscaling", TRANSLATABLE("GameSettingsTrait", "Disable Upscaling")}, + {"DisableScaledDithering", TRANSLATABLE("GameSettingsTrait", "Disable Scaled Dithering")}, + {"DisableWidescreen", TRANSLATABLE("GameSettingsTrait", "Disable Widescreen")}, + {"DisablePGXP", TRANSLATABLE("GameSettingsTrait", "Disable PGXP")}, + {"DisablePGXPCulling", TRANSLATABLE("GameSettingsTrait", "Disable PGXP Culling")}, + {"EnablePGXPVertexCache", TRANSLATABLE("GameSettingsTrait", "Enable PGXP Vertex Cache")}, + {"EnablePGXPCPUMode", TRANSLATABLE("GameSettingsTrait", "Enable PGXP CPU Mode")}, + {"ForceDigitalController", TRANSLATABLE("GameSettingsTrait", "Force Digital Controller")}, + {"EnableRecompilerMemoryExceptions", TRANSLATABLE("GameSettingsTrait", "Enable Recompiler Memory Exceptions")}, }}; const char* GetTraitName(Trait trait) diff --git a/src/core/host_interface.cpp b/src/core/host_interface.cpp index 9840e7424..db8efc625 100644 --- a/src/core/host_interface.cpp +++ b/src/core/host_interface.cpp @@ -114,7 +114,7 @@ void HostInterface::ResetSystem() { System::Reset(); System::ResetPerformanceCounters(); - AddOSDMessage("System reset."); + AddOSDMessage(TranslateStdString("OSDMessage", "System reset.")); } void HostInterface::PowerOffSystem() @@ -284,13 +284,13 @@ bool HostInterface::LoadState(const char* filename) if (!stream) return false; - AddFormattedOSDMessage(5.0f, "Loading state from '%s'...", filename); + AddFormattedOSDMessage(5.0f, TranslateString("OSDMessage", "Loading state from '%s'..."), filename); if (!System::IsShutdown()) { if (!System::LoadState(stream.get())) { - ReportFormattedError("Loading state from '%s' failed. Resetting.", filename); + ReportFormattedError(TranslateString("OSDMessage", "Loading state from '%s' failed. Resetting."), filename); ResetSystem(); return false; } @@ -318,12 +318,12 @@ bool HostInterface::SaveState(const char* filename) const bool result = System::SaveState(stream.get()); if (!result) { - ReportFormattedError("Saving state to '%s' failed.", filename); + ReportFormattedError(TranslateString("OSDMessage", "Saving state to '%s' failed."), filename); stream->Discard(); } else { - AddFormattedOSDMessage(5.0f, "State saved to '%s'.", filename); + AddFormattedOSDMessage(5.0f, TranslateString("OSDMessage", "State saved to '%s'."), filename); stream->Commit(); } @@ -451,13 +451,20 @@ void HostInterface::FixIncompatibleSettings(bool display_osd_messages) if (g_settings.gpu_renderer == GPURenderer::Software) { if (display_osd_messages) - AddOSDMessage("PGXP is incompatible with the software renderer, disabling PGXP.", 10.0f); + { + AddOSDMessage(TranslateStdString("OSDMessage", "PGXP is incompatible with the software renderer, disabling PGXP."), 10.0f); + } g_settings.gpu_pgxp_enable = false; } else if (g_settings.gpu_pgxp_cpu && g_settings.cpu_execution_mode == CPUExecutionMode::Recompiler) { if (display_osd_messages) - AddOSDMessage("PGXP CPU mode is incompatible with the recompiler, using Cached Interpreter instead.", 10.0f); + { + AddOSDMessage( + TranslateStdString("OSDMessage", + "PGXP CPU mode is incompatible with the recompiler, using Cached Interpreter instead."), + 10.0f); + } g_settings.cpu_execution_mode = CPUExecutionMode::CachedInterpreter; } } @@ -683,6 +690,16 @@ float HostInterface::GetFloatSettingValue(const char* section, const char* key, return float_value.value_or(default_value); } +TinyString HostInterface::TranslateString(const char* context, const char* str) const +{ + return str; +} + +std::string HostInterface::TranslateStdString(const char* context, const char* str) const +{ + return str; +} + void HostInterface::ToggleSoftwareRendering() { if (System::IsShutdown() || g_settings.gpu_renderer == GPURenderer::Software) diff --git a/src/core/host_interface.h b/src/core/host_interface.h index da9071226..596ffaf75 100644 --- a/src/core/host_interface.h +++ b/src/core/host_interface.h @@ -109,6 +109,10 @@ public: /// Returns a float setting from the configuration. virtual float GetFloatSettingValue(const char* section, const char* key, float default_value = 0.0f); + /// Translates a string to the current language. + virtual TinyString TranslateString(const char* context, const char* str) const; + virtual std::string TranslateStdString(const char* context, const char* str) const; + /// Loads the BIOS image for the specified region. std::optional> GetBIOSImage(ConsoleRegion region); @@ -164,4 +168,6 @@ protected: std::string m_user_directory; }; +#define TRANSLATABLE(context, str) str + extern HostInterface* g_host_interface; diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 620df6e02..d63d0fbf2 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -291,7 +291,10 @@ void Settings::Save(SettingsInterface& si) const static std::array s_log_level_names = { {"None", "Error", "Warning", "Perf", "Success", "Info", "Dev", "Profile", "Debug", "Trace"}}; static std::array s_log_level_display_names = { - {"None", "Error", "Warning", "Performance", "Success", "Information", "Developer", "Profile", "Debug", "Trace"}}; + {TRANSLATABLE("LogLevel", "None"), TRANSLATABLE("LogLevel", "Error"), TRANSLATABLE("LogLevel", "Warning"), + TRANSLATABLE("LogLevel", "Performance"), TRANSLATABLE("LogLevel", "Success"), + TRANSLATABLE("LogLevel", "Information"), TRANSLATABLE("LogLevel", "Developer"), TRANSLATABLE("LogLevel", "Profile"), + TRANSLATABLE("LogLevel", "Debug"), TRANSLATABLE("LogLevel", "Trace")}}; std::optional Settings::ParseLogLevelName(const char* str) { @@ -319,7 +322,8 @@ const char* Settings::GetLogLevelDisplayName(LOGLEVEL level) static std::array s_console_region_names = {{"Auto", "NTSC-J", "NTSC-U", "PAL"}}; static std::array s_console_region_display_names = { - {"Auto-Detect", "NTSC-J (Japan)", "NTSC-U (US)", "PAL (Europe, Australia)"}}; + {TRANSLATABLE("ConsoleRegion", "Auto-Detect"), TRANSLATABLE("ConsoleRegion", "NTSC-J (Japan)"), + TRANSLATABLE("ConsoleRegion", "NTSC-U (US)"), TRANSLATABLE("ConsoleRegion", "PAL (Europe, Australia)")}}; std::optional Settings::ParseConsoleRegionName(const char* str) { @@ -347,7 +351,8 @@ const char* Settings::GetConsoleRegionDisplayName(ConsoleRegion region) static std::array s_disc_region_names = {{"NTSC-J", "NTSC-U", "PAL", "Other"}}; static std::array s_disc_region_display_names = { - {"NTSC-J (Japan)", "NTSC-U (US)", "PAL (Europe, Australia)", "Other"}}; + {TRANSLATABLE("DiscRegion", "NTSC-J (Japan)"), TRANSLATABLE("DiscRegion", "NTSC-U (US)"), + TRANSLATABLE("DiscRegion", "PAL (Europe, Australia)"), TRANSLATABLE("DiscRegion", "Other")}}; std::optional Settings::ParseDiscRegionName(const char* str) { @@ -375,7 +380,8 @@ const char* Settings::GetDiscRegionDisplayName(DiscRegion region) static std::array s_cpu_execution_mode_names = {{"Interpreter", "CachedInterpreter", "Recompiler"}}; static std::array s_cpu_execution_mode_display_names = { - {"Intepreter (Slowest)", "Cached Interpreter (Faster)", "Recompiler (Fastest)"}}; + {TRANSLATABLE("CPUExecutionMode", "Intepreter (Slowest)"), TRANSLATABLE("CPUExecutionMode", "Cached Interpreter (Faster)"), + TRANSLATABLE("CPUExecutionMode", "Recompiler (Fastest)")}}; std::optional Settings::ParseCPUExecutionMode(const char* str) { @@ -408,9 +414,10 @@ static std::array s_gpu_renderer_names = {{ "Vulkan", "OpenGL", "Software"}}; static std::array s_gpu_renderer_display_names = {{ #ifdef WIN32 - "Hardware (D3D11)", + TRANSLATABLE("GPURenderer", "Hardware (D3D11)"), #endif - "Hardware (Vulkan)", "Hardware (OpenGL)", "Software"}}; + TRANSLATABLE("GPURenderer", "Hardware (Vulkan)"), TRANSLATABLE("GPURenderer", "Hardware (OpenGL)"), + TRANSLATABLE("GPURenderer", "Software")}}; std::optional Settings::ParseRendererName(const char* str) { @@ -437,7 +444,9 @@ const char* Settings::GetRendererDisplayName(GPURenderer renderer) } static std::array s_display_crop_mode_names = {{"None", "Overscan", "Borders"}}; -static std::array s_display_crop_mode_display_names = {{"None", "Only Overscan Area", "All Borders"}}; +static std::array s_display_crop_mode_display_names = {{TRANSLATABLE("DisplayCropMode", "None"), + TRANSLATABLE("DisplayCropMode", "Only Overscan Area"), + TRANSLATABLE("DisplayCropMode", "All Borders")}}; std::optional Settings::ParseDisplayCropMode(const char* str) { @@ -493,7 +502,8 @@ float Settings::GetDisplayAspectRatioValue(DisplayAspectRatio ar) } static std::array s_audio_backend_names = {{"Null", "Cubeb", "SDL"}}; -static std::array s_audio_backend_display_names = {{"Null (No Output)", "Cubeb", "SDL"}}; +static std::array s_audio_backend_display_names = { + {TRANSLATABLE("AudioBackend", "Null (No Output)"), TRANSLATABLE("AudioBackend", "Cubeb"), TRANSLATABLE("AudioBackend", "SDL")}}; std::optional Settings::ParseAudioBackend(const char* str) { @@ -522,7 +532,9 @@ const char* Settings::GetAudioBackendDisplayName(AudioBackend backend) static std::array s_controller_type_names = { {"None", "DigitalController", "AnalogController", "NamcoGunCon", "PlayStationMouse", "NeGcon"}}; static std::array s_controller_display_names = { - {"None", "Digital Controller", "Analog Controller (DualShock)", "Namco GunCon", "PlayStation Mouse", "NeGcon"}}; + {TRANSLATABLE("ControllerType", "None"), TRANSLATABLE("ControllerType", "Digital Controller"), + TRANSLATABLE("ControllerType", "Analog Controller (DualShock)"), TRANSLATABLE("ControllerType", "Namco GunCon"), + TRANSLATABLE("ControllerType", "PlayStation Mouse"), TRANSLATABLE("ControllerType", "NeGcon")}}; std::optional Settings::ParseControllerTypeName(const char* str) { @@ -549,9 +561,10 @@ const char* Settings::GetControllerTypeDisplayName(ControllerType type) } static std::array s_memory_card_type_names = {{"None", "Shared", "PerGame", "PerGameTitle"}}; -static std::array s_memory_card_type_display_names = {{"No Memory Card", "Shared Between All Games", - "Separate Card Per Game (Game Code)", - "Separate Card Per Game (Game Title)"}}; +static std::array s_memory_card_type_display_names = { + {TRANSLATABLE("MemoryCardType", "No Memory Card"), TRANSLATABLE("MemoryCardType", "Shared Between All Games"), + TRANSLATABLE("MemoryCardType", "Separate Card Per Game (Game Code)"), + TRANSLATABLE("MemoryCardType", "Separate Card Per Game (Game Title)")}}; std::optional Settings::ParseMemoryCardTypeName(const char* str) { diff --git a/src/core/system.cpp b/src/core/system.cpp index ac632b7b1..67a316f64 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -650,8 +650,10 @@ bool DoLoadState(ByteStream* state, bool force_software_renderer) if (header.version != SAVE_STATE_VERSION) { - g_host_interface->ReportFormattedError("Save state is incompatible: expecting version %u but state is version %u.", - SAVE_STATE_VERSION, header.version); + g_host_interface->ReportFormattedError( + g_host_interface->TranslateString("System", + "Save state is incompatible: expecting version %u but state is version %u."), + SAVE_STATE_VERSION, header.version); return false; } @@ -672,8 +674,9 @@ bool DoLoadState(ByteStream* state, bool force_software_renderer) media = OpenCDImage(media_filename.c_str(), false); if (!media) { - g_host_interface->ReportFormattedError("Failed to open CD image from save state: '%s'.", - media_filename.c_str()); + g_host_interface->ReportFormattedError( + g_host_interface->TranslateString("System", "Failed to open CD image from save state: '%s'."), + media_filename.c_str()); return false; } } @@ -1173,10 +1176,12 @@ void UpdateMemoryCards() { if (s_running_game_code.empty()) { - g_host_interface->AddFormattedOSDMessage(5.0f, - "Per-game memory card cannot be used for slot %u as the running " - "game has no code. Using shared card instead.", - i + 1u); + g_host_interface->AddFormattedOSDMessage( + 5.0f, + g_host_interface->TranslateString("System", + "Per-game memory card cannot be used for slot %u as the running " + "game has no code. Using shared card instead."), + i + 1u); card = MemoryCard::Open(g_host_interface->GetSharedMemoryCardPath(i)); } else @@ -1195,10 +1200,12 @@ void UpdateMemoryCards() } else if (s_running_game_title.empty()) { - g_host_interface->AddFormattedOSDMessage(5.0f, - "Per-game memory card cannot be used for slot %u as the running " - "game has no title. Using shared card instead.", - i + 1u); + g_host_interface->AddFormattedOSDMessage( + 5.0f, + g_host_interface->TranslateString("System", + "Per-game memory card cannot be used for slot %u as the running " + "game has no title. Using shared card instead."), + i + 1u); card = MemoryCard::Open(g_host_interface->GetSharedMemoryCardPath(i)); } else @@ -1212,8 +1219,10 @@ void UpdateMemoryCards() { if (g_settings.memory_card_paths[i].empty()) { - g_host_interface->AddFormattedOSDMessage(10.0f, "Memory card path for slot %u is missing, using default.", - i + 1u); + g_host_interface->AddFormattedOSDMessage( + 10.0f, + g_host_interface->TranslateString("System", "Memory card path for slot %u is missing, using default."), + i + 1u); card = MemoryCard::Open(g_host_interface->GetSharedMemoryCardPath(i)); } else @@ -1256,7 +1265,8 @@ bool InsertMedia(const char* path) if (g_settings.HasAnyPerGameMemoryCards()) { - g_host_interface->AddOSDMessage("Game changed, reloading memory cards.", 2.0f); + g_host_interface->AddOSDMessage( + g_host_interface->TranslateStdString("System", "Game changed, reloading memory cards."), 10.0f); UpdateMemoryCards(); } diff --git a/src/duckstation-qt/advancedsettingswidget.cpp b/src/duckstation-qt/advancedsettingswidget.cpp index 40219cf56..2b4d93a32 100644 --- a/src/duckstation-qt/advancedsettingswidget.cpp +++ b/src/duckstation-qt/advancedsettingswidget.cpp @@ -1,7 +1,7 @@ #include "advancedsettingswidget.h" +#include "mainwindow.h" #include "settingsdialog.h" #include "settingwidgetbinder.h" -#include "mainwindow.h" AdvancedSettingsWidget::AdvancedSettingsWidget(QtHostInterface* host_interface, QWidget* parent, SettingsDialog* dialog) : QWidget(parent), m_host_interface(host_interface) @@ -9,7 +9,7 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(QtHostInterface* host_interface, m_ui.setupUi(this); for (u32 i = 0; i < static_cast(LOGLEVEL_COUNT); i++) - m_ui.logLevel->addItem(tr(Settings::GetLogLevelDisplayName(static_cast(i)))); + m_ui.logLevel->addItem(qApp->translate("LogLevel", Settings::GetLogLevelDisplayName(static_cast(i)))); SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.logLevel, "Logging", "LogLevel", &Settings::ParseLogLevelName, &Settings::GetLogLevelName, diff --git a/src/duckstation-qt/audiosettingswidget.cpp b/src/duckstation-qt/audiosettingswidget.cpp index 583decfc5..194251e6d 100644 --- a/src/duckstation-qt/audiosettingswidget.cpp +++ b/src/duckstation-qt/audiosettingswidget.cpp @@ -11,7 +11,10 @@ AudioSettingsWidget::AudioSettingsWidget(QtHostInterface* host_interface, QWidge m_ui.setupUi(this); for (u32 i = 0; i < static_cast(AudioBackend::Count); i++) - m_ui.audioBackend->addItem(tr(Settings::GetAudioBackendDisplayName(static_cast(i)))); + { + m_ui.audioBackend->addItem( + qApp->translate("AudioBackend", Settings::GetAudioBackendDisplayName(static_cast(i)))); + } SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.audioBackend, "Audio", "Backend", &Settings::ParseAudioBackend, &Settings::GetAudioBackendName, diff --git a/src/duckstation-qt/consolesettingswidget.cpp b/src/duckstation-qt/consolesettingswidget.cpp index a3bdf4e32..33914b39a 100644 --- a/src/duckstation-qt/consolesettingswidget.cpp +++ b/src/duckstation-qt/consolesettingswidget.cpp @@ -11,10 +11,16 @@ ConsoleSettingsWidget::ConsoleSettingsWidget(QtHostInterface* host_interface, QW m_ui.setupUi(this); for (u32 i = 0; i < static_cast(ConsoleRegion::Count); i++) - m_ui.region->addItem(tr(Settings::GetConsoleRegionDisplayName(static_cast(i)))); + { + m_ui.region->addItem( + qApp->translate("ConsoleRegion", Settings::GetConsoleRegionDisplayName(static_cast(i)))); + } for (u32 i = 0; i < static_cast(CPUExecutionMode::Count); i++) - m_ui.cpuExecutionMode->addItem(tr(Settings::GetCPUExecutionModeDisplayName(static_cast(i)))); + { + m_ui.cpuExecutionMode->addItem( + qApp->translate("CPUExecutionMode", Settings::GetCPUExecutionModeDisplayName(static_cast(i)))); + } SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.region, "Console", "Region", &Settings::ParseConsoleRegionName, &Settings::GetConsoleRegionName, @@ -35,9 +41,10 @@ ConsoleSettingsWidget::ConsoleSettingsWidget(QtHostInterface* host_interface, QW dialog->registerWidgetHelp(m_ui.fastBoot, tr("Fast Boot"), tr("Unchecked"), tr("Patches the BIOS to skip the console's boot animation. Does not work with all games, " "but usually safe to enabled.")); - - dialog->registerWidgetHelp(m_ui.cdromLoadImageToRAM, tr("Preload Image to RAM"), tr("Unchecked"), - tr("Loads the game image into RAM. Useful for network paths that may become unreliable during gameplay.")); + + dialog->registerWidgetHelp( + m_ui.cdromLoadImageToRAM, tr("Preload Image to RAM"), tr("Unchecked"), + tr("Loads the game image into RAM. Useful for network paths that may become unreliable during gameplay.")); } ConsoleSettingsWidget::~ConsoleSettingsWidget() = default; diff --git a/src/duckstation-qt/controllersettingswidget.cpp b/src/duckstation-qt/controllersettingswidget.cpp index 45653ed4f..c7c5d7914 100644 --- a/src/duckstation-qt/controllersettingswidget.cpp +++ b/src/duckstation-qt/controllersettingswidget.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -48,7 +49,7 @@ void ControllerSettingsWidget::onProfileLoaded() ControllerType ctype = Settings::ParseControllerTypeName( m_host_interface ->GetStringSettingValue(QStringLiteral("Controller%1").arg(i + 1).toStdString().c_str(), - QStringLiteral("Type").toStdString().c_str()) + QStringLiteral("Type").toStdString().c_str()) .c_str()) .value_or(ControllerType::None); @@ -86,7 +87,7 @@ void ControllerSettingsWidget::createPortSettingsUi(int index, PortSettingsUI* u for (int i = 0; i < static_cast(ControllerType::Count); i++) { ui->controller_type->addItem( - QString::fromUtf8(Settings::GetControllerTypeDisplayName(static_cast(i)))); + qApp->translate("ControllerType", Settings::GetControllerTypeDisplayName(static_cast(i)))); } ControllerType ctype = Settings::ParseControllerTypeName( diff --git a/src/duckstation-qt/gamepropertiesdialog.cpp b/src/duckstation-qt/gamepropertiesdialog.cpp index 61a6b8fb9..f72fe4bed 100644 --- a/src/duckstation-qt/gamepropertiesdialog.cpp +++ b/src/duckstation-qt/gamepropertiesdialog.cpp @@ -104,12 +104,13 @@ void GamePropertiesDialog::populateCompatibilityInfo(const std::string& game_cod void GamePropertiesDialog::setupAdditionalUi() { for (u8 i = 0; i < static_cast(DiscRegion::Count); i++) - m_ui.region->addItem(tr(Settings::GetDiscRegionDisplayName(static_cast(i)))); + m_ui.region->addItem(qApp->translate("DiscRegion", Settings::GetDiscRegionDisplayName(static_cast(i)))); for (int i = 0; i < static_cast(GameListCompatibilityRating::Count); i++) { m_ui.compatibility->addItem( - tr(GameList::GetGameListCompatibilityRatingString(static_cast(i)))); + qApp->translate("GameListCompatibilityRating", + GameList::GetGameListCompatibilityRatingString(static_cast(i)))); } m_ui.userAspectRatio->addItem(tr("(unchanged)")); @@ -123,29 +124,29 @@ void GamePropertiesDialog::setupAdditionalUi() for (u32 i = 0; i < static_cast(DisplayCropMode::Count); i++) { m_ui.userCropMode->addItem( - QString::fromUtf8(Settings::GetDisplayCropModeDisplayName(static_cast(i)))); + qApp->translate("DisplayCropMode", Settings::GetDisplayCropModeDisplayName(static_cast(i)))); } m_ui.userControllerType1->addItem(tr("(unchanged)")); for (u32 i = 0; i < static_cast(ControllerType::Count); i++) { m_ui.userControllerType1->addItem( - QString::fromUtf8(Settings::GetControllerTypeDisplayName(static_cast(i)))); + qApp->translate("ControllerType", Settings::GetControllerTypeDisplayName(static_cast(i)))); } m_ui.userControllerType2->addItem(tr("(unchanged)")); for (u32 i = 0; i < static_cast(ControllerType::Count); i++) { m_ui.userControllerType2->addItem( - QString::fromUtf8(Settings::GetControllerTypeDisplayName(static_cast(i)))); + qApp->translate("ControllerType", Settings::GetControllerTypeDisplayName(static_cast(i)))); } QGridLayout* traits_layout = new QGridLayout(m_ui.compatibilityTraits); for (u32 i = 0; i < static_cast(GameSettings::Trait::Count); i++) { - m_trait_checkboxes[i] = - new QCheckBox(QString::fromUtf8(GameSettings::GetTraitDisplayName(static_cast(i))), - m_ui.compatibilityTraits); + m_trait_checkboxes[i] = new QCheckBox( + qApp->translate("GameSettingsTrait", GameSettings::GetTraitDisplayName(static_cast(i))), + m_ui.compatibilityTraits); traits_layout->addWidget(m_trait_checkboxes[i], i / 2, i % 2); } @@ -189,8 +190,8 @@ void GamePropertiesDialog::populateTracksInfo(const std::string& image_path) const CDImage::TrackMode mode = image->GetTrackMode(static_cast(track)); const int row = static_cast(track - 1u); m_ui.tracks->insertRow(row); - m_ui.tracks->setItem(row, 0, new QTableWidgetItem(tr("%1").arg(track))); - m_ui.tracks->setItem(row, 1, new QTableWidgetItem(tr(track_mode_strings[static_cast(mode)]))); + m_ui.tracks->setItem(row, 0, new QTableWidgetItem(QStringLiteral("%1").arg(track))); + m_ui.tracks->setItem(row, 1, new QTableWidgetItem(track_mode_strings[static_cast(mode)])); m_ui.tracks->setItem(row, 2, new QTableWidgetItem(MSFTotString(position))); m_ui.tracks->setItem(row, 3, new QTableWidgetItem(MSFTotString(length))); m_ui.tracks->setItem(row, 4, new QTableWidgetItem(tr(""))); diff --git a/src/duckstation-qt/gpusettingswidget.cpp b/src/duckstation-qt/gpusettingswidget.cpp index eae0af7fa..21a4eb503 100644 --- a/src/duckstation-qt/gpusettingswidget.cpp +++ b/src/duckstation-qt/gpusettingswidget.cpp @@ -129,7 +129,8 @@ GPUSettingsWidget::GPUSettingsWidget(QtHostInterface* host_interface, QWidget* p m_ui.widescreenHack, tr("Widescreen Hack"), tr("Unchecked"), tr("Scales vertex positions in screen-space to a widescreen aspect ratio, essentially " "increasing the field of view from 4:3 to 16:9 in 3D games.
For 2D games, or games which " - "use pre-rendered backgrounds, this enhancement will not work as expected. May not be compatible with all games.")); + "use pre-rendered backgrounds, this enhancement will not work as expected. May not be compatible with all " + "games.")); dialog->registerWidgetHelp( m_ui.pgxpEnable, tr("Geometry Correction"), tr("Unchecked"), tr("Reduces \"wobbly\" polygons and \"warping\" textures that are common in PS1 games.
Only " @@ -143,7 +144,8 @@ GPUSettingsWidget::GPUSettingsWidget(QtHostInterface* host_interface, QWidget* p dialog->registerWidgetHelp(m_ui.pgxpVertexCache, tr("Vertex Cache"), tr("Unchecked"), tr("Uses screen coordinates as a fallback when tracking vertices through memory fails. " "May improve PGXP compatibility.")); - dialog->registerWidgetHelp(m_ui.pgxpCPUMode, tr("CPU Mode"), tr("Unchecked"), + dialog->registerWidgetHelp( + m_ui.pgxpCPUMode, tr("CPU Mode"), tr("Unchecked"), tr("Tries to track vertex manipulation through the CPU. Some games require this option for PGXP to be effective. " "Very slow, and incompatible with the recompiler.")); } @@ -161,7 +163,10 @@ void GPUSettingsWidget::updateScaledDitheringEnabled() void GPUSettingsWidget::setupAdditionalUi() { for (u32 i = 0; i < static_cast(GPURenderer::Count); i++) - m_ui.renderer->addItem(QString::fromUtf8(Settings::GetRendererDisplayName(static_cast(i)))); + { + m_ui.renderer->addItem( + qApp->translate("GPURenderer", Settings::GetRendererDisplayName(static_cast(i)))); + } for (u32 i = 0; i < static_cast(DisplayAspectRatio::Count); i++) { @@ -172,7 +177,7 @@ void GPUSettingsWidget::setupAdditionalUi() for (u32 i = 0; i < static_cast(DisplayCropMode::Count); i++) { m_ui.displayCropMode->addItem( - QString::fromUtf8(Settings::GetDisplayCropModeDisplayName(static_cast(i)))); + qApp->translate("DisplayCropMode", Settings::GetDisplayCropModeDisplayName(static_cast(i)))); } std::array resolution_suffixes = {{ diff --git a/src/duckstation-qt/hotkeysettingswidget.cpp b/src/duckstation-qt/hotkeysettingswidget.cpp index 7bbfac751..0473f415c 100644 --- a/src/duckstation-qt/hotkeysettingswidget.cpp +++ b/src/duckstation-qt/hotkeysettingswidget.cpp @@ -4,6 +4,7 @@ #include "inputbindingwidgets.h" #include "qthostinterface.h" #include "qtutils.h" +#include #include #include #include @@ -63,7 +64,7 @@ void HotkeySettingsWidget::createButtons() std::string section_name("Hotkeys"); std::string key_name(hi.name.GetCharArray()); - layout->addWidget(new QLabel(QString::fromUtf8(hi.display_name), container), target_row, 0); + layout->addWidget(new QLabel(qApp->translate("Hotkeys", hi.display_name), container), target_row, 0); layout->addWidget( new InputButtonBindingWidget(m_host_interface, std::move(section_name), std::move(key_name), container), target_row, 1); diff --git a/src/duckstation-qt/memorycardsettingswidget.cpp b/src/duckstation-qt/memorycardsettingswidget.cpp index fc7730424..63ee1eaae 100644 --- a/src/duckstation-qt/memorycardsettingswidget.cpp +++ b/src/duckstation-qt/memorycardsettingswidget.cpp @@ -76,7 +76,7 @@ void MemoryCardSettingsWidget::createPortSettingsUi(SettingsDialog* dialog, int for (int i = 0; i < static_cast(MemoryCardType::Count); i++) { ui->memory_card_type->addItem( - QString::fromUtf8(Settings::GetMemoryCardTypeDisplayName(static_cast(i)))); + qApp->translate("MemoryCardType", Settings::GetMemoryCardTypeDisplayName(static_cast(i)))); } const MemoryCardType default_value = (index == 0) ? MemoryCardType::PerGameTitle : MemoryCardType::None; diff --git a/src/duckstation-qt/qthostinterface.cpp b/src/duckstation-qt/qthostinterface.cpp index 882a6c9e3..6c2b9fb95 100644 --- a/src/duckstation-qt/qthostinterface.cpp +++ b/src/duckstation-qt/qthostinterface.cpp @@ -34,7 +34,10 @@ Log_SetChannel(QtHostInterface); #ifdef WIN32 +#include "common/windows_headers.h" #include "frontend-common/d3d11_host_display.h" +#include +#include #endif QtHostInterface::QtHostInterface(QObject* parent) : QObject(parent), CommonHostInterface() @@ -1186,6 +1189,49 @@ void QtHostInterface::wakeThread() QMetaObject::invokeMethod(m_worker_thread_event_loop, "quit", Qt::QueuedConnection); } +static std::string GetFontPath(const char* name) +{ +#ifdef WIN32 + PWSTR folder_path; + if (FAILED(SHGetKnownFolderPath(FOLDERID_Fonts, 0, nullptr, &folder_path))) + return StringUtil::StdStringFromFormat("C:\\Windows\\Fonts\\%s", name); + + std::string font_path(StringUtil::WideStringToUTF8String(folder_path)); + CoTaskMemFree(folder_path); + font_path += "\\"; + font_path += name; + return font_path; +#else + return name; +#endif +} + +static bool AddImGuiFont(const std::string& language, float size, float framebuffer_scale) +{ + std::string path; + const ImWchar* range = nullptr; +#ifdef WIN32 + if (language == "jp") + { + path = GetFontPath("msgothic.ttc"); + range = ImGui::GetIO().Fonts->GetGlyphRangesJapanese(); + } + else if (language == "zh-cn") + { + path = GetFontPath("msyh.ttc"); + range = ImGui::GetIO().Fonts->GetGlyphRangesChineseSimplifiedCommon(); + } +#endif + + if (!path.empty()) + { + return (ImGui::GetIO().Fonts->AddFontFromFileTTF(path.c_str(), size * framebuffer_scale, nullptr, range) != + nullptr); + } + + return false; +} + void QtHostInterface::createImGuiContext(float framebuffer_scale) { ImGui::CreateContext(); @@ -1197,7 +1243,10 @@ void QtHostInterface::createImGuiContext(float framebuffer_scale) ImGui::GetStyle().ScaleAllSizes(framebuffer_scale); ImGui::StyleColorsDarker(); - ImGui::AddRobotoRegularFont(15.0f * framebuffer_scale); + + std::string language = GetStringSettingValue("Main", "Language", ""); + if (!AddImGuiFont(language, 15.0f, framebuffer_scale)) + ImGui::AddRobotoRegularFont(15.0f * framebuffer_scale); } void QtHostInterface::destroyImGuiContext() @@ -1205,6 +1254,24 @@ void QtHostInterface::destroyImGuiContext() ImGui::DestroyContext(); } +TinyString QtHostInterface::TranslateString(const char* context, const char* str) const +{ + const QString translated(m_translator->translate(context, str)); + if (translated.isEmpty()) + return TinyString(str); + + return TinyString(translated.toUtf8().constData()); +} + +std::string QtHostInterface::TranslateStdString(const char* context, const char* str) const +{ + const QString translated(m_translator->translate(context, str)); + if (translated.isEmpty()) + return std::string(str); + + return translated.toStdString(); +} + QtHostInterface::Thread::Thread(QtHostInterface* parent) : QThread(parent), m_parent(parent) {} QtHostInterface::Thread::~Thread() = default; diff --git a/src/duckstation-qt/qthostinterface.h b/src/duckstation-qt/qthostinterface.h index 294aa2225..663bb26eb 100644 --- a/src/duckstation-qt/qthostinterface.h +++ b/src/duckstation-qt/qthostinterface.h @@ -64,6 +64,9 @@ public: void SetStringListSettingValue(const char* section, const char* key, const std::vector& values); void RemoveSettingValue(const char* section, const char* key); + TinyString TranslateString(const char* context, const char* str) const; + std::string TranslateStdString(const char* context, const char* str) const; + ALWAYS_INLINE const GameList* getGameList() const { return m_game_list.get(); } ALWAYS_INLINE GameList* getGameList() { return m_game_list.get(); } void refreshGameList(bool invalidate_cache = false, bool invalidate_database = false); diff --git a/src/duckstation-qt/update_translations.bat b/src/duckstation-qt/update_translations.bat index 9c88cd3e9..e6b4298b8 100644 --- a/src/duckstation-qt/update_translations.bat +++ b/src/duckstation-qt/update_translations.bat @@ -1,6 +1,10 @@ -..\..\dep\msvc\qt\5.15.0\msvc2017_64\bin\lupdate.exe ./ -ts translations\duckstation-qt_de.ts -..\..\dep\msvc\qt\5.15.0\msvc2017_64\bin\lupdate.exe ./ -ts translations\duckstation-qt_he.ts -..\..\dep\msvc\qt\5.15.0\msvc2017_64\bin\lupdate.exe ./ -ts translations\duckstation-qt_pt-br.ts -..\..\dep\msvc\qt\5.15.0\msvc2017_64\bin\lupdate.exe ./ -ts translations\duckstation-qt_pt-pt.ts -..\..\dep\msvc\qt\5.15.0\msvc2017_64\bin\lupdate.exe ./ -ts translations\duckstation-qt_zh-cn.ts +set LUPDATE=..\..\dep\msvc\qt\5.15.0\msvc2017_64\bin\lupdate.exe ./ ../core/ ../frontend-common/ -tr-function-alias translate+=TranslateString -tr-function-alias translate+=TranslateStdString -tr-function-alias QT_TRANSLATE_NOOP+=TRANSLATABLE + +%LUPDATE% -ts translations\duckstation-qt_de.ts +%LUPDATE% -ts translations\duckstation-qt_es.ts +%LUPDATE% -ts translations\duckstation-qt_he.ts +%LUPDATE% -ts translations\duckstation-qt_it.ts +%LUPDATE% -ts translations\duckstation-qt_pt-br.ts +%LUPDATE% -ts translations\duckstation-qt_pt-pt.ts +%LUPDATE% -ts translations\duckstation-qt_zh-cn.ts pause diff --git a/src/frontend-common/common_host_interface.cpp b/src/frontend-common/common_host_interface.cpp index 470f4718f..b9181a44c 100644 --- a/src/frontend-common/common_host_interface.cpp +++ b/src/frontend-common/common_host_interface.cpp @@ -1240,44 +1240,51 @@ bool CommonHostInterface::AddRumbleToInputMap(const std::string& binding, u32 co void CommonHostInterface::RegisterGeneralHotkeys() { - RegisterHotkey(StaticString("General"), StaticString("FastForward"), StaticString("Fast Forward"), + RegisterHotkey(StaticString("General"), StaticString("FastForward"), TRANSLATABLE("Hotkeys", "Fast Forward"), [this](bool pressed) { m_speed_limiter_temp_disabled = pressed; UpdateSpeedLimiterState(); }); - RegisterHotkey(StaticString("General"), StaticString("ToggleFastForward"), StaticString("Toggle Fast Forward"), - [this](bool pressed) { + RegisterHotkey(StaticString("General"), StaticString("ToggleFastForward"), + StaticString(TRANSLATABLE("Hotkeys", "Toggle Fast Forward")), [this](bool pressed) { if (!pressed) { m_speed_limiter_temp_disabled = !m_speed_limiter_temp_disabled; UpdateSpeedLimiterState(); - AddFormattedOSDMessage(2.0f, "Speed limiter %s.", - m_speed_limiter_enabled ? "enabled" : "disabled"); + AddOSDMessage(m_speed_limiter_enabled ? + TranslateStdString("OSDMessage", "Speed limiter enabled.") : + TranslateStdString("OSDMessage", "Speed limiter disabled."), + 2.0f); } }); - RegisterHotkey(StaticString("General"), StaticString("ToggleFullscreen"), StaticString("Toggle Fullscreen"), - [this](bool pressed) { + RegisterHotkey(StaticString("General"), StaticString("ToggleFullscreen"), + StaticString(TRANSLATABLE("Hotkeys", "Toggle Fullscreen")), [this](bool pressed) { if (!pressed) SetFullscreen(!IsFullscreen()); }); - RegisterHotkey(StaticString("General"), StaticString("TogglePause"), StaticString("Toggle Pause"), - [this](bool pressed) { + RegisterHotkey(StaticString("General"), StaticString("TogglePause"), + StaticString(TRANSLATABLE("Hotkeys", "Toggle Pause")), [this](bool pressed) { if (System::IsValid() && !pressed) PauseSystem(!System::IsPaused()); }); - RegisterHotkey(StaticString("General"), StaticString("PowerOff"), StaticString("Power Off System"), - [this](bool pressed) { + RegisterHotkey(StaticString("General"), StaticString("PowerOff"), + StaticString(TRANSLATABLE("Hotkeys", "Power Off System")), [this](bool pressed) { if (!pressed && System::IsValid()) { if (g_settings.confim_power_off && !m_batch_mode) { - SmallString confirmation_message("Are you sure you want to stop emulation?"); + SmallString confirmation_message( + TranslateString("CommonHostInterface", "Are you sure you want to stop emulation?")); if (g_settings.save_state_on_exit) - confirmation_message.AppendString("\n\nThe current state will be saved."); + { + confirmation_message.AppendString("\n\n"); + confirmation_message.AppendString( + TranslateString("CommonHostInterface", "The current state will be saved.")); + } if (!ConfirmMessage(confirmation_message)) { @@ -1290,53 +1297,55 @@ void CommonHostInterface::RegisterGeneralHotkeys() } }); - RegisterHotkey(StaticString("General"), StaticString("Screenshot"), StaticString("Save Screenshot"), - [this](bool pressed) { + RegisterHotkey(StaticString("General"), StaticString("Screenshot"), + StaticString(TRANSLATABLE("Hotkeys", "Save Screenshot")), [this](bool pressed) { if (!pressed && System::IsValid()) SaveScreenshot(); }); - RegisterHotkey(StaticString("General"), StaticString("FrameStep"), StaticString("Frame Step"), [this](bool pressed) { - if (!pressed) - { - DoFrameStep(); - } - }); + RegisterHotkey(StaticString("General"), StaticString("FrameStep"), + StaticString(TRANSLATABLE("Hotkeys", "Frame Step")), [this](bool pressed) { + if (!pressed) + { + DoFrameStep(); + } + }); } void CommonHostInterface::RegisterGraphicsHotkeys() { RegisterHotkey(StaticString("Graphics"), StaticString("ToggleSoftwareRendering"), - StaticString("Toggle Software Rendering"), [this](bool pressed) { + StaticString(TRANSLATABLE("Hotkeys", "Toggle Software Rendering")), [this](bool pressed) { if (!pressed) ToggleSoftwareRendering(); }); - RegisterHotkey( - StaticString("Graphics"), StaticString("TogglePGXP"), StaticString("Toggle PGXP"), [this](bool pressed) { - if (!pressed) - { - g_settings.gpu_pgxp_enable = !g_settings.gpu_pgxp_enable; - g_gpu->UpdateSettings(); - AddFormattedOSDMessage(5.0f, "PGXP is now %s.", g_settings.gpu_pgxp_enable ? "enabled" : "disabled"); + RegisterHotkey(StaticString("Graphics"), StaticString("TogglePGXP"), + StaticString(TRANSLATABLE("Hotkeys", "Toggle PGXP")), [this](bool pressed) { + if (!pressed) + { + g_settings.gpu_pgxp_enable = !g_settings.gpu_pgxp_enable; + g_gpu->UpdateSettings(); + AddFormattedOSDMessage(5.0f, "PGXP is now %s.", + g_settings.gpu_pgxp_enable ? "enabled" : "disabled"); - if (g_settings.gpu_pgxp_enable) - PGXP::Initialize(); + if (g_settings.gpu_pgxp_enable) + PGXP::Initialize(); - // we need to recompile all blocks if pgxp is toggled on/off - if (g_settings.IsUsingCodeCache()) - CPU::CodeCache::Flush(); - } - }); + // we need to recompile all blocks if pgxp is toggled on/off + if (g_settings.IsUsingCodeCache()) + CPU::CodeCache::Flush(); + } + }); RegisterHotkey(StaticString("Graphics"), StaticString("IncreaseResolutionScale"), - StaticString("Increase Resolution Scale"), [this](bool pressed) { + StaticString(TRANSLATABLE("Hotkeys", "Increase Resolution Scale")), [this](bool pressed) { if (!pressed) ModifyResolutionScale(1); }); RegisterHotkey(StaticString("Graphics"), StaticString("DecreaseResolutionScale"), - StaticString("Decrease Resolution Scale"), [this](bool pressed) { + StaticString(TRANSLATABLE("Hotkeys", "Decrease Resolution Scale")), [this](bool pressed) { if (!pressed) ModifyResolutionScale(-1); }); @@ -1345,80 +1354,94 @@ void CommonHostInterface::RegisterGraphicsHotkeys() void CommonHostInterface::RegisterSaveStateHotkeys() { RegisterHotkey(StaticString("Save States"), StaticString("LoadSelectedSaveState"), - StaticString("Load From Selected Slot"), [this](bool pressed) { + StaticString(TRANSLATABLE("Hotkeys", "Load From Selected Slot")), [this](bool pressed) { if (!pressed) m_save_state_selector_ui->LoadCurrentSlot(); }); RegisterHotkey(StaticString("Save States"), StaticString("SaveSelectedSaveState"), - StaticString("Save To Selected Slot"), [this](bool pressed) { + StaticString(TRANSLATABLE("Hotkeys", "Save To Selected Slot")), [this](bool pressed) { if (!pressed) m_save_state_selector_ui->SaveCurrentSlot(); }); RegisterHotkey(StaticString("Save States"), StaticString("SelectPreviousSaveStateSlot"), - StaticString("Select Previous Save Slot"), [this](bool pressed) { + StaticString(TRANSLATABLE("Hotkeys", "Select Previous Save Slot")), [this](bool pressed) { if (!pressed) m_save_state_selector_ui->SelectPreviousSlot(); }); RegisterHotkey(StaticString("Save States"), StaticString("SelectNextSaveStateSlot"), - StaticString("Select Next Save Slot"), [this](bool pressed) { + StaticString(TRANSLATABLE("Hotkeys", "Select Next Save Slot")), [this](bool pressed) { if (!pressed) m_save_state_selector_ui->SelectNextSlot(); }); - for (u32 global_i = 0; global_i < 2; global_i++) + for (u32 slot = 1; slot <= PER_GAME_SAVE_STATE_SLOTS; slot++) { - const bool global = ConvertToBoolUnchecked(global_i); - const u32 count = global ? GLOBAL_SAVE_STATE_SLOTS : PER_GAME_SAVE_STATE_SLOTS; - for (u32 slot = 1; slot <= count; slot++) - { - RegisterHotkey(StaticString("Save States"), - TinyString::FromFormat("Load%sState%u", global ? "Global" : "Game", slot), - TinyString::FromFormat("Load %s State %u", global ? "Global" : "Game", slot), - [this, global, slot](bool pressed) { - if (!pressed) - LoadState(global, slot); - }); - RegisterHotkey(StaticString("Save States"), - TinyString::FromFormat("Save%sState%u", global ? "Global" : "Game", slot), - TinyString::FromFormat("Save %s State %u", global ? "Global" : "Game", slot), - [this, global, slot](bool pressed) { - if (!pressed) - SaveState(global, slot); - }); - } + RegisterHotkey(StaticString("Save States"), TinyString::FromFormat("LoadGameState%u", slot), + TinyString::FromFormat(TRANSLATABLE("Hotkeys", "Load Game State %u"), slot), + [this, slot](bool pressed) { + if (!pressed) + LoadState(false, slot); + }); + RegisterHotkey(StaticString("Save States"), TinyString::FromFormat("SaveGameState%u", slot), + TinyString::FromFormat(TRANSLATABLE("Hotkeys", "Save Game State %u"), slot), + [this, slot](bool pressed) { + if (!pressed) + SaveState(false, slot); + }); + } + + for (u32 slot = 1; slot <= GLOBAL_SAVE_STATE_SLOTS; slot++) + { + RegisterHotkey(StaticString("Save States"), TinyString::FromFormat("LoadGlobalState%u", slot), + TinyString::FromFormat(TRANSLATABLE("Hotkeys", "Load Global State %u"), slot), + [this, slot](bool pressed) { + if (!pressed) + LoadState(true, slot); + }); + RegisterHotkey(StaticString("Save States"), TinyString::FromFormat("SaveGlobalState%u", slot), + TinyString::FromFormat(TRANSLATABLE("Hotkeys", "Save Global State %u"), slot), + [this, slot](bool pressed) { + if (!pressed) + SaveState(true, slot); + }); } } void CommonHostInterface::RegisterAudioHotkeys() { - RegisterHotkey(StaticString("Audio"), StaticString("AudioMute"), StaticString("Toggle Mute"), [this](bool pressed) { - if (System::IsValid() && !pressed) - { - g_settings.audio_output_muted = !g_settings.audio_output_muted; - m_audio_stream->SetOutputVolume(g_settings.audio_output_muted ? 0 : g_settings.audio_output_volume); - if (g_settings.audio_output_muted) - AddOSDMessage("Volume: Muted", 2.0f); - else - AddFormattedOSDMessage(2.0f, "Volume: %d%%", g_settings.audio_output_volume); - } - }); - RegisterHotkey(StaticString("Audio"), StaticString("AudioVolumeUp"), StaticString("Volume Up"), [this](bool pressed) { - if (System::IsValid() && pressed) - { - g_settings.audio_output_volume = std::min(g_settings.audio_output_volume + 10, 100); - g_settings.audio_output_muted = false; - m_audio_stream->SetOutputVolume(g_settings.audio_output_volume); - AddFormattedOSDMessage(2.0f, "Volume: %d%%", g_settings.audio_output_volume); - } - }); - RegisterHotkey(StaticString("Audio"), StaticString("AudioVolumeDown"), StaticString("Volume Down"), - [this](bool pressed) { + RegisterHotkey( + StaticString("Audio"), StaticString("AudioMute"), StaticString(TRANSLATABLE("Hotkeys", "Toggle Mute")), + [this](bool pressed) { + if (System::IsValid() && !pressed) + { + g_settings.audio_output_muted = !g_settings.audio_output_muted; + m_audio_stream->SetOutputVolume(g_settings.audio_output_muted ? 0 : g_settings.audio_output_volume); + if (g_settings.audio_output_muted) + AddOSDMessage(TranslateStdString("OSDMessage", "Volume: Muted"), 2.0f); + else + AddFormattedOSDMessage(2.0f, TranslateString("OSDMessage", "Volume: %d%%"), g_settings.audio_output_volume); + } + }); + RegisterHotkey(StaticString("Audio"), StaticString("AudioVolumeUp"), + StaticString(TRANSLATABLE("Hotkeys", "Volume Up")), [this](bool pressed) { + if (System::IsValid() && pressed) + { + g_settings.audio_output_volume = std::min(g_settings.audio_output_volume + 10, 100); + g_settings.audio_output_muted = false; + m_audio_stream->SetOutputVolume(g_settings.audio_output_volume); + AddFormattedOSDMessage(2.0f, TranslateString("OSDMessage", "Volume: %d%%"), + g_settings.audio_output_volume); + } + }); + RegisterHotkey(StaticString("Audio"), StaticString("AudioVolumeDown"), + StaticString(TRANSLATABLE("Hotkeys", "Volume Down")), [this](bool pressed) { if (System::IsValid() && pressed) { g_settings.audio_output_volume = std::max(g_settings.audio_output_volume - 10, 0); g_settings.audio_output_muted = false; m_audio_stream->SetOutputVolume(g_settings.audio_output_volume); - AddFormattedOSDMessage(2.0f, "Volume: %d%%", g_settings.audio_output_volume); + AddFormattedOSDMessage(2.0f, TranslateString("OSDMessage", "Volume: %d%%"), + g_settings.audio_output_volume); } }); } @@ -1554,7 +1577,7 @@ void CommonHostInterface::ApplyInputProfile(const char* profile_path, SettingsIn UpdateInputMap(si); - ReportFormattedMessage("Loaded input profile from '%s'", profile_path); + ReportFormattedMessage(TranslateString("OSDMessage", "Loaded input profile from '%s'"), profile_path); } bool CommonHostInterface::SaveInputProfile(const char* profile_path, SettingsInterface& si) @@ -2018,11 +2041,11 @@ bool CommonHostInterface::SaveScreenshot(const char* filename /* = nullptr */, b const bool screenshot_saved = m_display->WriteDisplayTextureToFile(filename, full_resolution, apply_aspect_ratio); if (!screenshot_saved) { - AddFormattedOSDMessage(10.0f, "Failed to save screenshot to '%s'", filename); + AddFormattedOSDMessage(10.0f, TranslateString("OSDMessage", "Failed to save screenshot to '%s'"), filename); return false; } - AddFormattedOSDMessage(5.0f, "Screenshot saved to '%s'.", filename); + AddFormattedOSDMessage(5.0f, TranslateString("OSDMessage", "Screenshot saved to '%s'."), filename); return true; }