| // Copyright 2015 Google Inc. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "cobalt/base/localized_strings.h" |
| |
| #include <libxml/parser.h> |
| #include <libxml/tree.h> |
| |
| #include "base/file_path.h" |
| #include "base/file_util.h" |
| #include "base/logging.h" |
| #include "base/path_service.h" |
| |
| namespace base { |
| |
| namespace { |
| // Does a DFS over the tree starting at |node| and ending at the first element |
| // whose name is |name|. |
| xmlNode* FindXmlNode(xmlNode* node, const char* name) { |
| xmlNode* child = node->children; |
| while (child) { |
| if (child->type == XML_ELEMENT_NODE) { |
| if (strcmp((const char*)child->name, name) == 0) { |
| return child; |
| } |
| xmlNode* descendant = FindXmlNode(child, name); |
| if (descendant) { |
| return descendant; |
| } |
| } |
| child = child->next; |
| } |
| return NULL; |
| } |
| } // namespace |
| |
| LocalizedStrings* LocalizedStrings::GetInstance() { |
| return Singleton<LocalizedStrings>::get(); |
| } |
| |
| LocalizedStrings::LocalizedStrings() { |
| // Initialize to US English on creation. A subsequent call to Initialize |
| // will overwrite all available strings in the specified language. |
| LoadStrings("en-US"); |
| } |
| |
| LocalizedStrings::~LocalizedStrings() {} |
| |
| void LocalizedStrings::Initialize(const std::string& language) { |
| LoadStrings(language); |
| } |
| |
| std::string LocalizedStrings::GetString(const std::string& id, |
| const std::string& fallback) { |
| StringContainer::iterator iter = strings_.find(id); |
| if (iter == strings_.end()) { |
| return fallback; |
| } |
| return iter->second; |
| } |
| |
| void LocalizedStrings::LoadStrings(const std::string& language) { |
| // Construct the XLB filename. |
| FilePath xlb_path; |
| PathService::Get(base::DIR_EXE, &xlb_path); |
| xlb_path = xlb_path.Append("i18n").Append(language).AddExtension("xlb"); |
| |
| // Try to open the XLB file. |
| std::string content; |
| if (!file_util::ReadFileToString(xlb_path, &content)) { |
| DLOG(WARNING) << "Cannot open XLB file: " << xlb_path.value(); |
| |
| // Fall back to a generic version of the same language. |
| size_t dash = language.find('-'); |
| if (dash != std::string::npos) { |
| // Chop off the country part of the language string and try again. |
| std::string generic_lang(language.c_str(), dash); |
| LoadStrings(generic_lang); |
| } |
| return; |
| } |
| |
| // Parse the XML document. |
| xmlDoc* doc = xmlParseDoc(reinterpret_cast<const xmlChar*>(content.c_str())); |
| if (!doc) { |
| DLOG(WARNING) << "Cannot parse XLB file: " << xlb_path.value(); |
| return; |
| } |
| |
| // Find the first <msg> node by DFS. |
| xmlNode* msg = FindXmlNode(xmlDocGetRootElement(doc), "msg"); |
| // Iterate through the sibling <msg> elements. |
| while (msg) { |
| if (!strcmp((const char*)msg->name, "msg")) { |
| // Add the data from this element to the strings list. |
| char* name = |
| reinterpret_cast<char*>(xmlGetProp(msg, (const xmlChar*)"name")); |
| char* value = |
| reinterpret_cast<char*>(xmlNodeListGetString(doc, msg->children, 1)); |
| strings_[name] = value; |
| xmlFree(name); |
| xmlFree(value); |
| } |
| msg = msg->next; |
| } |
| |
| xmlFreeDoc(doc); |
| } |
| |
| } // namespace base |