diff --git a/minipath/src/Config.cpp b/minipath/src/Config.cpp index d63c9c7e9..9472f89ea 100644 --- a/minipath/src/Config.cpp +++ b/minipath/src/Config.cpp @@ -31,8 +31,10 @@ extern "C" WCHAR g_wchIniFile[MAX_PATH]; extern "C" WCHAR g_wchIniFile2[MAX_PATH]; extern "C" WCHAR g_wchNP3IniFile[MAX_PATH]; +#if defined(HAVE_DYN_LOAD_LIBS_MUI_LNGS) extern "C" WCHAR g_tchPrefLngLocName[LOCALE_NAME_MAX_LENGTH + 1]; -extern "C" LANGID g_iPrefLANGID; +#endif +extern "C" LANGID g_iUsedLANGID; //============================================================================= @@ -912,12 +914,14 @@ void LoadFlags() const WCHAR* const Settings_Section2 = L"Settings2"; - if (!IniSectionGetString(Settings_Section2, L"PreferredLanguageLocaleName", L"", - g_tchPrefLngLocName, COUNTOF(g_tchPrefLngLocName))) { +#if defined(HAVE_DYN_LOAD_LIBS_MUI_LNGS) + const WCHAR* const PrefLngLocName = L"PreferredLanguageLocaleName"; + + if (!IniSectionGetString(Settings_Section2, PrefLngLocName, L"", g_tchPrefLngLocName, COUNTOF(g_tchPrefLngLocName))) { // try to fetch Locale Name from Notepad3.ini - IniFileGetString(g_wchNP3IniFile, L"Settings2", L"PreferredLanguageLocaleName", L"", - g_tchPrefLngLocName, COUNTOF(g_tchPrefLngLocName)); + IniFileGetString(g_wchNP3IniFile, Settings_Section2, PrefLngLocName, L"", g_tchPrefLngLocName, COUNTOF(g_tchPrefLngLocName)); } +#endif if (!flagNoReuseWindow) { @@ -1134,7 +1138,7 @@ void LoadSettings() void SaveSettings(BOOL bSaveSettingsNow) { - WCHAR wchTmp[MAX_PATH]; + WCHAR wchTmp[MAX_PATH] = { L'\0' }; if (StrIsEmpty(g_wchIniFile)) { return; @@ -1210,10 +1214,21 @@ void SaveSettings(BOOL bSaveSettingsNow) // cleanup IniSectionDelete(Settings_Section, L"WriteTest", FALSE); - /* - SaveSettingsNow(): query Window Dimensions - */ +#if defined(HAVE_DYN_LOAD_LIBS_MUI_LNGS) + // === prevents "Preferred Language not available" next time === + const WCHAR* const Section2_Section = L"Settings2"; + const WCHAR* const PrefLngLocName = L"PreferredLanguageLocaleName"; + if (!IniSectionGetString(Section2_Section, PrefLngLocName, L"", wchTmp, COUNTOF(wchTmp))) { + // try fetch Locale Name from Notepad3.ini + IniFileGetString(g_wchNP3IniFile, Section2_Section, PrefLngLocName, L"", wchTmp, COUNTOF(wchTmp)); + if (!StrEqual(wchTmp, g_tchPrefLngLocName)) { + IniSectionSetString(Section2_Section, PrefLngLocName, g_tchPrefLngLocName); + } + } +#endif + + // === SaveSettingsNow(): query current Window Dimensions === if (bSaveSettingsNow) { WINDOWPLACEMENT wndpl; ZeroMemory(&wndpl, sizeof(WINDOWPLACEMENT)); diff --git a/minipath/src/Dialogs.c b/minipath/src/Dialogs.c index 2f4e95a45..9cce95637 100644 --- a/minipath/src/Dialogs.c +++ b/minipath/src/Dialogs.c @@ -45,7 +45,7 @@ // extern HWND hwndMain; extern HICON g_hDlgIconSmall; -extern LANGID g_iPrefLANGID; +extern LANGID g_iUsedLANGID; //============================================================================= @@ -2775,7 +2775,7 @@ int ErrorMessage(int iLevel, UINT uIdMsg, ...) HWND focus = GetFocus(); HWND hwnd = focus ? focus : hwndMain; - return MessageBoxEx(hwnd, szText, szTitle, MB_SETFOREGROUND | iIcon, g_iPrefLANGID); + return MessageBoxEx(hwnd, szText, szTitle, MB_SETFOREGROUND | iIcon, g_iUsedLANGID); } @@ -2797,7 +2797,7 @@ DWORD MsgBoxLastError(LPCWSTR lpszMessage, DWORD dwErrID) FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwErrID, - g_iPrefLANGID, + g_iUsedLANGID, (LPTSTR)&lpMsgBuf, 0, NULL); @@ -2815,7 +2815,7 @@ DWORD MsgBoxLastError(LPCWSTR lpszMessage, DWORD dwErrID) HWND focus = GetFocus(); HWND hwnd = focus ? focus : hwndMain; - MessageBoxEx(hwnd, lpDisplayBuf, L"MiniPath - ERROR", MB_ICONERROR, g_iPrefLANGID); + MessageBoxEx(hwnd, lpDisplayBuf, L"MiniPath - ERROR", MB_ICONERROR, g_iUsedLANGID); LocalFree(lpDisplayBuf); } diff --git a/minipath/src/Helpers.c b/minipath/src/Helpers.c index fbffb26c1..b916e5be7 100644 --- a/minipath/src/Helpers.c +++ b/minipath/src/Helpers.c @@ -44,7 +44,7 @@ #pragma warning( disable : 26451 ) // ----------------------------------------------------------------------------- -extern LANGID g_iPrefLANGID; +extern LANGID g_iUsedLANGID; extern WCHAR g_wchIniFile[MAX_PATH]; //============================================================================= @@ -145,7 +145,7 @@ DWORD GetLastErrorToMsgBox(LPWSTR lpszFunction, DWORD dwErrID) FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwErrID, - g_iPrefLANGID, + g_iUsedLANGID, (LPTSTR)&lpMsgBuf, 0, NULL); @@ -156,7 +156,7 @@ DWORD GetLastErrorToMsgBox(LPWSTR lpszFunction, DWORD dwErrID) if (lpDisplayBuf) { wsprintf((LPWSTR)lpDisplayBuf, L"Error: '%s' failed with error id %d:\n%s.\n", lpszFunction, dwErrID, (LPWSTR)lpMsgBuf); - MessageBoxEx(NULL, (LPCWSTR)lpDisplayBuf, L"MiniPath - ERROR", MB_OK | MB_ICONEXCLAMATION, g_iPrefLANGID); + MessageBoxEx(NULL, (LPCWSTR)lpDisplayBuf, L"MiniPath - ERROR", MB_OK | MB_ICONEXCLAMATION, g_iUsedLANGID); } LocalFree(lpMsgBuf); @@ -1720,7 +1720,7 @@ BOOL GetLocaleDefaultUIFont(LANGID lang, LPWSTR lpFaceName, WORD* wSize) BOOL GetThemedDialogFont(LPWSTR lpFaceName, WORD* wSize) { - BOOL bSucceed = GetLocaleDefaultUIFont(g_iPrefLANGID, lpFaceName, wSize); + BOOL bSucceed = GetLocaleDefaultUIFont(g_iUsedLANGID, lpFaceName, wSize); HDC hDC = GetDC(NULL); int const iLogPixelsY = GetDeviceCaps(hDC, LOGPIXELSY); diff --git a/minipath/src/minipath.c b/minipath/src/minipath.c index 14b1cb8e5..f9e71cd51 100644 --- a/minipath/src/minipath.c +++ b/minipath/src/minipath.c @@ -37,17 +37,10 @@ SETTINGS_T Settings; SETTINGS_T Defaults; SETTINGS2_T Settings2; -WCHAR g_wchIniFile[MAX_PATH]; -WCHAR g_wchIniFile2[MAX_PATH]; -WCHAR g_wchNP3IniFile[MAX_PATH]; - //HICON g_hDlgIcon128 = NULL; HICON g_hDlgIconBig = NULL; HICON g_hDlgIconSmall = NULL; -WCHAR g_tchPrefLngLocName[LOCALE_NAME_MAX_LENGTH + 1]; -LANGID g_iPrefLANGID; - HBRUSH g_hbrDarkModeBkgBrush = NULL; HBRUSH g_hbrDarkModeBtnFcBrush = NULL; @@ -120,15 +113,18 @@ WCHAR szDDETopic[256] = L""; BOOL bHasQuickview = FALSE; -UINT16 g_uWinVer; +UINT16 g_uWinVer; HINSTANCE g_hInstance = NULL; HMODULE g_hLngResContainer = NULL; -WCHAR g_tchPrefLngLocName[LOCALE_NAME_MAX_LENGTH + 1]; -LANGID g_iPrefLANGID = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US); -// 'en-US' internal default -static WCHAR* const g_tchAvailableLanguages = L"af-ZA be-BY de-DE el-GR en-GB es-419 es-ES fr-FR hi-IN hu-HU id-ID it-IT ja-JP ko-KR nl-NL pl-PL pt-BR pt-PT ru-RU sk-SK sv-SE tr-TR vi-VN zh-CN zh-TW"; +LANGID g_iUsedLANGID = MUI_BASE_LNG_ID; + +#if defined(HAVE_DYN_LOAD_LIBS_MUI_LNGS) +WCHAR g_tchPrefLngLocName[LOCALE_NAME_MAX_LENGTH + 1] = { L'\0' }; +static WCHAR* const g_tchAvailableLanguages = L"af-ZA be-BY de-DE el-GR en-GB en-US es-419 es-ES fr-FR hi-IN hu-HU id-ID it-IT ja-JP ko-KR nl-NL pl-PL pt-BR pt-PT ru-RU sk-SK sv-SE tr-TR vi-VN zh-CN zh-TW"; +#endif + //============================================================================= @@ -183,17 +179,31 @@ static BOOL __fastcall _LngStrToMultiLngStr(WCHAR* pLngStr, WCHAR* pLngMultiStr, return rtnVal; } +// fallback to buildin MUI_BASE_LNG_ID +inline HMODULE LangResourceInternalFallback() { + g_iUsedLANGID = MUI_BASE_LNG_ID; + SetThreadUILanguage(MUI_BASE_LNG_ID); + InitMUILanguage(MUI_BASE_LNG_ID); + return g_hInstance; +} +#if defined(HAVE_DYN_LOAD_LIBS_MUI_LNGS) //============================================================================= // // _LoadLanguageResources // -// -static HMODULE __fastcall _LoadLanguageResources(const WCHAR* localeName, LANGID const langID) + +inline int LangIDToLocaleName(const LANGID lngID, LPWSTR lpName_out, size_t cchName) { + LCID const lcid = MAKELCID(lngID, SORT_DEFAULT); + return LCIDToLocaleName(lcid, lpName_out, (int)cchName, 0); +} + +static HMODULE _LoadLanguageResources(const WCHAR* localeName, LANGID const langID) { - BOOL bLngAvailable = (StrStrIW(g_tchAvailableLanguages, localeName) != NULL); - if (!bLngAvailable) { - return NULL; + BOOL const bLngAvailable = (StrStrIW(g_tchAvailableLanguages, localeName) != NULL); + + if (!bLngAvailable || (MUI_BASE_LNG_ID == langID)) { + return LangResourceInternalFallback(); } WCHAR tchAvailLngs[512] = { L'\0' }; @@ -201,7 +211,7 @@ static HMODULE __fastcall _LoadLanguageResources(const WCHAR* localeName, LANGID WCHAR tchUserLangMultiStrg[512] = { L'\0' }; if (!_LngStrToMultiLngStr(tchAvailLngs, tchUserLangMultiStrg, 512)) { GetLastErrorToMsgBox(L"Trying to load Language resource!", ERROR_MUI_INVALID_LOCALE_NAME); - return NULL; + return LangResourceInternalFallback(); } // set the appropriate fallback list @@ -209,7 +219,7 @@ static HMODULE __fastcall _LoadLanguageResources(const WCHAR* localeName, LANGID // using SetProcessPreferredUILanguages is recommended for new applications (esp. multi-threaded applications) if (!SetThreadPreferredUILanguages(MUI_LANGUAGE_NAME, tchUserLangMultiStrg, &langCount) || (langCount == 0)) { GetLastErrorToMsgBox(L"Trying to set preferred Language!", ERROR_RESOURCE_LANG_NOT_FOUND); - return NULL; + return LangResourceInternalFallback(); } SetThreadUILanguage(langID); @@ -225,18 +235,22 @@ static HMODULE __fastcall _LoadLanguageResources(const WCHAR* localeName, LANGID // for standard Win32 resource loading this is normally a PE module - use LoadLibraryEx HMODULE const hLangResourceContainer = LoadMUILibraryW(L"lng/mplng.dll", MUI_LANGUAGE_NAME, langID); + if (!hLangResourceContainer) + { + ErrorMessage(2, IDS_WARN_PREF_LNG_NOT_AVAIL, localeName); + // prevent (if saved) Error Dialog on next start + LangIDToLocaleName(MUI_BASE_LNG_ID, g_tchPrefLngLocName, COUNTOF(g_tchPrefLngLocName)); + return LangResourceInternalFallback(); + } // MUI Language for common controls InitMUILanguage(langID); - - //if (!hLangResourceContainer) - //{ - // GetLastErrorToMsgBox(L"LoadMUILibrary", 0); - // return NULL; - //} - + g_iUsedLANGID = langID; return hLangResourceContainer; + + } +#endif //============================================================================= @@ -303,62 +317,59 @@ int WINAPI wWinMain(HINSTANCE hInstance,HINSTANCE hPrevInst,LPWSTR lpCmdLine,int // ---------------------------------------------------- // MultiLingual // +#if defined(HAVE_DYN_LOAD_LIBS_MUI_LNGS) int res = 0; - if (lstrlenW(g_tchPrefLngLocName) > 0) { + LANGID iPrefLANGID = MUI_BASE_LNG_ID; + + if (StrIsNotEmpty(g_tchPrefLngLocName)) { WCHAR wchLngLocalName[LOCALE_NAME_MAX_LENGTH]; res = ResolveLocaleName(g_tchPrefLngLocName, wchLngLocalName, LOCALE_NAME_MAX_LENGTH); if (res > 0) { StringCchCopy(g_tchPrefLngLocName, COUNTOF(g_tchPrefLngLocName), wchLngLocalName); // put back resolved name + // get LANGID + DWORD value = MUI_BASE_LNG_ID; + res = GetLocaleInfoEx(g_tchPrefLngLocName, LOCALE_ILANGUAGE | LOCALE_RETURN_NUMBER, (LPWSTR)&value, sizeof(value) / sizeof(WCHAR)); + if (res > 0) { + iPrefLANGID = (LANGID)value; + } } - // get LANGID - g_iPrefLANGID = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US); - res = GetLocaleInfoEx(g_tchPrefLngLocName, LOCALE_ILANGUAGE | LOCALE_RETURN_NUMBER, (LPWSTR)&g_iPrefLANGID, sizeof(LANGID)); } if (res == 0) { // No preferred language defined or retrievable, try to get User UI Language + //~GetUserDefaultLocaleName(&g_tchPrefLngLocName[0], COUNTOF(g_tchPrefLngLocName)); ULONG numLngs = 0; - DWORD cchLngsBuffer = 0; + ULONG cchLngsBuffer = 0; BOOL hr = GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &numLngs, NULL, &cchLngsBuffer); if (hr) { - WCHAR* pwszLngsBuffer = LocalAlloc(LPTR, (cchLngsBuffer + 2) * sizeof(WCHAR)); + WCHAR* const pwszLngsBuffer = LocalAlloc(LPTR, (cchLngsBuffer + 2) * sizeof(WCHAR)); if (pwszLngsBuffer) { hr = GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &numLngs, pwszLngsBuffer, &cchLngsBuffer); if (hr && (numLngs > 0)) { - // get the first + // get the first one StringCchCopy(g_tchPrefLngLocName, COUNTOF(g_tchPrefLngLocName), pwszLngsBuffer); - g_iPrefLANGID = LANGIDFROMLCID(LocaleNameToLCID(g_tchPrefLngLocName, 0)); + iPrefLANGID = LANGIDFROMLCID(LocaleNameToLCID(g_tchPrefLngLocName, 0)); res = 1; } LocalFree(pwszLngsBuffer); } } if (res == 0) { // last try - g_iPrefLANGID = GetUserDefaultUILanguage(); - LCID const lcid = MAKELCID(g_iPrefLANGID, SORT_DEFAULT); - res = LCIDToLocaleName(lcid, g_tchPrefLngLocName, COUNTOF(g_tchPrefLngLocName), 0); + iPrefLANGID = GetUserDefaultUILanguage(); + res = LangIDToLocaleName(iPrefLANGID, g_tchPrefLngLocName, COUNTOF(g_tchPrefLngLocName)); } } -#ifdef HAVE_DYN_LOAD_LIBS_MUI_LNGS - bool bPrefLngNotAvail = false; - g_hLngResContainer = _LoadLanguageResources(g_tchPrefLngLocName, g_iPrefLANGID); - if (!g_hLngResContainer) { // fallback en-US (1033) - g_hLngResContainer = g_hInstance; - g_iPrefLANGID = MUI_BASE_LNG_ID; - bPrefLngNotAvail = true; - } + g_hLngResContainer = _LoadLanguageResources(g_tchPrefLngLocName, iPrefLANGID); + #else - g_hLngResContainer = g_hInstance; - g_iPrefLANGID = MUI_BASE_LNG_ID; + + g_hLngResContainer = LangResourceInternalFallback(); + #endif - SetThreadUILanguage(g_iPrefLANGID); - InitMUILanguage(g_iPrefLANGID); - // ---------------------------------------------------- - if (!InitApplication(hInstance)) { return FALSE; } @@ -370,12 +381,6 @@ int WINAPI wWinMain(HINSTANCE hInstance,HINSTANCE hPrevInst,LPWSTR lpCmdLine,int hAcc = LoadAccelerators(hInstance,MAKEINTRESOURCE(IDR_MAINWND)); -#ifdef HAVE_DYN_LOAD_LIBS_MUI_LNGS - if (bPrefLngNotAvail) { - ErrorMessage(2, IDS_WARN_PREF_LNG_NOT_AVAIL, g_tchPrefLngLocName); - } -#endif - while (GetMessage(&msg,NULL,0,0)) { if (!TranslateAccelerator(hwnd,hAcc,&msg)) { TranslateMessage(&msg); @@ -383,6 +388,9 @@ int WINAPI wWinMain(HINSTANCE hInstance,HINSTANCE hPrevInst,LPWSTR lpCmdLine,int } } + if (g_hLngResContainer != g_hInstance) { + FreeMUILibrary(g_hLngResContainer); + } OleUninitialize(); return(int)(msg.wParam); diff --git a/minipath/src/resource.h b/minipath/src/resource.h index 3d819bba7..f234805f8 100644 --- a/minipath/src/resource.h +++ b/minipath/src/resource.h @@ -17,13 +17,9 @@ // 1. Comment-Out the following line #define HAVE_DYN_LOAD_LIBS_MUI_LNGS 1 // ----------------------------------------------------- -#ifdef HAVE_DYN_LOAD_LIBS_MUI_LNGS -// currently only en-US allowed for Base-Lng in MUI env +// 2. Uncomment one of the following lines according to +// the desired Language (use en-US if undefined) #define MUI_BASE_LNG_EN_US 1 -#else -// 2. Uncomment one of the following lines -// according to the desired Language -//#define MUI_BASE_LNG_EN_US 1 //#define MUI_BASE_LNG_AF_ZA 1 //#define MUI_BASE_LNG_BE_BY 1 //#define MUI_BASE_LNG_DE_DE 1 @@ -50,8 +46,6 @@ //#define MUI_BASE_LNG_ZH_CN 1 //#define MUI_BASE_LNG_ZH_TW 1 -#endif - // ----------------------------------------------------- // 3. In case of a new language: // Extent Minipath.rc file accordingly diff --git a/src/Config/Config.cpp b/src/Config/Config.cpp index 20cee1a89..c5d2c75f9 100644 --- a/src/Config/Config.cpp +++ b/src/Config/Config.cpp @@ -1087,7 +1087,7 @@ void LoadSettings() // -------------------------------------------------------------------------- #if defined(HAVE_DYN_LOAD_LIBS_MUI_LNGS) - LANGID lngID = 0; + LANGID lngID = MUI_BASE_LNG_ID; Defaults2.PreferredLanguageLocaleName[0] = L'\0'; GetUserPreferredLanguage(Defaults2.PreferredLanguageLocaleName, COUNTOF(Defaults2.PreferredLanguageLocaleName), &lngID); @@ -2008,6 +2008,7 @@ static bool _SaveSettings(bool bForceSaveSettings) // --- remove deprecated --- IniSectionDelete(IniSecSettings2, L"MarkOccurrencesMaxCount", false); + // -------------------------------------------------------------------------- const WCHAR* const IniSecWindow = Constants.Window_Section; // -------------------------------------------------------------------------- diff --git a/src/Dialogs.c b/src/Dialogs.c index 813c19164..f2fb0a878 100644 --- a/src/Dialogs.c +++ b/src/Dialogs.c @@ -145,7 +145,7 @@ int MessageBoxLng(UINT uType, UINT uidMsg, ...) HWND const hwnd = focus ? focus : Globals.hwndMain; s_hCBThook = SetWindowsHookEx(WH_CBT, &SetPosRelatedToParent_Hook, 0, GetCurrentThreadId()); - return MessageBoxEx(hwnd, szText, _W(SAPPNAME), uType, Globals.iPrefLANGID); + return MessageBoxEx(hwnd, szText, _W(SAPPNAME), uType, Globals.iCurrentLANGID); } @@ -167,7 +167,7 @@ DWORD MsgBoxLastError(LPCWSTR lpszMessage, DWORD dwErrID) FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwErrID, - Globals.iPrefLANGID, + Globals.iCurrentLANGID, (LPWSTR)&lpMsgBuf, 0, NULL); @@ -186,7 +186,7 @@ DWORD MsgBoxLastError(LPCWSTR lpszMessage, DWORD dwErrID) s_hCBThook = SetWindowsHookEx(WH_CBT, &SetPosRelatedToParent_Hook, 0, GetCurrentThreadId()); UINT uType = MB_ICONERROR | MB_TOPMOST | (Settings.DialogsLayoutRTL ? MB_RTLREADING : 0); - MessageBoxEx(hwnd, lpDisplayBuf, _W(SAPPNAME) L" - ERROR", uType, Globals.iPrefLANGID); + MessageBoxEx(hwnd, lpDisplayBuf, _W(SAPPNAME) L" - ERROR", uType, Globals.iCurrentLANGID); FreeMem(lpDisplayBuf); } @@ -455,7 +455,7 @@ LONG InfoBoxLng(UINT uType, LPCWSTR lpstrSetting, UINT uidMsg, ...) FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, Globals.dwLastError, - Globals.iPrefLANGID, + Globals.iCurrentLANGID, (LPWSTR)&lpMsgBuf, 0, NULL); @@ -722,7 +722,7 @@ void DisplayCmdLineHelp(HWND hwnd) mbp.lpszIcon = MAKEINTRESOURCE(IDR_MAINWND); mbp.dwContextHelpId = 0; mbp.lpfnMsgBoxCallback = NULL; - mbp.dwLanguageId = Globals.iPrefLANGID; + mbp.dwLanguageId = Globals.iCurrentLANGID; hhkMsgBox = SetWindowsHookEx(WH_CBT, &_MsgBoxProc, 0, GetCurrentThreadId()); @@ -4715,27 +4715,23 @@ void DialogGrepWin(HWND hwnd, LPCWSTR searchPattern) IniSectionSetString(globalSection, grepWinIniSettings[i].key, value); } - #if defined(HAVE_DYN_LOAD_LIBS_MUI_LNGS) - // get grepWin language - int lngIdx = -1; - for (int i = 0; i < grepWinLang_CountOf(); ++i) { - if (grepWinLangResName[i].lngid == Globals.iPrefLANGID) { - lngIdx = i; - break; - } + // get grepWin language + int lngIdx = -1; + for (int i = 0; i < grepWinLang_CountOf(); ++i) { + if (grepWinLangResName[i].lngid == Globals.iCurrentLANGID) { + lngIdx = i; + break; } - if (lngIdx >= 0) { - IniSectionGetString(globalSection, L"languagefile", grepWinLangResName[lngIdx].filename, tchTemp, COUNTOF(tchTemp)); - IniSectionSetString(globalSection, L"languagefile", tchTemp); - } else { - IniSectionGetString(globalSection, L"languagefile", L"", tchTemp, COUNTOF(tchTemp)); - if (StrIsEmpty(tchTemp)) { - IniSectionDelete(globalSection, L"languagefile", false); - } + } + if (lngIdx >= 0) { + IniSectionGetString(globalSection, L"languagefile", grepWinLangResName[lngIdx].filename, tchTemp, COUNTOF(tchTemp)); + IniSectionSetString(globalSection, L"languagefile", tchTemp); + } else { + IniSectionGetString(globalSection, L"languagefile", L"", tchTemp, COUNTOF(tchTemp)); + if (StrIsEmpty(tchTemp)) { + IniSectionDelete(globalSection, L"languagefile", false); } - #else - IniSectionDelete(globalSection, L"languagefile", false); - #endif + } bool const bDarkMode = UseDarkMode(); // <- override usr ~ IniSectionGetBool(globalSection, L"darkmode", UseDarkMode()); IniSectionSetBool(globalSection, L"darkmode", bDarkMode); @@ -5718,7 +5714,7 @@ bool GetLocaleDefaultUIFont(LANGID lang, LPWSTR lpFaceName, WORD* wSize) bool GetThemedDialogFont(LPWSTR lpFaceName, WORD* wSize) { - bool bSucceed = GetLocaleDefaultUIFont(Globals.iPrefLANGID, lpFaceName, wSize); + bool bSucceed = GetLocaleDefaultUIFont(Globals.iCurrentLANGID, lpFaceName, wSize); if (!bSucceed) { if (IsAppThemed()) { diff --git a/src/MuiLanguage.c b/src/MuiLanguage.c index 840bca89a..47388c6c1 100644 --- a/src/MuiLanguage.c +++ b/src/MuiLanguage.c @@ -15,6 +15,7 @@ #include "Helpers.h" +#include #include #include #include @@ -27,12 +28,108 @@ //============================================================================= + +grepWinLng_t grepWinLangResName[] = { + { MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), L".\\lng\\gwLng\\English (United States) [en-US].lang" }, + { MAKELANGID(LANG_AFRIKAANS, SUBLANG_AFRIKAANS_SOUTH_AFRICA), L".\\lng\\gwLng\\Afrikaans (Suid-Afrika) [af-ZA].lang" }, + { MAKELANGID(LANG_BELARUSIAN, SUBLANG_BELARUSIAN_BELARUS), L".\\lng\\gwLng\\Беларуская (Беларусь) [be-BY].lang" }, + { MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), L".\\lng\\gwLng\\Deutsch (Deutschland) [de-DE].lang" }, + { MAKELANGID(LANG_GREEK, SUBLANG_GREEK_GREECE), L".\\lng\\gwLng\\Ελληνικά (Ελλάδα) [el-GR].lang" }, + { MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK), L".\\lng\\gwLng\\English (United Kingdom) [en-GB].lang" }, + { MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_LATIN_AMERICA), L".\\lng\\gwLng\\Español (América Latina) [es-419].lang" }, + { MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), L".\\lng\\gwLng\\Español (España) [es-ES].lang" }, + { MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH), L".\\lng\\gwLng\\Français (France) [fr-FR].lang" }, + { MAKELANGID(LANG_HINDI, SUBLANG_HINDI_INDIA), L".\\lng\\gwLng\\हिन्दी (भारत) [hi-IN].lang" }, + { MAKELANGID(LANG_HUNGARIAN, SUBLANG_HUNGARIAN_HUNGARY), L".\\lng\\gwLng\\Magyar (Magyarország) [hu-HU].lang" }, + { MAKELANGID(LANG_INDONESIAN, SUBLANG_INDONESIAN_INDONESIA), L".\\lng\\gwLng\\Bahasa Indonesia (Indonesia) [id-ID].lang" }, + { MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), L".\\lng\\gwLng\\Italiano (Italia) [it-IT].lang" }, + { MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), L".\\lng\\gwLng\\日本語 (日本)[ja-JP].lang" }, + { MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN), L".\\lng\\gwLng\\한국어 (대한민국) [ko-KR].lang" }, + { MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), L".\\lng\\gwLng\\Nederlands (Nederland) [nl-NL].lang" }, + { MAKELANGID(LANG_POLISH, SUBLANG_POLISH_POLAND), L".\\lng\\gwLng\\Polski (Polska) [pl-PL].lang" }, + { MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), L".\\lng\\gwLng\\Português Brasileiro (Brasil) [pt-BR].lang" }, + { MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE), L".\\lng\\gwLng\\Português (Portugal) [pt-PT].lang" }, + { MAKELANGID(LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA), L".\\lng\\gwLng\\Русский (Pоссия) [ru-RU].lang" }, + { MAKELANGID(LANG_SLOVAK, SUBLANG_SLOVAK_SLOVAKIA), L".\\lng\\gwLng\\Slovenčina (Slovensko) [sk-SK].lang" }, + { MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), L".\\lng\\gwLng\\Svenska (Sverige) [sv-SE].lang" }, + { MAKELANGID(LANG_TURKISH, SUBLANG_TURKISH_TURKEY), L".\\lng\\gwLng\\Türkçe (Türkiye) [tr-TR].lang" }, + { MAKELANGID(LANG_VIETNAMESE, SUBLANG_VIETNAMESE_VIETNAM), L".\\lng\\gwLng\\Tiếng Việt (Việt Nam) [vi-VN].lang" }, + { MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), L".\\lng\\gwLng\\简体中文 (中国) [zh-CN].lang" }, + { MAKELANGID(LANG_CHINESE_TRADITIONAL, SUBLANG_CHINESE_TRADITIONAL), L".\\lng\\gwLng\\繁體中文 (台灣) [zh-TW].lang" } +}; + +int grepWinLang_CountOf() { + return COUNTOF(grepWinLangResName); +}; + + +//============================================================================= +// +// SetMuiLocaleAll +// +static void SetMuiLocaleAll(LPCWSTR pszLocaleStr) { + if (pszLocaleStr) { + const WCHAR *const pszLocaleCur = _wsetlocale(LC_ALL, pszLocaleStr); + if (pszLocaleCur && (StringCchCompareXI(pszLocaleStr, pszLocaleCur) != 0)) { + //const _locale_t pCurLocale = _get_current_locale(); + _wsetlocale(LC_ALL, L""); // system standard +#ifdef _DEBUG + WCHAR msg[128]; + StringCchPrintf(msg, COUNTOF(msg), L"Can't set desired locale '%s', using '%s' instead!", + pszLocaleStr, pszLocaleCur ? pszLocaleCur : L""); + MsgBoxLastError(msg, ERROR_MUI_INVALID_LOCALE_NAME); +#endif + } + } +} + + +//============================================================================= +// +// SetCurrentLanguage +// +void SetCurrentLanguage(LANGID iLanguageID) { + + int const langIdx = GetMUILanguageIndexByLangID(iLanguageID); + + assert((langIdx >= 0) && "Faild to get LangID!"); + + if (iLanguageID != Globals.iCurrentLANGID) { + + Globals.iCurrentLANGID = iLanguageID; // == MUI_LanguageDLLs[langIdx].LangId + + const WCHAR *const szLocaleName = MUI_LanguageDLLs[langIdx].szLocaleName; + + SetThreadUILanguage(iLanguageID); + InitMUILanguage(iLanguageID); // MUI Language for common controls + SetMuiLocaleAll(szLocaleName); + + const WCHAR *const SettingName = L"PreferredLanguageLocaleName"; + + if (StringCchCompareXIW(Settings2.PreferredLanguageLocaleName, szLocaleName) != 0) { + StringCchCopyW(Settings2.PreferredLanguageLocaleName, COUNTOF(Settings2.PreferredLanguageLocaleName), szLocaleName); + + if (Globals.bCanSaveIniFile) { + if (StringCchCompareXIW(Settings2.PreferredLanguageLocaleName, Defaults2.PreferredLanguageLocaleName) != 0) { + IniFileSetString(Paths.IniFile, Constants.Settings2_Section, SettingName, Settings2.PreferredLanguageLocaleName); + } else { + IniFileDelete(Paths.IniFile, Constants.Settings2_Section, SettingName, false); + } + } + } + } +} + + +//============================================================================= +//============================================================================= + + #if defined(HAVE_DYN_LOAD_LIBS_MUI_LNGS) extern prefix_t g_mxSBPrefix[STATUS_SECTOR_COUNT]; extern prefix_t g_mxSBPostfix[STATUS_SECTOR_COUNT]; -//============================================================================= MUILANGUAGE MUI_LanguageDLLs[] = { { IDS_MUI_LANG_EN_US, L"en-US", L"English (United States)\t\t\t[%s]", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), true, false }, // internal - must be 1st @@ -71,46 +168,6 @@ int MuiLanguages_CountOf() }; - -grepWinLng_t grepWinLangResName[] = { - { MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), L".\\lng\\gwLng\\English (United States) [en-US].lang"}, - { MAKELANGID(LANG_AFRIKAANS, SUBLANG_AFRIKAANS_SOUTH_AFRICA), L".\\lng\\gwLng\\Afrikaans (Suid-Afrika) [af-ZA].lang"}, - { MAKELANGID(LANG_BELARUSIAN, SUBLANG_BELARUSIAN_BELARUS), L".\\lng\\gwLng\\Беларуская (Беларусь) [be-BY].lang"}, - { MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), L".\\lng\\gwLng\\Deutsch (Deutschland) [de-DE].lang"}, - { MAKELANGID(LANG_GREEK, SUBLANG_GREEK_GREECE), L".\\lng\\gwLng\\Ελληνικά (Ελλάδα) [el-GR].lang"}, - { MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK), L".\\lng\\gwLng\\English (United Kingdom) [en-GB].lang"}, - { MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_LATIN_AMERICA), L".\\lng\\gwLng\\Español (América Latina) [es-419].lang"}, - { MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), L".\\lng\\gwLng\\Español (España) [es-ES].lang"}, - { MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH), L".\\lng\\gwLng\\Français (France) [fr-FR].lang"}, - { MAKELANGID(LANG_HINDI, SUBLANG_HINDI_INDIA), L".\\lng\\gwLng\\हिन्दी (भारत) [hi-IN].lang"}, - { MAKELANGID(LANG_HUNGARIAN, SUBLANG_HUNGARIAN_HUNGARY), L".\\lng\\gwLng\\Magyar (Magyarország) [hu-HU].lang"}, - { MAKELANGID(LANG_INDONESIAN, SUBLANG_INDONESIAN_INDONESIA), L".\\lng\\gwLng\\Bahasa Indonesia (Indonesia) [id-ID].lang"}, - { MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), L".\\lng\\gwLng\\Italiano (Italia) [it-IT].lang"}, - { MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), L".\\lng\\gwLng\\日本語 (日本)[ja-JP].lang"}, - { MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN), L".\\lng\\gwLng\\한국어 (대한민국) [ko-KR].lang"}, - { MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), L".\\lng\\gwLng\\Nederlands (Nederland) [nl-NL].lang"}, - { MAKELANGID(LANG_POLISH, SUBLANG_POLISH_POLAND), L".\\lng\\gwLng\\Polski (Polska) [pl-PL].lang"}, - { MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), L".\\lng\\gwLng\\Português Brasileiro (Brasil) [pt-BR].lang"}, - { MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE), L".\\lng\\gwLng\\Português (Portugal) [pt-PT].lang"}, - { MAKELANGID(LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA), L".\\lng\\gwLng\\Русский (Pоссия) [ru-RU].lang"}, - { MAKELANGID(LANG_SLOVAK, SUBLANG_SLOVAK_SLOVAKIA), L".\\lng\\gwLng\\Slovenčina (Slovensko) [sk-SK].lang"}, - { MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), L".\\lng\\gwLng\\Svenska (Sverige) [sv-SE].lang"}, - { MAKELANGID(LANG_TURKISH, SUBLANG_TURKISH_TURKEY), L".\\lng\\gwLng\\Türkçe (Türkiye) [tr-TR].lang"}, - { MAKELANGID(LANG_VIETNAMESE, SUBLANG_VIETNAMESE_VIETNAM), L".\\lng\\gwLng\\Tiếng Việt (Việt Nam) [vi-VN].lang"}, - { MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), L".\\lng\\gwLng\\简体中文 (中国) [zh-CN].lang"}, - { MAKELANGID(LANG_CHINESE_TRADITIONAL, SUBLANG_CHINESE_TRADITIONAL), L".\\lng\\gwLng\\繁體中文 (台灣) [zh-TW].lang"} -}; - -int grepWinLang_CountOf() -{ - return COUNTOF(grepWinLangResName); -}; - - -// ---------------------------------------------------------------------------- - - - //============================================================================= // // GetMUILanguageIndexByLangID @@ -138,15 +195,19 @@ static int _CheckAvailableLanguageDLLs() int count = 1; for (int lng = 1; lng < MuiLanguages_CountOf(); ++lng) { + if (IsValidLocaleName(MUI_LanguageDLLs[lng].szLocaleName)) { + //WCHAR wchLngLocalName[LOCALE_NAME_MAX_LENGTH]; //if (ResolveLocaleName(MUI_LanguageDLLs[i].szLocaleName, wchLngLocalName, LOCALE_NAME_MAX_LENGTH)) { // StringCchCopy(MUI_LanguageDLLs[i].szLocaleName, COUNTOF(MUI_LanguageDLLs[i].szLocaleName), wchLngLocalName); // put back resolved name //} // get LANGID - GetLocaleInfoEx(MUI_LanguageDLLs[lng].szLocaleName, LOCALE_ILANGUAGE | LOCALE_RETURN_NUMBER, - (LPWSTR)&(MUI_LanguageDLLs[lng].LangId), sizeof(LANGID)); + DWORD value = MUI_BASE_LNG_ID; + if (GetLocaleInfoEx(MUI_LanguageDLLs[lng].szLocaleName, LOCALE_ILANGUAGE | LOCALE_RETURN_NUMBER, (LPWSTR)&value, sizeof(value) / sizeof(WCHAR)) > 0) { + MUI_LanguageDLLs[lng].LangId = (LANGID)value; + } // check for DLL StringCchPrintf(wchRelPath, COUNTOF(wchRelPath), L"lng/%s/np3lng.dll.mui", MUI_LanguageDLLs[lng].szLocaleName); @@ -199,7 +260,6 @@ static bool _LngStrToMultiLngStr(WCHAR* pLngStr, WCHAR* pLngMultiStr, size_t ln } - //============================================================================= // // GetUserPreferredLanguage @@ -214,7 +274,7 @@ bool GetUserPreferredLanguage(LPWSTR pszPrefLocaleName, int cchBuffer, LANGID* p res = ResolveLocaleName(pszPrefLocaleName, wchLngLocalName, COUNTOF(wchLngLocalName)); if (res > 0) { // get LANGID - DWORD value; + DWORD value = MUI_BASE_LNG_ID; res = GetLocaleInfoEx(wchLngLocalName, LOCALE_ILANGUAGE | LOCALE_RETURN_NUMBER, (LPWSTR)&value, sizeof(value) / sizeof(WCHAR)); if (res > 0) { lngID = (LANGID)value; @@ -234,16 +294,16 @@ bool GetUserPreferredLanguage(LPWSTR pszPrefLocaleName, int cchBuffer, LANGID* p if (hr && (numLngs > 0)) { // get the first StringCchCopy(wchLngLocalName, COUNTOF(wchLngLocalName), pwszLngsBuffer); + // TODO: deprecated lngID = LANGIDFROMLCID(LocaleNameToLCID(wchLngLocalName, 0)); res = 1; } FreeMem(pwszLngsBuffer); } } - if (res == 0) { // last try + if (res == 0) { // last try (deprecated) lngID = GetUserDefaultUILanguage(); - LCID const lcid = MAKELCID(lngID, SORT_DEFAULT); - res = LCIDToLocaleName(lcid, wchLngLocalName, COUNTOF(wchLngLocalName), 0); + res = LangIDToLocaleName(lngID, wchLngLocalName, COUNTOF(wchLngLocalName)); } } if (res != 0) { @@ -255,87 +315,34 @@ bool GetUserPreferredLanguage(LPWSTR pszPrefLocaleName, int cchBuffer, LANGID* p } -//============================================================================= -// -// SetPreferredLanguage -// -static void SetMuiLocaleAll(LPCWSTR pszLocaleStr) -{ - if (pszLocaleStr) { - const WCHAR* const pszLocaleCur = _wsetlocale(LC_ALL, pszLocaleStr); - if (pszLocaleCur && (StringCchCompareXI(pszLocaleStr, pszLocaleCur) != 0)) { - //const _locale_t pCurLocale = _get_current_locale(); - _wsetlocale(LC_ALL, L""); // system standard -#ifdef _DEBUG - WCHAR msg[128]; - StringCchPrintf(msg, COUNTOF(msg), L"Can't set desired locale '%s', using '%s' instead!", - pszLocaleStr, pszLocaleCur ? pszLocaleCur : L""); - MsgBoxLastError(msg, ERROR_MUI_INVALID_LOCALE_NAME); -#endif - } - - } -} - -void SetPreferredLanguage(LANGID iPreferredLanguageID) -{ - int const langIdx = GetMUILanguageIndexByLangID(iPreferredLanguageID); - if (langIdx < 0) { - Globals.iPrefLANGID = MUI_BASE_LNG_ID; // internal - int const idx = GetMUILanguageIndexByLangID(MUI_BASE_LNG_ID); - if (idx >= 0) { - SetMuiLocaleAll(MUI_LanguageDLLs[idx].szLocaleName); - } - return; - } - - if (iPreferredLanguageID != Globals.iPrefLANGID) { - - Globals.iPrefLANGID = iPreferredLanguageID; // == MUI_LanguageDLLs[langIdx].LangId - - const WCHAR* const szLocaleName = MUI_LanguageDLLs[langIdx].szLocaleName; - - SetMuiLocaleAll(szLocaleName); - - if (StringCchCompareXIW(Settings2.PreferredLanguageLocaleName, szLocaleName) != 0) { - StringCchCopyW(Settings2.PreferredLanguageLocaleName, COUNTOF(Settings2.PreferredLanguageLocaleName), szLocaleName); - - if (Globals.bCanSaveIniFile) { - if (StringCchCompareXIW(Settings2.PreferredLanguageLocaleName, Defaults2.PreferredLanguageLocaleName) != 0) { - IniFileSetString(Paths.IniFile, Constants.Settings2_Section, L"PreferredLanguageLocaleName", Settings2.PreferredLanguageLocaleName); - } else { - IniFileDelete(Paths.IniFile, Constants.Settings2_Section, L"PreferredLanguageLocaleName", false); - } - } - } - } -} - - //============================================================================= // // LoadLanguageResources // // -LANGID LoadLanguageResources() +LANGID LoadLanguageResources(LPCWSTR localeName) { + FreeLanguageResources(); // reset + + int const iInternalLngIndex = max_i(0, GetMUILanguageIndexByLangID(MUI_BASE_LNG_ID)); + // 1st check language resources Globals.iAvailLngCount = _CheckAvailableLanguageDLLs(); // set the appropriate fallback list - int iPrefLngIndex = -1; + int iLngIndex = -1; WCHAR tchAvailLngs[2 * (LOCALE_NAME_MAX_LENGTH + 1)] = { L'\0' }; for (int lng = 0; lng < MuiLanguages_CountOf(); ++lng) { - if (StringCchCompareXIW(MUI_LanguageDLLs[lng].szLocaleName, Settings2.PreferredLanguageLocaleName) == 0) { + if (StringCchCompareXIW(MUI_LanguageDLLs[lng].szLocaleName, localeName) == 0) { if (MUI_LanguageDLLs[lng].bHasDLL && (lng > 0)) { StringCchCatW(tchAvailLngs, COUNTOF(tchAvailLngs), MUI_LanguageDLLs[lng].szLocaleName); StringCchCatW(tchAvailLngs, COUNTOF(tchAvailLngs), L";"); } - iPrefLngIndex = lng; + iLngIndex = lng; break; } } - StringCchCatW(tchAvailLngs, COUNTOF(tchAvailLngs), MUI_LanguageDLLs[0].szLocaleName); // en-US fallback + StringCchCatW(tchAvailLngs, COUNTOF(tchAvailLngs), MUI_LanguageDLLs[iInternalLngIndex].szLocaleName); // en-US fallback // NOTES: // an application developer that makes the assumption the fallback list provided by the @@ -363,36 +370,41 @@ LANGID LoadLanguageResources() // obtains access to the proper resource container // for standard Win32 resource loading this is normally a PE module - use LoadLibraryEx - HINSTANCE _hLangResourceContainer = NULL; - Globals.bPrefLngNotAvail = (iPrefLngIndex < 0); - int iUsedLngIdx = (iPrefLngIndex >= 0) ? iPrefLngIndex : 0; + Globals.hLngResContainer = NULL; //(!) - if ((iPrefLngIndex >= 0) && MUI_LanguageDLLs[iPrefLngIndex].bHasDLL) { - _hLangResourceContainer = (iPrefLngIndex == 0) ? Globals.hInstance : - LoadMUILibrary(L"lng/np3lng.dll", MUI_LANGUAGE_NAME | MUI_LANGUAGE_EXACT, MUI_LanguageDLLs[iPrefLngIndex].LangId); - if (_hLangResourceContainer) { - MUI_LanguageDLLs[0].bIsActive = false; - MUI_LanguageDLLs[iPrefLngIndex].bIsActive = true; - iUsedLngIdx = iPrefLngIndex; + if (iLngIndex == iInternalLngIndex) { + + Globals.hLngResContainer = Globals.hInstance; + MUI_LanguageDLLs[iInternalLngIndex].bIsActive = true; + + } else if ((iLngIndex >= 0) && MUI_LanguageDLLs[iLngIndex].bHasDLL) { + + Globals.hLngResContainer = LoadMUILibrary(L"lng/np3lng.dll", + MUI_LANGUAGE_NAME | MUI_LANGUAGE_EXACT, + MUI_LanguageDLLs[iLngIndex].LangId); + if (Globals.hLngResContainer) { + MUI_LanguageDLLs[iLngIndex].bIsActive = true; + MUI_LanguageDLLs[iInternalLngIndex].bIsActive = false; + } else { + //DbgMsgBoxLastError(L"LoadMUILibrary", 0); + iLngIndex = -1; } } - if (!_hLangResourceContainer) { - // fallback to ENGLISH_US - //MsgBoxLastError(L"LoadMUILibrary", 0); - Globals.bPrefLngNotAvail = (iPrefLngIndex != 0); - _hLangResourceContainer = Globals.hInstance; - MUI_LanguageDLLs[0].bIsActive = true; - iUsedLngIdx = 0; + if (!Globals.hLngResContainer || (iLngIndex < 0)) { + // fallback to MUI_BASE_LNG_ID + Globals.hLngResContainer = Globals.hInstance; + MUI_LanguageDLLs[iInternalLngIndex].bIsActive = true; + iLngIndex = iInternalLngIndex; + + const WCHAR *const suprMsg = L"MsgPrefLanguageNotAvailable"; + InfoBoxLng(MB_ICONWARNING, suprMsg, IDS_WARN_PREF_LNG_NOT_AVAIL, localeName); + int const noMsg = IniFileGetInt(Paths.IniFile, Constants.SectionSuppressedMessages, suprMsg, 0); + if (noMsg && Globals.bCanSaveIniFile) { + IniFileSetString(Paths.IniFile, Constants.Settings2_Section, L"PreferredLanguageLocaleName", MUI_LanguageDLLs[iInternalLngIndex].szLocaleName); + } } - // MUI Language for common controls - LANGID const langID = MUI_LanguageDLLs[iUsedLngIdx].LangId; - SetThreadUILanguage(langID); - InitMUILanguage(langID); - - Globals.hLngResContainer = _hLangResourceContainer; - // === update language dependent items === for (cpi_enc_t enc = 0; enc < Encoding_CountOf(); ++enc) { @@ -414,7 +426,7 @@ LANGID LoadLanguageResources() IniFileGetString(Paths.IniFile, StatusBar_Section, L"SectionPostfixes", tchDefaultStrg, tchStatusBar, COUNTOF(tchStatusBar)); ReadStrgsFromCSV(tchStatusBar, g_mxSBPostfix, STATUS_SECTOR_COUNT, MICRO_BUFFER, L"_POFX_"); - return MUI_LanguageDLLs[iUsedLngIdx].LangId; + return MUI_LanguageDLLs[iLngIndex].LangId; } @@ -425,14 +437,13 @@ LANGID LoadLanguageResources() // void FreeLanguageResources() { CloseNonModalDialogs(); + int const iInternalLngIndex = GetMUILanguageIndexByLangID(MUI_BASE_LNG_ID); if (Globals.hLngResContainer != Globals.hInstance) { - HINSTANCE const _hLngResContainer = Globals.hLngResContainer; + FreeMUILibrary(Globals.hLngResContainer); Globals.hLngResContainer = Globals.hInstance; - MUI_LanguageDLLs[0].bIsActive = true; - FreeMUILibrary(_hLngResContainer); } - for (int i = 1; i < MuiLanguages_CountOf(); ++i) { - MUI_LanguageDLLs[i].bIsActive = false; + for (int i = 0; i < MuiLanguages_CountOf(); ++i) { + MUI_LanguageDLLs[i].bIsActive = (iInternalLngIndex == i); } } @@ -494,14 +505,14 @@ void DynamicLanguageMenuCmd(int cmd) { return; } if (!MUI_LanguageDLLs[iLngIdx].bIsActive) { + DestroyMenu(Globals.hMainMenu); // desired language LANGID const desiredLngID = MUI_LanguageDLLs[iLngIdx].LangId; - SetPreferredLanguage(desiredLngID); - - FreeLanguageResources(); - LoadLanguageResources(); + LPCWSTR desiredLocaleName = MUI_LanguageDLLs[iLngIdx].szLocaleName; + LoadLanguageResources(desiredLocaleName); + SetCurrentLanguage(desiredLngID); Globals.hMainMenu = LoadMenu(Globals.hLngResContainer, MAKEINTRESOURCE(IDR_MUI_MAINMENU)); if (!Globals.hMainMenu) { diff --git a/src/MuiLanguage.h b/src/MuiLanguage.h index a54312d43..611b5445d 100644 --- a/src/MuiLanguage.h +++ b/src/MuiLanguage.h @@ -13,19 +13,63 @@ * * * * *******************************************************************************/ + +// TODO: Get rid of these deprecated LCID Stuff (see "winnt.h"): +// +// ** DEPRECATED ** DEPRECATED ** DEPRECATED ** DEPRECATED ** DEPRECATED ** +// +// DEPRECATED: The LCID/LANGID/SORTID concept is deprecated, please use +// Locale Names instead, eg: en-US instead of an LCID like 0x0409. +// See the documentation for GetLocaleInfoEx. +// +// A locale ID is a 32 bit value which is the combination of a +// language ID, a sort ID, and a reserved area. The bits are +// allocated as follows: +// +// +-------------+---------+-------------------------+ +// | Reserved | Sort ID | Language ID | +// +-------------+---------+-------------------------+ +// 31 20 19 16 15 0 bit +// +// WARNING: This pattern isn't always followed (es-ES_tradnl vs es-ES for example) +// +// WARNING: Some locales do not have assigned LCIDs. Please use +// Locale Names, such as "tlh-Piqd". +// +// It is recommended that applications test for locale names rather than +// attempting to rely on LCID or LANGID behavior. +// +// DEPRECATED: Locale ID creation/extraction macros: +// +// MAKELCID - construct the locale id from a language id and a sort id. +// MAKESORTLCID - construct the locale id from a language id, sort id, and sort version. +// LANGIDFROMLCID - extract the language id from a locale id. +// SORTIDFROMLCID - extract the sort id from a locale id. +// SORTVERSIONFROMLCID - extract the sort version from a locale id. +// +// Note that the LANG, SUBLANG construction is not always consistent. +// The named locale APIs (eg GetLocaleInfoEx) are recommended. +// +// DEPRECATED: LCIDs do not exist for all locales. +// +// ** DEPRECATED ** DEPRECATED ** DEPRECATED ** DEPRECATED ** DEPRECATED ** +// + #pragma once #ifndef _NP3_MUI_LANGUAGE_H_ #define _NP3_MUI_LANGUAGE_H_ #include "resource.h" +void SetCurrentLanguage(LANGID iLanguageID); + #if defined(HAVE_DYN_LOAD_LIBS_MUI_LNGS) typedef struct _muilanguage { UINT rid; const WCHAR* szLocaleName; const WCHAR* szMenuItem; - // !!! WARNING: LCID is DEPRECATED + // !!! WARNING: LCID/LANGID is DEPRECATED LANGID LangId; bool bHasDLL; bool bIsActive; @@ -34,31 +78,22 @@ typedef struct _muilanguage { extern MUILANGUAGE MUI_LanguageDLLs[]; int MuiLanguages_CountOf(); - - -typedef struct _gwlang_ini { - const LANGID lngid; - const WCHAR* const filename; -} -grepWinLng_t; - -extern grepWinLng_t grepWinLangResName[]; -int grepWinLang_CountOf(); - - int GetMUILanguageIndexByLangID(LANGID iLanguageID); - bool GetUserPreferredLanguage(LPWSTR pszPrefLocaleName, int cchBuffer, LANGID* pLangID); -void SetPreferredLanguage(LANGID iPreferredLanguageID); - -LANGID LoadLanguageResources(); +LANGID LoadLanguageResources(LPCWSTR localeName); void FreeLanguageResources(); - bool InsertLanguageMenu(HMENU hMenuBar); void DynamicLanguageMenuCmd(int cmd); #endif // HAVE_DYN_LOAD_LIBS_MUI_LNGS +typedef struct _gwlang_ini { + const LANGID lngid; + const WCHAR *const filename; +} grepWinLng_t; + +extern grepWinLng_t grepWinLangResName[]; +int grepWinLang_CountOf(); int LoadLngStringW(UINT uID, LPWSTR lpBuffer, int nBufferMax); int LoadLngStringA(UINT uID, LPSTR lpBuffer, int nBufferMax); @@ -70,6 +105,11 @@ int LoadLngStringW2MB(UINT uID, LPSTR lpBuffer, int nBufferMax); #define GetLngStringA(id,pb,cb) LoadLngStringA((id),(pb),(cb)) #define GetLngStringW2MB(id,pb,cb) LoadLngStringW2MB((id),(pb),(cb)) +// TODO: deprecated +inline int LangIDToLocaleName(const LANGID lngID, LPWSTR lpName_out, size_t cchName) { + LCID const lcid = MAKELCID(lngID, SORT_DEFAULT); + return LCIDToLocaleName(lcid, lpName_out, (int)cchName, 0); +} #endif //_NP3_MUI_LANGUAGE_H_ diff --git a/src/Notepad3.c b/src/Notepad3.c index a220cd0e9..dd1e1c4b9 100644 --- a/src/Notepad3.c +++ b/src/Notepad3.c @@ -630,6 +630,8 @@ static void _InitGlobals() ZeroMemory(&(Globals.fvCurFile), sizeof(FILEVARS)); Globals.WindowsBuildNumber = GetWindowsBuildNumber(NULL, NULL); + + Globals.hLngResContainer = NULL; Globals.hDlgIcon256 = NULL; Globals.hDlgIcon128 = NULL; @@ -644,7 +646,7 @@ static void _InitGlobals() Globals.pMRUfind = NULL; Globals.pMRUreplace = NULL; Globals.iAvailLngCount = 1; - Globals.iPrefLANGID = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US); + Globals.iCurrentLANGID = WORD_MAX; Globals.iWrapCol = 80; Globals.CmdLnFlag_PosParam = false; @@ -875,11 +877,9 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, // MultiLingual // #if defined(HAVE_DYN_LOAD_LIBS_MUI_LNGS) - SetPreferredLanguage(LoadLanguageResources()); + SetCurrentLanguage(LoadLanguageResources(Settings2.PreferredLanguageLocaleName)); #else - Globals.iPrefLANGID = MUI_BASE_LNG_ID; - SetThreadUILanguage(MUI_BASE_LNG_ID); - InitMUILanguage(MUI_BASE_LNG_ID); + SetCurrentLanguage(MUI_BASE_LNG_ID); #endif // ---------------------------------------------------- @@ -997,17 +997,6 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, SetTimer(hwnd, IDT_TIMER_MRKALL, _MQ_TIMER_CYCLE, MQ_ExecuteNext); - #if defined(HAVE_DYN_LOAD_LIBS_MUI_LNGS) - if (Globals.bPrefLngNotAvail) { - const WCHAR* const suprMsg = L"MsgPrefLanguageNotAvailable"; - InfoBoxLng(MB_ICONWARNING, suprMsg, IDS_WARN_PREF_LNG_NOT_AVAIL, Settings2.PreferredLanguageLocaleName); - int const noMsg = IniFileGetInt(Paths.IniFile, Constants.SectionSuppressedMessages, suprMsg, 0); - if (noMsg && Globals.bCanSaveIniFile) { - IniFileSetString(Paths.IniFile, Constants.Settings2_Section, L"PreferredLanguageLocaleName", MUI_LanguageDLLs[0].szLocaleName); - } - } - #endif - MSG msg; while (GetMessage(&msg,NULL,0,0)) { if (IsWindow(Globals.hwndDlgFindReplace) && ((msg.hwnd == Globals.hwndDlgFindReplace) || IsChild(Globals.hwndDlgFindReplace, msg.hwnd))) { diff --git a/src/TypeDefs.h b/src/TypeDefs.h index 8ccf475cf..0062baa30 100644 --- a/src/TypeDefs.h +++ b/src/TypeDefs.h @@ -346,8 +346,6 @@ typedef struct _globals_t HINSTANCE hLngResContainer; DWORD WindowsBuildNumber; bool bCanSaveIniFile; - int iAvailLngCount; - bool bPrefLngNotAvail; HWND hwndMain; HANDLE hndlProcessHeap; HWND hwndEdit; @@ -374,13 +372,15 @@ typedef struct _globals_t HWND hwndDlgCustomizeSchemes; int iDefaultCharSet; cpi_enc_t DOSEncoding; - LANGID iPrefLANGID; LPMRULIST pFileMRU; LPMRULIST pMRUfind; LPMRULIST pMRUreplace; FILEVARS fvCurFile; int iWrapCol; + int iAvailLngCount; + LANGID iCurrentLANGID; + bool CmdLnFlag_PosParam; int CmdLnFlag_AlwaysOnTop; int CmdLnFlag_WindowPos; diff --git a/src/resource.h b/src/resource.h index 8dc8f33a4..05031070d 100644 --- a/src/resource.h +++ b/src/resource.h @@ -15,13 +15,9 @@ // 1. Comment-Out the following line #define HAVE_DYN_LOAD_LIBS_MUI_LNGS 1 // ----------------------------------------------------- -#ifdef HAVE_DYN_LOAD_LIBS_MUI_LNGS -// currently only en-US allowed for Base-Lng in MUI env +// 2. Uncomment one of the following lines according to +// the desired Language (use en-US if undefined) #define MUI_BASE_LNG_EN_US 1 -#else -// 2. Uncomment one of the following lines -// according to the desired Language -//#define MUI_BASE_LNG_EN_US 1 //#define MUI_BASE_LNG_AF_ZA 1 //#define MUI_BASE_LNG_BE_BY 1 //#define MUI_BASE_LNG_DE_DE 1 @@ -48,8 +44,6 @@ //#define MUI_BASE_LNG_ZH_CN 1 //#define MUI_BASE_LNG_ZH_TW 1 -#endif - // ----------------------------------------------------- // 3. In case of a new language: // Extent Notepad3.rc file accordingly