From 74db157b9406594a549a70415668dd6cbe17d1d3 Mon Sep 17 00:00:00 2001 From: Ethan Yonker Date: Wed, 28 Oct 2015 12:44:49 -0500 Subject: Multiple Language Support This is similar to https://gerrit.omnirom.org/#/c/14014 A lot of the features built in the older patch set have been split out into separate patches, most of which have already been merged. The remaining functionality here should all be directly related to language selection and loading. We always load English as a base before loading other languages over the top of the base. The idea is that if another language is missing a translation, then we will still display the English. Maybe still to do: read the /cache/recovery/last_locale file and load a language based on that. For me, this file contains just: en_US We probably won't bother with region specific translations so we would have to look at either trimming off the _US or using some other method like perhaps a symlink or a combination of the two. Thanks to _that for twmsg.cpp class Change-Id: I9647a22e47883a3ddd2de1da51f64aab7c328f74 --- gui/pages.cpp | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 178 insertions(+), 6 deletions(-) (limited to 'gui/pages.cpp') diff --git a/gui/pages.cpp b/gui/pages.cpp index 0511b1ab5..13f3bd7b5 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) -- cgit v1.2.3