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);