[localization] add subdialog localization

This commit is contained in:
Pete Batard 2013-06-28 02:17:27 +01:00
parent d7db1ebb94
commit ad67467e12
6 changed files with 267 additions and 34 deletions

View File

@ -48,4 +48,14 @@ t IDC_SET_ICON "创建扩展标签和图标文件"
m IDC_ADVANCED -24 0
m IDC_NBPASSES 8 0
m IDC_BOOTTYPE 8 0
m IDC_SELECT_ISO 6 0
m IDC_SELECT_ISO 6 0
t IDC_ABOUT "关于..."
t IDC_LOG "日志"
m IDC_LOG -5 0
r IDC_LOG +5 0
t IDCANCEL "关闭"
t IDC_START "开始"
p IDD_ABOUTBOX
t IDC_ABOUT_LICENSE "许可证"
t IDC_ABOUT_UPDATES "更新"
t IDOK "确定"

View File

@ -27,6 +27,7 @@
#include <stdio.h>
#include <wchar.h>
#include <string.h>
#include <stddef.h>
#include "rufus.h"
#include "resource.h"
@ -36,7 +37,18 @@
#define LOC_CTRL(x) { #x, x }
// TODO: move this to an autogenerated file
loc_control_id control_id[] = {
const loc_control_id control_id[] = {
// The dialog IDs must come first
LOC_CTRL(IDD_DIALOG),
LOC_CTRL(IDD_ABOUTBOX),
LOC_CTRL(IDD_NOTIFICATION),
LOC_CTRL(IDD_LICENSE),
LOC_CTRL(IDD_ISO_EXTRACT),
LOC_CTRL(IDD_LOG),
LOC_CTRL(IDD_UPDATE_POLICY),
LOC_CTRL(IDD_NEW_VERSION),
LOC_CTRL(IDOK),
LOC_CTRL(IDCANCEL),
LOC_CTRL(IDS_DEVICE_TXT),
LOC_CTRL(IDS_PARTITION_TYPE_TXT),
LOC_CTRL(IDS_FILESYSTEM_TXT),
@ -52,6 +64,27 @@ loc_control_id control_id[] = {
LOC_CTRL(IDC_NBPASSES),
LOC_CTRL(IDC_BOOTTYPE),
LOC_CTRL(IDC_SELECT_ISO),
LOC_CTRL(IDC_ABOUT),
LOC_CTRL(IDC_LOG),
LOC_CTRL(IDC_START),
LOC_CTRL(IDC_ABOUT_LICENSE),
LOC_CTRL(IDC_ABOUT_UPDATES),
};
// Have a root loc_cmd that points to parent loc_cmd
// MUST be in the same order as in resource.h, and with IDs in
// consecutive order with no gap, as we'll use IDD_XYZ = IDD_DIALOG to
// locate our index in dialog_active
#define LOC_DLG_LST(x) { x, NULL, {NULL, NULL} }
loc_dlg_list loc_dlg[IDD_NEW_VERSION - IDD_DIALOG + 1] = {
LOC_DLG_LST(IDD_DIALOG),
LOC_DLG_LST(IDD_ABOUTBOX),
LOC_DLG_LST(IDD_NOTIFICATION),
LOC_DLG_LST(IDD_LICENSE),
LOC_DLG_LST(IDD_ISO_EXTRACT),
LOC_DLG_LST(IDD_LOG),
LOC_DLG_LST(IDD_UPDATE_POLICY),
LOC_DLG_LST(IDD_NEW_VERSION),
};
/* c control ID (no space, no quotes), s: quoted string, i: 32 bit signed integer, */
@ -65,7 +98,7 @@ loc_parse parse_cmd[] = {
{ 'f', LC_FONT, "si" },
{ 'd', LC_DIRECTION, "i" },
};
size_t PARSE_CMD_SIZE = ARRAYSIZE(parse_cmd);
const size_t PARSE_CMD_SIZE = ARRAYSIZE(parse_cmd);
int loc_line_nr = 0;
char loc_filename[32];
@ -78,58 +111,149 @@ void free_loc_cmd(loc_cmd* lcmd)
free(lcmd);
}
void loc_dlg_add(int index, loc_cmd* lcmd)
{
if ((lcmd == NULL) || (index < 0) || (index >= ARRAYSIZE(loc_dlg))) {
uprintf("loc_dlg_add: invalid parameter\n");
return;
}
list_add(&lcmd->list, &loc_dlg[index].list);
}
// TODO: rename this to something_localization()
void free_loc_dlg(void)
{
size_t i = 0;
loc_cmd *lcmd, *next;
for (i=0; i<ARRAYSIZE(loc_dlg); i++) {
if (list_empty(&loc_dlg[i].list))
continue;
list_for_each_entry_safe(lcmd, next, &loc_dlg[i].list, list, loc_cmd) {
list_del(&lcmd->list);
free_loc_cmd(lcmd);
}
}
}
/*
* We need to initialize the command lists
*/
void init_localization(void) {
size_t i;
for (i=0; i<ARRAYSIZE(loc_dlg); i++)
list_init(&loc_dlg[i].list);
}
/*
* Yada. Should be called during init
* if hDlg is NULL, we try to apply the commands against an active Window
* if dlg_id is negative, we try to apply all
*/
void apply_localization(int dlg_id, HWND hDlg)
{
loc_cmd* lcmd;
HWND hCtrl = NULL;
if (hDlg != NULL) {
loc_dlg[dlg_id-IDD_DIALOG].hDlg = hDlg;
} else {
hDlg = loc_dlg[dlg_id-IDD_DIALOG].hDlg;
}
if (!IsWindow(hDlg))
return; // Not an active dialog
if (list_empty(&loc_dlg[dlg_id-IDD_DIALOG].list))
return; // Empty list
list_for_each_entry(lcmd, &loc_dlg[dlg_id-IDD_DIALOG].list, list, loc_cmd) {
if (lcmd->command <= LC_TEXT) { // TODO: should always be the case
hCtrl = GetDlgItem(hDlg, lcmd->ctrl_id);
if (hCtrl == NULL) {
// TODO: store the line nr in command so that we can print a better error?
// Would also avoid global in dispatch
loc_line_nr = lcmd->line_nr;
luprintf("control '%s' is not part of dialog '%s'\n",
lcmd->text[0], control_id[dlg_id-IDD_DIALOG].name);
}
}
switch(lcmd->command) {
// NB: For commands that take an ID, ctrl_id is always a valid index at this stage
case LC_TEXT:
if (hCtrl != NULL) {
SetWindowTextU(hCtrl, lcmd->text[1]);
}
break;
case LC_MOVE:
if (hCtrl != NULL) {
ResizeMoveCtrl(hDlg, hCtrl, lcmd->num[0], lcmd->num[1], 0, 0);
}
break;
case LC_RESIZE:
if (hCtrl != NULL) {
ResizeMoveCtrl(hDlg, hCtrl, 0, 0, lcmd->num[0], lcmd->num[1]);
}
break;
}
}
}
// Can't use isWindow() against our existing HWND to avoid this call
// as handles are recycled.
void reset_localization(int dlg_id)
{
loc_dlg[dlg_id-IDD_DIALOG].hDlg = NULL;
}
// TODO: we need to store a revert for every action we execute here,
// or do we want to reinstantiate the dialogs?
BOOL execute_loc_cmd(loc_cmd* lcmd)
BOOL dispatch_loc_cmd(loc_cmd* lcmd)
{
size_t i;
static HWND hParent = NULL;
static char parent_name[128] = "IDD_DIALOG"; // Keep a copy of the parent
HWND hCtrl = NULL;
static int dlg_index = 0;
if (lcmd == NULL)
return FALSE;
if (hParent == NULL)
hParent = hMainDialog;
// uprintf("cmd #%d: ('%s', '%s') (%d, %d)\n",
// lcmd->command, lcmd->text[0], lcmd->text[1], lcmd->num[0], lcmd->num[1]);
if (lcmd->command <= LC_TEXT) {
// Any command before LC_VERSION takes a control ID in text[0]
// Any command up to LC_TEXT takes a control ID in text[0]
for (i=0; i<ARRAYSIZE(control_id); i++) {
if (safe_strcmp(lcmd->text[0], control_id[i].name) == 0) {
hCtrl = GetDlgItem(hParent, control_id[i].id);
lcmd->ctrl_id = control_id[i].id;
break;
}
}
if (hCtrl == NULL) {
luprintf("'%s' is not a member of '%s'\n", lcmd->text[0], parent_name);
if (lcmd->ctrl_id < 0) {
luprintf("unknown control '%s'\n", lcmd->text[0]);
goto err;
}
}
switch(lcmd->command) {
// NB: Form commands that take an ID, ctrl_id is always a valid index at this stage
case LC_TEXT:
if (hCtrl != NULL) {
SetWindowTextU(hCtrl, lcmd->text[1]);
}
break;
case LC_MOVE:
if (hCtrl != NULL) {
ResizeMoveCtrl(hParent, hCtrl, lcmd->num[0], lcmd->num[1], 0, 0);
}
break;
case LC_RESIZE:
if (hCtrl != NULL) {
ResizeMoveCtrl(hParent, hCtrl, 0, 0, lcmd->num[0], lcmd->num[1]);
}
loc_dlg_add(dlg_index, lcmd);
break;
case LC_PARENT:
// ???
if ((lcmd->ctrl_id-IDD_DIALOG) > ARRAYSIZE(loc_dlg)) {
luprintf("'%s' is not a dialog ID\n", lcmd->text[0]);
goto err;
}
dlg_index = lcmd->ctrl_id - IDD_DIALOG;
free_loc_cmd(lcmd);
break;
default:
free_loc_cmd(lcmd);
break;
}
return TRUE;
// /!\ lcmd is freed after this call => if text messages need to be stored, they
// must be removed from cmd so that they won't be freed
err:
free_loc_cmd(lcmd);
return FALSE;
}

View File

@ -18,6 +18,7 @@
*/
#include <stdint.h>
#include <stddef.h>
// What we need for localization
// # Comment
@ -42,6 +43,74 @@
#define luprint(msg) uprintf("%s(%d): " msg "\n", loc_filename, loc_line_nr)
#define luprintf(msg, ...) uprintf("%s(%d): " msg "\n", loc_filename, loc_line_nr, __VA_ARGS__)
/*
* List handling functions (stolen from libusb)
* NB: offsetof() requires '#include <stddef.h>'
*/
struct list_head {
struct list_head *prev, *next;
};
/* Get an entry from the list
* ptr - the address of this list_head element in "type"
* type - the data type that contains "member"
* member - the list_head element in "type"
*/
#define list_entry(ptr, type, member) \
((type *)((uintptr_t)(ptr) - (uintptr_t)offsetof(type, member)))
/* Get each entry from a list
* pos - A structure pointer has a "member" element
* head - list head
* member - the list_head element in "pos"
* type - the type of the first parameter
*/
#define list_for_each_entry(pos, head, member, type) \
for (pos = list_entry((head)->next, type, member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, type, member))
#define list_for_each_entry_safe(pos, n, head, member, type) \
for (pos = list_entry((head)->next, type, member), \
n = list_entry(pos->member.next, type, member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, type, member))
#define list_empty(entry) ((entry)->next == (entry))
static __inline void list_init(struct list_head *entry)
{
entry->prev = entry->next = entry;
}
static __inline void list_add(struct list_head *entry, struct list_head *head)
{
entry->next = head->next;
entry->prev = head;
head->next->prev = entry;
head->next = entry;
}
static __inline void list_add_tail(struct list_head *entry,
struct list_head *head)
{
entry->next = head;
entry->prev = head->prev;
head->prev->next = entry;
head->prev = entry;
}
static __inline void list_del(struct list_head *entry)
{
entry->next->prev = entry->prev;
entry->prev->next = entry->next;
entry->next = entry->prev = NULL;
}
enum loc_command_type {
LC_PARENT,
LC_MOVE,
@ -55,8 +124,11 @@ enum loc_command_type {
typedef struct loc_cmd_struct {
int command;
int ctrl_id;
uint32_t line_nr;
char* text[2];
int32_t num[2];
struct list_head list;
} loc_cmd;
typedef struct loc_parse_struct {
@ -70,10 +142,20 @@ typedef struct loc_control_id_struct {
const int id;
} loc_control_id;
typedef struct loc_dlg_list_struct {
const int dlg_id;
HWND hDlg;
struct list_head list;
} loc_dlg_list;
loc_parse parse_cmd[];
size_t PARSE_CMD_SIZE;
const size_t PARSE_CMD_SIZE;
int loc_line_nr;
char loc_filename[32];
void free_loc_cmd(loc_cmd* lcmd);
BOOL execute_loc_cmd(loc_cmd* lcmd);
BOOL dispatch_loc_cmd(loc_cmd* lcmd);
void init_localization(void);
void apply_localization(int dlg_id, HWND hDlg);
void reset_localization(int dlg_id);
void free_loc_dlg(void);

View File

@ -34,6 +34,7 @@
#include "rufus.h"
#include "msapi_utf8.h"
#include "localization.h"
#include "resource.h" // TODO: remove_me - only needed for IDD_DIALOG
static const wchar_t wspace[] = L" \t";
@ -58,7 +59,9 @@ static loc_cmd* get_loc_cmd(wchar_t wc, wchar_t* wline) {
luprint("could not allocate command");
return NULL;
}
lcmd->ctrl_id = -1;
lcmd->command = parse_cmd[j].cmd;
lcmd->line_nr = loc_line_nr;
i = 0;
for (k = 0; parse_cmd[j].arg_type[k] != 0; k++) {
@ -147,8 +150,7 @@ static void* get_loc_data_line(wchar_t* wline)
lcmd = get_loc_cmd(t, &wline[i]);
// TODO: process LC_LOCALE in seek_locale mode
// TODO: check return value?
execute_loc_cmd(lcmd);
free_loc_cmd(lcmd);
dispatch_loc_cmd(lcmd);
return NULL;
}
@ -176,6 +178,8 @@ char* get_loc_data_file(const char* filename)
if ((filename == NULL) || (filename[0] == 0))
return NULL;
// TODO: revert previous changes
free_loc_dlg();
loc_line_nr = 0;
safe_strcpy(loc_filename, sizeof(loc_filename), filename);
wfilename = utf8_to_wchar(filename);
@ -258,6 +262,7 @@ char* get_loc_data_file(const char* filename)
} while(1);
out:
apply_localization(IDD_DIALOG, hMainDialog);
if (fd != NULL)
fclose(fd);
safe_free(wfilename);

View File

@ -40,6 +40,7 @@
#include "resource.h"
#include "rufus.h"
#include "registry.h"
#include "localization.h"
/* Redefinitions for WDK and MinGW */
#ifndef PBM_SETSTATE
@ -1465,6 +1466,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
break;
case WM_INITDIALOG:
apply_localization(IDD_DIALOG, hDlg);
SetUpdateCheck();
// Create the log window (hidden)
hLogDlg = CreateDialogA(hMainInstance, MAKEINTRESOURCEA(IDD_LOG), hDlg, (DLGPROC)LogProc);
@ -1889,7 +1891,11 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
uprintf("*** " APPLICATION_NAME " init ***\n");
SetThreadLocale(MAKELCID(LANG_FRENCH, SUBLANG_FRENCH));
// Init localization
init_localization();
// TODO: See what happens with this
// SetThreadLocale(MAKELCID(LANG_FRENCH, SUBLANG_FRENCH));
// Reattach the console, if we were started from commandline
if (AttachConsole(ATTACH_PARENT_PROCESS) != 0) {
@ -1975,7 +1981,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
SetLGP(FALSE, &existing_key, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer", "NoDriveTypeAutorun", 0x9e);
// Create the main Window
if ( (hDlg = CreateDialogA(hInstance, MAKEINTRESOURCEA(IDD_DIALOG), NULL, MainCallback)) == NULL ) {
hDlg = CreateDialogA(hInstance, MAKEINTRESOURCEA(IDD_DIALOG), NULL, MainCallback);
if (hDlg == NULL) {
MessageBoxU(NULL, "Could not create Window", "DialogBox failure", MB_ICONSTOP);
goto out;
}
@ -2042,6 +2049,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
out:
DestroyAllTooltips();
free_loc_dlg();
safe_free(iso_path);
safe_free(update.download_url);
safe_free(update.release_notes);

View File

@ -39,6 +39,7 @@
#include "registry.h"
#include "resource.h"
#include "license.h"
#include "localization.h"
/* The following is only available on Vista and later */
#if (_WIN32_WINNT >= 0x0600)
@ -491,6 +492,8 @@ INT_PTR CALLBACK AboutCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lP
switch (message) {
case WM_INITDIALOG:
// Execute dialog localization
apply_localization(IDD_ABOUTBOX, hDlg);
SetTitleBarIcon(hDlg);
CenterDialog(hDlg);
if (reg_commcheck)
@ -529,6 +532,7 @@ INT_PTR CALLBACK AboutCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lP
switch (LOWORD(wParam)) {
case IDOK:
case IDCANCEL:
reset_localization(IDD_ABOUTBOX);
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
case IDC_ABOUT_LICENSE: