summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorLéo Lam <leo@leolam.fr>2021-04-06 12:34:58 +0200
committerGitHub <noreply@github.com>2021-04-06 12:34:58 +0200
commite89ae71cec6390e2cc420af2548caf33afe02280 (patch)
tree9827a25eafb4aee8a5090351f1383c7f2de8a375 /Source/Core
parenta1ee6ace71ed9c0250e19e8ff11177da350f6a7c (diff)
parent27ddf6382ba312dbed77cf31f5a4a2bf9a013c88 (diff)
Merge pull request #9388 from JosJuice/default-locale
Set console's default language/country/region based on computer settings
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/BootManager.cpp5
-rw-r--r--Source/Core/Core/CMakeLists.txt2
-rw-r--r--Source/Core/Core/Config/DefaultLocale.cpp199
-rw-r--r--Source/Core/Core/Config/DefaultLocale.h23
-rw-r--r--Source/Core/Core/Config/MainSettings.cpp3
-rw-r--r--Source/Core/Core/Config/SYSCONFSettings.cpp7
-rw-r--r--Source/Core/Core/ConfigManager.cpp11
-rw-r--r--Source/Core/Core/Host.h3
-rw-r--r--Source/Core/DiscIO/Enums.cpp16
-rw-r--r--Source/Core/DiscIO/Enums.h3
-rw-r--r--Source/Core/DolphinLib.props2
-rw-r--r--Source/Core/DolphinNoGUI/MainNoGUI.cpp8
-rw-r--r--Source/Core/DolphinQt/Host.cpp12
13 files changed, 283 insertions, 11 deletions
diff --git a/Source/Core/Core/BootManager.cpp b/Source/Core/Core/BootManager.cpp
index 78b191e1e7..f622c680fa 100644
--- a/Source/Core/Core/BootManager.cpp
+++ b/Source/Core/Core/BootManager.cpp
@@ -393,9 +393,8 @@ bool BootCore(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi)
// Override out-of-region languages/countries to prevent games from crashing or behaving oddly
if (!StartUp.bOverrideRegionSettings)
{
- const int gc_language =
- static_cast<int>(StartUp.GetLanguageAdjustedForRegion(false, StartUp.m_region));
- StartUp.SelectedLanguage = gc_language - (gc_language > 0);
+ StartUp.SelectedLanguage =
+ DiscIO::ToGameCubeLanguage(StartUp.GetLanguageAdjustedForRegion(false, StartUp.m_region));
if (StartUp.bWii)
{
diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt
index d14d998462..5cf611024f 100644
--- a/Source/Core/Core/CMakeLists.txt
+++ b/Source/Core/Core/CMakeLists.txt
@@ -16,6 +16,8 @@ add_library(core
BootManager.h
CheatCodes.h
CommonTitles.h
+ Config/DefaultLocale.cpp
+ Config/DefaultLocale.h
Config/FreeLookSettings.cpp
Config/FreeLookSettings.h
Config/GraphicsSettings.cpp
diff --git a/Source/Core/Core/Config/DefaultLocale.cpp b/Source/Core/Core/Config/DefaultLocale.cpp
new file mode 100644
index 0000000000..af67ea63b7
--- /dev/null
+++ b/Source/Core/Core/Config/DefaultLocale.cpp
@@ -0,0 +1,199 @@
+// Copyright 2020 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "Core/Config/DefaultLocale.h"
+
+#include <algorithm>
+#include <array>
+#include <locale>
+#include <optional>
+#include <string>
+#include <string_view>
+#include <vector>
+
+#ifdef _WIN32
+#include <Windows.h>
+#endif
+
+#include "Common/Assert.h"
+#include "Common/CommonTypes.h"
+#include "Common/StringUtil.h"
+#include "Core/Host.h"
+#include "DiscIO/Enums.h"
+
+namespace Config
+{
+static std::vector<std::string> GetPreferredLocales()
+{
+ static const std::vector<std::string> locales = Host_GetPreferredLocales();
+ return locales;
+}
+
+static std::optional<DiscIO::Language> TryParseLanguage(const std::string& locale)
+{
+ const std::vector<std::string> split_locale = SplitString(locale, '-');
+ if (split_locale.empty())
+ return std::nullopt;
+
+ // Special handling of Chinese due to its two writing systems
+ if (split_locale[0] == "zh")
+ {
+ const auto locale_contains = [&split_locale](std::string_view str) {
+ return std::find(split_locale.cbegin(), split_locale.cend(), str) != split_locale.cend();
+ };
+
+ if (locale_contains("Hans"))
+ return DiscIO::Language::SimplifiedChinese;
+ if (locale_contains("Hant"))
+ return DiscIO::Language::TraditionalChinese;
+
+ // Mainland China and Singapore use simplified characters
+ if (locale_contains("CN") || locale_contains("SG"))
+ return DiscIO::Language::SimplifiedChinese;
+ else
+ return DiscIO::Language::TraditionalChinese;
+ }
+
+ // Same order as in Wii SYSCONF
+ constexpr std::array<std::string_view, 10> LANGUAGES = {
+ "ja", "en", "de", "fr", "es", "it", "nl", "zh", "zh", "ko",
+ };
+
+ const auto it = std::find(LANGUAGES.cbegin(), LANGUAGES.cend(), split_locale[0]);
+ if (it == LANGUAGES.cend())
+ return std::nullopt;
+
+ return static_cast<DiscIO::Language>(it - LANGUAGES.cbegin());
+}
+
+static DiscIO::Language ComputeDefaultLanguage()
+{
+ for (const std::string& locale : GetPreferredLocales())
+ {
+ if (const std::optional<DiscIO::Language> language = TryParseLanguage(locale))
+ return *language;
+ }
+
+ return DiscIO::Language::English;
+}
+
+static std::optional<std::string> TryParseCountryCode(const std::string& locale)
+{
+ const auto is_upper = [](char c) { return std::isupper(c, std::locale::classic()); };
+
+ for (const std::string& part : SplitString(locale, '-'))
+ {
+ if (part.size() == 2 && is_upper(part[0]) && is_upper(part[1]))
+ return part;
+ }
+
+ return std::nullopt;
+}
+
+static std::string ComputeDefaultCountryCode()
+{
+#ifdef _WIN32
+ // Windows codepath: Check the regional information.
+ // More likely to match the user's physical location than locales are.
+ // TODO: Can we use GetUserDefaultGeoName? (It was added in a Windows 10 update)
+ GEOID geo = GetUserGeoID(GEOCLASS_NATION);
+ const int buffer_size = GetGeoInfoW(geo, GEO_ISO2, nullptr, 0, 0);
+ std::vector<wchar_t> buffer(buffer_size);
+ const int result = GetGeoInfoW(geo, GEO_ISO2, buffer.data(), buffer_size, 0);
+ if (result != 0)
+ return TStrToUTF8(buffer.data());
+#endif
+
+ // Generic codepath: Check the locales.
+ // Might be entirely unrelated to someone's actual country (for instance someone in a
+ // non-English-speaking country using en-US), but could also be a perfect match.
+ for (const std::string& locale : GetPreferredLocales())
+ {
+ if (const std::optional<std::string> country_code = TryParseCountryCode(locale))
+ return *country_code;
+ }
+
+ return "";
+}
+
+static std::optional<u8> ComputeDefaultCountry()
+{
+ // clang-format off
+ // Same order as in Wii SYSCONF
+ static constexpr std::array<std::string_view, 178> COUNTRIES = {
+ "--", "JP", "--", "--", "--", "--", "--", "--", "AI", "AG", "AR", "AW", "BS", "BB", "BZ", "BO",
+ "BR", "VG", "CA", "KY", "CL", "CO", "CR", "DM", "DO", "EC", "SV", "GF", "GD", "GP", "GT", "GY",
+ "HT", "HN", "JM", "MQ", "MX", "MS", "AN", "NI", "PA", "PY", "PE", "KN", "LC", "VC", "SR", "TT",
+ "TC", "US", "UY", "VI", "VE", "--", "--", "--", "--", "--", "--", "--", "--", "--", "--", "--",
+ "AL", "AU", "AT", "BE", "BA", "BW", "BG", "HR", "CY", "CZ", "DK", "EE", "FI", "FR", "DE", "GR",
+ "HU", "IS", "IE", "IT", "LV", "LS", "LI", "LT", "LU", "MK", "MT", "ME", "MZ", "NA", "NL", "NZ",
+ "NO", "PL", "PT", "RO", "RU", "RS", "SK", "SI", "ZA", "ES", "SZ", "SE", "CH", "TR", "GB", "ZM",
+ "ZW", "AZ", "MR", "ML", "NE", "TD", "SD", "ER", "DJ", "SO", "--", "--", "--", "--", "--", "--",
+ "TW", "--", "--", "--", "--", "--", "--", "--", "KR", "--", "--", "--", "--", "--", "--", "--",
+ "HK", "MO", "--", "--", "--", "--", "--", "--", "ID", "SG", "TH", "PH", "MY", "--", "--", "--",
+ "CN", "--", "--", "--", "--", "--", "--", "--", "AE", "IN", "EG", "OM", "QA", "KW", "SA", "SY",
+ "BH", "JO",
+ };
+ // clang-format on
+
+ std::string country = ComputeDefaultCountryCode();
+
+ // Netherlands Antilles was split into three new codes after the release of the Wii
+ if (country == "BQ" || country == "CW" || country == "SX")
+ country = "AN";
+
+ const auto it = std::find(COUNTRIES.cbegin(), COUNTRIES.cend(), country);
+ if (it == COUNTRIES.cend())
+ return std::nullopt;
+
+ return static_cast<u8>(it - COUNTRIES.cbegin());
+}
+
+static DiscIO::Region ComputeDefaultRegion()
+{
+ const std::optional<u8> country = GetDefaultCountry();
+
+ if (country)
+ {
+ const DiscIO::Region region = DiscIO::SysConfCountryToRegion(GetDefaultCountry());
+ ASSERT(region != DiscIO::Region::Unknown);
+ return region;
+ }
+
+ switch (GetDefaultLanguage())
+ {
+ case DiscIO::Language::Japanese:
+ return DiscIO::Region::NTSC_J;
+ case DiscIO::Language::Korean:
+ return DiscIO::Region::NTSC_K;
+ default:
+ return DiscIO::Region::PAL;
+ }
+}
+
+DiscIO::Language GetDefaultLanguage()
+{
+ static const DiscIO::Language language = ComputeDefaultLanguage();
+ return language;
+}
+
+std::optional<u8> GetOptionalDefaultCountry()
+{
+ static const std::optional<u8> country = ComputeDefaultCountry();
+ return country;
+}
+
+u8 GetDefaultCountry()
+{
+ constexpr u8 FALLBACK_COUNTRY = 0x6c; // Switzerland, as per Dolphin tradition
+ return GetOptionalDefaultCountry().value_or(FALLBACK_COUNTRY);
+}
+
+DiscIO::Region GetDefaultRegion()
+{
+ static const DiscIO::Region region = ComputeDefaultRegion();
+ return region;
+}
+
+} // namespace Config
diff --git a/Source/Core/Core/Config/DefaultLocale.h b/Source/Core/Core/Config/DefaultLocale.h
new file mode 100644
index 0000000000..cc4abfceee
--- /dev/null
+++ b/Source/Core/Core/Config/DefaultLocale.h
@@ -0,0 +1,23 @@
+// Copyright 2020 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <optional>
+
+#include "Common/CommonTypes.h"
+
+namespace DiscIO
+{
+enum class Language;
+enum class Region;
+} // namespace DiscIO
+
+namespace Config
+{
+DiscIO::Language GetDefaultLanguage();
+std::optional<u8> GetOptionalDefaultCountry();
+u8 GetDefaultCountry();
+DiscIO::Region GetDefaultRegion();
+} // namespace Config
diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp
index d0fbd6c1f2..8fc3580891 100644
--- a/Source/Core/Core/Config/MainSettings.cpp
+++ b/Source/Core/Core/Config/MainSettings.cpp
@@ -8,6 +8,7 @@
#include "AudioCommon/AudioCommon.h"
#include "Common/Config/Config.h"
+#include "Core/Config/DefaultLocale.h"
#include "Core/HW/EXI/EXI_Device.h"
#include "Core/HW/Memmap.h"
#include "Core/HW/SI/SI_Device.h"
@@ -108,7 +109,7 @@ const Info<bool> MAIN_CUSTOM_RTC_ENABLE{{System::Main, "Core", "EnableCustomRTC"
// Default to seconds between 1.1.1970 and 1.1.2000
const Info<u32> MAIN_CUSTOM_RTC_VALUE{{System::Main, "Core", "CustomRTCValue"}, 946684800};
const Info<DiscIO::Region> MAIN_FALLBACK_REGION{{System::Main, "Core", "FallbackRegion"},
- DiscIO::Region::NTSC_J};
+ GetDefaultRegion()};
const Info<bool> MAIN_AUTO_DISC_CHANGE{{System::Main, "Core", "AutoDiscChange"}, false};
const Info<bool> MAIN_ALLOW_SD_WRITES{{System::Main, "Core", "WiiSDCardAllowWrites"}, true};
const Info<bool> MAIN_ENABLE_SAVESTATES{{System::Main, "Core", "EnableSaveStates"}, false};
diff --git a/Source/Core/Core/Config/SYSCONFSettings.cpp b/Source/Core/Core/Config/SYSCONFSettings.cpp
index 3aaebc52bc..f1a21f3e73 100644
--- a/Source/Core/Core/Config/SYSCONFSettings.cpp
+++ b/Source/Core/Core/Config/SYSCONFSettings.cpp
@@ -4,13 +4,16 @@
#include "Core/Config/SYSCONFSettings.h"
+#include "Core/Config/DefaultLocale.h"
+
namespace Config
{
// SYSCONF.IPL
const Info<bool> SYSCONF_SCREENSAVER{{System::SYSCONF, "IPL", "SSV"}, false};
-const Info<u32> SYSCONF_LANGUAGE{{System::SYSCONF, "IPL", "LNG"}, 0x01};
-const Info<u32> SYSCONF_COUNTRY{{System::SYSCONF, "IPL", "SADR"}, 0x6c};
+const Info<u32> SYSCONF_LANGUAGE{{System::SYSCONF, "IPL", "LNG"},
+ static_cast<u32>(GetDefaultLanguage())};
+const Info<u32> SYSCONF_COUNTRY{{System::SYSCONF, "IPL", "SADR"}, GetDefaultCountry()};
const Info<bool> SYSCONF_WIDESCREEN{{System::SYSCONF, "IPL", "AR"}, true};
const Info<bool> SYSCONF_PROGRESSIVE_SCAN{{System::SYSCONF, "IPL", "PGS"}, true};
const Info<bool> SYSCONF_PAL60{{System::SYSCONF, "IPL", "E60"}, 0x01};
diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp
index d4ec804b3a..91161cd4e9 100644
--- a/Source/Core/Core/ConfigManager.cpp
+++ b/Source/Core/Core/ConfigManager.cpp
@@ -33,6 +33,7 @@
#include "Core/Boot/Boot.h"
#include "Core/CommonTitles.h"
+#include "Core/Config/DefaultLocale.h"
#include "Core/Config/MainSettings.h"
#include "Core/Config/SYSCONFSettings.h"
#include "Core/ConfigLoaders/GameConfigLoader.h"
@@ -472,7 +473,8 @@ void SConfig::LoadCoreSettings(IniFile& ini)
core->Get("CPUThread", &bCPUThread, true);
core->Get("SyncOnSkipIdle", &bSyncGPUOnSkipIdleHack, true);
core->Get("EnableCheats", &bEnableCheats, false);
- core->Get("SelectedLanguage", &SelectedLanguage, 0);
+ core->Get("SelectedLanguage", &SelectedLanguage,
+ DiscIO::ToGameCubeLanguage(Config::GetDefaultLanguage()));
core->Get("OverrideRegionSettings", &bOverrideRegionSettings, false);
core->Get("DPL2Decoder", &bDPL2Decoder, false);
core->Get("AudioLatency", &iLatency, 20);
@@ -963,12 +965,11 @@ DiscIO::Region SConfig::GetFallbackRegion()
DiscIO::Language SConfig::GetCurrentLanguage(bool wii) const
{
- int language_value;
+ DiscIO::Language language;
if (wii)
- language_value = Config::Get(Config::SYSCONF_LANGUAGE);
+ language = static_cast<DiscIO::Language>(Config::Get(Config::SYSCONF_LANGUAGE));
else
- language_value = SConfig::GetInstance().SelectedLanguage + 1;
- DiscIO::Language language = static_cast<DiscIO::Language>(language_value);
+ language = DiscIO::FromGameCubeLanguage(SConfig::GetInstance().SelectedLanguage);
// Get rid of invalid values (probably doesn't matter, but might as well do it)
if (language > DiscIO::Language::Unknown || language < DiscIO::Language::Japanese)
diff --git a/Source/Core/Core/Host.h b/Source/Core/Core/Host.h
index cf65c22eb0..ec539a01d2 100644
--- a/Source/Core/Core/Host.h
+++ b/Source/Core/Core/Host.h
@@ -5,6 +5,7 @@
#pragma once
#include <string>
+#include <vector>
// Host - defines an interface for the emulator core to communicate back to the
// OS-specific layer
@@ -32,9 +33,11 @@ enum class HostMessageID
WMUserJobDispatch,
};
+std::vector<std::string> Host_GetPreferredLocales();
bool Host_UIBlocksControllerState();
bool Host_RendererHasFocus();
bool Host_RendererIsFullscreen();
+
void Host_Message(HostMessageID id);
void Host_NotifyMapLoaded();
void Host_RefreshDSPDebuggerWindow();
diff --git a/Source/Core/DiscIO/Enums.cpp b/Source/Core/DiscIO/Enums.cpp
index c43132b7f2..7ee3ce78eb 100644
--- a/Source/Core/DiscIO/Enums.cpp
+++ b/Source/Core/DiscIO/Enums.cpp
@@ -126,6 +126,22 @@ bool IsNTSC(Region region)
return region == Region::NTSC_J || region == Region::NTSC_U || region == Region::NTSC_K;
}
+int ToGameCubeLanguage(Language language)
+{
+ if (language < Language::English || language > Language::Dutch)
+ return 0;
+ else
+ return static_cast<int>(language) - 1;
+}
+
+Language FromGameCubeLanguage(int language)
+{
+ if (language < 0 || language > 5)
+ return Language::Unknown;
+ else
+ return static_cast<Language>(language + 1);
+}
+
// Increment CACHE_REVISION (GameFileCache.cpp) if the code below is modified
Country TypicalCountryForRegion(Region region)
diff --git a/Source/Core/DiscIO/Enums.h b/Source/Core/DiscIO/Enums.h
index 14940d92a8..18a344b680 100644
--- a/Source/Core/DiscIO/Enums.h
+++ b/Source/Core/DiscIO/Enums.h
@@ -76,6 +76,9 @@ bool IsDisc(Platform volume_type);
bool IsWii(Platform volume_type);
bool IsNTSC(Region region);
+int ToGameCubeLanguage(Language language);
+Language FromGameCubeLanguage(int language);
+
Country TypicalCountryForRegion(Region region);
Region SysConfCountryToRegion(u8 country_code);
// Avoid using this function if you can. Country codes aren't always reliable region indicators.
diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props
index 9d89aee8b9..0c9b412a00 100644
--- a/Source/Core/DolphinLib.props
+++ b/Source/Core/DolphinLib.props
@@ -166,6 +166,7 @@
<ClInclude Include="Core\BootManager.h" />
<ClInclude Include="Core\CheatCodes.h" />
<ClInclude Include="Core\CommonTitles.h" />
+ <ClInclude Include="Core\Config\DefaultLocale.h" />
<ClInclude Include="Core\Config\FreeLookSettings.h" />
<ClInclude Include="Core\Config\GraphicsSettings.h" />
<ClInclude Include="Core\Config\MainSettings.h" />
@@ -737,6 +738,7 @@
<ClCompile Include="Core\Boot\DolReader.cpp" />
<ClCompile Include="Core\Boot\ElfReader.cpp" />
<ClCompile Include="Core\BootManager.cpp" />
+ <ClCompile Include="Core\Config\DefaultLocale.cpp" />
<ClCompile Include="Core\Config\FreeLookSettings.cpp" />
<ClCompile Include="Core\Config\GraphicsSettings.cpp" />
<ClCompile Include="Core\Config\MainSettings.cpp" />
diff --git a/Source/Core/DolphinNoGUI/MainNoGUI.cpp b/Source/Core/DolphinNoGUI/MainNoGUI.cpp
index 5ab18a38eb..2c9d39a4b0 100644
--- a/Source/Core/DolphinNoGUI/MainNoGUI.cpp
+++ b/Source/Core/DolphinNoGUI/MainNoGUI.cpp
@@ -10,6 +10,8 @@
#include <cstring>
#include <signal.h>
#include <string>
+#include <vector>
+
#ifndef _WIN32
#include <unistd.h>
#else
@@ -48,9 +50,15 @@ static void signal_handler(int)
s_platform->RequestShutdown();
}
+std::vector<std::string> Host_GetPreferredLocales()
+{
+ return {};
+}
+
void Host_NotifyMapLoaded()
{
}
+
void Host_RefreshDSPDebuggerWindow()
{
}
diff --git a/Source/Core/DolphinQt/Host.cpp b/Source/Core/DolphinQt/Host.cpp
index f5202c1287..fdf0309b26 100644
--- a/Source/Core/DolphinQt/Host.cpp
+++ b/Source/Core/DolphinQt/Host.cpp
@@ -6,6 +6,7 @@
#include <QAbstractEventDispatcher>
#include <QApplication>
+#include <QLocale>
#include <imgui.h>
@@ -95,6 +96,17 @@ void Host::ResizeSurface(int new_width, int new_height)
g_renderer->ResizeSurface();
}
+std::vector<std::string> Host_GetPreferredLocales()
+{
+ const QStringList ui_languages = QLocale::system().uiLanguages();
+ std::vector<std::string> converted_languages(ui_languages.size());
+
+ for (int i = 0; i < ui_languages.size(); ++i)
+ converted_languages[i] = ui_languages[i].toStdString();
+
+ return converted_languages;
+}
+
void Host_Message(HostMessageID id)
{
if (id == HostMessageID::WMUserStop)