13 changed files with 311 additions and 132 deletions
@ -1 +1 @@
@@ -1 +1 @@
|
||||
Subproject commit d09fb3722cda34c082a1bb2645224a85af1d27e8 |
||||
Subproject commit bbf908d31cc0b66f62a205f3e6eaafb2439f47d2 |
||||
@ -0,0 +1,142 @@
@@ -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 @@
@@ -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