Set console's default language/country/region based on computer settings

This commit is contained in:
JosJuice 2020-12-27 23:11:22 +01:00
parent a1000afacc
commit 27ddf6382b
13 changed files with 278 additions and 5 deletions

View File

@ -93,12 +93,21 @@ void UpdatePointer()
env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), IDCache::GetUpdateTouchPointer());
}
std::vector<std::string> Host_GetPreferredLocales()
{
// We would like to call ConfigurationCompat.getLocales here, but this function gets called
// during dynamic initialization, and it seems like that makes us unable to obtain a JNIEnv.
return {};
}
void Host_NotifyMapLoaded()
{
}
void Host_RefreshDSPDebuggerWindow()
{
}
bool Host_UIBlocksControllerState()
{
return false;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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};

View File

@ -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};

View File

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

View File

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

View File

@ -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" />

View File

@ -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()
{
}

View File

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

View File

@ -6,9 +6,14 @@
// do nothing except return default values when required.
#include <string>
#include <vector>
#include "Core/Host.h"
std::vector<std::string> Host_GetPreferredLocales()
{
return {};
}
void Host_NotifyMapLoaded()
{
}

View File

@ -5,11 +5,15 @@
// Stub implementation of the Host_* callbacks for tests. These implementations
// do nothing except return default values when required.
#include <memory>
#include <string>
#include <vector>
#include "Core/Host.h"
std::vector<std::string> Host_GetPreferredLocales()
{
return {};
}
void Host_NotifyMapLoaded()
{
}