提交 79c16c0d 编写于 作者: P Pete Batard

[localization] improve message generation and cleanup

上级 0c8d0e0c
l "English" 0x0409, 0x0809, 0x0c09, 0x1009, 0x1409, 0x1809, 0x1c09, 0x2009, 0x2409, 0x2809, 0x2c09, 0x3009, 0x3409, 0x3809, 0x3c09, 0x4009, 0x4409, 0x4809
# TODO: replace 'p' with 's' for section
p IDD_MESSAGES
s IDD_MESSAGES
t MSG_001 "WARNING: ALL DATA ON DEVICE '%s' WILL BE DESTROYED.\n"
"To continue with this operation, click OK. To quit click CANCEL."
l "French" 0x040c, 0x080c, 0x0c0c, 0x100c, 0x140c, 0x180c, 0x1c0c, 0x200c, 0x240c, 0x280c, 0x2c0c, 0x300c, 0x340c, 0x380c, 0xe40c
p IDD_DIALOG
s IDD_DIALOG
t IDS_FORMATOPTIONS_TXT "Options de Formattage "
t IDS_LABEL_TXT "Nouveau label"
t IDS_FILESYSTEM_TXT "Système de fichier"
......@@ -16,14 +15,14 @@ t IDC_BADBLOCKS "Vérification de mauvais blocs:"
t IDC_QUICKFORMAT "Formattage rapide"
t IDC_BOOT "Disque de démarrage avec:"
t IDC_SET_ICON "Ajouter un label étendu et une icône"
m IDC_ADVANCED +18 0
m IDC_ADVANCED +36 0
p IDD_MESSAGES
s IDD_MESSAGES
t MSG_001 "ATTENTION: TOUTES LES DONNEES SUR LE VOLUME '%s' VONT ETRE EFFACEES.\n"
"Pour continuer cette operation, cliquez sur OK.\nPour quitter cliquez sur ANNULER."
l "Chinese (Traditional)" 0x0404, 0x0804, 0x0c04, 0x1004, 0x1404
p IDD_DIALOG
s IDD_DIALOG
t IDS_DEVICE_TXT "设备"
t IDS_PARTITION_TYPE_TXT "分区计划和目标系统类型"
t IDS_FILESYSTEM_TXT "文件系统"
......@@ -50,36 +49,36 @@ t IDC_ENABLE_FIXED_DISKS "列表固定(非flash)或USB磁盘分区"
t IDC_EXTRA_PARTITION "添加修复旧的BIOS(额外的分区,校准等等)"
t IDC_RUFUS_MBR "使用 Rufus MBR BIOS ID:"
p IDD_ABOUTBOX
s IDD_ABOUTBOX
t IDD_ABOUTBOX "关于 Rufus"
t IDC_ABOUT_LICENSE "许可证"
t IDC_ABOUT_UPDATES "更新"
t IDOK "确定"
p IDD_ISO_EXTRACT
s IDD_ISO_EXTRACT
t IDD_ISO_EXTRACT "复制ISO文件..."
t IDC_ISO_FILENAME "打开ISO映像 - 请稍候..."
t IDC_ISO_ABORT "取消"
p IDD_LICENSE
s IDD_LICENSE
t IDD_LICENSE "Rufus 许可证"
t IDOK "取消"
p IDD_NOTIFICATION
s IDD_NOTIFICATION
t IDC_MORE_INFO "更多信息"
t IDYES "是"
t IDNO "否"
p IDD_LOG
s IDD_LOG
t IDD_LOG "日志"
t IDC_LOG_CLEAR "清除日志"
t IDC_LOG_SAVE "保存日志"
t IDCANCEL "关闭日志"
p IDD_LICENSE
s IDD_LICENSE
t IDOK "取消"
p IDD_UPDATE_POLICY
s IDD_UPDATE_POLICY
t IDD_UPDATE_POLICY "更新方案和设置"
t IDS_UPDATE_SETTINGS_TXT "设置"
t IDS_UPDATE_FREQUENCY_TXT "检查更新:"
......@@ -87,7 +86,7 @@ t IDS_INCLUDE_BETAS_TXT "包括测试版本:"
t IDC_CHECK_NOW "立即检查"
t IDCANCEL "取消"
p IDD_NEW_VERSION
s IDD_NEW_VERSION
t IDD_NEW_VERSION "检查更新 - Rufus"
t IDS_NEW_VERSION_AVAIL_TXT "更新的版本可用。请下载最新版本!"
t IDC_WEBSITE "点击这里进入网站"
......
......@@ -35,8 +35,14 @@
#include "localization.h"
#include "localization_data.h"
/* c control ID (no space, no quotes), s: quoted string, i: 32 bit signed integer, u: 32 bit unsigned CSV list */
// Remember to update the size of the array in localization.h when adding/removing elements
/*
* List of supported locale commands, with their parameter syntax:
* c control ID (no space, no quotes)
* s: quoted string
* i: 32 bit signed integer
* u: 32 bit unsigned CSV list
* Remember to update the size of the array in localization.h when adding/removing elements
*/
const loc_parse parse_cmd[9] = {
// Translation name and Windows LCIDs it should apply to
{ 'l', LC_LOCALE, "su" }, // l "English (US)" 0x0009,0x1009
......@@ -46,9 +52,8 @@ const loc_parse parse_cmd[9] = {
{ 'v', LC_VERSION, "ii" }, // v 1.0 // TODO: NOT IMPLEMENTED YET
// Translate the text control associated with an ID
{ 't', LC_TEXT, "cs" }, // t IDC_CONTROL "Translation"
// Set the parent dialog to which the next commands should apply.
// Use 'p NONE' for text data that is not bound to a dialog
{ 'p', LC_PARENT, "c" }, // p IDD_DIALOG
// Set the section/dialog to which the next commands should apply
{ 's', LC_SECTION, "c" }, // p IDD_DIALOG
// Resize a dialog (dx dy pixel increment)
{ 'r', LC_RESIZE, "cii" }, // t IDC_CONTROL +10 +10
// Move a dialog (dx dy pixed displacement)
......@@ -60,10 +65,23 @@ const loc_parse parse_cmd[9] = {
// 0 = Left to right, 1 = Right to left
{ 'd', LC_DIRECTION, "i" }, // d 1 // TODO: NOT IMPLEMENTED YET
};
/* Globals */
int loc_line_nr;
char loc_filename[32];
struct list_head locale_list = {NULL, NULL};
/*
* Add a localization command to a dialog/section
*/
void add_dialog_command(int index, loc_cmd* lcmd)
{
if ((lcmd == NULL) || (index < 0) || (index >= ARRAYSIZE(loc_dlg))) {
uprintf("add_dialog_command: invalid parameter\n");
return;
}
list_add(&lcmd->list, &loc_dlg[index].list);
}
void free_loc_cmd(loc_cmd* lcmd)
{
if (lcmd == NULL)
......@@ -74,17 +92,7 @@ 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)
void free_dialog_list(void)
{
size_t i = 0;
loc_cmd *lcmd, *next;
......@@ -110,25 +118,82 @@ void free_locale_list(void)
}
/*
* We need to initialize the command lists
* Init/destroy our various localization lists
*/
void init_localization(void) {
size_t i;
for (i=0; i<ARRAYSIZE(loc_dlg); i++)
list_init(&loc_dlg[i].list);
list_init(&locale_list);
}
void exit_localization(void) {
free_loc_dlg();
free_dialog_list();
free_locale_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
* Validate and store localization command data
*
* TODO: Do we need to store a revert for every action we execute here,
* or do we want to reinstantiate the dialogs?
*/
BOOL dispatch_loc_cmd(loc_cmd* lcmd)
{
size_t i;
static int dlg_index = 0;
if (lcmd == NULL)
return FALSE;
if (lcmd->command <= LC_TEXT) {
// 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->txt[0], control_id[i].name) == 0) {
lcmd->ctrl_id = control_id[i].id;
break;
}
}
if (lcmd->ctrl_id < 0) {
luprintf("unknown control '%s'\n", lcmd->txt[0]);
goto err;
}
}
switch(lcmd->command) {
// NB: For commands that take an ID, ctrl_id is always a valid index at this stage
case LC_TEXT:
case LC_MOVE:
case LC_RESIZE:
add_dialog_command(dlg_index, lcmd);
break;
case LC_SECTION:
if ((lcmd->ctrl_id-IDD_DIALOG) > ARRAYSIZE(loc_dlg)) {
luprintf("'%s' is not a section ID\n", lcmd->txt[0]);
goto err;
}
dlg_index = lcmd->ctrl_id - IDD_DIALOG;
free_loc_cmd(lcmd);
break;
case LC_VERSION:
luprintf("GOT VERSION: %d.%d\n", lcmd->num[0], lcmd->num[1]);
free_loc_cmd(lcmd);
break;
default:
free_loc_cmd(lcmd);
break;
}
return TRUE;
err:
free_loc_cmd(lcmd);
return FALSE;
}
/*
* Apply stored localization commands to a specific dialog
* If hDlg is NULL, apply the commands against an active Window
* TODO: if dlg_id is <0, apply all
*/
void apply_localization(int dlg_id, HWND hDlg)
{
......@@ -202,80 +267,53 @@ void apply_localization(int dlg_id, HWND hDlg)
}
}
// Can't use isWindow() against our existing HWND to avoid this call
// as handles are recycled.
/*
* This function should be called when a localized dialog is destroyed
* NB: we 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: Do we need to store a revert for every action we execute here,
// or do we want to reinstantiate the dialogs?
BOOL dispatch_loc_cmd(loc_cmd* lcmd)
{
size_t i;
static int dlg_index = 0;
if (lcmd == NULL)
return FALSE;
if (lcmd->command <= LC_TEXT) {
// 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->txt[0], control_id[i].name) == 0) {
lcmd->ctrl_id = control_id[i].id;
break;
}
}
if (lcmd->ctrl_id < 0) {
luprintf("unknown control '%s'\n", lcmd->txt[0]);
goto err;
}
}
switch(lcmd->command) {
// NB: For commands that take an ID, ctrl_id is always a valid index at this stage
case LC_TEXT:
case LC_MOVE:
case LC_RESIZE:
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->txt[0]);
goto err;
}
dlg_index = lcmd->ctrl_id - IDD_DIALOG;
free_loc_cmd(lcmd);
break;
case LC_VERSION:
luprintf("GOT VERSION: %d.%d\n", lcmd->num[0], lcmd->num[1]);
free_loc_cmd(lcmd);
break;
default:
free_loc_cmd(lcmd);
break;
}
return TRUE;
err:
free_loc_cmd(lcmd);
return FALSE;
}
char* get_loc_msg(int msg_id)
/*
* Produce a formatted localized message.
* Like printf, this call takes a variable number of argument, and uses
* the message ID to identify the formatted message to use.
* Uses a rolling list of buffers to allow concurrency
* TODO: use dynamic realloc'd buffer in case 2048 is not enough
*/
char* lmprintf(int msg_id, ...)
{
static int buf_id = 0;
static char buf[4][2048];
char *format = NULL;
va_list args;
loc_cmd* lcmd;
buf_id %= 4;
buf[buf_id][0] = 0;
list_for_each_entry(lcmd, &loc_dlg[IDD_MESSAGES-IDD_DIALOG].list, loc_cmd, list) {
if ((lcmd->command == LC_TEXT) && (lcmd->ctrl_id == msg_id) && (lcmd->txt[1] != NULL)) {
return lcmd->txt[1];
format = lcmd->txt[1];
}
}
// TODO: print the message ID or something
return "UNTRANSLATED MESSAGE";
if (format == NULL) {
safe_sprintf(buf[buf_id], 2047, "MSG_%03d UNTRANSLATED", msg_id);
} else {
va_start(args, msg_id);
safe_vsnprintf(buf[buf_id], 2047, format, args);
va_end(args);
buf[buf_id][2047] = '\0';
}
return buf[buf_id++];
}
/*
* These 2 functions are used to set the current locale
*/
loc_cmd* get_locale_from_lcid(int lcid)
{
loc_cmd* lcmd = NULL;
......
......@@ -25,9 +25,6 @@
// TODO: display control name on mouseover
// Link to http://www.resedit.net/
// Commands that take a control ID *MUST* be at the top
// The last command with a control ID *MUST* be LC_TEXT
#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__)
......@@ -98,9 +95,10 @@ static __inline void list_del(struct list_head *entry)
entry->next = entry->prev = NULL;
}
// Commands that take a control ID *MUST* be at the top
// The last command with a control ID *MUST* be LC_TEXT
enum loc_command_type {
LC_PARENT,
LC_SECTION,
LC_MOVE,
LC_RESIZE,
LC_TEXT, // Delimits commands that take a Control ID and commands that don't
......@@ -150,8 +148,8 @@ void init_localization(void);
void exit_localization(void);
void apply_localization(int dlg_id, HWND hDlg);
void reset_localization(int dlg_id);
void free_loc_dlg(void);
char* get_loc_msg(int id);
void free_dialog_list(void);
char* lmprintf(int msg_id, ...);
BOOL get_supported_locales(const char* filename);
char* get_loc_data_file(const char* filename, long offset, long end_offset);
void free_locale_list(void);
......
......@@ -38,8 +38,10 @@
static const char space[] = " \t";
static const wchar_t wspace[] = L" \t";
// Fill a localization command buffer by parsing the line arguments
// The command is allocated and must be freed (by calling free_loc_cmd)
/*
* Fill a localization command buffer by parsing the line arguments
* The command is allocated and must be freed (by calling free_loc_cmd)
*/
static loc_cmd* get_loc_cmd(char c, char* line) {
size_t i, j, k, l, r, ti = 0, ii = 0;
char *endptr, *expected_endptr, *token;
......@@ -151,8 +153,9 @@ err:
return NULL;
}
// Parse an UTF-8 localization command line
/*
* Parse an UTF-8 localization command line
*/
static void get_loc_data_line(char* line)
{
size_t i;
......@@ -183,17 +186,9 @@ static void get_loc_data_line(char* line)
free_loc_cmd(lcmd);
}
static __inline void *_reallocf(void *ptr, size_t size)
{
void *ret = realloc(ptr, size);
if (!ret)
free(ptr);
return ret;
}
/*
* First pass of parsing the locale file, to construct the list
* of locales available. The locale file must be UTF-8 with NO BOM.
* Parse a localization file, to construct the list of available locales.
* The locale file must be UTF-8 with NO BOM.
* TODO: merge this with the next call or factorize fopen
*/
BOOL get_supported_locales(const char* filename)
......@@ -264,9 +259,9 @@ out:
return r;
}
// Parse a Rufus localization command file (UTF-8, no BOM)
// TODO: detect if locale could not be found and fallback to En
// TODO: change the return value and return an error if locale was not found
/*
* Parse a locale section in a localization file (UTF-8, no BOM)
*/
char* get_loc_data_file(const char* filename, long offset, long end_offset)
{
wchar_t *wfilename = NULL;
......@@ -281,7 +276,7 @@ char* get_loc_data_file(const char* filename, long offset, long end_offset)
if ((filename == NULL) || (filename[0] == 0))
return NULL;
free_loc_dlg();
free_dialog_list();
loc_line_nr = 0;
safe_strcpy(loc_filename, sizeof(loc_filename), filename);
wfilename = utf8_to_wchar(filename);
......@@ -405,7 +400,7 @@ char* get_loc_data_file(const char* filename, long offset, long end_offset)
out:
// TODO: do we really need this here?
apply_localization(-1, NULL);
// apply_localization(-1, NULL);
if (fd != NULL)
fclose(fd);
safe_free(wfilename);
......@@ -414,9 +409,11 @@ out:
}
// Parse a line of UTF-16 text and return the data if it matches the 'token'
// The parsed line is of the form: [ ]token[ ]=[ ]["]data["][ ] and is
// modified by the parser
/*
* Parse a line of UTF-16 text and return the data if it matches the 'token'
* The parsed line is of the form: [ ]token[ ]=[ ]["]data["][ ] and is
* modified by the parser
*/
static wchar_t* get_token_data_line(const wchar_t* wtoken, wchar_t* wline)
{
size_t i, r;
......@@ -469,8 +466,10 @@ static wchar_t* get_token_data_line(const wchar_t* wtoken, wchar_t* wline)
return (wline[r] == 0)?NULL:&wline[r];
}
// Parse a file (ANSI or UTF-8 or UTF-16) and return the data for the first occurrence of 'token'
// The returned string is UTF-8 and MUST be freed by the caller
/*
* Parse a file (ANSI or UTF-8 or UTF-16) and return the data for the first occurrence of 'token'
* The returned string is UTF-8 and MUST be freed by the caller
*/
char* get_token_data_file(const char* token, const char* filename)
{
wchar_t *wtoken = NULL, *wdata= NULL, *wfilename = NULL;
......@@ -514,8 +513,10 @@ out:
return ret;
}
// Parse a buffer (ANSI or UTF-8) and return the data for the 'n'th occurrence of 'token'
// The returned string is UTF-8 and MUST be freed by the caller
/*
* Parse a buffer (ANSI or UTF-8) and return the data for the 'n'th occurrence of 'token'
* The returned string is UTF-8 and MUST be freed by the caller
*/
char* get_token_data_buffer(const char* token, unsigned int n, const char* buffer, size_t buffer_size)
{
unsigned int j, curly_count;
......@@ -578,10 +579,12 @@ static __inline char* get_sanitized_token_data_buffer(const char* token, unsigne
return data;
}
// Parse an update data file and populates a rufus_update structure.
// NB: since this is remote data, and we're running elevated, it *IS* considered
// potentially malicious, even if it comes from a supposedly trusted server.
// len should be the size of the buffer, including the zero terminator
/*
* Parse an update data file and populates a rufus_update structure.
* NB: since this is remote data, and we're running elevated, it *IS* considered
* potentially malicious, even if it comes from a supposedly trusted server.
* len should be the size of the buffer, including the zero terminator
*/
void parse_update(char* buf, size_t len)
{
size_t i;
......@@ -628,8 +631,10 @@ void parse_update(char* buf, size_t len)
update.release_notes = get_sanitized_token_data_buffer("release_notes", 1, buf, len);
}
// Insert entry 'data' under section 'section' of a config file
// Section must include the relevant delimitors (eg '[', ']') if needed
/*
* Insert entry 'data' under section 'section' of a config file
* Section must include the relevant delimitors (eg '[', ']') if needed
*/
char* insert_section_data(const char* filename, const char* section, const char* data, BOOL dos2unix)
{
const wchar_t* outmode[] = { L"w", L"w, ccs=UTF-8", L"w, ccs=UTF-16LE" };
......@@ -753,10 +758,12 @@ out:
return ret;
}
// Search for a specific 'src' substring data for all occurrences of 'token', and replace
// it with 'rep'. File can be ANSI or UNICODE and is overwritten. Parameters are UTF-8.
// The parsed line is of the form: [ ]token[ ]data
// Returns a pointer to rep if replacement occurred, NULL otherwise
/*
* Search for a specific 'src' substring data for all occurrences of 'token', and replace
* it with 'rep'. File can be ANSI or UNICODE and is overwritten. Parameters are UTF-8.
* The parsed line is of the form: [ ]token[ ]data
* Returns a pointer to rep if replacement occurred, NULL otherwise
*/
char* replace_in_token_data(const char* filename, const char* token, const char* src, const char* rep, BOOL dos2unix)
{
const wchar_t* outmode[] = { L"w", L"w, ccs=UTF-8", L"w, ccs=UTF-16LE" };
......
......@@ -1458,7 +1458,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
RECT DialogRect, DesktopRect;
int nDeviceIndex, fs, bt, i, nWidth, nHeight;
static DWORD DeviceNum = 0, LastRefresh = 0;
char tmp[128], str[MAX_PATH];
char tmp[128];
static UINT uBootChecked = BST_CHECKED, uQFChecked;
static BOOL first_log_display = TRUE, user_changed_label = FALSE;
loc_cmd* selected_locale;
......@@ -1786,8 +1786,8 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
break;
}
GetWindowTextU(hDeviceList, tmp, ARRAYSIZE(tmp));
_snprintf(str, ARRAYSIZE(str), get_loc_msg(MSG_001), tmp);
if (MessageBoxU(hMainDialog, str, APPLICATION_NAME, MB_OKCANCEL|MB_ICONWARNING) == IDCANCEL) {
if (MessageBoxU(hMainDialog, lmprintf(MSG_001, tmp),
APPLICATION_NAME, MB_OKCANCEL|MB_ICONWARNING) == IDCANCEL) {
format_op_in_progress = FALSE;
break;
}
......
......@@ -342,12 +342,20 @@ extern void parse_update(char* buf, size_t len);
extern BOOL WimExtractCheck(void);
extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst);
__inline static BOOL UnlockDrive(HANDLE hDrive)
static __inline BOOL UnlockDrive(HANDLE hDrive)
{
DWORD size;
return DeviceIoControl(hDrive, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &size, NULL);
}
static __inline void *_reallocf(void *ptr, size_t size)
{
void *ret = realloc(ptr, size);
if (!ret)
free(ptr);
return ret;
}
/* Basic String Array */
typedef struct {
char** Table;
......
......@@ -40,7 +40,8 @@ HWND hStatus;
#ifdef RUFUS_DEBUG
void _uprintf(const char *format, ...)
{
char buf[4096], *p = buf;
static char buf[4096];
char* p = buf;
va_list args;
int n;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册