diff --git a/Android.mk b/Android.mk index 33a43d8b..61435c31 100644 --- a/Android.mk +++ b/Android.mk @@ -329,6 +329,11 @@ endif ifeq ($(shell test $(PLATFORM_SDK_VERSION) -gt 22; echo $$?),0) LOCAL_CFLAGS += -DTW_USE_NEW_MINADBD endif +ifneq ($(TW_DEFAULT_LANGUAGE),) + LOCAL_CFLAGS += -DTW_DEFAULT_LANGUAGE=$(TW_DEFAULT_LANGUAGE) +else + LOCAL_CFLAGS += -DTW_DEFAULT_LANGUAGE=en +endif LOCAL_ADDITIONAL_DEPENDENCIES := \ dump_image \ diff --git a/data.cpp b/data.cpp index 9f2e6b5c..6b0f9713 100644 --- a/data.cpp +++ b/data.cpp @@ -50,6 +50,7 @@ #include "find_file.hpp" #include "set_metadata.h" #include +#include "gui/gui.hpp" #define DEVID_MAX 64 #define HWID_MAX 32 @@ -229,7 +230,7 @@ void DataManager::get_device_id(void) { } strcpy(device_id, "serialno"); - LOGERR("=> device id not found, using '%s'\n", device_id); + LOGINFO("=> device id not found, using '%s'\n", device_id); mConstValues.insert(make_pair("device_id", device_id)); return; } @@ -616,8 +617,10 @@ void DataManager::SetBackupFolder() } } } else { - if (PartitionManager.Fstab_Processed() != 0) - LOGERR("Storage partition '%s' not found\n", str.c_str()); + if (PartitionManager.Fstab_Processed() != 0) { + LOGINFO("Storage partition '%s' not found\n", str.c_str()); + gui_err("unable_locate_storage=Unable to locate storage device."); + } } } @@ -890,6 +893,8 @@ void DataManager::SetDefaultValues() #endif mValues.insert(make_pair("tw_mount_system_ro", make_pair("2", 1))); mValues.insert(make_pair("tw_never_show_system_ro_page", make_pair("0", 1))); + mValues.insert(make_pair("tw_language", make_pair(EXPAND(TW_DEFAULT_LANGUAGE), 1))); + LOGINFO("LANG: %s\n", EXPAND(TW_DEFAULT_LANGUAGE)); pthread_mutex_unlock(&m_valuesLock); } @@ -1033,7 +1038,7 @@ void DataManager::Output_Version(void) } FILE *fp = fopen(Path.c_str(), "w"); if (fp == NULL) { - LOGERR("Unable to open '%s'.\n", Path.c_str()); + gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(Path)(strerror(errno))); return; } strcpy(version, TW_VERSION_STR); @@ -1069,7 +1074,7 @@ void DataManager::ReadSettingsFile(void) { usleep(500000); if (!PartitionManager.Mount_Settings_Storage(false)) - LOGERR("Unable to mount %s when trying to read settings file.\n", settings_file); + gui_msg(Msg(msg::kError, "unable_to_mount=Unable to mount {1}")(settings_file)); } mkdir(mkdir_path, 0777); diff --git a/find_file.cpp b/find_file.cpp index 78db5343..7f4191e4 100644 --- a/find_file.cpp +++ b/find_file.cpp @@ -48,7 +48,7 @@ string Find_File::Find_Internal(const string& filename, const string& starting_p d = opendir(starting_path.c_str()); if (d == NULL) { - LOGERR("Find_File: Error opening '%s'\n", starting_path.c_str()); + LOGINFO("Find_File: Error opening '%s'\n", starting_path.c_str()); return ""; } diff --git a/gui/Android.mk b/gui/Android.mk index 66883a4f..84f890ca 100644 --- a/gui/Android.mk +++ b/gui/Android.mk @@ -28,7 +28,8 @@ LOCAL_SRC_FILES := \ mousecursor.cpp \ scrolllist.cpp \ patternpassword.cpp \ - textbox.cpp + textbox.cpp \ + twmsg.cpp ifneq ($(TWRP_CUSTOM_KEYBOARD),) LOCAL_SRC_FILES += $(TWRP_CUSTOM_KEYBOARD) @@ -107,6 +108,7 @@ ifeq ($(TW_CUSTOM_THEME),) ifeq ($(TWRP_NEW_THEME),true) TWRP_THEME_LOC := $(commands_recovery_local_path)/gui/theme/$(TW_THEME) TWRP_RES := $(commands_recovery_local_path)/gui/theme/common/fonts + TWRP_RES += $(commands_recovery_local_path)/gui/theme/common/languages TWRP_RES += $(commands_recovery_local_path)/gui/theme/common/$(word 1,$(subst _, ,$(TW_THEME))).xml # for future copying of used include xmls and fonts: # UI_XML := $(TWRP_THEME_LOC)/ui.xml diff --git a/gui/action.cpp b/gui/action.cpp index 46f4575d..3e27dbb4 100644 --- a/gui/action.cpp +++ b/gui/action.cpp @@ -197,6 +197,7 @@ GUIAction::GUIAction(xml_node<>* node) ADD_ACTION(cancelbackup); ADD_ACTION(checkpartitionlifetimewrites); ADD_ACTION(mountsystemtoggle); + ADD_ACTION(setlanguage); // remember actions that run in the caller thread for (mapFunc::const_iterator it = mf.begin(); it != mf.end(); ++it) @@ -340,12 +341,12 @@ int GUIAction::NotifyVarChange(const std::string& varName, const std::string& va void GUIAction::simulate_progress_bar(void) { - gui_print("Simulating actions...\n"); + gui_msg("simulating=Simulating actions..."); for (int i = 0; i < 5; i++) { if (PartitionManager.stop_backup.get_value()) { DataManager::SetValue("tw_cancel_backup", 1); - gui_print("Backup Canceled.\n"); + gui_msg("backup_cancel=Backup Canceled."); DataManager::SetValue("ui_progress", 0); PartitionManager.stop_backup.set_value(0); return; @@ -381,10 +382,10 @@ int GUIAction::flash_zip(std::string filename, int* wipe_cache) { DataManager::SetValue("tw_operation", "Configuring TWRP"); DataManager::SetValue("tw_partition", ""); - gui_print("Configuring TWRP...\n"); + gui_msg("config_twrp=Configuring TWRP..."); if (TWFunc::Exec_Cmd("/sbin/installTwrp reinstall") < 0) { - gui_print("Unable to configure TWRP with this kernel.\n"); + gui_msg("config_twrp_err=Unable to configure TWRP with this kernel."); } } } @@ -587,12 +588,12 @@ int GUIAction::mount(std::string arg) if (!simulate) PartitionManager.usb_storage_enable(); else - gui_print("Simulating actions...\n"); + gui_msg("simulating=Simulating actions..."); } else if (!simulate) { PartitionManager.Mount_By_Path(arg, true); PartitionManager.Add_MTP_Storage(arg); } else - gui_print("Simulating actions...\n"); + gui_msg("simulating=Simulating actions..."); return 0; } @@ -602,12 +603,12 @@ int GUIAction::unmount(std::string arg) if (!simulate) PartitionManager.usb_storage_disable(); else - gui_print("Simulating actions...\n"); + gui_msg("simulating=Simulating actions..."); DataManager::SetValue(TW_ACTION_BUSY, 0); } else if (!simulate) { PartitionManager.UnMount_By_Path(arg, true); } else - gui_print("Simulating actions...\n"); + gui_msg("simulating=Simulating actions..."); return 0; } @@ -615,7 +616,7 @@ int GUIAction::restoredefaultsettings(std::string arg __unused) { operation_start("Restore Defaults"); if (simulate) // Simulated so that people don't accidently wipe out the "simulation is on" setting - gui_print("Simulating actions...\n"); + gui_msg("simulating=Simulating actions..."); else { DataManager::ResetDefaults(); PartitionManager.Update_System_Details(); @@ -636,7 +637,7 @@ int GUIAction::copylog(std::string arg __unused) TWFunc::copy_file("/tmp/recovery.log", dst.c_str(), 0755); tw_set_default_metadata(dst.c_str()); sync(); - gui_print("Copied recovery log to %s.\n", DataManager::GetCurrentStoragePath().c_str()); + gui_msg(Msg("copy_log=Copied recovery log to {1}.")(DataManager::GetCurrentStoragePath())); } else simulate_progress_bar(); operation_end(0); @@ -733,7 +734,7 @@ int GUIAction::overlay(std::string arg) int GUIAction::queuezip(std::string arg __unused) { if (zip_queue_index >= 10) { - gui_print("Maximum zip queue reached!\n"); + gui_msg("max_queue=Maximum zip queue reached!"); return 0; } DataManager::GetValue("tw_filename", zip_queue[zip_queue_index]); @@ -747,7 +748,7 @@ int GUIAction::queuezip(std::string arg __unused) int GUIAction::cancelzip(std::string arg __unused) { if (zip_queue_index <= 0) { - gui_print("Minimum zip queue reached!\n"); + gui_msg("min_queue=Minimum zip queue reached!"); return 0; } else { zip_queue_index--; @@ -925,7 +926,7 @@ int GUIAction::screenshot(std::string arg __unused) chmod(path, 0666); chown(path, uid, gid); - gui_print("Screenshot was saved to %s\n", path); + gui_msg(Msg("screenshot_saved=Screenshot was saved to %s")(path)); // blink to notify that the screenshow was taken gr_color(255, 255, 255, 255); @@ -933,7 +934,7 @@ int GUIAction::screenshot(std::string arg __unused) gr_flip(); gui_forceRender(); } else { - LOGERR("Failed to take a screenshot!\n"); + gui_err("screenshot_err=Failed to take a screenshot!"); } return 0; } @@ -959,7 +960,7 @@ int GUIAction::fileexists(std::string arg) void GUIAction::reinject_after_flash() { if (DataManager::GetIntValue(TW_HAS_INJECTTWRP) == 1 && DataManager::GetIntValue(TW_INJECT_AFTER_ZIP) == 1) { - gui_print("Injecting TWRP into boot image...\n"); + gui_msg("injecttwrp=Injecting TWRP into boot image..."); if (simulate) { simulate_progress_bar(); } else { @@ -970,7 +971,7 @@ void GUIAction::reinject_after_flash() string injectcmd = "injecttwrp --dump /tmp/backup_recovery_ramdisk.img /tmp/injected_boot.img --flash bd=" + Boot->Actual_Block_Device; TWFunc::Exec_Cmd(injectcmd); } - gui_print("TWRP injection complete.\n"); + gui_msg("done=Done."); } } } @@ -993,7 +994,7 @@ int GUIAction::flash(std::string arg) ret_val = flash_zip(zip_path, &wipe_cache); TWFunc::SetPerformanceMode(false); if (ret_val != 0) { - gui_print("Error flashing zip '%s'\n", zip_path.c_str()); + gui_msg(Msg(msg::kError, "zip_err=Error installing zip file '{1}'")(zip_path)); ret_val = 1; break; } @@ -1001,7 +1002,7 @@ int GUIAction::flash(std::string arg) zip_queue_index = 0; if (wipe_cache) { - gui_print("One or more zip requested a cache wipe\nWiping cache now.\n"); + gui_msg("zip_wipe_cache=One or more zip requested a cache wipe -- Wiping cache now."); PartitionManager.Wipe_By_Path("/cache"); } @@ -1063,7 +1064,7 @@ int GUIAction::wipe(std::string arg) LOGINFO("wipe_path '%s'\n", wipe_path.c_str()); if (wipe_path == "/and-sec") { if (!PartitionManager.Wipe_Android_Secure()) { - LOGERR("Unable to wipe android secure\n"); + gui_msg("and_sec_wipe_err=Unable to wipe android secure"); ret_val = false; break; } else { @@ -1071,7 +1072,7 @@ int GUIAction::wipe(std::string arg) } } else if (wipe_path == "DALVIK") { if (!PartitionManager.Wipe_Dalvik_Cache()) { - LOGERR("Failed to wipe dalvik\n"); + gui_err("dalvik_wipe_err=Failed to wipe dalvik"); ret_val = false; break; } else { @@ -1087,7 +1088,7 @@ int GUIAction::wipe(std::string arg) } if (!skip) { if (!PartitionManager.Wipe_By_Path(wipe_path)) { - LOGERR("Unable to wipe '%s'\n", wipe_path.c_str()); + gui_msg(Msg(msg::kError, "unable_to_wipe=Unable to wipe {1}.")(wipe_path)); ret_val = false; break; } else if (wipe_path == DataManager::GetSettingsStoragePath()) { @@ -1152,6 +1153,8 @@ int GUIAction::nandroid(std::string arg) if (arg == "backup") { string Backup_Name; DataManager::GetValue(TW_BACKUP_NAME, Backup_Name); + string auto_gen = gui_lookup("auto_gen", "(Auto Generate)"); + string curr_date = gui_lookup("curr_date", "(Current Date)"); if (Backup_Name == "(Auto Generate)" || Backup_Name == "(Current Date)" || Backup_Name == "0" || Backup_Name == "(" || PartitionManager.Check_Backup_Name(true) == 0) { ret = PartitionManager.Run_Backup(); } @@ -1159,7 +1162,7 @@ int GUIAction::nandroid(std::string arg) operation_end(1); return -1; } - DataManager::SetValue(TW_BACKUP_NAME, "(Auto Generate)"); + DataManager::SetValue(TW_BACKUP_NAME, auto_gen); } else if (arg == "restore") { string Restore_Name; DataManager::GetValue("tw_restore", Restore_Name); @@ -1178,7 +1181,7 @@ int GUIAction::nandroid(std::string arg) } else { DataManager::SetValue("tw_cancel_backup", 1); - gui_print("Backup Canceled.\n"); + gui_msg("backup_cancel=Backup Canceled."); ret = 0; } operation_end(ret); @@ -1242,7 +1245,7 @@ int GUIAction::partitionsd(std::string arg __unused) int allow_partition; DataManager::GetValue(TW_ALLOW_PARTITION_SDCARD, allow_partition); if (allow_partition == 0) { - gui_print("This device does not have a real SD Card!\nAborting!\n"); + gui_err("no_real_sdcard=This device does not have a real SD Card! Aborting!"); } else { if (!PartitionManager.Partition_SDCard()) ret_val = 1; // failed @@ -1332,7 +1335,7 @@ int GUIAction::terminalcommand(std::string arg) fp = popen(command.c_str(), "r"); if (fp == NULL) { - LOGERR("Error opening command to run.\n"); + LOGERR("Error opening command to run (%s).\n", strerror(errno)); } else { int fd = fileno(fp), has_data = 0, check = 0, keep_going = -1, bytes_read = 0; struct timeval timeout; @@ -1391,12 +1394,12 @@ int GUIAction::reinjecttwrp(std::string arg __unused) { int op_status = 0; operation_start("ReinjectTWRP"); - gui_print("Injecting TWRP into boot image...\n"); + gui_msg("injecttwrp=Injecting TWRP into boot image..."); if (simulate) { simulate_progress_bar(); } else { TWFunc::Exec_Cmd("injecttwrp --dump /tmp/backup_recovery_ramdisk.img /tmp/injected_boot.img --flash"); - gui_print("TWRP injection complete.\n"); + gui_msg("done=Done."); } operation_end(op_status); @@ -1462,7 +1465,7 @@ int GUIAction::adbsideload(std::string arg __unused) simulate_progress_bar(); operation_end(0); } else { - gui_print("Starting ADB sideload feature...\n"); + gui_msg("start_sideload=Starting ADB sideload feature..."); bool mtp_was_enabled = TWFunc::Toggle_MTP(false); // wait for the adb connection @@ -1471,7 +1474,7 @@ int GUIAction::adbsideload(std::string arg __unused) if (ret != 0) { if (ret == -2) - gui_print("You need adb 1.0.32 or newer to sideload to this device.\n"); + gui_msg("need_new_adb=You need adb 1.0.32 or newer to sideload to this device."); ret = 1; // failure } else { int wipe_cache = 0; @@ -1509,7 +1512,7 @@ int GUIAction::adbsideloadcancel(std::string arg __unused) { struct stat st; DataManager::SetValue("tw_has_cancel", 0); // Remove cancel button from gui - gui_print("Cancelling ADB sideload...\n"); + gui_msg("cancel_sideload=Cancelling ADB sideload..."); LOGINFO("Signaling child sideload process to exit.\n"); // Calling stat() on this magic filename signals the minadbd // subprocess to shut down. @@ -1543,7 +1546,7 @@ int GUIAction::openrecoveryscript(std::string arg __unused) // Run those first. int reboot = 0; if (TWFunc::Path_Exists(SCRIPT_FILE_TMP)) { - gui_print("Processing AOSP recovery commands...\n"); + gui_msg("running_recovery_commands=Running Recovery Commands"); if (OpenRecoveryScript::run_script_file() == 0) { reboot = 1; op_status = 0; @@ -1551,7 +1554,7 @@ int GUIAction::openrecoveryscript(std::string arg __unused) } // Check for the ORS file in /cache and attempt to run those commands. if (OpenRecoveryScript::check_for_script_file()) { - gui_print("Processing OpenRecoveryScript file...\n"); + gui_msg("running_ors=Running OpenRecoveryScript"); if (OpenRecoveryScript::run_script_file() == 0) { reboot = 1; op_status = 0; @@ -1640,7 +1643,6 @@ int GUIAction::repair(std::string arg __unused) if (PartitionManager.Repair_By_Path(part_path, true)) { op_status = 0; // success } else { - LOGERR("Error repairing file system.\n"); op_status = 1; // fail } } @@ -1662,7 +1664,6 @@ int GUIAction::resize(std::string arg __unused) if (PartitionManager.Resize_By_Path(part_path, true)) { op_status = 0; // success } else { - LOGERR("Error resizing file system.\n"); op_status = 1; // fail } } @@ -1685,7 +1686,7 @@ int GUIAction::changefilesystem(std::string arg __unused) if (PartitionManager.Wipe_By_Path(part_path, file_system)) { op_status = 0; // success } else { - LOGERR("Error changing file system.\n"); + gui_err("change_fs_err=Error changing file system."); op_status = 1; // fail } } @@ -1826,3 +1827,16 @@ int GUIAction::mountsystemtoggle(std::string arg) operation_end(op_status); return 0; } + +int GUIAction::setlanguage(std::string arg __unused) +{ + int op_status = 0; + + operation_start("Set Language"); + PageManager::LoadLanguage(DataManager::GetStrValue("tw_language")); + PageManager::RequestReload(); + op_status = 0; // success + + operation_end(op_status); + return 0; +} diff --git a/gui/console.cpp b/gui/console.cpp index 6b38d613..b5204fb7 100644 --- a/gui/console.cpp +++ b/gui/console.cpp @@ -1,3 +1,21 @@ +/* + Copyright 2015 bigbiff/Dees_Troy TeamWin + This file is part of TWRP/TeamWin Recovery Project. + + TWRP is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TWRP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TWRP. If not, see . +*/ + // console.cpp - GUIConsole object #include @@ -24,10 +42,16 @@ extern "C" { #include "rapidxml.hpp" #include "objects.hpp" +#include "gui.hpp" +#include "twmsg.h" +#define GUI_CONSOLE_BUFFER_SIZE 512 -static std::vector gConsole; -static std::vector gConsoleColor; +size_t last_message_count = 0; +std::vector gMessages; + +std::vector gConsole; +std::vector gConsoleColor; static FILE* ors_file; extern "C" void __gui_print(const char *color, char *buf) @@ -58,22 +82,22 @@ extern "C" void __gui_print(const char *color, char *buf) gConsole.push_back(start); gConsoleColor.push_back(color); } - if (ors_file) { - fprintf(ors_file, "%s\n", buf); - fflush(ors_file); - } } extern "C" void gui_print(const char *fmt, ...) { - char buf[512]; // We're going to limit a single request to 512 bytes + char buf[GUI_CONSOLE_BUFFER_SIZE]; // We're going to limit a single request to 512 bytes va_list ap; va_start(ap, fmt); - vsnprintf(buf, 512, fmt, ap); + vsnprintf(buf, GUI_CONSOLE_BUFFER_SIZE, fmt, ap); va_end(ap); fputs(buf, stdout); + if (ors_file) { + fprintf(ors_file, "%s", buf); + fflush(ors_file); + } __gui_print("normal", buf); return; @@ -81,14 +105,18 @@ extern "C" void gui_print(const char *fmt, ...) extern "C" void gui_print_color(const char *color, const char *fmt, ...) { - char buf[512]; // We're going to limit a single request to 512 bytes + char buf[GUI_CONSOLE_BUFFER_SIZE]; // We're going to limit a single request to 512 bytes va_list ap; va_start(ap, fmt); - vsnprintf(buf, 512, fmt, ap); + vsnprintf(buf, GUI_CONSOLE_BUFFER_SIZE, fmt, ap); va_end(ap); fputs(buf, stdout); + if (ors_file) { + fprintf(ors_file, "%s", buf); + fflush(ors_file); + } __gui_print(color, buf); return; @@ -99,6 +127,70 @@ extern "C" void gui_set_FILE(FILE* f) ors_file = f; } +void gui_msg(const char* text) +{ + if (text) { + Message msg = Msg(text); + gui_msg(msg); + } +} + +void gui_warn(const char* text) +{ + if (text) { + Message msg = Msg(msg::kWarning, text); + gui_msg(msg); + } +} + +void gui_err(const char* text) +{ + if (text) { + Message msg = Msg(msg::kError, text); + gui_msg(msg); + } +} + +void gui_highlight(const char* text) +{ + if (text) { + Message msg = Msg(msg::kHighlight, text); + gui_msg(msg); + } +} + +void gui_msg(Message msg) +{ + std::string output = msg; + output += "\n"; + fputs(output.c_str(), stdout); + if (ors_file) { + fprintf(ors_file, "%s", output.c_str()); + fflush(ors_file); + } + gMessages.push_back(msg); +} + +void GUIConsole::Translate_Now() { + size_t message_count = gMessages.size(); + if (message_count <= last_message_count) + return; + + for (size_t m = last_message_count; m < message_count; m++) { + std::string message = gMessages[m]; + std::string color = "normal"; + if (gMessages[m].GetKind() == msg::kError) + color = "error"; + else if (gMessages[m].GetKind() == msg::kHighlight) + color = "highlight"; + else if (gMessages[m].GetKind() == msg::kWarning) + color = "warning"; + gConsole.push_back(message); + gConsoleColor.push_back(color); + } + last_message_count = message_count; +} + GUIConsole::GUIConsole(xml_node<>* node) : GUIScrollList(node) { xml_node<>* child; @@ -160,6 +252,7 @@ int GUIConsole::RenderSlideout(void) int GUIConsole::RenderConsole(void) { + Translate_Now(); AddLines(&gConsole, &gConsoleColor, &mLastCount, &rConsole, &rConsoleColor); GUIScrollList::Render(); diff --git a/gui/devices/common/res/languages/en.xml b/gui/devices/common/res/languages/en.xml new file mode 100644 index 00000000..c11176a7 --- /dev/null +++ b/gui/devices/common/res/languages/en.xml @@ -0,0 +1,226 @@ + + + + English + + + + + + + + + + System + System Image + Vendor + Vendor Image + Boot + Recovery + Cache + Data + SDCard + Internal Storage + Micro SDCard + USB OTG + Android Secure + Dalvik / ART Cache + + SD-EXT + + + Install + + + Kernel does not have support for reading SELinux contexts. + Full SELinux support is present. + No SELinux support (no libselinux). + MTP Enabled + MTP Crashed, not starting MTP on boot. + Rebooting... + Successfully decrypted with default password. + Unable to decrypt with default password. You may need to perform a Format Data. + Generating MD5 + + * Generating md5... + * MD5 Created. + * MD5 Error! + * Error computing MD5. + * MD5 Created. + (Current Date) + (Auto Generate) + Unable to locate '{1}' partition for backup calculations. + No partitions selected for backup. + * Total number of partitions to back up: {1} + * Total size of all data: {1}MB + * Available space: {1}MB + Unable to locate storage device. + Not enough free space on storage. + [BACKUP STARTED] + * Backup Folder: {1} + Failed to make backup folder. + Average backup rate for file systems: {1} MB/sec + Average backup rate for imaged drives: {1} MB/sec + [{1} MB TOTAL BACKED UP] + [BACKUP COMPLETED IN {1} SECONDS] + [RESTORE STARTED] + Restore folder: '%s' + + [{1} done ({2} seconds)] + Verifying MD5 + Skipping MD5 check based on user setting. + Calculating restore details... + Cannot restore %s -- mounted read only. + Unable to locate '{1}' partition for restoring. + No partitions selected for restore. + Restoring {1} partitions... + Total restore size is {1}MB + Updating System Details + [RESTORE COMPLETED IN {1} SECONDS] + + Error opening: '{1}' ({2}) + Unable to locate partition by backup name: '{1}' + Unable to find partition for path '{1}' + Updating partition details... + ...done + Wiping Dalvik Cache Directories... + Cleaned: {1}... + -- Dalvik Cache Directories Wipe Complete! + No android secure partitions found. + Unable to locate {1}. + Wiping internal storage -- /data/media... + Unable to mount {1} + Unable to mount internal_storage + Unable to mount storage + Failed to decrypt data. + No crypto support was compiled into this build. + Data successfully decrypted, new block device: '{1}' + Done. + Partitioning SD Card... + Unable to locate device to partition. + EXT + Swap size is larger than sdcard size. + Removing partition table... + Unable to remove partition table. + Creating {1} partition... + Unable to create {1} partition. + Formatting sd-ext as {1}... + Partitioning complete. + Unable to open '{1}'. + MTP already enabled + Failed to enable MTP + MTP support not included + [IMAGE FLASH STARTED] + Image to flash: '{1}' + Unable to locate '{1}' partition for flashing. + No partitions selected for flashing. + Too many partitions selected for flashing. + Invalid flash partition specified. + IMAGE FLASH COMPLETED] + Wiping {1} + {1} does not exist! Cannot repair! + Unable to repair {1}. + Could not mount /data and unable to find crypto footer. + + Can not create '{1}' folder ({2}). + + Failed to mount '{1}' ({2}) + + Failed to unmount '{1}' ({2}) + Cannot resize {1}. + Repairing {1} before resizing. + Unable to resize {1}. + No md5 file found for '{1}'. Please unselect Enable MD5 verification to restore. + MD5 failed to match on '{1}'. + Restoring + You may need to reboot recovery to be able to use /data again. + Unable to format to remove encryption. + Formatting {1} using {2}... + Unable to wipe {1}. + Removing all files under '{1}' + Wiping data without wiping /data/media ... + Backing up {1}... + Backing Up + Backup file size for '%s' is 0 bytes. + WARNING: This /data backup was made with {1} file system! The backup may not boot unless you change back to {1}. + Restoring {1}... + Restoring + Unable to recreate {1} folder. + Size of image is larger than target device + Flashing {1}... + Backup folder set to '{1}' + Unable to locate backup '{1}' + Setting restore options: '{1}': + MD5 check skip is on + Unable to use OpenRecoveryScript to restore an encrypted backup. + Mounting + Unmounting + Mounted '{1}' + Unmounted '{1}' + Setting '{1}' to '{2}' + Setting '{1}' to empty + Making Directory + Making directory: '{1}' + Running Command + ADB Sideload + Starting ADB sideload feature... + You need adb 1.0.32 or newer to sideload to this device. + No password provided. + Done processing script file + Injecting TWRP into boot image... + Error installing zip file '{1}' + Installing zip file '{1}' + Setting backup options: + Compression is on + MD5 Generation is off + Backup Failed + Backup complete! + Running Recovery Commands + Recovery Commands Complete + Running OpenRecoveryScript + OpenRecoveryScript Complete + Could not find '{1}' in the zip file. + Checking for MD5 file... + Failed to map file '{1}' + Verifying zip signature... + Zip signature verification failed! + Zip signature verified successfully. + Zip file is corrupt! + Skipping MD5 check: no MD5 file found + MD5 does not match + MD5 matched + {1} process ended with signal: {2} + {1} process ended with ERROR: {2} + Installing HTC Dumlock to system... + Restoring original boot... + Reflashing recovery to boot... + Running {1} script... + Renamed stock recovery file in /system to prevent the stock ROM from replacing TWRP. + Breaking backup file into multiple archives... + Error creating backup. + Error during restore process. + Splitting thread ID {1} into archive {2} + %llu of %llu files, %i%% + %lluMB of %lluMB, %i%% + Attempting to decrypt data partition via command line. + Failed to load base packages. + Simulating actions... + Backup Canceled. + Configuring TWRP... + Unable to configure TWRP with this kernel. + Copied recovery log to {1}. + Maximum zip queue reached! + Minimum zip queue reached! + Failed to take a screenshot! + One or more zip requested a cache wipe -- Wiping cache now. + Unable to wipe android secure + Failed to wipe dalvik + (Auto Generate) + (Current Date) + Backup name is too long. + Backup name '{1}' contains invalid character: '{1}' + A backup with this name already exists. + This device does not have a real SD Card! Aborting! + Cancelling ADB sideload... + Error changing file system. + + diff --git a/gui/devices/common/res/languages/es.xml b/gui/devices/common/res/languages/es.xml new file mode 100644 index 00000000..ad5c54a7 --- /dev/null +++ b/gui/devices/common/res/languages/es.xml @@ -0,0 +1,13 @@ + + + + EspaƱol + + + + + + + Instalar + + diff --git a/gui/devices/common/res/languages/fi.xml b/gui/devices/common/res/languages/fi.xml new file mode 100644 index 00000000..0c4f5bc8 --- /dev/null +++ b/gui/devices/common/res/languages/fi.xml @@ -0,0 +1,13 @@ + + + + Suomi + + + + + + + Asenna + + diff --git a/gui/gui.cpp b/gui/gui.cpp index 31b61be6..78e8a7e0 100644 --- a/gui/gui.cpp +++ b/gui/gui.cpp @@ -517,13 +517,19 @@ static void ors_command_read() fprintf(orsout, "%s", result); LOGINFO("Command cannot be performed, operation in progress.\n"); } else { - if (gui_console_only() == 0) { + if (strlen(command) == 11 && strncmp(command, "dumpstrings", 11) == 0) { + // This cannot be done safely with gui_console_only because gui_console_only updates mCurrentSet + // which makes the resources that we are trying to read unreachable. + gui_set_FILE(orsout); + PageManager::GetResources()->DumpStrings(); + gui_set_FILE(NULL); + } else if (gui_console_only() == 0) { LOGINFO("Console started successfully\n"); gui_set_FILE(orsout); if (strlen(command) > 11 && strncmp(command, "runscript", 9) == 0) { char* filename = command + 11; if (OpenRecoveryScript::copy_script_file(filename) == 0) { - LOGERR("Unable to copy script file\n"); + LOGINFO("Unable to copy script file\n"); } else { OpenRecoveryScript::run_script_file(); } @@ -534,7 +540,7 @@ static void ors_command_read() gui_print("%s = %s\n", varname, temp.c_str()); } else if (strlen(command) > 9 && strncmp(command, "decrypt", 7) == 0) { char* pass = command + 8; - gui_print("Attempting to decrypt data partition via command line.\n"); + gui_msg("decrypt_cmd=Attempting to decrypt data partition via command line."); if (PartitionManager.Decrypt_Device(pass) == 0) { set_page_done = 1; } @@ -753,15 +759,39 @@ std::string gui_parse_text(std::string str) { // This function parses text for DataManager values encompassed by %value% in the XML // and string resources (%@resource_name%) - size_t pos = 0; + size_t pos = 0, next, end; while (1) { - size_t next = str.find('%', pos); + next = str.find("{@", pos); + if (next == std::string::npos) + break; + + end = str.find('}', next + 1); + if (end == std::string::npos) + break; + + std::string var = str.substr(next + 2, (end - next) - 2); + str.erase(next, (end - next) + 1); + + size_t default_loc = var.find('=', 0); + std::string lookup; + if (default_loc == std::string::npos) { + str.insert(next, PageManager::GetResources()->FindString(var)); + } else { + lookup = var.substr(0, default_loc); + std::string default_string = var.substr(default_loc + 1, var.size() - default_loc - 1); + str.insert(next, PageManager::GetResources()->FindString(lookup, default_string)); + } + } + pos = 0; + while (1) + { + next = str.find('%', pos); if (next == std::string::npos) return str; - size_t end = str.find('%', next + 1); + end = str.find('%', next + 1); if (end == std::string::npos) return str; @@ -787,6 +817,10 @@ std::string gui_parse_text(std::string str) } } +std::string gui_lookup(const std::string& resource_name, const std::string& default_value) { + return PageManager::GetResources()->FindString(resource_name, default_value); +} + extern "C" int gui_init(void) { gr_init(); @@ -828,7 +862,7 @@ extern "C" int gui_loadResources(void) { if (PageManager::LoadPackage("TWRP", TWRES "ui.xml", "decrypt")) { - LOGERR("Failed to load base packages.\n"); + gui_err("base_pkg_err=Failed to load base packages."); goto error; } else @@ -849,10 +883,9 @@ extern "C" int gui_loadResources(void) retry_count--; } - if (!PartitionManager.Mount_Settings_Storage(false)) + if (!PartitionManager.Mount_Settings_Storage(true)) { - LOGERR("Unable to mount %s during GUI startup.\n", - theme_path.c_str()); + LOGINFO("Unable to mount %s during GUI startup.\n", theme_path.c_str()); check = 1; } } @@ -863,7 +896,7 @@ extern "C" int gui_loadResources(void) #endif // ifndef TW_OEM_BUILD if (PageManager::LoadPackage("TWRP", TWRES "ui.xml", "main")) { - LOGERR("Failed to load base packages.\n"); + gui_err("base_pkg_err=Failed to load base packages."); goto error; } #ifndef TW_OEM_BUILD @@ -886,7 +919,7 @@ extern "C" int gui_loadCustomResources(void) { #ifndef TW_OEM_BUILD if (!PartitionManager.Mount_Settings_Storage(false)) { - LOGERR("Unable to mount settings storage during GUI startup.\n"); + LOGINFO("Unable to mount settings storage during GUI startup.\n"); return -1; } @@ -898,7 +931,7 @@ extern "C" int gui_loadCustomResources(void) if (PageManager::ReloadPackage("TWRP", theme_path)) { // Custom theme failed to load, try to load stock theme if (PageManager::ReloadPackage("TWRP", TWRES "ui.xml")) { - LOGERR("Failed to load base packages.\n"); + gui_err("base_pkg_err=Failed to load base packages."); goto error; } } diff --git a/gui/gui.hpp b/gui/gui.hpp new file mode 100644 index 00000000..afcd9b0a --- /dev/null +++ b/gui/gui.hpp @@ -0,0 +1,33 @@ +/* + Copyright 2015 bigbiff/Dees_Troy TeamWin + This file is part of TWRP/TeamWin Recovery Project. + + TWRP is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TWRP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TWRP. If not, see . +*/ + +#ifndef _GUI_HPP_HEADER +#define _GUI_HPP_HEADER + +#include "twmsg.h" + +void gui_msg(const char* text); +void gui_warn(const char* text); +void gui_err(const char* text); +void gui_highlight(const char* text); +void gui_msg(Message msg); + +std::string gui_parse_text(std::string inText); +std::string gui_lookup(const std::string& resource_name, const std::string& default_value); + +#endif //_GUI_HPP_HEADER diff --git a/gui/listbox.cpp b/gui/listbox.cpp index d2973bb6..eeddff95 100644 --- a/gui/listbox.cpp +++ b/gui/listbox.cpp @@ -26,6 +26,9 @@ extern "C" { #include "rapidxml.hpp" #include "objects.hpp" #include "../data.hpp" +#include "pages.hpp" + +extern std::vector Language_List; GUIListBox::GUIListBox(xml_node<>* node) : GUIScrollList(node) { @@ -56,6 +59,21 @@ GUIListBox::GUIListBox(xml_node<>* node) : GUIScrollList(node) DataManager::SetValue(mVariable, attr->value()); // Get the currently selected value for the list DataManager::GetValue(mVariable, currentValue); + if (mVariable == "tw_language") { + std::vector::iterator iter; + for (iter = Language_List.begin(); iter != Language_List.end(); iter++) { + ListItem data; + data.displayName = (*iter).displayvalue; + data.variableValue = (*iter).filename; + data.action = NULL; + if (currentValue == (*iter).filename) { + data.selected = 1; + DataManager::SetValue("tw_language_display", (*iter).displayvalue); + } else + data.selected = 0; + mListItems.push_back(data); + } + } } else allowSelection = false; // allows using listbox as a read-only list or menu diff --git a/gui/objects.hpp b/gui/objects.hpp index 3d217c45..438905b9 100644 --- a/gui/objects.hpp +++ b/gui/objects.hpp @@ -43,6 +43,15 @@ using namespace rapidxml; #define TW_Y_OFFSET 0 #endif +struct translate_later_struct { + std::string resource_name; // Name of the string resource for looking up + std::string default_value; // Default in case we don't find the string resource + std::string color; // Color for the console... normal, highlight, warning, error + std::string format; // Formatted extra variables like %i, %s + std::string text; // Final, translated, formatted text + bool inline_format; // Indicates if the final text includes an inlined format variable +}; + class RenderObject { public: @@ -356,6 +365,7 @@ protected: int cancelbackup(std::string arg); int checkpartitionlifetimewrites(std::string arg); int mountsystemtoggle(std::string arg); + int setlanguage(std::string arg); int simulate; }; @@ -734,6 +744,7 @@ public: virtual size_t GetItemCount(); virtual void RenderItem(size_t itemindex, int yPos, bool selected); virtual void NotifySelect(size_t item_selected); + static void Translate_Now(); protected: enum SlideoutState { diff --git a/gui/pages.cpp b/gui/pages.cpp index 0511b1ab..13f3bd7b 100644 --- a/gui/pages.cpp +++ b/gui/pages.cpp @@ -33,6 +33,7 @@ #include #include #include "../twrp-functions.hpp" +#include "../partitions.hpp" #include @@ -50,6 +51,14 @@ extern "C" { extern int gGuiRunning; +// From ../twrp.cpp +extern bool datamedia; + +// From console.cpp +extern size_t last_message_count; +extern std::vector gConsole; +extern std::vector gConsoleColor; + std::map PageManager::mPageSets; PageSet* PageManager::mCurrentSet; PageSet* PageManager::mBaseSet = NULL; @@ -57,6 +66,7 @@ MouseCursor *PageManager::mMouseCursor = NULL; HardwareKeyboard *PageManager::mHardwareKeyboard = NULL; bool PageManager::mReloadTheme = false; std::string PageManager::mStartPage = "main"; +std::vector Language_List; int tw_x_offset = 0; int tw_y_offset = 0; @@ -670,7 +680,48 @@ PageSet::~PageSet() delete mResources; } -int PageSet::Load(ZipArchive* package, char* xmlFile) +int PageSet::LoadLanguage(char* languageFile, ZipArchive* package) +{ + xml_document<> lang; + xml_node<>* parent; + xml_node<>* child; + std::string resource_source; + + if (languageFile) { + printf("parsing languageFile\n"); + lang.parse<0>(languageFile); + printf("parsing languageFile done\n"); + } else { + return -1; + } + + parent = lang.first_node("language"); + if (!parent) { + LOGERR("Unable to locate language node in language file.\n"); + lang.clear(); + return -1; + } + + child = parent->first_node("display"); + if (child) { + DataManager::SetValue("tw_language_display", child->value()); + resource_source = child->value(); + } else { + LOGERR("language file does not have a display value set\n"); + DataManager::SetValue("tw_language_display", "Not Set"); + resource_source = languageFile; + } + + child = parent->first_node("resources"); + if (child) + mResources->LoadResources(child, package, resource_source); + else + return -1; + lang.clear(); + return 0; +} + +int PageSet::Load(ZipArchive* package, char* xmlFile, char* languageFile) { xml_document<> mDoc; xml_node<>* parent; @@ -735,10 +786,14 @@ int PageSet::Load(ZipArchive* package, char* xmlFile) } else { LOGINFO("XML contains no details tag, no scaling will be applied.\n"); } + + if (languageFile) + LoadLanguage(languageFile, package); + LOGINFO("Loading resources...\n"); child = parent->first_node("resources"); if (child) - mResources->LoadResources(child, package); + mResources->LoadResources(child, package, "theme"); LOGINFO("Loading variables...\n"); child = parent->first_node("variables"); @@ -831,7 +886,7 @@ int PageSet::CheckInclude(ZipArchive* package, xml_document<> *parentDoc) LOGINFO("Loading included resources...\n"); child = parent->first_node("resources"); if (child) - mResources->LoadResources(child, package); + mResources->LoadResources(child, package, "theme"); LOGINFO("Loading included variables...\n"); child = parent->first_node("variables"); @@ -1121,6 +1176,11 @@ int PageSet::NotifyVarChange(std::string varName, std::string value) return (mCurrentPage ? mCurrentPage->NotifyVarChange(varName, value) : -1); } +void PageSet::AddStringResource(std::string resource_source, std::string resource_name, std::string value) +{ + mResources->AddStringResource(resource_source, resource_name, value); +} + char* PageManager::LoadFileToBuffer(std::string filename, ZipArchive* package) { size_t len; char* buffer = NULL; @@ -1181,12 +1241,96 @@ char* PageManager::LoadFileToBuffer(std::string filename, ZipArchive* package) { return buffer; } +void PageManager::LoadLanguageListDir(string dir) { + if (!TWFunc::Path_Exists(dir)) { + LOGERR("LoadLanguageListDir '%s' path not found\n", dir.c_str()); + return; + } + + DIR *d = opendir(dir.c_str()); + struct dirent *p; + + if (d == NULL) { + LOGERR("LoadLanguageListDir error opening dir: '%s', %s\n", dir.c_str(), strerror(errno)); + return; + } + + while ((p = readdir(d))) { + if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..") || strlen(p->d_name) < 5) + continue; + + string file = p->d_name; + if (file.substr(strlen(p->d_name) - 4) != ".xml") + continue; + string path = dir + p->d_name; + string file_no_extn = file.substr(0, strlen(p->d_name) - 4); + struct language_struct language_entry; + language_entry.filename = file_no_extn; + char* xmlFile = PageManager::LoadFileToBuffer(dir + p->d_name, NULL); + if (xmlFile == NULL) { + LOGERR("LoadLanguageListDir unable to load '%s'\n", language_entry.filename.c_str()); + continue; + } + xml_document<> *doc = new xml_document<>(); + doc->parse<0>(xmlFile); + + xml_node<>* parent = doc->first_node("language"); + if (!parent) { + LOGERR("Invalid language XML file '%s'\n", language_entry.filename.c_str()); + } else { + xml_node<>* child = parent->first_node("display"); + if (child) { + language_entry.displayvalue = child->value(); + } else { + LOGERR("No display value for '%s'\n", language_entry.filename.c_str()); + language_entry.displayvalue = language_entry.filename; + } + Language_List.push_back(language_entry); + } + doc->clear(); + delete doc; + free(xmlFile); + } + closedir(d); +} + +void PageManager::LoadLanguageList(ZipArchive* package) { + Language_List.clear(); + if (TWFunc::Path_Exists(TWRES "customlanguages")) + TWFunc::removeDir(TWRES "customlanguages", true); + if (package) { + TWFunc::Recursive_Mkdir(TWRES "customlanguages"); + struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default + mzExtractRecursive(package, "languages", TWRES "customlanguages/", ×tamp, NULL, NULL, NULL); + LoadLanguageListDir(TWRES "customlanguages/"); + } else { + LoadLanguageListDir(TWRES "languages/"); + } +} + +void PageManager::LoadLanguage(string filename) { + string actual_filename; + if (TWFunc::Path_Exists(TWRES "customlanguages/" + filename + ".xml")) + actual_filename = TWRES "customlanguages/" + filename + ".xml"; + else + actual_filename = TWRES "languages/" + filename + ".xml"; + char* xmlFile = PageManager::LoadFileToBuffer(actual_filename, NULL); + if (xmlFile == NULL) + LOGERR("Unable to load '%s'\n", actual_filename.c_str()); + else { + mCurrentSet->LoadLanguage(xmlFile, NULL); + free(xmlFile); + } + PartitionManager.Translate_Partition_Display_Names(); +} + int PageManager::LoadPackage(std::string name, std::string package, std::string startpage) { int fd; ZipArchive zip, *pZip = NULL; long len; char* xmlFile = NULL; + char* languageFile = NULL; PageSet* pageSet = NULL; int ret; MemMapping map; @@ -1201,6 +1345,8 @@ int PageManager::LoadPackage(std::string name, std::string package, std::string LOGINFO("Load XML directly\n"); tw_x_offset = TW_X_OFFSET; tw_y_offset = TW_Y_OFFSET; + LoadLanguageList(NULL); + languageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL); } else { @@ -1220,6 +1366,8 @@ int PageManager::LoadPackage(std::string name, std::string package, std::string } pZip = &zip; package = "ui.xml"; + LoadLanguageList(pZip); + languageFile = LoadFileToBuffer("languages/en.xml", pZip); } xmlFile = LoadFileToBuffer(package, pZip); @@ -1230,8 +1378,11 @@ int PageManager::LoadPackage(std::string name, std::string package, std::string // Before loading, mCurrentSet must be the loading package so we can find resources pageSet = mCurrentSet; mCurrentSet = new PageSet(xmlFile); - - ret = mCurrentSet->Load(pZip, xmlFile); + ret = mCurrentSet->Load(pZip, xmlFile, languageFile); + if (languageFile) { + free(languageFile); + languageFile = NULL; + } if (ret == 0) { mCurrentSet->SetPage(startpage); @@ -1253,6 +1404,8 @@ int PageManager::LoadPackage(std::string name, std::string package, std::string sysReleaseMap(&map); } free(xmlFile); + if (languageFile) + free(languageFile); return ret; error: @@ -1313,7 +1466,7 @@ int PageManager::ReloadPackage(std::string name, std::string package) if (LoadPackage(name, package, mStartPage) != 0) { - LOGERR("Failed to load package '%s'.\n", package.c_str()); + LOGINFO("Failed to load package '%s'.\n", package.c_str()); mPageSets.insert(std::pair(name, set)); return -1; } @@ -1322,6 +1475,7 @@ int PageManager::ReloadPackage(std::string name, std::string package) if (mBaseSet == set) mBaseSet = mCurrentSet; delete set; + GUIConsole::Translate_Now(); return 0; } @@ -1364,6 +1518,18 @@ int PageManager::RunReload() { ret_val = 1; } } + if (ret_val == 0) { + if (DataManager::GetStrValue("tw_language") != "en.xml") { + LOGINFO("Loading language '%s'\n", DataManager::GetStrValue("tw_language").c_str()); + LoadLanguage(DataManager::GetStrValue("tw_language")); + } + } + + // This makes the console re-translate + last_message_count = 0; + gConsole.clear(); + gConsoleColor.clear(); + return ret_val; } @@ -1511,6 +1677,12 @@ int PageManager::NotifyVarChange(std::string varName, std::string value) return (mCurrentSet ? mCurrentSet->NotifyVarChange(varName, value) : -1); } +void PageManager::AddStringResource(std::string resource_source, std::string resource_name, std::string value) +{ + if (mCurrentSet) + mCurrentSet->AddStringResource(resource_source, resource_name, value); +} + extern "C" void gui_notifyVarChange(const char *name, const char* value) { if (!gGuiRunning) diff --git a/gui/pages.hpp b/gui/pages.hpp index 018c2cab..5dcc9e0b 100644 --- a/gui/pages.hpp +++ b/gui/pages.hpp @@ -6,7 +6,9 @@ #include "../minzip/Zip.h" #include #include +#include #include "rapidxml.hpp" +#include "gui.hpp" using namespace rapidxml; enum TOUCH_STATE { @@ -27,12 +29,18 @@ struct COLOR { : red(r), green(g), blue(b), alpha(a) {} }; +struct language_struct { + std::string filename; + std::string displayvalue; +}; + +extern std::vector Language_List; + // Utility Functions int ConvertStrToColor(std::string str, COLOR* color); int gui_forceRender(void); int gui_changePage(std::string newPage); int gui_changeOverlay(std::string newPage); -std::string gui_parse_text(string inText); class Resource; class ResourceManager; @@ -82,7 +90,8 @@ public: virtual ~PageSet(); public: - int Load(ZipArchive* package, char* xmlFile); + int LoadLanguage(char* languageFile, ZipArchive* package); + int Load(ZipArchive* package, char* xmlFile, char* languageFile); int CheckInclude(ZipArchive* package, xml_document<> *parentDoc); Page* FindPage(std::string name); @@ -103,6 +112,7 @@ public: int NotifyVarChange(std::string varName, std::string value); std::vector*> styles; + void AddStringResource(std::string resource_source, std::string resource_name, std::string value); protected: int LoadPages(xml_node<>* pages); @@ -121,6 +131,8 @@ class PageManager public: // Used by GUI static char* LoadFileToBuffer(std::string filename, ZipArchive* package); + static void LoadLanguageList(ZipArchive* package); + static void LoadLanguage(std::string filename); static int LoadPackage(std::string name, std::string package, std::string startpage); static PageSet* SelectPackage(std::string name); static int ReloadPackage(std::string name, std::string package); @@ -155,9 +167,14 @@ public: static HardwareKeyboard *GetHardwareKeyboard(); static xml_node<>* FindStyle(std::string name); + static void AddStringResource(std::string resource_source, std::string resource_name, std::string value); protected: static PageSet* FindPackage(std::string name); + static void LoadLanguageListDir(std::string dir); + static void Translate_Partition(const char* path, const char* resource_name, const char* default_value); + static void Translate_Partition(const char* path, const char* resource_name, const char* default_value, const char* storage_resource_name, const char* storage_default_value); + static void Translate_Partition_Display_Names(); protected: static std::map mPageSets; diff --git a/gui/resources.cpp b/gui/resources.cpp index 253d438f..a8f41991 100644 --- a/gui/resources.cpp +++ b/gui/resources.cpp @@ -99,6 +99,13 @@ void Resource::CheckAndScaleImage(gr_surface source, gr_surface* destination, in FontResource::FontResource(xml_node<>* node, ZipArchive* pZip) : Resource(node, pZip) +{ + origFontSize = 0; + origFont = NULL; + LoadFont(node, pZip); +} + +void FontResource::LoadFont(xml_node<>* node, ZipArchive* pZip) { std::string file; xml_attribute<>* attr; @@ -116,12 +123,21 @@ FontResource::FontResource(xml_node<>* node, ZipArchive* pZip) if(file.size() >= 4 && file.compare(file.size()-4, 4, ".ttf") == 0) { m_type = TYPE_TTF; + int font_size = 0; - attr = node->first_attribute("size"); - if(!attr) - return; + if (origFontSize != 0) { + attr = node->first_attribute("scale"); + if (attr == NULL) + return; + font_size = origFontSize * atoi(attr->value()) / 100; + } else { + attr = node->first_attribute("size"); + if (attr == NULL) + return; + font_size = scale_theme_min(atoi(attr->value())); + origFontSize = font_size; + } - int size = scale_theme_min(atoi(attr->value())); int dpi = 300; attr = node->first_attribute("dpi"); @@ -130,13 +146,13 @@ FontResource::FontResource(xml_node<>* node, ZipArchive* pZip) if (ExtractResource(pZip, "fonts", file, "", TMP_RESOURCE_NAME) == 0) { - mFont = gr_ttf_loadFont(TMP_RESOURCE_NAME, size, dpi); + mFont = gr_ttf_loadFont(TMP_RESOURCE_NAME, font_size, dpi); unlink(TMP_RESOURCE_NAME); } else { file = std::string(TWRES "fonts/") + file; - mFont = gr_ttf_loadFont(file.c_str(), size, dpi); + mFont = gr_ttf_loadFont(file.c_str(), font_size, dpi); } } else @@ -145,13 +161,28 @@ FontResource::FontResource(xml_node<>* node, ZipArchive* pZip) } } +void FontResource::DeleteFont() { + if(mFont) + gr_ttf_freeFont(mFont); + mFont = NULL; + if(origFont) + gr_ttf_freeFont(origFont); + origFont = NULL; +} + +void FontResource::Override(xml_node<>* node, ZipArchive* pZip) { + if (!origFont) { + origFont = mFont; + } else if (mFont) { + gr_ttf_freeFont(mFont); + mFont = NULL; + } + LoadFont(node, pZip); +} + FontResource::~FontResource() { - if(mFont) - { - if(m_type == TYPE_TTF) - gr_ttf_freeFont(mFont); - } + DeleteFont(); } ImageResource::ImageResource(xml_node<>* node, ZipArchive* pZip) @@ -255,17 +286,58 @@ AnimationResource* ResourceManager::FindAnimation(const std::string& name) const std::string ResourceManager::FindString(const std::string& name) const { - std::map::const_iterator it = mStrings.find(name); - if (it != mStrings.end()) - return it->second; + if (this != NULL) { + std::map::const_iterator it = mStrings.find(name); + if (it != mStrings.end()) + return it->second.value; + LOGERR("String resource '%s' not found. No default value.\n", name.c_str()); + PageManager::AddStringResource("NO DEFAULT", name, "[" + name + ("]")); + } else { + LOGINFO("String resources not loaded when looking for '%s'. No default value.\n", name.c_str()); + } return "[" + name + ("]"); } +std::string ResourceManager::FindString(const std::string& name, const std::string& default_string) const +{ + if (this != NULL) { + std::map::const_iterator it = mStrings.find(name); + if (it != mStrings.end()) + return it->second.value; + LOGERR("String resource '%s' not found. Using default value.\n", name.c_str()); + PageManager::AddStringResource("DEFAULT", name, default_string); + } else { + LOGINFO("String resources not loaded when looking for '%s'. Using default value.\n", name.c_str()); + } + return default_string; +} + +void ResourceManager::DumpStrings() const +{ + if (this == NULL) { + gui_print("No string resources\n"); + return; + } + std::map::const_iterator it; + gui_print("Dumping all strings:\n"); + for (it = mStrings.begin(); it != mStrings.end(); it++) + gui_print("source: %s: '%s' = '%s'\n", it->second.source.c_str(), it->first.c_str(), it->second.value.c_str()); + gui_print("Done dumping strings\n"); +} + ResourceManager::ResourceManager() { } -void ResourceManager::LoadResources(xml_node<>* resList, ZipArchive* pZip) +void ResourceManager::AddStringResource(std::string resource_source, std::string resource_name, std::string value) +{ + string_resource_struct res; + res.source = resource_source; + res.value = value; + mStrings[resource_name] = res; +} + +void ResourceManager::LoadResources(xml_node<>* resList, ZipArchive* pZip, std::string resource_source) { if (!resList) return; @@ -290,6 +362,26 @@ void ResourceManager::LoadResources(xml_node<>* resList, ZipArchive* pZip) delete res; } } + else if (type == "fontoverride") + { + if (mFonts.size() != 0 && child && child->first_attribute("name")) { + string FontName = child->first_attribute("name")->value(); + size_t font_count = mFonts.size(), i; + bool found = false; + + for (i = 0; i < font_count; i++) { + if (mFonts[i]->GetName() == FontName) { + mFonts[i]->Override(child, pZip); + found = true; + break; + } + } + if (!found) { + LOGERR("Unable to locate font '%s' for override.\n", FontName.c_str()); + } + } else if (mFonts.size() != 0) + LOGERR("Unable to locate font name for type fontoverride.\n"); + } else if (type == "image") { ImageResource* res = new ImageResource(child, pZip); @@ -312,9 +404,12 @@ void ResourceManager::LoadResources(xml_node<>* resList, ZipArchive* pZip) } else if (type == "string") { - if (xml_attribute<>* attr = child->first_attribute("name")) - mStrings[attr->value()] = child->value(); - else + if (xml_attribute<>* attr = child->first_attribute("name")) { + string_resource_struct res; + res.source = resource_source; + res.value = child->value(); + mStrings[attr->value()] = res; + } else error = true; } else diff --git a/gui/resources.hpp b/gui/resources.hpp index 0eb32674..ce06d967 100644 --- a/gui/resources.hpp +++ b/gui/resources.hpp @@ -6,6 +6,7 @@ #include #include #include +#include "rapidxml.hpp" struct ZipArchive; @@ -49,10 +50,19 @@ public: public: void* GetResource() { return this ? mFont : NULL; } int GetHeight() { return gr_getMaxFontHeight(this ? mFont : NULL); } + void Override(xml_node<>* node, ZipArchive* pZip); protected: void* mFont; Type m_type; + +private: + void LoadFont(xml_node<>* node, ZipArchive* pZip); + void DeleteFont(); + +private: + int origFontSize; + void* origFont; }; class ImageResource : public Resource @@ -92,19 +102,26 @@ class ResourceManager public: ResourceManager(); virtual ~ResourceManager(); - void LoadResources(xml_node<>* resList, ZipArchive* pZip); + void AddStringResource(std::string resource_source, std::string resource_name, std::string value); + void LoadResources(xml_node<>* resList, ZipArchive* pZip, std::string resource_source); public: FontResource* FindFont(const std::string& name) const; ImageResource* FindImage(const std::string& name) const; AnimationResource* FindAnimation(const std::string& name) const; std::string FindString(const std::string& name) const; + std::string FindString(const std::string& name, const std::string& default_string) const; + void DumpStrings() const; private: + struct string_resource_struct { + std::string value; + std::string source; + }; std::vector mFonts; std::vector mImages; std::vector mAnimations; - std::map mStrings; + std::map mStrings; }; #endif // _RESOURCE_HEADER diff --git a/gui/theme/common/landscape.xml b/gui/theme/common/landscape.xml old mode 100644 new mode 100755 index a6b38a25..938c8548 --- a/gui/theme/common/landscape.xml +++ b/gui/theme/common/landscape.xml @@ -193,7 +193,7 @@ - Team Win Recovery Project + {@twrp_header=Team Win Recovery Project} @@ -204,7 +204,7 @@ @@ -261,25 +261,25 @@ - Install Zip + {@install_zip_hdr=Install Zip} - Install Image + {@install_image_hdr=Install Image} - Select File from %tw_storage_display_name% (%tw_storage_free_size% MB) + {@select_file_from_storage=Select File from %tw_storage_display_name% (%tw_storage_free_size% MB)}