MyGUI  3.2.0
MyGUI_LanguageManager.cpp
Go to the documentation of this file.
00001 
00006 /*
00007     This file is part of MyGUI.
00008 
00009     MyGUI is free software: you can redistribute it and/or modify
00010     it under the terms of the GNU Lesser General Public License as published by
00011     the Free Software Foundation, either version 3 of the License, or
00012     (at your option) any later version.
00013 
00014     MyGUI is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017     GNU Lesser General Public License for more details.
00018 
00019     You should have received a copy of the GNU Lesser General Public License
00020     along with MyGUI.  If not, see <http://www.gnu.org/licenses/>.
00021 */
00022 #include "MyGUI_Precompiled.h"
00023 #include "MyGUI_LanguageManager.h"
00024 #include "MyGUI_ResourceManager.h"
00025 #include "MyGUI_XmlDocument.h"
00026 #include "MyGUI_DataManager.h"
00027 #include "MyGUI_FactoryManager.h"
00028 
00029 namespace MyGUI
00030 {
00031 
00032     const std::string XML_TYPE("Language");
00033 
00034     template <> LanguageManager* Singleton<LanguageManager>::msInstance = nullptr;
00035     template <> const char* Singleton<LanguageManager>::mClassTypeName("LanguageManager");
00036 
00037     LanguageManager::LanguageManager() :
00038         mIsInitialise(false)
00039     {
00040     }
00041 
00042     void LanguageManager::initialise()
00043     {
00044         MYGUI_ASSERT(!mIsInitialise, getClassTypeName() << " initialised twice");
00045         MYGUI_LOG(Info, "* Initialise: " << getClassTypeName());
00046 
00047         ResourceManager::getInstance().registerLoadXmlDelegate(XML_TYPE) = newDelegate(this, &LanguageManager::_load);
00048 
00049         MYGUI_LOG(Info, getClassTypeName() << " successfully initialized");
00050         mIsInitialise = true;
00051     }
00052 
00053     void LanguageManager::shutdown()
00054     {
00055         MYGUI_ASSERT(mIsInitialise, getClassTypeName() << " is not initialised");
00056         MYGUI_LOG(Info, "* Shutdown: " << getClassTypeName());
00057 
00058         ResourceManager::getInstance().unregisterLoadXmlDelegate(XML_TYPE);
00059 
00060         MYGUI_LOG(Info, getClassTypeName() << " successfully shutdown");
00061         mIsInitialise = false;
00062     }
00063 
00064     void LanguageManager::_load(xml::ElementPtr _node, const std::string& _file, Version _version)
00065     {
00066         std::string default_lang;
00067         bool event_change = false;
00068 
00069         // берем детей и крутимся, основной цикл
00070         xml::ElementEnumerator root = _node->getElementEnumerator();
00071         while (root.next(XML_TYPE))
00072         {
00073             // парсим атрибуты
00074             root->findAttribute("default", default_lang);
00075 
00076             // берем детей и крутимся
00077             xml::ElementEnumerator info = root->getElementEnumerator();
00078             while (info.next("Info"))
00079             {
00080                 // парсим атрибуты
00081                 std::string name(info->findAttribute("name"));
00082 
00083                 // доюавляем в карту пользователя
00084                 if (name.empty())
00085                 {
00086                     xml::ElementEnumerator source_info = info->getElementEnumerator();
00087                     while (source_info.next("Source"))
00088                     {
00089                         loadLanguage(source_info->getContent(), true);
00090                     }
00091                 }
00092                 // добавляем в карту языков
00093                 else
00094                 {
00095                     xml::ElementEnumerator source_info = info->getElementEnumerator();
00096                     while (source_info.next("Source"))
00097                     {
00098                         std::string file_source = source_info->getContent();
00099                         // добавляем в карту
00100                         mMapFile[name].push_back(file_source);
00101 
00102                         // если добавляемый файл для текущего языка, то подгружаем и оповещаем
00103                         if (name == mCurrentLanguageName)
00104                         {
00105                             loadLanguage(file_source, false);
00106                             event_change = true;
00107                         }
00108                     }
00109                 }
00110 
00111             }
00112         }
00113 
00114         if (!default_lang.empty())
00115             setCurrentLanguage(default_lang);
00116         else if (event_change)
00117             eventChangeLanguage(mCurrentLanguageName);
00118     }
00119 
00120     void LanguageManager::setCurrentLanguage(const std::string& _name)
00121     {
00122         MapListString::iterator item = mMapFile.find(_name);
00123         if (item == mMapFile.end())
00124         {
00125             MYGUI_LOG(Error, "Language '" << _name << "' is not found");
00126             return;
00127         }
00128 
00129         mMapLanguage.clear();
00130         mCurrentLanguageName = _name;
00131 
00132         for (VectorString::const_iterator iter = item->second.begin(); iter != item->second.end(); ++iter)
00133         {
00134             loadLanguage(*iter, false);
00135         }
00136 
00137         eventChangeLanguage(mCurrentLanguageName);
00138     }
00139 
00140     bool LanguageManager::loadLanguage(const std::string& _file, bool _user)
00141     {
00142         DataStreamHolder data = DataManager::getInstance().getData(_file);
00143         if (data.getData() == nullptr)
00144         {
00145             MYGUI_LOG(Error, "file '" << _file << "' not found");
00146             return false;
00147         }
00148 
00149         if (_file.find(".xml") != std::string::npos)
00150             _loadLanguageXML(data.getData(), _user);
00151         else
00152             _loadLanguage(data.getData(), _user);
00153 
00154         return true;
00155     }
00156 
00157     void LanguageManager::_loadLanguageXML(IDataStream* _stream, bool _user)
00158     {
00159         xml::Document doc;
00160         // формат xml
00161         if (doc.open(_stream))
00162         {
00163             xml::ElementPtr root = doc.getRoot();
00164             if (root)
00165             {
00166                 xml::ElementEnumerator tag = root->getElementEnumerator();
00167                 while (tag.next("Tag"))
00168                 {
00169                     if (_user)
00170                         mUserMapLanguage[tag->findAttribute("name")] = tag->getContent();
00171                     else
00172                         mMapLanguage[tag->findAttribute("name")] = tag->getContent();
00173                 }
00174             }
00175         }
00176     }
00177 
00178     void LanguageManager::_loadLanguage(IDataStream* _stream, bool _user)
00179     {
00180         // формат txt
00181         std::string read;
00182         while (!_stream->eof())
00183         {
00184             _stream->readline(read, '\n');
00185             if (read.empty()) continue;
00186 
00187             // заголовок утф
00188             if ((uint8)read[0] == 0xEF && read.size() > 2)
00189             {
00190                 read.erase(0, 3);
00191             }
00192 
00193             if (read[read.size()-1] == '\r') read.erase(read.size() - 1, 1);
00194             if (read.empty()) continue;
00195 
00196             size_t pos = read.find_first_of(" \t");
00197             if (_user)
00198             {
00199                 if (pos == std::string::npos) mUserMapLanguage[read] = "";
00200                 else mUserMapLanguage[read.substr(0, pos)] = read.substr(pos + 1, std::string::npos);
00201             }
00202             else
00203             {
00204                 if (pos == std::string::npos) mMapLanguage[read] = "";
00205                 else mMapLanguage[read.substr(0, pos)] = read.substr(pos + 1, std::string::npos);
00206             }
00207         }
00208     }
00209 
00210     UString LanguageManager::replaceTags(const UString& _line)
00211     {
00212         UString result(_line);
00213 
00214         bool replace = false;
00215         do
00216         {
00217             result = replaceTagsPass(result, replace);
00218         }
00219         while (replace);
00220 
00221         return result;
00222     }
00223 
00224     UString LanguageManager::getTag(const UString& _tag)
00225     {
00226         MapLanguageString::iterator iter = mMapLanguage.find(_tag);
00227         if (iter == mMapLanguage.end())
00228         {
00229             iter = mUserMapLanguage.find(_tag);
00230             if (iter != mUserMapLanguage.end()) return iter->second;
00231             return _tag;
00232         }
00233 
00234         return iter->second;
00235     }
00236 
00237     const std::string& LanguageManager::getCurrentLanguage() const
00238     {
00239         return mCurrentLanguageName;
00240     }
00241 
00242     void LanguageManager::addUserTag(const UString& _tag, const UString& _replace)
00243     {
00244         mUserMapLanguage[_tag] = _replace;
00245     }
00246 
00247     void LanguageManager::clearUserTags()
00248     {
00249         mUserMapLanguage.clear();
00250     }
00251 
00252     bool LanguageManager::loadUserTags(const std::string& _file)
00253     {
00254         return loadLanguage(_file, true);
00255     }
00256 
00257     UString LanguageManager::replaceTagsPass(const UString& _line, bool& _replaceResult)
00258     {
00259         _replaceResult = false;
00260 
00261         // вот хз, что быстрее, итераторы или математика указателей,
00262         // для непонятно какого размера одного символа UTF8
00263         UString line(_line);
00264 
00265         UString::iterator end = line.end();
00266         for (UString::iterator iter = line.begin(); iter != end; )
00267         {
00268             if (*iter == '#')
00269             {
00270                 ++iter;
00271                 if (iter == end)
00272                 {
00273                     return line;
00274                 }
00275                 else
00276                 {
00277                     if (*iter != '{')
00278                     {
00279                         ++iter;
00280                         continue;
00281                     }
00282                     UString::iterator iter2 = iter;
00283                     ++iter2;
00284 
00285                     while (true)
00286                     {
00287                         if (iter2 == end)
00288                             return line;
00289 
00290                         if (*iter2 == '}')
00291                         {
00292                             size_t start = iter - line.begin();
00293                             size_t len = (iter2 - line.begin()) - start - 1;
00294                             const UString& tag = line.substr(start + 1, len);
00295                             UString replacement;
00296 
00297                             bool find = true;
00298                             // try to find in loaded from resources language strings
00299                             MapLanguageString::iterator replace = mMapLanguage.find(tag);
00300                             if (replace != mMapLanguage.end())
00301                             {
00302                                 replacement = replace->second;
00303                             }
00304                             else
00305                             {
00306                                 // try to find in user language strings
00307                                 replace = mUserMapLanguage.find(tag);
00308                                 if (replace != mUserMapLanguage.end())
00309                                 {
00310                                     replacement = replace->second;
00311                                 }
00312                                 else
00313                                 {
00314                                     find = false;
00315                                 }
00316                             }
00317 
00318                             // try to ask user if event assigned or use #{_tag} instead
00319                             if (!find)
00320                             {
00321                                 if (!eventRequestTag.empty())
00322                                 {
00323                                     eventRequestTag(tag, replacement);
00324                                 }
00325                                 else
00326                                 {
00327                                     iter = line.insert(iter, '#') + size_t(len + 2);
00328                                     end = line.end();
00329                                     break;
00330                                 }
00331                             }
00332 
00333                             _replaceResult = true;
00334 
00335                             iter = line.erase(iter - size_t(1), iter2 + size_t(1));
00336                             size_t pos = iter - line.begin();
00337                             line.insert(pos, replacement);
00338                             iter = line.begin() + pos + replacement.length();
00339                             end = line.end();
00340                             if (iter == end)
00341                                 return line;
00342                             break;
00343                         }
00344                         ++iter2;
00345                     }
00346                 }
00347             }
00348             else
00349             {
00350                 ++iter;
00351             }
00352         }
00353 
00354         return line;
00355     }
00356 
00357 } // namespace MyGUI