mirror of https://github.com/OpenVPN/openvpn-gui
added support for GUI localization at runtime
parent
41be82f81c
commit
6f37fd999f
120
localization.c
120
localization.c
|
@ -24,15 +24,20 @@
|
||||||
#define WINVER Windows2000
|
#define WINVER Windows2000
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <windowsx.h>
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include "main.h"
|
||||||
|
#include "localization.h"
|
||||||
|
#include "openvpn-gui-res.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "registry.h"
|
#include "registry.h"
|
||||||
|
|
||||||
extern struct options o;
|
extern struct options o;
|
||||||
|
|
||||||
static const LANGID defaultLangId = MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL);
|
static const LANGID fallbackLangId = MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL);
|
||||||
|
static LANGID gui_language;
|
||||||
|
|
||||||
static HRSRC
|
static HRSRC
|
||||||
FindResourceLang(PTSTR resType, PTSTR resId, LANGID langId)
|
FindResourceLang(PTSTR resType, PTSTR resId, LANGID langId)
|
||||||
|
@ -45,7 +50,7 @@ FindResourceLang(PTSTR resType, PTSTR resId, LANGID langId)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
/* try to find the resource in the default language */
|
/* try to find the resource in the default language */
|
||||||
res = FindResourceEx(o.hInstance, resType, resId, defaultLangId);
|
res = FindResourceEx(o.hInstance, resType, resId, fallbackLangId);
|
||||||
if (res)
|
if (res)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
@ -57,7 +62,33 @@ FindResourceLang(PTSTR resType, PTSTR resId, LANGID langId)
|
||||||
static LANGID
|
static LANGID
|
||||||
GetGUILanguage(void)
|
GetGUILanguage(void)
|
||||||
{
|
{
|
||||||
return GetUserDefaultUILanguage();
|
if (gui_language == 0)
|
||||||
|
{
|
||||||
|
HKEY regkey;
|
||||||
|
DWORD value = 0;
|
||||||
|
|
||||||
|
LONG status = RegOpenKeyEx(HKEY_CURRENT_USER, GUI_REGKEY_HKCU, 0, KEY_READ, ®key);
|
||||||
|
if (status != ERROR_SUCCESS)
|
||||||
|
ShowLocalizedMsg(GUI_NAME, ERR_CREATE_REG_HKCU_KEY, GUI_REGKEY_HKCU);
|
||||||
|
|
||||||
|
GetRegistryValueNumeric(regkey, "ui_language", &value);
|
||||||
|
gui_language = ( value != 0 ? value : LANGIDFROMLCID(GetThreadLocale()) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return gui_language;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
SetGUILanguage(LANGID langId)
|
||||||
|
{
|
||||||
|
HKEY regkey;
|
||||||
|
if (RegCreateKeyEx(HKEY_CURRENT_USER, GUI_REGKEY_HKCU, 0, NULL, 0,
|
||||||
|
KEY_WRITE, NULL, ®key, NULL) != ERROR_SUCCESS )
|
||||||
|
ShowLocalizedMsg(GUI_NAME, ERR_CREATE_REG_HKCU_KEY, GUI_REGKEY_HKCU);
|
||||||
|
|
||||||
|
SetRegistryValueNumeric(regkey, "ui_language", langId);
|
||||||
|
gui_language = langId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -235,3 +266,86 @@ CreateLocalizedDialog(const UINT dialogId, DLGPROC dialogFunc)
|
||||||
|
|
||||||
return CreateDialogIndirect(o.hInstance, resInfo, NULL, dialogFunc);
|
return CreateDialogIndirect(o.hInstance, resInfo, NULL, dialogFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PTSTR
|
||||||
|
LangListEntry(const UINT stringId, const LANGID langId, ...)
|
||||||
|
{
|
||||||
|
static TCHAR str[128];
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start(args, langId);
|
||||||
|
LoadStringLang(stringId, langId, str, sizeof(str)/sizeof(*str), args);
|
||||||
|
va_end(args);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
HWND languages;
|
||||||
|
LANGID language;
|
||||||
|
} langProcData;
|
||||||
|
|
||||||
|
|
||||||
|
static BOOL
|
||||||
|
FillLangListProc(HANDLE module, PTSTR type, PTSTR stringId, WORD langId, LONG lParam)
|
||||||
|
{
|
||||||
|
langProcData *data = (langProcData*) lParam;
|
||||||
|
|
||||||
|
int index = ComboBox_AddString(data->languages, LangListEntry(IDS_LANGUAGE_NAME, langId));
|
||||||
|
ComboBox_SetItemData(data->languages, index, langId);
|
||||||
|
|
||||||
|
/* Select this item if it is the currently displayed language */
|
||||||
|
if (langId == data->language
|
||||||
|
|| (PRIMARYLANGID(langId) == PRIMARYLANGID(data->language)
|
||||||
|
&& ComboBox_GetCurSel(data->languages) == CB_ERR) )
|
||||||
|
ComboBox_SetCurSel(data->languages, index);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOL CALLBACK
|
||||||
|
LanguageSettingsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
LPPSHNOTIFY psn;
|
||||||
|
langProcData langData = {
|
||||||
|
.languages = GetDlgItem(hwndDlg, CB_LANGUAGES),
|
||||||
|
.language = GetGUILanguage()
|
||||||
|
};
|
||||||
|
|
||||||
|
switch(msg) {
|
||||||
|
|
||||||
|
case WM_INITDIALOG:
|
||||||
|
/* Populate UI language selection combo box */
|
||||||
|
EnumResourceLanguages( NULL, RT_STRING, MAKEINTRESOURCE(IDS_LANGUAGE_NAME / 16 + 1),
|
||||||
|
(ENUMRESLANGPROC) FillLangListProc, (LONG) &langData );
|
||||||
|
|
||||||
|
/* If none of the available languages matched, select the fallback */
|
||||||
|
if (ComboBox_GetCurSel(langData.languages) == CB_ERR)
|
||||||
|
ComboBox_SelectString(langData.languages, -1,
|
||||||
|
LangListEntry(IDS_LANGUAGE_NAME, fallbackLangId));
|
||||||
|
|
||||||
|
/* Clear language id data for the selected item */
|
||||||
|
ComboBox_SetItemData(langData.languages, ComboBox_GetCurSel(langData.languages), 0);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_NOTIFY:
|
||||||
|
psn = (LPPSHNOTIFY) lParam;
|
||||||
|
if (psn->hdr.code == (UINT) PSN_APPLY)
|
||||||
|
{
|
||||||
|
LANGID langId = (LANGID) ComboBox_GetItemData(langData.languages,
|
||||||
|
ComboBox_GetCurSel(langData.languages));
|
||||||
|
|
||||||
|
if (langId != 0)
|
||||||
|
SetGUILanguage(langId);
|
||||||
|
|
||||||
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, PSNRET_NOERROR);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
|
@ -30,5 +30,6 @@ LPCDLGTEMPLATE LocalizedDialogResource(const UINT);
|
||||||
INT_PTR LocalizedDialogBoxParam(const UINT, DLGPROC, const LPARAM);
|
INT_PTR LocalizedDialogBoxParam(const UINT, DLGPROC, const LPARAM);
|
||||||
INT_PTR LocalizedDialogBox(const UINT, DLGPROC);
|
INT_PTR LocalizedDialogBox(const UINT, DLGPROC);
|
||||||
HWND CreateLocalizedDialog(const UINT, DLGPROC);
|
HWND CreateLocalizedDialog(const UINT, DLGPROC);
|
||||||
|
BOOL CALLBACK LanguageSettingsDlgProc(HWND, UINT, WPARAM, LPARAM);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
9
main.c
9
main.c
|
@ -359,7 +359,7 @@ BOOL CALLBACK AboutDialogFunc (HWND hwndDlg, UINT msg, WPARAM wParam, UNUSED LPA
|
||||||
static void
|
static void
|
||||||
ShowSettingsDialog()
|
ShowSettingsDialog()
|
||||||
{
|
{
|
||||||
PROPSHEETPAGE psp[1];
|
PROPSHEETPAGE psp[2];
|
||||||
psp[0].dwSize = sizeof(PROPSHEETPAGE);
|
psp[0].dwSize = sizeof(PROPSHEETPAGE);
|
||||||
psp[0].dwFlags = PSP_DLGINDIRECT;
|
psp[0].dwFlags = PSP_DLGINDIRECT;
|
||||||
psp[0].hInstance = o.hInstance;
|
psp[0].hInstance = o.hInstance;
|
||||||
|
@ -367,6 +367,13 @@ ShowSettingsDialog()
|
||||||
psp[0].pfnDlgProc = ProxySettingsDialogFunc;
|
psp[0].pfnDlgProc = ProxySettingsDialogFunc;
|
||||||
psp[0].lParam = 0;
|
psp[0].lParam = 0;
|
||||||
psp[0].pfnCallback = NULL;
|
psp[0].pfnCallback = NULL;
|
||||||
|
psp[1].dwSize = sizeof(PROPSHEETPAGE);
|
||||||
|
psp[1].dwFlags = PSP_DLGINDIRECT;
|
||||||
|
psp[1].hInstance = o.hInstance;
|
||||||
|
psp[1].pResource = LocalizedDialogResource(IDD_LANGUAGE);
|
||||||
|
psp[1].pfnDlgProc = LanguageSettingsDlgProc;
|
||||||
|
psp[1].lParam = 0;
|
||||||
|
psp[1].pfnCallback = NULL;
|
||||||
|
|
||||||
PROPSHEETHEADER psh;
|
PROPSHEETHEADER psh;
|
||||||
psh.dwSize = sizeof(PROPSHEETHEADER);
|
psh.dwSize = sizeof(PROPSHEETHEADER);
|
||||||
|
|
|
@ -130,6 +130,18 @@ BEGIN
|
||||||
AUTOCHECKBOX "Beim Verbinden nach Benutzername/Passwort fragen", CHECKB_PROXY_AUTH, 13, 103, 183, 10
|
AUTOCHECKBOX "Beim Verbinden nach Benutzername/Passwort fragen", CHECKB_PROXY_AUTH, 13, 103, 183, 10
|
||||||
END
|
END
|
||||||
|
|
||||||
|
/* General Settings Dialog */
|
||||||
|
IDD_LANGUAGE DIALOGEX 6, 18, 249, 124
|
||||||
|
STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | DS_CENTER
|
||||||
|
CAPTION "Allgemein"
|
||||||
|
FONT 8, "Microsoft Sans Serif"
|
||||||
|
LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL
|
||||||
|
BEGIN
|
||||||
|
GROUPBOX "Benutzeroberfläche", 201, 6, 6, 235, 30
|
||||||
|
LTEXT "Sprache:", TEXT_LANGUAGES, 17, 19, 29, 12
|
||||||
|
COMBOBOX CB_LANGUAGES, 51, 17, 177, 85, CBS_DROPDOWNLIST | WS_TABSTOP
|
||||||
|
END
|
||||||
|
|
||||||
/* Proxy Authentication Dialog */
|
/* Proxy Authentication Dialog */
|
||||||
IDD_PROXY_AUTH DIALOG 29, 23, 154, 65
|
IDD_PROXY_AUTH DIALOG 29, 23, 154, 65
|
||||||
STYLE DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | DS_CENTER
|
STYLE DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | DS_CENTER
|
||||||
|
@ -147,6 +159,8 @@ END
|
||||||
STRINGTABLE
|
STRINGTABLE
|
||||||
LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL
|
LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL
|
||||||
BEGIN
|
BEGIN
|
||||||
|
IDS_LANGUAGE_NAME "Deutsch - German"
|
||||||
|
|
||||||
/* About Dialog */
|
/* About Dialog */
|
||||||
TEXT_ABOUT_OPENVPNGUI "OpenVPN GUI v%s - Eine grafische Oberfläche für OpenVPN"
|
TEXT_ABOUT_OPENVPNGUI "OpenVPN GUI v%s - Eine grafische Oberfläche für OpenVPN"
|
||||||
|
|
||||||
|
|
|
@ -125,6 +125,18 @@ BEGIN
|
||||||
AUTOCHECKBOX "Prompt for username/password when connecting.", CHECKB_PROXY_AUTH, 13, 103, 183, 10
|
AUTOCHECKBOX "Prompt for username/password when connecting.", CHECKB_PROXY_AUTH, 13, 103, 183, 10
|
||||||
END
|
END
|
||||||
|
|
||||||
|
/* General Settings Dialog */
|
||||||
|
IDD_LANGUAGE DIALOGEX 6, 18, 249, 124
|
||||||
|
STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | DS_CENTER
|
||||||
|
CAPTION "General"
|
||||||
|
FONT 8, "Microsoft Sans Serif"
|
||||||
|
LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
|
||||||
|
BEGIN
|
||||||
|
GROUPBOX "User Interface", 201, 6, 6, 235, 30
|
||||||
|
LTEXT "Language:", TEXT_LANGUAGES, 17, 19, 52, 12
|
||||||
|
COMBOBOX CB_LANGUAGES, 57, 17, 171, 85, CBS_DROPDOWNLIST | WS_TABSTOP
|
||||||
|
END
|
||||||
|
|
||||||
/* Proxy Authentication Dialog */
|
/* Proxy Authentication Dialog */
|
||||||
IDD_PROXY_AUTH DIALOG 29, 23, 154, 65
|
IDD_PROXY_AUTH DIALOG 29, 23, 154, 65
|
||||||
STYLE DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | DS_CENTER
|
STYLE DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | DS_CENTER
|
||||||
|
@ -142,6 +154,8 @@ END
|
||||||
STRINGTABLE
|
STRINGTABLE
|
||||||
LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
|
LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
|
||||||
BEGIN
|
BEGIN
|
||||||
|
IDS_LANGUAGE_NAME "English"
|
||||||
|
|
||||||
/* About Dialog */
|
/* About Dialog */
|
||||||
TEXT_ABOUT_OPENVPNGUI "OpenVPN GUI v%s - A Windows GUI for OpenVPN"
|
TEXT_ABOUT_OPENVPNGUI "OpenVPN GUI v%s - A Windows GUI for OpenVPN"
|
||||||
|
|
||||||
|
|
|
@ -141,6 +141,8 @@ END
|
||||||
STRINGTABLE
|
STRINGTABLE
|
||||||
LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL
|
LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL
|
||||||
BEGIN
|
BEGIN
|
||||||
|
IDS_LANGUAGE_NAME "Español - Spanish"
|
||||||
|
|
||||||
/* About Dialog */
|
/* About Dialog */
|
||||||
TEXT_ABOUT_OPENVPNGUI "OpenVPN GUI v%s - Un frontend de Windows para OpenVPN"
|
TEXT_ABOUT_OPENVPNGUI "OpenVPN GUI v%s - Un frontend de Windows para OpenVPN"
|
||||||
|
|
||||||
|
|
|
@ -140,6 +140,8 @@ END
|
||||||
STRINGTABLE
|
STRINGTABLE
|
||||||
LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
|
LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
|
||||||
BEGIN
|
BEGIN
|
||||||
|
IDS_LANGUAGE_NAME "Français - French"
|
||||||
|
|
||||||
/* About Dialog */
|
/* About Dialog */
|
||||||
TEXT_ABOUT_OPENVPNGUI "OpenVPN GUI v%s - A Windows GUI for OpenVPN"
|
TEXT_ABOUT_OPENVPNGUI "OpenVPN GUI v%s - A Windows GUI for OpenVPN"
|
||||||
|
|
||||||
|
|
|
@ -140,6 +140,8 @@ END
|
||||||
STRINGTABLE
|
STRINGTABLE
|
||||||
LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL
|
LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL
|
||||||
BEGIN
|
BEGIN
|
||||||
|
IDS_LANGUAGE_NAME "Italiano - Italian"
|
||||||
|
|
||||||
/* About Dialog */
|
/* About Dialog */
|
||||||
TEXT_ABOUT_OPENVPNGUI "OpenVPN GUI v%s - Interfaccia per Windows di OpenVPN"
|
TEXT_ABOUT_OPENVPNGUI "OpenVPN GUI v%s - Interfaccia per Windows di OpenVPN"
|
||||||
|
|
||||||
|
|
|
@ -140,6 +140,8 @@ END
|
||||||
STRINGTABLE
|
STRINGTABLE
|
||||||
LANGUAGE LANG_DUTCH, SUBLANG_NEUTRAL
|
LANGUAGE LANG_DUTCH, SUBLANG_NEUTRAL
|
||||||
BEGIN
|
BEGIN
|
||||||
|
IDS_LANGUAGE_NAME "Nederlands - Dutch"
|
||||||
|
|
||||||
/* About Dialog */
|
/* About Dialog */
|
||||||
TEXT_ABOUT_OPENVPNGUI "OpenVPN GUI v%s - Een Windows GUI voor OpenVPN"
|
TEXT_ABOUT_OPENVPNGUI "OpenVPN GUI v%s - Een Windows GUI voor OpenVPN"
|
||||||
|
|
||||||
|
|
|
@ -145,6 +145,8 @@ END
|
||||||
STRINGTABLE
|
STRINGTABLE
|
||||||
LANGUAGE LANG_NORWEGIAN, SUBLANG_NEUTRAL
|
LANGUAGE LANG_NORWEGIAN, SUBLANG_NEUTRAL
|
||||||
BEGIN
|
BEGIN
|
||||||
|
IDS_LANGUAGE_NAME "Norsk - Norwegian"
|
||||||
|
|
||||||
/* About Dialog */
|
/* About Dialog */
|
||||||
TEXT_ABOUT_OPENVPNGUI "OpenVPN GUI v%s - Ett Windows-Grensesnitt mot OpenVPN"
|
TEXT_ABOUT_OPENVPNGUI "OpenVPN GUI v%s - Ett Windows-Grensesnitt mot OpenVPN"
|
||||||
|
|
||||||
|
|
|
@ -141,6 +141,8 @@ END
|
||||||
STRINGTABLE
|
STRINGTABLE
|
||||||
LANGUAGE LANG_PORTUGUESE, SUBLANG_NEUTRAL
|
LANGUAGE LANG_PORTUGUESE, SUBLANG_NEUTRAL
|
||||||
BEGIN
|
BEGIN
|
||||||
|
IDS_LANGUAGE_NAME "Português - Portuguese"
|
||||||
|
|
||||||
/* About Dialog */
|
/* About Dialog */
|
||||||
TEXT_ABOUT_OPENVPNGUI "OpenVPN GUI v%s - Uma GUI Windows para OpenVPN"
|
TEXT_ABOUT_OPENVPNGUI "OpenVPN GUI v%s - Uma GUI Windows para OpenVPN"
|
||||||
|
|
||||||
|
|
|
@ -146,6 +146,8 @@ END
|
||||||
STRINGTABLE
|
STRINGTABLE
|
||||||
LANGUAGE LANG_SWEDISH, SUBLANG_NEUTRAL
|
LANGUAGE LANG_SWEDISH, SUBLANG_NEUTRAL
|
||||||
BEGIN
|
BEGIN
|
||||||
|
IDS_LANGUAGE_NAME "Svenska - Swedish"
|
||||||
|
|
||||||
/* About Dialog */
|
/* About Dialog */
|
||||||
TEXT_ABOUT_OPENVPNGUI "OpenVPN GUI v%s - Ett Windows GUI för OpenVPN"
|
TEXT_ABOUT_OPENVPNGUI "OpenVPN GUI v%s - Ett Windows GUI för OpenVPN"
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,12 @@
|
||||||
#define TEXT_PROXY_PORT 217
|
#define TEXT_PROXY_PORT 217
|
||||||
#define CHECKB_PROXY_AUTH 218
|
#define CHECKB_PROXY_AUTH 218
|
||||||
|
|
||||||
|
/* Language Settings Dialog */
|
||||||
|
#define IDD_LANGUAGE 230
|
||||||
|
#define IDS_LANGUAGE_NAME 231
|
||||||
|
#define CB_LANGUAGES 232
|
||||||
|
#define TEXT_LANGUAGES 233
|
||||||
|
|
||||||
/* Proxy Auth Dialog */
|
/* Proxy Auth Dialog */
|
||||||
#define IDD_PROXY_AUTH 250
|
#define IDD_PROXY_AUTH 250
|
||||||
#define EDIT_PROXY_USERNAME 251
|
#define EDIT_PROXY_USERNAME 251
|
||||||
|
|
Loading…
Reference in New Issue