Reputation: 1051
I never done something like this, so this is my first attempt. From reading online different information and tutorials, I can confidently say that I got very confused so I went on my own with this.
What I am trying to achieve is have different build configurations with different languages for the GUI.
My application is Win32 built using Visual Studio 2019.
Steps I tried:
However the result is nothing. The menu and dialogs are still in English.
Is there something else I must do to specify which set of resources to use to obtain a different language build ?
Or am I over complicating this and going all wrong...
Any advice/examples are much appreciated.
Upvotes: 1
Views: 840
Reputation: 1051
It seems I will answer my own question because I believe others have hit this problem as well.
The correct and official way to change the language of a Windows GUI applications is:
Using this function, and the exact thing I did in my question; the function will apply the resources in that language at runtime. ( menu, dialogs, everything )
I my case it was as simple as:
SetThreadUILanguage(MAKELANGID(LANG_VIETNAMESE, SUBLANG_VIETNAMESE_VIETNAM));
However in my case I am creating builds per language, so if you want to allow the user to change the language at runtime please see the notes and this article.
The un-official way of doing this is a bit more work, however quite stable and not error prone.
For the community and other developers, I will share the code to rebuild the menu:
// Find our Menu resource based on desired language
HRSRC hRes = FindResourceExW(hInstance, RT_MENU, MAKEINTRESOURCE(IDC_APPLICATION), MAKELANGID(LANG_VIETNAMESE, SUBLANG_VIETNAMESE_VIETNAM));
if (!hRes) {
wchar_t buf[MAX_PATH] = { 0 };
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(wchar_t)), NULL);
MessageBoxW(0, buf, _TEXT(L"FindResourceExW Error"), MB_OK | MB_ICONERROR);
return FALSE;
}
// Load our Menu resource based on desired language
HGLOBAL hGlo = LoadResource(hInstance, hRes);
if (!hGlo) {
wchar_t buf[MAX_PATH] = { 0 };
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(wchar_t)), NULL);
MessageBoxW(0, buf, _TEXT(L"LoadResource Error"), MB_OK | MB_ICONERROR);
return FALSE;
}
// Lock the resource
LPVOID pData = LockResource(hGlo);
if (pData == NULL) {
wchar_t buf[MAX_PATH] = { 0 };
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(wchar_t)), NULL);
MessageBoxW(0, buf, _TEXT(L"LockResource Error"), MB_OK | MB_ICONERROR);
return FALSE;
}
// Load the new Menu into memory
HMENU hMenu = LoadMenuIndirectW((MENUTEMPLATE*)pData);
if (!hMenu) {
wchar_t buf[MAX_PATH] = { 0 };
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(wchar_t)), NULL);
MessageBoxW(0, buf, _TEXT(L"LoadMenuIndirectW Error"), MB_OK | MB_ICONERROR);
return FALSE;
}
// Get our default Menu
HMENU hMenu_old = GetMenu(g_Hwnd);
// Set no Menu
SetMenu(g_Hwnd, NULL);
// Erase default Menu
DestroyMenu(hMenu_old);
// Set our new Menu
SetMenu(g_Hwnd, hMenu);
// Draw our new Menu
DrawMenuBar(g_Hwnd);
NOTE: If you want to use FindResourceEx to search for strings, it's more complicated because of RT_STRING so please see this before you waste your time.
Enjoy!
Upvotes: 1