From 9417fc6a3a939292bdb993b2e42390a7733ce118 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Fri, 21 Jul 2017 12:46:12 +0200 Subject: [PATCH 1/5] DolphinWX: Set C++ locale After 3a83ebc, the Show System Clock feature started using the unfortunate combination of MM/DD/YY dates (rare outside of the US) and 24-hour time (rare in the US) regardless of the user's locale settings. This commit makes it use the configured locale again. I've noticed one minor difference in behavior between now and before 3a83ebc: The new way of setting the C/C++ locale seems to treat "en" as "en-US", but the wx way of setting the C locale treated it as "en-GB" (at least on Windows). --- Source/Core/DolphinWX/Main.cpp | 3 ++ Source/Core/UICommon/UICommon.cpp | 52 +++++++++++++++++++++++++++++++ Source/Core/UICommon/UICommon.h | 4 +++ 3 files changed, 59 insertions(+) diff --git a/Source/Core/DolphinWX/Main.cpp b/Source/Core/DolphinWX/Main.cpp index ff6b3810cb..ab301df0be 100644 --- a/Source/Core/DolphinWX/Main.cpp +++ b/Source/Core/DolphinWX/Main.cpp @@ -343,6 +343,9 @@ void DolphinApp::InitLanguageSupport() _("Error")); m_locale.reset(new wxLocale(wxLANGUAGE_DEFAULT)); } + + // wxWidgets sets the C locale for us, but not the C++ locale, so let's do that ourselves + UICommon::SetLocale(language_code); } void DolphinApp::OnEndSession(wxCloseEvent& event) diff --git a/Source/Core/UICommon/UICommon.cpp b/Source/Core/UICommon/UICommon.cpp index 423fe2d0ea..25c13bc8ce 100644 --- a/Source/Core/UICommon/UICommon.cpp +++ b/Source/Core/UICommon/UICommon.cpp @@ -2,7 +2,10 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include +#include #include +#include #include #ifdef _WIN32 #include // for SHGetFolderPath @@ -66,6 +69,55 @@ void Shutdown() Config::Shutdown(); } +void SetLocale(std::string locale_name) +{ + auto set_locale = [](const std::string& locale) { +#ifdef __linux__ + std::string adjusted_locale = locale; + if (!locale.empty()) + adjusted_locale += ".UTF-8"; +#else + const std::string& adjusted_locale = locale; +#endif + + // setlocale sets the C locale, and global sets the C and C++ locales, so the call to setlocale + // would be redundant if it wasn't for not having any other good way to check whether + // the locale name is valid. (Constructing a std::locale object for an unsupported + // locale name throws std::runtime_error, and exception handling is disabled in Dolphin.) + if (!std::setlocale(LC_ALL, adjusted_locale.c_str())) + return false; + std::locale::global(std::locale(adjusted_locale)); + return true; + }; + +#ifdef _WIN32 + constexpr char PREFERRED_SEPARATOR = '-'; + constexpr char OTHER_SEPARATOR = '_'; +#else + constexpr char PREFERRED_SEPARATOR = '_'; + constexpr char OTHER_SEPARATOR = '-'; +#endif + + std::replace(locale_name.begin(), locale_name.end(), OTHER_SEPARATOR, PREFERRED_SEPARATOR); + + // Use the specified locale if supported. + if (set_locale(locale_name)) + return; + + // Remove subcodes until we get a supported locale. If that doesn't give us a supported locale, + // "" is passed to set_locale in order to get the system default locale. + while (!locale_name.empty()) + { + const size_t separator_index = locale_name.rfind(PREFERRED_SEPARATOR); + locale_name.erase(separator_index == std::string::npos ? 0 : separator_index); + if (set_locale(locale_name)) + return; + } + + // If none of the locales tried above are supported, we just keep using whatever locale is set + // (which is the classic locale by default). +} + void CreateDirectories() { // Copy initial Wii NAND data from Sys to User. diff --git a/Source/Core/UICommon/UICommon.h b/Source/Core/UICommon/UICommon.h index 8bbd864ec0..b32e0f410b 100644 --- a/Source/Core/UICommon/UICommon.h +++ b/Source/Core/UICommon/UICommon.h @@ -19,6 +19,10 @@ void EnableScreenSaver(Display* display, Window win, bool enable); void EnableScreenSaver(bool enable); #endif +// Calls std::locale::global, selecting a fallback locale if the +// requested locale isn't available +void SetLocale(std::string locale_name); + void CreateDirectories(); void SetUserDirectory(const std::string& custom_path); From 72040600d725e45db3f76034aac2577ef13b2798 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Fri, 21 Jul 2017 13:35:35 +0200 Subject: [PATCH 2/5] Set locale to "en_GB" if "en" is configured --- Source/Core/UICommon/UICommon.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Source/Core/UICommon/UICommon.cpp b/Source/Core/UICommon/UICommon.cpp index 25c13bc8ce..783a3c94eb 100644 --- a/Source/Core/UICommon/UICommon.cpp +++ b/Source/Core/UICommon/UICommon.cpp @@ -98,6 +98,14 @@ void SetLocale(std::string locale_name) constexpr char OTHER_SEPARATOR = '-'; #endif + // Users who use a system language other than English are unlikely to prefer American date and + // time formats, so let's explicitly request "en_GB" if Dolphin's language is set to "en". + // (The settings window only allows setting "en", not anything like "en_US" or "en_GB".) + // Users who prefer the American formats are likely to have their system language set to en_US, + // and are thus likely to leave Dolphin's language as the default value "" (). + if (locale_name == "en") + locale_name = "en_GB"; + std::replace(locale_name.begin(), locale_name.end(), OTHER_SEPARATOR, PREFERRED_SEPARATOR); // Use the specified locale if supported. From 13d060491c12b5d5c6adf571b702e2d411cf39f6 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Mar 2018 13:38:23 +0100 Subject: [PATCH 3/5] DolphinQt2: Set locale We want things like number formatting to be done the way the user expects. --- Source/Core/DolphinQt2/Translation.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Source/Core/DolphinQt2/Translation.cpp b/Source/Core/DolphinQt2/Translation.cpp index e22b4dbb6b..191a721c3b 100644 --- a/Source/Core/DolphinQt2/Translation.cpp +++ b/Source/Core/DolphinQt2/Translation.cpp @@ -18,6 +18,7 @@ #include "Common/MsgHandler.h" #include "Common/StringUtil.h" #include "Core/ConfigManager.h" +#include "UICommon/UICommon.h" constexpr u32 MO_MAGIC_NUMBER = 0x950412de; @@ -270,6 +271,10 @@ static bool TryInstallTranslator(const QString& exact_language_code) if (translator->load(filename)) { QApplication::instance()->installTranslator(translator); + + QLocale::setDefault(QLocale(exact_language_code)); + UICommon::SetLocale(exact_language_code.toStdString()); + return true; } translator->deleteLater(); From 0dca432836a0d51c5540acffcaa8ae54444814d1 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 10 Mar 2018 13:49:47 +0100 Subject: [PATCH 4/5] Remove old code for using default locale This isn't needed anymore now that the global C++ locale isn't set to the classic locale. --- Source/Core/Common/StringUtil.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Source/Core/Common/StringUtil.h b/Source/Core/Common/StringUtil.h index ec2e5c6337..ef84fb6dcd 100644 --- a/Source/Core/Common/StringUtil.h +++ b/Source/Core/Common/StringUtil.h @@ -51,10 +51,6 @@ std::string ThousandSeparate(I value, int spaces = 0) std::ostringstream stream; #endif -// std::locale("") seems to be broken on many platforms -#if defined _WIN32 || (defined __linux__ && !defined __clang__) - stream.imbue(std::locale("")); -#endif stream << std::setw(spaces) << value; #ifdef _WIN32 From a66d56aece307431337fba99acdbe27602430eb6 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 1 Apr 2018 12:26:50 +0200 Subject: [PATCH 5/5] Use configured locale in UICommon::FormatSize StringFromFormat always uses the C locale, so we can't use it if we want the decimal separator to be locale aware, but we can use a stringstream. --- Source/Core/UICommon/UICommon.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Source/Core/UICommon/UICommon.cpp b/Source/Core/UICommon/UICommon.cpp index 783a3c94eb..f761313add 100644 --- a/Source/Core/UICommon/UICommon.cpp +++ b/Source/Core/UICommon/UICommon.cpp @@ -5,8 +5,10 @@ #include #include #include +#include #include #include +#include #ifdef _WIN32 #include // for SHGetFolderPath #endif @@ -406,7 +408,10 @@ std::string FormatSize(u64 bytes) // Don't need exact values, only 5 most significant digits const double unit_size = std::pow(2, unit * 10); - return StringFromFormat("%.2f %s", bytes / unit_size, GetStringT(unit_symbols[unit]).c_str()); + std::stringstream ss; + ss << std::fixed << std::setprecision(2); + ss << bytes / unit_size << ' ' << GetStringT(unit_symbols[unit]); + return ss.str(); } } // namespace UICommon