diff --git a/src/core/host_interface.cpp b/src/core/host_interface.cpp index f482c664b..bbb65fe1f 100644 --- a/src/core/host_interface.cpp +++ b/src/core/host_interface.cpp @@ -992,14 +992,51 @@ 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 +TinyString HostInterface::TranslateString(const char* context, const char* str, + const char* disambiguation /*= nullptr*/, int n /*= -1*/) const { - return str; + TinyString result(str); + if (n >= 0) + { + const std::string number = std::to_string(n); + result.Replace("%n", number.c_str()); + result.Replace("%Ln", number.c_str()); + } + return result; } -std::string HostInterface::TranslateStdString(const char* context, const char* str) const +std::string HostInterface::TranslateStdString(const char* context, const char* str, + const char* disambiguation /*= nullptr*/, int n /*= -1*/) const { - return str; + std::string result(str); + if (n >= 0) + { + const std::string number = std::to_string(n); + // Made to mimick Qt's behaviour + // https://github.com/qt/qtbase/blob/255459250d450286a8c5c492dab3f6d3652171c9/src/corelib/kernel/qcoreapplication.cpp#L2099 + size_t percent_pos = 0; + size_t len = 0; + while ((percent_pos = result.find('%', percent_pos + len)) != std::string::npos) + { + len = 1; + if (percent_pos + len == result.length()) + break; + if (result[percent_pos + len] == 'L') + { + ++len; + if (percent_pos + len == result.length()) + break; + } + if (result[percent_pos + len] == 'n') + { + ++len; + result.replace(percent_pos, len, number); + len = number.length(); + } + } + } + + return result; } bool HostInterface::GetMainDisplayRefreshRate(float* refresh_rate) diff --git a/src/core/host_interface.h b/src/core/host_interface.h index c5e87712d..641ced6a0 100644 --- a/src/core/host_interface.h +++ b/src/core/host_interface.h @@ -118,8 +118,10 @@ public: virtual std::vector GetSettingStringList(const char* section, const char* key) = 0; /// 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; + virtual TinyString TranslateString(const char* context, const char* str, const char* disambiguation = nullptr, + int n = -1) const; + virtual std::string TranslateStdString(const char* context, const char* str, const char* disambiguation = nullptr, + int n = -1) const; /// Returns the refresh rate for the "main" display. Use when it's not possible to query the graphics API for the /// refresh rate of the monitor the window is running in. diff --git a/src/duckstation-qt/qthostinterface.cpp b/src/duckstation-qt/qthostinterface.cpp index 0b9e7d959..7ccc8f5e3 100644 --- a/src/duckstation-qt/qthostinterface.cpp +++ b/src/duckstation-qt/qthostinterface.cpp @@ -127,8 +127,6 @@ void QtHostInterface::shutdownOnThread() void QtHostInterface::installTranslator() { - m_translator = std::make_unique(); - std::string language = GetStringSettingValue("Main", "Language", ""); if (language.empty()) language = "en"; @@ -143,7 +141,8 @@ void QtHostInterface::installTranslator() return; } - if (!m_translator->load(path)) + auto translator = std::make_unique(qApp); + if (!translator->load(path)) { QMessageBox::warning( nullptr, QStringLiteral("Translation Error"), @@ -152,7 +151,7 @@ void QtHostInterface::installTranslator() } Log_InfoPrintf("Loaded translation file for language '%s'", language.c_str()); - qApp->installTranslator(m_translator.get()); + qApp->installTranslator(translator.release()); } void QtHostInterface::ReportError(const char* message) @@ -1602,22 +1601,17 @@ void QtHostInterface::setImGuiKeyMap() io.KeyMap[ImGuiKey_Z] = Qt::Key_Z & IMGUI_KEY_MASK; } -TinyString QtHostInterface::TranslateString(const char* context, const char* str) const +TinyString QtHostInterface::TranslateString(const char* context, const char* str, + const char* disambiguation /*= nullptr*/, int n /*= -1*/) const { - const QString translated(m_translator->translate(context, str)); - if (translated.isEmpty()) - return TinyString(str); - - return TinyString(translated.toUtf8().constData()); + const QByteArray bytes(qApp->translate(context, str, disambiguation, n).toUtf8()); + return TinyString(bytes.constData(), bytes.size()); } -std::string QtHostInterface::TranslateStdString(const char* context, const char* str) const +std::string QtHostInterface::TranslateStdString(const char* context, const char* str, + const char* disambiguation /*= nullptr*/, int n /*= -1*/) const { - const QString translated(m_translator->translate(context, str)); - if (translated.isEmpty()) - return std::string(str); - - return translated.toStdString(); + return qApp->translate(context, str, disambiguation, n).toStdString(); } QtHostInterface::Thread::Thread(QtHostInterface* parent) : QThread(parent), m_parent(parent) {} diff --git a/src/duckstation-qt/qthostinterface.h b/src/duckstation-qt/qthostinterface.h index fe17fe922..a1dd4aa34 100644 --- a/src/duckstation-qt/qthostinterface.h +++ b/src/duckstation-qt/qthostinterface.h @@ -64,8 +64,10 @@ 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 override; - std::string TranslateStdString(const char* context, const char* str) const override; + TinyString TranslateString(const char* context, const char* str, const char* disambiguation = nullptr, + int n = -1) const override; + std::string TranslateStdString(const char* context, const char* str, const char* disambiguation = nullptr, + int n = -1) const override; bool RequestRenderWindowSize(s32 new_window_width, s32 new_window_height) override; void* GetTopLevelWindowHandle() const override; @@ -263,8 +265,6 @@ private: void queueSettingsSave(); void wakeThread(); - std::unique_ptr m_translator; - MainWindow* m_main_window = nullptr; QThread* m_original_thread = nullptr; Thread* m_worker_thread = nullptr;