13 changed files with 311 additions and 132 deletions
@ -1 +1 @@ |
|||||||
Subproject commit d09fb3722cda34c082a1bb2645224a85af1d27e8 |
Subproject commit bbf908d31cc0b66f62a205f3e6eaafb2439f47d2 |
||||||
@ -0,0 +1,142 @@ |
|||||||
|
#include "Localization.h" |
||||||
|
|
||||||
|
#include <algorithm> |
||||||
|
#include <vector> |
||||||
|
|
||||||
|
#include "def.h" |
||||||
|
|
||||||
|
extern "C" |
||||||
|
{ |
||||||
|
|
||||||
|
EP_L10N_Language LangIDToEPLanguage(LANGID wLanguage) |
||||||
|
{ |
||||||
|
EP_L10N_Language language = {}; |
||||||
|
language.id = wLanguage; |
||||||
|
GetLocaleInfoW(wLanguage, LOCALE_SNAME, language.wszId, ARRAYSIZE(language.wszId)); |
||||||
|
GetLocaleInfoW(wLanguage, LOCALE_SLOCALIZEDLANGUAGENAME, language.wszDisplayName, ARRAYSIZE(language.wszDisplayName)); |
||||||
|
return language; |
||||||
|
} |
||||||
|
|
||||||
|
BOOL EP_L10N_ApplyPreferredLanguageForCurrentThread() |
||||||
|
{ |
||||||
|
BOOL rv = FALSE; |
||||||
|
HKEY hKey = nullptr; |
||||||
|
RegCreateKeyExW( |
||||||
|
HKEY_CURRENT_USER, |
||||||
|
TEXT(REGPATH), |
||||||
|
0, |
||||||
|
nullptr, |
||||||
|
REG_OPTION_NON_VOLATILE, |
||||||
|
KEY_READ | KEY_WOW64_64KEY, |
||||||
|
nullptr, |
||||||
|
&hKey, |
||||||
|
nullptr |
||||||
|
); |
||||||
|
if (hKey == nullptr || hKey == INVALID_HANDLE_VALUE) |
||||||
|
{ |
||||||
|
hKey = nullptr; |
||||||
|
} |
||||||
|
if (hKey) |
||||||
|
{ |
||||||
|
DWORD dwPreferredLanguage = 0; |
||||||
|
DWORD dwSize = sizeof(dwPreferredLanguage); |
||||||
|
LSTATUS lres = RegQueryValueExW( |
||||||
|
hKey, |
||||||
|
TEXT("Language"), |
||||||
|
nullptr, |
||||||
|
nullptr, |
||||||
|
(LPBYTE)&dwPreferredLanguage, |
||||||
|
&dwSize |
||||||
|
); |
||||||
|
if (lres == ERROR_SUCCESS && dwSize > 0) |
||||||
|
{ |
||||||
|
EP_L10N_Language language = LangIDToEPLanguage(dwPreferredLanguage); |
||||||
|
rv = SetThreadPreferredUILanguages(MUI_LANGUAGE_NAME, language.wszId, nullptr); |
||||||
|
} |
||||||
|
RegCloseKey(hKey); |
||||||
|
} |
||||||
|
return rv; |
||||||
|
} |
||||||
|
|
||||||
|
BOOL EP_L10N_GetCurrentUserLanguage(wchar_t* wszLanguage, int cch) |
||||||
|
{ |
||||||
|
BOOL bOk = FALSE; |
||||||
|
ULONG ulNumLanguages = 0; |
||||||
|
ULONG cchLanguagesBuffer = 0; |
||||||
|
if (GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &ulNumLanguages, nullptr, &cchLanguagesBuffer)) |
||||||
|
{ |
||||||
|
wchar_t* wszLanguagesBuffer = (wchar_t*)malloc(cchLanguagesBuffer * sizeof(wchar_t)); |
||||||
|
if (wszLanguagesBuffer) |
||||||
|
{ |
||||||
|
if (GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &ulNumLanguages, wszLanguagesBuffer, &cchLanguagesBuffer)) |
||||||
|
{ |
||||||
|
wcscpy_s(wszLanguage, cch, wszLanguagesBuffer); |
||||||
|
bOk = TRUE; |
||||||
|
} |
||||||
|
free(wszLanguagesBuffer); |
||||||
|
} |
||||||
|
} |
||||||
|
if (!bOk) |
||||||
|
{ |
||||||
|
wcscpy_s(wszLanguage, cch, L"en-US"); |
||||||
|
} |
||||||
|
return TRUE; |
||||||
|
} |
||||||
|
|
||||||
|
BOOL EP_L10N_GetCurrentThreadLanguage(wchar_t* wszLanguage, int cch) |
||||||
|
{ |
||||||
|
BOOL bOk = FALSE; |
||||||
|
ULONG ulNumLanguages = 0; |
||||||
|
ULONG cchLanguagesBuffer = 0; |
||||||
|
if (GetThreadPreferredUILanguages(MUI_LANGUAGE_NAME, &ulNumLanguages, nullptr, &cchLanguagesBuffer)) |
||||||
|
{ |
||||||
|
wchar_t* wszLanguagesBuffer = (wchar_t*)malloc(cchLanguagesBuffer * sizeof(wchar_t)); |
||||||
|
if (wszLanguagesBuffer) |
||||||
|
{ |
||||||
|
if (GetThreadPreferredUILanguages(MUI_LANGUAGE_NAME, &ulNumLanguages, wszLanguagesBuffer, &cchLanguagesBuffer)) |
||||||
|
{ |
||||||
|
wcscpy_s(wszLanguage, cch, wszLanguagesBuffer); |
||||||
|
bOk = TRUE; |
||||||
|
} |
||||||
|
free(wszLanguagesBuffer); |
||||||
|
} |
||||||
|
} |
||||||
|
if (!bOk) |
||||||
|
{ |
||||||
|
wcscpy_s(wszLanguage, cch, L"en-US"); |
||||||
|
} |
||||||
|
return TRUE; |
||||||
|
} |
||||||
|
|
||||||
|
void EP_L10N_EnumerateLanguages(HMODULE hModule, LPCWSTR lpType, LPCWSTR lpName, EP_L10N_EnumerateLanguagesProc_t pfnProc, void* data) |
||||||
|
{ |
||||||
|
std::vector<EP_L10N_Language> languages; |
||||||
|
|
||||||
|
// English (US) is our primary language
|
||||||
|
languages.push_back(LangIDToEPLanguage(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US))); |
||||||
|
|
||||||
|
// Add the rest below it
|
||||||
|
EnumResourceLanguagesW(hModule, lpType, lpName, [](HMODULE, LPCWSTR, LPCWSTR, WORD wLanguage, LONG_PTR lParam) -> BOOL |
||||||
|
{ |
||||||
|
if (wLanguage != MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)) |
||||||
|
{ |
||||||
|
EP_L10N_Language language = LangIDToEPLanguage(wLanguage); |
||||||
|
((std::vector<EP_L10N_Language>*)lParam)->push_back(language); |
||||||
|
} |
||||||
|
return TRUE; |
||||||
|
}, (LONG_PTR)&languages); |
||||||
|
|
||||||
|
// Sort the non-primary languages by localized display name
|
||||||
|
std::sort(languages.begin() + 1, languages.end(), [](const EP_L10N_Language& a, const EP_L10N_Language& b) -> bool |
||||||
|
{ |
||||||
|
return wcscmp(a.wszDisplayName, b.wszDisplayName) < 0; |
||||||
|
}); |
||||||
|
|
||||||
|
// Call the callback for each language
|
||||||
|
for (const EP_L10N_Language& language : languages) |
||||||
|
{ |
||||||
|
pfnProc(&language, data); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,26 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <Windows.h> |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
extern "C" |
||||||
|
{ |
||||||
|
#endif |
||||||
|
|
||||||
|
typedef struct EP_L10N_Language |
||||||
|
{ |
||||||
|
LANGID id; |
||||||
|
wchar_t wszId[LOCALE_NAME_MAX_LENGTH]; |
||||||
|
wchar_t wszDisplayName[LOCALE_NAME_MAX_LENGTH]; |
||||||
|
} EP_L10N_Language; |
||||||
|
|
||||||
|
typedef void(*EP_L10N_EnumerateLanguagesProc_t)(const EP_L10N_Language* language, void* data); |
||||||
|
|
||||||
|
BOOL EP_L10N_ApplyPreferredLanguageForCurrentThread(); |
||||||
|
BOOL EP_L10N_GetCurrentUserLanguage(wchar_t* wszLanguage, int cch); |
||||||
|
BOOL EP_L10N_GetCurrentThreadLanguage(wchar_t* wszLanguage, int cch); |
||||||
|
void EP_L10N_EnumerateLanguages(HMODULE hModule, LPCWSTR lpType, LPCWSTR lpName, EP_L10N_EnumerateLanguagesProc_t pfnProc, void* data); |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
} |
||||||
|
#endif |
||||||
Loading…
Reference in new issue